Spring Boot 2.0 버전의 특징

|

스프링부트 2.0의 특징

스프링부트 2.1.5을 주로 사용했는데, 특징이나 그전 버전과의 차이점을 제대로 알지 못해서 블로그에 정리하기 위하여 글을 썻다

자바 8이상 버전부터 가능

  • 최소 java 8+ 부터 지원, 그전 버전은 jdk를 업그레이드 하지 않는 이상 사용이 불가능하다. 제발 그전 버전은 사용하지 말자

Spring WebFlux 도입

  • Spring WebFlux의 도입. Spring MVC와 같이 사용 가능
    • 복수개의 서비스로 이루어진 분산 시스템을 제공, MSA에 적합하다
    • 비동기, 논블록킹 방식의 리엑티브 개발가능
    • 효율적으로 동작하는 고성능 웹 어플리케이션 개발 가능
    • 서비스간 호출이 많은 MSA에 적합하다.
  • AutoConfigration을 제공, 기존에는 내장 톰캣만 지원 -> Netty 등 내장 서버 구성 지원을 해준다
  • @WebFluxTest을 통해서 테스트도 가능하다.
  • 서드파티 라이브러리가 도입되면서 최소버전등이 올라갔음

Spring Loaded -> Spring devtools

  • 그전 Spring Loaded가 지원을 안한다고 한다. 대신 devtools를 지원하는데, 이 라이브러리는 프로그래머가 어플리케이션 개발을 좀 더 편하게 할 수 있도록 도와준다.
    • 캐싱기능 비활성화, 자동 새로고침 처리 등등의 기능을 지원해준다

HTTP/2 지원

  • 공식적으로 HTTP/2를 지원한다. 기존의 HTTP1.1과 호환성을 유지한다.
  • 특징
    • HTTP 헤더 데이터 압축
    • 서버 푸시 기술
    • 요청을 HTTP 파이프라인으로 처리
    • TCP 연결 하나로 여러 요청을 다중화 처리
    • 이런 특징으로 인해서 네트워크 지연시간을 줄이고, 웹 브라우저 렌더링 속도를 향상시킵니다.

Configuration Properties

  • 언더스코어, 카멜 표기법등을 지원했지만 현재는 소문자와 kebab-case만 지원합니다. 하이픈으로 연결하는 방식만 지원
  • ex) spring.jpa.databaseplatform=mysql

Data Support

  • 커넥션풀 변경
    • 커넥션풀이 톰캣에서 HikariCP로 변경됨.
  • 몇몇 reactive Data 자동설정을 지원해줌
    • 몽고 db, Redis 등등

Spring Framework 5.0

  • 스프링 프레임워크 5.0기반으로 작동한다. 스프링 프레임워크 리엑티브로 인해 많은 변경점이 생겼다.

Starter 및 Test 지원

  • 새로운 spring-boot-starter-json가 추가 되었다. jackson-databind 뿐만아니라 java8에서 유용하게 사용할 수 있는 jackson-datatype-jdk8와 Thymeleaf starter 등을 지원한다.

  • @DataRedisTest를 통해서 간단하게 Redis 테스트 가능

Gradle 플러그인 개선

  • Spring boot의 Gradle plugin 개선

Quartz 스케쥴러 전용 starter 지원

  • 쿼츠는 자바 어플리케이션에 통합할 수 있는 오픈소스 스케쥴링 라이브러리라고 한다. Database 설정을 안할 경우 인메모리 방식으로 작동한다. 결국 어플리케이션을 재시작할 경우 휘발성으로 데이터는 사라진다.

출처

  • https://brunch.co.kr/@springboot/55
  • http://wonwoo.ml/index.php/post/1769

NoSQL이란?

|

NoSQL이란?

  • NOT ONLY SQL, 대부분이 오픈소스며 Schema-less 데이터 베이스라고 부른다
  • 간단히 말하면 기존의 관계형 데이터베이스와는 다른 특징을 가진 데이터베이스를 말합니다.

특징

  • 대부분이 관계형 모델을 사용하지 않으며 테이블간 조인 기능없음
  • 대부분이 여러대의 데이터베이스 서버를 묶어서(클러스터링) 하나의 데이터베이스를 구성할 목적으로 만들어졌다
  • 관계형 데이터베이스에서 지원하는 ACID 트랜잭션 미보장 -> 몽고DB 4부터 지원한다고 함
  • 스키마를 정의할 필요 없음, 구조에 대한 정의없이 자유롭게 필드를 추가할 수 있다
  • 확장성, 가용성, 높은성능 Scale-out(수평확장)에 초점을 두고 있다
  • RDBMS에 비해 샤딩처리가 원활
    • 샤딩은 샤드키를 기준으로 하나의 테이블을 수평분할하여 서로 다른 클러스터에 분산저장하고 질의할 수 있는 기법이다

