Artificial Condition: The Murderbot Diaries

머더봇 다이어리 2권, Artificial Condition을 읽었다.

1권의 사건 이후로 일종의 자유를 얻게된 머더봇은, 처음으로 자신의 목적에 따른 여정을 떠나게 된다.

회사의 소유는 아니게 되었지만 여전히 SecUnit이 홀로 다닌다는 것은 인간들에게 커다란 위협이다. 인간사회로부터 이목을 끌지 않기 위해 노력하는 과정들이 흥미롭고, 결국 어느 정도 성공한 것으로 보인다. 특히 인간들과도 어울릴 수 있게 된 점으로 인해 시리즈의 후속편들에서 여러가지 전개의 가능성이 열리게 된 것 같다.

이 책에서 가장 즐거웠던 것은 머더봇이 ART (Asshole Research Transport)라고 부르는 연구용 수송선과 티격태격 대는 장면들이었다. 드라마를 함께보며 신뢰를 쌓고 서로의 의도를 알아채고 행동을 하는, 인간으로 말하자면 우정을 쌓으며 사건을 해결해나가는 과정이 재미있었다.

1권과 마찬가지로 2권의 사건도 격렬한 전투로 마무리가 된다. 마치 액션 영화를 한편 본 느낌.

이야기가 진행되는 공간의 범위가 크게 넓어지면서, 머더봇이 설명하는 인간들의 모습이나 네트워크와 봇들과 어울려 살아가는 인간 사회의 모습이 꽤나 있음직하고 자세하게 묘사되었다. 이후의 이야기들도 기대가 된다.

삼체 1부: 삼체 문제

류츠신의 삼체 1부를 읽었다.

삼체 세계라는 3개의 항성을 가진 행성의 문명과 인류가 조우하는 이야기를, 삼체 게임을 통한 삼체 세계에 관한 설명, 문화혁명으로 시작하는 예원제의 비극적인 삶, 과학자들의 자살 사건으로 시작하는 미스테리와 충돌이라는 3가지의 흐름으로 풀어내고 있다.

이 작품에서 가장 매력을 느꼈던 이야기는 예원제의 이야기였다. 문화혁명에서 소신을 굽히지 않았던 과학자 아버지를 잃고 자신도 반동분자의 자식으로서 정신적인 고통과 고초를 겪는다. 과학자로서 예전에 했던 연구를 의미를 알아보는 사람이 있어서, 양탄일성과 함께 시작된 국가 프로젝트의 격리된 시설에서 외롭고 생존을 위한 치열한 삶을 살아간다. 예원제의 이야기는, 소설의 다른 이야기들과는 달리, 국가 또는 대중의 개인에 대한 폭력이 얼마나 개인에게 상처를 줄 수 있는지, 그리고 정치적인 관념이 과학을 지배할 때 어떠한 일이 일어나는지를 섬세하게 보여주어, 이 소설의 주인공과 주제는 예원제의 삶이 아닐까 생각했다.

삼체 문명과의 조우 사건이 전개되는 과정에서 일반해가 없다고 증명된 삼체 문제를 몬테카를로 방법으로 풀려고 사도한다든가, 우주엘리베이터에 사용될 수 있는 강도를 가진 나노 소재 연구라든가, 소립자의 차원을 조작해서 직접회로를 만든다든가 하는 SF 소설을 읽는 사람들이 즐길만한 소재들도 상당히 많이 활용되었다. 개인적으로는 과학적인 소재에 대한 설명을 줄이고 좀 더 인물들의 생각과 대화에 좀 더 비중을 두었다면 이미 훌륭한 작품이 더욱 훌륭한 SF 고전이 되지 않았을까 생각한다. 하지만, 저자의 맺음말에서도 오히려 과학적인 소재에 치중하는 중국 SF계의 유행을 벗어나기 위해 의식적으로 노력을 기울인 결과임을 알고나서는 어느 정도 이해가 되었다.

다섯번째 계절

N. K. 제미신의 부서진 대지 3부작의 1권인 다섯번째 계절을 읽었습니다.

서로 다른 시간과 장소에서 세 갈래의 이야기가 각각의 강렬한 사건으로 시작합니다. 이 책을 읽으며 이야기 속의 세상과 삶이 어떻게 이루어져 있는지 배우고, 절반 정도에 이르면 어느 정도 익숙해집니다. 하지만, 이것으로 끝나지 않고, 이 책의 마지막 장까지 놀라움은 끊이지 않습니다.

주인공들과 이 세상의 사람들은 (우리와 별 다를 것 없이) 고통 한가운데에서도 한 줌의 평범한 삶과 자유를 구합니다. 주인공들이 욕지거리를 하거나 그저 침묵으로 말을 하며 감정을 드러내지 않을 때에도 깊이 감정이 전해졌습니다.

마지막에 이르러 세갈래의 이야기가 만나며 이제서야 이야기가 시작되었다고 말합니다.

나이브스 아웃: 글래스 어니언

셜록 홈즈와 같은 추리소설에서 흔히, 독자들은 사건의 상황과 이를 둘러싼 인물들을 파악하는데에 집중하고 이윽고 대체 무슨 일이 벌어졌지라고 생각할 무렵, 탐정은 독자들이 거의 신경을 기울이지 못했을 법한 사소함으로부터 사건의 실마리를 찾고 논리를 통해 결론을 짓는다. 글래스 어니언에서도 ‘세계 최고의 탐정’은 비슷한 일을 해낸다. 하지만 글래스 어니언과 추리소설들과의 차이는 탐정이 근거를 제시하는 것들 중 일부는 시청자들도 이미 함께 봤던 것이라는 점이다. 함께 보고 함께 들었는데도 난 그냥 지나쳤고 탐정은 거기에서 중요한 단서를 찾아냈다는 것은 그야말로 가장 높은 수준의 묘미를 보여준 것이 아닌가 싶다.

