Skip to content

Naver Deview

JaeYeonLee0621 edited this page Oct 14, 2018 · 7 revisions

Naver Deview 2017

Openstack Neutron - DataPlan 구현


베어 메탈 이란 가상 서버와 반대되는 의미로 물리적 서버를 의미한다.

nova 자체도 vm을 프로비저닝하면서 기본적으로 네트워크도 제공

하지만 Neutron은 multi tenancy나 각종 네트워크 복잡한 컴포넌트를 제공하기 때문에 사용

multi tenancy를 제공하기 위해 ip overlapping 을 할 수 밖에 없음

tenancy : 누구나 다 ip네트워크를 가지는데 충돌이 나지 않게 하는 것을 tenancy라고 하고,

tenancy를 구성하기 위해 overlay network 구성,VLAN으로 쪼개던 VxLAN으로 쪼개던 MVGRL을 쓰던 이런 네트워 프로토콜을 통해서 각자 서로 다른 네트워크를 지원


네트워크 모델이 존재하는데

1. Centralized2. Distributed 가 있다.

control plane 은 micro architecture가 가지고 있음

controller는 각각에 어떤 agent가 어떤 서버에 깔리냐 따라서 특정한 노드의 기능이 부여된다.

nove나 neutron 등 모두 API나 RPC call 을 구현해서 사용한다. (message queue)

지금까지는 control plane 이고 실제로 packet을 처리하는 애들은 data plane 에 있음

open vswitch(open flow를 이용해서 packet flow 조절 / 특정한 룰들의 매칭에 의해 packet을 어느 M방향으로 보낼껀지 결정)나 ovs-ofctl, ovs-vsctl등 을 사용

linux도 사용하는데 network function을 이용한 route를 구성하고, veth, router, firewall(iptables), NAT(iptables) 등을 이용.


neutron에서 두가지를 살펴보면

centralized virtual router 는 한개의 라우터를 통해서 외부로 가는 구조

  • 모든 트래픽은 network node에 있는 route를 통해서 나간다라는 상식적인 구현을 해놓은 것
  • 단순하고 명확하지만 network node 장애에 취약

distributed virtual router

  • 장애에 강한 분산구조
  • network node를 거치지 않고 자기 안에 있는 라우터를 통해서 외부로 나감
  • 분산되어있는 효과가 있어서 네트워크 노드가 죽어도 계속 서비스를 할 수 있음
  • 하지만 라우터를 만들고 삭제하고 하는 작업에서 Control 부하가 있을 수 있다.

DVR은 퍼펙트한 솔루션일까?

위와같은 장점은 있지만

  • Control RPC가 증가하고 Neutron 서버를 늘려서 대응 을 해야한다.
  • Router가 증가하면 Sync 속도는 현저히 저하 된다.
  • vm하나를 외부로 통신시키기 위해서 엄청나게 복잡한 구조 로 구현해야한다.
  • linux network function 을 통해서 외부로 통신을 한다는 것은 속도에 문제가 생긴다.
  • 배포판 리눅스는 네트워킹에 최적화되지 않았다.
  • general purpose하기 때문에 router, iptable, linux networking이 빠르지 않고, 이것을 위해 ip, iptables 명령어를 막쓴다.

기본적으로 OpenVSwitch (가상네트워크에서 VM을 위해 제공되는 스위치) 를 사용

  • 이게 multi core를 충분히 활용하지 못한다.
  • packet flow rule이 추가할 수록 속도가 느려지고, rule을 추가하기 위해 많은 command 추가
  • 코드 오류 문제가 발생할 경우 panic으로 이어지고 command를 또 많이 날려야되고 반복

internet gateway

  • SNAT 덩어리, 사용자가 늘어날수록 안 만들래야 안 만들수 없음
  • 무조건 만들어서 그게 네트워크 노드에 쌓여서 fail over시 또 수천개의 command를 날려서 죽여야하기 때문에 매우 많은 시간이 걸린다.
  • data plane뿐만 아니라 control plane에도 부하가 감
  • 대부분 floating ip를 많이 사용해 사용빈도가 낮으나, 없으면 동작하지 않음

결과적으로

  • CVR이던 DVR이던 L2가 한통으로 엮여있어 적절하게 제어가 되지 않음
  • 전체적인 network는 B(Broadcast)U(Unknow Multicast)M(Multicast) packet에 의해서 network 성능 저하 발생 할 수 밖에 없음
  • 어느 정도 compute node를 늘이다가 한계 에 다다름
  • VLAN이 4096개 밖에 사용할 수 없고, 제한이 되어있다고 하더라도 compute node에 Switch가 있기 때문에 모든 노드가 Trunk 모드로 동작 > 누가 braodcast때리면 10000개의 서버가 있으면 10000개에 다감..
  • 전체적으로 속도가 느려짐
  • Control도 마찬가지로 늘어날수록 RPC가 늘어나고 성능 저하가 발생한다. 어느정도 확장성의 한계를 보여준다.

극뽁!