데이터베이스 모델 종류

  • Key-value
  • Document
  • Column-family
  • Graph
    • 그래프 모델을 제외하고 나머지 세 모델은 집합-지향모델이다

key-value 구조

  • 질의 속도가 굉장히 빠르고, 수평적 확장이 용이하다. 그렇지만 값의 내용을 사용한 쿼리가 불가능하다. 데이터를 가공하려면 어플리케이션단에서 키를 이용해서 값을 읽어들인뒤 적절히 처리해야한다.

  • 키-값 저장소는 데이터가 키와 값의 쌍으로 저장된다. 키는 값에 접근하기 위한 용도로 사용되며, 값은 어떠한 형태의 데이터라도 담을 수 있다. 심지어는 이미지나 비디오도 가능하다. 또한 간단한 API를 제공하는 만큼 질의의 속도가 굉장히 빠른 편이다.

  • 대표적인 예로는 Redis, Amazon Dynamo DB가 있다

Document 구조

  • 데이터는 키와 도큐먼트 구조로 저장된다. key-value 모델과는 다르게 value가 계층적인 형태로 저장됩니다. 객체지향에서의 객체와 유사하며, 하나의 단위로 취급되어 저장됩니다. 다시 말해 하나의 객체를 여러 개의 테이블에 나눠 저장할 필요가 없습니다.

  • 주요특징은 ORM과 같이 객체-관계 매핑이 필요없음, 또한 Document 모델에서는 도큐먼트 내의 item을 이용한 쿼리가 가능하다. 다만 이를 위해서는 Xquery나 다른 도큐먼트 질의 언어가 필요하다. 질의 언어가 SQL과 달라 사용에 익숙하기 까지 시간이 걸릴 수 있음.

  • 대표적인 예로는 MongoDB가 있다

집향지향 모델

  • 집합이란 연산의 한 단위로 취급되는 연관된 객체들의 집합이다. 하나의 집합에 대한 연산에서는 트랜잭션을 지원한다.

  • 집합 지향 데이터베이스는 여러 대의 클러스터로 이루어진 시스템에서 사용하기 적합하다. 다시 말해 수평적 확장이 용이하다는 것이다. 이는 관계형 데이터베이스와는 달리 연관된 데이터들이 함께 움직이기 때문이다.

  • 또한 메모리 내의 자료구조와 집합 간 데이터가 잘 일치하므로, 관계형 데이터베이스처럼 객체-관계 매핑 프레임워크가 필요하지 않다. 데이터의 검색도 아주 쉬운 편으로, 키나 ID를 사용하면 쉽게 집합 레코드를 찾아낼 수 있다.

  • 집합 지향 데이터베이스는 조인 연산이 불가능한데, 이를 보완하기 위해 MongoDB나 Cassandra등의 데이터베이스에서는 맵 리듀스(MapReduce) 기능을 제공함으로써 조인과 유사한 연산을 가능하도록 설계했다.

  • 이를 사용하여 데이터 분석도 가능하다. 하지만 사용법이 어렵고 Hadoop의 맵 리듀스에 비하면 속도도 매우 느리다

  • 맵리듀스란?

    • 맵리듀스(MapReduce)는 구글에서 정보 검색을 위한 데이터 가공(색인어 추출, 정렬 및 역 인덱스 생성)을 목적으로 개발된 분산 환경에서의 병렬 데이터 처리 기법이자 프로그래밍 모델이다

결과적 일관성

  • NoSQL에서는 응답시간, 일관성, 지속성의 균형을 위해 결과적 일관성을 구현한다.
  • 결과적 일관성이란, 서버가 여러 대인 분산시스템에서 데이터를 조회 했을 때 특정 서버는 변경 된 데이터가 조회되고 일부는 변경되지 않는 상태로 조회될 수 있다
  • 그 때 데이터 일관성을 위해서 모든 서버에 결과값을 질의하고 N개 이상의 같은 값을 반환할 때 사용자에게 해당 값을 보여주는 형태의 일관성이다

synchronized란?

|

