Сегодня я проходил собеседование на должность разработчика Java на крупной фабрике, не обладая собственными способностями. Ко мне подошел мужчина средних лет, который был в середине своей жизни, держа в руках Mac с включенным экраном. Он вежливо улыбнулся. Затем он сказал: «Извините, я заставил вас ждать», затем жестом пригласил меня сесть и сказал: «Давайте начнем. Прочитав ваше резюме, я думаю, вы должны хорошо разбираться в Redis. Давайте обсудим Redis сегодня . …”. Я подумал: «Ну, когда ты придешь, солдаты придут, чтобы перекрыть воду и засыпать землю».
Что такое Редис
-
Интервьюер: Не могли бы вы сначала рассказать о том, что такое Redis?
-
Я: (Это не краткое изложение определения и характеристик Redis) Redis — это высокопроизводительная база данных с открытым исходным кодом (соответствие протоколу BSD) в памяти, разработанная на языке C, которую можно использовать в качестве базы данных, кеш, промежуточное ПО сообщений и т. д. Это база данных NoSQL (не только sql, обычно относится к нереляционной базе данных).
-
Я сделал паузу, затем продолжил: Redis как база данных в памяти. 1. Отличная производительность, данные в памяти, очень высокая скорость чтения и записи, поддержка одновременных запросов 10 Вт в секунду 2. Один процесс и один поток, потокобезопасность, использование механизма мультиплексирования ввода-вывода 3. Богатые типы данных, поддержка строк символов, хэшей, списки, наборы, отсортированные наборы и т. д. 4. Поддержка сохранения данных. Данные в памяти могут храниться на диске и загружаться при перезапуске 5. Репликация ведущий-ведомый, дозорный, высокая доступность 6. Может использоваться в качестве распределенной блокировки 7. Может использоваться в качестве промежуточного программного обеспечения сообщений, поддерживающего публикацию и подписку
Пять типов данных
-
Интервьюер: Резюме хорошее, кажется, вы подготовились. Я только что услышал, что вы упомянули, что Redis поддерживает пять типов данных, поэтому не могли бы вы кратко описать эти пять типов данных?
-
Я: Конечно, но прежде чем я это скажу, я думаю, необходимо понять, как управление внутренней памятью Redis описывает эти 5 типов данных. Сказав это, я взял ручку и нарисовал интервьюеру:
-
Я: Во-первых, Redis использует объект redisObject для представления всех ключей и значений.Основная информация о redisObject показана на рисунке выше: тип указывает, к какому типу данных относится объект-значение, а кодирование — как различаются типы данных. хранятся внутри Redis. Например: type=string означает, что value хранит обычную строку, тогда кодировка может быть raw или int.
-
Я сделал паузу на мгновение, а затем сказал: Я кратко опишу 5 типов данных ниже:
1. Строка — это самый базовый тип Redis, его можно понимать как точно такой же тип, как и memcached, один ключ соответствует одному значению. value является не только строкой, но и числом. Строковый тип безопасен для двоичных файлов, что означает, что строковый тип Redis может содержать любые данные, например изображения в формате jpg или сериализованные объекты. Значение типа string может хранить до 512M.
2. Хэш — это набор ключей-значений. Хэш Redis – это таблица сопоставления строковых ключей и значений. Хэш особенно подходит для хранения объектов. Общие команды: hget, hset, hgetall и т. д.
3. Список списка представляет собой простой список строк, отсортированных по порядку вставки. Вы можете добавить элемент в начало (слева) или хвост (справа) списка.Распространенные команды: lpush, rpush, lpop, rpop, lrange (получить сегменты списка) и т. д.
Сценарии применения: существует множество сценариев применения списка, и это также одна из наиболее важных структур данных Redis.Например, список подписчиков в Твиттере и список поклонников могут быть реализованы структурой списка.
Структура данных: список — это связанный список, который можно использовать как очередь сообщений. Redis предоставляет операции push и pop для списка, а также предоставляет API для работы с определенным сегментом, который может напрямую запрашивать или удалять элементы определенного сегмента.
Метод реализации: реализация списка redis представляет собой двусвязный список, который может поддерживать обратный поиск и обход, что более удобно в работе, но требует дополнительных затрат памяти.
4. Set — неупорядоченная коллекция строкового типа. Коллекции реализованы через хеш-таблицы. Элементы в наборе не упорядочены и не повторяются.
Общие команды: sdd, spop, smembers, sunion и т. д.
Сценарий приложения: Функция, предоставляемая redis set для внешнего мира, представляет собой список, подобный списку.Особенностью является то, что набор автоматически дедуплицируется, и набор позволяет определить, находится ли элемент в наборе коллекции.
5. Как и набор, zset представляет собой набор элементов строкового типа, и повторяющиеся элементы не допускаются. Общие команды: zadd, zrange, zrem, zcard и др. Сценарий использования: Отсортированный набор может сортировать элементы, предоставляя пользователю дополнительный параметр приоритета (балла), и он вставляется по порядку, то есть автоматическая сортировка. Если вам нужен упорядоченный и неповторяющийся список наборов, вы можете выбрать структуру отсортированного набора. По сравнению с набором, отсортированный набор связан с оценкой параметра с весом двойного типа, так что элементы в наборе можно сортировать в соответствии с оценкой, а redis используется для сортировки членов набора от меньшего к большему.
Метод реализации: Отсортированный набор Redis внутренне использует HashMap и список пропуска (skipList) для обеспечения хранения и упорядочения данных. в HashMap использование структуры таблицы переходов может обеспечить относительно высокую эффективность поиска и относительно проста в реализации. -
Я: Я резюмировал картину о сценариях применения типов данных Если вам интересно, вы можете перейти к моим самородкам, чтобы увидеть. .
Сводка сценария приложения типа данных
тип | Введение | характеристика | Сцены |
---|---|---|---|
строка (строка) | бинарный сейф | Может содержать любые данные, например изображения в формате jpg или сериализованные объекты. | --- |
Хэш (словарь) | Пары ключ-значение, т. е. типы MAP в языках программирования. | Он подходит для хранения объектов и может изменять только значение определенного атрибута, например, обновлять атрибут в базе данных. | Храните, читайте и изменяйте пользовательские атрибуты |
Список | Связанный список (двухсвязный список) | Добавляйте и удаляйте быстро, предоставляет API для работы с элементом | Рейтинг последних новостей; очередь сообщений |
набор (коллекция) | Реализация хеш-таблицы, элементы не повторяются | Сложность добавления, удаления и поиска составляет O(1), обеспечивая операции пересечения, объединения и разности. | Общие друзья; используйте уникальность для подсчета всех IP-адресов, посещающих веб-сайт. |
отсортированный набор | Добавьте оценку параметра веса к элементам в наборе, и элементы будут расположены в порядке оценки | Когда данные вставляются в коллекцию, они уже отсортированы естественным образом. | Таблица лидеров; взвешенная очередь сообщений |
-
Интервьюер: Я не могу поверить, что вы обычно прикладываете к этому много усилий, поэтому вы, должно быть, использовали кеш Redis.
-
я: использовал. .
-
Интервьюер: Тогда расскажи мне, как ты его используешь?
-
Я использую его в сочетании с весенней загрузкой. Обычно есть два способа: один — использовать его напрямую через RedisTemplate, а другой — использовать кеш Spring для интеграции Redis (то есть способ аннотации). Конкретный код не скажу, в моих самородках есть демо (см. ниже).
Кэш Redis
- Используйте напрямую через RedisTemplate
- Интеграция Redis с весенним кешем Добавьте следующие зависимости в pom.xml:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
- spring-boot-starter-data-redis: после весенней загрузки 2.x Jedis больше не используется внизу, но заменяется салатом.
- commons-pool2: используется в качестве пула соединений Redis, будет сообщено об ошибке, если запуск не будет введен
- spring-session-data-redis: представленный Spring Session, он используется как общий сеанс. Конфигурация конфигурационного файла application.yml:
server:
port: 8082
servlet:
session:
timeout: 30ms
spring:
cache:
type: redis
redis:
host: 127.0.0.1
port: 6379
password:
# redis默认情况下有16个分片,这里配置具体使用的分片,默认为0
database: 0
lettuce:
pool:
# 连接池最大连接数(使用负数表示没有限制),默认8
max-active: 100
Создайте класс сущности User.java
public class User implements Serializable{
private static final long serialVersionUID = 662692455422902539L;
private Integer id;
private String name;
private Integer age;
public User() {
}
public User(Integer id, String name, Integer age) {
this.id = id;
this.name = name;
this.age = age;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
Как использовать RedisTemplate
По умолчанию шаблон может поддерживать только RedisTemplate
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisCacheConfig {
@Bean
public RedisTemplate<String, Serializable> redisCacheTemplate(LettuceConnectionFactory connectionFactory) {
RedisTemplate<String, Serializable> template = new RedisTemplate<>();
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setConnectionFactory(connectionFactory);
return template;
}
}
тестовый класс
@RestController
@RequestMapping("/user")
public class UserController {
public static Logger logger = LogManager.getLogger(UserController.class);
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedisTemplate<String, Serializable> redisCacheTemplate;
@RequestMapping("/test")
public void test() {
redisCacheTemplate.opsForValue().set("userkey", new User(1, "张三", 25));
User user = (User) redisCacheTemplate.opsForValue().get("userkey");
logger.info("当前获取对象:{}", user.toString());
}
Затем зайдите в браузер и просмотрите фоновый журналhttp://localhost:8082/user/test
Интеграция Redis с использованием кэша Spring
Spring cache обладает хорошей гибкостью, он может не только использовать SPEL (язык выражений Spring) для определения ключа и различных условий кэша, но также предоставляет готовое решение для временного хранения кэша, а также поддерживает основные профессиональные кэши. такие как EhCache, Redis, интеграция с Guava.
Определите интерфейс UserService.java
public interface UserService {
User save(User user);
void delete(int id);
User get(Integer id);
}
Класс реализации интерфейса UserServiceImpl.java
@Service
public class UserServiceImpl implements UserService{
public static Logger logger = LogManager.getLogger(UserServiceImpl.class);
private static Map<Integer, User> userMap = new HashMap<>();
static {
userMap.put(1, new User(1, "肖战", 25));
userMap.put(2, new User(2, "王一博", 26));
userMap.put(3, new User(3, "杨紫", 24));
}
@CachePut(value ="user", key = "#user.id")
@Override
public User save(User user) {
userMap.put(user.getId(), user);
logger.info("进入save方法,当前存储对象:{}", user.toString());
return user;
}
@CacheEvict(value="user", key = "#id")
@Override
public void delete(int id) {
userMap.remove(id);
logger.info("进入delete方法,删除成功");
}
@Cacheable(value = "user", key = "#id")
@Override
public User get(Integer id) {
logger.info("进入get方法,当前获取对象:{}", userMap.get(id)==null?null:userMap.get(id).toString());
return userMap.get(id);
}
}
Чтобы облегчить демонстрацию работы базы данных, здесь непосредственно определяется Map
Тестовый класс: UserController
@RestController
@RequestMapping("/user")
public class UserController {
public static Logger logger = LogManager.getLogger(UserController.class);
@Autowired
private StringRedisTemplate stringRedisTemplate;
@Autowired
private RedisTemplate<String, Serializable> redisCacheTemplate;
@Autowired
private UserService userService;
@RequestMapping("/test")
public void test() {
redisCacheTemplate.opsForValue().set("userkey", new User(1, "张三", 25));
User user = (User) redisCacheTemplate.opsForValue().get("userkey");
logger.info("当前获取对象:{}", user.toString());
}
@RequestMapping("/add")
public void add() {
User user = userService.save(new User(4, "李现", 30));
logger.info("添加的用户信息:{}",user.toString());
}
@RequestMapping("/delete")
public void delete() {
userService.delete(4);
}
@RequestMapping("/get/{id}")
public void get(@PathVariable("id") String idStr) throws Exception{
if (StringUtils.isBlank(idStr)) {
throw new Exception("id为空");
}
Integer id = Integer.parseInt(idStr);
User user = userService.get(id);
logger.info("获取的用户信息:{}",user.toString());
}
}
Будьте осторожны при использовании кеша, класс запуска должен добавить аннотацию для включения кеша
@SpringBootApplication(exclude=DataSourceAutoConfiguration.class)
@EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
1. Сначала вызовите интерфейс добавления:http://localhost:8082/user/add
2. Затем вызовите интерфейс запросов, чтобы запросить информацию о пользователе с id=4: Здесь видно, что данные были получены из кеша, потому что метод add на предыдущем шаге поместил пользовательские данные с id=4 в кеш Redis. 3. Вызовите метод удаления, удалите информацию о пользователе с id=4 и одновременно очистите кеш. 4. Снова вызовите интерфейс запроса, чтобы запросить информацию о пользователе с id=4: Кеша нет, поэтому он входит в метод get и получает его из userMap.Кэшировать аннотации
1. @Кэшируемый Кэшировать результат метода на основе его параметров запроса
- key: Кэшированный ключ, который может быть пустым, если он указан, то должен быть записан согласно выражению SPEL, если не указан, то будет объединен по всем параметрам метода.
- значение: имя кеша, хотя бы одно должно быть указано (например, @Cacheable(value='user') или @Cacheable(value={'user1','user2'}))
- условие: состояние кеша, которое может быть пустым, записанное на языке SPEL, возвращает true или false и кэширует только если оно истинно.
2. @CachePut
Результат метода кэшируется в соответствии с параметрами запроса метода, в отличие от @Cacheable, он каждый раз вызывает вызов реального метода. См. выше описание параметра.
3. @CacheEvict
Очистить кеш в зависимости от условий
- ключ: такой же, как указано выше
- значение: то же, что и выше
- состояние: то же, что и выше
- allEntries: очищать ли весь кешированный контент, по умолчанию установлено значение false, если указано значение true, все кеши будут очищены сразу после вызова метода.
- beforeInvocation: следует ли очищать перед выполнением метода, по умолчанию — false, если указано значение true, кеш очищается перед выполнением метода. По умолчанию кэш не очищается, если выполнение метода вызывает исключение.
проблема с кешем
-
Интервьюер: Я посмотрел вашу демонстрацию, ее легко понять. Знаете ли вы, с какими проблемами или проблемами вы столкнетесь при использовании кешей в реальных проектах?
-
Я: Проблемы согласованности данных кэша и базы данных: очень легко иметь проблемы с согласованностью данных между кэшами и базами данных в распределенной среде.Для этого, если требования проекта к кэшам строго непротиворечивы, то не используйте кэши. Мы можем только принять соответствующие стратегии для снижения вероятности несогласованности данных между кешем и базой данных, но не можем гарантировать надежную согласованность между ними. Соответствующие стратегии включают подходящую стратегию обновления кэша, своевременное обновление кэша после обновления базы данных и добавление механизма повторных попыток при сбое кэша.
-
Интервьюер: Вы понимаете Redis Avalanche?
-
Я: Я понимаю, что текущая домашняя страница электронной коммерции и горячие данные кэшируются. Как правило, кэш обновляется запланированными задачами или кэш обновляется после того, как его не удается найти. Возникла проблема с обновлением запланированных задач. Например: если срок действия всех ключей на домашней странице составляет 12 часов, а обновление происходит в 12:00, у меня есть большое продвижение в 0:00 и большое количество пользователей. Предполагая, что 6000 запросов в секунду, кеш выдерживает 5000 запросов в секунду, но все ключи в кеше недействительны. В это время все 6000 запросов в секунду легли на базу данных, и база данных должна быть не в состоянии это обработать.В реальной ситуации администратор БД может не ответить и зависнуть напрямую.В это время, если нет особого плана чтобы справиться с этим, администратор базы данных очень беспокоится и перезапускает базу данных. , но база данных была немедленно убита новым трафиком. Вот что я понимаю под лавиной кеша.
-
Я подумал про себя: В то же время большая область отказа, и Redis не то же самое в одно мгновение, то для запросов такого масштаба прямое попадание в базу данных почти катастрофично.Если вы думаете о библиотеке что привязан к пользовательскому сервису, то от него зависят остальные.Практически все интерфейсы в библиотеке будут сообщать об ошибках.Если не делать фьюз и прочие стратегии,то в принципе повесишь ритм в один миг.Неважно как перезапустишь юзера, так и зависнет.При перезагрузке юзер рано ляжет спать, а перед сном будет ругаться."Что за дрянь продукт".
-
Интервьюер потрогал его за волосы: Ну, неплохо, как вы справляетесь с этой ситуацией?
-
Я: Бороться с лавинами кеша просто: при пакетном хранении данных в Redis полезно добавлять случайное значение ко времени истечения срока действия каждого ключа, чтобы гарантировать, что данные не будут сбоить на большой площади при в то же время.
setRedis(key, value, time+Math.random()*10000);
Если Redis развернут в кластере, равномерное распределение горячих данных в разных библиотеках Redis также может избежать всех сбоев. Или установите срок действия данных точки доступа неограниченный, просто обновите кеш, если есть операция обновления (например, если операция и обслуживание обновляют продукт домашней страницы, вы можете просто обновить кеш, не устанавливая время истечения), также могут быть использованы данные домашней страницы электронной коммерции, операции, страхование.
-
Интервьюер: Тогда вы понимаете проникновение и сбой кэша, можете рассказать о разнице между ними и Avalanche?
-
Я: Ну, я понял, давайте сначала поговорим о проникновении в кеш. К проникновению в кеш относятся данные, которых нет ни в кеше, ни в базе данных, а пользователи (хакеры) продолжают делать запросы. Например, идентификаторы нашей базы данных все из 1 к 1. Кроме того, если данные с id=-1 или данные с особенно большим id, которого не существует, будут инициированы, такие постоянные атаки вызовут большую нагрузку на базу данных, которая серьезно перегрузит базу данных.
-
Далее я сказал: «Что касается разбивки кеша, это немного похоже на лавину кеша, но немного отличается. Лавина кеша возникает из-за того, что большая часть кеша недействительна и БД уничтожена, и разбивка кеша отличается от разбивки кеша.Это означает что ключ очень горячий.Он постоянно несет большое количество запросов,и большой параллелизм концентрируется на доступе к этой точке.При сбое ключа происходит непрерывный большой параллелизм напрямую попадает в базу данных.Нажмите, чтобы разбить кеш.
-
Интервьюер вздохнул с облегчением: как они ее решили?
-
Я: Я добавлю проверку на уровне интерфейса для проникновения в кеш, такую как аутентификация пользователя и проверка параметров. Незаконная проверка будет возвращена напрямую. Например, id будет использоваться для базовой проверки, а id
-
Интервьюер: Так у вас есть другой способ?
-
Я: Я помню, что в Redis также есть расширенное использование **Фильтр Блума**, который также может очень хорошо предотвратить проникновение в кеш.Его принцип также очень прост, то есть использовать эффективные структуры данных и алгоритм может быстро определить есть ли ваш ключ в БД.если нет то можно вернуть.если есть то можно проверить БД обновить КВ и вернуть его. Если кеш выйдет из строя, установите для данных точки доступа неограниченный срок действия или добавьте мьютекс, и все будет готово. Как теплый человек, код готов для вас, спасибо, что взяли его.
public static String getData(String key) throws InterruptedException {
//从Redis查询数据
String result = getDataByKV(key);
//参数校验
if (StringUtils.isBlank(result)) {
try {
//获得锁
if (reenLock.tryLock()) {
//去数据库查询
result = getDataByDB(key);
//校验
if (StringUtils.isNotBlank(result)) {
//插进缓存
setDataToKV(key, result);
}
} else {
//睡一会再拿
Thread.sleep(100L);
result = getData(key);
}
} finally {
//释放锁
reenLock.unlock();
}
}
return result;
}
- Интервьюер: Ну, неплохо.
Почему Redis такой быстрый
-
Интервьюер: Все используют Redis в качестве кеша, поэтому Redis должен быть быстрым?
-
Я: Конечно, официальные данные могут достигать 100 000+ QPS (количество запросов в секунду), что не хуже, чем у Memcached!
-
Интервьюер: Redis настолько быстр, вы понимаете его «многопоточную модель»? (с лукавой улыбкой)
-
Я: Вы хотите спросить, почему Redis такой быстрый, почему он до сих пор однопоточный? Redis действительно является однопроцессорной и однопоточной моделью, потому что Redis полностью основан на памяти, а ЦП не является узким местом Redis. Узким местом Redis, скорее всего, является размер машинной памяти или пропускная способность сети. Так как однопоточность реализовать легко, а ЦП не станет узким местом, логично использовать однопоточное решение (ведь использование многопоточности доставит массу хлопот).
-
Интервьюер: Ну да. Тогда можно сказать, что Redis однопоточный, почему он такой быстрый?
-
Я: Можно так сказать. Во-первых: Redis полностью основан на памяти, большинство запросов - это операции с чистой памятью, очень быстрые, и данные хранятся в памяти.Как и в случае с HashMap, преимущество HashMap заключается в том, что временная сложность поиска и работы составляет O (1). Во-вторых: структура данных проста, и обработка данных также проста. Третье: используется один поток, чтобы избежать ненужного переключения контекста и условий конкуренции, нет переключения процессора, вызванного многопоточностью, нет необходимости учитывать различные проблемы с блокировкой, нет операции снятия блокировки и нет проблемы взаимоблокировки. потребление производительности. Четвертое: используйте мультиплексированную модель ввода-вывода, неблокирующий ввод-вывод.
Разница между Redis и Memcached
-
Интервьюер: Ну, это очень подробно. Так почему же вы выбрали решение для кэширования Redis вместо memcached?
-
Я: 1. По способу хранения: memcache будет хранить все данные в памяти, а после сбоя питания будет зависать, а данные не могут превышать размер памяти. Redis хранит некоторые данные на жестком диске, что может обеспечить их сохранность. 2. Тип поддержки данных: memcache поддерживает простые типы данных, только простые ключ-значение, тогда как Redis поддерживает пять типов данных. 3. Различные базовые модели: базовые реализации между ними и прикладной протокол для связи с клиентом различны. Redis напрямую сам строит механизм ВМ, потому что, если общая система вызывает системные функции, она будет тратить определенное количество времени на перемещение и запрос. 4. Размер значения: Redis может достигать 1 ГБ, а memcache — всего 1 МБ.
стратегия ликвидации
-
Интервьюер: Тогда какие стратегии устранения redis вы знаете?
-
Я: У Redis есть шесть стратегий исключения.
Стратегия | описывать |
---|---|
volatile-lru | Сначала наименее использовавшиеся данные удаляются из набора KV с истекшим временем. |
volitile-ttl | Данные с коротким оставшимся временем (время жизни) будут удалены первыми из набора KV, для которого установлено время истечения срока действия. |
volitile-random | Произвольный выбор данных для исключения из набора KV с установленным сроком действия |
allkeys-lru | Предпочитает, чтобы из всех наборов KV удалялись наименее использовавшиеся данные. |
allKeys-random | Произвольное удаление данных из всех наборов KV |
noeviction | Стратегии устранения нет, если превышен максимальный объем памяти, будет возвращено сообщение об ошибке |
Чтобы добавить: Redis4.0 добавил стратегию устранения LFU (наименее частотное использование), включая volatile-lfu и allkeys-lfu, Подсчитывая частоту доступа, KV с наименьшей частотой доступа, то есть наименее часто используемый KV, устраняется.
Упорство
-
Интервьюер: Вы понимаете механизм сохранения Redis? Можешь рассказать об этом?
-
Я: Чтобы обеспечить эффективность, Redis кэширует данные в памяти, но периодически записывает обновленные данные на диск или записывает операции модификации в дополнительные файлы записей, чтобы обеспечить постоянство данных. Для Redis существует две стратегии сохранения: 1. RDB: форма моментального снимка предназначена для непосредственного сохранения данных в памяти в файл дампа, их регулярного сохранения и сохранения стратегии. 2. AOF: Храните все команды для изменения сервера Redis в файле, наборе команд. Redis — это метод сохраняемости моментальных снимков RDB по умолчанию. Когда Redis перезапустится, он сначала будет использовать файл AOF для восстановления набора данных, поскольку набор данных, сохраненный в файле AOF, обычно более полный, чем набор данных, сохраненный в файле RDB. Вы даже можете отключить постоянство, чтобы данные сохранялись только во время работы сервера.
-
Интервьюер: Тогда расскажите мне, как работает RDB?
-
Я: По умолчанию Redis представляет собой двоичный файл dump.rdb, который сохраняет данные на диск в виде моментального снимка «RDB». Кратко описывается принцип работы: когда Redis нужно сделать постоянство, Redis разветвит дочерний процесс, и дочерний процесс запишет данные во временный файл RDB на диске. Когда дочерний процесс завершает запись временного файла, он заменяет исходную RDB, которая имеет преимущество копирования при записи.
-
Я: Преимущество RDB заключается в следующем: этот вид файлов очень подходит для резервного копирования: например, вы можете создавать резервные копии каждый час в течение последних 24 часов, а также создавать резервные копии файлов RDB каждый день месяца. Таким образом, вы всегда сможете восстановить свой набор данных до другой версии, даже если у вас возникнут проблемы. RDB отлично подходят для аварийного восстановления. Недостатком RDB является то, что если вам нужно попытаться избежать потери данных в случае сбоя сервера, то RDB не для вас.
-
Интервьюер: Тогда вы хотите перестать говорить об AOF? ?
-
Я: (Давайте поговорим об этом вместе) Используя AOF для сохраняемости, каждая команда записи добавляется к appendonly.aof через функцию записи.Конфигурация выглядит следующим образом:
appendfsync yes
appendfsync always #每次有数据修改发生时都会写入AOF文件。
appendfsync everysec #每秒钟同步一次,该策略为AOF的缺省策略。
AOF может быть постоянным на протяжении всего процесса, просто включите в конфигурации appendonly yes. Таким образом, каждый раз, когда Redis выполняет команду для изменения данных, она будет добавлена в файл AOF.При перезапуске Redis будет считывать файл AOF для воспроизведения и восстановления до последнего момента перед закрытием Redis.
-
Я сделал паузу и продолжил: Преимущество использования AOF в том, что он делает Redis очень надежным. Можно установить различные политики fsync.По умолчанию для aof используется fsync один раз в секунду.В этой конфигурации даже в случае сбоя данные будут потеряны на срок до одной секунды. Недостатком является то, что для одного и того же набора данных размер файла AOF обычно больше, чем размер файла RDB. В зависимости от используемой стратегии fsync AOF может работать медленнее, чем RDB.
-
Интервьюер снова спросил: Вы так много сказали, что мне использовать?
-
Я: Если вы очень заботитесь о своих данных, но все же можете позволить себе потерять данные в течение нескольких минут, тогда вы можете просто использовать RDB для сохранения. AOF добавляет каждую команду, выполняемую Redis, на диск, обработка огромных операций записи снижает производительность Redis, я не знаю, сможете ли вы это принять. Резервное копирование базы данных и аварийное восстановление. Регулярное создание моментальных снимков RDB очень удобно для резервного копирования базы данных, а RDB восстанавливает наборы данных быстрее, чем восстановление AOF. Конечно, Redis поддерживает одновременное открытие RDB и AOF.После перезагрузки системы Redis будет отдавать приоритет использованию AOF для восстановления данных, так что потеря данных будет наименьшей.
репликация master-slave
-
Интервьюер: у одного узла Redis есть проблема с единственной точкой отказа. Чтобы решить проблему с одной точкой, обычно необходимо настроить подчиненный узел для Redis, а затем использовать дозорный для отслеживания статуса выживания главного узла. Если главный узел выходит из строя, подчиненный узел может продолжать предоставлять кеш Функция, можете ли вы рассказать о процессе и принципе репликации redis master-slave?
-
Я немного запутался, это длинная история. Но, к счастью, он был подготовлен заранее: конфигурация master-slave в сочетании с режимом Sentinel может решить проблему единой точки отказа и повысить доступность Redis. Ведомый узел обеспечивает только операции чтения, а главный узел обеспечивает операции записи. В случае большего количества операций чтения, чем записи, можно настроить несколько подчиненных узлов для главного узла, чтобы повысить эффективность ответа.
-
Я немного помолчал, а потом сказал: Что касается процесса копирования, то он такой: 1. Выполните команду slaveof[masterIP][masterPort] на узле, чтобы сохранить информацию о главном узле.
2. Задача синхронизации на подчиненном узле обнаруживает информацию о главном узле и устанавливает соединение через сокет с главным узлом.
3. Подчиненный узел отправляет сигнал Ping, главный узел возвращает Pong, и обе стороны могут общаться друг с другом.
4. После установления соединения ведущий узел отправляет все данные подчиненному узлу (синхронизация данных).
5. После того, как главный узел синхронизирует текущие данные с подчиненным узлом, процесс установления репликации завершается. Затем главный узел продолжит отправлять команды записи подчиненным узлам, чтобы обеспечить согласованность данных ведущий-ведомый. -
Интервьюер: Тогда не могли бы вы подробнее рассказать о процессе синхронизации данных?
-
(Я подумал про себя: это слишком подробно.) Я: Да. До redis2.8 используйте команду синхронизации sync[runId][offset], а после redis2.8 используйте команду psync[runId][offset]. Разница между ними заключается в том, что команда sync поддерживает только процесс полной репликации, а psync поддерживает полную и частичную репликацию. Прежде чем вводить синхронизацию, давайте введем несколько понятий:
runId: уникальный uuid будет генерироваться для каждого запуска узла Redis, и runId будет меняться каждый раз при перезапуске Redis.
offset: как главный узел, так и подчиненный узел поддерживают свое собственное смещение смещения репликации master-slave.Когда у главного узла есть команда записи, смещение=смещение+длина командного байта. После того, как подчиненный узел получит команду, отправленную ведущим узлом, он также увеличит свое собственное смещение и отправит свое собственное смещение главному узлу. Таким образом, главный узел одновременно сохраняет свое собственное смещение и смещение подчиненного узла и оценивает, согласуются ли данные главного и подчиненного узлов, сравнивая смещения.
repl_backlog_size: очередь FIFO фиксированной длины, хранящаяся на главном узле, размер по умолчанию — 1 МБ.
(1) Когда главный узел отправляет данные подчиненному узлу, главный узел также выполняет некоторые операции записи, и данные в это время сохраняются в буфере репликации. После того, как подчиненный узел синхронизирует данные главного узла, главный узел продолжает отправлять данные в буфере подчиненному узлу для частичной репликации.
(2) Когда главный узел отвечает на команду записи, он не только отправляет имя подчиненному узлу, но также записывает в буфер невыполненной репликации для восстановления данных, потерянных командой репликации.
Ведомый узел отправляет команду psync[runId][offset], а главный узел получает три ответа:
(1) FULLRESYNC: первое подключение, полная репликация
(2) ПРОДОЛЖИТЬ: сделать частичную копию
(3) ERR: команда psync не поддерживается, выполняется полное копирование
-
Интервьюер: Очень хорошо, тогда не могли бы вы рассказать о процессе полного и частичного копирования?
-
Я могу
Выше описан процесс полной репликации. В основном это следующие шаги:
1. Подчиненный узел отправляет команду psync ?-1 (поскольку это первая отправка, он не знает runId главного узла, поэтому это ?, поскольку это первая репликация, поэтому смещение=-1 ).
2. Главный узел обнаруживает, что подчиненный узел выполняет репликацию в первый раз, и возвращает FULLRESYNC {runId} {offset}, где runId — это runId главного узла, а offset — текущее смещение главного узла.
3. После получения информации о главном узле от подчиненного узла сохраните ее в файле info.
4. После того, как главный узел отправляет FULLRESYNC, он запускает команду bgsave для создания файла RDB (сохранение данных).
5. Главный узел отправляет файл RDB подчиненному узлу. Команда записи главного узла помещается в буфер в течение периода, пока подчиненный узел не загрузит данные.
6. Очистите свои собственные данные базы данных от узла.
7. Загрузите файл RDB с узла и сохраните данные в собственной базе данных.
8. Если подчиненный узел включает AOF, подчиненный узел асинхронно перезапишет файл AOF.
Несколько замечаний о частичной репликации:
1. Частичная репликация — это в основном мера оптимизации, сделанная Redis для больших накладных расходов полной репликации, которая реализуется с помощью команды psync[runId][offset]. Когда подчиненный узел реплицирует главный узел, в случае возникновения нештатной ситуации, такой как сетевая вспышка или потеря команды, подчиненный узел запросит у главного узла повторный выпуск потерянных данных команды, и буфер невыполненной репликации главного узла отправит это напрямую. часть данных на подчиненные узлы, чтобы можно было поддерживать согласованность репликации между ведущими и подчиненными узлами. Эта часть перевыпущенных данных, как правило, намного меньше, чем полный объем данных.
2. Во время прерывания соединения master-slave мастер-узел все еще отвечает на команду, но команда не может быть отправлена на подчиненный узел из-за прерывания соединения репликации. все еще можно сохранить данные команды записи последнего периода.
3. При восстановлении соединения master-slave, поскольку подчиненный узел ранее сохранил собственное реплицированное смещение и текущий идентификатор главного узла. Поэтому они отправляются мастеру в качестве параметров psync, запрашивая частичную репликацию.
4. После того, как мастер-узел получил команду psync, он сначала проверяет, согласован ли параметр runId с самим собой, если он согласован, это означает, что текущий мастер-узел был скопирован ранее, затем он ищет в буфере невыполненных копий в соответствии с смещение параметра.Если данные после смещения существуют, то отправьте команду +COUTINUE подчиненному узлу, указывающую, что частичная репликация может быть выполнена. Поскольку размер буфера фиксирован, в случае переполнения буфера выполняется полное копирование.
5. Главный узел отправляет данные из буфера невыполненной репликации подчиненному узлу в соответствии со смещением, чтобы убедиться, что репликация ведущий-ведомый переходит в нормальное состояние.
часовой
-
Интервьюер: Какие проблемы с репликацией master-slave?
-
Я: Репликация master-slave будет иметь следующие проблемы:
1. Как только главный узел выходит из строя, подчиненный узел повышается до главного узла.В то же время адрес главного узла на стороне приложения необходимо изменить, и всем подчиненным узлам необходимо приказать скопировать новый главный узел Весь процесс требует ручного вмешательства.
2. Возможность записи главного узла ограничена одной машиной.
3. Емкость хранилища главного узла ограничена одной машиной. 4. Недостатки нативной репликации заметны и в более ранних версиях: например, после прерывания репликации redis подчиненный узел инициирует psync. В это время, если синхронизация не удалась, будет выполнена полная синхронизация.Когда основная база данных выполняет полное резервное копирование, это может вызвать задержку в миллисекунды или секунды. -
Интервьюер: Какое решение более распространено?
-
Я: Сентинел, конечно.
-
Интервьюер: Итак, снова вопрос. Итак, каковы функции часового?
-
Я: Как показано на рисунке, это схема архитектуры Redis Sentinel. Основные функции Redis Sentinel включают в себя обнаружение выживаемости главного узла, обнаружение операций ведущий-ведомый, автоматическое переключение при сбое и переключение ведущий-ведомый. Минимальная конфигурация Redis Sentinel — один ведущий и один подчиненный сервер. Система Redis Sentinel может использоваться для управления несколькими серверами Redis.Система может выполнять следующие четыре задачи:
1. Мониторинг: постоянно проверяйте, нормально ли работают главный сервер и подчиненный сервер.
2. Уведомление. При возникновении проблемы с отслеживаемым сервером Redis Sentinel отправляет уведомление администратору или другим приложениям через сценарий API.
3. Автоматический переход на другой ресурс: если главный узел не работает нормально, Sentinel запускает операцию автоматического перехода на другой ресурс, он обновляет один из подчиненных узлов, который находится в отношениях ведущий-ведомый с вышедшим из строя главным узлом, на новый главный узел и will other Ведомый узел указывает на новый главный узел, так что можно избежать ручного вмешательства.
4. Поставщик конфигурации: в режиме Redis Sentinel клиентское приложение подключается к набору узлов Sentinel во время инициализации и получает от него информацию о главном узле. -
Опрашивающий: Тогда не могли бы вы рассказать мне, как работает Страж?
-
Я: Нечего сказать, просто перейдите к картинке:
2. Если экземпляр превышает значение, указанное в миллисекундах вниз после последнего действительного ответа на команду PING, то экземпляр будет помечен Sentinel как субъективно отключенный. (на фото выше)
3. Если главный сервер помечен как субъективно отключенный, то все узлы Sentinel, отслеживающие этот сервер, должны подтверждать, что главный сервер действительно перешел в субъективное автономное состояние с частотой один раз в секунду. 4. Если главный сервер помечен как субъективно отключенный, и достаточное количество Стражей (по крайней мере, количество, указанное в файле конфигурации) согласны с этим суждением в течение указанного периода времени, то главный сервер помечен как объективный отключенный. 5. При нормальных обстоятельствах каждый Sentinel отправляет команды INFO всем известным ему главным серверам и подчиненным серверам с периодичностью каждые 10 секунд. Когда главный сервер помечен как объективно отключенный, Sentinel отключается от главного сервера. при которой все команды INFO отправляются с сервера, будет изменено с одного раза в 10 секунд на один раз в секунду. 6. Sentinel и другие Sentinel согласовывают статус главного узла, который объективно находится в автономном режиме.Если он находится в состоянии SDOWN, новый главный узел будет автоматически выбран голосованием, а оставшиеся подчиненные узлы будут направлены на новый главный узел. для репликации данных. 7. Когда Sentinel недостаточно, чтобы согласиться на автономный режим основного сервера, объективный автономный статус основного сервера будет удален. Когда первичный сервер возвращает действительный ответ на команду Sentinel PING, субъективный статус основного сервера в автономном режиме будет удален.-
Интервьюер: Да, я проделал большую работу перед интервью. Вы сегодня прошли вопрос Redis. О других вещах мы поговорим завтра в какое-то время. (с облегченной улыбкой)
-
Я в порядке.
Суммировать
В процессе интервью в этой статье описывается, что такое Redis, характеристики и функции Redis, использование кеша Redis, почему Redis такой быстрый, стратегия устранения кеша Redis, два метода сохранения и мастер-классы. подчиненная часть высокодоступной части Redis Rationale для репликации и дозорных. Пока вы усердно работаете, перемалываете железный пестик в иглу и готовитесь в обычное время, вам не нужно паниковать перед собеседованием. Хотя интервью не обязательно задается таким образом, оно всегда неотделимо от своего «зонга». (Автор считает, что такой формат блога с вопросами и ответами очень хорош, он легко читается, а постскриптум более глубокий)
Справочная статья
nuggets.capable/post/684490…
nuggets.capable/post/684490…