Netty(자바 네트워크 프레임워크)
- 네티는 비동기 이벤트 기반 네트워크 애플리케이션 프레임워크로서 유지보수를 고려한 고성능 프로토콜 서버와 클라이언트를 빠르게 개발할 수 있다.
- 전 세계 수많은 개발자가 사용하는 범용 자바 네트워크 프레임워크
- 네티가 제공하는 이벤트 모델과 바이트 버퍼 이해 필수
- 네티를 이용하면 기능적으로 TCP 및 UDP 소켓 서버와 같은 네트워크 프로그래밍을 단순하게 만들 수 있습니다.
- 네티는 쓰레드풀을 사용으로 스레드의 생성과 종료로 인한 CPU사용이 별도로 없습니다
- 네티는 이벤트를 인바운드, 아웃바운드로 구분한 추상화 모델 제공
- 프레임워크 기반으로 API 제공
*인바운드 : 자신의 컴퓨터로 들어오기 시작하는 네트워크 데이터
*아웃바운드 : 자신의 컴퓨터에서 나가기 시작하는 네트워크 데이터
핵심 키워드 : 비동기, 이벤트 기반, 프로토콜 서버, 빠른 개발
netty 주요개념
- Channel
- ChannelPipeline
- Handler
- ChannelBuffer <--> 기존 byte buffer
- Decoder
- Encoder
- Frame
Netty server 소스 구조
EchoServer
1. 멀티스레드 이벤트 루프 생성
2. 서버 브트스트랩 선언, 서버 channel 직접 세팅, 옵션지정
3. 인커밍 커넥션을 액세스하기위해 바인드 후 시작
4. 서버 소켓이 닫힐때까지 대기
EhcoServerHandler
- 채널을 읽을 때 동장할 코드 정의
channelRead : 데이터 수신 이벤트
channelReadComplete : 채널 완료시 동작 코드
exceptionCaught : 예외 발생 시 동작 코드
부트스트랩
- 애플리케이션 시작 시 가장 처음으로 수행되는 부분,
- 수행할 동작과 각종 설정을 지정하며 네티 애플리케이션의 기본이 된다.
- 네티로 작성한 네트워크 애플리케이션의 동작 방식과 환경을 설정하는 도우미 클래스
- 전송 계층(소켓 모드 및 I/O 종류, 이벤트 루프(단일 스레드, 다중 스레드), 채널 파이프라인 설정, 소켓 주소와 포트, 소켓 옵션
용어정리
- data pipeline : 수많은 데이터를 모아 처리기로 보내주는 통로 역할
- channel은 언제나 버퍼를 통해 데이터 read/write.
- IO : NIO = Stream : channel (stream : 단방향, channel : 양방향)
- 동기식 : 서비스 처리가 완료된 이후 처리 결과를 알 수 있는 방식
- 비동기식 : 요청이 끝나기 전에 다른 작업 가능
- 자바 1.3 까지 i/o만 지원, 이후 1.4 nio 논블로킹 지원
- 블로킹은 요청한 작업이 성공하거나 에러가 발생하기 전까지 응답을 돌려주지 않음,
논블로킹은 요청한 작업의 성공 여부와 상관없이 결과 돌려줌.
블로킹 작업 순서
1. 클라이언트가 서버로 연결 요청
2. 서버 연결 수락, 클라이언트와 연결 소켓 생성
3. 해당 메서드(read, write) 처리 완료까지 스레드 블로킹
- 스레드 블로킹으로 동시 여러 클라이언트 처리 불가능
- accept 메서드로 새로운 스레드 생성 후 클라이언트 소켓 i/o 처리.
- 스레드 과부하는 스레드 풀링으로 제한
소켓 : 네트워크상에서 서버와 클라이언트 두개의 프로그램이 특정 포트를 통해 양방향 통신이 가능하도록 만들어주는 소프트웨어 장치.
빌드 패턴 : 메서드의 호출 결과로 자신의 객체 참조를 돌려주는 프로그래밍을 구현하는 패턴의 일종
채널파이프 라인과 코덱 : 채널에서 발생한 이벤트가 이동하는 통로
코덱 : 이벤트 핸들러를 상속받아서 구현한 구현체들을 코덱이라고 한다.
서버 네트워크 애플리케이션을 네티로 작성시
1. 부트스트랩으로 네트워크 애플리케이션에 필요한 설정을 지정
2. 부트스트랩에 이벤트 핸들러를 사용하여 채널 파이프라인을 구성
3. 이벤트 핸들러의 데이터 수신 이벤트 메서드에서 데이터를 읽어들인다.
4. 이벤트 핸들러의 네트워크 끊김 이벤트 메서드에서 에러 처리를 한다.
네티는 소켓 채널에 채널 파이프라인을 등록하고 이벤트 핸들러의 설정을 완료하기 위한 프로세스
1. 클라이언트 연결에 대응하는 소켓 채널 객체를 생성하고 빈 채널 파이프라인 객체를 생성하여 소켓 채널에 할당한다.
2. 소켓 채널에 등록된 channellnitializer 인터페이스의 구현체를 가져와서 initchannel 메서드를 호출한다.
3. 소켓 채널 참조로부터 1에서 등록한 파이프라인 객체를 가져오고 채널 파이프라인에 입력된 이벤트 핸들러의 객체를 등록한다.
코덱의 실행 과정
- 네티의 코덱은 템플릿 메서드 패턴으로 구현되어 있다.
- 템플릿 메서드 패턴은 상위 구현체에서 메서드의 실행 순서만을 지정하고 수행될 메서드의 구현은 하위 구현체로 위임
이벤트 모델
- 이벤트를 처리하는 방법은 크게 두가지
- 이벤트 리스너와 이벤트 처리 스레드에 기반한 방법
네티는 단일, 다중 스레드 이벤트 루프 지원
이벤트의 수행 순서가 일치하지 않는 근본적인 이유는 이벤트 루프들이 이벤트 큐를 공유하기 때문에 발생, 네티는 이벤트 큐를 이벤트 루프 스레드의 내부에 둠으로써 수행 순서 불일치의 원인을 제거.
퓨처 패턴 : 미래에 완료될 작업을 등록하고 처리 결과를 확인하는 객체를 통해 작업의 완료를 확인하는 패턴
(케이크 주문시 케이크 주문서에 해당.)
이벤트 수행 선수의 관점에서 네티의 이벤트 루프 스레드는 단일 스레드와 다중 스레드의 차이가 없는 것이 장점
바이트 버퍼
- 자바 NIO 바이트 버퍼는 바이트 데이터를 저장하고 읽는 저장소다.
- 데이터형에 따른 추상 클래스의 팩토리 메서드를 통해서 생성.
바이트 버퍼 클래스 내부 배열 상태 관리 세가지 속성
capacity : 버퍼에 저장할 수 있는 데이터의 최대 크기로 한 번 정하면 변경 불가. 버퍼 생성 시 생성자의 인수로 입력한 값
position : 읽기 또는 쓰기가 작업 중인 위치를 나타냄.
limit : 읽고 쓸 수 있는 버퍼 공간의 최대치를 나타냄. 값을 조정할 수 있다.
다이렉트 버퍼는 힙 버퍼에 비해서 생성 시간은 길지만 더 빠른 읽기/쓰기 성능을 제공
네티 바이트 버퍼의 특징
- 별도의 읽기 인덱스와 쓰기 인덱스
- filp 메서드 없이 읽기 쓰기 가능
- 가변 바이트 버퍼
- 바이트 버퍼 풀
- 자바의 바이트 버퍼와 네티의 바이트 버퍼 상호 변환
- 복합 버퍼
네티 바이트 버퍼
- 네티 바이트 버퍼는 자바 바이트 버퍼와 달리 프레임워크 레벨의 바이트 버퍼 풀을 제공.
- 네티 바이트 버퍼는 자바 바이트 버퍼와 달리 읽기 쓰기 전환에 flip 메서드를 호출하지 않는다.
- 자바의 바이트 버퍼는 쓰기 작업이 끝나고 읽기 작업을 시작하기 전 또는 그 반대의 상황에서 항상 flip 메서드를 호출해야 한다. 원인은 바이트 버퍼에서 사용하는 인덱스가 하나이기 때문인데 네티는 읽기 인덱스와 쓰기 인덱스를 분리함으로써 이같은 문제를 해결한다.
- 네티는 프레임워크에서 바이트 버퍼 풀을 제공.
- 장점) 버퍼를 빈번히 할당하고 해제할 때 일어나는 가비지 컬렉션 횟수의 감소