Post

๋ง›๋™์‚ฐ๐ŸŽ…ย ๋™ํ™” ์บ์‹œ ์‹œ์Šคํ…œ ๊ตฌ์ถ•ํ•˜๊ธฐ

๋ง›๋™์‚ฐ๐ŸŽ…ย ๋™ํ™” ์บ์‹œ ์‹œ์Šคํ…œ ๊ตฌ์ถ•ํ•˜๊ธฐ

๋„์ž… ๋ฐฐ๊ฒฝ

Image

๋ง›๋™์‚ฐ๐ŸŽ…์€ย ์•„์ด ๋งž์ถคํ˜• ๋™ํ™”๋ฅผ ์ƒ์„ฑํ•˜๊ณ , ์•„์ด์—๊ฒŒ ๋™ํ™”๋ฅผ ๋“ค๋ ค์ฃผ๋ฉฐ ์ง์ ‘ ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ „์šฉ ์ธํ˜• ๋””๋ฐ”์ด์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ์„œ๋น„์Šค์ด๋‹ค.

์ฒ˜์Œ AI๊ฐ€ ์•„์ด์˜ ๋‚˜์ด, ์–ธ์–ด, ์ฃผ์–ด์ง„ ํ”„๋กฌํ”„ํŠธ์— ๋งž๊ฒŒ ๋™ํ™”๋ฅผ ์ƒ์„ฑํ•ด์„œ ์ œ๊ณตํ•˜๋ฉด ๊ทธ ์ดํ›„์— ์œ ์ €๋“ค์€ ์ƒ์„ฑ๋œ ๋™ํ™”๋ฅผ ๊ณต์œ ํ•˜๊ฑฐ๋‚˜ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋ ‡๋“ฏ, ๋™ํ™”๊ฐ€ ์‚ฌ์šฉ์ž ๋งž์ถคํ˜•์œผ๋กœ AI์— ์˜ํ•ด ์ƒ์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ฒ˜์Œ ์ƒ์„ฑ ์ดํ›„, ์ˆ˜์ • & ์‚ญ์ œ ์š”์ฒญ์ด ๋งค์šฐ ์ ๊ณ  ์กฐํšŒ ์š”์ฒญ์ด ๋งŽ์„ ๊ฒƒ์ด๋ผ๋Š” ์ ์„ ์•Œ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

๋˜ํ•œ ์ธ๊ธฐ ๋™ํ™”, ์ตœ๊ทผ ์ƒ์„ฑ๋œ ๋™ํ™” ๋ฆฌ์ŠคํŠธ ๋“ฑ์„ ์ œ๊ณตํ•˜๋ฉด์„œ ํŠน์ • ๋™ํ™”๋กœ์˜ ์กฐํšŒ๊ฐ€ ๋ชฐ๋ฆด ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.

์ด์— ๋™ํ™” ์บ์‹œ ์‹œ์Šคํ…œ ๋„์ž…์„ ๊ฒฐ์ •ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.


์บ์‹œ๋ž€?

๋ณธ๊ฒฉ์ ์œผ๋กœ ์บ์‹œ ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•˜๊ธฐ์— ์•ž์„œ ๋จผ์ € ์บ์‹œ๋ž€ ๋ฌด์—‡์ธ์ง€์— ๋Œ€ํ•ด์„œ ๊ฐ„๋žตํ•˜๊ฒŒ ์‚ดํŽด๋ณด๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

Image

์บ์‹œ๋ž€ ๋ฌด์—‡์ผ๊นŒ?

์ปดํ“จํ„ฐ ๊ณผํ•™์—์„œ ๋ฐ์ดํ„ฐ๋‚˜ ๊ฐ’์„ ๋ฏธ๋ฆฌ ๋ณต์‚ฌํ•ด ๋†“๋Š” ์ž„์‹œ ์žฅ์†Œ

์บ์‹œ๋Š”ย ์ปดํ“จํ„ฐ ๊ณผํ•™์—์„œ ๋ฐ์ดํ„ฐ๋‚˜ ๊ฐ’์„ ๋ฏธ๋ฆฌ ๋ณต์‚ฌํ•ด ๋†“๋Š” ์ž„์‹œ ์žฅ์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋ฉฐ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๋Š” ์‹œ๊ฐ„์ด ์˜ค๋ž˜ ๊ฑธ๋ฆฌ๋Š” ๊ฒฝ์šฐ๋‚˜ ๊ฐ’์„ ๋‹ค์‹œ ๊ณ„์‚ฐํ•˜๋Š” ์‹œ๊ฐ„์„ ์ ˆ์•ฝํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•œ๋‹ค.

