SNS 에서 활용 예시
개요
Redis는 고성능 읽기 및 쓰기 기능을 제공하여 소셜 앱에 기대되는 기능을 지원하므로 소규모 팀이 빠르게 출시하고 반복할 수 있습니다.
Redis는 주요 소셜 네트워크 규모로 확장되지 않을 수 있지만 상당한 사용자 증가를 통해 앱의 첫 번째 버전을 강화할 수 있습니다.
구성
먼저 Spring Boot 프로젝트를 설정하고 필요한 종속성을 추가합니다. spring-boot-starter-data-redis를 사용하여 Redis를 통합합니다. 이렇게하면 Redis 서버와의 연결 및 상호 작용이 가능합니다.
1. User Profile
각 사용자 프로필을 Redis 해시로 나타낼 수 있습니다. 여기서 키는 사용자 ID이고 해시 필드에는 프로필 속성이 포함됩니다.
관계형 모델과 비교하여 Redis Hash는 나중에 데이터베이스 스키마를 수정하지 않고도 새 프로필 속성을 쉽게 추가할 수 있는 유연성을 제공합니다. 데이터베이스 스키마 변경을 거칠 필요가 없기 때문에 사용자 프로필에 더 많은 속성을 검색하고 추가하는 방법을 정의하기만 하면 됩니다.
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@Service
public class UserProfileService {
private final String USER_PROFILE_KEY = "user:%s";
private final RedisTemplate<String, String> redisTemplate;
private final HashOperations<String, String, String> hashOperations;
public UserProfileService(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
this.hashOperations = redisTemplate.opsForHash();
}
public void saveUserProfile(String userId, String name, String location, String interests) {
String key = String.format(USER_PROFILE_KEY, userId);
hashOperations.put(key, "name", name);
hashOperations.put(key, "location", location);
hashOperations.put(key, "interests", interests);
}
public UserProfile getUserProfile(String userId) {
String key = String.format(USER_PROFILE_KEY, userId);
String name = hashOperations.get(key, "name");
String location = hashOperations.get(key, "location");
String interests = hashOperations.get(key, "interests");
return new UserProfile(name, location, interests);
}
}
2. User Relationships
Redis는 내장된 Set 데이터 구조를 사용하여 사용자 관계를 표현하는 보다 자연스러운 방법을 제공합니다.
Redis에서는 사용자 ID를 키로 사용하여 사용자의 친구 ID를 Set에 직접 저장할 수 있습니다. 사용자의 친구를 검색하는 것은 ZSet의 구성원을 반환하는 것만큼 간단합니다.
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.stereotype.Service;
@Service
public class UserRelationshipService {
private final String USER_FRIENDS_KEY = "user:friends:%s";
private final RedisTemplate<String, String> redisTemplate;
private final SetOperations<String, String> setOperations;
public UserRelationshipService(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
this.setOperations = redisTemplate.opsForSet();
}
public void addFriend(String userId, String friendUserId) {
String key = String.format(USER_FRIENDS_KEY, userId);
setOperations.add(key, friendUserId);
}
public boolean areFriends(String userId, String friendUserId) {
String key1 = String.format(USER_FRIENDS_KEY, userId);
String key2 = String.format(USER_FRIENDS_KEY, friendUserId);
return setOperations.isMember(key1, friendUserId) && setOperations.isMember(key2, userId);
}
}
3. Posts
사용자에 대해 타임스탬프별로 정렬된 정렬 세트에 post_ids를 저장할 수 있습니다. 키는 사용자 ID가 될 수 있으며 각각의 새로운 post_id는 Set의 멤버로 추가됩니다. 게시물 콘텐츠 자체는 post_id를 해시 키로 사용하여 해시에 별도로 저장됩니다.
사용자가 새 게시물을 생성하면 새 post_id가 생성되고, 게시물 콘텐츠를 나타내는 해시가 생성되며, 사용자의 게시물 정렬 집합에 post_id가 추가됩니다. 이는 게시 타임라인을 모델링하는 자연스러운 방법을 제공합니다. 새로운 post_ids가 Set의 꼬리에 추가되고 post_ids의 ZRANGE를 사용하여 시간순으로 정렬된 게시물을 페이지로 이동할 수 있습니다.
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.stereotype.Service;
@Service
public class UserPostService {
private final String USER_POSTS_KEY = "user:posts:%s";
private final String POSTS_HASH_KEY = "post:%s";
private final RedisTemplate<String, String> redisTemplate;
private final ZSetOperations<String, String> zSetOperations;
private final HashOperations<String, String, String> hashOperations;
public UserPostService(RedisTemplate<String, String> redisTemplate) {
this.redisTemplate = redisTemplate;
this.zSetOperations = redisTemplate.opsForZSet();
this.hashOperations = redisTemplate.opsForHash();
}
public void createPost(String userId, String postId, String message) {
String userPostsKey = String.format(USER_POSTS_KEY, userId);
String postHashKey = String.format(POSTS_HASH_KEY, postId);
zSetOperations.add(userPostsKey, postId, System.currentTimeMillis());
hashOperations.put(postHashKey, "user_id", userId);
hashOperations.put(postHashKey, "timestamp", String.valueOf(System.currentTimeMillis()));
hashOperations.put(postHashKey, "message", message);
}
public List<UserPost> getUserPosts(String userId) {
String userPostsKey = String.format(USER_POSTS_KEY, userId);
Set<String> postIds = zSetOperations.reverseRange(userPostsKey, 0, -1);
List<UserPost> userPosts = new ArrayList<>();
for (String postId : postIds) {
String postHashKey = String.format(POSTS_HASH_KEY, postId);
String message = hashOperations.get(postHashKey, "message");
String timestamp = hashOperations.get(postHashKey, "timestamp");
userPosts.add(new UserPost(postId, message, Long.parseLong(timestamp)));
}
return userPosts;
}
}
Top comments (0)