어떻게 좋게 할꺼야?

  • 확장성이 있어야한다.

    1. L2가 격리 되어잇어야한다.
    2. L2가 격리 되어있기 때문에 L2끼리는 L3로 제어한다.
  • CVR과 DVR의 장점을 모아보자

  • HW 도움을 많이 받아보자

  • 성능이 낮은 부분은 개발하자

    1. router
    2. VxLAN
    3. OVS
  • 하지만 개발은 최소화 : openstack controller은 6개월에 한번 릴리즈 > 최신 소스를 한번 안따라가면 못따라감 > controller의 개발은 최소화

    1. Neutron은 냅두고
    2. 보편적 장비도 냅두자.

Scope 이라는 격리 단위를 만들었다.

  • Scope은 L2가 도달하는 영역
  • Scope 밖은 L3이다. (Overlay를 위해 Scope을 넘어 E(End)P(Point)로 전달하는 방법 역시 Tunneling)
  • 증설은 Scope단위로 한다.
  • Scope 내부는 Scope Controller의 vSwitch가 담당

원래는

  • 하나의 neutron에 여러개의 agent가 있고
  • 각 Compute node가 쭉있고 그 앞에는 OVS, DVR router가 있으며
  • 각 agent가 그 router를 제어하게 되어있다.
  • 경계가 없고 Compute Node가 수백대건 같은 L2안에 묶이게되어 BUM packet이 늘어나는 것 을 막을 수 없다.

해결

  • 따라서 어느 정도까지는 경계를 나누어서 L2가 밖으로 못나가게하자.
  • agent와 VSwtich들은 상단으로 올리자
  • compute node내부에는 agent가 없고 상단에 Controller가 agent를 들고 있음(Top Of Rack - Rack 상단에 위치해서 이렇게 많이 부름) 여기서 처리
  • 이게 가능한 이유? neutron과 nova는 느슨한 관계

  1. Scope마다 다른 DVR 존재
  • endpoint database (자기 tenant에 속한 VM들이 어느 Scope에 위치하는지)
  1. L2를 격리하기 위해, 자기 tenant를 분리하기 위해 scope내부는 VLAN으로 쪼개져 있고 이걸 밖으로 연결하기 위해 VxLAN을 사용 이 둘간에는 mapping관계가 있어야한다.
  • 동일 segment의 vlan을 scope마다 다를 수 있다.
  1. Scope밖으로 L2가 전달되지 않는다.
  • BUM cast는 Scope 내에서
  • VxLAN Multicast는 Unicast로 변환
  • floating IP는 host-routers로 ARP 억제
  1. Scope안에서 vm은 퍼져있고, 각 vm은 다른 vlan을 가지고 있다. 그 vlan은 Scope Controller가 결정해준다.
  2. 만들어진 네트워크는 Neutron이 network의 identify즉 VNI를 정해주고
  3. vm이 Scope Controller를 거쳐 밖으로 나갈때는 VxLAN으로 변환되어 mapping 관계로 바뀐다.

control plane

  1. nova controller가 nova compute에게 vm 만들어줘 하면
  2. nova compute이 libvertd를 통해 vm을 하나 만들고 구동을 시킴
  3. neutron controller에게 network 붙여달라고 얘기함
  4. 그럼 해당하는 compute node, agent에게 vm을 생성했으니까, 밖으로 연결시키는 명령어를 날려서 밖으로 네트워크를 붙여주는 구조
  5. nova compute이라는 애가 VIFdrive를 이용해서 상단 controller에게 network 붙여달라고 말하면 controller는 neutron에 얘기해서 필요한 정보 가져와서 db에 저장을 하고 compute node의 network를 만져서 연결
  6. Internet Gateway형태는 netnode라고 이야기한 Internet GW도 각각의 서버에 LB와 SNAT의 agent도 controller와 통신하면서 구성



운영체제 수준에서의 데이터베이스 성능 분석과 최적화

Amazon Aurora DB는 MySql 대비 5배의 성능을 내고 상용 제품 대비 1/10 비용을 낼 수 있다.

예전에는 오픈소스 DB가 정말 장난감같았는데 현재에는 상용화된 것보다 훨씬 더 좋음

과거에는 OS 수준 지원이 미비해서 (OS를 믿지 못함) DB안에 작은 OS를 두어 OS 간섭을 최소화하는 방향으로 전개되었다.

현재는 큰 공룡기업들이 기여를 하다보니까 빠르게 발전

실제 리소스 관리/할당의 주체는 운영체제이므로 DB 수준 최적화만으로는 성능 개선의 한계가 있음


OS가 DB의 성능에 영향을 주는 사례


1. MySQL - Swap Insanity

MySQL의 Swap Insanity 라는 문제가 있는데, 요즘에는 일반적인 환경인것 같은데,

CPU여러개를 두고 멀티코어로 구축이되어있음. 성능적인 이슈때문에 CPU아래에 여러개의 메모리를 두는 아키텍쳐로 디자인

이 디자인을 NUMA(Non-Uniform Memory Access) 아키텍처 라고 부르는데, Local 메모리에 접근을 하면 속도가 빠르고 Remote Memory에 접근을 하면 속도가 느림

즉 CPU0에 있는 애에게 접근을 하면 속도가 빠르고 CPU1에 접근을 하면 속도가 느림

