AWS EC2에 접속하는 방법

https://honglab.tistory.com/179

 

[AWS] AWS EC2에 접속하는 방법 5가지 (SSH, RDP)

팀블로그에 작성한 글입니다 1. 제일 추천 - mobaXterm (SSH, RDP, SFTP 등 한꺼번에 사용 가능) https://err-bzz.oopy.io/223a9c02-7ac2-498c-afde-01db6cf873ae [강추] mobaXterm으로 Linux, Windows Server 접속 mobaXterm이란? err-bzz.

honglab.tistory.com

 

|  개요

- 지난 시간에 한 작업
1. EC2 프리티어 계정 만들기
2. Yum 설치하기 
3. JDK 설치하기

- 이번 시간에 한 작업 
1. EC2에 도커와 레디스 설치하기
2. EC2 인바운드 규칙 설정하기

 

|  절차

1. EC2 도커와 레디스 설치하기

- 이 부분은 별도의 포스팅에 작성해두었는데, 아래에 적어두었다.

https://why-dev.tistory.com/378

 

[Docker/Redis] Ubuntu에 Redis 설치 & Docker로 Redis 실행

| Redis 설치하기 1. Ubuntu에 Redis 설치 sudo apt-get install redis-server 2. 설치 확인 redis-server --version 3. redis가 6379 포트를 쓰는지 확인 // netstat 없으면 net-tools 설치 sudo apt install net-tools // 6379 포트 쓰는지

why-dev.tistory.com

 

2. EC2 인바운드 규칙 설정하기

- 팀원 분께 인바운드와 아웃바운드에 대해 배웠다.

- 인바운드 : 들어오는 포트을 열어두는 것

- 아웃바운드 : 나가는 포트를 열어두는 것

 

(1) EC2 인스턴스로 가기 

- 보안그룹을 어떤걸 사용하는지를 먼저 확인한다.

 

(2) 네트워크 및 보안 > 보안그룹 

- (1)에서 확인한 보안그룹을 체크하고, [인바운드 규칙 편집]을 선택한다.

- 인바운드 규칙 편집 화면에서 0.0.0.0 모든 IP에서 레디스 6379 포트로 접속이 가능하게 하고 규칙을 저장한다.

 

(3) 텔넷을 통해 접속이 가능한지 확인한다.

- 텔넷을 쓰려면 먼저 텔넷을 깔아주어야한다.

- 나는 윈도우를 사용하는데, 윈도우의 경우 텔넷은 아래와 같이 설치할 수 있었다.

https://jsson.tistory.com/44

 

Windows 10 Telnet(텔넷) 서비스 설치, 사용 방법

네트워크 장비 또는 기타 장비들의 관리를 위해 텔넷(Telnet)을 사용할 때가 있는데요, Windows 10에는 기본적으로 설치가 되어 있지 않습니다. 다만, 기본 패키지 내에 포함이 되어 있기 때문에 간단

jsson.tistory.com

* ping : 주소에 대한 접근이 가능한지 확인

* telnet : 특정 ip의 포트로 접근이 가능한지 확인

- cmd를 열어 아래와 같이 작성하면 EC2의 해당 위치로 접속이 가능해진다.

telnet {ip 주소} {port 번호}

ex.
telnet 12.123.145.21 6379

 

(4) 내 로컬 PC에서 작성중이던 프로젝트를 열고 application.properties의 redis 주소를 수정하고 테스트를 해본다.

spring.redis.host={EC2 탄력적 ip주소}
spring.redis.port=6379

'Infra > AWS, Azure' 카테고리의 다른 글

[AWS] AWS EC2에 접속하는 방법 (스크랩)  (0) 2022.12.28
[AWS] EC2 Ubuntu 서버에 JDK 설치하기  (0) 2022.12.05

1. RedisTemlate을 통해 다양한 형태의 데이터 CRUD하기

https://blog.kingbbode.com/25

 

Spring Boot에서 Redis 사용하기

Redis란?Remote Dictionary Server의 약자오픈 소스 소프트웨어휘발성이면서 영속성을 가진 key-value 저장소Redis는 NoSQLNoSQL은 데이터 간의 관계를 정의하지 않고 고정된 스키마를 갖지 않는 새로운 형태의

