[DB] (NHN FORWARD 2021) Mysql 비동기 처리 세션 정리

Woong·2021년 12월 14일
0

컨퍼런스/세미나

목록 보기
10/12

https://forward.nhn.com/2021/sessions/11

전통적인 동기 방식의 처리

connection pool
미리 연결을 맺어둔 connection pool 을 이용해 매번 connection을 맺는 병목을 줄여줌

thread pool 을 이용해 thread 에 위임해 대기시간을 줄이고 더 빠르게 처리
동시에 여러개 작업도 가능
thread pool, connection pool 사이즈를 잘 맞춰주는 것이 중요.

비동기

응답을 대기하지 않고 계속적인 처리를 수행, 필요한 시점에 결과 반환

아래 2가지 방법을 고려하였음.
1. Mysql 에서 제공하는 X DevAPI
2. Kotlin 기반의 jasync SQL 사용

두 방법 모두 생산성이 좋아지는 결과를 가져왔으나, 동기 방식처럼 API로 트랜잭션을 직접 처리하면 상대적으로 느려짐

Transaction 처리하면 내부적으로 START TRANSACTION 을 요청한 후, 쿼리 요청을 받아 작업 후 응답한 다음 COMMIT 이나 ROLLBACK 을 처리
-> 내부적으로 메시지를 처리하는 횟수가 증가하고, 처리 내용이 끝날 때까지 연결이 유지되므로 비동기 쿼리의 장점인 성능을 잃게 됨

R&D 과정

Mysql 에서 제공하는 X DevAPI

Mysql 8.0 부터 지원
8.0 에서 새로 추가된 X Protocol 기반으로 쿼리를 비동기로 처리하고, JSON 기반의 document store 를 제공
5.7.12 버전 이상에선 X Protocol 을 추가로 설치하면 X DevAPI 를 제공

세션 생성시 X Protocol 을 사용하도록 지정하고, CompetableFuture 클래스 인스턴스의 executeAsync() 메소드를 호출.
필요한 작업을 수행한 후 결과를 가져올 땐 get() 메소드 호출하여 RowResult 가져옴

데이터량이 많아졌을 때 느려지는 현상이 있었음
기존 JDBC에 비해 10~20배 느려지는 현상이 발견되었으나, issue report 에 대해 응답이 없는 상태였음.

테스트 수행
1. 세션 하나 만들고 비동기 요청을 여러번 수행 -> 성능 저하 문제 없이 테스트 완료
2. 세션을 10개를 만들고 비동기 요청을 수행 -> 성능이 떨어지는 것이 확인됨. (세션 1개 대비 87%의 성능을 보임)
-> 세션이 많아질 수록 성능이 떨어지는 현상이 확인됨.

API 소스를 확인하였더니 메시지를 보내고 응답을 처리하는 메소드를 콜백으로 등록하고, 콜백 안에서 dispatchingThreadMonitor 객체에 lock 을 거는데 이것이 원인으로 보임.
-> 이 안에서 while 루프마다 lock 을 걸고 있었음 -> 요청마다 lock 이 걸리고 있었음 -> 여러 세션을 맺으면 각 스레드에서 lock 경합을 벌이게 됨

jasync SQL

PostgreSQL, MySQL 지원하는 간단한 도구.
MySQL 4.1이상 지원.

ConnectionPool 생성 후, sendPreparedStatement 를 호출하여 비동기 요청.
필요한 작업 후 get(); 메소드를 호출하여 비동기 쿼리 결과를 가져옴

NoSQL은 지원하지 않음
레퍼런스로 Spring 의 R2DBC나 Vert.x 등에 많이 사용하고 있어 Spring 기반 환경이라면 간단하게 사용 가능.

비동기로 얻을 수 있는 것

코드 생산성
동기 쿼리시 스레드 pool을 이용해 코드가 blocking 되지 않도록(서버가 멎지 않도록) 처리해야함
비동기 쿼리로 처리할 시 code blocking 고려하지 않고 로직에만 집중할 수 있음.

성능
8core 16GB VM 23개로 테스트 환경을 구성 후 테스트

X DevAPI 사용하였을 때 10000 TPS 정도 더 높게 나왔고,
jasync-SQL 사용하였을 때 X DevAPI 보다 더 높은 TPS 를 보였음 (X DevAPI 174%, jasync-SQL 로 190% 성능 향상)

Mysql 은 Stored Procedure 를 사용하지 않는 편
장점 : 코드와 쿼리 분리, 하나의 요청으로 여러 SQL 실행, 네트워크 소요시간 단축
단점 : 디버깅이 어려움, 처리 성능이 낮음, 세션 단위로 캐싱되어 메모리 사용량 많음

StoredProcedure 를 적용하였을 때
Mybatis 기준 72% 로 성능이 떨어짐
X DevAPI 는 162%, jasync-SQL 은 180% 로 10% 가량 더 낮은 성능을 보였으나, 여전히 동기쿼리 방식보다는 높은 성능을 보임.

비동기 쿼리에서 API 방식으로 트랜잭션 처리시 성능이 떨어지는 이슈에 대해 처리하기 위해서
StoredProcedure 에서 Transaction 을 처리하도록 하여 테스트 진행
그러나 Mybatis, jasync-SQL 모두 성능이 더 떨어지는 현상을 보였음. (69%, 168% 로 여전히 비동기 쿼리의 성능이 높은 것은 동일)

요약

동기 방식인 MyBatis, HIBERNATE
비동기 방식인 MySQL X DevAPI, jasync SQL
MyBatis(100%) < HIBERNATE(109%) << MySQL X DevAPI(174%) < jasync SQL (190%)

또한 비동기 방식에서 코드 생산성과 가독성, 성능이 우수함.

jasync SQL + storedProcedure 를 사용하도록 하고 있음.

향후 과제
row 형태의 쿼리를 그대로 쓰고 있어서, 개발 및 유지보수에 불편하므로
mapper 를 사용하기 위해 R&D 진행중
NHN Cloud Gameanvil 문서에 비동기 처리 문서가 있으니 참조 권유
MySQL 커넥션 부족 혹은 많은 부하가 걸리는 경우 2019년도 NHN FORWARSD '200만 동접 게임을 위한 MySQL 샤딩' 발표한 내용이 있으니 참조.

0개의 댓글