전체 이야기에서도 매우 독특한 상황과 역시 독특하고 다양한 인물들, 화려한 장소에 대해서 시청자들이 탐색하고 파악하느라 바쁜 와중에, 이미 사건들은 모두 발생했고, 그조차도 탐정의 계산 하에 있었다는 전개는 추리소설 특유의 재미를 한껏 보여주었다고 생각한다. 그런 탐정은 뻔뻔하게 나의 관할은 사실을 찾아내고 그 정보를 경찰이나 검찰에게 제공하는 것까지라는 말을 반복한다.

한편으로는, 나의 삶에서도, 어떤 사람의 겉으로 드러난 이미지나 어떤 사건이나 상황에 대해 표면적으로 드러난 것만 가지고 많은 사람들이 생각하는 것에 빠지지 않고, 이면에 존재하는 진실한 모습과 사실에 기초한 진정한 이해를 추구할 수 있는 한해가 되었으면 좋겠다는 생각을 하게 하는 영화였다.

규칙은 마지막에 고려하세요

규칙과 규칙에 대한 보상과 벌을 설계하고 운영하는 일은 아주 어려운 일이다. 조직에서 어떤 부정적인 행동들이 관찰될 때 매니저로서 즉각적으로 드는 생각은 규칙을 만드는 것일지도 모른다. 하지만, 실제로는 많은 경우 가장 마지막에 고려해야 하는 방법이다.


‘9시 – 6시를 근무시간으로 한다’라는 규칙을 가진 회사를 가정해보자.

인간이 살아가는 세상이 늘 그렇듯이 9시보다 늦게 출근하는 사람들이 생겨나기 시작한다.

정시에 회사에 도착하려고 지하철역에서 뛰어왔지만 1분 늦어버린 사람, 그래도 아침에 맛있는 커피는 필수니까라고 생각하며 카페에 들르다보니 9시 10분에 도착한 사람, 어젯밤에 오랜만에 만난 친구들과 새벽까지 회포를 풀다보니 늦잠을 자버려 10시가 좀 지나서 출근한 사람.

약 20%의 사람들이 한달간 1번 이상 9시 정시 출근을 지키지 않았다. 반대로 정시에 출근하는 사람들의 20% (전체의 16%)는 늦게 출근하는 사람들로 인해 업무에 방해가 되거나 또는 불공평함을 느낀다고 생각했다.

조금 보수적인 회사의 인사부서에서는 이러한 현상을 막기 위해 9시 정시 출근하지 않는 사람들에게 직접적인 불이익을 주는 방법을 고려하다가 그 해의 인사고과에 정시 출근 여부를 반영하기로 했다. 또한, 한달 동안 시스템에 기록된 출근 시간 중에서 9시 이후인 시간이 한 번 이상 있다면 인사부서에서 매니저와 본인을 대상으로 규칙 위반을 통지하고 이는 인사고과에 반영될 것이라는 이메일을 보내기로 했다.

효과는 즉각적이었다. 정시 출근을 지키지 않던 그룹이었던 20%의 80% (전체 중 16%)가 정시 출근을 지키기 시작했다. 다만, 규칙을 지키기 시작한 20%-80% 중에서 다시 80% (전체 중 약 13%)는 다시 규칙을 지키기 시작했음에도 불구하고, 이러한 규칙에 대해 불만이 생겨났다. 살다보면 발생할 수 있는 여러가지 사고와 실수로 인해 10분 늦는 것에 대해 너무 과도한 불이익이 주어진다는 것이었다. 어떤 사람들은 자신은 아침마다 반드시 등교를 돕고 빠듯한 시간 내에 최선을 다해 출근을 하는데도 이러한 불이익은 너무 가혹하다는 논리를 폈다. 반대로, 그래도 정시 출근을 지키지 않던 그룹이었던 20%의 20% (전체 중 4%)의 출근 지연 시간은 평균 10분에서 평균 20분대로 더 늦어졌다. 어차피 불이익을 볼거라면 별 차이가 없지 않냐는 논리였다. 한편, 정시출근을 하지 않는 사람들에 대한 불만은 해소되었지만, 정시출근을 원래부터 지키던 80% 그룹 내에서도 20%의 사람들은 자신이 혹시라도 지키지 않았을 경우 발생하는 불이익에 대해 스트레스를 느꼈고 그것이 불만으로 이어졌다.

여러가지 경로로 이러한 문제점들을 들은 인사부서는 규칙을 조금 개선하기로 했다. 10분 지각까지는 경고를 하되 한달간 3회 누적이 되면 원래 대로의 불이익을 주기로 했다. 다시 규칙을 지키기 시작한 그룹 중에서 80%는 실수로 인한 위험이 줄어들어 어느 정도 만족을 했지만, 그 중 20%는 불만이었다. 그 이유는 다양했는데, 여전히 오는 경고 이메일은 두렵다는 것, 10분 이상의 지각이 일어날 수도 있는 가능성에 대한 불안, 3회 누적 시 불이익은 여전히 너무 강한 불이익이라는 것 등이었다. 정시 출근을 원래부터 지키던 80% 그룹 내에서 스트레스로 인한 불만이 줄어들었다고 대답했지만 여전히 그들 머리 속에는 불안이 자리잡고 있었다.