๋˜ํ•œ ์บ์‹œ์˜ ์ข…๋ฅ˜๋กœ๋Š” CPU ์บ์‹œ, ์›น ์บ์‹œ, ๋ธŒ๋ผ์šฐ์ € ์บ์‹œ, ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์บ์‹œ ๋“ฑ๋“ฑ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜๊ฐ€ ์žˆ์œผ๋ฉฐ ์ปดํ“จํ„ฐ ๊ณผํ•™ ์ „๋ฐ˜์—์„œ ์บ์‹œ๊ฐ€ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋‹ค๊ณ  ํ•ด๋„ ๊ณผ์–ธ์ด ์•„๋‹ˆ๋‹ค.

์ด๋•Œ ์บ์‹œ๊ฐ€ ํšจ์œจ์ ์œผ๋กœ ๋™์ž‘ํ•˜๋ ค๋ฉด ์บ์‹œ์— ์ €์žฅํ•  ๋ฐ์ดํ„ฐ๊ฐ€ ์ง€์—ญ์„ฑ์„ ๊ฐ€์ ธ์•ผ ํ•œ๋‹ค.

  • ์‹œ๊ฐ„์  ์ง€์—ญ์„ฑ
    • ํŠน์ • ๋ฐ์ดํ„ฐ๊ฐ€ ํ•œ๋ฒˆ ์ ‘๊ทผ๋˜์—ˆ์„ ๊ฒฝ์šฐ, ๊ฐ€๊นŒ์šด ๋ฏธ๋ž˜์— ๋˜ ํ•œ๋ฒˆ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์€ ๊ฒƒ
  • ๊ณต๊ฐ„์  ์ง€์—ญ์„ฑ
    • ํŠน์ • ๋ฐ์ดํ„ฐ์™€ ๊ฐ€๊นŒ์šด ์ฃผ์†Œ๊ฐ€ ์ˆœ์„œ๋Œ€๋กœ ์ ‘๊ทผ๋˜์—ˆ์„ ๊ฒฝ์šฐ

Image

๋˜ํ•œ ์บ์‹œ ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•˜๋Š”๋ฐ์—๋Š” ๋‹ค์–‘ํ•œ ์ „๋žต์ด ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค.

  • ์ฝ๊ธฐ ์ „๋žต โ€“ Look Aside ์ „๋žต

    Image

  • ์ฝ๊ธฐ ์ „๋žต โ€“ Read Through ์ „๋žต

    Image

  • ์“ฐ๊ธฐ ์ „๋žต โ€“ Write Back ์ „๋žต

    Image

  • ์“ฐ๊ธฐ ์ „๋žต โ€“ Write Through ์ „๋žต

    Image

  • ์“ฐ๊ธฐ ์ „๋žต โ€“ Write Around ์ „๋žต

    Image


Redis๋ฅผ ํ™œ์šฉํ•œ ์บ์‹œ ์‹œ์Šคํ…œ ๊ตฌ์ถ•ํ•˜๊ธฐ

์Šคํ”„๋ง์—์„œ ์บ์‹œ ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€๊ฐ€ ์žˆ์ง€๋งŒ ๋ณธ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์ต์ˆ™ํ•œ Redis๋ฅผ ํ™œ์šฉํ•˜์—ฌ์„œ ์ง„ํ–‰ํ•ด ๋ณด์•˜๋‹ค.

Cache๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์— ์•ž์„œ ์–ด๋– ํ•œ ์ „๋žต์œผ๋กœ ์ ์šฉํ•˜์—ฌ ์„ฑ๋Šฅ์„ ๊ฐœ์„ ํ• ์ง€ ๊ณ ๋ฏผํ•ด๋ณด์•„์•ผ ํ•˜๋Š”๋ฐ, ๋ณธ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ์บ์‹œ์˜ ์ฝ๊ธฐ ์ „๋žต์œผ๋กœ Read Through ์ „๋žต์„, ์“ฐ๊ธฐ ์ „๋žต์œผ๋กœ๋Š” Write Through ์ „๋žต์„ ์‚ฌ์šฉํ•˜์˜€๋‹ค.

RedisConfig.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Configuration
@EnableCaching
public class RedisConfig {

    @Bean
    public CacheManager customCacheManager(RedisConnectionFactory redisConnectionFactory) {
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofMinutes(15))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

        return RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(config)
                .build();
    }
}

๋จผ์ € RedisConfig์—์„œ ์บ์‹œ์™€ ๊ด€๋ จ๋œ ์„ค์ •์„ ์ง„ํ–‰ํ•ด์ฃผ์—ˆ๋‹ค. ์—ฌ๊ธฐ์„œ TTL, ์บ์‹œํ‚ค์™€ ์บ์‹œ๊ฐ’์˜ ์ง๋ ฌํ™” ๋ฐฉ์‹ ๋“ฑ ์บ์‹ฑ ์ •์ฑ…์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • entryTtl: ์บ์‹œ์˜ TTL ์„ค์ •
  • serializeKeysWith: ์บ์‹œํ‚ค์˜ ์ง๋ ฌํ™” ๋ฐฉ์‹
  • serializeValuesWith: ์บ์‹œ๊ฐ’์˜ ์ง๋ ฌํ™” ๋ฐฉ์‹

