일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
- 파이썬 데이터분석
- 스칼라 동시성
- 주키퍼
- 플레이프레임워크
- 파이썬 강좌
- 스칼라
- Play2 로 웹 개발
- 블록체인
- 파이썬 머신러닝
- Golang
- 파이썬
- 하이브리드앱
- play 강좌
- 이더리움
- 스위프트
- 그라파나
- akka 강좌
- Akka
- 하이퍼레저 패브릭
- CORDA
- 안드로이드 웹뷰
- hyperledger fabric
- 스칼라 강좌
- Actor
- 엔터프라이즈 블록체인
- play2 강좌
- 파이썬 동시성
- Play2
- Hyperledger fabric gossip protocol
- Adapter 패턴
- Today
- Total
HAMA 블로그
[블록체인] TPS 그리고 Disruptor 패턴 본문
블록체인과 TPS
Transactions Per Second (TPS) 란 말 그대로 초당 트랜잭션 수를 의미하는데, 시중 대형은행의 TPS 는 보통 몇백에서 몇천건이라고 합니다. 글 본론에서 소개해드릴 자바기반의 LMAX 아키텍쳐에서 사용한 DISRUPTOR 패턴은 초당 600백만 트랜잭션을 처리 할 수 있다고 하는데요. (실..실화냐?)
* DISRUPTOR 패턴을 한마디로 축약하면 "싱글 쓰레드" 의 힘!! 입니다.
TPS 는 보통 "- 외부에서 데이터를 받고 - 그 데이터를 처리하고 - 처리된 데이터를 외부로 내보내고" 를 한 싸이클로 보고 계산을 하게 되는데, 그림에서 보다시피, 외부에서 데이터를 받는 네트워킹 상황에 따라서도 영향을 받을 수 있으며, 내부의 로직을 처리하는 시간에 따라서도 영향을 받게 됩니다. 1세대 블록체인 기술인 비트코인 같이 모든 노드가 네트워킹에 참여하여 동일한 역할을 수행하는 경우, 그 부분에서의 제약이 작지 않으리라는 것을 추측 할 수 있을 것입니다.
또한 블록체인에서는 "신뢰의 속도"라는 개념이 TPS에 추가됩니다. 따라서 기존 메세지큐(MQ) 들의 TPS 를 계산하는 방식을 그대로 적용할 수는 없는 노릇이기도 합니다.
비트코인
비트코인 경우 1MB 의 블록용량한도와 10분의 블록 생성을 근거로, 1 트랜잭션을 계산해보면 약 7TPS 가 채 안나오게 됩니다. 네트워킹 능력을 떠나서 애초에 로직상에서 처리 할 수 있는 한도를 정해놨기 때문에 추가 성능향상은 트랜잭션 크기를 줄이거나, 블록생성 속도를 빠르게 할 수 밖에 없지요. (이런 논의는 계속되고 있습니다.) 즉 컴퓨터 공학적인 어떤 트릭이나 기술로만은 해결하기 힘든 문제입니다. (사이드 체인은 논외)
이더리움
이더리움 경우는 블록생성 주기가 대략 12초이며, TPS 는 10~30정도로 보고 있습니다. 일단 이더리움은 비트코인과 다르게 블록사이즈의 limit 와 트랜잭션 사이즈가 정해져 있지 않으며, 비트코인보다는 채굴속도도 비약적으로 빠르지만 TPS 처리가 쩌리인 이유는 블록당 사용할 수 있는 가스가 정해져 있기 때문입니다. 가스라는 것은 이더리움상에서의 코인을 좀 더 유연하게 처리하기 위한 대체재인데, 트랜잭션 비용을 처리 할 때 매개체로 사용됩니다. 그 가스량이 정해져 있다는 것은 블록사이즈의 크기가 정해져 있다는 것과 비슷한 제약을 가져오는 것이지요. (DDOS 등 외부 침입자의 무차별적인 트랜잭션 전송을 막기 위한 방편으로 트랜잭션별,블록별가스리밋이 생김)
이더리움의 차세대 합의 메커니즘인 캐스퍼에서는 일단 블록생성 주기는 엄청 짧아 질 것이며, (신뢰의속도 증가) 기타 다양한 (샤딩 등) 기술들의 도입으로 TPS 는 훨씬 빨라지리라 예상되고 있습니다.
하이퍼레저 패브릭
프라이빗 블록체인인 이 놈은 15노드로 10만 TPS 를 목표로 합니다.
스팀/EOS
이더리움의 강력한 라이벌인 EOS 는 백서에서 밝히길,싱글 쓰레드에서 1만 TPS를, 멀티쓰레드에서 100만 목표로 하고 있습니다. EOS 를 만든 댄라이머는 비트쉐어와 스팀도 만든 사람인데, 이것들은 모두 DPOS (간접민주주의 방식)라는 합의메커니즘을 사용하며, 플랫폼 내부에 있는 그래핀이라는 코어의 트랜잭션 처리 기술이 Distruptor 패턴에서 영감을 받았습니다. 어떤 엄청난 신뢰의 산물을(신뢰비용)을 만들기 위해 많은 시간을 쏟아 붙는 것도 아니고, 전국민이 투표하는것도 아니고, 몇몇 대표자들끼리 투표하는데 얼마 걸리겠습니까?
(참고로 스팀/EOS 는 트랜잭션 비용도 무료(?)입니다. 소액결제부분에서 이더리움이 너무나 큰 약점으로 생각되는 부분이죠. 물론 엄청나게 뛰어나보이는 기술/철학 뒤의 약점도 많습니다. 참고. 트레이드오프가 있지 항상 참인 기술은 없으니까요, 블록체인 플랫폼간의 트랜잭션 비용 전쟁은 사용자들이 가장 흥미롭게 지켜 볼 만한 요소라고 생각합니다. 여담으로 저는 현재 이더리움의 사이드체인 기술들, 예를들어 loom network 와 스팀의 SMT에 굉장히 매력을 느끼며 저울질 중에 있습니다)
(https://steemit.com/coinkorea/@dev1by0/3qa1pb-eos 발췌)
이제 블록체인 얘기는 그만하고, EOS가 영향받은 LMAX Architecture 와 Distruptor 패턴에 대해서 살짝 알아 보겠습니다. 일단 이 패턴은 일반적으로 사용될 수 있는 기술이고, 오픈소스로 공개되어 있기 때문에, 여러분의 상황에 맞다면 가져다 쓸만하다고 볼 수 있습니다. 물론 그 상황이 초당 몇백,몇천 정도 TPS 수준으로 충분하다면 굳이 바꿀 필요는 없겠지요.이 놈은 초당 몇백만TPS를 처리하는 녀석이니까요.
LMAX Architecture 와 Distruptor 패턴
제가 C++로 유체역학 솔루션을 만들던 (즉 대규모 트랜잭션처리에 대해선 무지) 2011년에 자바진영에서 엄청난 물건이 나왔습니다. 스타워즈에 나오는 광선총의 이름과 같은 Distruptor 패턴인데, smalllake 님의 블로그에 소개된 내용을 보면
"Java로 개발된 프로그램에 주는 Duke’s Choice Award를 2011년에 수상한 Distruptor는 현재 영국 LMAX에서 사용하고 있습니다. LMAX는 FX(외환거래)를 하는 곳입니다. 겉으로 보면 증권사같습니다만 FX는 중앙거래소가 없기때문에 LMAX자체가 거래소라고 할 수 있다고 합니다. 고객의 호가주문을 받아서 매매체결하는 부분으로 연결시켜주기 위한 라이브러리가 Disruptor입니다. Inter-Thread Library이며 고성능지지연(Low Latency)을 가능하도록 합니다. 그런데 LMAX는 이를 오픈소스로 공개하였습니다."
라고 적혀져 있는데요. 해당 소스는 여기를 참고하시면 됩니다 (https://github.com/LMAX-Exchange/disruptor)
처음은 자바로 짜여져있으나, 모든 패턴이 그러하듯이 다른 언어로도 충분히 구현이 가능합니다. 이 패턴에는 어떤 외부 라이브러리가 필요 없으며, 자바의 고유 사용패턴을 함께 사용할 필요도 없습니다.
이 패턴을 개발하기전에 액터패턴 같은 것을 처음 시도하였지만, 쓰레드 사용에 대한 오류와 복잡도에 대한 부분은 줄였지만, 역시 액터사이에 메세지를 전달하기 위해 사용되는 큐에 대한 지연 부분이 문제가 되었다고 합니다. 즉 로직에서 지연보다 큐에서 블럭되어 있는 시간이 훨씬 길었다는 것이지요.
이때 눈여겨 본 부분은 바로, "캐시" 이며, "캐시" 를 적극적으로 사용하기 위한 아이디어로 Distruptor는 탄생되었습니다.이것은 아무리 소프트웨어,특정 언어라고 말해도, 기본적인 하드웨어에 대한 관심도 중요하다는 교훈(mechanical-sympathy)을 줍니다.
캐시
컴퓨터 내부의 각 장치들 간의 속도를 보면
보시다시피 , CPU는 1ns 즉 10억분의 1초의 속도를 자랑하지만, HDD로 갈수록 점점 엄청 느려지는 것을 알 수 있습니다.
멀티코어 CPU라고 모든 캐시와 메모리를 각자 사용하는 것이아니라, 메모리는 물론 캐쉬도 공유합니다.
보통 우리가 (제가) 어떤 메세지를 전달하는 구조를 생각할때 가장 먼저 떠올리는 것은 생산자-소비자 패턴에 중간의 매개체로 언어에서 제공해주는 쓰레드 안전한 큐를 사용하는 생각을 했을 것인데요. 이런 큐는 항상 앞이나 뒤에서 머무르는 시간이 대부분일테고 (밸런스가 딱 맞기 힘들죠), 그리고 생산자들과 소비자들 쓰레드간에 Lock을 반드시 걸어줘야 할 겁니다. 이 Lock은 생각보다 훨씬 더 속도에 악영향을 미치는데요.
락이 걸리는 순간 컨텍스트 스위칭이 커널에서 발생하며, 프로세서는 캐쉬안에 저장되있는 데이터를 잃어버리기 쉬운 환경이 조성됩니다. 캐시를 보다 잘 보존하기 위해서는 단순합니다. 그저 하나의 코어만 쓰기를 하면 됩니다. (다중읽기는 괜찮지만요) 만약 두개의 쓰레드가 각기 다른 값에 쓰기를 할지라도 서로 다른 캐시라인을 무효화 할 수 있게 됩니다. 이 말은 큐에서 하나는 head 에서 작업하고 하나는 tail에서 작업한다고 할 경우에도 캐시에 문제가 생길 수 있다는 의미입니다.
링버퍼 와 Distruptor
그럼 Distruptor에서는 락을 걸지 않고 어떻게 쓰레드간에 데이터를 주고 받을 수있을까요? 그 키는 링버퍼에 있습니다.
보다시피, 버퍼의 개수는 정해져있으며, 마지막 슬롯이라는 개념이 없습니다. 위 그림상에서 7번이 끝이아니라, 0번버퍼를 다시 8번으로 그래도 재활용(재할당없이)하기 때문입니다. 즉 버퍼를 가르키는 포인터에 대한 인덱스는 버퍼사이즈만큼으로 정해져 있지만, 시퀀스는 무한히 (64 bit signed numbers: 초당 백만건 처리해도 3십만년) 생성됩니다.
하나의 생산자와 하나의 소비자를 대상으로 할 경우 링버퍼에서 일어나는 일은 매우 단순한데요. 생산자와 소비자는 각각 자신의 어디쯤에 있는지만 서로 확인 할 수 있으면, 그 범위 내에서 작업을 하면 되기 때문입니다.
예를들어 생성자가 5번까지 입력했어. 라고 하면 (cursor 위치가 5가 됨) 소비자는 5까지 읽어가면 됩니다.
반대로 생성자는 소비자가 읽은 곳을 넘어가서 입력하면 안되겠지요. (waiting 이 이루어 집니다)
생산자가 여러개 일 경우는 좀 특별하다. 생산자A가 10번 슬롯을 먼저 처리했다고해서, 그 곳까지 소비자가 읽을 순 없게 해야한다. 이유는 또다른 생산자B는 아직 8번슬롯을 처리하지 못했을 수도 있기 때문이다. 따라서 생산자B가 완료 할 때까지 기다려서 생산자 A는 확정 처리 해야한다.
소비자의 경우는 일단 WaitFor 하다가, 이전에 자기가 처리 했던 슬롯위치 +1 의 위치의 값을 가져오는데, 생산자가 입력을 했는지도 확인을 해서 ㅇㅋ 면 값을 가져와서 처리한다. 또한 생산자의 속도가 빨라서 거리가 많이 벌어졌다면, 소비자는 범위를 크게 잡아서 데이터를 가져 갈 수도 있기 때문에, (batching effect) 밸런싱 맞추는것도 쉬워집니다. 주요 단점으로는 소비자가 여럿일 때 하나의 소비자에서 지체현상이 일어난다면, 해당 슬롯이 막혀서 생산자는 더이상 추가를 못하게 되고, 따라서 소비자들도 정체 될 것입니다. 생산자,소비자가 여러개 일 경우 등 좀 더 구체적인 내용에 대한 설명은 다음 세 글을 참고하세요
-> Trish’s post, codeaholics's post, 쭌안아빠님 블로그
또한 리팩토링의 저자이자 패턴계의 스승이신 마틴파울러는 2011년 그의 글에서 LMAX Architecture 이 왜 만들어졌는지에 대한 전반에 대해 말하고 있으며, 블록체인(bitshare)에서 사용된 LMAX Architecture 에 대한 글 링크를 소개합니다.
또한 리팩토링의 저자이자 패턴계의 스승이신 마틴파울러는 2011년 그의 글에서 LMAX Architecture 이 왜 만들어졌는지에 대한 전반에 대해 말하고 있으며, 블록체인(bitshare)에서 사용된 LMAX Architecture 에 대한 글 링크를 소개합니다.
Distruptor 패턴 과 블록체인
마지막으로 다시 블록체인으로 돌아와 보죠.
먼저 EOS,스팀에서 LMAX Architecture 를 통해 얻은 교훈은 아래와 같습니다.
ㅡ 모든것은 메모리에 유지시키자.
ㅡ 코어 비지니스 로직은 무조건 싱글 쓰레드에서 처리한다.
ㅡ 암호화에 관련된 조작들은 (해싱,서명) 코어 비지니스 로직 외부로 꺼낸다.
ㅡ 상태의존적인 검증과 상태독립적인 검증을 나눈다
ㅡ 데이터 모델로 부터 만들어진 객체를 사용한다.
그리고 직접 소스를 살펴보며 적용된 것을 개발자 시각으로 생각해 볼것은 아래와 같습니다.
ㅡ 왜 굳이?
ㅡ 어떻게 구현 해 있나?
ㅡ 개선방안은?
이 있겠으며,
좀 더 넓은 시야에서는
ㅡ 비트코인,이더리움에서는 신뢰의 속도 때문에 Distrupt 패턴이 무의미 한데, 스팀,EOS 는 삐른 대신 대신 신뢰의 속도를 포기 한건지?
ㅡ 어떻게 보면 얄팍하기 까지 보이는 EOS,STEEM 의 신뢰의 속도 처리 방안에 비해 이더리움은 앞으로 어떻게 묵직히 처리 할 것인지.
를 지켜보는 재미가 있다고 볼 수 있습니다.
* 모든 기술에 은탄환은 없으니, Distruptor 패턴도 자신의 상황에 맞춰서 잘 적용하는것이 중요 할 것입니다.
* 이 포스트의 최종목적이 EOS 에서 사용된 LMAX Architecture 해부 인데, 어느정도 분석이 되면 따로 글을 파겠습니다.
레퍼런스:
https://medium.com/corda/transactions-per-second-tps-de3fb55d60e3
http://blog.codeaholics.org/2011/the-disruptor-lock-free-publishing/
https://martinfowler.com/articles/lmax.html
http://goodjoon.tistory.com/254
http://www.smallake.kr/?p=2254
https://www.slideshare.net/trishagee/introduction-to-the-disruptor?next_slideshow=1
http://mechanitis.blogspot.kr/2011/07/dissecting-disruptor-writing-to-ring.html
'블록체인' 카테고리의 다른 글
[이더리움 메모] 스마트 컨트랙트와 비용 (0) | 2018.06.01 |
---|---|
[Ethereum] Node Discovery with Kademlia (1) | 2018.05.18 |
[이더리움] Merkle Patricia Tree (MPT) 를 이해하기 위한 여정 (4) | 2018.05.10 |
[블록체인] 개발자를 위한 블록체인 로드맵 (1) | 2018.04.15 |
[비트코인] Raw Transaction 만들기 (sig 는 어떻게 만들어 지는가?) (0) | 2018.04.07 |