최근에 작도닷넷 서버를 망가트려서 하마터면 데이터를 날릴 뻔 했다. 2001년부터 20년 가까이 쌓은 데이터가 한 순간의 실수로 없어질 뻔 했다. 내가 그렇게 백업을 잘 하는 것도 아니었고, 많은 취약점을 안은 채로 적당히 운영하다가 큰 코를 다친 것이었다. 그렇다고 그렇게 대단한 데이터도 아니지만, 그래도 말이다.
지금까지 나는 많은 데이터를 잃어버렸다. 중학교때 수백장의 공CD를 구웠고, 군대갈 때 집에서 버릴까봐 친구에게 맡기고 갔지만, 10년 후 타임머신을 꺼내듯이 다시 열어보니 CD 표면이 울고 까져서 대부분 읽히지 않았다. 한 장에 300원짜리 싸구려 CD는 물론이고, 한 장에 1800원씩 했던 코닥, 다이요 유덴같은 최고급 CD까지 비슷하게 읽히지 않았다.
그럼 CD 말고 다른데 저장하면 낫지 않을까? 그래서 휴대용 하드디스크에 저장해서 4년 주기로 새로 사서 복사하는데, 이제는 더 이상 데이터를 잃어버리지 않는다. 약간의 배드 섹터가 생기긴 하지만 CD에 비해서는 양호하다.
근데 사실 하드디스크도 완전히 신뢰할 수 있는 건 아니다. 데이터베이스 시간에 교수님이 말씀하시길, 백만번 정도 읽으면 그중에 한 번은 확실히 실패할 거라고 하셨다. 오래된 2007년 논문이지만 구글에 “google hdd failure study”로 검색하면 나오는 “Failure Trends in a Large Disk Drive Population”를 봐도, 하드디스크를 많이 쓰는 데이터센터는 더욱 심각하다. 어차피 언젠가는 깨질테니 그걸 대비해서 운영을 해야 한다.
조금 더 나아가 마찬가지로 좀 오래된 2009년 논문이지만 구글에 “google dram error study”로 검색하면 나오는 “DRAM Errors in the Wild: A Large-Scale Field Study” 보면, 메모리에 저장하는 값마저 실패하기도 한다. 물론 구글 정도의 대규모가 되야 이게 약간 보이는 수준이겠지만, 그래도 세상에 데이터를 완전히 믿을 수 없다는 건 확실하다.
그럼 이렇게 불확실한 하드웨어 기반에서 데이터를 어떻게 안 날릴까? 아니 디스크나 메모리 같은 하드웨어는 둘째치고, 그 위에서 돌아가는 소프트웨어는 믿을 수 있을까? 사람이 짜는 건데 버그가 당연히 있지 않을까? 그리고 서버들 간에 네트워크로 통신하는데 그럼 네트워크는 믿을 수 있나? 뭐가 끊어지고 잘못되고 오염되지 않을까? 전원이 나가면 어떡하나? 불이 나면 어떡하나? 구글에 “삼성SDS 데이터센터 화재”로 검색하면 2014년에 화재가 난 적이 있는데, 불은 꺼야 하는데 물을 뿌릴수가 없어서 직원들이 직접 드라이 아이스를 부으며 열심히 불을 껐다. 하지만 과천 데이터센터 외에 지역적으로 백업을 더 해놓은 곳이 없어서 상당 부분 데이터를 날려야 했다. 그리고 복구하는 동안 서버가 안되는 걸 직원들이 엑셀 등으로 손으로 하나하나 쳐서 처리했다. 생각보다 사람이 서버 역할을 많이 할 수 있었지만, 그렇다고 그런 고생을 계속 할 순 없을 것이다.
하여튼, 이렇게 믿을 수 없는 기반 위에서 어떻게 데이터를 안 날릴 수 있을까? 그냥 지금의 컴퓨터 기술은 모래성 위에 쌓은 것이 아닐까? 어느날 바람이 불면 한 순간에 날아가버리지 않을까? 감상적인 얘기지만 그거야 우리가 하기에 달렸다. 내가 작도닷넷을 운영하듯이 대충 하면 그럴수도 있겠지만, 고민을 많이 해서 철저하게 운영하면 100%까지는 아니더라도 한 99% 이상은 데이터를 날리지 않을 수 있다.
내가 충치가 생겨서 치과에 갔는데, 어떻게 하면 충치가 안 생길까 물어봤다. 그거야 당연히 이빨을 잘 닦으면 되겠고, 여기에 치실도 하고, 가글도 하고, 전동칫솔, 치간 칫솔, 워터픽, 주기적인 스케일링 등 하여튼 많이 할수록 좋다고 했다. 그런데 이렇게 많이 해도 여전히 충치가 생길수는 있다고 했다. 다만 철저히 많이 할수록 그럴 확률이 줄어든다고 했다. 데이터도 마찬가지다. 우리가 믿을 구석은 우리에게 달렸다. 최선을 다하고 나머지는 하늘에 맡겨야겠지.
일단 가장 먼저 생각할 건 백업이다. 현재 데이터를 똑같이 어디다가 복사해놓으면 된다. 그래서 원래 데이터가 깨졌을때, 복사해놓은 걸 가져다 쓰면 된다. 그러면 복사본을 읽어도 원래 데이터랑 같을테니까, 메인 서버가 1대고 복제본이 3대면 총 4대 중에 아무거나 하나에서 읽어도 똑같을테니 부하가 분산될 것이다.
근데 그럼 메인 서버에 데이터를 쓸 때 정확히 복제본이 생길까? 조금 시간이 걸리면 어떡할까? 복사하는 사이에 누가 읽으면 옛날 데이터를 읽지 않을까? 아니면 누군가는 메인 서버에서 새 데이터를 읽는데 다른 누구는 복제본에서 옛날 데이터를 읽으면 일관성이 없지 않나? 이래도 괜찮나? 이런게 걱정이 된다면 트랜잭션을 걸면 된다. 그래서 데이터를 쓰는 사이에 누가 읽으려고 하면 그 동안은 옛날 데이터를 보여주다가, 다 쓰고 나면 이제 새 데이터를 보여준다. 그럼 누가 읽던간에 항상 똑같을 것이다.
근데 뭐 이렇게까지 안해도 되고, 어차피 웹페이지를 새로고침하다 보면 언젠가는 새 데이터가 보일테니까, 이 정도는 봐줄수도 있다. 아마존에서 아이템을 카트에 담았는데, 카트로 갔더니 방금 담았던 아이템이 보이지 않아서 새로고침을 하니까 보였다. 이렇게 새로고침을 하다보면 마침내 일관성(eventual consistency)을 지키는 정도면 될 것이다. 그럼 서버 부담이 줄어서 서버를 덜 사도 될테니 돈을 아낄 수 있다. 네이버, 아마존 등 요즘 테크 기업들은 이렇게 돈을 아낀다. 근데 이건 다른 주제니까 일단 넘어가자.
하여튼 복사를 해놔야 한다. 그래야 그 중에 뭔가 실패하더라도 복구할 수 있다. 근데 조금 더 나아가 생각해보면, 복사본이 아니라 메인 서버가 쓰는 중에도 실패할 수 있다. 데이터를 쓰는데 하필이면 거기가 배드 섹터라서 쓰는데 실패하면, 그건 복사를 해놓지도 못했으니 그 데이터는 완전히 날리는 것이다. 그럼 이건 어떨까? 메인 서버에 쓸 때 두번 쓰는 것이다. 첫번째는 일단 이런 걸 쓰겠다고 기록을 남기고, 두번째로 그 기록대로 데이터를 쓰는 것이다. 그럼 첫번째는 성공하고 두번째는 실패하더라도, 첫번째 것을 보고 다시 쓰면 된다. 물론 첫번째가 실패하면 여전히 데이터를 날리겠지만, 그래도 아까보다는 낫지 않나? 이런걸 “쓰기 전에 로그 남기기(Write-ahead Log, WAL)”라고 한다.
그리고 메인 서버에서 백업 서버로 복사할 때 실패할 수도 있다. 네트워크가 오류가 난다거나 백업 서버의 디스크에 또 배드 섹터가 생길 수 있다. 그러면 메인과 백업이 서로 시퀀스나 타임스탬프나 버전 같은 걸 가지고 있어서, 메인 서버의 최신 버전으로 덮어써서 따라잡으면 된다.
조금 더 나아가, 메인 서버가 실패해서 백업 서버로 전환하는 시간조차도 아깝다면, 메인 서버를 여러 대 두는 방식도 가능하다. 여기에 복구 시간까지 전혀 들지 않으려면 모든 메인 서버들이 완전히 똑같이 최신이어야 한다. 그러면 트랜잭션 단위로 동기화를 해야 한다. 그러면 좀 느려지는 건 어쩔 수 없어서 메인 서버를 9대 이상 두지 않는게 좋다.
여기에 더 문제가, 메인 서버 여러 대 중에서 혹시라도 서버가 동작은 하는데 좀 이상하게 동작하는 놈이 하나 생기면 어떡하나? 저것만 데이터가 조금 깨졌는데 정상으로 잘못 인식하거나 할 수도 있다. 예를 들어 서버가 5대인데 1대만 이상하다면, 아마도 4대인 쪽이 1대인 쪽보다 맞을테니 다수결에 붙여서 그 이상한 서버 하나를 쫒아낸다. 이렇게 하면 더욱 안정적일 것이다. 그래서 다수결에 쉽게 다다를 수 있도록 메인 서버의 갯수를 3대, 5대, 7대 이런 식으로 홀수로 맞춰주는게 좋다. 2대면 1대만 이상해도 1:1이 되어 다수결이 안 되니까 의미가 없고, 3대면 1대가 이상해도 2:1로 다수결이 되는데 4대면 3:1로 다수결이 되니까, 3대나 4대나 이상한 서버가 1대일때까지밖에 커버가 안 된다. 그러니까 서버를 3대에서 4대로 늘리는 의미가 없다. 그래서 짝수보다 홀수가 좋다.