리눅스에서는 기본적으로 메모리를 Thread가 있는 곳의 메모리를 채우는데 기본 NUMA 할당은 Node0부터 채워서 Node1까지 채우는 것이다.

만약 node0(32GB)부터 node1(32GB)에 53GB를 채워서 node1에 메모리를 남긴 상태일때, MySQL thread가 메모리를 요청하면 Node0는 꽉 찬 상태이기 때문에 Swap이 발생한다. 즉 메모리가 부족해서 disk에 내리는 현상이 발생하는데, 실제로 메모리는 남아있다. Node1에.

따라서 node0과 node1에 균등하게 메모리를 분배하기 위해 interleave 라는 것이 있다. 이것을 실행시켜주면 node0와 node1에 균등하게 분배되어, node0에 요청해도 swap이 발생하지 않고 메모리가 비어있는 것으로 인식한다.


2. MongoDB Readahead 튜닝

Application이 Data를 가져올 때, Data를 순차적으로 몇번 반복해서 읽으면 Linux는 Sequencial하게 데이터를 읽는 것으로 파악해 미리 데이터를 읽어온다. 이게 Prefetching 기능 이다. 하지만 데이터베이스의 경우 Random Pattern이 많아 미리 읽어오는 데이터에 hit를 치는 횟수가 적다는 것이다. readahead가 쓸데없이 메모리를 많이 읽어 메모리 낭비가 생길 수 있다. 그래서 아예 Readahead를 끄라는 이야기도 많다.

하지만 실제로 실험을 해보면, 처리량이 40%정도 줄어든 것을 확인할 수 있다. 즉 Readahead 를 그냥 꺼버리면, 데이터를 읽어오는 속도가 늦어진다. 따라서 아예 끄는 것보다는 어느 정도라도 작게 있는 것이 낫다.


3. PostgreSQL Autovacuum 설정

만약 데이터를 update하면 그 위치에 쓰는 것이 아니라 새로 쓴다. 그럼 원래 있던 데이터는 garbage가 되기 때문에 Autovaccum 데몬이 주기적으로 데이터를 없애준다.

Autovaccum 데몬은 조금 보수적으로 설정이 되어있는데, 읽어서 새로운 값을 써주는 것 자체가 Disk I/O를 발생시켜, 사용자의 요청과 충돌이 나기 때문에 조금 느리게 작동한다.

Autovaccum을 빠르게 돌아가게 풀어보면 처리량이 40%정도 더 증가한다. 하지만 문제가 있는게 처리량은 좋은데 Disk I/O 때믄에 latency가 늘어나는 경우가 있다.


4. ElasticSearch Logging

ElasticSearch Logging부분을 보면 Memory에 변경된 데이터들을 넣어놓고 데이터가 손실되면 안되니 Translog형태로 쌓아놓는다. Memory에 쌓여있는게 Disk로 Flush가 되면 Translog가 지워지는 형태이다.

매 query마다 transaction log에 써지는 것을 기다려서 처리량이 낮다.

근데 async 모드로 기다리지 않고 바로 메모리에 쓰고 처리되어버리는 모드로 변경하면 처리량이 약 4.5배 정도 올라간다. 하지만 메모리에만 쓰고 return했으니, 데이터를 손실할 수 있는 경우가 있다.

ElasitcLogging이 쓰여지는 것을 보면 TransLog뒤에 데이터를 붙이고 데이터를 붙일 때까지 기다린다. 하지만 이걸로 끝나는게 아니라 밑의 FileSystem에서는 FilSystem Size가 변경되었기 때문에, FileSystem Metadata Logging을 한다. 이후, ElasticSearch Level에서 Metadata를 스는 작업까지 sync가 끝나면 모든 작업이 완료된다.

만약에 FileSystem Logging하는 부분을 없애는 방법을 해결하면 처리량이 2배 정도 올라간다. TransLog Metadata를 쓰는 것은 TransLog를 쓴 이후에 일어나야하므로 Ordering만 조건을 잘 맞춰주면 TransLog Metadata를 쓰는 것도 sync 처리 한번으로 해결할 수 있다.


DB 성능 관점에서의 리눅스 커널 분석

DB의 일반적인 구조를 보면, 사용자의 Request를 처리하는 Process가 있고(외부에서는 Database의 성능), Background에서 Tack는 Compaction, CheckPoint, Eviction 등의 일을 한다.

MongoDB의 성능을 테스트해보면 높은 라인으로 안정적으로 나오는 것이 가장 이상적인데, MongoDB는 60초주기로 CheckPoint가 실행되고, 이것이 실행될 때마다 주기적으로 성능이 떨어지는 것을 확인할 수 있다.

하지만 Checkpoint Thread를 극단적으로 낮춰도 성능의 변화는 거의 없다.


왜 이런일들이 발생할까?

Linux Kernel안에 보면, 여러개의 Layer가 있다. OS안에는 Disk로 가는게 느리니까 최대한 메모리에 올려놓기 위해 Cache가 있는데, 메모리가 계속 cache에 쌓이고 disk에 보내주지 않으면 문제가 생기기때문에 Cache안에서는 이를 위한 처리를 한다.

Cache를 통과하고 File System으로 가도 File System 내에서 여러 처리와 Scheduling를 해준다.