blog.kingbbode.com

 

2. Json으로 파싱하여 저장, 조회하기

https://velog.io/@kshired/Spring-Redis%EC%97%90%EC%84%9C-%EA%B0%9D%EC%B2%B4-%EC%BA%90%EC%8B%B1%ED%95%98%EA%B8%B0

 

[Spring] Redis에서 객체 그래프를 유지하며 "직접" 캐싱하기

Spring에서 @Cacheable 어노테이션을 이용하면 한 함수에서 같은 인자가 들어왔을 때, return 값을 caching 할 수 있다는 것은 대부분 아는 사실입니다. 하지만 가끔은 로직상에서 캐싱을 해야하는 경우

velog.io

 

|  Redis 설치하기

 

1. Ubuntu에 Redis 설치

sudo apt-get install redis-server

2. 설치 확인

redis-server --version

3. redis가 6379 포트를 쓰는지 확인

// netstat 없으면 net-tools 설치
sudo apt install net-tools

// 6379 포트 쓰는지 확인
netstat -nlpt | grep 6379


tcp        0      0 127.0.0.1:6379          0.0.0.0:*               LISTEN      -
tcp6       0      0 ::1:6379                :::*                    LISTEN      -

4. redis에 접속 후 테스트

// 접속
redis-cli

// 테스트
127.0.0.1:6379> set test1 testvalue
OK

get test1
127.0.0.1:6379> get test1
"testvalue"

 

|  Docker 로 Redis 이미지 생성하기

 

1. Ubuntu에 Docker 설치

sudo docker apt install docker.io

 

2. Docker 로그인 하고 Docker 서비스가 실행되는지 확인하기

// 로그인
sudo docker login -u <아이디>
Password : <패스워드 작성 후 엔터>

// 실행확인
service docker status

 

3. 기존의 Redis-server 끄고, Docker에서 Redis image 생성하기

// 일단 redis-server 끄고
sudo systemctl stop redis-server

// 서비스 꺼진거 확인하고
service --status-all

// docker에서 image 생성하면서 실행
sudo docker run -it --name <이미지명> -p 6379:6379 -d redis

 

4. 컨테이너 확인하기 

sudo docker ps -a
CONTAINER ID   IMAGE     COMMAND                  CREATED          STATUS    PORTS     NAMES
b037231966f6   redis     "docker-entrypoint.s…"   23 minutes ago   Created             zero-mall-product-redis

 

5. 컨테이너 실행하기

sudo docker start b037231966f6

 

 

[ 참고 ]

서비스 시작/중지 https://vitux.com/how-to-start-stop-or-restart-services-in-ubuntu/

레디스 설치 https://hayden-archive.tistory.com/429

도커에 레디스 이미지 생성 https://icodebroker.tistory.com/9067

컨테이너 리스트 확인 https://codechacha.com/ko/docker-list-containers/

|  개요

- 이번 시간에 한 작업 : 
1. EC2 프리티어 계정 만들기
2. Yum 설치하기 
3. JDK 설치하기

 

1. EC2 프리티어 계정 만들기

- 이 부분은 이전에 우분투로 프리티어 계정을 만들어둔게 있어서 그걸 활용했습니다.

- 프리티어의 경우 하나의 인스턴스를 실행 시켜둘 수 있는데, 하나를 만들어두었고, 탄력적 IP를 설정해두었어요.

 

 

2. EC2 ubuntu에 Yum 설치하기

- 저는 AWS EC2로 우분투 운영체제를 사용합니다.

- 리눅스 계열의 운영체제에서 패캐지를 설치하기 위해서는 RPM 또는 YUM을 사용해야 합니다.

https://velog.io/@jwpark06/Linux-%ED%8C%A8%ED%82%A4%EC%A7%80-%EC%84%A4%EC%B9%98-%EB%B0%A9%EB%B2%95-RPM-YUM

 

Linux의 패키지 설치 방법 RPM & YUM이란?

