-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[QUZ-83][FEATURE] 게임 랜덤 매칭 구현 #34
base: develop
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
벡터랑 SSE가 저한텐 생소한 개념이라 궁금한거 질문 달았습니다.
Redis에서 벡터를 지원하는건가요 아니면 그냥 벡터DB처럼 사용 할 수 있게 한건가요..? 어렵네영
|
||
@GetMapping( | ||
value = ["/subscribe"], | ||
produces = [MediaType.TEXT_EVENT_STREAM_VALUE] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이게 sse 쓸 때 필요한건가요 ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵 맞습니당 저 옵션을 주면 연결 유지하면서 서버에서 이벤트 스트림으로 보내줄 수 있어요!
return UserVector( | ||
FloatArray(vectorSize).apply { | ||
this[rating.index] = 1.0f | ||
interests.forEach { this[it.index + GameRating.entries.size] = 1.0f } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이렇게 하면 vector db처럼 쓰는건가요..?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
저 로직 자체는 매칭할 사용자 정보를 벡터화해서 레디스에 저장하기 위해
레이팅이랑 관심 분야 값을 벡터로 전처리하는 로직입니당
데이터를 벡터로 변환하는 로직..? 이라고 보시면 될 거 같아용
@Bean | ||
fun userStatusTemplate(): RedisTemplate<String, RedisUserStatus> { | ||
val redisTemplate = RedisTemplate<String, RedisUserStatus>() | ||
redisTemplate.connectionFactory = redisConnectionFactory | ||
redisTemplate.keySerializer = StringRedisSerializer() | ||
redisTemplate.valueSerializer = Jackson2JsonRedisSerializer(RedisUserStatus::class.java) | ||
return redisTemplate | ||
} | ||
|
||
@Bean | ||
fun userIdTemplate(): RedisTemplate<String, String> { | ||
val redisTemplate = RedisTemplate<String, String>() | ||
redisTemplate.connectionFactory = redisConnectionFactory | ||
redisTemplate.keySerializer = StringRedisSerializer() | ||
redisTemplate.valueSerializer = StringRedisSerializer() | ||
return redisTemplate | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이거 템플릿 각각 따로 지정하는 이유가 있나요 ??
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
첫 번째 템플릿은 data class를 redis 리스트에 추가하는 용이고
두 번째 템플릿은 그냥 userId 값을 set에 저장하려고 구분한거긴 합니다..!
딱히 이유가 있다기 보단 그냥 저장하는 데이터 타입이 달라서 나눠야하지 않을까 싶긴 했는데 안 나눠도 되나용?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
그냥 redisTemplate 하나 만들어두고 넣을 때 직렬화하는게 낫지않나요...?
어떤거는 Jackson으로 하고 어떤건 String으로 하시고 계속해서 객체가 생기면 Bean을 주입해줘야하지않나요? 객체마다 Config가 늘어나는거도 뭔가 좋지않은구조아닌가 싶어서..
저는 그래서 그냥 하나로 만들고 직렬화하고있어요
val keyPattern = "$MATCHING_POOL_KEY:*" | ||
val keys = redisTemplate.keys(keyPattern) ?: return emptyList() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이거 사실 잘 모르긴하는데 Redis 사용할 때 하지 말아야 될 1번이 keys 사용하기라고 하더라구요
keys 사용하는 대신 scan을 사용하는게 좋다고 하더라구요 싱글스레드기반이라 keys 사용시 모든 키를 가져오기 때문에 모든 요청이 밀릴수도 있다고 합니다...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵 맞습니다....
말씀해주신거처럼 지금 구현된 로직은 메모리나 성능상 문제가 많아서
PR에 언급한 RediSearch를 사용해서 쿼리로 데이터를 가져오는 방법을 찾고 있어용
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이게 애초에 벡터DB가 아닌데 벡터DB처럼 쓰기 위해서 일단 전부 다 가져오고 비슷한걸 찾는 로직으로 구현하셔서 그런건가요 ??
레디스자체가 벡터를 지원을 안해서 그냥 Hash로 집어넣은 채로 꺼내서 이렇게 되는거죠..?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵 일단 지금 구현은 그런 식이에요..!
레디스가 벡터를 지원하긴 합니다! 그런데 그러려면 RediSearch라는 모듈을 사용하고
서버에서도 Lettuce나 Jedis 같은 걸로 직접 쿼리문을 작성해서 사용하는 걸로 알고 있어용
약간 이런식입니당 Redis Vector Search
이거 PR 올리기 전에 시도 해봤는데 뭐가 잘 안돼서,,, 일단 보류했다가 뭔가 원인을 찾은 거 같아서 지금 다시 해보고 있습니당
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
레디스에 그냥 깡 레디스말고도 신기한게 되게 많네요.. 구현 잘되면 한번 저도 배워보겠습니다 ! 화이팅입니다
지금은 그냥 순수 레디스에 벡터를 그냥 해시 형태로 저장해서 서버 단에서 처리하고 있어요 그래서 지금처럼 그냥 냅다 데이터 긁어와서 서버에서 필터링 하는 거 말고 레디스 쿼리로 KNN 같은 알고리즘으로 조회할 수 있다고 해용 |
✨ 구현 기능 명세
✅ PR Point
전반적인 랜덤 매칭 플로우 및 알고리즘은 다음과 같이 구현했습니다.
위 로직에서 각각의 Redis 자료구조는 다음과 같은 용도로 사용됩니다.
😭 어려웠던 점
지금 로직은 사용자 정보 벡터를 직접 Redis Hash로 저장하고, 매칭 후보를 찾을 때 전부 조회한 뒤 서버 상에서 필터링하고 있습니다.
이게 메모리 상에 부담이 될 거 같아 RediSearch 모듈을 통해 Redis 자체에서 KNN으로 조회하는 쿼리를 사용하려고 했는데,
오류가 너무 많이 나서 일단 보류하고 추후에 더 알아보고 리팩토링하려 합니다.