이후 File System을 통과해서 Disk로 가더라도 Scheduling을 하기 때문에 계속해서 시간이 든다. FileSystem에서는 중요한 일과 안 중요한 일 모두 실행을 하고 (Transaction처럼) 끝나면 다음 것이 동작한다.

CheckPoint를 하면 쌓여있던 메모리를 모두 Disk로 내릴 때 FG(ForeGround)와 BG(BackGround) 중에서 FG가 먼저 처리가 되야하는데, 만약 BG가 앞에 쭉 쌓여있고, FG가 뒤로 물러나 있으면, 처리 시간이 훨씬 더 걸린다.

더 복잡해지는 문제가 뭐냐면 I/O Scheduling 쪽에도 Priority Inversion과 같은 문제가 있다. 중요하지 않은 BG가 Thread를 잡고 있으면 BG가 Disk I/O를 처리할 때까지, lock이 걸리고 Thread를 잡으려고 하는 것은 Sleep상태이다. 즉 FG가 Thread를 잡아야할 때, BG가 Thread를 잡고 있다면 간접적으로 Disk I/O까지 기다려야한다.

만약에 Condition을 만족시켜야 일어나는 FG가 있을 때, BG가 Condition을 만족시키기 전에 Disk I/O를 처리해야한다면, 마찬가지로 간접적으로 기다리게 된다.

Checkpoint가 Disk I/O에 이미 써서 Disk에 던져놨는데, 그걸 FG가 직접 기다려야하는 경우도 생긴다. 즉 자기가 쏘지도 않았는데, 자기가 기다려야하는 일이 생긴다.


Solution1

  1. 전체 레이어드에서 중요한것과 안중요한게 생기면 그걸 구분해서 Interface를 열어줬다.
  2. Priority Inversion이 생기면 임시적으로 Priority가 높은 것부터 처리하도록 생성했다.

Solution1의 문제점

Application과 Kernel단의 소스를 많이 고쳐야했는데 이러면 안정성을 보장할 수 없었다.


Solution2

Solution1은 문제가 생기고 나서 사후처리를 한건데, 그렇게 하지 말고 미리 예방을 하자는 솔루션으로 가기 시작했다.

Front-End File System을 생성했는데, 실제 파일 시스템이 아니고 wrapper같은 것이다. 실제 FileSystem을 통과하기 전에 Front-End FileSystem을 통과하도록 만들었다. Front-End FileSystem에서 우선순위를 기반으로 I/O를 제어했고, OS Cache 효율성을 향상하도록 만들었다.

또한 제일 바닥에서 I/O Scheduler를 만들어서 한번 더 컨트롤을 하도록 만들었다.

이렇게 하면

latency는 성능이 최적화되지만 처리량 부분에서는 크게 두각을 나타내지 않았다.

이유는 WAL 로그 쓰기 증폭

  1. fallocate log file을 해서 log를 쓰는게 아니고 예상되는 log size에 맞게 할당한다.
  2. log record를 WTLog에 쓴다음에 Sync를 하면, FileSystem Metadata가 수정이 된다.

이것이 latency의 원인이 되었다.


그걸 해결하더라도..

성능에서 최대 0.9초의 지연이 생겼다.

이번에는 문제가..

MongoDB에는 Collection file이 생기는데, 다른 offset에 write를 하더라도 동기화 문제로 한번에 하나를 쓴다.

이런식으로 서로 다른 Block에 접근하고 있는데도 하나밖에 쓰지 못해 응답 지연 현상이 생긴다.

Solution

실제로 offset이 겹치지 않으면 동시에 진행할 수 있게 만들었다!


DB 성능 관점에서의 리눅스 커널 분석


멀티 코어 로드 밸런싱 문제

현재 리눅스에서는 코어마다 스케쥴러가 따로 있는데, 결국 어느 시점이 되면 불균형이 생긴다. 그걸 방지를 하기 위해 로드 밸런싱한다.

Load Balancing 종류

  1. Pre LB : LB는 새로운 thread wake가 되었거나, 새로 생기는 등의 현상이 발생하면 놀고있는 core쪽에 할당을 해준다
  2. Periodic LB : 주기적으로 체크해서 옮긴다.
  3. Kick LB : 일정 주기마다 놀고 있는 Thread로 보내버린다.
  4. Drain LB : 반대로 내가 놀고있으면 가져온다.

LB의 OverHead 를 보면 1. CPU Cycle 소모 2. Lock 경쟁 발생 (migration시 - LB에 의해 Task가 이동하는 순간)

CPU Cycle을 소모하는 것은 별로 중요한 일이 아닌데, Migration하는 동안에는 Source Core와 Target Core가 모두 Lock이 잡힌다.

DB에서는 네트워크를 쪽에서 무언가를 받아와서 Disk에 접근하는 경우가 많이 생겨 잦은 Task Sate 변화로 Pre LB가 발생한다.

반대로 IDLE 상태시 kick, drain등의 LB가 계속 발생한다.

