๐Ÿงฃ SpringBoot + Redis ์‚ฌ์šฉํ•˜๊ธฐ

์ดํ•˜์–€ยท2023๋…„ 12์›” 7์ผ
0
post-thumbnail

ํ˜„์žฌ ํ”„๋กœ์ ํŠธ

  • ํœด๋งฅ์Šค๋ชจ๋นŒ๋ฆฌํ‹ฐ ์ฃผ์ฐจ์žฅ ์„œ๋น„์Šค ๊ฐœ๋ฐœ
  • SpringBoot + MySQL + Docker + AWS EC2(Amazon Linux 2)
  • ์ฃผ์ฐจ์žฅ ๊ฒ€์ƒ‰ ์‹œ ์˜ฌ๋ผ๊ฐ€๋Š” ์นด์šดํŠธ๋ฅผ ํ†ตํ•ด ์ธ๊ธฐ๋„ ์ถœ๋ ฅ
    - ๊ธฐ์กด MySQL์˜ search_count๋ฅผ -> Redis๋กœ ์ด๊ด€ํ•˜๊ธฐ ์œ„ํ•œ ์ž‘์—… ์ง„ํ–‰

1. Redis ์„ค์น˜

๐Ÿ“ [Redis] Redis ์„ค์น˜ ๋ฐ ๊ฐ„๋‹จํ•œ ์‚ฌ์šฉ ๋ฐฉ๋ฒ• (Mac)

  • Mac Os์˜ Homebrew๋ฅผ ํ†ตํ•œ ์„ค์น˜๋ฅผ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.
    $ brew install redis

  • ์„ค์น˜๊ฐ€ ์™„๋ฃŒ๋˜๋ฉด ๋‹ค์Œ์˜ ๋ช…๋ น์–ด๋กœ redis๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.
    $ brew services start redis

  • redis-cli์„ ํ†ตํ•ด ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    $ redis-cli


2. Redis ๊ธฐ๋ณธ ๋ช…๋ น์–ด

https://wlswoo.tistory.com/44
-> ์—ฌ๊ธฐ๋ณด๊ณ  ์ •๋ฆฌํ•ด๋‘๊ธฐ


3. Redis ์ ์šฉ ํ…Œ์ŠคํŠธ

  • ์šฐ์„  ์ œ ๋ธŒ๋žœ์น˜๋กœ ๋Œ์•„์™€์„œ ํ…Œ์ŠคํŠธ๋ฅผ ํ•ด๋ณด๊ธฐ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค.
    ๊ทธ๋Ÿฐ๋ฐ checkout ํ•˜๋‹ˆ, resources/application.yml์ด ์—†...์–ด์กŒ..์Šต๋‹ˆ๋‹ค๐Ÿ˜ฎ
    ์—„์ฒญ ๋‹นํ™ฉํ–ˆ๋Š”๋ฐ ๊ทธ๋ƒฅ ์ œ๊ฐ€ ์ €์žฅ์•ˆํ•˜๊ณ  ๋‹ค๋ฅธ ๋ธŒ๋žœ์น˜๋กœ ๋„˜์–ด๊ฐ”๋‹ค๊ฐ€ ์™€์„œ ๊ทธ๋Ÿฐ ๊ฒƒ ๊ฐ™์•„์„œ, ๊ทธ๋ƒฅ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค..!

    ๋‹ค์‹œ ๋งŒ๋“œ๋‹ˆ๊นŒ ์•Œ์•„์„œ ignore ์ฒ˜๋ฆฌ๊ฐ€ ๋ฐ”๋กœ ๋˜์–ด์„œ ์•ˆ์‹ฌํ•˜๊ณ  commitํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ๊นƒ์€ ์ •๋ง ๋‹ค ์•Œ์•˜๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋Š” ์ˆœ๊ฐ„ ์ฒ˜์Œ ๋ณด๋Š” ๋ฌธ์ œ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค๋Š” ๊ฒƒ ๊ฐ™์•„์š”๐Ÿ˜…
    ๊นƒ ๊ณต๋ถ€ํ•˜๊ธฐ(๋ฉ”๋ชจ)

    .
    .

  • ๋‹ค์‹œ ๋Œ์•„์™€์„œ ๋ณ€๊ฒฝํ•œ ๋ถ€๋ถ„์„ ๋ง์”€๋“œ๋ ค๋ณผ๊ฒŒ์š”.

1๏ธโƒฃ ์˜์กด์„ฑ ์ถ”๊ฐ€

Spring Boot ๋‚ด์— Redis๋ฅผ ์ง€์›ํ•ด์ฃผ๋Š” spring-boot-starter-data-redis๋ผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์žˆ์–ด์„œ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ bulid.gradle

...
	// Redis
	implementation 'org.springframework.boot:spring-boot-starter-data-redis'
...

2๏ธโƒฃ host ๋ฐ port ์ง€์ •ํ•ด์ฃผ๊ธฐ

