테이블을 설계하다 보면 자기 자신을 참조하는 경우가 있다. 이를 JPA로 나타내자면 아래와 같다.

@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Category {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    private Category parent;

    @Builder.Default
    @OneToMany(mappedBy = "parent")
    private Set<Category> children = new HashSet<>();
}

 

 

이와 다른 형태로는 아래와 같은데 이와 다르게 자식 테이블이 별도로 생성되어 이 경우 불필요한 join query가 불필요하게 발생되어 아래와 같은 방식 보단 첫번째 방식으로 계층형 테이블을 설계해야 한다

 

@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Category {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany
    private Set<Category> children = new HashSet<>();
}

 

반응형

SQL과 객체지향언어가 갖는 큰 차이점 중 하나가 바로 상속의 유무이다.

객체 지향언어는 상속을 지원하지만, 데이터베이스는 상속을 지원하지 않는다. 

 

스프링에서는 JPA를 이용하여 ORM 기술을 사용하는데, 클래스 간 상속 관계에 대해서는 어떻게 정의를 하는지 알아보자.

 

물리 모델을 데이터 베이스 테이블로 구현하는 방법에는 크게 4가지 방법이 존재한다.

 

- MappedSupperclass

- Single Table 전략

- Joined Table 전략

- Table per Class 전략

 

MappedSuperclass 

 

MappedSuperclass 어노테이션은 부모클래스를 데이터베이스의 테이블로 매핑하지 않고 자식클래스에게 매핑 정보를 제공하고 싶을 때만 사용한다.

 

특징

- MappedSuperclass 어노테이션을 사용한 클래스는 엔티티가 아니다. 따라서 해당 클래스를 가지고 영속성 컨텍스트 또는 JPQL 등에서 사용할 수 없다.

- MappedSuperclass 어노테이션을 사용한 클래스는 자체적으로 의미가 없기에 추상 클래스로 만드는 것이 좋다.

 

Single Table 전략

 

Single Table 전략은 각 클래스 계층에 대해 하나의 테이블을 만들며 명시적으로 지정하지 않는 경우 JPA에서는 Default로 해당 전략을 사용한다. 

discriminatorType으로 식별자를 integer로 할 것 인지 혹은 다른 타입으로 지정할 것인지 선택할 수 있다. name을 지정하게 되면 해당 식별자의 이름이 지정되어 테이블로 들어간다. 

 

특징

- 싱글 테이블이기 때문에 조인 쿼리를 사용하지 않고 한 번에 조회가 가능하다.

- 싱글 테이블이기 때문에 null 값이 들어가는 자료가 생긴다.

- 단일 테이블로 유지하기 때문에 테이블의 크기가 커진다.

 

Joined Table 전략

 

조인 전략은 계층 구조를 띄는 각 클래스가 해당 테이블로 매핑된다. 이 때, 테이블마다 반복되는 열이 하나가 있는 데, 이는 조인할 때 반드시 필요한 식별자 이다. 

 

특징

- 테이블을 정규화 할 수 있다.

- 저장공간을 효율적으로 사용한다 이는 정규화를 실시했기 때문이다.

- 조회할 때 외래키를 이용하여 조인 쿼리를 사용하기 때문에 성능이 좋지 않다.

- 데이터 등록 시 쿼리가 한 번 더 발생한다. 

 

Table per Class

 

Table per Class 는 각각의 테이블을 모두 생성하는 전략이다. 결과적으로 MappedSuperclass를 사용한 것돠 유사하다. 그러나 Table per Class 전략에서는 상위 클래스에 대한 엔티티를 정의하기 때문에 상위 클래스를 연결 및 쿼리 사용이 가능하다.

 

특징

- 서브 타입과 구분해서 처리할 때 효과적이다.

- 상속 없이 각 엔티티를 매핑하는 것과 다르지 않아, Union을 사용하여 쿼리를 작성한다.

- Union 쿼리로 인해 성능이 저하될 수 있다.