만약 Thread 2개가 있고 Core 1개를 공유해서 돌고있는 시나리오 일때

  1. 원래는
  • Thread 1이 Computation을 하고 Disk에 접근할 때 Thread1은 Sleep
  • Thread 2 Wake 한 후 Computation을 하고 Disk에 접근한다.
  1. Core가 2개라서 중간에 Migration을 한다면 중간에 lock이 잡혀 진행이 되지 않는다. 즉 쓸데없이 Migration을 해서 lock이 잡혀 시간이 더 걸린다.




Naver Deview 2018 Day1


네이버에서 사용되는 여러가지 Data Platform 그리고 MongoDB


1. 네이버에서의 Data Platform

  1. 초창기에는 거의 모든 서비스가 Web Server > RDBMS Server 인 2tier 구조.

  2. 서비스가 점점 커지면서 DB Query가 복잡하고 무거워져 DB앞에 Cache (Redis) 추가

  3. 지표를 저장하기엔 RDBMS에서 공간과 비용에서 문제가 발생 > 원활한 데이터처리를 위해 HBASE (Hadoop) 사용


2. MongoDB가 네이버에서 어떤 경우 대안이 되고 있는가?


2.0 지원 Coverage 확대

기존에 지원하고 있던 Data Platform에서 Cover되지 않는 영역이 늘어남 > MongoDB를 설치해서 자체적으로 운영하는 팀이 많아짐

따라서

  1. Schema-less
  2. Sharding
  3. Secondary Index
  4. Transaction

처리가 가능한 MongoDB도 지원하게 됨


2.1 Schema less

사전에 데이터에 대한 구조나 정의를 하지 않아도 됨

서비스의 종류가 많아지면서 여러 서비스에서 공통적으로 쓰이는 부분을 플랫폼화하여 각 서비스의 요구사항에 따른 스키마 처리와 데이터 처리가 고민됨

RDBMS라면 각 서비스 별 별도의 table로 관리해야하거나 Column 추가 & 삭제 등의 서비스 중 overhead 발생

table을 생성하는 것을 보면 RDBMS가 MongoDB보다 더 적은 Byte(메모리)를 사용하는 것 을 알 수 있음

그 이유는 MongoDB는 컬럼이 없기 때문에 컬럼명까지 함께 저장해야함 따라서 컬럼명이 포함된 값이 더 byte가 클수밖에 없음

그리고 MongoDB는 각 컬럼마다 PK를 잡아 저장해놓기 때문에 사실상 한개를 저장해도 여러개를 저장하는 효과

따라서 Read, Write I/O가 증가 할 수 있고 Memory Buffer에도 상대적으로 적은 수의 document가 존재

성능상 취약해질 가능성 이 큼


2.2 Sharding

서비스 규모가 커지면서 데이터 사이즈가 증가하여 Scale up의 한계가 있음

RDBMS는 Sharding으로 Scale out을 구현할 수 있지만, 확장성이 딸어지고, 개발 및 관리의 Overhead가 발생

Auto Sharding이 가능한 DataPlatform 필요 > MongoDB


2.3 Secondary Index

단순 Bigdata 성 데이터는 Hbase를 사용하고 있음 (인프라 운영비용 절감)

조회 조건이 다양해짐에 따라 Secondary Index의 기능이 필요해짐

HBase는 Secondary Index를 지원해주지 않지만 Coprocessor, HIndex, Phoenix를 통해 Secondary Index와 비슷하게 구현은 가능

HBase Rowid가 아닌 조건으로의 조회는 region full scan으로 처리되어야함

즉 그 많은 DB를 모두 full scan해야한다!

HBase는 리전별로 별도의 Hfile에 데이터가 저장되는데 그 모든 파일이 물리적으로 분리되어있어 Secondary Index를 만들 수 없다.

하지만 MongoDB는 Collection의 Data file에 가상으로 Chunk로 분리되어있어, Secondary Index를 생성하기 용이하다. 하지만 chunk migration시 부하가 있어, 조심해야한다.


2.4 Transaction

NoSQL을 사용하면서 Transaction 기능을 원하는 경우가 있는데, MongoDB는 WiredTiger Storage Engine을 이용할 경우 높은 수준의 ACID를 지원한다.


2.5 Json 지원

메시지 포맷을 Json으로 사용 가능

가끔 쥬니어 개발자 중에 쿼리를 짜는 것에 대해 불편함을 느끼는 사람이 있음.


2.6 IDC DR

서비스가 커지고 중요도가 높아짐에 따라 DR(Disaster Recovery)를 위해 IDC이중화가 필요해짐

MongoDB는 IDC간 Auto Failover 가 가능한 Data Platform으로 한쪽의 DB가 죽으면 다른쪽의 DB가 자동으로 살아남


3. 네이버에서 MongoDB를 사용하면서 겪은 에피소드들


3.1 Mongos 관리

제조사 권장은 Mongos(Router)를 Client와 같이 배포 권장

Mongos는 WebServer와 같이 배포되어 각 Mongos가 알맞은 Shard DB를 찾아가 쿼리를 돌림

하지만 naver에는 수백대의 서버가 있으며, 모든 서버에 Mongos 데몬을 설치하여 사용할 수 없음 & 관리의 어려움 따라서 사용하고 있지 않음


3.2 L4와 getmore

