[BE / 로비서버] Redis map 데이터 동시성 접근 오류, 성능 저하
Closed this issue · 1 comments
Tae-Hyeon commented
기존 방식
- map을 String으로 저장하다보니 sync 시 redis의 String형 map 데이터를 가져와서 MapDto Object로 변환해줌
- 변환 자체의 로직은 문제 없으나 동시에 접근하면서 문제가 발생함
- 성능적으로 필요 없는 map 데이터를 많이 불러와서 변환(Deserialize)하는 것은 문제
- 현재 sync는 맵 업데이트, 입장 시의 데이터 동기화를 위해 자주 호출되지는 않음
- move에 따른 동기화가 많이 필요하다면 문제
- map을 필요할때만 불러오고, 평상시에는 map을 제외한 로딩이 필요함
해결 방법 생각
- redisTemplate를 이용한 직접적인 쿼리
- template.opsForValue().set("key", "value");
Tae-Hyeon commented
Before Code
public synchronized void moveUserInRedis(String roomId, String movedUserId, Direction direction) {
Optional<RoomCache> opRoomCache = roomCacheRepository.findById(roomId);
RoomCache roomCache;
if(opRoomCache.isPresent()) {
roomCache = opRoomCache.get();
roomCache.moveUser(movedUserId, direction);
roomCacheRepository.save(roomCache);
}
}
public synchronized void moveUser(String userId, Direction direction) {
this.getUsers().get(userId).move(direction, Integer.parseInt(JsonUtil.parse(this.map, "side").toString()));
}
public void move(Direction direction, Integer max) {
switch (direction) {
case UP:
if(y < max)
y++;
break;
case RIGHT:
if(x < max)
x++;
break;
case DOWN:
if(y > 0)
y--;
break;
case LEFT:
if (x > 0)
x--;
break;
}
}
after code
public synchronized void moveUserInRedis(String roomId, String movedUserId, Direction direction) {
HashOperations<String, String, Integer> hash = redisTemplate.opsForHash();
String mainKey = "library:1";
String hashKey = "users.[" + movedUserId + "].";
switch (direction) {
case UP:
hashKey += 'y';
if(hash.get(mainKey, hashKey) < MAX_SIDE_OF_MAP)
hash.increment(mainKey, hashKey, 1);
break;
case RIGHT:
hashKey += 'x';
if(hash.get(mainKey, hashKey) < MAX_SIDE_OF_MAP)
hash.increment(mainKey, hashKey, 1);
break;
case DOWN:
hashKey += 'y';
if(hash.get(mainKey, hashKey) > 0)
hash.increment(mainKey, hashKey, -1);
break;
case LEFT:
hashKey += 'x';
if(hash.get(mainKey, hashKey) > 0)
hash.increment(mainKey, hashKey, -1);
break;
}
}