AWS EC2에 설치하기에 관련된 포스팅을 진행하다보니 yum, rpm, yum.repos.d, GPG-KEY 등의 용어들이 사용되는데, 명확히 모르고 쓰고 있었던 것 같아서 한번 정리해볼까 합니다.RPM과 YUM둘 모두 Linux 환경

velog.io

- 따라서 먼저, 아래의 명령어를 통해 Yum을 설치합니다.

sudo apt install yum

 

3. 우분투에서 터미널로 JDK 설치하기

- 이제 리눅스에서 아래의 명령어들을 통해 JDK 11 버전을 설치하고, 잘 설치되었는지 확인합니다.

// 설치하기
$ sudo apt-get install openjdk-11-jdk

// 버전확인
ubuntu@ip-172-31-41-208:~$ java -version
openjdk version "11.0.17" 2022-10-18
OpenJDK Runtime Environment (build 11.0.17+8-post-Ubuntu-1ubuntu222.04)
OpenJDK 64-Bit Server VM (build 11.0.17+8-post-Ubuntu-1ubuntu222.04, mixed mode, sharing)

ubuntu@ip-172-31-41-208:~$ javac --version
javac 11.0.17

 

 

[ 참고 및 출처 ]

https://pinggoopark.tistory.com/14

https://develop-writing.tistory.com/121

https://davelogs.tistory.com/71

|  Redis insight란?

- Redis GUI이다. 사용자 편의를 위한 인터페이스임.

- 다운로드 링크 : https://redis.com/redis-enterprise/redis-insight/

 

RedisInsight | The Best Redis GUI

RedisInsight provides an intuitive and efficient graphical interface for Redis, allowing you to interact with your databases and manage your data.

redis.com

 

|  사용 사례

- Docker를 통해서 Redis를 pull, run 한 후,

- Redis insight를 통해서 database를 입력하여 들어왔다.

- 지금 어느정도의 공간을, 어떻게 사용하고 있는지를 한눈에 볼 수 있다.

|  Cache란?

용어 What? why? How?
Cache 임시로 데이터를 저장하는 공간 성능 향상 - Look aside Cache, Write Back
- Memcahced, Redis API

 

1. Cache의 배경과 목적

- 파레토의 법칙에 따르면, 80%의 결과는 20%의 원인에 의해 발생한다.

- 다시말해, 사람들이 자주 쓰는 데이터는 정해져 있고 이를 캐싱해서 저장하면 DB에 접근할 필요가 없어진다.

- 서비스를 런칭하고 사용자가 늘어나면 그만큼 DB 작업량도 늘어나기 마련이라 한다.

- 이럴 때 캐시를 사용한다면, 성능을 개선할 수 있다.

 

2.  Cache의 사용 방식

- 캐시는 조회 또는 쓰기를 할 때에 사용될 수 있다.

Look Aside Cache (Lazy Loading) 캐시를 한 번 접근하여 데이터의 존재 유무에 따라 바로 반환 또는 DB (or API) 호출
Write Back 쓰기(Insert) 작업이 많을 때 쿼리를 모아서 배치(Batch)처리

(1) Look aside Cache

- 한 번 조회한 데이터를 캐시에 저장 후, 동일한 데이터를 조회할 때,

  DB에 direct로 접근하지 않고, Look aside(주의를 돌려) 캐시의 내용을 확인한다.

- Process

  - 사용자가 웹서버에 요청을 보낸다.

  - 웹서버는 Cache를 먼저 조회한다.

  - Cache에 데이터가 있다면, 사용자에게 해당 데이터를 반환(Cache Hit)하고,

    Cache에 데이터가 없다면, DB에서 데이터를 조회한 후 해당 데이터를 반환(Cache Miss)한다.

(2) Write Back

- 캐시 안에 일시적으로 저장한 후 한 번에 모아 배치 처리를 하는 것을 말한다.

- 하지만 Write Back을 사용하면 캐시 안의 데이터가 중간에 유실될 수 있기 때문에 사용에 주의가 필요하다.

(3) 그 외에도 Write Through 등등이 있다.

 

|  Redis