Sharding에서의 L4 (Network Switch) 사용을 초기에는 권장했으나, getmore 이슈 가 있었음

MongoDB에서는 한번에 모든 데이터를 가져오는 것이 아니라 (예를 들어) 20개씩 불러오는데 처음에는 쿼리를 날리고 이후에는 getmore를 날려서 받아옴

getmore는 세션처럼 연결됬던 곳에 또 연결이 되야 받아올수 있음.

하지만 L4는 로드 밸런서이므로 해당 기능의 문제점이 생길 수 있음.

따라서 L4 사용을 중단.


3.3 mongos <-> Shard Commection

mongos와 Shard사이 커넥션 문제가 있었음

이 문제는 매우 중요한 문제이고 평소에도 많이 일어날 수 있기 때문에 해당 사에서는 이 문제를 꼭 고려해보길 바람.

원래 mongos는 최소 1개 그리고 최대 unlimited로 connection을 맺을 수 있게 되어있음.

connection은 query보다 우선순위가 높아 connection이 들어오면 query는 lock에 걸림

만약 서비스가 몰렸을 때 connection 요청이 많아 query에 lock이 걸려 몇 십초가 아닌 최대 몇 분까지 데이터가 조회되지 않았을 때가 있었음

이는 default된 configuration을 변경하는 작업으로 처리 할 수 있는데, 현재 네이버에서는 min 1 max 20으로 두어 사용하고 있음.

이렇게 사용하면 connection을 최대 20개만 맺고 이후의 connection은 무시함.

따라서 데이터 조회 동작이 빨라지는 효과를 얻을 수 있음.

이 configuration은 해당 사의 서버 사양, 데이터 크기 등등 여러가지 환경을 고려해 수정해야함.


3.4 nod.js driver

node.js 모듈인 mongoose는 성능이슈로 권장하지 않음.

node.js 3.x version은 커넥션 반환 이슈가 있기 때문에 node.js driver 2.x 사용을 권장


3.5 Storage Engine

WiredTiger Storage Engine만을 사용 & MMAPV1 및 3rd Party는 지원하지 않음

MMAPv1은 성능상의 문제가 있으며 3rd Party는 트러블 슈팅의 문제가 있음


3.6 Storage Engine - eviction problem

3.0, 3.2.x 이하 버전에서 WiredTiger 엔진 사용시 eviction 이슈가 발견

+) eviction이란 Memory Buffer에서 오래된 데이터를 삭제하는 작업

따라서 이슈가 해결된 3.2.11또는 3.4 버전 이상을 권장하며, 만약 3.2 이하라면 WiredTiger가 아닌 MMAPv1을 권장


3.7 Storage Engine - CheckPoint

checkpoint란 memory buffer와 disk 사이의 데이터 불일치를 해소하기 위해 memory > disk로 data sync를 하는 작업

WiredTiger 스토리지 엔진, 샤프 체크포인트 방식

체크포인트가 실행되는 시점에 한번에 디스크 쓰기가 발생하여, Write Heavy한 환경에서는 Checkpoint 성능이 하락

주기적으로 disk i/o가 높아진다면 checkpoint 문제일 가능성이 높음


3.6 & 7 eviction & CheckPoint

위의 그림을 보면 어떻게 DB가 동작하는지 설명되어있다.

우선 Client가 쓰기 쿼리를 보내면 DB는 바로 Disk로 가는게 아닌, Buffer Memory에 써놓는다.

이때 Buffer Memory에 있는 데이터와 Disk 데이터의 차이를 Dirty Page라고 부른다.

그리고 Buffer Memory에 써 놓는 것 뿐만 아니라 Journal log 에 따로 파일에 데이터를 써놓는다.

Journal log는 만약 buffer의 데이터를 잃었다면 역으로 Journal log를 buffer에 써 데이터 복구가 가능하다.

여기서 Checkpoint가 발생하면 WiredTiger는 Buffer Memory에 있는 데이터를 모두 Disk로 복제한다.

밑에 Eviction에서 사용하지 않는 데이터들을 모두 삭제한다.


3.8 Background Index

Mongodb는 Background Index가 가능하다. 이것은 RDBMS의 online index create와 같다.

Background Index는 Indexing을 Background에서 하는 작업이다.

내부적으로 매우 짧은 시간을 주기로 인덱스 생성, 생성 중단, 쿼리 수행 과정을 반복한다.

인덱스 생성 process시 db lock이 유발되어 쿼리 지연이 발생하므로 background Index는 새벽에 진행해야한다.


3.9 Compact

컬렉션의 모든 데이터와 인덱스를 다시 작성하고 조각모음을 수행하여 불필요한 디스크 공간을 해제하는 작업이다.

작업 중 질의 수행이 안되기 때문에 서비스를 제외하고 진행해야한다.

하지만 네이버에서는 이 활동을 진행하지 않고 있다. (권장하고 있지만)


3.10 Balancer

MongoDB의 Chunk Migration은 많은 비용이 든다.

여러 이유로 Balancing 작업이 실패할 수 있어 Config Server에서 Change log를 자주 확인해야하고, 응답속도에 민감한 서비스는 새벽시간에만 수행해야한다.


3.11 Clustered Indexing