임원진으로부터 너무 불이익을 주는 방법만 생각하지말고 정시 출근을 하는 사람들에게 이익을 주는 방법도 생각해보자는 의견이 나와서 인사부서는 또 고민을 하게 되었다. 3년 동안 정시 출근을 빠짐없이 한 직원들을 개근 표창하고 보너스 20만원을 지급하기로 했다. 어차피 정시 출근을 하는 사람들이 80% 이상을 차지하고 있기에 3년 개근을 달성하는 것은 약 64%가 달성할 것으로 기대되는, 아주 어려운 일은 아니었다. 그래서 보너스 액수도 적을 수 밖에 없었다. 64%나 받는 표창이기에 어떤 뿌듯함 같은 것은 없었다. 어차피 정시 출근을 지키지 않던 그룹은 이 액수를 보고 마음을 바꾸지 않았다. 반대로 정시 출근을 하던 그룹의 사람들에 대해서 지각을 할 것 같으면 휴가를 사용하라는 웃지 못할 이야기도 돌았다.


‘9시 출근’이라는 어떤 회사에서 반드시 지켜야 하는 어떤 규칙을 사례로, 어떤 규칙을 지키도록 만들기 위해 어떤 일들이 일어나고 그런 과정이 얼마나 험난한지 이야기 식으로 풀어보았다. 어떤 규칙을 지키지 않는 사람들이 발생하고, 규칙을 더 많은 사람들을 지키도록 만들기 위한 과정에서 당근과 채찍을 동원하고, 규칙 그 자체에 대해 불만을 가진 사람들과 채찍에 대한 불안감을 가진 사람들, 당근에 대한 효과와 공정성에 의문을 가진 사람들이 발생한다.

사실 우리들이 모든 일에 대해서 규칙을 원하는 것은 아니다. 우리가 실제로 무엇을 원하는가를 잘 생각해보면, 실은 어떤 긍정적인 행동에 대해 여러 사람들에게 그것이 무엇인지, 그리고 왜 정당한지를 설명하고, 더 많은 사람들이 그러한 행동을 하도록 하고 싶은 것이 대부분이다. 더 좋은 단어가 있을지 모르겠지만 나는 보통 ‘규칙’ 대신 ‘가이드라인’이라는 단어를 쓴다. 가이드라인이라면, 일부가 그렇게 행동하지 않아도 큰 문제가 없다. 오히려 가이드라인이 제시하는 방식에 얽매이지 않고 다른 방식의 행동을 통해 새로운 돌파구를 찾아내는 길을 열어놓아야 할 때도 있다.

물론, 규칙이 필요한 경우도 있다. 모든 사람들이 같거나 비슷한 행동을 할 때 발생하는 시너지가 있다. 하지만, 규칙이라고 해도 여전히 이를 지키지 않는 사람들이 발생할 것이다. 처음에 규칙이 만들어질 때는 모두의 합의에 기초를 했더라도 시간이 흐르면서 또는 새로운 사람들이 들어오면서 규칙을 지키지 않는 사람들이 늘어나는 경우가 있다. 규칙을 지키지 않는 사람들이 너무 늘어나면 규칙이 유명무실해 지므로, 일정 비율 이하로 유지해야할 필요성이 있다.

그럼에도 불구하고, 규칙을 보상과 벌을 이용해 제어하려는 생각도 가급적이면 뒤로 미루는 것이 좋다. 모든 것을 규칙으로 제어하려고 하면 위에서 본 것처럼 규칙을 만드는 사람과 따르는 사람 모두가 그 규칙에 얽매여서 불행한 삶을 살아가야한다. 규칙에 대해 많은 제어를 하지 않기 위해서는 다음과 같은 고려들이 필요한 것 같다.

  • 먼저, 많은 사람들이 현실적으로 지키기 힘든 규칙이어서는 안된다.
  • 가능하다면 규칙의 설계 상 인간으로서 할 수 있는 실수는 어느 정도 허용해야 한다.
  • 규칙을 운영하면서 발생하는 작은 위반들은 그냥 눈감아주되 정상적인 상태로 올 수 있도록 가벼운 자극을 주는 것이 좋다.
  • 규칙의 목적에 반하는 매우 커다란 위반들에 대해서도 규칙을 만들지 말고 하나의 예외로서 처리하는 것이 좋다.

이러한 방식으로 규칙을 만들 때 나는 ‘정책’이라는 단어를 쓴다. ‘정책’은 조직을 운영해나가려는 의도를 통해서 조직의 방향을 제시해 사람들의 혼란을 방지할 수 있고, 규칙을 위반하는 사람들을 어느 정도 포용하면서 논의를 통해 더 나은 방법을 찾아나갈 수 있는 메시지를 준다고 생각한다.

나도 처음 매니저 역할을 경험하면서 명확한 규칙과 엄정한 실행이 답이라고 생각했던 적이 있었기에, 새롭게 매니저 역할을 하시는 분들에게 조금이나마 도움이 되기를 기대하면서 아침에 떠오른 생각들을 정리해봤다.

결국은 더 많은 규칙이 더 효과적인 조직을 만들어주지는 못한다.

First Impression of Edge Browser in iPad