REDIS : Remote (외부에 있는) Dictionary (Key-Value형태) Server (서버)

 

1. Redis란?

  한줄 요약 특징
Redis Key-value 형태의 값을 저장할 수 있는 In-Memory 저장소 - Key-Value 형식의 NoSql
- In-memory
- 다양한 데이터 타입 제공
- 주로 캐시로 사용
- 싱글 쓰레드
- Atomic

- Redis는 인메모리 기반의 data structure store로, db/cache/message broker, streaming engine으로 사용될 수 있다.
  * 많은 개발자들은 Redis를 Store가 아닌 Cache라고 분류한다.
  * Redis는 지속성을 보장하기 위해 데이터를 In-Memory 곧, Disk에 저장할 수 있다.

  * 단, In-memory지만 영구적으로 저장할 수 있기도 하다.

- Redis는 NoSQL로 분류되며, Key-Value 형태로 데이터를 저장한다.
- Redis는 문자열, 해쉬, 리스트, Set, sorted Set 형태의 다양한 자료구조를 지원한다.
- Redis는 기본적으로 Single-Threaded하며, 자료구조는 Atomic 한 성질(=원자성, All or nothing)을 가지고 있어

  race condition이 일어나는 것일 예방할 수 있다는 장점을 가지고 있다.

 

2. Redis의 다양한 모드

종류 서버 특징
Single 단일서버 HA미지원
Sentinel 여러서버 Master-slave* 방식, HA지원*
Cluster

* HA(High Availability) : 서버 하나가 죽더라도 나머지 서버들이 서비스를 계속 운영할 수 있도록 하는 전략

* Master-Slave

  - Master : 한 서버에는 하나의 Master노드가 있다.

  -Slave    : Master노드에 대한 복사본

- Cluster 모드에서는, 여러 서버가 있다고 전제할 때, 각 서버의 Master의 복제본은 다른 서버의 Slave에 저장한다.

  이렇게 할 경우, 서버가 다 죽고 하나만 남는다고 하더라도 운영에 지장이 생기지 않게된다.

  1번서버 2번서버 3번서버
Master Master1 Master2 Master3
Slave Master2 복제본 Master1 복제본 Master1 복제본
Slave Master3 복제본 Master3 복제본 Master2 복제본

 

|  Redis 설치하기

** 참고사항 : embeded-redis를 사용할 경우, 아래와 같이 별도로 redis를 설치하지 않고도,
                     스프링 build.gradle에 라이브러리를 추가하는 것만으로도 redis를 사용할 수 있다.

 

1. OS에 맞게 Redis를 설치한다.

https://redis.io/docs/getting-started/

- 윈도우의 경우 리눅스 환경을 만든 후에야 Redis를 설치할 수 있다.

- 윈도우에서 설치할 수 있는 다른 방법이 있는데 아래 사이트를 가면 된다.

https://github.com/microsoftarchive/redis/releases

* 자세한 설치과정에 대한 포스팅

 

[REDIS] 📚 Window10 환경에 Redis 설치 & 설정

Redis 윈도우 설치 Redis 다운로드 페이지로 이동하여 설치 프로그램을 다운로드하고 설치를 진행한다. Releases · microsoftarchive/redis Redis is an in-memory database that persists on disk. The data model is key-value, but

inpa.tistory.com

 

2. redis-cli.exe를 실행한 후, Redis 명령어를 입력해본다.

* Redis gate에 가면 더 자세한 명령어를 확인할 수 있다.

  http://redisgate.kr/redis/introduction/redis_intro.php

• $> set myKey myValue
• $> OK


• $> get myKey
• $> myValue


• $> del myKey
• $> myValue


• $> get myKey

• $> (nil) 

• $> keys*             <-- 모든 데이터 확인 (실제 운영 시에는 사용X)

• $> set key value <-- redis-server.exe 서버 종료

 

|  스프링에서 Redis 사용하기

 

1. 시작하기

(1) Build.gradle에 Redis 라이브러리 추가

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

(2) application.yml에 redis ip주소 및 port번호 입력

redis:
  host: localhost
  port: 6379