Clustered Index 란 해당 key값을 기준으로 실제 데이터가 정렬되어있는 것인데

예를 들어 네이버 라는 조회가 많다면, 네이버를 기준으로 데이터를 정렬하여, 네이버로 clustered된 데이터들을 순서대로 따라들어가서 조회하는 것이다.

원래의 쿼리는 네이버라는 값을 full scan하여 데이터를 조회한다.

하지만 Mongodb에서는 Clustered Index가 없기 때문에 Clustered Index 조회 방식에는 사용하지 않는다.


3.12 Unique Index

Sharding 환경에서 unique Index는 전체 Shard에서 Unique하지 않다.

왜냐하면 Shard 끼리는 독립적이므로 Shard 안에있는 Index는 중복될 수 있다.

따라서 DB내에서 Unique를 보장하기 위해서는 Sharding Key값이 필요하다.


3.13 개인 정보 - 전자금융거래법

법적 조치 대상에 해당하는 Data Platform으로 MongoDB를 사용하고 있음

법적 요건을 지키기 위해서는 여러 영역을 확인해야하는데, DB영역의 법적 조건 (IP 기반 access control)을 지키기 위해서 MongoDB 3.6 Version의 AuthenticaitonResitrictions 기능 을 사용중이다.

bind_ip라는 것을 혼동하는 사람이 많은데, Bind_IP는 해당 IP가 DB접속이 가능한 걸 파악하는 것뿐 이다.

DB ACL이 해당 ip를 막아주는 기능 이다.


4. 개인적으로 바라보는 MongoDB의 장단점과 전망

  • 2018-10-11 아직까지는

  • Checkpoint 등 일부 성능상의 문제점 해결이 시급

  • Mongos <-> Shard 사이의 커넥션 안정화

  • 한글 전문 검색 문제 해결 필요

  • wiredtiger 엔진에서 B-tree 이외의 LSM도 지원이 필요




쿠팡 서비스 클라우드 마이그레이션


* 2016년 여름

쿠팡 서버 상태

  • 100개의 microservice
  • 목동 IDC, 분당 IDC

문제점

  • 추가 및 확장 진행 시간
    • 확장을 하려면 서버 구매, 요청 등 최소 6개월의 시간이 걸림
  • 확장하지 못해서 장애 발생

* 클라우드 이전의 원칙

  • 확장성을 위해 클라우드로 이전 (Scalability)
  • 서비스는 무중단으로 이전한다. (Availability)
  • 고객에게 만족도에 영향을 주지 않는다. (Performances)

* 클라우드 이전 전략

  • Roman Ride
    • Roman Ride란 두개의 말에 다리를 올려놓고 말을 타는 것
    • 데이터 센터와 클라우드 동시 운영
  • 리스크 최소화
    • 작은 변경
    • 변경에 이상이 있을 시 바로 rollback

* 클라우드 이전 준비

Dynamic Routing

DB Connection Manager
  • 공통 라이브러리 형태
  • Dynamic Config
  • 상태모니터링과 조작을 위한 Admin
  • 빠른 rollback 지원
DB 이관 순서
  • DB Replication
  • Read DB 연결 이동
  • Write DB 연결 이동
Write 기능 일시 실패
  • Conflict를 막기 위한 전략
  • microservice들의 retry를 활용
  • Long Transaction 강제 실패
API G/W를 이용한 트래픽 조절

조금씩 데이터를 옮기고 그걸 테스트 해보는 형식

기존의 데이터에서 일부분의 데이터를 불러오는 API만 변경

그렇게 변경하려면 API G/W가 필요

  • 기존 API G/W를 활용
  • 2개의 Domain Name을 사용해 트래픽 조절
  • 빠른 rollback 지원
마이크로서비스 클라우드 이관
  • 트래픽이 작고 영향도가 낮은 것부터 이관
  • 0~100%까지 트래픽 Ramp-up
  • 빠른 rollback
  • instance size 이슈
  • load balancer warm-up 이슈

Canary Testing

Canary란 꽃 종류 중 하나인데, 탄광 작업시 일산화탄소가 많으면 Canary를 이용하여 테스트 하는 것으로 비롯된 테스트 방식

Blue Green Deployment

최신 버전의 서버와 오래된 버전의 서버를 두어 그 서버 앞에 Load Balancer (HA Proxy)를 두고 최신 버전의 서버로 옮겼다가, 만약 에러가 나면 바로 오래된 버전으로 변경하는 배포 방법

  • 무중단 배포

  • 빠른 rollback 지원

  • 기존 환경과 비교하여 테스트 진행

  • 10분간 테스트를 진행

    • metric 정보 비교
    • cpu, memory, load 등 비교

Log 수집 및 저장

ELK Stack
  • Elastic Search, Logstack, Kibana Dashboard
  • docker image 형태
  • app, metric, syslog 수집
  • custom log는 공통 디렉터리 수집
로그 저장 & 분석
  • Object Storage
  • 압축, 라이프 사이클 적용

* 현재 쿠팡 서비스 상태

  • 클라우드 이동 완료

  • 200개의 microservice

  • 5000대의 인스턴스

  • 추가 및 확장 리드 타임 감소

  • 확장관련 장애 감소

  • 313 release/day

  • 300개의 micro microservice

  • 10000대의 instance

  • 18000000 metric/Day

  • 7000000000 req/day

