Lichess Tablebase 서버 최적화
(lichess.org)- Lichess는 요청 부하 때문에 7-piece Syzygy tablebase 서버의 주기적 RAID 검사가 밀리자, 전체 블록을 훑는 방식 대신 읽기 시 무결성 검증으로 전환함
- 긴 다운타임 없이 17TiB tablebase를 옮기기 위해 새 서버를 마련했고, 32GiB RAM·2×201GiB NVMe·6×5.46TiB HDD 환경에서 실제 요청 로그를 재생해 검증함
- 프로덕션에서 기록한 100만 개 요청을 12개 병렬 클라이언트로 재생한 결과, 평균 응답보다 사용자가 체감하는 꼬리 지연시간이 핵심 병목으로 드러남
- 구현 측면에서는
mmap보다pread(2)가 오류 처리와 꼬리 지연시간에서 유리했고,POSIX_FADV_RANDOM·MADV_RANDOM같은 랜덤 접근 힌트는 대체로 역효과였음 - 제한된 SSD에는 table prefix를 올리고 요청 내부 probe를 병렬화해 느린 디스크 접근을 줄였으며, 벤치마크 개선이 프로덕션 응답 시간에도 이어지는지 확인함
RAID 전체 검사 대신 읽기 시 검증으로 전환
- Lichess의 7-piece Syzygy tablebase 서버는 tablebase 요청이 많은 동안 주기적 RAID 무결성 검사를 끝내기 어려웠음
- 새 구성은 dm-integrity on LVM을 사용해 모든 데이터 블록을 주기적으로 검사하지 않고, 블록이 읽힐 때마다 검증함
- 17TiB tablebase를 몇 시간 다운타임 없이 이전하기 위해 새 서버를 따로 구성함
- 실제 전환 전에 전체 tablebase를 대상으로 제어된 벤치마크를 실행할 수 있었음
- 이후 새 서버로 전환하고 기존 서버를 퇴역시킴
새 서버 구성
- RAM은 기존과 같은 32GiB를 유지함
- 저장장치는 기존 서버에 없던 2×201GiB NVMe를 추가했고, 476GiB 디스크의 나머지 공간은 OS와 작업 공간으로 예약함
- HDD는 기존 5개에서 6×5.46TiB HDD로 늘어남
- 운영체제는 Debian bookworm이며, 커널은
Linux 6.1.0-21-amd64계열임 - 기본 I/O 스케줄러는 NVMe에서
none, HDD에서mq-deadline이 선택된 상태였음
RAID 5 설정과 모니터링
- RAID 5는 단일 디스크 장애에서 복구할 수 있고, 랜덤 읽기를 여러 디스크에 분산할 수 있어 tablebase 서버에 잘 맞음
- 초기 구성은 다음과 같았음
lvcreate --type raid5 --raidintegrity y --raidintegrityblocksize 512 --name tables --size 21T vg-hdd
- 초기 테스트 성능은 괜찮았지만, 모니터링이 없었다면 일부 디스크가 같은 수준으로 참여하지 않는 문제를 놓쳤을 수 있음
--stripes를 생략하면 모든 물리 볼륨을 기본으로 사용하지 않음- 디스크별 읽기 활동 모니터링이 잘못된 RAID 설정을 잡아내는 데 필요했음
실제 요청 로그로 본 병목
- 정상 조건에서 서버는 초당 10~35개 요청을 받음
- 프로덕션 환경에서 100만 개 요청을 기록하고, 선택한 시나리오에서 12개 병렬 클라이언트가 이를 순차 제출함
- table은 지연 열기 방식으로 열리고, 애플리케이션 및 OS 캐시는 점진적으로 채워짐
- 처음 80만 개 응답 시간은 워밍업으로 제외함
- 이후 20만 개 요청의 응답 시간을 분석함
- 평균 응답 시간은 충분히 빠르지만 꼬리 지연시간이 높아 최적화의 초점이 됨
- ECDF 그래프는 각 응답 시간보다 빠른 요청 비율을 보여주며, x축은 로그 스케일임
- 그래프에는 클라이언트의 30ms ping time을 반영하기 위해 각 응답 시간에 30ms를 더함
- 로그 스케일 x축이 낮은 구간의 몇 밀리초 차이를 과하게 강조하지 않도록 하기 위한 처리임
mmap보다 유리했던 pread(2)
- Syzygy tablebase 구현체인 shakmaty-syzygy는 table 파일을 여는 방식과 읽는 방식을 교체할 수 있는 인터페이스를 제공함
- 주요 후보는 두 가지였음
mmap은 매핑 후 추가 시스템 호출이 필요 없지만, 읽기가 일반 메모리 접근처럼 보이기 때문에 오류를 시그널 같은 out-of-band 방식으로 처리해야 함- 서버 구현에서는 더 견고한 오류 처리만으로도
pread사용을 정당화할 수 있었고, 벤치마크에서도 관심 시나리오에서pread성능이 더 좋았음 - 가능한 원인 중 하나는 메모리 매핑된 단일 데이터 블록 접근이 페이지 경계를 넘을 때 두 번의 디스크 읽기로 이어질 수 있다는 점임
- 체스 엔진에 곧바로
pread를 적용할 필요는 없음- 엔진 매치의 tablebase 사용은 보통 모든 WDL table을 충분히 빠른 저장장치에 둘 수 있을 때 이뤄짐
- 이 경우 일반적인 응답 시간 범위는 해당 그래프에 보이지 않을 정도이고, 시스템 호출 오버헤드를 줄이는 메모리 매핑이 더 나음
랜덤 접근 힌트의 역효과
posix_fadvise(fd, 0, 0, POSIX_FADV_RANDOM)와 메모리 맵에 해당하는 힌트는 결과적으로 대부분 역효과였음POSIX_FADV_RANDOM은 파일 접근이 랜덤이고 자동 read-ahead가 유용하지 않을 가능성이 높다고 OS에 알려, 페이지 캐시 압박을 줄이기 위한 힌트임- 사람들이 엔드게임을 분석할 때의 tablebase 접근 패턴은 예상보다 랜덤하지 않을 수 있음
- 체스 엔진에서는 probe가 서로 다른 가능한 엔드게임에 더 흩어질 수 있어 결과가 달라질 수 있음
제한된 SSD에 올릴 table prefix
- table probe는 먼저 포지션을 table header의 인코딩 정보를 바탕으로 정수 인덱스로 인코딩함
- 이후 해당 인덱스의 결과가 들어 있는 압축 데이터 블록을 찾아야 함
- Syzygy는 올바른 항목 근처를 가리키는 sparse block length list를 제공하고, 이어서 block length list로 관련 데이터 블록을 찾음
- table section 크기는 다음과 같음
| Table section | WDL | DTZ | Total |
|---|---|---|---|
| Headers and sparse block length lists | 38GiB | 9GiB | 47GiB |
| Block length lists | 274GiB | 64GiB | 339GiB |
| Compressed data blocks | 8433GiB | 8458GiB | 16891GiB |
- SSD 공간을 적응형 캐시 계층으로 사용해 hot list entry와 data block을 캐시할 수도 있음
- 꼬리 지연시간을 줄이는 목표에서는 최악의 경우를 고려해 sparse block length list와 block length list를 SSD에 두는 방식이 적합함
- 이 배치는 hot/cold 여부와 관계없이 table probe당 느린 디스크 읽기를 최대 1회로 제한할 수 있음
- 해당 서버에서는 RAID 1 미러링을 하기엔 SSD 공간이 충분하지 않았고, 선택적 최적화라는 이유로 중복성을 포기하고 RAID 0을 사용함
요청 내부 probe 병렬화
- 체스 엔진의 일반적인 tablebase 요청은 단일 WDL 값에 대한 요청임
- 사용자 인터페이스에서는 모든 수에 대한 DTZ 값을 표시하려고 함
- Syzygy 내부의 capture 해소까지 포함하면 평균 요청은 23 WDL probe와 70 DTZ probe를 발생시킴
- 초기 구현은 요청 처리 자체는 병렬화했지만, 각 요청 내부의 probe는 순차 실행함
- 더 세밀한 병렬성은 낮은 지연 구간에서 오버헤드를 만들지만 꼬리 지연시간을 크게 줄임
- 디스크가 실제로 많은 병렬 읽기를 물리적으로 처리할 수는 없어도, I/O 스케줄러가 각 요청을 더 빨리 끝내도록 읽기를 계획할 가능성이 높아짐
- 이 방식은 디스크 헤드가 다음 요청 섹터에 도달할 때까지의 시간을 줄이도록 관련 디스크 접근 순서를 더 잘 계획하게 함
프로덕션 확인과 원자료
- 벤치마크 시나리오의 최적화가 실제 프로덕션에도 도움이 되는지 응답 시간 차트로 확인함
- 원자료는 lila-tablebase-bench에 공개되어 있음
댓글과 토론
Hacker News 의견들
-
Lichess는 좋은 와인처럼 가만히 감탄하게 되는 서비스임. 체스 커뮤니티에 정말 훌륭하고, 매일 쓰면서 기능과 성능에 계속 자극받고 있음
특히 제한된 예산의 1~2명 규모 팀이라는 걸 알면 더 놀라움- 무료이고 오픈소스이며, 돈을 요구하지도 않고 앞으로도 그럴 일이 없다는 점도 빠뜨리면 안 됨. 많은 사람이 기부하고, 지출도 공개되어 있으며 앱도 있음
- 더 많은 최종 사용자용 오픈소스 소프트웨어가 Lichess처럼 사용자 친화적이고, 잘 설계되고, 잘 유지보수되면 좋겠음
- 나도 그렇게 느낌. 최근 새 베타 모바일 앱은 더 깔끔하고 햅틱 피드백까지 있어서 멋짐
- 언젠가 Lichess만큼 가치 있고 멋진 걸 만들고 싶음
-
응답 시간마다 30ms를 더한 ECDF를 보여준 부분이 흥미로웠음
상수 추가가 인위적으로 보일 수 있지만, 실제로는 30ms 핑을 가진 클라이언트 관점에서 결과를 보는 방식이고, 로그 스케일 x축이 낮은 구간의 몇 ms 차이를 과장하지 않게 해줌. 표준 기법일 수도 있지만 꽤 똑똑한 요령처럼 보임 -
비용 절감이 꼭 필요했는지, 아니면 그냥 박스 하나에 20TB SSD를 넣고 끝내면 안 되는 다른 이유가 있었는지 궁금함. 4TB SSD도 대략 300달러이고, HP나 Dell SFF 드라이브도 훨씬 비싸진 않음
아마 테스트와 최적화 자체에 흥미가 있었던 것 같고, 제품 관점이라면 제한된 시간을 다른 프로젝트에 썼을 것 같음- Lichess는 비영리이고 자원봉사자가 많아서, 대부분의 영리 회사와는 시간 대비 하드웨어 비용의 균형이 다를 가능성이 큼
- Lichess는 기부와 자원봉사로만 운영되는 비영리 단체임. 직원은 비영리 단체를 만든 한 명뿐이고, 실력에 비해 다른 직장에서 벌 수 있는 돈보다 훨씬 적게 가져가는 것처럼 보임
조직이 프랑스 기반이라는 점도 비용에 어떤 영향을 주는지는 모르지만 언급할 만함 - 이 작업으로 최대 응답 시간을 한 자릿수 규모로 줄였음. 프로젝트가 1주, 길어도 2주 걸렸고 일부 사용자의 응답 시간이 15초에서 1.5초로 줄었다면 충분히 가치 있음
이보다 시간 투자를 더 잘 정당화하려면 사용자 경험이 더 나쁜 프로젝트가 있거나, 영리 조직에서 다른 곳에 돈 벌 기회가 있고 고객 고통에는 별 관심 없다고 인정하는 경우 정도일 것임 - “재미로 테스트와 최적화”라고 생각하는 엔지니어는 IT 말고는 다른 산업에 거의 없을 듯함
너무 강력하고 싼 하드웨어와, 그냥 “오늘은 여기까지” 하고 싶어 하는 게으른 사람 쪽이 결합된 결과처럼 보임. 자기 일에 자부심을 가지라는 말도 있지 않나 - 제품 관점에서는 말이 되지만, Lichess는 제품을 가진 영리 회사가 아니라 실제로 비영리 조직으로 운영되므로 결정을 이해하려면 관점을 바꿔야 함
-
이 최적화에는 의문스러운 선택이 몇 가지 있음. 최적화 이유는 입출력 활동이 너무 많아서 RAID 검사가 완료되지 못한다는 것임
글만 봐서는 17TiB 데이터에 대한 RAID 검사가 실제로 끝난 적이 있는지 불명확함. 대신 주기적 RAID 검사를 끄고, 데이터를 읽을 때 페이지 단위로 오류 검사를 하도록 바꿨는데 두 방식은 같지 않고 중요한 데이터라면 둘 다 써야 함
데이터를 읽으려 할 때만 손상을 발견하면 오래된 데이터 손상이 계속 남을 수 있고, 백업 보관 기간을 넘어 원본을 복구하지 못할 수도 있음. 여기에 RAID 0으로 바꾼 점도 깔려 있는데, 가장 빠른 선택이긴 해도 그 NVMe 구성이 그런 부하를 견딜 거라고 꽤 크게 믿는 셈임
백업이 잘 되어 있기를 바람. 좋은 해결책은 임시 서버를 띄워 백업을 복원하고 전체 데이터 검사를 수행한 뒤, 성공하면 백업·복원 절차와 파일 무결성도 함께 검증하는 것임. 그래도 주 서버에서 RAID 검사를 끝낼 여유는 확보해야 하고, 성능 때문에 RAID 0을 쓰지는 않는 편이 좋음- 두 방식이 같지 않은 건 맞지만, 이 사용 사례에는 충분함. 데이터 손상을 발견하면 파일을 버리고 다시 다운로드하거나 재생성하면 되기 때문임
이건 자유롭게 구할 수 있는 데이터셋이고, 크기만 좀 큼. https://en.wikipedia.org/wiki/Endgame_tablebase가 더 잘 설명해줌. 그래서 백업도 하지 않음
- 두 방식이 같지 않은 건 맞지만, 이 사용 사례에는 충분함. 데이터 손상을 발견하면 파일을 버리고 다시 다운로드하거나 재생성하면 되기 때문임
-
lishogi도 있지만 아직은 규모가 작아서 이런 최적화가 필요할 정도는 아님
체스 변형 중에는 쇼기가 가장 재미있고, 샹치는 그 정도는 아님 -
lichess가 여성 lich라는 뜻이라고 보면 되는 건가 싶음. baron/baroness 같은 식으로
- 귀족 칭호는 비교 대상으로 별로임. 남성 전용 어근이 실제로 있는 드문 예라서 그렇고, 대부분의 단어는 어근이 중성이며 남성형이나 여성형이 있더라도 접사가 필요함
엄밀히는 남성 lich는 “werlich”, 여성 lich는 “wiflich”이고 복수형에는 “-en”이 붙음. 다만 언데드에게 성별은 대체로 무관하니 중성형이 압도적으로 많이 쓰임
“lichess”는 독일어와 프랑스어 어근이 뒤섞인 괴상한 조합이라서, 자연스럽게 영어의 다른 단어들과 구분이 안 됨 - Libre chess, 즉 자유롭고 오픈소스인 체스라는 뜻임
- 귀족 칭호는 비교 대상으로 별로임. 남성 전용 어근이 실제로 있는 드문 예라서 그렇고, 대부분의 단어는 어근이 중성이며 남성형이나 여성형이 있더라도 접사가 필요함
-
공정한 비교는 아니지만, Lichess 팀의 엔지니어링 품질에는 정말 감탄하게 됨. 주 경쟁자는 GCP 이전을 자랑하면서도 인기 증가에 따라 반복적인 장애를 겪었고, 인원은 100배쯤 더 많을 거라고 봄
Lichess의 약점은 모바일 앱이었지만, Flutter로 다시 만든 v2는 아직 베타인데도 이미 꽤 좋음
그리고 Thibault가 자기 보수로 연 6만 달러도 안 가져간다는 점도 기억해야 함- 급여를 올린다고 미안해할 필요는 없다고 봄. 연 20만 달러로 올려서 삶을 더 편하게 만들면 장기적으로 프로젝트에도 좋을 수밖에 없음
- Lichess는 나 같은 캐주얼 체스 플레이어가 다른 사람과 빠르게 한 판 두기에 훌륭한 서비스임. 거의 기다릴 일이 없음
다만 Lichess를 어떻게 발음하는지 궁금함. Lie chess인지, Le chess인지, League chess인지 - Lichess는 Wikipedia가 코드와 조직 양쪽에서 얼마나 효율적일 수 있었는지 보여주는 좋은 예처럼 보임
- Chess.com에 개발자가 얼마나 많은지 꽤 과대평가하는 것 같음