반응형

Lombok 에서 'is' prefix가 붙은 컬럼의 boolean과 Boolean의 타입 차에 따라 직렬화시 값이 달라진다. 

 

@Getter
@Setter
public class Member {

    private boolean isDisabled;

    public void test(){
        this.setDisabled(true);  //Lombok - 자동생성된 setter
        this.isDisabled();       //Lombok - 자동생성된 getter
    }
}

@Getter
@Setter
public class Member {

    private Boolean isDisabled;

    public void test(){
        this.setIsDisabled(true);  //Lombok - 자동생성된 setter
        this.getIsDisabled();      //Lombok - 자동생성된 getter
    }
}

 

위와 같이 객체의 속성이 boolean 타입에 'is' prefix를 사용하게 될 경우, getter가 isXXXX로 생성되기 때문에 정상적인 동작이 이루어지지 않는다 때문에 아래처럼 @JsonProperty의 is를 제거한 상태로 넣거나 getIsXXXX() getter() 메서드를 작성하면 정상 동작한다.

@Getter
@Setter
public class Member {

	@JsonProperty("disabled")
    private boolean isDisabled;

    public void test(){
        this.setDisabled(true);  //Lombok - 자동생성된 setter
    }
}

 

다른 방법은 타입을 Warpper class인  Boolean으로 사용하여 getter, setter를 생성하면된다.

반응형

서론

 

JPA에 Cache 적용방법에 대해 다루고자 한다. 먼저 Cache 적용 기준 및 패턴에 대한 소개 및 적용 방법에 대해 설명하고자 한다. 또한 Spring Actuator를 통해 캐시 Metric에 대한 변화도 함께 살펴보고자 한다.

 

 

1. Cache 적용 기준

캐시는 기본적으로 속도와 효율성을 위한 기술로 테이터를 빠르게 제공하고 시스템 자원을 절약하는 것이 목적으로써 애플리케이션 레벨에서의 캐시란 데이터베이스나 외부 API 호출 결과를 캐싱해 불필요한 중복 작업(DB I/O 및 Newtork I/O)를 줄이기 위해 사용하며 이를 통해 시스템의 응답 시간 개선 및 리소스를 절약할 수 있다.

 

그렇다면 Cache의 적용 기준은 어떻게 될까

 

1. 데이터의 접근 빈도(Frequency of Access)

 자주 사용되어지는 데이터를 캐싱하는 것이 가장 기본적인 원칙이며 자주 조회되는 제품 목록, 사용자의 프로필 정보등이 이에 해당된다. 

 

2. 데이터의 크기(Size of Data)

 캐시는  제한된 용량을 가지므로 데이터 사이즈가 작교 자주 요청되는 데이터를 우선적으로 캐시하는 것이 좋다. 

 

3. 데이터 변동성 (Volatility of Data)

캐시할 데이터가 변동이 적고 안정적인지 판단해야 한다. 자주 변동되는 데이터는 캐시에 저장되더라도 무효화시점이 빠르기 때문에 캐시의 이점이 크지 않을 수 있기 때문이다.

 

4. 데이터 일관성 요구사항 (Consistency Requirements)

 캐시는 일관성 문제를 발생 시킬 수 있기 때문에 캐시된 데이터가 최신 데이터와 불일치할 가능성이 있기 때문에 일관성이 중요한 애플리케이션에서 캐시의 적용을 신중히 해야 한다.

 

5. 캐시 히트율 (Cache Hit Rate)

 캐시가 효과적으로 동작하는지 판단하는 중요한 기준은 캐시 히트율이다. 히트율이 높으면 캐시가 제대로 동작하고 있다는 뜻이며, 히트율이 낮으면 캐시의 적용범위나 정책을 조정해야 한다.

 

2. Cache 패턴

 캐시에 적용되는 패턴은 크게 세가지 인데 다음과 같다.

 