Redis๋ฅผ ์„ค์น˜ํ•˜๊ณ , ์•„๋ฌด ์„ค์ •์„ ํ•˜์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ

  • ๊ธฐ๋ณธ host : localhost(ec2์˜ ๊ฒฝ์šฐ ํ•ด๋‹น IP)
  • port : 6379
  • password : ์—†์Œ(์„ค์ •์—์„œ ์ถ”๊ฐ€ํ•ด์ค€ ๊ฒฝ์šฐ์—๋งŒ ์ ์šฉ)

์ด๋ ‡๊ฒŒ ์„ค์ •์ด ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ์„ค์ •์€ application.yml์— ์ถ”๊ฐ€ํ•ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

โฐ ๋ฐ˜๋“œ์‹œ spring: ๋ฐ”๋กœ ์•„๋ž˜ indentation์— ์ž‘์„ฑํ•ด์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. โฐ

๐Ÿ“ application.yml

spring:
  redis:
    host: localhost
    port: 6379
    ...

3๏ธโƒฃ RedisConfig ์ ์šฉ(์„ ํƒ)

spring-boot-starter-data-redis์— ์ž์ฒด์ ์œผ๋กœ RedisTemplete์„ ์ž๋™ ์ฃผ์ž…ํ•ด์ฃผ์ง€๋งŒ, ์•ฝ๊ฐ„์˜ ์˜ค๋ฅ˜๊ฐ€ ์žˆ์–ด ์ถ”๊ฐ€ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค!
๐Ÿ“ config/RedisConfig.java

package com.humax.parking.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.StringRedisTemplate;

@Configuration
public class RedisConfig {

    @Bean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory) {
        return new StringRedisTemplate(connectionFactory);
    }
}

4๏ธโƒฃ UserService ์ˆ˜์ •

๊ธฐ์กด์˜ MySQL์—์„œ์˜ search_count๋ฅผ Redis๋กœ ์˜ฎ๊ฒจ์ฃผ๊ณ , MySQL์—๋Š” ์ฃผ๊ธฐ์ ์œผ๋กœ ๊ฐฑ์‹ ๋งŒ ํ•ด์ฃผ๋„๋ก ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.
๐Ÿ“ service/UserService.java
๐Ÿ™Œ ๊ธฐ์กด

private void updateSearchCount(List<ParkingEntity> parkingEntities){
        for(ParkingEntity parkingEntity : parkingEntities){
            parkingEntity.setSearchCount(parkingEntity.getSearchCount()+1);
        }
    }

๐Ÿ™Œ ๋ณ€๊ฒฝํ›„

...
private final StringRedisTemplate stringRedisTemplate;

private static final String SEARCH_COUNT_KEY_PREFIX = "search_count:";
    ...
    
private void updateSearchCount(List<ParkingEntity> parkingEntities) {
        for (ParkingEntity parkingEntity : parkingEntities) {
            String key = SEARCH_COUNT_KEY_PREFIX + parkingEntity.getParkingId();
            stringRedisTemplate.opsForValue().increment(key);
            // ๋กœ๊ทธ ์ถ”๊ฐ€
            System.out.println("์ถ”๊ฐ€๋œ ์ฃผ์ฐจ์žฅ parking_id: " + parkingEntity.getParkingId());
        }
    }
  • RedisTemplate ์‚ฌ์šฉ์„ ์œ„ํ•ด ์„ ์–ธ์„ ํ•ด์ฃผ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ๋˜ํ•œ, SEARCH_COUNT_KEY_PREFIX๋กœ search_count๋ฅผ ๋ช…์‹œํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • Redis์— SEARCH_COUNT_KEY_PREFIX๋ฅผ ํ†ตํ•ด ์นด์šดํŠธ์˜ KEY ๊ฐ’์„ ๋„ฃ์–ด์ฃผ๊ณ , ์‹ค์ œ๋กœ ๊ฒ€์ƒ‰๋œ ํ›„ key๊ฐ’์ด increment ๋˜๋„๋ก ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ๋กœ๊ทธ๋ฅผ ๋„ฃ์–ด์ฃผ์–ด ์‹ค์ œ๋กœ ํ˜ธ์ถœ์ด ๋˜๋Š”์ง€๋„ ๋ฐ”๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.

5๏ธโƒฃ ๊ฒฐ๊ณผ ํ™•์ธ ๋ฐฉ๋ฒ•

search_count์˜ ๋™์ž‘ ๋กœ์ง์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
1. ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ€๊นŒ์šด ์ฃผ์ฐจ์žฅ์„ ๋ฐ˜๊ฒฝ, ์œ„๋„์™€ ๊ฒฝ๋„๋กœ ์กฐํšŒํ•ฉ๋‹ˆ๋‹ค.
(๋ฐ˜๋“œ์‹œ ์†Œ์…œ๋กœ๊ทธ์ธ์ด ๋˜์–ด ์žˆ๋Š” ์œ ์ €์—ฌ์•ผ๋งŒ ํ•ฉ๋‹ˆ๋‹ค)

URI
localhost:8080/api/v1/user/search

Body(JSON)

{ 
	"distance": 2000,
    "lon":"37.5170112",
    "lat":"126.9019532"
}
  1. ์‹ค์ œ ์ ์šฉ๋˜์—ˆ์Œ์„ ๋กœ๊ทธ์™€ redis ์กฐํšŒ, ๊ทธ๋ฆฌ๊ณ  MySQL ๊ฐฑ์‹  ์—ฌ๋ถ€๋ฅผ ํ†ตํ•ด ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.

