CockroachDB in Production

이준성

이 글과 관련된 다른 글 보기


Summary

세상에는 다양한 종류의 데이터베이스 소프트웨어가 존재합니다. 특히 이용자가 많은 모바일 게임의 메인 데이터베이스로 사용하려면 쓰기 위주의 (Write-Heavy) 워크로드에 적합해야 하고, 이용자가 급격히 늘어날 때 빠르게 확장할 수 있어야 합니다. 대표적으로 MySQL, PostgreSQL과 같은 전통적인 관계형 데이터베이스를 고려해볼 수도 있고, Couchbase나 MongoDB, Cassandra와 같은 문서형 분산 데이터베이스를 고려해볼 수도 있고, DynamoDB와 같은 관리형 데이터베이스를 고려해볼 수도 있습니다.

데브시스터즈에서는 <쿠키런 킹덤> 의 데이터베이스로 CockroachDB라는 데이터베이스를 운용하고 있습니다. 이 글에서는 CockroachDB의 여러 가지 고유한 특성을 알아보고, 왜 CockroachDB를 메인 데이터베이스로 선택했는지, 그리고 Production 서비스에서 CockroachDB를 운용하기 위해 어떤 점들을 주의하고 신경써야 하는지에 대해 다룹니다.

01 devsisters cockroachdb case study
참고: 데브시스터즈 CockroachDB Case Study

What is CockroachDB?

CockroachDB란 SQL 인터페이스를 지원하는 분산 데이터베이스입니다. 수평 확장이 가능하고, 다양한 종류의 물리적 장애에서 살아남을 수 있으며, 전 지구적인 스케일로 데이터베이스를 구축하고 관리할 수 있는 다양한 기능을 지원합니다. GitHub에 오픈소스로 공개되어 있고, 무료로 사용할 수 있으나 몇몇 기능은 엔터프라이즈 라이센스를 필요로 합니다.

“SQL 인터페이스를 지원하면서 수평 확장이 가능한 강력한 분산 데이터베이스” 라고 하면 Google Cloud의 Spanner를 떠올리시는 분들도 계실텐데요. 실제로 CockroachDB의 세 설립자는 모두 구글의 전 직원이었고, 구글에서 퇴사한 후 Spanner와 비슷한 시스템을 세상에 내놓고자 프로젝트를 시작했습니다. 그래서 사실 CockroachDB의 핵심적인 설계는 많은 부분에서 Spanner로부터 영감을 받았다고 볼 수 있습니다.

그렇지만 Spanner와 다른 부분들도 많습니다. 대표적으로, Spanner의 경우 트랜잭션 사이의 실행 순서를 엄격히 보장하기 위해 Google 데이터센터의 전용 하드웨어에 달려있는 원자 시계 (Atomic Clock) 를 활용한다고 알려져 있습니다. 하지만…. 저희를 포함해 대부분의 개발팀은 구글이 아니고, 전용 하드웨어도 원자 시계도 없죠 😅. CockroachDB의 경우 원자 시계를 사용하지 않는 (정확히는, 시간의 동기화에 의존하긴 하지만 원자 시계만큼의 정확도까지는 요구하지 않는) 알고리즘을 구현하여 소프트웨어적인 방법으로 같은 로직을 처리하고 있습니다.

02 crdb logo

그들은 왜 데이터베이스에 Cockroach (바퀴벌레) 라는 징그러운 이름을 붙였을까요? 왜냐하면 CockroachDB는 시스템에 크고 작은 문제가 생겼을 때 생존하고 스스로 회복하는 것 (Resiliency) 에 가장 큰 강점이 있기 때문입니다. 분산 시스템을 설계할 때에 가장 어려운 문제 중 하나가 바로 장애 상황에서 일관성이나 가용성을 최대한 유지하면서 복구해내는 것인데요. 특히 분산 데이터베이스 시스템의 경우 복구에 많은 시간이 걸리거나 많은 데이터가 소실되면 어플리케이션에 큰 영향을 끼칠 수 있습니다.

CockroachDB의 경우 디스크, 물리적 머신, 심지어 데이터 센터 단위의 장애가 생기더라도 생존할 수 있는 다양한 옵션을 제공하고 있습니다. 또한 문제 상황이 생기면 스스로 감지하고 사람의 개입 없이도 자동으로 서비스를 최대한 복구해냅니다. 실제로 CockroachDB를 운영하다보면 하드웨어 문제로 데이터베이스 인스턴스 중 하나가 꺼졌는데 서비스 지표에는 영향이 전혀 없고 조금 기다리면 인스턴스도 알아서 교체되어 있는 놀라운 경험을 하게 되기도 합니다.