(3) @SpringBootApplication 클래스에 @EnableCaching을 추가

@SpringBootApplication
@EnableScheduling
@EnableCaching
public class BaedanguemApplication {

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

    }

}

 

2. RedisConnectionFactory 및 CacheManager Bean 생성

(1) RedisConnectionFactory 빈 생성

- 사용하는 모드에 따라, Configuration인스턴스를 생성한 후, host, port, password 등을 setting한다.

- 이후 LettuceConnectionFactory에 해당 configuration을 넣어 반환하면 빈 생성이 완료된다.

@Configuration
@RequiredArgsConstructor
public class CacheConfig {

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Bean
    public RedisConnectionFactory redisConnectionFactory(){

        // Single 모드
        RedisStandaloneConfiguration conf = new RedisStandaloneConfiguration();

        // Cluster 모드
        // RedisClusterConfiguration conf = new RedisClusterConfiguration();

        conf.setHostName(host);
        conf.setPort(port);

        return new LettuceConnectionFactory(conf);
    }

}

* C:\Program Files\Redis 의 redis.windows-service.conf 파일에서 port, required password 등을 설정할 수 있다.

 

(2) CacheManager 빈 생성

- RedisConnectionFactory를 매개변수로 담은 메소드를 생성한다. (반환 값은 CacheManager)

- RedisCacheConfiguration.defaultCacheConfig()key, value에 대한 Serialization 방식을 설정한다.

!! Redis에 data 또는 Object를 저장하기 위해 직렬화(Serialization)를 통해 data, object를 Byte 단위로 변경한다.

  * Redis는 Java 시스템 외부의 캐시 서버이기 때문에, 외부에 데이터를 저장하기 위해서는 직렬화가 필요하다.

  * 마찬가지로 Redis에서 데이터를 가져와 data, object로 변환할 때에 역직렬화를 사용한다.

- RedisCacheManager.RedisCacheManagerBuilder를 통해

  매개변수의 RedisConnectionFactory와, 바로 위에서 작성한 RedisCacheConfiguration을 담아 반환한다.

@Configuration
@RequiredArgsConstructor
public class CacheConfig {

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Bean
    public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory){

        RedisCacheConfiguration conf = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));

        return RedisCacheManager.RedisCacheManagerBuilder
                .fromConnectionFactory(redisConnectionFactory)
                .cacheDefaults(conf)
                .build();
    }

    @Bean
    public RedisConnectionFactory redisConnectionFactory(){

        // Single 모드
        RedisStandaloneConfiguration conf = new RedisStandaloneConfiguration();

        // Cluster 모드
        // RedisClusterConfiguration conf = new RedisClusterConfiguration();

        conf.setHostName(host);
        conf.setPort(port);

        return new LettuceConnectionFactory(conf);
    }

}

 

3. 조회 요청 시 캐시 저장하기

(1) 조회 요청시 호출되는 메소드에 @Cacheable(key = "", value = "") 추가하기

@Service
class XXXService{

	// 사전 고려사항 : 
	// (1) 자주 요청되는 데이터인가? 그렇다면 캐싱
	// (2) 변경이 잦은 데이터인가?   그렇다면 캐싱x

	// redis server의 key-value와 다른 개념
	@Cacheable(key = "#companyName", value = "finance")
	public ScrapedResult getDividendByCompanyName(String companyName) {
		// 메소드 내용
	}
    
}

ㄴ value 값을 일일히 입력하지 않고, 상수화하여 사용할 수도 있다.

package com.example.baedanguem.model.constants;

public class CacheKey {
    
    public static final String KEY_FINANCE = "finance";
    
}

 

(2) Http 요청을 보낸 후 결과 확인하기

- 수업에서는 Serialization 관련하여 InvalidDefinitionException 오류가 발생했다.

- 원인 : LocalDateTime 타입의 데이터를 캐시에 저장하기 위해 직렬화 하는 과정에서 타입 미스매치 발생

   - 3.에서 직/역직렬화를 StringRedisSerializer가 담당하고 있었기 때문에 LocalDateTime은 직렬화할 수 없다.