6๏ธโƒฃ ๊ฒฐ๊ณผ ํ™•์ธ!

๐Ÿ“ฉ ๊ฐ€๊นŒ์šด ์ฃผ์ฐจ์žฅ ์กฐํšŒ


๐Ÿ“ฉ ํ”„๋กœ์ ํŠธ ๋กœ๊ทธ๊ฐ€ ์ถœ๋ ฅ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ


๐Ÿ“ฉ Redis ํ™•์ธ
GET search_count:{parking_id}

  • crossCheck : ์กฐํšŒ๋˜์ง€ ์•Š์€ ์ฃผ์ฐจ์žฅ์˜ count ํ™•์ธ โœ…


๐Ÿ“ฉ MySQL ํ™•์ธ
์ผ๋ฐ˜์ ์œผ๋กœ ์ด ์ฟผ๋ฆฌ๊ฐ€ ์ข…๋ฃŒ๋œ ์ฆ‰์‹œ, MySQL์—์„œ ์ ์šฉ์ด ๋˜์–ด์•ผ ํ•˜์ง€๋งŒ ๋ฐ”๋กœ ์ ์šฉ๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ ๋ฐœ์ƒ



4. MySQL Batch ์ž‘์—…

  • ์ฃผ๊ธฐ์ ์œผ๋กœ MySQL์— search_count๊ฐ€ ๊ฐฑ์‹ ๋  ์ˆ˜ ์žˆ๋„๋ก ๋ฐฐ์น˜ ์ž‘์—…์„ ์‹œ๋„ํ•ด๋ดค์Šต๋‹ˆ๋‹ค.
    ๐Ÿ“ service์— redis ํŒจํ‚ค์ง€ ์ƒ์„ฑ/GSearchCountUpdateTask.java
package com.humax.parking.service.redis;

import com.humax.parking.service.UserService;
import java.util.ArrayList;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

@SpringBootApplication
@EnableScheduling
public class SearchCountUpdateTask {

    private final UserService userService;

    public SearchCountUpdateTask(UserService userService) {
        this.userService = userService;
    }

    @Scheduled(fixedDelay = 60000) // 1๋ถ„๋งˆ๋‹ค ์‹คํ–‰ (๋ฐ€๋ฆฌ์ดˆ ๋‹จ์œ„) -> ์ถ”ํ›„ ์‹ค์ œ ๋ฐฐ์น˜ ์ž‘์—… ์‹œ 1์‹œ๊ฐ„์œผ๋กœ ๋ณ€๊ฐฑ
    public void updateSearchCount() {
        try {
            // ์—ฌ๊ธฐ์„œ userService์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ MySQL์˜ ๊ฒ€์ƒ‰ ํšŸ์ˆ˜๋ฅผ ๊ฐฑ์‹ 
            userService.updateSearchCount(new ArrayList<>());
            System.out.println("๊ฐฑ์‹  ์™„๋ฃŒ");
        } catch (Exception e) {
            // ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
            e.printStackTrace();
        }
    }
}

๐Ÿ“ UserService.java ์ˆ˜์ •

public void updateSearchCount(List<ParkingEntity> parkingEntities) {
        for (ParkingEntity parkingEntity : parkingEntities) {
            String key = SEARCH_COUNT_KEY_PREFIX + parkingEntity.getParkingId();
            stringRedisTemplate.opsForValue().increment(key);
            // ๋กœ๊ทธ ์ถ”๊ฐ€
            System.out.println("์ถ”๊ฐ€๋œ ์ฃผ์ฐจ์žฅ parking_id: " + parkingEntity.getParkingId());
        }
    }

๊ฒฐ๊ณผ

  • ํ…Œ์ŠคํŠธ์šฉ์ด๋ผ 1๋ถ„์— ํ•œ๋ฒˆ์”ฉ MySQL์— ๊ฐฑ์‹ ์ด ๋˜๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.

  • ํ•˜์ง€๋งŒ ์‹ค์ œ MySQL์—์„œ ๊ฐ’์ด ์•„์ง ๋ฐ˜์˜๋˜์ง€ ์•Š๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋ฐฐ์น˜ ์ž‘์—…์„ ํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์œผ๋กœ ๊ฒฐ๋ก .


๋‹ค์Œ ํŽธ : ๐Ÿงฃ SpringBoot + Redis - ๋ฉ”์ธ ํ™”๋ฉด ์ธ๊ธฐ ์ฃผ์ฐจ์žฅ ๋„์šฐ๊ธฐ

profile
์–ธ์  ๊ฐ€ ๋‚ด ์ฝ”๋“œ๋กœ ์„ธ์ƒ์— ๊ธฐ์—ฌํ•  ์ˆ˜ ์žˆ๋„๋ก, BE ๊ฐœ๋ฐœ ๊ธฐ๋ก ๋…ธํŠธโ˜˜๏ธ

0๊ฐœ์˜ ๋Œ“๊ธ€