본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성하였습니다.
Redis로 성능 개선
Redis에 대해서 더 자세하게 알아보기 전 캐시 서버(Cache Server)에 대해서,
데이터 베이스가 있는데도 Redis라는 인메모리 데이터 구조 저장소를 사용하는 이유는 무엇일까요?
데이터 베이스는 데이터를 물리 디스크에 직접 쓰기 때문에 서버에 문제가 발생하여 다운되더라도 데이터가 손실되지 않습니다. 하지만 매번 디스크에 접근해야 하기 때문에 사용자가 많아질수록 부하가 많아져서 느려질 수 있는데요.
일반적으로 서비스 운영 초반이거나 규모가 작은, 사용자가 많지 않은 서비스의 경우에는 WEB - WAS - DB 의 구조로도 데이터 베이스에 무리가 가지 않습니다.
하지만 사용자가 늘어난다면 데이터 베이스가 과부하 될 수 있기 때문에 이때 캐시 서버를 도입하여 사용합니다.
그리고 이 캐시 서버로 이용할 수 있는 것이 바로 Redis 입니다.
캐시는 한번 읽어온 데이터를 임의의 공간에 저장하여 다음에 읽을 때는 빠르게 결괏값을 받을 수 있도록 도와주는 공간입니다.
같은 요청이 여러 번 들어오는 경우 매번 데이터 베이스를 거치는 것이 아니라 캐시 서버에서 첫 번째 요청 이후 저장된 결괏값을 바로 내려주기 때문에 DB의 부하를 줄이고 서비스의 속도도 느려지지 않는 장점이 있습니다.
캐시 서버는 Look aside cache 패턴과 Write Back 패턴이 존재합니다.
Look aside cache
- 클라이언트가 데이터를 요청
- 웹서버는 데이터가 존재하는지 Cache 서버에 먼저 확인
- Cache 서버에 데이터가 있으면 DB에 데이터를 조회하지 않고 Cache 서버에 있는 결과값을 클라이언트에게 바로 반환 (Cache Hit)
- Cache 서버에 데이터가 없으면 DB에 데이터를 조회하여 Cache 서버에 저장하고 결과값을 클라이언트에게 반환 (Cache Miss)
Write Back
- 웹서버는 모든 데이터를 Cache 서버에 저장
- Cache 서버에 특정 시간 동안 데이터가 저장됨
- Cache 서버에 있는 데이터를 DB에 저장
- DB에 저장된 Cache 서버의 데이터를 삭제
- insert 쿼리를 한 번씩 500번 날리는 것보다 insert 쿼리 500개를 붙여서 한 번에 날리는 것이 더 효율적이라는 원리입니다.
- 이 방식은 들어오는 데이터들이 저장되기 전에 메모리 공간에 머무르는데 이때 서버에 장애가 발생하여 다운된다면 데이터가 손실될 수 있다는 단점이 있습니다.
https://wildeveloperetrain.tistory.com/21
1. Redis 소개
redis(REmote DIctionary Server) 소개
- Redis란 오픈소스이며, In-Memory 데이터베이스로써 다양한 자료구조를 제공
- https://redis.io/docs/data-types/
- 메모리 접근이 디스크 접근보다 빠르기 때문에 데이터베이스(MySQL, Oracle)보다 빠르다
- request마다 약국데이터를 매번 DB에서 조회, 거리계산 알고리즘 계산 및 정렬 후 결과값 반환
- 현재 약국 도메인 데이터가 크지 않기 때문에, redis 사용은 optional
- 데이터가 큰 경우, 이를 매번 DB 조회하는 부분을 메모리에 캐싱하여 성능 향상 가능
redis(REmote DIctionary Server) 사용 시 주의사항
- Redis 캐싱을 이용하여 성능을 개선하고자 할 때, 캐싱 데이터는 update가 자주 일어나지 않는 데이터가 효과적
- 너무 많은 update가 일어나는 데이터일 경우, DB와의 Sync 비용 발생
- Redis 사용 시 반드시 failover에 대한 고려 ex) redis 장애 시 데이터베이스에서 조회, redis 이중화 및 백업
redis(REmote DIctionary Server) cli
- Redis CLI
docker exec -it {container id} redis-cli --raw #redis cli로 접속
- String 자료 구조 (key-value)
set id 10 # key(id)의 value를 10으로 저장
get id # key 조회
del id # key 삭제
scan 0 # key들을 일정 단위 개수 만큼 씩 조회
- Hash 자료 구조(key-subKey-value)
hgetall USER # Key(USER)의 매핑되는 모든 필드와 값들을 조회
hset USER subkey value # Key(USER)의 subkey의 값을 지정
hget USER subkey # Key(USER)의 subkey의 값을 조
redis geospatial 자료구조
- Test Code 1
#geopoints1 라는 자료구조에 pharmacy1,2 각각 경도, 위도를 추가
geoadd geopoints1 127.0817 37.5505 pharmacy1
geoadd geopoints1 127.0766 37.541 pharmacy2
#두 지역의 거리를 리턴한다. 단위는 km
geodist geopoints1 pharmacy1 pharmacy2 km
- Test Code 2
geoadd geopoints2 127.0569046 37.61040424 pharmacy1
geoadd geopoints2 127.029052 37.60894036 pharmacy2
geoadd geopoints2 127.236707811313 37.3825107393401 pharmacy3
#geopoints2 이름의 자료구조에서 주어진 위도, 경도 기준으로 반경 10km 이내에 가까운 약국 찾기
georadius geopoints2 127.037033003036 37.596065045809 10 km withdist withcoord asc count 3
클라우드 서비스 배포하기
1. 운영 환경 도커 컴포즈 및 profile 작성
docker-compose.yaml 작성
version: "3.8" # 파일 규격 버전
services: # 이 항목 밑에 실행하려는 컨테이너들을 정의
pharmacy-recommendation-redis: # 서비스명
container_name: pharmacy-recommendation-redis # 컨테이너 명
build:
dockerfile: Dockerfile
context: ./redis
image: yoonms5319/pharmacy-recommendation-redis
ports:
- "6379:6379"
pharmacy-recommendation-database:
container_name: pharmacy-recommendation-database
build:
dockerfile: Dockerfile
context: ./database
image: yoonms5319/pharmacy-recommendation-database
environment:
- MARIADB_DATABASE=pharmacy-recommendation
- MARIADB_ROOT_PASSWORD=${SPRING_DATASOURCE_PASSWORD}
volumes:
- ./database/config:/etc/mysql/conf.d
- ./database/init:/docker-entrypoint-initdb.d
ports:
- "3306:3306" # 접근 포트 설정 (컨테이너 외부:컨테이너 내부)
pharmacy-recommendation-app:
container_name: pharmacy-recommendation-app
build: .
depends_on: # DB, REDIS 컨테이너가 실행된 다음 WEB을 실행시킨다.
- pharmacy-recommendation-database
- pharmacy-recommendation-redis
image: yoonms5319/pharmacy-recommendation-app
environment:
- SPRING_DATASOURCE_USERNAME=${SPRING_DATASOURCE_USERNAME}
- SPRING_DATASOURCE_PASSWORD=${SPRING_DATASOURCE_PASSWORD}
- SPRING_PROFILES_ACTIVE=${SPRING_PROFILES_ACTIVE}
- KAKAO_REST_API_KEY=${KAKAO_REST_API_KEY}
ports:
- "80:8080"
restart: always # depends on은 실행 순서만 컨트롤 할뿐,
# 컨테이너 안의 서비스가 실행가능한 상태인지까지는 확인 하지 않기 때문에
# DB 또는 Redis가 아직 실행가능한 상태가 아니여서 실패하는 경우 재시작 하도록 설정
.env 파일 작성
SPRING_DATASOURCE_USERNAME=root
SPRING_DATASOURCE_PASSWORD=1234
SPRING_PROFILES_ACTIVE=prod
KAKAO_REST_API_KEY=
application.yaml에 prod 추가
spring:
config:
activate:
on-profile: prod
datasource:
driver-class-name: org.mariadb.jdbc.Driver
url: jdbc:mariadb://pharmacy-recommendation-database:3306/pharmacy-recommendation
username: ${SPRING_DATASOURCE_USERNAME}
password: ${SPRING_DATASOURCE_PASSWORD}
redis:
host: pharmacy-recommendation-redis
port: 6379
jpa:
hibernate:
ddl-auto: validate # prod 배포시 validate
show-sql: true
pharmacy:
recommendation:
base:
url: <http://localhost/dir/> # aws ec2 ip 할당 받은 후 변경 예정
도커 컴포즈 실행
docker-compose up --build
'패스트캠퍼스 강의' 카테고리의 다른 글
[37일차] 50일 포트폴리오 챌린지 (0) | 2023.09.13 |
---|---|
[31일] 50일 포트폴리오 챌린지 (0) | 2023.09.07 |
[30일] 50일 포트폴리오 챌린지 (0) | 2023.09.06 |
[29일차] 50일 포트폴리오 챌린지 (0) | 2023.09.05 |
[28일차] 50일 포트폴리오 챌린지 (0) | 2023.09.04 |