Сначала, а затем прочитайте, Брат Нэн поможет вам получить более половины ваших навыков Java.
Заградительный огоньСистема зародилась в Японии.,Популярно на видеосайтахniconico。Хацунэ Мику, которую мы знаем(Hatsune Miku)Просто тамniconico
Популярно на платформе!!
Я брат Нэн, лидер в области изучения и развития Java. Я верю, что вам будет полезно пройти собеседование и получить предложение поступить в компанию, о которой вы мечтали.
⭐⭐⭐Эта статья включена в《Javaизучать/Передовой/Руководство по собеседованию》:https://github..JavaSouth
Южные друзья, обратите внимание на Заградительный в правом нижнем углу. список огней,Этот список Заградительный огонь — это то, что мы хотим покорить сегодня.,至于中间视频直播的走马灯Заградительный огонь
,На самом деле оно основано на Заградительный данные списка огня для прокрутки.
Брат Нэн наблюдал за этой комнатой прямой трансляции.,Теперь есть415 000
люди смотрят!
Компьютерный мир на самом деле является абстракцией реального мира, так какую структуру данных нам следует использовать для поддержки заграждающего списка?
Я надеюсь использовать Redis. Официальный слоган Redis имеет такой властный лозунг.
Get the world’s fastest in-memory database from the ones who built it
Получите самую быструю в мире базу данных в памяти от конструктора
Что касается базовой структуры данных, мы используем один из пяти основных типов данных Redis: Zset. Zset — это тип упорядоченного набора. Он имеет значение оценки. Значение оценки используется для хранения отметки времени комментария пользователя. Затем весь список будет отсортирован в соответствии с отметкой времени.
Значение элемента Zset используется пользователем Заградительный огонь,Например, тот, что на фото выше:Сценарий воспроизводится снова и снова
。
Учитывая поддержку базовой структуры данных, давайте поговорим о функциональных ограничениях этого заградительного списка. Вы заметили, что когда мы входим в комнату прямой трансляции, в комнате прямой трансляции не будет отображаться весь контент заграждения?
Часто отображаются только первые 10 элементов.
Затем мы также добавляем эту функцию в список блокировки и сохраняем атрибуты только первых 10 элементов в структуре Zset Redis.
// Создайте структуру данных Zset и установите ограничение в 10 элементов.
public class DanmakuService {
private Jedis jedis = new Jedis("localhost");
public void addDanmaku(String roomId, String danmaku, long timestamp) {
String key = "room:" + roomId + ":danmaku";
jedis.zadd(key, timestamp, danmaku);
// Сохраняйте только последние 10 Заградительный огонь
jedis.zremrangeByRank(key, 0, -(11));
}
}
Когда пользователь входит в комнату прямой трансляции, как запрашивается список заграждений?
Мы придерживаемся самого простого и эффективного подхода. Когда пользователь входит в комнату прямой трансляции, клиент вызывает интерфейс API для запроса списка заграждений в Redis.
Некоторые друзья могут спросить: это только первые 10 последних записей чата, а что насчет остальных?
Не волнуйтесь, есть два варианта.
(1) Опросный запрос
Клиент опрашивает интерфейс API и постоянно фиксирует новые сообщения, отправленные пользователями. огонь. Для получения более подробной информации клиент сначала спросил о Заградительный. список огней的数据结构是:[(Временная метка1: Заградительный огонь 1), (Отметка времени 2: Заградительный огонь2)]
。
Последующий клиент запроса продолжает опрашивать и вызывать интерфейс API, передавая текущий Заградительный список огней的Максимальный входной параметр временной метки。而后端服务就会根据该Временная метка返回比该Временная метка大的数据,Новый Заградительный, присланный пользователями Также будет отображаться огонь.
// API-интерфейс опроса
public class DanmakuService {
private Jedis jedis = new Jedis("localhost");
public Set<String> getRecentDanmaku(String roomId, long lastTimestamp) {
String key = "room:" + roomId + ":danmaku";
return jedis.zrangeByScore(key, lastTimestamp + 1, Long.MAX_VALUE);
}
}
Как часто нам нужно устанавливать время опроса для API опроса? Давайте сначала настроим 3 секунды
Проголосуйте за обновления один раз Заградительный список огней, который позже будет оптимизирован и скорректирован на основе отзывов пользователей и ресурсов сервера.
(2) Технология WebSocket
Особенностью комнаты прямой видеотрансляции является то, что ведущий и зрители постоянно взаимодействуют и общаются, что требует синхронизации аудио и видео в реальном времени. Тогда прямая трансляция должна осуществляться в режиме реального времени. Используя первый метод API опроса, это может быть. 3 секунды延迟
的情况发生。
Чтобы отправлять новые заграждения в реальном времени, мы можем использовать технологию WebSocket. Клиент и сервер WebSocket сохраняют длительное соединение. Пока пользователь отправляет новое сообщение заграждения, сервер WebSocket будет отправлять его клиенту в реальном времени.
Хотя первый метод является грубым, если запрос опроса будет пустым, то этот запрос является пустой тратой ресурсов и небезопасен для ресурсов сервера. Но это просто и эффективно, с небольшим количеством ошибок.
Если ваш начальник хочет, чтобы вы за полмесяца запустили эту функцию списка заграждений, то первый способ — неплохая идея. В будущем мы будем разрабатывать стратегии обновления и настройки, основанные на реальных условиях, например, переход на технологию WebSocket.
Брат Нэн нарисовал процесс всей системы.
Пользователи отправляют заграждения через клиент, а сообщения о заграждениях отправляются в Kafka через серверную службу. Используя сообщения Kafka, мы можем сократить пиковый трафик. Сообщения заграждения иногда исчисляются десятками тысяч в секунду. Задача хранения сообщений заграждения кэшируется в очереди сообщений и выполняется одно за другим, что снижает мгновенную высокую нагрузку на сервер.
После отправки в Kafka серверная служба, отвечающая за мониторинг заграждающих сообщений Kafka, записывает заграждающие сообщения в Redis.
// Монитор пишет в Redis
public class DanmakuListener {
private Jedis jedis = new Jedis("localhost");
@KafkaListener(topics = "danmaku", groupId = "group_id")
public void listen(ConsumerRecord<String, String> record) {
String roomId = record.key();
String message = record.value();
long timestamp = System.currentTimeMillis();
String key = "room:" + roomId + ":danmaku";
// Воля Заградительный Огонь Сообщение, отправленное в Redis Zset
jedis.zadd(key, timestamp, message);
// Сохраните последние 10 элементов
jedis.zremrangeByRank(key, 0, -11);
}
}
Есть такая ситуация,пользовательAОтправил(1726406132, Заградительный огоньA)
,пользовательBОтправил(1726406150, Заградительный огоньB)
,Пользователь A первый отправил Заградительный огонь, затем пользователь Б отправляет Заградительный огонь。
Если заграждения пользователя B сначала записываются в список Zset Redis, другие пользователи входят в комнату прямой трансляции, чтобы запросить первый список заграждений. Даже если пользователь А успешно напишет блокировку позже, другие пользователи не получат блокировку пользователя А.
Потому что клиент будет обновлять только сообщения о заграждении с меткой времени, большей, чем заграждение B. Как с этим справиться?
Мы хотим решить проблему, заключающуюся в том, что блокировка B успешно записывается до блокировки A. Независимо от других особых обстоятельств, мы можем добавить функцию распределенной блокировки к методу записи в Redis, чтобы гарантировать, что блокировка будет получена первой, а сообщение о блокировке будет получено первым. Во время этого процесса не будет никаких помех от написания других сообщений.
// Письмо Заградительный Получить распределенную блокировку, когда огонь
public class DanmakuService {
private RedisLockUtil redisLock = new RedisLockUtil();
private Jedis jedis = new Jedis("localhost");
public void addDanmakuWithLock(String roomId, String danmaku, long timestamp) {
String lockKey = "lock:" + roomId;
try {
if (redisLock.acquireLock(lockKey)) {
String key = "room:" + roomId + ":danmaku";
jedis.zadd(key, timestamp, danmaku);
jedis.zremrangeByRank(key, 0, -11);
}
} finally {
redisLock.releaseLock(lockKey);
}
}
}
public class RedisLockUtil {
private Jedis jedis = new Jedis("localhost");
private static final int EXPIRE_TIME = 5000; // 5 секунд
// Получить блокировку
public boolean acquireLock(String lockKey) {
long currentTime = System.currentTimeMillis();
String result = jedis.set(lockKey, String.valueOf(currentTime), "NX", "PX", EXPIRE_TIME);
return "OK".equals(result);
}
// разблокировать замок
public void releaseLock(String lockKey) {
jedis.del(lockKey);
}
}
Я Брат Нэн, Нэн — это Нэн. Я нашла ваши интересные комментарии на Get➕Like➕Follow.
Творить непросто, поэтому вы можете ставить лайки, собирать и подписываться, чтобы поддержать его. Ваша поддержка — самая большая мотивация для моего творчества.❤️