본문 바로가기

개발/Redis

Redis AOF에서 성능 저하를 방지하는 방법

개요


이번에 Redis 유실 방지를 위해 AOF를 사용해보면서 한가지 의문점이 생겼습니다.

 

AOF는 Redis 데이터에 대한 Create, Update 작업을 Disk의 로그 파일에 기록해서 Redis 프로세스가 다운되어도 복구할 수 있게 만드는 전략입니다.

 

그런데 이 때, 로그 파일에 기록하는 것은 Disk I/O 작업이기 때문에 Disk에 데이터를 기록하는 RDBMS를 사용했을때와 다를게 없습니다.

 

그래서 Redis에서는 어떤 방식으로 성능 저하를 방지하면서 AOF를 사용할 수 있도록 구현했는지 알아보겠습니다.

 

 

 

 

appendfsync


appendfsync 속성은 AOF 전략을 사용할 때, 로그 데이터를 어떤 주기로 저장할지 결정하는 속성입니다.

 

redis.conf 파일을 보면, appendfsync 속성을 확인하실 수 있습니다.

 

 

이제 각 속성에 대해서 알아보겠습니다.

 

 

 

always


redis.conf의 appendfsync 주석에서는 아래와 같이 설명하고있습니다.

 

always: fsync after every write to the append only log. Slow, Safest.

use "always" that's very slow but a bit safer than everysec.

 

always는 말 그대로 Redis에서 작업하는 command를 즉각적으로 aof 파일에 기록하는 것 입니다.

 

즉각적으로 기록하게되면 Disk I/O가 모든 command에 발생하기 때문에 very slow라고 표현하고 있습니다.

 

 

 

 

everysec


everysec: fsync only one time every second. Compromise.

The default is "everysec", as that's usually the right compromise between speed and data safety

If unsure, use "everysec

 

everysec는 매 초마다 작업한 command를 모아서 aof 파일에 기록하는 방식입니다.

 

초당 10^4개의 요청이 있다고 가정했을 때 everysec는 한번의 Disk I/O가 있는 반면 always는 10^4번의 Disk I/O를 가져가기 때문에 everysec가 성능면에서 더 우수하다고 볼 수 있습니다.

 

하지만 일부 데이터들이 유실될 수 있다는 단점은 여전히 존재합니다.

 

Redis에서는 기본적으로 everysec 속성을 사용하기를 권장하고 있습니다.

 

 

 

 

no


no: don't fsync, just let the OS flush the data when it wants. Faster.

It's up to you to understand if you can relax this to "no" that will let the operating system flush the output buffer when it wants, for better performances (but if you can live with the idea of some data loss consider the default persistence mode that's snapshotting)

 

Disk에 command 로그 데이터를 반영하는 시간을 OS에게 맡기는 전략입니다.

 

대부분의 리눅스 시스템에서는 30초 마다 Disk에 저장됩니다. 

 

만약 운이 나쁠 경우 30초의 데이터를 모두 유실할 수 있기 때문에 주의해서 사용해야합니다.

 

 

 

 

성능 테스트 - always


 

 

테스트는 간단합니다.

 

영상 조회수 증가 API를 호출하면 Redis에 10^4번 쓰기 요청을 보내서 응답 시간을 체크하는 방식입니다.

 

 

우선 appendfsync 속성을 설정해주기 위해 redis를 실행시키는 docker-compose.yml 파일에서 appendfsync 속성을 always로 설정합니다.

 

 

이후 redis cli에서 확인해보면 always로 잘 설정된 것을 볼 수 있습니다.

 

이후 테스트 시간을 체크해보면 약 37초가 걸린것을 확인할 수 있습니다.

 

 

 

 

성능 테스트 - everysec


 

redis appendfsync의 기본 속성은 everysec기 때문에 따로 속성을 지정하지 않고 실행하면 everysec으로 적용됩니다.

 

 

redis-cli에서 확인해보면 잘 적용된 것을 확인할 수 있습니다.

 

이후, always 속성에서 사용한 api를 재 호출해서 성능을 확인해보겠습니다.

 

약 3초가 소요됩니다.

 

always에서 37초가 걸렸던 것이 everysec에서는 3초로 줄어들었습니다.

 

생각보다 많은 성능차이에 놀랐지만, 그도 그럴것이 always는 Disk I/O가 1만번 발생하는 것에 비해 everysec는 세번 발생한 것이기 때문에 이런 차이가 발생하는 것이 이해됩니다.

 

 

 

 

결론


everysec는 always 설정에 비해 빠르다는 장점이 있지만, 운이 안좋게도 0.9초간의 데이터가 모두 사라질 수 있다는 단점이 존재합니다. 

 

결국 데이터 유실을 모두 방지하면서 성능까지 챙기는 방법은 없었습니다.

 

만약 데이터가 절대 유실되지 않아야 한다면 always 설정을 사용하고 초 단위의 일부 데이터가 유실되도 되는 경우엔 everysec이나 no를 사용하는게 좋을 것이라 생각합니다.

 

성능과 데이터 유실 사이 적절한 트레이드오프를 통해 비즈니스를 구현하는 것이 중요하다고 생각하게된 시간이었습니다.