그 주의 화요일, 금요일을 지정 날짜로 업데이트 합니다
UnsupportedOperationException 에러는 일반적으로 List 형을 new로 초기화하지 않는 상태에서 Arrays로 생성 하였을 시 주로 발생한다.
@Entity
public class Line extends BaseEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "line", cascade = CascadeType.All)
private List<Section> sections = new ArrayList<>();
...
public List<Section> getSections() {
return sections;
}
}
나의 경우 다음과 같은 Line 의 List<Section> sections
를 아래와 같이 일급 컬렉션으로 리팩터링을 진행하던 도중 작성했었던 인수 테스트가 실패하였다.
@Entity
public class Line extends BaseEntity {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Embedded
private Sections sections = new Sections();
...
public List<Section> getSections() {
return sections.getSections();
}
}
@Embeddable
public class Sections {
@OneToMany(mappedBy = "line", cascade = CascadeType.All))
private List<Section> sections = new ArrayList<>();
...
public List<Section> getSections(){
return Collections.unmodifiableList(sections);
}
오류가 발생했던 부분은 아래의 LineService 에서 addLine 메서드를 통해 Section 부분을 추가하는 다음과 같은 코드였고 UnsupportedOperationException
에러가 발생하였다.
line.getSections().add(new Section(line, upStation, downStation, distance));
원인 은 getSections()
를 할때, 일급 컬렉션의 getSections 를 통해서 unmodifiableList
되어있는 sections 를 가져오게 되었는데, 때문에 변경이 안되게 되어 발생 하게 되었다.
임시 해결 로 return Collections.unmodifiableList(sections);
대신 return sections;
를 하게 된다면 문제는 해결된다.
하지만, 이건 나중에 _일급 컬렉션을 건드릴 수 있는 문제의 여지를 남겨두게되므로
LineService의 비즈니스 로직을 도메인으로 옮기고 return Collections.unmodifiableList(sections);
를 유지하는 것이 적합하다.
인수 테스트 기반 리팩터링 미션
- LineService의 비즈니스 로직을 도메인으로 옮기는 리팩터링 진행
Service layer 의 비즈니스 로직을 도메인(Domain) 으로 옮겨야하는 이유에 관한 블로그 포스팅 정리
쿠키와 세션에 대한 개념들과 이 것들을 왜 사용하는지에 관해 이전에 학습했던 내용들이
인프라 미션을 진행하고 네트워크에 관해 학습을 해나가면서
다시 한번 혼동되는 개념들을 잡고 좀 더 깊숙하게 학습해보기 위해 블로그 포스팅 을 진행하였다.
+ (추가) 서드 파티 쿠키
쿠키의 종류는 퍼스트 파티 쿠키(First-Party-Cookie)
, 서드 파티 쿠키(Third-Party-Cookie)
가 있다.
서드 파티 쿠키는 사용자의 온라인상 행동을 추적 및 데이터를 분석하여 광고 등에 사용할 수 있지만 개인정보보호를 침해할 수 있다는 위험도 존재하여
구글에서는 서드파티 쿠키의 지원을 중단할 것이라고 발표하고 서드 파티 쿠키를 대체할 기술 플록(Floc) 에 대하여 개발자 버전을 배포하기도 하였다.
쉘 스크립트란, 간단히 말하자면 Unix 커맨드(명령어) 등을 나열해서 실행하는 것이다.
쉘 스크립트는 파일안에 스크립트 작성 후, 실행 시 해당 스크립트가 실행되는 방식으로 이루어진다.
서버 작업 자동화를 위해 작성되며, 언제 어떤 조건으로 어떠한 명령을 실행시킬 것인가, 파일을 컨텐츠를 읽어 들일 것인가, 로그 파일을 작성하는 것 등을 할 수 있다.
배포 미션 ( 배포 스크립트 작성하기 )
배포는 작성한 코드를 실제 서버에 반영하는 것으로,
배포할때는 git clone 혹은 git pull을 통해 새 버전의 프로젝트를 받거나, Gradle이나 Maven을 통해 프로젝트 테스트와 빌드, EC2 서버에서 해당 프로젝트 실행 및 재실행 하는 등의 과정들이 필요하게 된다.
위와 같은 과정을 배포할 때마다 매번 (명령어를) 실행시키는 것은 번거롭기 때문에 반복적으로 동작하는 명령어를 배포 스크립트로 작성해보았다.
ddl-auto 옵션 종류는 다음과 같다.
create
: 기존테이블 삭제 후 다시 생성 (DROP + CREATE)create-drop
: create와 같으나 종료시점에 테이블 DROPupdate
: 변경분만 반영validate
: 엔티티와 테이블이 정상 매핑되었는지만 확인none
: 사용하지 않음실제 서비스 배포시(운영 환경)에는 create, create-drop, update 와 같은 옵션을 사용하면 안되지만 개발 초기 테스트시에는 유용하게 사용할 수 있다.
+) update
의 경우 변경 부분만 반영하기 때문에 alter table 쿼리가 나가는 것을 확인할 수 있는데, alter table이 되는 동안 데이터베이스가 lock이 걸려서 서비스가 멈출 수 있기 때문에 자제해야한다.
배포 미션 피드백
배포 미션 중 운영,local,test 에 따른 설정 파일을 나누며 큰 실수를 발견하였다.
운영 설정 파일에서ddl-auto
옵션 을create-drop
으로 설정한 것이다.
테이블을 DROP 시킬 수는 없으므로(😱) 운영환경은validate
설정으로 해두어야 한다.spring.jpa.hibernate.ddl-auto=validate
무중단 배포의 필요 조건
두 대 이상의 서버를 서비스해야 한다.
다운 타임이 발생하지 않도록, 실제 서비스 중인 서버와 새롭게 배포한 서버가 동시에 존재해야 한다.
비용을 줄이려면 배포할 때만 새롭게 서버를 띄우고 배포가 완료된 후에 기존 서버는 죽이면 된다.
무중단 배포의 방법
롤링 배포 (Rolling Deployment)
일반적인 배포를 의미하며, 배포된 서버를 한 대씩 구 버전에서 새 버전으로 교체 하는 방법이다.
(ex. 서버1,2가 있을 때 서버1을 로드밸런서에서 뺀 후에 배포를 진행하고 다시 로드밸런서에 넣는다. 이후 서버2도 동일하게 진행하면 1,2에 배포가 완료되었다.)
단, 그렇게 되면 배포를 진행 중에 서버1,2 사용자들이 서로 다른 서비스를 받고 있다는 문제점이 발생한다.
또한 1대에 배포하는 것보다 최소 2배 이상 느릴 수 밖에 없다.
블루 그린 배포(Blue Green)
실제로 서비스 중인 환경(Blue/구 버전)와 새롭게 배포할 환경(Green/신 버전)을 세트로 준비해서 배포하는 방법이다.
로드밸런서가 블루에 연결되어있다가 새롭게 배포한 그린 서버에 로드밸런서 방향을 바꿔주는 것이다.
구 버전, 신 버전 서버를 동시에 나란히 구성하여 ( 배포 시점에 트래픽이 일제히 전환 )
짧은 시간동안 서버를 가리키는 것만으로(그린으로 변경) 배포가 끝난 상태가 되므로 가장 속도가 빠르고 빠른 롤백이 가능하다.
단, 시스템 자원이 두배로 필요하여 비용이 더 많이 발생한다.
카나리 배포(Canary)
소수의 유저(사내)만 사용하는 환경(Canary 환경)에 신규 버전을 배포하고 문제가 없다고 판단되었을 때 다른 모든 서버에 배포 하는 방법이다.
서버의 트래픽을 일부를 신 버전으로 분산하여 오류 여부를 확인할 수 있고 위험을 빠르게 감지할 수 있는 전략이다.
배포 미션
배포 포스팅 에서 무중단 배포에 및 배포에 관해 포스팅 재정리를 진행하였다.
빌드, 배포, 테스트 자동화란 무엇일까?
개발자는 단순히 git에 수정된 코드를 올리기만하고,
컴파일, 테스트, 빌드, 배포 등의 과정은 정해진 절차에따라 특정 프로그램이 자동으로 수행하는 것이다.
이 자동화에 관련하여 CI/CD 에 관해 학습을 진행하였다.
CI (Continuous Integration)
개발자를 위한 자동화 프로세스인 지속적 통합 으로, 모든 개발이 끝난 이후에 코드 품질을 관리하는 고전적 방식의 단점(비용적 측면 등)을 해소하기위해 나타난 개념이다.
개발을 하면서 지속적으로 코드에 대한 통합을 진행함으로써 발생하는 에러들을 확인하고 고쳐나가는 것이다. (품질을 유지하는 것이다)
프로세스를 살펴보면 자신이 개발한 코드를 git 에 올려서 통합하고 (코드 통합), 통합한 코드가 제대로 동작하는지 테스트하고, 제대로 빌드하는지 테스트한다. 만약 버그가 존재한다면 적어두고 결과를 정리한다.
이런 과정들을 자동화해주기 위해 나온 자동화 도구가 Jenkis
, Travis
이다.
(한마디로 CI를 하기 위한 프로세스들을 자동화하도록 도와주는 툴이다.)
CD (Continuous Deploy 또는 Delivery)
지속적 배포 로, 소프트웨어가 항상 신뢰 가능한 수준(테스트,빌드 통과)에서 배포될 수 있도록 지속적으로 관리하자는 개념이다.
(CI 에서도 빌드가 잘 되는지 테스트하는 과정들이 관련있기 때문에 CI 가 가능함에 따라 CD 가 가능하다는 느낌으로 CI/CD를 통칭해서 부르는 것 같다)
결국 한마디로 요약하자면,
지속적으로 통합하면서 테스트와 빌드를 진행하고 이를 통과한 코드에 대해서 배포할 수 있다 는 개념이다.
왜 CI/CD 를 사용해야하고, 사용함으로써 얻는 이점은 무엇인지는 추가적으로 다시 정리를 해야겠다.
배포 스크립트를 작성해보며 배포 과정/미션들을 다시 한번 회고하고
배포와 관련하여 무중단 배포, CI/CD에 대하여 추가적으로 학습을 진행하였다.
이전에는 배포 프로세스를 만들면서 고민할 수 있는 내용으로 무중단 배포가 중요하다는 것까지만 그쳤었지만
추가적으로 무중단 배포를 하기 위한 필요 조건과 무중단 배포의 방법들에 대하여 더 알아볼 수 있었다.
또한 이번에 Jenkis에 관해 간략하게 학습하였는데 다음에 직접 적용을 해보며 포스팅을 진행해야겠다.
[참조]
https://yeonyeon.tistory.com/52
https://engineer-mole.tistory.com/200
https://whitepro.tistory.com/403
-ci/cd
https://itholic.github.io/qa-cicd/
-배포
https://wonit.tistory.com/330
https://velog.io/@znftm97/%EB%AC%B4%EC%A4%91%EB%8B%A8-%EB%B0%B0%ED%8F%AC%EB%A5%BC-%EC%9C%84%ED%95%9C-%ED%99%98%EA%B2%BD-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0#span-stylecolord9730d5-2-%EB%B8%94%EB%A3%A8-%EA%B7%B8%EB%A6%B0blue-greenspan
10분 테코톡 - 빌드와 배포
프로젝트 공방 1기- 배포 스크립트 작성