STOVE-Milk/steam-clone

[BE / 로비서버] 유저 기존 세션 유지한 채 다른 세션으로 재입장 시 기존 세션 끊기

Closed this issue · 9 comments

방법 찾기

  • 현재 구조에서 가능한 방법을 찾지 못하겠다.
  • 로비 서버가 여러개라 기존 세션과 다른 세션이 각각 다른 서버에 연결될 수 있다.
    • 이게 가장 문제
  • 방법 1
    • 유저가 입장할 때, 유저의 세션 id를 유저id-세션id 로 Redis에 저장한다.
    • 유저가 입장할 때, Redis의 정보를 가져와 유저-세션이 존재한다면 세션 close를 한다.
      • publishing을 통해 유저 입장 메세지에 세션 id를 같이 날린다.
      • 다른 서버에서 세션 id를 통해 방 정보를 찾고 해당 방의 유저 정보를 삭제하고 세션을 종료한다.
      • 문제 발생
        • 같은 방에 재입장 했을 경우 문제가 발생한다.
        • publishing한 메세지를 늦게 받을 경우, 방에 입장했고, 새로운 세션이 생겼지만, 다른 유저는 나갔다는 메세지를 늦게 받게된다.
          • 이 때문에, 결론적으로 유저가 나가버리는 문제가 발생한다.

세션-방 관계 컬렉션이 있으니까, 이를 가지고 입장하는 방과, 세션에 해당하는 방이 같으면 나가기 메세지를 보내지 않도록 할까?

  • 이렇게 하면 중복 입장이 될수도 있다. --> 입장 메세지도 전파하지 않으면 되나?
    • 서버가 같다면 처리가 되지만, 다른 서버들에서는 중복 입장이 될 것 같다.

레디스에 세션id + 방 id를 모두 저장하면 입장 시 입장 방 id와 레디스 정보를 비교하여 메세지 전송 여부를 분기 처리하면?

  • 다른 방에 있으면 그대로 보내서 나가도록 처리하면 되고, 같은 방이면 사실상 세션 정보만 바뀌고, 나가진 않는다.
  • 대신 다른 서버에서 기존 세션에 해당하는 정보를 삭제하도록 새로운 메세지가 필요?
    • 다른 방에 입장 시 - 입장 메세지의 기존 세션id를 통해 나가기 처리
    • 같은 방에 입장 시 - 세션 정보만 삭제하고, closeConnection 메소드가 아닌 session close
      • 삭제할 것
      • session_room
      • user_session Map (같은 서버일 경우 갱신되기 때문에 필요한가?)
        • 서버가 다를 경우를 어떻게 판단해야하나
      • room 내의 sessions Map (이것도 마찬가지로 갱신되기 때문에 필요한가?)
        • 서버가 다를 경우를 어떻게 판단해야하나
      • userData Map

STOMP의 구조를 생각하면 해결할 수 있지 않을까?

  • 유저마다 특정 방에 대해 subscribe하게된다.
  • RabbitMQ의 topic을 잘 활용하면 될 것 같다.
  • 지금까지는 fanout방식으로 사용하고 있었다.
    • 로드밸런싱을 샤딩처럼 할 수 있을까? --> 같은 서버에 유저를 몰아두면 편하지 않을까?
    • 유저 수가 많은데 이에 따라 구역을 나눌 수 있을까?
  • STOMP는 동적으로 queue를 생성한다.
  • 이것을 따로 구현하기에는 어려움이 있다.
  • 좀 비효율적이지만 필터링을 잘 거치면 임시 해결은 될 것 같다.
  • 새 브랜치를 파서 수정을 해봐야겠다.

현재 생각하는 로직

Session Storage 이용 - Redis

  • 입장 시 Redis에 userId-sessionId,roomId를 저장해 놓는다
  • 유저가 입장하면 userId를 키로 Redis에서 값을 가져온다.
  • 이미 유저가 세션이 등록되어 있다면, 세션 클로징 메세지를 발행한다.
  • 세션 클로징 메세지 내용
    • postRoomId|USER_MULTI_ENTER|data
    • data
      • preSessionId,, postSessionId, preRoomId
    • 세션 클로징 단계 (preSessionId가 있다면 아래 로직 실행)
      • userId-sessionId
        • preSessionId value가 있다면 삭제
      • sessionId-userDetails
        • preSessionId key가 있다면 삭제
      • sessionId-roomId
        • preSessionId key가 있다면 삭제
      • roomId-room
        • sessionId-session
          • preSessionId가 있다면 session 클로즈 & 삭제
        • userId-userDto
          • sessionId-session에 postSessionId가 Key로 없으면 삭제

같은 방에 입장은 막고 다른 방의 입장은 커넥션을 끊는다?

생각해보니 다른 방에 중복 입장은 크게 상관이 없을지도?
서버에서 유저 당 하나의 세션 정보를 유지한다.

  • 이것도 기존 세션을 끊는 용도로 사용할 것이었기 때문에, 없애면 그만?
  • 실제로 코드를 체크해 봤을 때, 끊는 용도가 아니면 사용을 하지 않는다.
  • 세션 id를 키로 갖고있는 컬렉션이 있기도 하고, 레디스에 상태를 저장한다면, 굳이 필요 없는 컬렉션이다.

그래도 입장을 막는 것은 아니라고 생각해서 다른 방에 접근할 때는 허용하되, 같은 방에 중복 입장할 경우에 기존 세션을 끊는 것으로 해결했다.