DEV Community

NeNoVen
NeNoVen

Posted on

Redis storage 활용

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);
    }
}

Enter fullscreen mode Exit fullscreen mode

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);
    }
}

Enter fullscreen mode Exit fullscreen mode

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;
    }
}

Enter fullscreen mode Exit fullscreen mode

Top comments (0)