생존과 자가 회복 외에도 CockroachDB에는 여러 개의 핵심적인 특성 (Killer Features) 이 있는데요. 그 중 저희가 주목했던 몇 가지를 소개합니다.

  • PostgreSQL Compatibility

PostgreSQL 프로토콜의 거의 대부분을 지원하기 때문에, 기존에 커뮤니티에 존재하던 다양한 DB 접속 라이브러리나 ORM 등을 거의 그대로 사용할 수 있습니다.

  • Serializable Transactions

SQL 표준에 정의되어 있는 트랜잭션 격리 수준 4단계 중 가장 강력한 SERIALIZABLE 격리를 모든 트랜잭션에서 사용하도록 되어 있습니다. 즉, 여러 개의 트랜잭션이 동시에 실행되어도 한 번에 하나씩 실행한 것과 동일한 결과를 보장합니다.

  • 수평 확장성

데이터베이스 확장이 필요한 경우 노드를 추가로 확보하고 붙여주기만 하면 그대로 처리량과 용량을 늘릴 수 있습니다. 노드를 확장/축소하거나 교체할 때 별도의 서비스 중단이 필요하지 않고 무중단으로 작업할 수 있는 것 또한 강력한 강점입니다.

  • Multi-Region 클러스터 지원

전 세계를 대상으로 하는 어플리케이션의 경우 데이터베이스의 위치와 이용자의 위치 사이의 물리적 거리로 인해 응답 시간이 길어질 수 밖에 없는데요. 이것을 극복하기 위해 데이터베이스를 여러 개로 나누어 운영할 수도 있지만, 그러면 이제 그 데이터베이스들 사이의 싱크를 맞추는 일과 장애를 대비하는 일에 많은 공을 들여야 합니다.

CockroachDB에는 클러스터를 굳이 쪼개고 샤딩하지 않고도 하나의 거대한 클러스터를 여러 개의 리전에 걸쳐 운영할 수 있는 기능이 내장되어 있습니다. 이 기능을 활용하면 데이터베이스/테이블/row 단위로 메인 리전을 결정하고 최적화할 수 있게 됩니다.

Why we chose CockroachDB?

데브시스터즈에서는 <쿠키런: 킹덤> 의 개발 초창기부터 CockroachDB를 염두에 두고 설계했습니다. 그 전까지 데브시스터즈에서는 주로 JSON 문서 기반의 데이터베이스를 사용했었고, 원하는 정도의 성능 기준은 충분히 충족할 수 있었습니다. 하지만 이러한 NoSQL의 경우 문제 발생 시 대응하기 위해서 상당한 노력이 필요했고, Transaction 구현을 위해 어플리케이션 개발 시 별도의 복잡한 로직을 구현해야 했습니다. 반면 CockroachDB는 RDBMS의 장점 (Transaction 지원) 과 NoSQL의 장점 (샤딩 없이 수평 확장 가능) 을 모두 가지고 있어 상당히 매력적인 포지션에 놓여 있었습니다.

그렇지만 당시에는 CockroachDB가 세상에 나온지 얼마 되지 않은 시점이었기 때문에 대규모 제품에 사용한 케이스가 거의 존재하지 않았고, 아직 검증되지 않은 데이터베이스를 사용하는 것은 백엔드 엔지니어 입장에서 매우 도전적인 일이었습니다. 다행히도 CockroachDB가 PostgreSQL 인터페이스를 지원했기 때문에, 추후 성능 테스트를 진행해서 원하는 성능과 안정성이 나오지 않을 경우 최소한의 수정을 거쳐 PostgreSQL과 호환되는 다른 DB로 빠르게 전환하는 것을 플랜 B로 두고 설계를 진행할 수 있었습니다.

이후 제품 개발 과정을 거쳐 런칭 준비에 들어서면서, 본격적으로 데이터베이스에 대한 검증을 시작했습니다. 당시 검토했던 최종 후보는 1. Amazon DynamoDB, 2. Amazon Aurora (PostgreSQL 호환), 3. CockroachDB 총 세 가지였습니다. 성능, 확장 가능성, 비용 등 주요 요인에 대해 세 가지 데이터베이스를 벤치마크해보았습니다.

성능