오랫동안 Chrome 브라우저를 사용하고 있었고 모든 북마크가 Chrome에서 동기화되어 관리되고 있기에, iOS기기에서도 Safari 대신 Chrome을 써보려고 최근 몇달간 노력하고 있었다. 한편, 데스크탑에서 가볍게 브라우징 하는 용도로 Edge를 써봤더니 메모리 사용량도 적어 보이고 UI도 깔끔해 보여서 별 생각없이 아이패드에도 설치해서 사용해보았다. 그 결과, 아이패드에서 Chrome 브라우저를 사용할 때 불편했던 포인트 몇 개는 알 것 같다.

새 탭 열기

아이패드 Edge에서는 새 탭을 여튼 버튼의 위치가 항상 가장 오른쪽에 있어서 탭할 곳이 항상 일정하다. 마지막 탭 오른 쪽에 새 탭 버튼을 배치하는 아이패드 Chrome에 비해서 조금 더 편리한 것 같다.

데스크탑에서는 새 탭을 열 때는 브라우저에 관계 없이이 키보드나 마우스로 하니까 문제가 없는데, 터치 UI에서 비교적 자주 해야하는 일을 스크린의 안쪽에서, 그리고 매번 다른 장소에서 하도록 하는 것이 상당히 불편한 UI인 것 같다.

한편, 아이패드 Edge는 키보드 숏컷(Cmd+T)을 아직 지원하지 않는 것 같다.

새 탭에서 검색 또는 URL 입력

아이패드 Chrome의 중앙에 있는 검색 UI에 입력을 하면 위쪽에 URL바가 나타나서 입력을 이어가도록 한다. 물론 실제로는 키보드를 입력하면 되니까 손가락을 사용하는 위치는 달라지지 않지만, 봐야할 곳이 전환되는 것에는 영 적응이 안된다.

아이패드 Edge도 동일하게 동작하는 중앙의 검색 UI가 존재하지만, 새 탭을 열자마자 URL바도 함께 보여주기 때문에 익숙한 URL 바를 사용하게 되기 때문에 훨씬 나은 것 같다.

이 글을 적으면서 테스트하다보니, 아이패드 Chrome에서도 감춰져있는 URL 바 위치를 탭하면 URL 바가 나타나는 것을 알게 되었지만…

이 외에도 여러가지 차이점이 있는 것으로 보이지만, 아직은 잘 모르겠다. 당장은 아이패드에서 Edge 브라우저를 좀 더 활용해 볼 생각이다.

Talk: DEVIEW 2020 밑바닥부터 만드는 인공지능 서빙 플랫폼

얼마 전 열렸던 DEVIEW 2020의 세션 중 하나인 ‘밑바닥부터 만드는 인공지능 서빙 플랫폼’ 발표를 듣고 그 내용을 요약합니다. 플랫폼 개발의 이유를 명확하게 설명하고 이로부터 이어지는 시스템의 설계 내용이 논리적으로 잘 맞아떨어져서 즐겁게 들을 수 있었던 발표였습니다. 마이크로서비스들의 배포와 서빙을 위한 플랫폼과 머신러닝 배포 및 서빙 플랫폼 사이에 기능적, 기술적으로는 연관관계가 많이 있는 반면에, 둘 사이에 사용자, 환경, 작업 흐름의 차이 때문에 현실적으로는 머신러닝에 국한된 프로덕트가 필요하다는 생각을 가지게 되었습니다.


  • 시작
    • 2019년 초 weight 파일 + 인퍼런스 코드 + flask 서버로 서빙 시작
    • 지금은 각 모듈을 공통화
  • 모델 공통화 동기
    • 모델 수 증가 -> 서빙을 위한 엔지니어링 코스트 증가
    • 지속적인 모델 학습과 배포: A/B 테스트, 로그를 저장하고 이를 통한 학습
    • 사내시스템 연동: 유지보수가 잘 안되는 코드
    • 협업 가능한 환경 구축: 엔지니어가 모델러로부터 받은 인퍼런스 코드를 재작성하는 엔지니어링 코스트. 모델러와 엔지니어의 관심사에 따라 분리.
    • 공통화 요소
      • 게이트웨이
        • 인증, 레이트리미트, 로깅, 트래픽 관리, 비동기 처리
      • 인퍼런스를 위한 공통 라이브러리 (SDK)
        • 모델러 등의 협업 인터페이스 정의
        • http, grpc 라이브러리 제공
        • 모델 디스커버리, 로깅, 헬스체크 고려 (?)
      • 이종의 환경을 디플로이하기 위한 시스템
        • 이종의 환경을 디플로이하기 위한 단일한 인터페이스
  • MDS: 공통 모델 패키징
    • 요구사항
      • ML 프레임워크 – 텐서플로, PyTorch -> 베이스 이미지 제공
      • REST API -> Decorator/Flask
      • CPU/GPU 환경 -> GPU 환경을 위한 operator, 배치 처리 기능 추가
      • 종속성/배포 문제로 인해 Docker -> 모든 배포에 Docker 사용
    • 모델 서빙 클래스: 전처리, 인퍼런스, 후처리 코드를 decorator로 지정
    • 모델 서빙 클래스 + 모델 파일로 이루어진 모델 패키지를 생성
    • mds는 모델 패키지의 서빙 클래스를 flask와 연동하여 서빙
    • 배치 인퍼런스: 여러 리퀘스트를 한꺼번에 처리
    • 멀티 모델 파이프라인
  • DPLO: 공통 모델 배포
    • 요구사항
      • CPU/GPU 클러스터 -> 사내 주요 클러스터 오퍼레이터 구현
      • 배포 단계 제어 및 이력 관리 -> 선언적 배포 구성 파일
      • 라우팅 자동화 -> 엔드포인트 자동 등록
    • 모델 패키지를 S3에 업로드하고 DPLO에 배포 요청
    • DPLO는 패키지를 다운로드 받아서 이미지를 빌드하고 Docker Registry에 업로드
    • 요청 받은 클러스터로 배포
      • k8s 오퍼레이터 (NCC 클러스터 – 네이버 사내 컨테이너 클러스터), C3DL 오퍼레이터 (C3DL 클러스터 – 네이버 사내 딥러닝 플랫폼)
    • 클러스터의 엔드포인트 정보를 얻어 AIGW의 라우팅 정보를 업데이트
    • 기술
      • golang으로 작성
      • gRPC API 및 gRPC gateway로 REST API 노출
      • 배포 요청은 protobuf로 정의
    • 선언 파일을 통한 배포
      • Git을 통한 배포 제어 및 관리
      • 배포 상태와 배포 선언 파일 사이의 변경 관리
    • 동적 엔드포인트 디스커버리
      • 새로운 인스턴스 배포/기존 인스턴스 재시작에 따른 엔드포인트 정보 업데이트
      • MDS는 Route provider (Consul)에 라우트 정보를 등록, AIGW는 Route provider로부터 엔드포인트 업데이트
  • AIGW: 공통 모델 라우팅
    • nginx, istio 대신 직접 개발
    • 라우팅 scheme: project/model/version
      • project: 서비스, model: ML 기능, version: 버전
      • 버전 사이에서는 weighted round robin, 하나의 버전 내에서는 round robin
    • 요청 미러링 기능
      • 서비스 중인 모델의 요청을 복제해서 신규 모델에 요청 실행 가능
    • 가중치 기반 라우팅
      • 카나리 배포, A/B 테스트를 위한 버전간 가중치 라우팅
    • 로그 유통
      • 기본적인 메트릭 전송
      • anomaly detection
      • 사내 로그 저장/분석 플랫폼 활용
      • 로그 시각화
        • 미러링된 요청 구분 가능
    • 모델 서빙 모니터링
      • 모델 서버의 작동 여부
      • 쓰루풋, 응답 코드, latency, connection 수 등의 메트릭 모니터링

