ByteByteGo에서 7가지 API의 성능 향상 방법을 유튜브로 올렸기에 여기에 간단히 정리해 본다.

1. Pagenation

큰 파일은 일정 사이즈(페이지)로 나누어 전달하는 기법이다. 동영상 이미지 같은 큰 사이즈 파일의 업, 다운로드 등에서는 많이 쓰이는 기법이다.

2. Async Logging

시스템은 런타임시 로그를 기록하여야 한다. 그런데 상황에 따라 로깅해야할 데이터가 어떤것은 크고 어떤 것은 작을 때가 있다. 큰 것을 로깅하고 있다면 다음 로깅은 펜딩이 된다면? …

이를 위해서는 비동기 방식의 로깅이 필요하다.

3. N+1 문제

쿼리 1번으로 N건을 가져왔는데, 관련 컬럼을 얻기 위해 쿼리를 N번 추가 수행하는 문제를 N+1문제라고 한다. 이는 JOIN등을 사용한 쿼리의 개선으로 가능하다.

문제상황

$books = query_rows("SELECT * FROM books");
foreach( $books as &$book ) {
    $book['author_name'] = query_one("SELECT name FROM 
    authors WHERE id=?", $book['author_id']); 
}

위 코드는 하나의 id에 해당하는 author를 찾기 위해 books의 레코드 수만큼 루프를 돌면서 찾는다.

이는 다음과 같이 JOIN문으로 해결할 수 있다. (쿼리수 1회)

$books = query_rows("SELECT b.*, a.author_name
    FROM books b LEFT JOIN authors a ON b.author_id=a.id");

Eager 로딩을 하면 쿼리수를 1+1회로 줄일 수 있다.

SELECT * FROM books;
SELECT * FROM authors WHERE id=1;
SELECT * FROM authors WHERE id=2;
SELECT * FROM authors WHERE id=3;
... (생략)

Eager 로딩 작업 후

SELECT * FROM books;
SELECT * FROM authors WHERE id IN (1, 2, 3, ...);

4. caching

DB를 거치기 전에 Redis등의 메모리 DB로 캐시를 만들어 놓는 방법이다.

if redis_cache.contains(query):
   return redis_cache.get(query)
else:
   result = backend_database.query(query)
   redis_cache.put(query, result)
   return result

5. Connection Pool

DB Connection을 미리 여러개를 만들어 pool로 관리함. Connection이 발생할 때 마다 바로 바로 대응.

대표적CP: Hikari CP가 있음.

Hikari CP에서의 권장 Pool size =

(여기서 Tn은 전체 쓰레드 수, Cn은 하나의 요청에서 동시에 필요한 커넥션 수)

이 수치는 너무 찾기가 어려우므로 아래 공식이 많이 쓰이는 것 같다.(Postgre제공)

Pool Size = (core_count * 2) + effective_spindle_count

(core_count : CPU코어 수, effective_spindle_count: 하드 디스크 수)

6. Payload Compression

데이터의 전송시 압축하여 전송하는 기법을 의미

gzip도 있지만 최근에는 Brotli 압축법이 많이 사용되고 있음.

7. Using proper JSON Serialization library

JSON의 데이터 전송시 적절한 퍼포먼스의 Serialization라이브러리를 사용하면 전송 부하를 많이 줄일 수 있다.

언어에 맞는 최적화된 라이브러리를 사용하면 되겠다. google의 protobuf가 언어에서 제공하는 내장 라이브러리들보다 성능은 좋지만 사용하기가 복잡하다는 단점이 있다.