DB(SQLite?) 구현을 하던 중…
“음 이거 memory mapped file로 구현하면 되겠다.”
라고 생각하고 있었는데,
널리 쓰이는 상업 DB들은 memory mapped file이 아니라
그냥 block i/o(fwrite, fread) 로 구현한다는게 아니겠는가.
(https://quasar.ai/memory-mapped-files-considered-harmful/)
그래서 왜 그런지 보니…
memory mapped file의 문제는 다음과 같단다.
1.
더티 페이지가 언제 디스크로 플러쉬 될지 알 수 없음. (트랙잭션 안전 보장이 힘듬)
2.
엑세스하려는 데이터가 디스크에 있는지 램에 있는지 알 수 없음. (i/o wait)
3.
성능이 오히려 떨어짐. (멀티스레드에서 확장이 힘듬)
ok. 1,2 번은 이해가 된다.
근데 3번.
성능이 오히려 떨어짐. (멀티스레드에서 확장이 힘듬)
??? 성능이 오히려 떨어진다고?
이해가 안되서 이것저것 자료를 다 찾아봤다.
http://library.kaist.ac.kr/search/detail/view.do?bibCtrlNo=237642&flag=t
https://ryotta-205.tistory.com/34
https://rntlqvnf.github.io/lecture%20notes/os-cache/
등등… (전세계 기술 블로거 분들 사랑합니다.)
나 나름대로 취합하고 추측해 낸 내용은 다음과 같다.
1.
memory-mapped file을 쓰는 과정에서, DB는 거대하므로 page in/out이 반복될 것임.
2.
이 과정에서 TLB entry가 바뀌어야 하므로 해당하는 entry를 수정/무효화 해야함.이게 로컬 코어에서만 일어나는 일이면 문제가 별로 없다.그런데 이게 멀티코어에서 작업하는 경우 문제가 생긴다.
3.
코어의 로컬 TLB만 수정하면 안 된다.
캐시 일관성과 비슷하게, 다른 모든 코어들에게 해당 TLB entry가 무효화 됐음을 브로드캐스트 해야한다.(TLB shootdown)
4.
다른 코어가 해당 IPI(inter-processor interrupt)를 확인하고 TLB수정 후 ACK를 전송.
5.
Initiator 코어는 모든 ACK를 확인한 후 작업을 재개한다.
요약
멀티스레드 DB에서 memory mapped file을 사용하게 되면,
한 코어의 TLB entry가 변경될 시 다른 코어들에게 브로드캐스트 해야하고(TLB shootdown),
다른 코어들의 ACK를 받아내야하는데 이 정보교환 루틴이 무진장 느리다. (busy wait)
그래서 안정성 & 성능 문제로 상업DB에선 MMIO를 안쓴다!!
(물론 싱글코어에서는 MMIO가 훨씬 빠름)