Paper: Hybrid Garbage Collection for Multi-Version Concurrency Control in SAP HANA

Juchang Lee, Hyungyu Shin, Chang Gyoo Park, Seongyun Ko, Jaeyun Noh, Yongjae Chuh, Wolfgang Stephan, and Wook-Shin Han. 2016. Hybrid Garbage Collection for Multi-Version Concurrency Control in SAP HANA. In Proceedings of the 2016 International Conference on Management of Data (SIGMOD ’16). Association for Computing Machinery, New York, NY, USA, 1307–1318. DOI:https://doi.org/10.1145/2882903.2903734 (pdf)

요약

인메모리 데이터베이스 중 하나인 SAP HANA의 가비지 컬렉션에 대해 설명하고 있는 페이퍼.

MVCC를 구현하고 있는 데이터베이스에서 OLAP 워크로드 등으로 인해 버전을 유지하기 위한 메모리가 증가한다거나 버전들을 처리하기 위한 코스트가 증가하는 것을 방지하기 위해서 가능한 한 사용되지 않는 버전들을 적게 유지하는 효율적인 가비지 컬렉션 메커니즘은 매우 중요하다. 기본적으로 가비지 컬렉션의 대상이 되는 버전들은 현재 실행중인 트랜잭션으로부터 접근이 불가능한 – 미래에도 접근할 필요가 없는 버전들이라고 볼 수 있다. 이를 구현하기 위한 일반적인 접근은 현재 실행중인 트랜잭션이 접근하는 가장 오래된 스냅샷 타임스탬프 (minimum global snapshot timestamp)을 추적하고 이보다 이 전에 생성된 버전들을 삭제하는 것이다.

이 페이퍼에서는 이를 개선하기 위한 구간 가비지 컬렉션 (interval garbage collection), 그룹 가비지 컬렉션 (group gabage collection), 테이블 가비지 컬렉션 (table garbage collection), 그리고 이들을 조합한 하이브리드 가비지 컬렉션 (hybrid garbage collection)을 제안하고 있다.

SAP HANA의 버전 관리

레코드를 변경하는 INSERT/UPDATE/DELETE 오퍼레이션들은 버전 스페이스에 버전을 추가하는데, 버전 스페이스는 레코드 식별자 (RID)를 기준으로 하는 해시테이블로 구성되어있다. 버전 체인은 최근의 버전부터 저장하는 방식 (latest-first)을 채택하고 있다. 인플레이스 업데이트 (in-place update)를 채택한 다른 데이터베이스와는 달리 테이블 스페이스에는 가장 오래된 버전 (oldest version)이 저장되고, 가비지 컬렉션에 의해 테이블 스페이스의 버전이 더이상 액세스되지 않을 때 새로운 버전으로 업데이트된다.

각 버전은 그 버전을 생성한 트랜잭션에 해당하는 TransContext를 가리키고 있고, 그룹 커밋에 의해 동일한 커밋 식별자 (commit ID)를 가진 트랜잭션은 동일한 GroupCommitContext를 가리키게 된다.

전역 그룹 가비지 컬렉터 (Global Group Garbage Collector)