synchronized란?

  • 자바에서 말하는 synchronized란 간단히 설명하면 data를 thread-safe하게 만드는 것을 말합니다. 즉 멀티스레드 프로그래밍에서 스레드간 동기화가 되있지 않는 상태에서는 데이터의 안정성이 보장이 되지 않습니다.

  • 결국 여러개의 스레드가 하나의 자원에 접근하고자 할때, 현재 데이터를 사용하고 스레드가 있으면 다른 스레드가 접근하지 못하도록 막는 것입니다. 결국 데이터의 안정성을 위해서입니다. 다만 동기화를 잘못 사용하면 프로그램 성능에 큰 저하를 일으킬 수 있고 내부적으로 block, unblock, wait 등등 의 기능을 활용해야 함으로 내부 공수가 들어갑니다.

  • 적재적소에 동기화를 사용해야하고, 또한 프로그래밍적으로 많은 고려가 필요합니다.

  • 동기화를 적용하는 방법은 메소드, synchronized 블록을 사용하는 경우가 있습니다. 다만 동기화를 적용해도 순서를 보장해주진 않습니다. ex) A가 method에 접근, 그뒤 B가 method에 접근 결과는 B가 먼저 나올수도 있다.

// 두 코드는 같은 코드입니다.

public synchronized void method(){
    // 처리 코드
}

public void method(){
    synchronized(obj){
        // 처리
    }
}

SOLID - 객체지향 5원칙

|

프로그래밍을 하면서, 자바 언어를 사용하면서 객체지향 5대 원칙 혹은 SOLID 원칙을 들어본적은 있지만 제대로 정리한 적이 한번도 없어서 이해하기 위해서 블로그에 정리해본다.

객체지향 5원칙에 대하여

  • 객체지향 5대 원칙은,SRP(단일책임원칙),OCP(개방-폐쇄 원칙),DIP(의존역전원칙),ISP(인터페이스 분리원칙)을 말하며 앞글자를 따서 SOLID 원칙이라고 부른다. 프로그래머가 시간이 지나도 유지보수와 확장이 쉬운 소프트웨어를 만드는데 이 원칙들을 적용할 수 있다.

1. 단일 책임 원칙 - Single Responsiblity Principle

  • 소프트웨어의 설계( 클래스, 함수 )는 단 하나의 기능만을 수행해야 한다. 즉, 응집도는 높고 결합도는 낮아야한다.

  • 지키지 않을 경우 생길수 있는 문제는, 유지보수가 어려워진다. 여러개의 기능을 구현하고 있을 경우, 그 중 하나라도 변경 될 경우 연관되어 있는 모든 클래스를 수정해야 할 수 있다. 책임을 분리해야, 새로운 요구사항과 프로그램 변경에 유연하게 대처할 수 있다.

2. 개방폐쇄원칙 - OpenClosed Principle

  • 기존의 코드를 변경하지(Closed) 않고 기능을 수정하거나 추가할 수 있도록(Open) 설계해야 한다. 즉 자주변경 되는 내용은 수정하기 쉽게 설계하고, 변경되지 않아야 하는 것은 수정되는 내용에 영향을 받지 않도록 하는 것이 포인트다.

  • 이를 위해 자주 사용되는 문법이 인터페이스이다. 아래 코드를 보면, mp3 mp4 재생을 둘다 대응할 수 있다. 만약 여기서 다른 확장자의 음악 프로그램을 실행해야 하는 경우 class 하나만 추가하면 된다. 이처럼 개방폐쇄 원칙은 기능을 추가하거나 변경해야 할경우, 이미 제대로 동작하고 있던 원래 코드르 변경하지 않아도 기존의 코드에 새로운 코드를 추가함으로써 기능의 추가나 변경이 가능하다.


interface playService {
    public void play();
}

class Mp3 implements playService {
    @Override
    public void play(){
        System.out.println("Play Mp3");
    }
}

class Mp4 implements playService {
    @Override
    public void play(){
        System.out.println("Play Mp4");
    }
}

class SoundPlayer {
    private playService service;

    public void setService(playService service){
        this.service = service;
    }

    public void play(){
        service.play();
    }
}

public class Player {
    public static void main(Strings[] args){
        SoundPlayer sp = new SoundPlayer();
        sp.setService(new MP3());
        sp.setService(new MP4());
        sp.play();
    }
}