- 해결 방법 : 아래 확인

 

(3) 웹서버<->캐시 data 직렬화, 역직렬화  과정에서 타입 미스매치 시

- 수업에서는 Json 타입의 데이터를 송수신 하기 때문에 @JsonSerialize와 @JsonDeserialize를 통해

  직렬화/역직렬화 방식을 지정해주었다.

@Data
@Builder
public class Dividend {

    @JsonSerialize(using = LocalDateTimeSerializer.class)
    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
    private LocalDateTime date;

    private String dividend;

}

>> 이 상태에서, 프로그램을 실행한 후, 컨트롤러를 통해 최초로 데이터를 조회할 경우, 정상적으로 결과값을 받을 수 있다.

>> 그리고 redis-cli.exe에서 keys * 를 입력해 캐싱이 잘 되었는지 확인하면 결과는 아래처럼 나타난다.

127.0.0.1:6379> keys *
1) "finance::3M Company"
127.0.0.1:6379> get "finance::3M Company"
"{\"@class\":\"com.example.baedanguem.model.ScrapedResult\",\"company\":{\"@class\":\"com.example.baedanguem.model.Company\",\"ticker\":\"MMM\",\"name\":\"3M Company\"},\"dividends\":[\"java.util.ArrayList\",[{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2016,11,16,0,0],\"dividend\":\"1.11\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2017,2,15,0,0],\"dividend\":\"1.175\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2017,5,17,0,0],\"dividend\":\"1.175\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2017,8,23,0,0],\"dividend\":\"1.175\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2017,11,22,0,0],\"dividend\":\"1.175\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2018,2,15,0,0],\"dividend\":\"1.36\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2018,5,17,0,0],\"dividend\":\"1.36\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2018,8,23,0,0],\"dividend\":\"1.36\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2018,11,21,0,0],\"dividend\":\"1.36\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2019,2,14,0,0],\"dividend\":\"1.44\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2019,5,23,0,0],\"dividend\":\"1.44\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2019,8,15,0,0],\"dividend\":\"1.44\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2019,11,21,0,0],\"dividend\":\"1.44\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2020,2,13,0,0],\"dividend\":\"1.47\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2020,5,21,0,0],\"dividend\":\"1.47\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2020,8,21,0,0],\"dividend\":\"1.47\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2020,11,19,0,0],\"dividend\":\"1.47\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2021,2,11,0,0],\"dividend\":\"1.48\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2021,5,20,0,0],\"dividend\":\"1.48\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2021,8,20,0,0],\"dividend\":\"1.48\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2021,11,18,0,0],\"dividend\":\"1.48\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2022,2,17,0,0],\"dividend\":\"1.49\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2022,5,19,0,0],\"dividend\":\"1.49\"},{\"@class\":\"com.example.baedanguem.model.Dividend\",\"date\":[2022,8,19,0,0],\"dividend\":\"1.49\"}]]}"