최소 스냅샷 타임스탬프를 효율적으로 얻기 위해서 레퍼런스 전역 STS 트래커 (global snapshot timestamp tracker)를 유지한다. 이는 스냅샷 타임스탬프의 정렬된 리스트로 각각의 타임스탬프는 레퍼런스 카운팅으로 관리된다. 트랜잭션이 시작될 때 레퍼런스 카운트가 증가되고, 종료될 때는 레퍼런스 카운트가 감소되며 0에 도달하면 스냅샷 타임스탬프는 리스트로부터 삭제된다. 최소 스냅샷 타임스탬프를 얻기 위해서는 단순히 전역 STS 트래커 리스트의 첫번째 항목을 액세스하면 된다.

그룹 커밋 단위로 가비지 컬렉션을 수행하기 위해서 GroupCommitContext들이 커밋 ID 순으로 정렬된 리스트를 유지한다. 전역 그룹 가비지 컬렉터는 이 리스트를 순차적으로 방문하면서 최소 스냅샷 타임스탬프와 같거나 더 작은 커밋 ID를 가진 그룹커밋에 해당하는 버전들을 가비지 컬렉션한다.

구간 가비지 컬렉터 (Interval Garbage Collector)

전역 그룹 가비지 컬렉터는 스냅샷 타임스탬프의 최소값 이전만 가비지 컬렉션만 하기 때문에, 최소 값 이상의 타임스탬프를 가진 스냅샷들에 대해서는 한계가 있다. 한편, 최소값 이상의 타임스탬프를 가진 스냅샷이라고 하더라도 버전 체인 내의 모든 버전을 필요로 하는 것은 아니다. 특정 타임스탬프 상에서 생성된 스냅샷은 그 타임스탬프 이후의 버전 하나만을 필요로 하기 때문에, 이 구간에 속하지 않는 버전들은 가비지 컬렉션 대상으로 볼 수 있다.

구간 가비지 컬렉터는 간단히 말해, 실행중인 트랜잭션의 스냅샷 타임스탬프들과 각각의 버전 체인을 비교해서 액세스할 가능성이 없는 버전들을 가비지 컬렉션하는 방식이다. 이 때문에, 매우 정확하지만 비용이 많이 드는 가비지 컬렉션이라고 할 수 있다. 이 페이퍼에서는 이를 위한 모델을 정식화하고 이를 구현하기 위한 머지 기반의 알고리즘을 제시하고 있다. GroupCommitContext 리스트로부터 버전 체인들을 얻는 것으로 설명하고 있고, RID 테이블로부터 얻는 대체 구현도 제시하고 있다.

테이블 GC (Table GC)

SAP HANA의 경우 Stmt-SI라고 불리는 구문 (statement)별로 스냅샷을 가지는 모델을 디폴트로 채택하고 있다. 이 때문에 각각의 스냅샷이 액세스하는 테이블을, 트랜잭션 완료 시점이 아니라, 구문을 해석한 시점에 미리 알 수 있다. 테이블 GC는 이를 통해, 특정 테이블만 액세스하는 스냅샷의 부정적인 효과를 데이터베이스 전체가 아니라 테이블로 제한하는 방식이다.

테이블 GC의 구현은, 오랫동안 살아남은 스냅샷이 액세스하는 테이블을 확인해서, 스냅샷 타임스탬프 객체를 전역 STS 트래커로부터 테이블별 STS 트래커로 이동한 후, 테이블별 STS 트래커로부터 테이블별 최소 스냅샷 타임스탬프를 결정하고, 이를 이용해 각 버전의 가비지 컬렉션에 활용한다.

내부 트랜잭션의 경우 API를 통해 트랜잭션이 액세스하는 테이블을 지정할 수 있기 때문에, 실제로는 Stmt-SI가 아닌 Trans-SI에서도 테이블 GC가 많이 활용된다고 한다.

하이브리드GC (HybridGC)

전역 그룹 가비지 컬렉터, 테이블 가비지 컬렉터, 구간 가비지 컬렉터는 서로 다른 영역에 대해 가비지 컬렉션을 수행하고 있기 때문에, 세가지의 가비지 컬렉터를 모두 채용하는 것이 가비지 컬렉션의 효과성이나 데이터베이스의 성능에 긍정적인 영향이 있음을 보이고 있다.

