Redis 네트워크 병목현상?
왼쪽 형광색 막대를 우리가 개발하는 개발 서버이고 오른쪽 파란색 막대는 서버 오른쪽은 레디스 서버이다.

왼편의 그림 같은 경우 레디스와 연달아 통신하고 있고 오른쪽은 연달아 하기 보다는 하나의 통신으로 필요한 데이터들을 한번에 처리하고 있는 그림이다.
해당 그림 표현에서 TCP 요청 과정이 숨어 있다는 것을 알고 있어야한다.
보통 레디스는 싱글스레드와 이벤트루프 기반으로 비동기 방식으로 요청을 처리하기 때문에 보조데이터베이스로 주로 사용되어지며 성능적 향상을 기대할 수 있는 기술로 잘알려져있지만 기본적인 CS 개념을 잘 알고 있어야 한다.
문제 상황
나의 프로젝트에서 특히 redis에 각 상품별 평점에 대한 정보를 저장했고 평점을 매기기 위해 1점부터 5점까지 redisTemplate로 하나씩 가져오고 있었다.

해당 부분에서 우려한 것은 데이터의 범위가 넓어지면 넓어질 수록 TCP 3way, 4way 연결을 맺는 부분이였다.
일정 시간동안 한번에 연결하도록 하는 무언가가 있지 않을까란 생각이 있었지만, 없는 줄 알았다.여러 프로젝트를 순회하면서 “레디스 파이프라인 성능 개선하기” 라는 문구를 찾게 되었다.
RedisTemplate을 통해 여러 데이터들을 삽입하거나 가져오는 상황에서 레디스는 기본적으로 O(1) 시간 복잡도가 소요되지만 TCP 연결 방식을 이용하면서 네트워크I/O에 대해서 병목 생길 수 있는 가능성이 있다고 한다.
왜냐하면 매요청마다 응답을 받기 때문에 Blocking이 발생하게 되기 때문이다.
즉, 수십만개의 요청을 받는다면 부하가 생기고 RTT로 인해 오버헤드가 발생하게 된다.
RTT란?
네트워크에서 데이터 패킷이 송신 지점에서 수신 지점까지 전송되고 돌아오는 데 걸리는 시간을 나타낸다.
즉 한 번의 왕복 시간이다.
하지만 레디스에서는 RDBMS 처럼 벌크 연산을 지원하지 않지만 HTTP 기반으로 통신하기 때문에 파이프라이닝을 지원한다.

파이프라이닝은 클라이언트와 서버 간의 통신을 효율적으로 처리하여 레디스의 처리량을 높이는 방법으로 여러 개의 요청을 한 번에 보내고 응답을 기다리지 않고 다음 요청을 보내는 방식이다.
레디스에서 지원해주는 pipeline api인 executePipelined 메소드를 이용해 레디스에 연결을 한후 모든 원소들에 대한 처리를 이어간뒤 연결을 닫는다.

이전보다 처리량이 300ms → 58ms 감소한 결과를 보여줬다.
코드적으로 신경쓰이는 부분은 null이 있다는 것이다.
파이프라이닝에서 주의할 사항이 있다.
- 파이프라이닝은 네트워크 오버헤드를 줄이고 응답 시간을 최적화하는 데 도움이 되지만모든 요청에 대한 응답을 기다리지 않고 연속적으로 요청을 보내기 때문에, 요청 순서가 중요한 경우에는 주의해야 한다. 또한 파이프라이닝을 사용하기 위해서는 클라이언트와 서버가 파이프라이닝 프로토콜을 지원해야 하는 사실을 염두해 두어야 한다.
- 이미 클러스터 모드라면 샤딩되어 분산되어 저장한다는 사실을 알고 있을 것이다.
이점을 간과한체 무턱대고 한다면 서로 다른 노드들에서 꺼내기 때문에 비효율적일 수 있다. 만약 태그 기반으로 하나의 노드에 저장했다면 사용하는 것이 더 좋을 것이다.
파이프라이닝 효과 요약
장점: 네트워크 비용 절감으로 인해 처리량 향상
단점: 순서에 의존하는 로직인 경우 사용할 수 없으며, 클라이언트 서버가 파이프라이닝 프로토콜을 지원하는지 확인해야 한다.