로드를 소화하기에는 충분한, 비슷한 규모의 인프라를 기준으로 킹덤 서버의 특정 기능을 반복 수행하여 테스트를 진행했습니다. 다른 어플리케이션이나 다른 워크로드 수행시 충분히 양상이 달라질 수 있으므로 참고만 해주세요!

  • latency 중위값 (p50): CockroachDB = Aurora << DynamoDB
  • tail latency (p99): CockroachDB << Aurora = DynamoDB
  • Error Count: CockroachDB와 Aurora는 에러가 검출되지 않았고, DynamoDB에서 0.01% 정도의 에러 카운트 발생

중위 latency를 볼 때 세 엔진 모두 저희가 원하는 최소 성능은 만족시켰으나, 전반적인 분포로 볼 때에는 CockroachDB가 성능 면에서 가장 뛰어난 것으로 나타났습니다.

확장 가능성

Aurora의 경우 가장 큰 인스턴스가 최대 96개의 vCPU를 제공하므로 확장에 한계가 있었습니다. 현재 실제 운용중인 쿠키런 킹덤 데이터베이스가 수백~수천 개 단위의 vCPU 코어를 사용하고 있음을 감안하면 (당시엔 몰랐지만) 선택할 수 있는 옵션이 아니었죠.

DynamoDB의 경우 내부적으로 자동으로 수평 확장이 발생하므로 이 부분에서는 이점을 가지고 있었습니다. 그러나 사용량에 따라 다이나믹하게 수평확장이 발생하므로 확장 시점을 컨트롤하기 어렵고, hot partition이 발생하지 않도록 신경써야 합니다.

CockroachDB의 경우 수평적 확장이 가능하므로, 필요한 만큼 인스턴스를 띄워 확장할 수 있었습니다. 다만 DynamoDB와 마찬가지로 hot partition이 발생하지 않도록 신경써야 합니다.

비용

DynamoDB의 경우 OnDemand와 Provisioned 사이의 가격 차이가 크므로 1년 Provisioned 기준으로 대략적인 가격을 산정했습니다.

Aurora의 경우에도 1년 Reserved Instance 기준으로 가격을 산정했습니다.

CockroachDB의 경우 인스턴스 컴퓨팅 비용에 더해 라이센스 비용을 고려해야 했습니다. 물론 엔터프라이즈 라이센스 없이 오픈소스 버전으로 서비스하는것도 고려했지만, 상대적으로 새로운 엔진을 도입한다고 가정할 때 문제 상황 대처나 최적화 튜닝을 위해 CockroachLabs의 기술 지원이 꼭 필요하다는 판단을 내렸습니다. 실제로 서비스를 운영하면서 여러 가지 기술적으로 유용한 지원을 여러 번 받을 수 있었습니다.

전반적인 가격의 구체적인 비교는 사정상 자세하게 적기에는 어렵지만, 내부에서 계산해 본 결과 대체로 비슷하거나 CockroachDB의 가격이 (라이센스 비용을 포함해서) 조금 더 경쟁력 있는 것으로 나타났습니다.

종합적으로 비교해 본 결과 비용, 성능, 안정성, 확장성 등등 대부분의 지표에서 CockroachDB가 우위에 있었고, 최종적으로 킹덤에서 사용할 데이터베이스로 선정했습니다.

CockroachDB Internals

어떤 데이터베이스나 분산 시스템을 사용하건 그것의 동작 방식을 어느 정도 파악해두는 것은 매우 중요한 일입니다. 물론 기본 설정으로 배포해두어도 일단 적당히 사용할 수는 있겠지만, 최적화와 문제 상황 분석 및 트러블슈팅에 있어서 한계가 있을 수 밖에 없습니다.

CockroachDB를 사용하기로 결정한 이후로 저희는 이 시스템의 동작 방식을 이해하는 데에 많은 시간과 노력을 쏟았는데요. 그 중 운용을 위해 반드시 알아야 하는 중요한 컨셉을 몇 가지 소개하고자 합니다.

Key-Value Store

CockroachDB는 PostgreSQL 인터페이스를 사용해 데이터를 주고받기 때문에 관계형 데이터베이스처럼 보이지만, 사실 내부적으로는 분산 Key-Value 저장소로 구현되어 있습니다. SQL 쿼리문이 입력되면 이를 이에 맞는 Key-Value 연산으로 변환하여 수행 가능한 노드로 보낸 뒤 다시 결과를 취합하여 보여 주는 것이죠.