3. 리스코프 치환 원칙 - Liskov Substitution Principle

  • 자식 클래스는 부모클래스에서 가능한 행위를 수행할 수 있어야 한다. 부모와 자식 클래스 사이의 행위에는 일관성이 있어야 하는 원칙이며, 이는 객체지향 프로그래밍에서 부모 클래스의 인스턴스 대신 자식 클래스의 인스턴스를 사용해도 문제가 없어야 한다는 것을 의미합니다.

  • 상속관계에서는 일반화 관계가 성립해야 합니다. X IS A XX다. 라는 말이 성립해야 합니다. 예를 들면 고양이과 클래스와 그걸 상속받는 호랑이 클래스가 있다.

  • 고양이 Class
    • 고양이는 균형감각이 좋다
    • 고양이들은 그루밍을 매일 한다
    • 고양이들은 박스를 좋아한다
  • 호랑이 Class
    • 호랑이는 균형감각이 좋다
    • 호랑이들은 그루밍을 매일 한다
    • 호랑이들은 박스를 좋아한다
  • 이처럼 is a 관계가 성립하면 딱히, 이상하거나 어색하지 않다. 그렇지만 만약 저기에 강아지나, 다른 포유류 동물이 들어가면 어떻게 될까?

  • 강아지는 균형감각이 좋다
  • 강아지들은 그루밍을 매일 한다
  • 강아지들은 박스를 좋아한다

  • 읽어보면, 강아지들은 보통 그루밍을 하지 않는다. 스트레스를 받거나 어딘가 아파서 하는 경우가 많다. 이처럼 is a 관계가 성립되지 못한 부모자식 관계는 LSP를 성립하지 못한 관계, 즉 일관성이 없는 관계라고 할 수 있다.

4. 의존 역전 원칙 (DIP)

  • 의존 관계를 맺을 때, 변화하기 쉬운 것 보단 변화화기 어려운 것에 의존해야 한다는 원칙이다.
  • 여기서 말하는 변화하기 쉬운것이란 구체적인 것을 말하고, 변화하기 어려운 추상적인 것을 말한다. 객체 지향적인 관점에서 보면 변화하기 쉬운 것이란 구체화된 클래스를 의미하고, 변화하기 어려운 건 추상클래스나 인터페이스를 의미한다.

  • 즉, 객체지향 프로그래밍에서는 의존관계를 맺을 경우, 인터페이스나 추상클래스와 관계 맺는 것을 선호하라는 이야기다.
  • 예를 들면, 아까만든 PlayService란 인터페이스가 아닌 구체화된 클래스를 상속받아서 사용했을 경우 avi 확장자를 추가해야 했을경우는 어떻게 될까? 이처럼 의존성 주입 기술을 사용하지 않으면 추가나 확장에서 용이하지 않을 가능성이 크다.

5. 인터페이스 분리원칙 - Interface Segregation Principle

  • 한 클래스는 자신이 사용하지 않는 인터페이스는 구현하지 말아야 한다. 하나의 추상적인 인터페이스보다는, 여러개의 구체적인 인터페이스 낫다. 이는 다시 말해서 자신이 사용하지 않는 기능에는 영향을 받지 말아야 한다는 의미이다.

  • 한가지 예를 들면, 우리는 스마트폰으로 전화, 웹서핑, 사진 촬영 등 다양한 기능을 사용할 수 있다. 그런데 스마트폰에 기능이라는 인터페이스를 만들어서 그 안에 전화 웹서핑 사진 촬영의 기능을 모두 집어넣으면 어떻게 될까? 전화 기능 하나만 확장 하려고 해도 모든 메소드를 읽어보고 가독성이 떨어질 것이다. 또한 서로 영향이 가는 메소드가 있을 경우는, 시스템의 내부의존성이 높아져서 확장하거나, 변경할 경우 많은 공수가 들어갈 수 있다.

  • 참고

    • https://dev-momo.tistory.com/entry/SOLID-%EC%9B%90%EC%B9%99
    • https://vandbt.tistory.com/41
    • http://wonwoo.ml/index.php/post/1726

Node Js 교과서 - 1

|

노드란?

  • Node.js는 확장성 있는 네트워크 애플리케이션(특히 서버 사이드) 개발에 사용되는 소프트웨어 플랫폼이다. 작성 언어로 자바스크립트를 활용하며 Non-blocking I/O와 단일 스레드 이벤트 루프를 통한 높은 처리 성능을 가지고 있다.

  • 내장 HTTP 서버 라이브러리를 포함하고 있어 웹 서버에서 아파치 등의 별도의 소프트웨어 없이 동작하는 것이 가능하며 이를 통해 웹 서버의 동작에 있어 더 많은 통제를 가능케 한다.

  • 간단히 설명하면, Node.js는 웹환경이 아닌 다른 환경에서 자바스크립트 코드를 실행할 수 있는 프로그램, 환경이라고 볼수 있다.

