컴퓨터의 시간
0.
2018년 3월, 나는 소프트웨어 엔지니어로 일을 시작했다. 1970년 1월 1일 자정을 기준으로 대충 48년 2개월이 지난 시점이었다. 그때까지도 내가 네트워크 개발자가 될 줄은 몰랐다.
1.
1970년 1월 1일은 Unix Time의 기준점이다. Unix는 윈도우 같은 운영체제로, 거의 모든 개발자들이 쓰는 Linux 운영체제는 Unix에 기반한다. 뭐에 기반한 뭐에 기반한 무엇이 현대의 소프트웨어 개발이다. 사실 모든 기술은 이와 같다. 역사를 이은 진보의 총아다.
Unix Time은 epoch, 혹은 epoch time이라고 부른다. epoch은 시대, 세대라는 뜻이다. 1970년 1월 1일의 epoch time은 0이다. Unix의 시간은 그때부터 흐른다. 그리고 그때부터 흐른 시간을 초 단위로 샌다. 글을 쓰는 지금의 epoch time은 1,607,080,591이다.
그리고 2038년 1월 19일 03:14:07에 epoch time은 2,147,483,647이 되고, 거기서 1초가 더 지나면 -2,147,483,647가 된다.
epoch time을 저장하는 자료형은 Signed Int32인데, Signed는 "부호가 있는", Int32는 "32비트 정수형"이라는 의미다. 32 비트라는 의미는 숫자를 2^32개(0~2^32-1) 셀 수 있다는 의미인데, 부호가 있는 자료형은 가장 앞의 비트가 부호로 해석돼서, 실제로 저장할 수 있는 값의 상한은 2^31-1이 된다. 물론 하한이 -(2^31-1)이 되므로 셀 수 있는 숫자는 2^32로 같다.
(8비트 Signed Int(부호가 있는 정수 자료형)의 Integer Oveflow, https://docs.swift.org/swift-book/LanguageGuide/AdvancedOperators.html)
따라서 epoch time의 상한은 2^31-1(2,147,483,647)이며, 그 시점이 2038년 1월 19일 03:14:07인 것이다. 그다음 1초에 세상의 Unix 시스템은 시간은 1901년 12월 13일로 돌아간다. 잘못된 시간은 시스템 내부의 문제나, 보안 기능으로 인한 커뮤니케이션 장애를 일으킬 수 있다. 이를 Year 2038 problem, 혹은 Epochalypse라고 부른다. 아직 해결책에 대한 합의가 이루어지지는 않았지만, 알려진 문제(Known issue)인 이상 누군가가 해결할 것이니 걱정하지 말자.
앞서 본 epoch은 시간의 특성을 잘 나타낸다. 모든 시간은 상대적이고, 우리가 절대적 인양 다루는 현실의 시간조차 약속과 합의일 뿐이다. 우리가 익히 아는 1초 또한 절대 영도 상태의 세슘-133 원자의... (중략) 91억 9263만 1770회 진동하는 데 걸리는 시간이라는 약속이다.
2.
이런 범지구적인 합의, 혹은 Unix라는 시스템 안의 합의도 있지만, 단 두 개의 컴퓨터가 시간에 대해 합의해야 하는 경우도 있다. 나는 작년의 몇 개월, 그리고 최근의 몇 개월간 이 합의를 다루는 일을 했다. 기술적으로는 시간 동기화라고 부른다. 동기화에 대해 이야기하기 전에 먼저 컴퓨터의 시간에 대해서 가볍게 이해하고 넘어가자.
컴퓨터의 시간은 (내부적으로는) RTC(Real Time Clock)라는 부품이 정한다. RTC는 오직 시간을 재기 위해 존재하는 모듈인데, 심지어 컴퓨터 전원이 꺼져도 한참은 동작할 수 있도록 자체 배터리도 있다.
RTC 안에는 크리스털 오실레이터(결정 발진기)가 들어있다. 이 장치는 진동을 발생시키는데, 보편적으로 쓰이는 오실레이터는 1초에 32,768번 진동한다. 즉 32.768 kHz의 주파수를 발생시킨다. 32,768라는 숫자에는 나름의 의미가 있는데, 이는 2의 15승으로, 바이너리 연산을 기본으로 하는 컴퓨터가 이진 연산을 15번 하면 1초를 계산할 수 있다. 오실레이터가 32768번 진동하는 게 1초, 8192번 진동하게 0.25초인 것이다. 바꾸어 말하면 32.768로 진동하는 오실레이터를 탑재한 컴퓨터는 1/32768초 단위로 셀 수 있고, 이는 대략 30.517578125 us (microsecond, 1 second/10^6)다. 즉 50us도 10us도 셀 수 없고, 오직 30.5... us 단위로 시간을 센다는 의미다. 32.768 kHz 오실레이터가 10us를 셀 수 없다는 것에 희열을 느낀다면 당신은 네트워크 개발자를 해도 좋다!
요약하면 컴퓨터의 시간은 오실레이터의 진동이다. 그리고 시간을 동기화한다는 것은 지금 시간이 몇 시인지 합의하고, 1초는 얼마나 긴 시간인지 합의하는 과정이다. 앞선 것을 Synchronize, 뒤의 것을 Syntonize라고 부른다.
Synchronize는 비교적 간단하다. 서로 자신의 시간을 교환하고, 누구의 시간을 따를지 결정한다. "나는 1시, 너는 2시인데, 네 시간을 따라서 나도 지금을 2시라고 할게!"라고 합의하는 것이다. 이때 나는 secondary, 너는 primary가 된다. (모든 표준에는 master/slave라는 표현이 정석적이지만, 최근에는 BLM 운동의 일환으로 master/slave라는 표현을 쓰지 않도록 하고 있다)
대부분의 경우 Synchronize만으로도 시간동기는 충분하게 이루어진다. 가장 널리 쓰이는 Sync 프로토콜인 NTP만 해도 1/1000초 미만의 오차를 제공한다. 네트워크 개발을 하는 것이 아니라면 이것으로도 충분하다.
Syntonize는 굉장히 복잡하다. 가장 단순한 예시로는 "이 진자가 한 번 왕복하는 시간을 1초라고 하자!"라고 합의하는 것이다. 실제로는 1. 망 구성자(Network Entity)마다 오실레이터의 주파수가 다를 수 있고, 2. 같은 스펙의 오실레이터라도 환경에 따라 오차를 보인다. 오실레이터는 작은 규모에서 동작하는 물리 장치이므로 온도에 영향을 받는데, 예를 들어 25도씨 정도를 기점으로 10도의 온도 차이가 나면 1년에 100초 이상의 오차가 발생한다. 이런 요소들 때문에 Syntonize를 완벽하게 구현하는 것은 거의 불가능하다고 할 수 있다. 따라서 시간을 동기 한다는 것은 영원히 현재 시간에 대해서 공유하고, 주파수의 오차를 교정하는 지난한 작업인 것이다. 물론 내가 하는 건 아니고, 컴퓨터가 해준다. 대표적인 프로토콜은 gPTP 같은 것들이 있지만 누가 물어보면 모른 척하는 게 신상에 이롭다.
3.
여기까지 말한 시간 동기화 작업은 사실 내가 맡은 업무의 밑 작업일 뿐이었다. 내가 맡은 업무는 One-way Latency Profile로, 풀이하자면 단방향 전송 속도 측정이라고 할 수 있다.
일반적으로, 네트워크 성능의 측정은 양방향으로 하는데, 양방향 전송 시간을 RTT(Round Trip Time)라고 부른다. 즉 어떤 메세지가 갔다가 오는데 걸리는 시간을 의미한다.
(Neso Academy, https://www.youtube.com/watch?v=nT9F-USjtBg)
이 RTT에서 불필요한 프로세싱 타임을 제외하고 반으로 나누면 단방향 전송시간을 구할 수 있다. 이러한 측정방식은 특정 환경 내에서의 성능을 파악하거나(e.g. 내 인터넷 환경, 게임의 Ping), 두 기기간 성능/기술 적용이 일치할 경우 유용하다. 그러나 내 경우에는 신규 기술이 한쪽에만 적용되어서 RTT를 구하는 방식이 불가능했다. 보그체로 말하자면 Link가 Asymmetry 한 상태라고 할 수 있다.
성능을 측정한다는 것은 대부분 지루한 일이지만, 단방향 네트워크 성능을 측정하는 건 지루할 틈이 없을 만큼 극악한 난이도다. 왜냐하면 상단에 1천 자 가까이 적어놓은 시간 동기화에 대해서 이해하고 알맞은 프로토콜을 적용하고 잘 적용이 되었는지 시시때때로 확인하는 온갖 복잡한 절차가 추가되기 때문이다. 특히 0.001초의 성능을 다투는 패킷 가속화 테스트에서는 그 1/10인 0.0001초의 시간 차이도 매우 큰 영향을 미치기 마련이고, 앞서 말한 것처럼 시간을 완벽하게 동기화하는 것을 불가능하기 때문에 이러한 시간 오차를 무마할만한 큰 데이터셋을 만들어야 했다. 여하튼 고생을 많이 했다는 말이다.
그렇게 고생해서 개발하고 측정한 기술은 20% 성능 향상이라는 좋은 결과를 냈지만 주목받지는 못하고 어영부영 폐기되었다. 예를 들어 네트워크 상에서 10ms가 걸리던 것을 8ms로 줄였는데, 전체 서비스의 전송속도가 300ms이었던 것이다. 대부분 인코딩/디코딩/캡처 등 미디어 처리에서 소요되는 시간으로, 네트워크 레벨보다는 훨씬 많은 시간이 걸린다. 따라서 내가 준비한 기술은 전체 성능을 300ms에서 298ms로 향상한 결과를 낳았고, 고생했다는 말 정도만 들을 수 있었다. 회사가 원래 이렇다.
4.
네트워크 개발을 하면 이상한 병이 생기는데, 1ms, 1us 등 작은 단위의 시간을 다루다 보니 가끔 티비 광고에서 "1초 만에 완성" 같은 문구를 보면 마음속으로 '1,000ms... 느려.' 같은 중2중2한 반응을 하곤 한다. 하루 종일 4K 데모 영상을 편집하고 집에 와서 유튜브를 켰더니 모든 영상의 화질이 너무 안 좋아서 슬퍼했었던 기억도 있다. 덕분에 4K UHD 티비를 샀다.
내년에는 본격적으로 시간을 다루는 일을 하게 될 것 같다. 기술 이름 맨 앞에 '시간'이 들어가는데, 벌써부터 눈앞이 캄캄하고 개발이 나의 적성에 맞나 되물어보게 된다. 그래도 네트워크 개발에는 낭만이 있다. 모든 데이터는 전파(Radio Wave)를 통해서 전달되는데, 이 전파의 속도는 빛의 속도와 같다. 빛의 속도는 생각보다 빠르지 않다. 1초면 지구를 7바퀴 반을 돈다는 빛은 지구 반대편에 도달하는데 직선으로만 67ms가 걸린다. 실제 물리망을 타고 라우팅 되는 과정을 거치면 200ms 가까이 걸린다. 예를 들어 서울에서 브라질리아까지 RTT는 340ms 정도인데, 단방향으로 보면 170ms가 걸리는 셈이다(너무 빠른데? 여기서 확인할 수 있다 : https://wondernetwork.com/pings). 현재 5G와 같은 최신 무선통신 기술에서는 빛의 속도라는 물리적 제약을 극복하고자 사용자에게 더 가까이 클라우드를 배치(Edge Cloud or MEC)하는 등 다양한 시도를 하고 있다. 세계의 네트워크 기술자들은 빛의 속도라는 제약 속에서 최선을 다하고 있다. 이게 낭만적이라면 당신은 네트워크 개발을 해도 좋다!