1. No Caching

 

 Application에서 직접 DB로 요청하는 방식을 말하며, 별도 캐시 내역이 없으므로 매번 DB와의 통신이 필요하며 이는 캐시를 사용하는 경우와 비교했을때 DB I/O에 영향을 보다 더 주게 된다. 

 

2. Cache-aside

 

 Application 기동시 캐시에는 아무 데이터가 없으며, Application 이 요청시에 Cache Miss가 발생하면, DB로부터 데이터를 읽어와 Cache에 적재한다. 이후에 동일한 요청이 반복되면 캐시에 데이터가 존재하므로 DB 조회 없이 바로 데이터를 전달 받을 수 있다.

 

3. Cache-through

 

 캐시 데이터가 없는 상황에서 Miss가 발생했을 때 Application이 아닌 캐시 제공자가 데이터를 처리한 다음 Application에게 데이터를 전달하는 방법이다. 즉 기존 동기화의 책임이 Application에 있다면 해당 패턴은 캐시 제공자에게 책임이 위임된다.

Cache-through 패턴은 다음과 같이 세분화 할 수 있다.

 

Read-through

 

데이터 읽기 요청 시, 캐시 제공자가 DB와의 연계를 통해 데이터를 적재하고 이를 반환한다.

 

Write-through

 

데이터 쓰기 요청 시,  Application은 캐시에만 적용을 요청하면, 캐시 제공자가 DB에 데이터를 저장하고, Application에게 응답하는 방식이며. 모든 작업은 동기로 진행된다

 

Write-through

데이터 쓰기 요청시, Application은 데이터를 캐시에만 반영한 다음 요청을 종료하며. 이후 일정 시간을 간격으로 비동기적으로 캐시에서 DB로 데이터를 저장 요청한다. 이 방식은 Application의 쓰기 요청 성능을 높일 수 있으나 만약 캐시에 DB에 저장하기 전에 다운된다면, 데이터 유실이 발생한다

 

 

반응형
#docker install
sudo yum install docker -y


#docker remove
sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-selinux  docker-engine-selinux docker-engine docker-ce
#set docker repo and instal docker-ce
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce --allowerasing


#
sudo systemctl start docker
sudo systemctl enable docker
sudo systemctl status docker



#add user to docker group
sudo usermod -aG docker $USER

#docker-compose 설치 
sudo curl -L "https://github.com/docker/compose/releases/download/v2.27.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

#docker-compose 실행 권한 부여
sudo chmod +x /usr/local/bin/docker-compose

#설치된 docker-compose 실행 확인
docker-compose --version
반응형

ELB란 Elastic Load Balancer의 준말로 ELB 설정 정보를 다루기 전 로드 밸런서란 무엇인지에 대해 집고 갔으면 한다.

로드 밸런서란?

- 로드 밸런서는 (부하 분산장치)는 다수의 서버로, 또는 다수의 인스턴스로 트래픽을 분산하는 것을 의미한다 

왜 로드 밸러서를 사용해야하는가

  • 여러 다운스트림 인스턴스에 로드 분산을 할 수 있다.
  • 애플리케이션의 단일 액세스 지점을 노출 할 수 있다.

이러한 ELB를 설정하기 이전에 Target Group(대상그룹)을 설정해야 한다.

대상그룹이란 ELB 생성을 통해 생성을 한다면 아래처럼 리스너 및 라우팅에서 대상 그룹과 프로토콜을 지정하는데 이때의 대상 그룹을 의미한다.

리스너 및 라우팅

 

ELB는 가용 영역 및 로드 밸런서 노드를 설정한다.  로드 밸런서에서 아래 네트워크 매핑의 가용 영역을 활성화하면 ELB가 해당 가용 영역에 로드 밸런서 노드를 생성한다. 

네트워크 맵핑

 

가용영역을 매핑하면 해당 가용영역에 아래와 같이 활성화된 서브넷 영역을 드롭다운 메뉴로 보여주며 

 

 