내가 배운 것 & 생각한 것

  • 데이터베이스 사용자로서 오래 걸리는 (long-lived) 트랜잭션으로 인한 MVCC 데이터베이스의 성능 저하 등의 문제에 대해서는 어렴풋한 개념을 가지고 있었지만, 데이터베이스 상의 가비지 컬렉션 메커니즘에 대해서 자세한 내용을 접해본 것은 이 페이퍼를 읽고 관련된 강의를 들었던 작년 겨울이 처음이다.

  • 효율적인 가비지 컬렉션을 위해서 스냅샷 및 그룹 커밋들의 정렬된 리스트를 활용하고 있다.

  • 구간 가비지 컬렉터에 대해서 수학적인 모델과 알고리즘만 제시하고 있기 때문에 직관적으로 이해하는 것은 조금 어려웠다. 간단한 개념도만 있었다면 매우 이해하기 쉬웠을 것이다. 한편, 실질적인 접근성 (reachability)을 기준으로 모든 버전을 체크하는 것은 Java와 같은 언어 런타임의 가비지 컬렉션과 거의 차이가 없다는 생각이 들었다. 단, 과거의 버전에 대한 액세스가 새로 생겨날 가능성은 없으므로, 언어 런타임의 가비지 컬렉션보다는 동시성에 관한 난이도는 높지 않다고 생각했다.

  • 구간 가비지 컬렉터에 의해 버전 체인의 중간에 있는 버전들이 가비지 컬렉션 될 경우, 만약 델타 버전을 채택하고 있다면 삭제된 구간의 델타 버전들을 통합할 필요성이 있을텐데, 여기서는 그러한 언급이 없는 것으로 보아, 델타가 아닌 각 버전별 값을 저장하는 것으로 보인다.

  • 언어 런타임에서와 마찬가지로 워크로드에 따라서 각각의 가비지 컬렉터에 어느 정도의 CPU 리소스와 동시성을 투자해서 수행할지는 미묘한 튜닝 또는 셀프 튜닝의 문제가 될 것 같다.

  • 인메모리 데이터베이스에서 특정 워크로드에 의해서 가비지들이 갑자기 많아진다면 실용적으로 사용하는 것에 굉장히 크리티컬한 문제가 될 것 같으므로, 특히 인메모리 데이터베이스에 있어서, 신뢰할만한 가비지 컬렉션 메커니즘은 굉장히 중요한 것 같다. 한편, 버전 스페이스 오버플로우가 발생할 경우 오래된 버전을 디스크로 기록하고 일부 트랜잭션을 중지하는 등의 SAP HANA 기능에 대한 언급이 있기는 하다.

Paper: Fast Serializable Multi-Version Concurrency Control for Main-Memory Database Systems

Thomas Neumann, Tobias Mühlbauer, and Alfons Kemper. 2015. Fast Serializable Multi-Version Concurrency Control for Main-Memory Database Systems. In Proceedings of the 2015 ACM SIGMOD International Conference on Management of Data (SIGMOD ’15). Association for Computing Machinery, New York, NY, USA, 677–689. DOI:https://doi.org/10.1145/2723372.2749436 (pdf)

요약

HyPer의 MVCC 구현에 관한 페이퍼.

많은 DBMS들이 MVCC를 구현하고 있지만, 대부분의 경우, 직렬성 (Serializability)을 보장하기 보다는 이보다 더 약한 격리 수준인 스냅샷 격리 (Snapshot Isolation; SI) 만을 보장하고 있다. 일반적으로 스냅샷 격리를 직렬적으로 만들기 위해서는 높은 비용이 필요한 것으로 알려져있는데, 이 페이퍼에서는 적은 비용으로 직렬성을 보장하는 MVCC 구현을 제안하고 있다.

이 구현의 기본적인 접근은 메인 테이블에는 최신 버전을 유지하고 in-place update를 하되, 새로운 버전으로부터 오래된 버전 순서대로 (newest-to-oldest) 연결된 버전 벡터를 통해 이전 버전에 대한 액세스를 제공한다.

흥미로운 것은 아직 커밋되지 않은 트랜잭션에 의해 추가되는 버전이다. 위의 그림에서 Ty는 아직 커밋되지 않은 트랜잭션의 ID로 커밋된 시간과 구분하기 위해서 263 이상의 매우 큰 값으로 할당된다. Ty 트랜잭션에 의해 메인 테이블에서는 ‘7’이라는 값이 in-place update되고, 이 값은 Ty 트랜잭션에게만 보이는 값이 된다. 한편, 버전 벡터의 Ty에 해당하는 항목에는 Ty와 Ty 트랜잭션이 일어나기 전의 값이 저장된다. 따라서, T5 이후에 시작된 (Ty 이외의) 트랜잭션에서는 Ty 트랜잭션이 생성한 버전으로부터 ‘8’이라는 값을 얻게된다.

커밋되지 않은 데이터를 가진, 즉 트랜잭션 ID를 가진 버전이 존재하는 레코드에 대해 쓰기 오퍼레이션을 하려는 트랜잭션은 바로 중지되고 롤백된다.

Serializability Validation

직렬성을 보장하기 위해서 트랜잭션에서 일어난 읽기 오퍼레이션들이 다른 트랙잭션에 의해 영향을 받지 않았음을 보장하기 위한 검증 단계 (validation phase)를 필요로 한다.

기존의 방식은 주어진 트랜잭션의 모든 읽기 오퍼레이션을 기록하고, 트랜잭션이 끝나기 전에 다시 한번 읽기 오퍼레이션을 모두 수행함으로써 다른 트랜잭션으로부터의 영향이 없었음을 검증하는데, 이는 스캔이 많은 워크로드에서 굉장히 높은 비용을 요구하게 된다.

이 시스템에서는 Precision Locking이라는 오래된 기법을 이용하는데, 기본적으로 읽기 오퍼레이션이 아니라 읽기 오퍼레이션의 조건 (predicate)들을 기록하고, 검증단계에서는 해당 트랜잭션의 라이프타임 동안 발생한 트랜잭션들의 쓰기 오퍼레이션들이 읽기 오퍼레이션들의 조건과 겹치는 지를 확인하는 방식이다.

검증할 트랜잭션의 라이프타임 동안 발생한 트랜잭션들을 효율적으로 찾기 위해서 최근의 트랜잭션 리스트를 유지하고, 이 트랜잭션에 함께 저장된 undo 레코드를 통해서 쓰기 오퍼레이션들을 확인할 수 있다.

Efficient Scanning