자바스크립트 런타임

  • 노드는 자바스크립트 런타임입니다. 런타임은 특정 언어로 만든 프로그램들을 실행할 수 있는 환경을 뜻합니다. 따라서 노드는 자바스크립트 프로그램을 컴퓨터에서 실행할 수 있게 해줍니다. 기존에는 자바스크립트 프로그램을 인터넷 브라우저 위에서만 실행할 수 있었습니다. 노드는 V8 엔진을 기반으로 libuv 라는 라이브러리를 사용합니다. V8과 libuv는 C와 C++로 구현되어 있습니다.

  • libuv 라이브러리는 노드의 특성인 이벤트 기반, 논블로킹 I/O 모델을 구현하고 있었습니다.

노드는 이벤트 기반?

  • 이벤트 기반이란 이벤트가 발생할 때 미리 지정해둔 작업을 수행하는 방식을 의미합니다. 이벤트로는 클릭이나 네트워크 요청 등이 있을 수 있습니다. 이벤트 기반 시스템에서는 특정 이벤트가 발생할 때 무엇을 할지 미리 등록해두어야 합니다. 이것을 이벤트 리스너에 콜백 함수를 등록한다고 표현합니다.

  • 노드도 이벤트 기반 방식으로 동작하므로 이벤트가 발생하면, 이벤트 리스너에 등록해둔 콜백 함수를 호출합니다. 발생한 이벤트가 없거나 발생했던 이벤트를 다 처리하면 노드는 다음 이벤트가 발생할 때까지 대기합니다.

논블로킹 I/O

논블로킹 I/O는 무엇일까요? 블로킹은 기본적으로, 요청 <-> 응답을 완료하면 다음 작업을 실행할 수 있습니다. 그렇지만 논블로킹 I/O는 요청을 하고, 응답을 기다리지않고 바로 다음작업을 실행합니다. 그뒤에 순차적으로 완료된 응답을 다시 전달합니다.

image

블로킹보다 논블로킹 방식이 같은 작업을 더 짧은 시간 동안 처리할 수 있음을 알 수 있습니다.

노드는 싱글스레드?

  • 이벤트기반, 논블로킹 모델과 더불어 노드를 설명할 때 자주 나오는 용어, 바로 싱글 스레드입니다. 노드는 싱글 스레드 이므로, 주어진 작업을 혼자서 처리해야합니다. 반대로 멀티 스레드인 시스템에서는 여러 개의 스레드가 일을 나눠서 처리할 수 있습니다.

  • 자바스크립트와 노드에서 논블로킹이 중요한 이유는 바로 싱글 스레드이기 때문입니다. 한 번에 한가지 일밖에 처리하지 못하므로 어떠한 작업에서 블로킹이 발생하면 다음 일을 처리하지 못합니다.

image

  • 위에 그림은 싱글스레드, 블로킹 모델입니다.
  • 이번에는 점원이 한 손님이 주문을 받고, 주방에 주문 내역을 넘긴 뒤 요리가 완성되면 요리를 전달합니다. 그 뒤, 다음 손님의 주문을 받습니다. 딱 봐도 비효율적입니다.

image

  • 위 그림은 싱글스레드, 논블로킹 모델입니다. 노드가 채택하고 있는 방식입니다.
  • 아까와는 다르게 점원 한명이 주문을 받고, 요리가 완성되는 걸 기다리지 않고 다음 주문을 계속 받습니다. 그 뒤, 요리가 완성된 순서대로 손님에게 서빙을 합니다. 점원 혼자서 많은 일을 처리 할 수 있습니다. 단점은 점원에게 문제가 생기거나, 주문이나 서빙을 하는데 시간이 오래 걸릴 경우 처리하기 힘듭니다.

image

  • 멀티스레드, 블로킹 모델입니다. 손님 한명 당 점원이 한명입니다. 보기엔 점원이 여러명이니 싱글 스레드 보다 좋은 방법 같지만 문제는 손님이 많아지면 점원도 늘어납니다. 손님수가 적어지면, 그만큼 점원을 놀게됩니다. 점원을 새로 고용하거나 기존직원을 해고 하는데 비용이 발생합니다.

  • 결론은, 노드도 자체적으로는 스레드를 여러개를 가지고 있습니다. 하지만 프로그래머가 직접 제어할 수 있는 스레드는 하나뿐이므로, 흔히 싱글 스레드라고 부르는 것입니다. 노드는 스레드를 늘리는 대신, 프로세스 자체를 복사해 여러 작업을 동시에 처리하는 멀티 프로세싱 방식을 택했습니다. 자바스크립트 언어 자체가 싱글 스레드 특성을 띠고 있기 때문입니다.

노드는 어디서 사용할까?

  • 서버
    • 노드를 통해 다양한 자바스크립트 애플리케이션을 실행할 수 있지만, 노드는 서버 애플리케이션을 실행하는 데 제일 많이 사용됩니다.