NodeJS кластер сокет.IO как правильно создать игровую комнату?

#node.js #redis #socket.io #node-cluster

#node.js #redis #socket.io #узел-кластер

Вопрос:

Я создаю простой игровой движок, который реализует управление комнатой.

Я много думал и все еще сомневаюсь, что я создаю комнаты не так, как нужно.

Вот сценарий.

1) There's one static room, where users are able to 'register'.
2) after certain number of users are registered, it should create dynamic room and put these certain number of users in that room and make them quit the static room.

Итак, если мы запустим это в нескольких экземплярах и, допустим, мы ждем 2 пользователей.

2 пользователя присоединяются к статической комнате -> создать новую комнату (в redis) -> ввести этих двух игроков в эту комнату (подписаться) -> заставить этих игроков покинуть статическую комнату (система, подобная очереди).

Теперь то, что я думаю, является проблемой.

2 пользователя присоединяются к статической комнате -> перед созданием новой комнаты еще один игрок присоединяется к статической комнате (другой экземпляр узла) -> создать новую комнату -> переместить туда двух игроков -> другой экземпляр все еще думает, что пользователей достаточно для создания новой комнаты -> происходит что-то странное.

Правильно ли это? Как я должен реализовать комнату в стиле очереди?

Ответ №1:

Вам нужны атомарные операции: поместите все эти 4 шага в транзакцию. С Redis вы можете использовать для этого сценарии транзакций или Lua.

С помощью сценариев lua у вас может быть такой сценарий:

 -- add new user to static room
redis.call('lpush', 'static_room', ARGV[1])

-- if the number of static room reaches the limit
local num = redis.call('llen', 'static_room')
if num == 2  then
    -- get the room number for a new dynamic room
    local new_dynamic_room_num = redis.call('incr', 'dynamic_room');
    local dynamic_room = 'dynamic_room' .. new_dynamic_room_num

    -- move all users from static room to dynamic room
    while true do
        local num = redis.call('llen', 'static_room')

        if num == 0 then break end

        redis.call('rpoplpush', 'static_room', dynamic_room)
    end
end
 

Поскольку сценарий lua выполняется атомарно, ни один другой пользователь не сможет присоединиться к статической комнате, пока мы не закончим перемещение всех пользователей из статической комнаты в динамическую комнату.

Комментарии:

1. Вы абсолютно правы, но я хотел бы знать, есть ли какой-либо собственный способ javascript сделать это атомарно?

Ответ №2:

Решением может быть заставить всех не подключенных игроков входить в один уникальный экземпляр узла, который отвечает за создание комнат и назначение игроков в эти комнаты. Затем, как только они назначены для данной комнаты, он перенаправляет их на экземпляр узла, отвечающий за эту комнату.

Комментарии:

1. Тогда нет смысла использовать кластер узлов.

2. Это имеет смысл, потому что первый экземпляр — это просто точка входа. Как только пользователь попадает в комнату, она будет обработана другим экземпляром в кластере.

3. Так что, я думаю, это должен быть мастер? Или как я могу это сделать, я даже не знаю, к какому экземпляру узла подключается клиент

4. Да, первое соединение может быть выполнено с ведущим с помощью классического http-запроса; затем вы открываете websocket между дочерним элементом и клиентом.