스캔을 할 때 레코드별로 버전 벡터가 존재하는지 여부를 체크하는 것을 피하기 위해, 일정한 범위의 레코드들마다 버전 벡터가 존재하는 레코드의 범위를 저장하고 (VersionedPositions), 이를 통해 버전 벡터가 존재하지 않는 범위에서는 더 빠르게 스캔할 수 있도록 도와주는 메커니즘을 가지고 있다. 불필요한 버전들은 계속 가비지 컬렉션에 의해 제거되므로, 소수의 레코드들만이 버전을 가지고 있는 것을 가정하고 있다.

Evaluation

  • VersionPositions를 통해서 약 5배 가량의 스캔 throughput 개선이 이루어졌다.
  • 스냅샷 격리 (SI)에 대비해 직렬성을 보장하는 레코드 레벨 조건 로깅이나 애튜리뷰트 레벨 조건 로깅은 약 5-7%의 비용만을 요구했다.

내가 배운 것 & 생각한 것

  • 낙관적인 동시성 제어를 사용하는 MVCC 구현, OLTP/OLAP 둘다에 최적화, LLVM을 이용한 코드 생성 등의 기능들이 상용화되는 인메모리 데이터베이스 구현에서 많이 보이고 있다.
  • Precision locking을 이용한 낙관적인 트랜잭션의 검증은 듣고나면 당연한 것 같지만, Hyper의 독특한 방식이라고 생각한다. 기존의 데이터베이스에서 반드시 이런 접근을 할 필요는 없었다고 생각하는데, 포인트 쿼리와 업데이트들 만으로 구성된 OLTP 트랜잭션이라면 읽기 집합 (read set)을 이용한 검증이 그리 비효율적이지는 않다고 생각된다. 대량의 스캔을 포함한 OLAP 트랜잭션에 대해서는 2번의 읽기를 하는 것만으로도 비용이 굉장히 높아지므로, 이것을 최근의 트랜잭션 리스트를 유지하는 비용 및 쓰기 집합 (write set)의 크기에 따른 성능 저하와 트레이드 오프한 것으로 볼 수 있는 것 같다.
  • 우리가 흔히 사용하는 데이터베이스에서는 스냅샷 격리를 사용하는 것이 보편적이고 그 이상은 비용효율적이지 않다는 선입견을 가지고 있었는데, 직렬성을 보장하면서도 충분히 좋은 성능을 보여주는 이 페이퍼를 본 후에 그러한 선입견을 깰 수 있었다.

Jepsen report on RedisRaft

RedisRaft에 대한 Jepsen 리포트가 나왔다.

https://jepsen.io/analyses/redis-raft-1b3fbf6

RedisRaft는 Redis Labs에서 개발하고 있는, Raft를 이용해 replication을 구현한 Redis module이다. 약 2018년 초에 PoC 프로젝트로 시작되었고, 2019년 중반부터 본격적으로 개발하기 시작했다고 한다. 실제로 RedisRaft의 GitHub repository를 확인해보아도 Yossi Gottlieb라는 개발자가 약 1년 전부터 commit을 하기 시작한 것을 알 수 있다. 현재는 개발 중이고 2021년에 GA로 내놓을 예정이라고 한다.

실제로 분석을 통해 21개의 버그를 발견했고 다양한 성격의 문제들이 있었지만, RedisRaft가 가져다 사용한 Raft 구현에도 여러 버그가 있었고 치명적인 문제로도 연결되었던 것 같다. Paxos나 Raft 알고리즘은 대략적인 얼개를 구현하는 것은 어렵지 않을지는 몰라도 여러가지 실패 모드들을 제대로 구현하는 것은 굉장히 어렵기로 잘 알려져있다. 참고로, RedisRaft가 사용하고 있는 Raft 구현은 C로 쓰여진 https://github.com/willemt/raft. 이러한 이슈들을 보면 일단 데이터베이스에서도 그렇지만, 분산시스템에서는 더더욱 사려깊게 설계된 테스트가 굉장히 중요하다는 것을 다시 한 번 확인할 수 있었다. 그리고, 정확한 분산시스템을 쓰는 것이 얼마나 어려운 것인지, 그리고 시간이 드는 것인지도 다시금 떠올릴 수 있었다.

한편, Antirez도 이 리포트를 언급하며 Redis를 state machine으로 보고 Raft를 외부에 구현하는 것에 대한 아이디어와 설계에 대해 RedisRaft의 주저자인 Yossi Gottlib과 얘기했었다고 언급했다. 아이디어 자체야 새로운 것은 아니겠지만, 미니멀리스트인 Antirez로서는 충분히 예상되는 디자인. 분산시스템 분야 사람들은 Antriz가 취하는 여러가지 ‘실용적인’ 절충들에 대해서 탐탁치 않아하는 것이 사실이고, Redis cluster 설계에 대한 평가도 그리 좋지 않았다. Jensen의 Kyle Kingsbury도 이에 답글을 달아 이에 대해서 우리가 설득하려고 하지 않았냐고 그러한 논의를 상기시킨다. Antirez는 만약 그랬으면 Redis는 망했을거라고. 거의 Antirez 혼자서 Redis의 대부분의 기능들을 개발하는 상황 상 만약 그가 Raft 구현의 정확성에 시간을 쏟았다면 아마도 다른 부분의 진척은 굉장히 느려졌을거라는 상상은 충분히 할 수 있다. 분산시스템 개발은 그만큼 어렵다. 이렇게 서로 다른 의견을 가진 사람들이지만 어떤 형태로든 협력해서 또다른 좋은 프로덕트가 나오게 된 것은 좋은 일이라 생각한다.