CockroachDB의 각 노드는 로컬 Key-Value 스토리지 엔진으로 Pebble 을 사용합니다. 초창기에는 RocksDB 를 엔진으로 사용 했지만, CockroachDB에 더 적합한 엔진을 사용하기 위해 RocksDB를 기반으로 직접 개발한 것이 Pebble 입니다(CockroachDB v20.2 버전부터 Pebble을 디폴트 엔진으로 사용하고 있습니다).

RocksDB나 Pebble 은 내부적으로 LSM tree (Log-Structured Merge tree) 구조를 사용하며, 디스크에는 SST (Sorted String Table) 포맷으로 저장합니다. 실제로 각 노드의 데이터 디렉토리에 들어가면 .sst 파일들이 존재하는 것을 확인할 수 있습니다. cockroach 바이너리에는 각종 디버그 툴이 포함되어 있는데, 그 중에서 sst 파일의 내용을 key-value 단위로 확인할 수 있는 커맨드들도 있습니다. (e.g. cockroach debug sst_dump)

Range

큰 데이터베이스를 모두 Key-Value 형태로 저장하기 위해서는 적당한 크기로 나누어 저장해야 합니다. 기본적으로는 최대 512MiB 단위로 쪼개어 저장하는데, 이 단위를 Range 라고 부릅니다.

다시 말해서 CockroachDB의 각각의 노드는 여러 개의 Range를 저장하는 저장소이고, 하나의 Range에는 여러 개의 연속한 Key와 Value가 들어있으며, 여러 노드에 복제되어 있어 각각 복제본 (Replica)의 역할을 합니다.

아래 쿼리를 통해 어떤 키가 어느 range에 속하는지, 해당 range를 복제하고 있는 노드 목록은 무엇인지 등을 확인할 수 있습니다.

select * from crdb_internal.ranges_no_leases limit 10;

Replication: Leaseholder, Raft Leader

CockroachDB는 각 range를 Replication factor 에 맞춰 여러 노드에 복제합니다. 이때 여러 노드로 분산된 환경에서 Read 와 Write 를 올바르게 처리하기 위해, 각 range 별로 Leaseholder, Raft Leader 를 하나씩 선출합니다.

Leaseholder는 해당 range에 대한 모든 읽기 요청을 처리하고 raft leader에게 쓰기 연산을 제안하는 (즉 해당 range에 대한 읽기/쓰기 연산을 최전선에서 담당하는) 노드입니다. Raft Leader는 해당 range에 대한 쓰기 연산이 항상 합의된 상태로 유지되도록 관리하는 노드입니다. 구조적으로 Leaseholder 와 Raft Leader 가 동일한 노드인 경우 쓰기 연산의 rtt가 줄어들기 때문에, CockroachDB는 가급적 이 둘을 같은 노드로 배정하려고 하지만 항상 그렇게 배정되지는 않을 수도 있습니다. 읽기, 쓰기 연산에서 각각의 역할에 대해서는 아래의 다이어그램을 통해 더 자세히 설명합니다.

이름에서 알 수 있듯 range 내에서의 합의에는 Raft consensus algorithm 을 사용합니다. 이 알고리즘은 과반 이상이 투표해야 합의가 이루어지는 알고리즘이므로, 특정 range 의 레플리카 중 과반 이상이 작동하지 않는 경우 해당 range 를 포함하는 모든 쿼리는 거부됩니다. 즉 CockroachDB는 floor(replication factor / 2) 만큼의 노드 장애 까지는 서비스 품질 저하 없이 수용하지만, 이후부터는 확률에 따라 (특정 range의 replication이 장애난 노드에 몰려 있을 확률) 일부 쿼리 (장애 range 를 포함하는 쿼리) 가 작동하지 않게 됩니다.

Read Scenario

range에 대한 읽기 연산은 아래와 같이 행해집니다. r1, r2, r3 각각은 하나의 range를 의미합니다.

03 crdb read scenario
  1. r3 내의 값을 읽으려는 요청이 클러스터에 도달합니다. 이때 CockroachDB 에서 사용자의 요청은 어떤 노드에 도달하더라도 상관 없습니다. 처음으로 요청을 받은 노드(이를 게이트웨이 노드라 합니다)는 해당 요청을 처리할 수 있는 적합한 노드에게 해당 요청을 라우팅해줍니다.
  2. r3의 leaseholder는 Node 3 이므로, 게이트웨이 노드인 Node 2 는 이 요청을 Node 3 으로 전송합니다.
  3. Node 3이 해당하는 데이터를 게이트웨이 노드에 전달합니다.
  4. 사용자에게 응답이 내려갑니다.