MatdongsanServerApplication.java

1
2
3
4
5
6
7
8
9
@SpringBootApplication
@EnableFeignClients
@EnableCaching
public class MatdongsanServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(MatdongsanServerApplication.class, args);
    }
}

๋‹ค์Œ์œผ๋กœ๋Š” ์„œ๋ฒ„๋ฅผ ์‹คํ–‰์‹œํ‚ค๋Š” SpringBoot Starter class์— @EnableCaching ์–ด๋…ธํ…Œ์ด์…˜์„ ๋„ฃ์–ด์„œ ์บ์‹œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด์ฃผ์—ˆ๋‹ค.

StoryCacheService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@Service
@RequiredArgsConstructor
public class StoryCacheService {

    private final StoryRepository storyRepository;

    @Cacheable(value = "stories", key = "#storyId", cacheManager = "customCacheManager")
    public Story getStory(String storyId) {
        return storyRepository.findByIdOrThrow(storyId);
    }

    @CachePut(value = "stories", key = "#storyId", cacheManager = "customCacheManager")
    public Story updateStory(String storyId, StoryDto.StoryUpdateRequest requestDto) {
        return storyRepository.findByIdOrThrow(storyId)
                .updateStoryDetail(requestDto);
    }

    @CachePut(value = "stories", key = "#storyId", cacheManager = "customCacheManager")
    public Story likeStory(String storyId) {
        return storyRepository.findByIdOrThrow(storyId)
                .addLikes();
    }

    @CachePut(value = "stories", key = "#storyId", cacheManager = "customCacheManager")
    public Story unlikeStory(String storyId) {
        return storyRepository.findByIdOrThrow(storyId)
                .removeLikes();
    }
}

์บ์‹œ ํ™œ์„ฑํ™”๋ฅผ ์œ„ํ•ด์„œ ๋ณ„๋„๋กœ StoryCacheService๋ฅผ ๊ตฌํ˜„ํ•˜์˜€๊ณ  ๋‹ค๋ฅธ ํด๋ž˜์Šค์—์„œ ํ•ด๋‹น ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด ๋™ํ™”์˜ CRUD ์ž‘์—…์„ ์ฒ˜๋ฆฌํ•˜๋„๋ก ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

์บ์‹œ ์‹œ์Šคํ…œ ๊ตฌ์ถ•์—๋Š” ์ œ๊ณต๋˜๋Š” @Cacheable๊ณผ @CachePut ์–ด๋…ธํ…Œ์ด์…˜์„ ํ™œ์šฉํ•˜์˜€๊ณ , ๋™ํ™” ID๋ฅผ KEY๋กœ ๋™ํ™” ๋‚ด์šฉ์„ ์บ์‹œํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ตฌํ˜„ํ•˜์˜€๋‹ค.

@Cacheable๊ณผ @CachePut์˜ ์—ญํ• ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  • @Cacheable
    • ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œ์— ์ €์žฅํ•˜๊ณ , ์ดํ›„ ๋™์ผํ•œ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๋ฉด ์บ์‹œ์—์„œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜
    • ๋ฉ”์„œ๋“œ ์‹คํ–‰ ์ „์— ์บ์‹œ๋ฅผ ๋จผ์ € ํ™•์ธ ํ›„, ์บ์‹œ์— ๊ฐ’์ด ์—†์œผ๋ฉด ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•œ ๋’ค ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œ์— ์ €์žฅ
  • @CachePut
    • ๋ฉ”์„œ๋“œ ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ•์ œ๋กœ ์บ์‹œ์— ์ €์žฅ
    • ํ•ญ์ƒ ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉฐ, ๋ฐ˜ํ™˜๋œ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œ์— ์—…๋ฐ์ดํŠธ

์บ์‹œ๋ฅผ ๋น„์šฐ๋Š”๋ฐ ์‚ฌ์šฉ๋˜๋Š” @CacheEvict๋„ ์žˆ๋Š”๋ฐ ๋ณธ ํ”„๋กœ์ ํŠธ์—์„œ๋Š” ๋™ํ™” ์‚ญ์ œ ๊ธฐ๋Šฅ์„ ๋ณ„๋„๋กœ ๊ตฌํ˜„ํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•˜์ง€๋Š” ์•Š์•˜๋‹ค.


์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ

๊ตฌ์ถ•ํ•œ ์บ์‹œ ์‹œ์Šคํ…œ์ด ์–ด๋А ์ •๋„์˜ ์„ฑ๋Šฅ์ด ๋‚˜์˜ค๋Š”์ง€ ๊ฐ„๋‹จํ•œ ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•ด๋ณด์•˜๋‹ค.

Image

ํ…Œ์ŠคํŠธ์—๋Š” nGrinder๋ฅผ ํ™œ์šฉํ•˜์˜€๊ณ  ๋ฏธ๋ฆฌ 1000๊ฐœ์˜ ๋™ํ™” ๋ฐ์ดํ„ฐ๋ฅผ ์ƒ์„ฑ ํ›„, ํŒŒ๋ ˆํ† ์˜ ๋ฒ•์น™์„ ๋”ฐ๋ฅด๋Š” ์กฐํšŒ ์š”์ฒญ์„ ๋ณด๋‚ด๋„๋ก ํ•˜์˜€๋‹ค.

ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๊ตฌ์„ฑํ•˜์˜€๋‹ค.

  • Agent: 1๋Œ€
  • ํ…Œ์ŠคํŠธ ์œ ์ €: 1000
  • ํ…Œ์ŠคํŠธ ์‹œ๊ฐ„: 1๋ถ„
  • Ramp-Up (์‹œ๊ฐ„์— ๋”ฐ๋ผ ์‚ฌ์šฉ์ž ์ฆ๊ฐ€)

์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ์˜ ๊ฒฐ๊ณผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์€ ์ง€ํ‘œ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

  • ์บ์‹œ๋ฅผ ์ ์šฉํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ

    Image

  • ์บ์‹œ๋ฅผ ์ ์šฉํ•œ ๊ฒฝ์šฐ

    Image

ย ์บ์‹œ ์ ์šฉ X์บ์‹œ ์ ์šฉ์„ฑ๋Šฅ ๊ฐœ์„ 
TPS141.4224.4์•ฝ 58.7% ๊ฐœ์„ 
Mean Test Time1227.271024.08์•ฝ 16.6% ๊ฐœ์„ 

TPS์˜ ๊ฒฝ์šฐ ์•ฝ 58.7%์˜ ์„ฑ๋Šฅ ํ–ฅ์ƒ, ํ‰๊ท  ์‘๋‹ต ์‹œ๊ฐ„์˜ ๊ฒฝ์šฐ ์•ฝ 16.6%์˜ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

์ƒ๊ฐ๋ณด๋‹ค๋Š” ๋‚ฎ์€ ํญ์˜ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋Š”๋ฐ ์•„๋งˆ ๋™ํ™” ์กฐํšŒ ์š”์ฒญ์—์„œ ํ•ด๋‹น ๋™ํ™”์— ์ข‹์•„์š”๋ฅผ ๋ˆŒ๋ €๋Š”์ง€ ๋“ฑ์˜ ์ •๋ณด๋Š” ์–ด์ฉ” ์ˆ˜ ์—†์ด ๋””๋น„์—์„œ ๊ฐ€์ ธ์™€์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฐ ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์™”๋˜ ๊ฒƒ ๊ฐ™๋‹ค.


๋งˆ์น˜๋ฉฐ

์ž˜ ๋ชฐ๋ž๋˜ ์บ์‹œ์— ๋Œ€ํ•ด์„œ ํ•™์Šตํ•˜๊ณ  ์ง์ ‘ ํ”„๋กœ์ ํŠธ์— ์ ์šฉํ•ด๋ณด๋ฉด์„œ, ๋‚ด๊ฐ€ ์„ค๊ณ„ํ•œ ์„œ๋ฒ„์˜ ์„ฑ๋Šฅ ํ–ฅ์ƒ์— ๋Œ€ํ•ด์„œ ๊ณ ๋ฏผํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ์ข‹์€ ๊ฒฝํ—˜์ด์—ˆ๋‹ค.

ํŠนํžˆ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์บ์‹œ ๊ฐ„์˜ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•˜๋Š” ์ „๋žต์˜ ์ค‘์š”์„ฑ์„ ๊นจ๋‹ฌ์•˜๊ณ , ์‹ค๋ฌด์—์„œ์˜ ์บ์‹œ ๋„์ž…์„ ์œ„ํ•ด์„  ํšจ๊ณผ์ ์ธ ์ „๋žต ์ˆ˜๋ฆฝ์ด ํ•„์š”ํ•  ๊ฒƒ์ด๋ผ๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค.

๋˜ ์ง์ ‘ nGrinder๋ฅผ ํ†ตํ•ด์„œ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉฐ, ์„ฑ๋Šฅ ๊ฐœ์„  ์‚ฌํ•ญ์„ ์ˆ˜์น˜๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด์„œ ์ข‹์•˜๋‹ค.

This post is licensed under CC BY 4.0 by the author.