새로운 문제 발생

  • 전파되는 장애
    • 낮아지는 SLA
    • 해당 장비에서 장애가 발생하는 것이 아니라 장애가 전파됨
  • 예상치 못한 곳에서 발생하는 장애
    • Noisy Neighbor problem
      • 공용 자원, 클라우드 서비스 제공 자원
    • 자동화와 장애
Noisy Neighbor problem
: Noisy neighbor is a phrase used to describe a cloud computing infrastructure co-tenant
that monopolizes bandwidth, disk I/O, CPU and other resources
and can negatively affect other users' cloud performance

* 마이크로서비스와 클라우드를 통해 배운 것들

모든 곳에서 실패 가능

모든 것을 리소스로 생각하고 대피 필요

  • Retry, Fallback, Circuit Breaker

+) Circuit Breaker

여러 서비스가 API나 RPC로 연결되어있을 때, 이 네트워크 중 하나라도 응답을 하지 않는다면, 의존성이 있는 서비스 모두가 멈출 가능성 이 있다.

그리고 그 근본적인 원인을 찾을 때까지 오랜 시간이 걸린다.

따라서 네트워크 장애시, 가장 중요한 기능에는 영향이 가지 않도록 장애 서비스가 발생한 서비스에 대한 접속을 차단할 필요 가 있다.

이 접속을 차단하는 시스템을 자동화 한것이 Circuit Breaker이다.

오작동 하는 서비스 연동 중지

  • 장애 전파 방지
  • 빠르게 실패하고 자동 회복
  • 자체 솔루션 Hystrix (Netflix에서 개발해 사용 중인 오픈소스로, 원격 시스템이나 서비스를 호출하는 구간을 격리해 관리하고 모니터링해주는 라이브러리)
    • 중앙 관리, 분산

예측 못하는 것들을 예측하라

Fault Injection Testing
  • 복구 기능 테스트
  • 약점 찾아내기
  • Chaos Engineering
    • Chaos Monkey (AWS 에서 제공되는 서비스로 클라우드 내에서 Auto Scaling Group 을 찾고, Instance 를 종료하는 서비스)

* 혼돈 속에서 살기

장애 채널 스케치

  • 복잡한 시스템 상황에서 상태 확인이 어려움
  • 모든 서비스 관계를 알기 어려움
  • 각자가 개발한 시스템을 각자가 운영하고 있기 때문에 자신의 서버가 아니면 해당 상황을 실시간으로 알기 어려움

안정 상태 찾기

  • 주문 결제가 가장 중요한 서비스 이므로 주문 결제 카운트
  • 서비스의 건강도를 측정
  • 주기 적극 활용
    • 매달 1일 00시
    • 일요일 밤 23:59
    • 매일 23:59 에 체크하여 확인

변경 내역 확인하기

  • 각 서비스의 상태
  • 배포 이력
  • 인프라 변경 이력 (dns, security, auth)

* Auto Scaling

원래는 이벤트가 있을 때마다 scale out을 사람이 직접 함

그리고 이벤트 이후 scale down 또한 수동으로 진행

따라서 요청에 따라 자동으로 scale이 조절되는 것이 필요

  • 요청에 따라 자동 조절
  • 이벤트 준비 시간 단축
  • Target Tracking Policy
    • 매트릭 정보 (CPU, Request 등)

폐기 가능

  • 빠른 시작과 빠른 정상 종료 보장
    • 시작이 오래 걸리면 Auto Scaling이 Traffic을 따라가지 못함
    • 정상 종료가 오래 걸리면 새로운 배포시 리소스 문제 발생
  • 빠르게 늘리고 천천히 줄인다.

* 다른 장애로 부터 배우기

  • 대용량의 복잡한 분산 시스템
  • 끊임없는 변화
  • 지속적 안정화

* 장애 리포트

타임라인

  • Detection에 걸리는 시간
  • 원인을 찾는데 걸리는 시간
  • 복구에 걸린 시간

원인 찾기

  • 고객 관점에서 5 why작성
    • 왜 고객이 주문을 하지 못했는가
    • 왜 고객이 주문 페이지에 접근하지 못했는가 등등

재발 방지

  • Poka-Yoke : 품질 관리의 측면에서 실수를 방지하도록 행동을 제한하거나 정확한 동작을 수행하게끔 하도록 강제하는 여러 가지 제한점을 만들어 실패를 방지하는 방법

Site Reliability Engineering

  • Service Reliability를 책임
  • 복잡한 장애 상황에서 컨트롤 타워
  • 장애에 대한 지식 공유
  • 장애 재발 방지 및 복구 자동화를 위한 노력

* 잘한것

  • 작은 변화와 빠른 rollback
  • 공통 배포 파이프라인 유지
  • 만든 사람이 운영하는 문화
  • 장애 관리 문화

* 다르게 해보고 싶은 것

  • 복잡도 관리
  • 도커 오케스트레이션 적용
  • 클라우드 네이티브

React

Aiden

Zoe

Gini

Clone this wiki locally