ELB를 통해 AZ에서 활성화된 프라이빗 서브넷 영역의 타깃 그룹으로 연결을 시켜준다 생각하면 된다.  또한 이 연결된 로드 밸런서를 Route53과 맵핑을 시켜준다면 아래와 같은 플로우를 타게 된다.

 

Route53에서 지정된 도메인 주소 -> elb -> public subnet -> private subnet영역에 위치한 target group

 

필자는 온프레미스로 올려서 위의 VPC를 다른 프라이빗 IP주소로 선택하였고 때문에 기존 서버 주소, 온프레미스 서버주소 두개를 타겟그룹으로 지정하였고 이렇게 설정하게 되면 로드밸러서가 라운드 로빈 방식으로 통신을 진행하게 된다.

반응형

EB를 설정하기 이전에 우선 EB가 올라가야할 VPC 영역에 기본적인 셋팅을 진행해야 하는데 기본적인 셋팅이란 VPC 내의 서브넷 RT를 IGW와 연결을 해줘야만 한다. 또한 프라이빗 서브넷 영역의 RT에는 NAT가 등록되어 퍼블릭 영역과 통신 가능하게 되어야 기본 셋팅이 되었다고 할 수 있다. 

다음은 EB인스턴스 프로파일 관리이다,

인스턴스 프로파일이란 AWS IAM 역할을 위한 컨테이너로서 인스턴스 시작 시 Amazon EC2 인스턴스에 역할 정보를 전달하는 데 사용된다. 이를 설정 안할시 바로 실패를 경험할 것이다. 이전 EB는 AWS 계정이 처음으로 환경을 생성할 때 이름이 aws-elasticbeanstalk-ec2-role인 기본 EC2 인스턴스 프로파일을 생성했습니다. 이 인스턴스 프로파일에는 기본 관리형 정책이 포함되었습니다. 그러나 최근 AWS 보안 지침에서는 AWS 서비스가 다른 AWS 서비스(이 경우 EC2)에 대한 신뢰 정책을 사용하여 역할을 자동으로 생성하는 것을 허용하지 않습니다. 이러한 보안 지침 때문에 Elastic Beanstalk는 더 이상 기본 aws-elasticbeanstalk-ec2-role 인스턴스 프로파일을 생성하지 않습니다.

 

Elastic Beanstalk은 사용자 환경이 다양한 사용 사례를 충족할 수 있도록 여러 관리형 정책을 제공한다.

- AWSElasticBeanstalkWebTier

- AWSElasticBeanstalkWorkTier

- AWSElasticBeanstalkMulticontainerDocker

 

서비스 엑세스 구성

 

새 서비스/ 기존 서비스 역할은 아래와 같이 설정을 해주웠다.

EC2 인스턴스 프로파일은 앞서 언급한 세개의 권한을 포함하여 아래와 같이 신규 역할을 생성하였으며

반응형

VPC 를 설정하다 보면 왼쪽 보안 영역에 네트워크 ACL(NACL) 과 보안 그룹(Security Group) 에 대한 영역을 확인할 수 있다.

NACL과 SecurityGroup은 우선적으로 적용되는 영역이 다른데, 아래와 같다.

NACL

VPC -> NACL -> Subnet

SecurityGroup

VPC -> NACL -> Subnet -> SecurityGroup

 

SecurityGroup 과 NACL에 대한 내용을 보다보면 Stateless와 Stateful 이라는 용어가 나오는데 

- Stateless란 : 요청 정보를 따로 저장하지 않아 응답하는 트래픽도 제어를 해줘야 한다.(NACL)

- Stateful : 요청 정보를 저장하여 응답하는 트래픽 제어를 하지 않는다(SecurityGroup)

 

다시 표로써 NACL 과 SecurityGroup을 정리하자면

  NACL Security Group
적용 단위 서브넷 단위 인스턴스 단위
상태 저장 여부 Stateless Stateful
Order 순서 있음 순서 없음
Action Allow, Deny Allow만 가능

 

반응형

+ Recent posts