Write Scenario

04 crdb write scenario
  1. r1 내의 값을 업데이트하려는 요청이 클러스터에 도달합니다.
  2. 해당 요청은 r1의 leaseholder 인 Node 1 으로 전달됩니다.
  3. r1 의 raft leader 또한 Node 1 이기에, Node 1이 즉시 쓰기 연산에 대한 합의를 다른 노드들에게 전파합니다.
  4. Node 2 에게 ack 을 받습니다.
  5. 과반 이상이 확인하였으므로 (Node 1, Node 2) 즉시 게이트웨이 노드에 결과를 전달합니다.
  6. 사용자에게 응답이 내려갑니다.

MVCC

CockroachDB는 데이터를 저장할 때 MVCC (Multi-Version Concurrency Control) 를 사용합니다.

  • 모든 Key-Value 값은 한번 쓰이면 더이상 변경되지 않는 immutable 한 값입니다.
  • 특정 Key에 대한 업데이트 연산은 동일 Key 에 대해 (더 이후의 타임스탬프를 갖는) 새로운 값을 추가하는 연산입니다.
  • 특정 Key에 대한 삭제 연산은 해당 Key가 지워졌음을 표시하는 (이 마커를 tombstone 이라 합니다) 값을 추가하는 연산입니다.

이러한 특성을 이용해 읽기 쿼리 뒤에 AS OF SYSTEM TIME ... 을 붙여 과거 시간을 기준으로 읽기를 수행할 수 있습니다 (time travel query). 현재 진행되고 있는 트랜잭션과도 상관이 없기에, 이러한 time travel query 는 leaseholder 가 아닌 다른 레플리카에서 읽어도 상관이 없으며, 따라서 적절히 활용할 경우 leaseholder가 받는 읽기 부하를 완화할 수 있습니다.

즉, 어떤 키에 대한 데이터를 UPDATE 하면 예전 값이 사라지는 것이 아니라 MVCC에 의해 일정 시간동안 보존되게 됩니다. 따라서 INSERT 연산 보다 UPDATE 가 더 많은 경우 예상했던 것 보다 스토리지 사용량이 많을 수 있음을 유의해야 합니다. 같은 키를 가지는 오래 된 데이터는 시스템에 설정된 gc.ttlseconds 보다 오래 된 경우 sst compaction 과정에서 제거되는데, 이 설정의 기본값은 25시간입니다.

Production 배포시 고려해야 할 사항

Range Split

특정 range에 너무 많은 read나 write가 몰리면 병목이 발생하고 쿼리의 응답 속도가 느려질 수 있습니다. 이런 현상이 발생한 range를 hot range 혹은 hotspot 이라고 부릅니다. Hot range가 발생하거나 특정 range의 크기가 너무 커지면 CockroachDB가 자동으로 range를 쪼개어 부하를 분산하게 됩니다 (range split). 반대로 인접한 여러 개의 range가 너무 작거나 쿼리가 별로 발생하지 않는다면 range를 합치게 됩니다 (range merge).

Range를 합치거나 나누는 과정은 보통 CockroachDB에 의해 자동으로 이루어집니다. 그러나 서비스 런칭 혹은 특정 피쳐 배포 초창기에 수많은 INSERT 문이 발생하게 되면, 자동 split 이 INSERT 속도를 따라가지 못해 hot range가 발생할 수 있습니다. 특히 게임 서비스의 경우 런칭 직후나 패치 직후에 트래픽 피크가 발생하므로 서비스에 매우 큰 위험 요인이 될 수 있습니다.

이와 같이 테이블이 새로 생겼거나 새로운 패턴의 데이터가 폭발적으로 인입될 것이 예상되는 경우 range 범위를 미리 어느 정도 쪼개두는 것이 좋습니다. range를 수동으로 쪼개려면 다음과 같은 쿼리를 이용하면 됩니다.

ALTER TABLE members SPLIT AT VALUES ('AAAAA0000');
ALTER TABLE members SPLIT AT VALUES ('ABAAA0000');
...
ALTER TABLE members SPLIT AT VALUES ('ZYAAA0000');
ALTER TABLE members SPLIT AT VALUES ('ZZAAA0000');

ALTER TABLE members SCATTER;