>> 그런데, 이 상태에서 다시 컨트롤러를 통해 동일한 조회 요청을 보내면

     이번엔 아래와 같이 Deserialization을 하려는 Object가 생성자가 없는 Object라는 오류가 나타난다.

     - 원인 : Object에 생성자가 없기 때문에

     - 의문 :  왜 처음에는 오류가 안 났나? == 처음에는 캐시에서 내용을 찾아오지 않고, DB에서 찾아와서.

     - 해결 : Object에 @NoArgsConstructor나 @AllArgsConstructor를 추가한다.

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.example.baedanguem.model.Company` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (byte[])"{"@class":"com.example.baedanguem.model.ScrapedResult","company":{"@class":"com.example.baedanguem.model.Company","ticker":"MMM","name":"3M Company"},"dividends":["java.util.ArrayList",[{"@class":"com.example.baedanguem.model.Dividend","date":[2016,11,16,0,0],"dividend":"1.11"},{"@class":"com.example.baedanguem.model.Dividend","date":[2017,2,15,0,0],"dividend":"1.175"},{"@class":"com.example.baedanguem.model.Dividend","date":[2017,5,17,0,0],"dividend":"1.175"},{"@class":"com.example.baedanguem.m"[truncated 1906 bytes]; line: 1, column: 115] (through reference chain: com.example.baedanguem.model.ScrapedResult["company"])
	at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) ~[jackson-databind-2.12.5.jar:2.12.5]
	at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1764) ~[jackson-databind-2.12.5.jar:2.12.5]

 

(4)  추가적인 내용

- 스프링 프로그램을 종료하더라도, 캐시 서버에는 데이터가 남아있다.

- @Cacheable 메소드 안에 log를 남길 경우, 처음 DB에서 데이터를 조회할 때 콘솔에 로그가 남지만,

  캐시에서 데이터를 조회할 때에는 콘솔에 log가 남지 않는다.

 

4. 레디스 캐시 삭제

- 데이터가 업데이트 되었음에도 캐시에 이전 데이터가 남아다면, 이전 조회기록을 가져오게 된다.

- 따라서, 해당 캐시의 내용을 업데이트하거나, 해당 내용을 삭제하는 것이 필요하다.

- 더불어, 캐시 공간 또한 한계가 있기 때문에 오래된 캐시 데이터는 삭제하는 것이 필요하다.

* 수업에서는, 매일 00시에 데이터를 받아 업데이트를 진행하기 때문에, 스케줄러 메소드에 작업을 했다.

 

(1) @CacheEvict를 사용하여 특정 value 의 데이터를 삭제한다.

- 앞서서 캐시한 조회 메소드에 @Cacheable(key = "#companyName", value = "finance") 설정을 했었다.

- @CacheEvict의 value에 설정했던 "finance"를 넣어주고, allEntries = true 를 하면 "finance"로 캐시된 모든 데이터를 삭제한다.

@CacheEvict(value = CacheKey.KEY_FINANCE, allEntries = true)
@Scheduled(cron = "${scheduler.scrap.yahoo}")
public void yahooFinanceScheduling() {
   // 내용  
}

- 만약, 특정 데이터만 삭제하고 싶다면, key값에 해당 데이터의 key값을 넣어주면 된다.

@CacheEvict(value = CacheKey.KEY_FINANCE, key = "someCompany")
@Scheduled(cron = "${scheduler.scrap.yahoo}")
public void yahooFinanceScheduling() {
   // 내용  
}

 

(2) @CacheEvict를 붙인 스케줄러에 @EnableCaching을 추가한다.

- 스케줄러는 Main 메소드와 다른 쓰레드를 사용한다.

- 스케줄러가 동작할 때마다, @EnableCaching이 이루어질 수 있도록 추가한다.

@Component
@AllArgsConstructor
@EnableCaching
@Slf4j
public class ScraperScheduler {

    @CacheEvict(value = CacheKey.KEY_FINANCE, allEntries = true)
    @Scheduled(cron = "${scheduler.scrap.yahoo}")
    public void yahooFinanceScheduling() {
       // 내용  
    }
    
}

 

(3) TTL (Time to Live) 설정하기

- TTL : 데이터의 유효기간

- 앞에서 CacheConfig작성시 RedisCacheConfiguration을 작성했던 부분에 TTL 기간을 추가한다.

@Configuration
@RequiredArgsConstructor
public class CacheConfig {

    @Value("${spring.redis.host}")
    private String host;

    @Value("${spring.redis.port}")
    private int port;

    @Bean
    public CacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory){

        RedisCacheConfiguration conf = RedisCacheConfiguration.defaultCacheConfig()
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
                .entryTtl(Duration.ofDays(30)); // TTL 시간 지정 

        return RedisCacheManager.RedisCacheManagerBuilder
                .fromConnectionFactory(redisConnectionFactory)
                .cacheDefaults(conf)
                .build();
    }

}

 

 

[ 참고 및 출처 ]

부트캠프 내용 정리

Redis란?

https://steady-coding.tistory.com/586

https://www.baeldung.com/spring-boot-redis-cache

Redis 윈도우 10 환경에서 설치 후 실행하기

https://inpa.tistory.com/entry/REDIS-%F0%9F%93%9A-Window10-%ED%99%98%EA%B2%BD%EC%97%90-Redis-%EC%84%A4%EC%B9%98%ED%95%98%EA%B8%B0

 

1. 레디스 개념 및 특징

https://www.youtube.com/watch?v=Gimv7hroM8A 

https://www.youtube.com/watch?v=mPB2CZiAkKM 

- 이탈리아의 한 해커가 MySQL 로 작업 중 DB 처리 속도가 너무 느린 것을 보고 레디스를 만들었다.
- REDIS : Remote (외부에 있는) Dictionary (Key-Value형태) Server (서버)
- 공식문서에 따르면, Redis는 인메모리 기반의 data structure store로,
   db/cache/message broker, streaming engine으로 사용될 수 있다고 한다.
  * 단, 많은 개발자들은 Redis를 Store가 아닌 Cache라고 분류한다.
  * Redis는 지속성을 보장하기 위해 데이터를 Disk에 저장할 수 있다.
- Redis는 NoSQL로 분류되며, Key-Value 형태로 데이터를 저장하는데,
  Value 타입으로 문자열, 해쉬, 리스트, Set, sorted Set 형태의 다양한 자료구조를 지원한다.
- Redis는 기본적으로 Single-Threaded이며, 자료구조는 Atomic 한 성질을 가지고 있다. 
  * 서로 다른 트랜잭션에 대한 Read/Write를 동기화한다.

- 언제 쓸까? 
> 싱글 서버일 때 : Atomic 자료구조 + 캐시 기능 사용
ㄴ 이메일 인증 기능
ㄴ 좋아요, 조회수 처리
ㄴ 랭킹 보드로 사용
ㄴ 유저 API 제한 : ex. 주문 시 재고 확인
  * 캐시 : 여기서의 캐시란, 나중에 할 요청 처리를 미리 저장해 두었다가 빠르게 서비스해주는 걸 말한다.

- 주의할 점
> 싱글 쓰레드 서버이므로 시간 복잡도를 고려해야한다.
> 인-메모리 특성상 메모리 파편화, 가상 메모리 등의 이해가 필요하다.

- 싱글 쓰레드를 쓰는 이유?
> 비동기, 컨텍스트 스위칭 효율성 등

https://codingmania.tistory.com/18

https://blog.kingbbode.com/25

 

2. 레디스의 활용 사례

https://happyer16.tistory.com/entry/%EB%A0%88%EB%94%94%EC%8A%A4Redis%EC%9D%98-%EB%8B%A4%EC%96%91%ED%95%9C-%ED%99%9C%EC%9A%A9-%EC%82%AC%EB%A1%80

 

레디스(Redis)의 다양한 활용 사례

들어가기 전에 나는 아직 실력이 부족한 개발자여서 레디스=캐시 로의 의미로만 이해하고 있었다. 대부분의 서비스에서 단순 캐시용도로만 사용하기도 한다. 레디스에 대해 정확히 이해를 하지

happyer16.tistory.com

 

3. 레디스를 통해 캐시 처리하기

- 레디스를 언제 캐시로 사용하면 좋은가?

https://yonguri.tistory.com/82

- 레디스를 캐시로 사용한 사례(정리가 정말 깔끔하다.)

https://www.woolog.dev/backend/spring-boot/spring-boot-redis-cache-simple/#%EC%82%AC%EC%9A%A9-%ED%95%A0-redis-%EA%B0%84%EB%8B%A8-%EC%84%A4%EB%AA%85

- 레디스를 통해 조회수 처리하기

https://dev-monkey-dugi.tistory.com/151

- 레디스를 통해 좋아요 처리하기

https://intrepidgeeks.com/tutorial/create-a-good-spring-boot-redis-cache-system.

 

4. 레디스의 Redisson을 통해 분산락 처리하기

https://kkambi.tistory.com/196

레디스를 통해 재고관리하기 https://mslim8803.tistory.com/74?category=1005542 

 

6. 레디스 사용 방법 (공식 사이트)

https://redis.io/docs/about/

 

Introduction to Redis

Learn about the Redis open source project

redis.io

 

+ Recent posts