Hotspot 피하기

CockroachDB를 사용하기로 했다면 테이블을 설계할 때부터 데이터가 잘 분산되고 핫스팟이 생기지 않도록 고려할 필요가 있습니다. 가장 대표적으로 차이가 발생하는 부분이 Primary Key와 Index 입니다.

RDBMS에서는 auto_increment를 이용한 ID column이나 계속 증가하는 타임스탬프 등을 키로 쓰는 것이 보통 일반적입니다. 그러나 CockroachDB에서는 이렇게 계속 증가하는 column을 key로 활용하는 경우 항상 테이블의 마지막 range에서만 쓰기가 일어나고, 이것이 항상 핫스팟이 될 수 밖에 없습니다.

CockroachDB에서는 Table의 Primary Key로 UUID를 사용하거나 랜덤성이 있는 컬럼을 활용하는 등 최대한 잘 분산된 키를 사용할 것을 권장합니다. 여러 컬럼을 함께 Primary Key로 묶어서 사용하는 경우 키의 분산에 더 도움을 줄 수도 있습니다.

만약 꼭 증가하는 int column을 키로 써야만 한다면 hash-sharded index를 사용할 수 있습니다. 단 hash-sharded index 를 사용하는 경우 range query (>, <) 를 사용할 때 풀스캔이 발생함을 염두에 두어야 합니다.

Locality 설정하기

Multi-region 혹은 Multi-az 등 여러 개의 데이터센터에 걸쳐 CockroachDB를 배포하는 경우, --locality 플래그를 설정하여 각 range를 분산할 때 지리적 특성을 고려하도록 할 수 있습니다.

예를 들어 replication factor가 3 이고 세 개의 AZ (혹은 데이터 센터) 에 걸쳐 DB를 배포한 경우를 가정해보겠습니다. 만약 locality 플래그를 따로 설정하지 않은 상태에서 데이터 센터 장애가 발생한 경우, 특정 range의 replica가 모두 한 데이터 센터에 존재해서 결국 데이터가 소실될 가능성이 충분히 존재합니다.

반면 locality 플래그를 설정하게 되면 각 range 별로 3개의 레플리카가 전부 다른 az에 분배되도록 분산해줍니다. 이렇게 설정하면 특정 데이터 센터에 문제가 생겨도 나머지 두개의 데이터 센터에 2개의 replica가 남아 있는 것이 보장되므로 데이터 손실도 없고 서비스도 문제 없이 제공할 수 있게 됩니다.

쿠키런: 킹덤에서 CockroachDB 를 처음에 운영할 때에는 locality 플래그를 설정하지 않았는데, 실제로 이 부분으로 인해 장애를 겪은 적도 있었습니다. 이 부분에 대한 자세한 이야기는 NDC22 - 쿠키런: 킹덤, 총 56시간의 긴급 점검 회고 - 그때 그 명검은 왜 뽑아야 했는가 라는 세션에서 다룬 바 있으니 관심 있으신 독자분께서는 꼭 확인해보세요!

Conclusion

CockroachDB는 수평 확장이 가능하고 다양한 장애 시나리오에서도 생존할 수 있는 강력한 분산 데이터베이스 소프트웨어입니다. 데브시스터즈에서는 쿠키런: 킹덤 에서의 도입을 시작으로, 다양한 내/외부 프로젝트에서 CockroachDB를 메인 데이터베이스로서 검토하고 도입하고 있습니다.

만약 CockroachDB를 검토하고 계시거나 새 프로젝트에 사용할 멋진 데이터베이스를 찾고 있는 분이 계시다면, 이 글을 읽으신 후 꼭 CockroachDB를 한 번 활용해보시길 다시 한 번 권해드립니다.

감사합니다.

읽을 거리 / 볼 거리

Spanner: Google’s Globally-Distributed Database

https://www.cockroachlabs.com/docs/v20.2/topology-patterns.html

Devsisters: Uptime as a core requirement for online gaming application

쿠키런: 킹덤, 총 56시간의 긴급 점검 회고 - 그때 그 명검은 왜 뽑아야 했는가

데브시스터즈는 최고의 인재를 찾고 있습니다.

데브시스터즈에서는 능력있는 DevOps Engineer (경력)[쿠키런: 킹덤] DevOps Engineer를 찾고 있습니다.
자세한 내용은 채용 사이트를 확인해주세요!
DevOpsInfra

© 2024 Devsisters Corp. All Rights Reserved.