예) 블록체인에서 블록을 받아서 처리하기 

- 명령적

0. 서버에 클라이언트들을 등록하고 초기화 한다. 서버는 현재 running 상태이다. 
1. 입,출력 채널을 초기화하고 시작시킨다. 현재 connected 상태이다. 
2. Recv 이벤트를 event 쓰레드풀의 쓰레드 하나를 얻어서 등록한다.
3. Recv 이벤트를 기다린다. 
4. Recv 이벤트가 오면 읽을 수 있을 만큼 읽어서 버퍼에 저장해 두고, 채널은 다시 이벤트를 기다린다. 
5. Recv 한 데이터가 너무 많으면 버퍼는 자동으로 증가 하고 적으면, 이미 읽은 버퍼의 앞쪽으로 이동해서 채워진다. 
6. 채워진 버퍼는 유저 Handler에 세션정보와 함께 보내진다.
7. 유저는 어떤 세션에서 데이터가 왔는지 확인하고  버퍼에서 데이터를 4바이트 읽어서, 헤더를 확인하고, 바디 부분을 마져 읽는다. 전체 바디가 만들어지지 않을 경우, 상태를 읽고있는 중이라고, 유지하고 중단한다. 
8. 완전한 데이터가 읽혀지면, 블록이라는 객체를 만들어서 User application으로 보낸다. 
9. 블록의 헤더를 확인한다.
10. 블록의 바디를 확인하기 시작한다.
11. 정상포매팅인지 확인한다.
12. 서명이 제대로 됬는지 확인한다.
13. 데이터의 버전 및 커밋 될 수 있는지 확인한다.
14. 데이터를 데이터베이스에 저장한다. 
15, Event Hub에 결과를 알린다.
16. 웹,앱,모니터링 시스템등에 알린다. 

- 선언적

Core application) 
서버 : 서버는 클라이언트로 부터 접근하겠다는 이벤트를 받아서, 세션이라는 이름의 객체로 만들어서 관리합니다. 
세션:  클라이언트를 세션이라고 부르며, 클라이언트의 접속 상태를 관리하고, 입출력 채널을 관리합니다.
채널:  특정 클라이언트를 지칭하는 파일디스크립터를 읽기,쓰기 이벤트로 등록하고, 이벤트를 처리합니다.
버퍼:  버퍼는 바이트 데이터를 관리하는데, 읽을 수 있는 양, 쓸 수 있는 양에 대한 정보도 제공합니다. 
유저 핸들러 :  버퍼를 받아서, 패킷을 어플리케이션 레벨로 재구성 하고, 블록객체를 만든후 User단으로 보냅니다.

User application) 
Application: 블록을 받아서 처리 합니다. 헤더를 분석해서, 구분합니다.
Verifier : 서명을 확인합니다.
Committer : 데이터의 버전 및 커밋 가능성을 데이터베이스를 통해서 검증하고 저장합니다.
Notifier : 해당 블록처리에 관한 결과를 이벤트 허브에 전송합니다. 
EventHub: 웹,앱,모니터링시스템등 여러 단말 으로 보내 줍니다.


대게 복잡도는 단순하게 할 수 없다고 합니다. (쉬운 알고리즘으로 대체 가능한 일부 제외하고) 비지니스 로직적으로는 애초에 상태가 무지 많아지기 때문에 대부분 복잡도는 대개 구성원이 모두 익숙해지거나, 더 직관적인 아키텍쳐로 바꿔야 하는 방법뿐인데요. 보통 선언적으로 프로그래밍을 하면 유지/관리에 좋다고 합니다. 위에서 언급한 명령적/선언적 예는 좀 오버를 한거이구요. 사실 "for문으로 돌리면서 이렇게, 저렇게 한다" 를 map은 전체요소를 일률적으로 변경시킨다. fillter는 일부요소를 제거한다. reduce는 개개의 요소를 하나로 묶는다. 등등의 한단계 위의 추상화된 요소들로 선언하죠. 다음 글에는 위의 예제(상태가 굉장히 복잡한데, 매우 단순화 시켜 놓음) 중 일부를 하나는 Observer or Listener or Handler 식으로 코딩하고, 하나는 FRP (함수형 기반의 반응형 파라다임) 식으로 코딩해서 비교해보도록 하겠습니다. 

 

한국에선 Go가 1등, 세계적으론 Rust가 1등 - 사랑하고 배우고 싶은 언어 

 

1. 시작하면서

언어에 대한 벤치마크에 있어서 보편적, 절대적이란것은 없으며, 팀의 숙련도, 제품의 특징등에 따라서 성능/개발속도는 천차만별 일 것이다. 이 포스트는 그 동안 블록체인 연구만 하느라 잊어버린 코더라는 나의 정체성을 일 깨우고, 각 언어에 대해서 일단 빠른 시간내에 손가는 대로 만들면 어떻게 되는지 재미로 만든 것이며, 옵티마이징에 대한 부분은 전혀 신경 쓰지 않았기 때문에 객관적 지표로 삼을 수는 없을 것이다. 특히 CPU점유율 같은건 신경도 안썼다. 락을 안걸고 CPU 펌핑시키면 성능은 엄청 올라 간다. (참고로 코드 품질은 안드로메다) 이 벤치마크는 주로 생산자-소비자 패턴에 대한 테스트이며, 쓰레드끼리 데이터를 주고 받는 과정을 시뮬레이션 하였다. 현재 Future등을 통한 비동기 행위는 없으며 sequential(blocking)하게 통신이 이루어 진다. 

2. 벤치마크를 위한 심플 프로젝트

하이퍼레저 패브릭이라는 허가형 블록체인 시스템의 미니멀 버전으로써 코드의 주요 흐름은 2가지가 있는데 

1. 장부에 쓰기
   1-1. endorser들에게 보증 받기  <--- 벤치마크는 이 부분에서만 
   1-2. orderer/committer에게 값 보내서 영구저장 시키기
2. 장부에서 읽기

아래에 모듈간의 흐름을 그려보았다.

 

 

쓰기 순서

브라우저에서 신용장을 만들고 싶어서 해당 데이터를 백엔드로 보내고, 벡엔드에서는 하이퍼레저 패브릭 시스템과 통신할 수 있는 SDK를 호출 한다. 이 부분이 코드에서 미들웨어이다.

1. 미들웨어는 Endorsing Peer들에게 트랜잭션(Proposal request)을 요청함
2. Endorsing Peer 들은 해당 트랜잭션에 대한 체인코드를 호출하여 실행하고 결과값(RWSet)을 미들웨어로 돌려줌
3. 미들웨어는 RWSet을 받아서 보증에 대한 확인후 이상없으면 Orderer에 RWSet을 보낸다.
4. Orderer들은 받은 트랜잭션을  Kafka의 채널에 Push하고 , Pull 하여 정렬.
5. Orderer는 정렬된 트랜잭션 모음을 받아서 블록으로 가공.
6. 가공된 블록을 Commit Peer로 보내고
7. Commit Peer는 블록을 검증하고 Ledger (Blockchain + State Storage)에 저장.

 

 

읽기 순서
브라우저에서 신용장을 읽고 싶어서 백엔드로 요청. 벡엔드에서는 하이퍼레저 패브릭 시스템과 통신할 수 있는 SDK를 호출.

1. 미들웨어는 Commiting Peer에게 트랜잭션을 요청함
2. Commit Peer는 Ledger (State Storage)에서 정보를 가져온다.
3. 미들웨어(클라이언트)에 반납.

3. 결과

언어 성능 개발기간 개인적 언어 사용기간  요약   
Go 1.14  1(1)  1일 1년   x나 빠르네 (역시 성능 테스트는 뭘 하냐에 의존한다. b tree 같은거 하면 다를듯)
C++ 17 12 (4.2) 3일 13년 unique_lock과 condition을 직접 사용하여 concurrent queue를 만들어서 구현함. C++경력이 제일 길지만 중간에 멀리 했다 다시 하면서 디버깅하는데 애를 먹었다.  C++의 동시성 지원은 모던 C++ (11버전 이후) 들어서, 자바의 메모리모델을 참고하여 메모리 모델도 생기고, Thread, Lock도 생기는 등 뒤늦게나마  지원하기 시작했으며 C++20 를 통해 거의 완성 될 것으로 보이지만 역시 신세대 언어들에 비해 모듈 관리 편의성 및 유틸리티류가 부족.. 크로스플랫폼으로 가면...웬만한 경험치가 아니고선 후.. 
Java 11 1.6 (2) 1일 1년 lock과 condition도 사용하였으며, 의도적으로 LinkedBlockingQueue(블로킹) 과 concurrentLinkedList(비동기)를 혼합하여 사용하였다. java는 옛날 1.5버전부터 끝내주는 동시성 라이브러리를 많이 제공해 주고 있기 때문에 이것 저것 해볼게 많다. 
Scala 2.12 9.8(1.2) 2일 1년 akka의 actor패턴을 사용하여 구현하였다. go루틴/채널이 기본적인 것들만 지원하는것에 비해 정말 많은 것들을 지원해주고 있으며, 그 만큼 복잡하다. 양면의 칼!! 오랜만에 사용하다보니 삽질을 꽤나 했다. 
Rust  1.31 3.2(4.2) 3일 2주일 C++처럼 직접 동시성 큐를 만들려다가 채널라이브러리를 확인하고 go처럼 채널을 이용해서 만들어 보았다. 채널에는 std::sync::mpsc를 확장한 cossbeam::channel을 이용하였다. 참로로 이 채널은 Go와 다르게 recv시 블로킹을 하지 않는다. C++과 다르게 개발 편의 라이브러리가 대부분 존재 하고 Cargo덕분에 모듈관리편의성이 엄청 편해졌다. 물론 코딩하는 동안에 러스트의 러닝커브를 높이는 주범인 강제성 있는 소유권 문제, 라이프타임 문제등에 대한 에러가 당황스러웠으며 분석하고 수정하는데 애먹었다. 
Node 12.16 N/A(4.1) 1일 1개월 Since the release of Node.js v10.5.0, there’s a new worker_threads module available, and it has been stable since Node.js v12 LTS. There is a Message Channel that is a simple communication channel. It has two ends, which are called ‘ports’. In JavaScript/NodeJS terminology, two ends of a Message Channel are just called ‘port1' and ‘port2'.
Python 3.7 1000+(13) 1일 2년  Performance of this kind of pattern is very slow as i expected(GIL).  I think Python has to be only used like as asyncIO
Elixir 1.10.2  1.8(13) 1일 2일 Elixir is a dynamic, functional language Based on Green Thread, Actor model.
Actor communication is very fast but tail recursive optimization is not good.

* 성능은 낮을 수록 좋음 (100만 트랜잭션 처리 시간 기준)
* 사용기간이란 해당 언어를 사용(스터디, 쓰기,읽기) 해본 필자의 경력기간 
* 성능 괄호안은 Integer to String 변환 (32,000,000번 반복)
* rust, elixir, python, node is partially completed

4. 언어 별 썰을 풀어 보자면 

(Just my emotional criticize in some part but may be changed in future) 

C++
러스트와 다르게 메모리를 스마트하게 다루어도 되고,안 해도 되니 문제가 생길 수 밖에 없다. 개발자에게 자유를 준다. 망할 자유를... 즉 윈도우즈 버그의 70%이상이 메모리,동시성 문제. C++은 이제 이전에 레거시로 존재하는 것만 유지보수하고, 일반 서버솔루션에서는 Rust로도 시도를 해보는게 어떨 까 한다. 모던C++을 충실히 이해하는 당신은 비교적 무난하게 이동할 수 있다.(2022년에는 구글에서 C++개발자를 위한 새로운 언어인 카본이 등장한다. 코틀린이 자바개발자에게 그러하듯이 카본은 C++개발자에게 러스트보다 훨씬 더 상호호환성이 좋고 친숙하게 만들어졌다.) 혹시 자신은 C++ 버그 만드는 공장장이 아니라고 생각하나? 그럴 가망성이 없지만 믿어드린다. 다만 자신의 팀원들도 그럴까? 

@ 아직 아기인 Rust도 좀 더 떳으면 하는 마음에서 C++ 살짝 비판을 했지만 사실 나는 C++에 애증이 크다. (20년 개발자 인생중 13년을 C++을 했다) 따라서 이런 의견도 링크 해 드린다 : Rust 언어 비판과 C++이 사라지지 않을 이유 

아시다시피 모든 언어는 트레이드 오프가 있으니 무작정 하나를 깍아 내리지 말고 각 언어의 장점과 재미요소에 집중하는편이 좋다.

 

Criticizing the Rust Language, and Why C/C++ Will Never Die

We liked the article "Criticizing the Rust Language, and Why C/C++ Will Never Die" very much. We offer the author that we will do the translation on our own, and publish it in our blog. He agreed, and we represent this article in Russian and English with g

www.viva64.com

 

Java

자바로 코딩하면 제일 먼저 드는 생각은 모든 면에서 적당하다라는 느낌? 과한거 같기도 하고 ㅎㅎ 세계에서 제일 많이 사용되는 언어로 (특히 백엔드) 오랫동안 군림 할 수 있었던 여유와 안정성이 느껴진다. 특히 더그 리 덕분인지 동시성 지원 구성요소들이 잘 정리되어 있다. 2000년대 중반 부터 자바하면 다른 신생언어가 추종하는 성능 표준이 됬을 만큼 성능도 훌륭하다. (즉 이 정도 성능이면 웬만한 곳에서는 다 무리 없이 사용 가능) 편의성 + 성능 모두 대체적으로 만족 스럽다. 단 한가지 가벼운 쓰레드가 없는건 많이 아쉽다. 이 점 및 많은 부분에서 자바와 상호호환성이 좋은 코틀린은 정말 강력한 자바의 후계자 위치를 차지할 것 같다. 나도 코틀린으로 갈아탔고.

@ 자바와 코틀린의 가벼운 쓰레드 이야기는 여기 참고-> https://www.baeldung.com/kotlin/java-kotlin-lightweight-concurrency

String.valueOf(i)
* 자바와 스칼라에서 숫자 -> String 변환시 속도 차이가 약 2배나 차이나는데, 왜 그런지 누가 분석 해서 알려 주시면 좋겠다.

Go
절대로 Go로 하면 안되는게 아니고서는 (그런게 있을 확률도 희박, 가비지컬렉터 문제는 최신버전에서는 정말 더 좋아졌다.웬만하면 월드스탑 핑계는 대지말자) 즉 대부분의 프로젝트에서는 Go를 사용하자고 오버해서 말하고 싶다. 무엇을 하냐에 따라 달라지겠지만 최고의 전문가들로만 이루어진 팀이 아니라면 러스트,C++이 Go보다 성능이 더 좋을지도 의문사항이다. 다만 언어가 자유롭고 단순한 만큼 추상화 시키면 (특히 덕타이핑) 오히려 가독성이 많이 떨어지며 , 안전성은 러스트,스칼라에 비해 떨어지고, 스탠다드 라이브러리가 화려한 자바에 비해서는 기능이 빈약하긴 하다. 그럼에도 불구하고 서버개발의 첫번째 선택지로 두고 싶다. 한국에선 백엔드 개발에 있어서 스프링,노드가 디폴트이므로 직장을 찾는 주니어에겐 비추한다. 코틀린 굿!!

Rust
자신이 C++개발자인데, C++2X 버전들어서 RAII가 강제되고, Uniqued_ptr, move가 디폴트가 되었으며, Shared_ptr가 좀 더 세분화되어 강제되었다고 생각 해보자. 게다가 스칼라 같은 패턴 매칭 및 적절한 함수형 스타일 첨가와 Go처럼 클래스 없이 struct + traits의 덕타이핑 스타일로 변화 되었다고 하자. 그것이 Rust이다. 순수함수형 스타일이 아닌 언어로 멀티코어 프로그래밍을 할 때 얼마나 주의를 기울여야 안전한 솔루션이 나올 수 있는지에 대한 철저한 교과서이다. 즉 C++ 및 다른 언어로 개발 할 경우, 이 만큼의 주의를 기울이지 않을 가망성이 크기 때문에 버그가 끊임없이 생겨 난다는 얘기. C++은 자유(방관)를 주는 언어이고, 자바는 (최소한만) 알아서 챙겨주는 언어라면 러스트는 채찍들고 서방님을 최고의 장군으로 만들기 위해 맹훈련시키는 평강공주같은 스타일이다. 따라서 대중화 되기는 요원할 거 같다. 라이프타임의 책임이 컴파일러 제작사보다 너무 사용자에게 전가되어 있다. 대중은 쉬운길로 간다. 다만 팀원을 신뢰하게 만들고 성능이 최우선사항이며 사람목숨이나 큰 돈이 오가는곳에 C++,Go 대신해 쓰여 질 만하다. (근데 최근 스페이스X에는 일론 머스크가  C++를 욕하고도 결국 C++를 사용) 수년간 블록체인 분야에서 일하고 있는데 이쪽 분야가 비교적 Rust를 잘 사용한다. go에 비해 쓰레드가 무겁다는 것은 아쉽다.  green thread의 단점으로 의도적으로 제거했다고 하는데..태생이 시스템 언어라 green 쓰레드는 보통 VM기반에서 돌아가기 때문. 뭐 서드파티로 나오겠지..(rust goroutine equivalent golang -> https://github.com/Xudong-Huang/may)

Elixir 
Go에는 멀티코어 사용시에 mutable 사용이 너무 자유로우며 채널을 통한 메모리 공유로 안심하다가 뒤통수 맞을 가능성도 크다.(물론 심플하니깐 문제점 찾기도 비교적 쉬울 듯?)  Scala + akka 도 무거운데다가 구현하기 나름이지만 강제하지 않기 때문에 결국 비슷해보이고... Rust는 너무 복잡하게 관리를 유도하고...이런 전차로 벤치마크 리스트에 (비교적) 순수함수형 언어도 없고 해서 아무것도 모르지만 일단  Elixir를 구현해봤다. 안전성, 심플코딩이야 특유의 장점 인건 알겠는데 ...개빠르기 까지 하네?  Elixir is a dynamic, functional language Based on Green Thread, Actor model

 

 

5. 구현 코드

Go: https://github.com/wowlsh93/hyperledger-fabric-400

 

wowlsh93/hyperledger-fabric-400

hyperledger fabric in less than 400 lines of Go. Contribute to wowlsh93/hyperledger-fabric-400 development by creating an account on GitHub.

github.com

Elixir : https://github.com/wowlsh93/hyperledger-fabric-400-elixir
Scala:  https://github.com/wowlsh93/hyperledger-fabric-400-scala
Java:  https://github.com/wowlsh93/hyperledger-fabric-400-java
Rust :  https://github.com/wowlsh93/hyperledger-fabric-400-Rust 
C++:  https://github.com/wowlsh93/hyperledger-fabric-400-CPP  
Python: https://github.com/wowlsh93/hyperledger-fabric-400-python

6. 마무리

테크니컬 포스트라기 보다는 주관적 수필 같은 느낌의 코딩 작업과 글이 었습니다. 코드는 계속 수정 보완 될 것이며  실제 프로덕트에서는 Lock free 및 object copy관점에서 많은 최적화가 이루어 질 수 있을 것인데 언어별 문제점 및 동시성 최적화 후의 변화에 대해서는 (백수가 되면) 2편에서 다루어 볼 생각입니다. 

'소프트웨어 사색' 카테고리의 다른 글

Rust  (0) 2020.06.16
소프트웨어 복잡도 줄이기 (1)  (0) 2020.05.13
소프트웨어 아키텍트란  (0) 2019.12.11
'망할' 에이콘 출판사  (2) 2019.04.16
개발자 면접 방식을 바꾸자  (2) 2019.04.12

기사) https://www.samsungsds.com/global/ko/about/news/nexledger-accelerator.html

 

삼성SDS, 블록체인 가속 기술 발표

삼성SDS(대표 홍원표)는 14일 미국 샌프란시스코에서 열리고 있는 IBM의 연례 기술 컨퍼런스인 ‘IBM Think 2019’에서 블록체인 가속 기술을 발표한다.

www.samsungsds.com

Github) https://github.com/nexledger/accelerator


핵심아이디어는 개별 트랜잭션들을 묶어서 처리하는 것인데, 이로 인해서 개별 트랜잭션 부하를 배치로 묶어서 하나로 줄일 수 있게 되면서 네트워킹 부하 뿐 만 아니라 서명확인에 따른 부하까지도 줄일 수 있습니다. 하지만 

                               ( 그림1: 화물차에 사과를 1개만 보내는 농부를 가정하고 만든 accelerator) 

러프하게 보면 Nexledger의 acclerator의 경우는 클라이언트가 하나로 보낸다는 가정하에, (그림에서 보면 농부는 화물차에 사과 1개만 보낸다고 가정하는데 어떤 농부가 그럴까?)  그걸 대신 모아서 체인코드 함수를 for문을 돌면서 처리해 주는 방식입니다. 

근데 생각해보면 체인코드를 배열로 받으면 그러한 함수콜에 의한 부하도 줄일 수 있게 되는데 굳이 그런식으로 사용 할 필요가 없는 것 입니다. 즉 클라이언트 코드와 체인코드에서 제대로 개발하면 발생하지 않을 수 있는 부하인데 굳이 Nexledger의 acclerator를 쓸 필요가 있을 지 고민해 봐야 하는 문제. 

문제점으로 판단되는 5가지 이슈를 정리 해 봤습니다. 

  • Who deliver paramater one by one like that
  • SDS focused on only stupid situation. Concept of SDS is redundant in normal case
  • Each DApp may need a different delivery strategy for efficiency. SDS couldn’t adapt to all
  • There will be security concerns. In case that all data have to go through SDS and sign by SDS instead of Real owner.
  • To Network, Each Tx is just from one Owner (It's SDS)


이번 포스트에서는 하이퍼레저 패브릭에 관련된 기술중에 가장 알려지지 않은 주제인 Recovery에 대해서 다룬다. (그냥 링크로 무임승차지만;;;; 쏘오뤼~) 오랜시간 동안 네트워크가 작동하다보면 분산 노드들 간에 일관성에 관하여 문제가 생길 수 밖에 없기 때문에, (디스크 오류등 각종 예기치 못한 상황으로) 이를 회복시켜주는 기술이 패브릭에도 필요한데..

보통 일관성이 깨지는 곳은 스토리지에 무엇인가를 쓸 때이고 보통 하이퍼레저 패브릭에서는 committer 노드에서 일어난다. 좀 더 자세히 설명해 보면 orderer로 부터 받아온 블록을 가지고 해당 블록안에 있는 트랜잭션들을 VSCC, MVCC등의 다양한 방식으로 검증 한후에, 이상이 없으면, A) 블록체인을 업데이트하고 B) 상태DB도 업데이트 하고  C) 히스토리DB도 업데이트 한다. 이렇게 모두 잘 마무리 되면 모든 노드의 저장 상태는 동일하게 되는데 ( 물론 채널과 Private Data에 따라서 달라지는 부분 제외하고)

이때, VSCC, MVCC 중에 문제가 생겼을 경우에는 저장 과정에 돌입하지 않고 그냥 리턴해 버리기 때문에, 특별한 Recovery 과정이 필요 없지만, (그냥 가쉽을 통해 블록을 가져와서 다시 VSCC 부터 시작하면 되니까), A) 블록체인을 업데이트하고 B) 상태DB를 업데이트 하는 도중에 문제가 생겼을 경우에는 특별한 조치를 취해야 한다. 또한 과연 내가 가지고 있는 상태DB가 옳은것인지 체크하는 것과 최신 상태DB의 옳음을 합의 하는 방식 그리고 어떤 체크포인트까지 상태DB가 옳은 것으로 판명됬을 경우, 그 때 까지의 블록체인을 삭제하여 공간 활용성을 높히는 것에 대해서 알아야 할 필요가 있다. 

아래 링크는 그런 내용에 관해 좀 더 친절히 설명하며, 고민도 공유하고 있으니, 관심 있는 분들은 참고 하길 바란다.  

 

Checkpointing for Efficient Blockchain Platform -- Hyperledger Fabric

A blog about blockchain and various platforms such as Hyperledger Fabric, Quorum, Ethereum, and Corda.

www.bchainledger.com

http://www.bchainledger.com/2018/05/failure-and-recovery-of-statedb-in.html

 

Failure and Recovery of StateDB in Hyperledger Fabric v1.1

A blog about blockchain and various platforms such as Hyperledger Fabric, Quorum, Ethereum, and Corda.

www.bchainledger.com

http://www.bchainledger.com/2019/12/fork-detection-and-rollback-in.html

 

Fork Detection and Rollback In Hyperledger Fabric

A blog about blockchain and various platforms such as Hyperledger Fabric, Quorum, Ethereum, and Corda.

www.bchainledger.com


페이스북 :  엔터프라이즈 블록체인 그룹 


어차피,마침, 혹시, 굳이,김에 ,~바연, 차라리,이왕,애초에, 반면, 커녕, 구태여, 딱히, 하긴 .. 외국인 직원들과 토론할 때 머리속에 애꿋게도 먼저 떠오르는 단어들...영어로 치환 마져 바로 안되서 대락 난감...ㅜㅜ

이번기회에 정리 해보기로 했다. Let's go 


어차피 : anyway

어차피 지워질 데이터이기 때문에 여기서 처리 할 필요가 없다.
There is no need to process it here because it is data that will be erased anyway.

마침 : No english, happend to , just , exactly

마침 가진 돈이 없어요.

I happen to have no money with me
마침 새 서버가 도착했습니다.
A new server just arrived.
마침 탐지 기능이 작동 중이네요.
It just happened that the detection function was working.

혹시: No english, happend to , by any chance, don't suppose

혹시 ~~ 를 알고 있어요?

Do you happend to know that ~~~
혹시, 우리 얘기 좀 할 수 있을까요?
I was wondering if we could talk
혹히, 한국어 할 줄 아세요?
Do you by any chance speak korean?
혹시, 펜 좀 빌릴 수 있을까요?
I don't suppose I could borrow your pen?

굳이: No english , go out of one's way

굳이 내가 꼭 가야만 하나요?

Do I really have to go?
이 방법으로만 꼭 할 필요가 있나요?
Do I absolutely have to do it this way?
내가 좋아 하지 않는 음식을 굳이 먹진 않어.
I don't go out of my way, to eat healthy food that i don't like

~김에 : No english , while you are out, on your way out

나간김에 코드 연장선 좀 사다 줄래?

While you are out , could you pick up an extension cord for me?

~바엔: No english, rather

나중에 지울 바엔 여기서 지우는게 낫지.

I'd rather erase it right here than erase it later

차라리 : No english, would rater

난 차라리 네가 이것을 했으면 좋겠다.

I 'd rather you do this.

이왕 : No english, might as well

이왕 뭐 살거 있으면, 우리 그냥 같이 가자.
If you have some thing to buy, we might as well just go together

애초에: No english,  to begin with , in the first place

애초에 내가 실수를 했어.
I made some mistakes, to begin with.
애초에 내가 확인을 제대로 안했어.
I didn’t check properly in the first place.
처음에는 좀 어색했어.
At first it was a little awkward.
걔가 날 먼저 때렸어.
He hit me first.
나 면허 따고 처음으로 혼자 운전했어.
I drove by myself for the first time since I got my driver’s license.

반면: on the other hand.

이 차는 비싼 반면에, 매우 실용적이다.

This car is expensive , on the other hand , it is useful for me.
가격 치고는 꽤 맛있다.
Considering price , it 's good.

커녕: on the contrary

재밌긴 커녕 끔직했어.

On the contrary, It was terrible

딱히: No engish , No words, Particularly
딱히 할말이 없네
I have nothing left to say
딱히 문제가 있었다기 보다는...
There wasn't Particularly a problem

하긴..: No english, true
That's true. 

'잡동사니' 카테고리의 다른 글

산업용 전기요금 상식  (0) 2018.02.01

사실 Leader election 은 가장 단순하게는 주변 노드들의 이름을 리스트로 가지고 있다가, 이름 순으로 그 다음 노드가 그냥 리더가 되는 느낌으로 구현하면 매우 단순하긴 한데, (Distributed Systems 책들에 소개되는 수준의 Bully algorithm, Ring algorithm 등은 실용적으로 사용하기에는 다소 심플하다.) Split brain 때문에 Term(epoch) 단위 동안에 가장 다수의 투표를 받은 노드가 선출되는등의 기술(?) 이 들어가며 복잡해지곤 하며...문제를 완벽히 해결하기가 쉽지는 않다. 아래 글에서는 하이퍼레저 패브릭상에서 발생되는 2가지 주요 분산합의 상황에서의 리더 선출에 관해 대략적으로 끄젹 꺼려 보겠다. 

* 이 문서는 앞으로 실제 패브릭 구현 상에서의 알고리즘으로 꾸준하게 수정 될 예정이다.

Gossip Protocol 


(gossip protocol 은 주변에 랜덤하게 자신이 가진 최신 정보를 뿌려주고, 랜덤으로 선택된 피어에게 최신 정보를 요청하는 주로 push-pull 모델을 이용하여 전체 네트워크의 상태를 일치시키는 알고리즘이다. 이때 최신정보는 항상 리더로 부터 시작된다. 리드 선출에 관해 공개된 상세한 정보는 없으며, 코드를 봐야 이해 할 수 있다. 공식문서에는 그냥 static으로 설정하거나 dynamic으로 설정 할 수 있다 정도~)

- 상태는 Leader , Follower 2가지이다.
- ID 문자열의 사전상 순서로 우선순위를 가진다. 
- term id , epoch id 란 개념이 없다. 
- 하나의 membership view에서는 하나의 리더를 가진다.
- 네트워크가 분리되면 분리 된 수 만큼 리더를 가지며, (각자 orderer에게 블록 요청) 합쳐지면 하나로 돌아 온다.
- Leadership declaration (내가 리더다) 와 Proposal (내가 리더가 되고 싶어) 메세지가 있다. 
- Leadership declaration (내가 리더다) 를 주기적으로 보내며, 이것을 못받은 Follower는 리더선출에 돌입하며, 이렇게 네트워크는 분리된다..나중에 더 낮은 ID를 가진 노드에서 Leadership declaration 받게되면 리더 자리를 물러나게 되며 자연스럽게 네트워크는 합쳐진다.

 Startup():
 	wait for membership view to stabilize, or for a leadership declaration is received
      or the startup timeout expires.
	goto SteadyState()

// 3 possible ways to stabilize
//   - After a period of time, check whether the number of peer lists before and after is consistent.
//     if they are consistent, it indicates stability.
//   - If a leader is elected, it's also stable
//   - Otherwise if timeout, consider it stable and vote for new leader from proposal set


 SteadyState():
 	while true:
		If leaderKnown is false:
 			LeaderElection()
		If you are the leader:
			Broadcast leadership declaration
			If a leadership declaration was received from
 			a peer with a lower ID,
			become a follower
		Else, you're a follower:
			If haven't received a leadership declaration within
 			a time threshold:
				set leaderKnown to false

 LeaderElection():
 	Gossip leadership proposal message
	Collect messages from other peers sent within a time period
	If received a leadership declaration:
		return
	Iterate over all proposal messages collected.
 	If a proposal message from a peer with an ID lower
 	than yourself was received, return.
	Else, declare yourself a leader

 

RAFT


RAFT도 위와 조금 비슷하긴 한데 차이점은 우선순위(ID문자열 기준)가 없고, Term (epoch) 이라는 1씩 증가하는 공통적으로 공유하는 상태가 있으며 Candidate 상태가 추가 되었다. 특히 RAFT은 Gossip에 비해 split brain 문제를 방어하기 위해서 좀 더 복잡 한 면이 있으며, 리드선출 기간이 피어마다 랜덤하게 설정되서 먼저 자기를 투표해 달라고 하는 놈이 있으면 그 놈에게 그냥 투표해 주기 때문에 결국 그 피어가 리더가 될 확률이 높아진다. 과반수로 부터 표를 받으면 자기가 리더인것을 확정짓고 리더로써의 하트비트를 날려 주게 된다. 만약 운이 안좋아서 비슷한 시간에 2개의 피어가 후보자가 될 경우, 표를 과반 수 이상 못받으면 다음 Term으로 넘어간다. 즉 split brain이 발생하지 않는다. (비잔틴은 없다라고 가정한다) 

두가지 타임아웃이 있다:  heartbeat timeout (리더), election timeout (팔로워) heartbeat타임아웃은 election timeout보다 주기가 짧아야한다. election timeout은 그보다 큰 제한하에  각 노드별로 랜덤값 

1. When is it started 

     - 리더로 부터 정해진 시간안에
       정식 메세지 , 하트비트 ,  candidate 로 부터의 vote 메세지중 아무것도 못받은 경우   


2. How to elect leader 

     -  리더로 부터 아무것도 못받은 각 못받은 노드는 자신의 election timeout (노드별 랜덤) 이 발생하면 상태를 candidate로 변경하고 term + 1하고 스스로에게 투표한후 나머지 follower들에게 투표를 요청 한다.
     -  election timeout  이 발생되지 않은 follow 노드는 투표를 해 준다. ( 동일 term에 한해 1표, Candidate는 다른 Candidate에게 투표 안함) 
     - follower는 투표해주고 election timeout을 리셋한다. (term도 갱신된다) 
     - 과반수의 투표를 받으면 상태를 leader로 바꾸고 리더 역할을 한다. 
     - 과반수를 못받으면 다시 투표를 요청한다.
     - election timeout이 거의 비슷한 노드가 동시에 candidate 되었을 경우 발생 할 수 있는 split brain 에서 과반수를 받은 candidate가 없어서 leader가 선출이 안됬을 경우, re election을 진행해서 랜덤하게 새로 정해진 (term 마다 항상 새로 선정됨) election timeout을 기반으로 다시 leader 선출을 진행한다. 이때 follower 중 하나가 election timeout이 빨리 도달하면, 기존 candidate를 재치고 term+1을 통해 리더가 될 수도 있다. 
     - term이 높은 메세지가 오면 follower로 돌아간다. 

http://thesecretlivesofdata.com/raft/
 
리더 선출에 대한 간단히 표로 정리 해보았다.

 

 

페이스북 :  엔터프라이즈 블록체인 그룹 

 

 

PBFT (Practical Byzantine Fault Tolerance)

BFT는 분산된 노드들간에 동일한 상태를 유지하기 위한 방식으로, 악의적인 노드가 있는 것을 전제로 합니다. 여기서 악의적인 노드의 최대수는 N = 3f+1입니다.

N : 전체노드 개수 
f   : 악의적인 노드 개수 

따라서 4개의 노드에서는 1개는 악의적인 노드라도 생관없다는 의미입니다. 7개노드에서는 최대 2개.아래 이미지에서는 4개의 노드에서 최대1개의 비잔틴(악의적노드)가 있다고 치고 합의 단계에 대해 설명해보면 

Request 단계

클라이언트는 상태변경을 위한 요청 (REQUEST, o, t, c)sc 을 대표 노드에 보냅니다. 참고로 이 대표노드(Primary) 또한 비잔틴이 될 수 있으며 그땐 새로운 대표노드를 선출 하게 됩니다.

Pre-Prepare 단계

대표노드는 다른 모든 노드들에게 ((PRE-PREPARE, v, n, d)sp, m)이라는 메세지를 전파합니다.
이 상태에서는 최신상태를 일단 가지고 있게 됩니다만 이게 옳은 것인지는 판단 할 수 없습니다.
그리고 n은 순서를 나타내는데 오더링에 대한 합의를 한다고 볼 수 있습니다. 
 

Prepare 단계

 자신이 받은 최신 상태정보를 기반으로 (PREPARE, v, n, d, i)si라는 메세지를 클러스터 내의 모든 노드들에게  전파합니다. 여기서 다른 노드들의 PREPARE 메세지 2f를 받으면, Prepared가 되서 넘어갑니다. 이 단계에서는 오더링을 확신하게 되고 커밋 준비를 할 수 있게 됩니다. 근데 여기서 다시 봐야하는 부분이 2f인데요, 자기 빼고 3개중에 2개의 연락만 받으면 ㅇㅋ 라는 겁니다. 즉 나머지 1개가 비잔틴이건 아니건 상관없는거죠. 비잔틴은 아니지만 그 놈은 좀 헤롱헤롱 대서 처리가 좀 늦는다. 이 놈이 Primary가 된다면? 또한 PBFT를 접한 사람들이 가장 궁금하게 생각하는게 나오는데 , 바로 이 지점에서 클라이언트에게 리턴하면 왜 안되냐는 거죠. 어느 정도 합의를 이끌어 냈잖습니까? 이런 부분들에 대해서는 각자도생하는것으로 합시다. 하나씩 그려보면 안되는 경우를 도출해 낼 수 있을 겁니다. (합의에 3단계가 필요한 이유

Commit 단계

위에서 PREPARE 메세지 2f를 받으면,  (Commit, v, n, D(m), i)si라는 메세지를 전파할 수 있게 됩니다. 그리고 다른 노드들로 부터 Commit메세지를 받아서 자기포함 2f+1개(논문12p)를 받으면 커밋합니다. 

Reply 단계

                 

Commit 검증에 성공한 노드들은 클라이언트에게 응답을 보내주고 f+1개(논문8p) 이상의 똑같은 응답

을 받으면 클라이언트는 보낸 메세지가 성공적으로 분산노드들의 상태를 변경을 했다는 것을 인지합니다. 이런 합의 로직 이외에도 대표노드를 바꾸기 위한 view change,  메세지 prunning을 위한 checkpoint (watermark) 등에 관련된 내용이 있습니다.

간략히 아래와 같은 도식으로 이해 하실 수 있습니다. (PBFT 논문과는 다르게 Client는 모든 노드에게 메세지를 전달합니다. 이는 Primary가 헛수고 하는 것을 막기 위함으로 자신이 받았는데도 불구하고 Primary 로 부터 Pre-Prepare 메세지가 안날라오는 경우를 대비하기 위함입니다) 



아래부터는 블록체인 계에서 사용하는 PBFT 계열의 합의에 대한 간략한 소개 입니다.


Tendermint

사실상 아래 나오는 모든 알고리즘들의 부모격으로써 PoW 말고 PBFT를 이용하여 블록체인을 구성하기 위해서 처음 등장한 개념으로, 무허가형의 지분증명(PoS)기반의 보안 메커니즘에서 수백개의 노드로 활장 할 수 있는 BFT 기반의 프로토콜로써, 

소규모로 구성된 노드들말고 WAN용 광역네트워크에서도 PBFT를 활용할 수 있게 연구하였습니다. 

텐더민트에 관련된 글을 보면 항상 나오는 그림으로써, 위의 PBFT 글을 읽었다면 간단히 이해 할 수 있는 내용입니다. 녹색박스를 보면 Propose -> Pre-Prepare, Prevote Block -> Prepare , Precommit Block -> Commit 와 매칭됨을 알 수 있습니다. 그리고 

아래를 보면 PBFT에 대한 껄쩍지근했던 궁금증을 쉽게 해소 할 수 있습니다.

텐더민트 합의에 3단계가 필요한 이유
텐더민트 합의에 락이 필요한 이유


* Tendermint 에서 대표node 들을 어떻게 선출하는지에 관해서는 조사 안함.  

NCCU BFT

 대만의 Chengchi University 블록체인 그룹에서 텐더민트에서 영감을 받아 만든 프로젝트로써, 이더리움의 합의를 BFT를 통해서 하는 허가형 향으로 변경하기 위한 프로젝트입니다. 메세지로써 블록이 노드들에게 전달되며, 커밋 페이즈에서 블록(트랜잭션)은 실행되고 Insert 되게 됩니다. 




Hyperledger Fabric - SIEVE

PBFT에 체인코드 실행과정과 블록커밋 과정이 제일 앞단과 마지막 커밋 구간에 포함된 것입니다.  
이 얘기는 1.0 이후의 E-O-V 모델을 떠올릴만 한데. 즉 Endorsing 과정이 앞에 선두에 있으며, 그 과정이 끝나면 PBFT를 시작하고 마지막에 커밋한다는 것입니다. 이것은 Full Go언어 기반의 체인코드가 비결정적으로 실행 할 수 있다는 이야기인데, 앞에서 거를 수 있기 때문입니다. 

 

Hyperledger Fabric - Simple BFT 

하이퍼레저가 1.0에서 PBFT를 버리고, 카프카 기반으로 오더링 시스템으로 변한 후에도 패브릭 측은 BFT에 대한 추가 모듈을 개발하는것에 대한 끈은 놓지 않고 있습니다. 일례로 2.0에서 나올 예정인 RAFT도 결국 BFT를 위한 기반이라고 말하고 있는 정도니... (굳이 외부시스템(카프카,주키퍼)를 사용 할 필요없이) 위의 링크의 Simple BFT는 그러한 패브릭이 BFT을 이러한식으로 만들겠다라는 짧은 설계 방향에 대해서 서술해 놓고 있는데 PBFT의 단순화 버전입니다. 개인적으로는 

카프카 대체제로는 RAFT로 충분하고 BFT계열은 간단하든 복잡하는 오버스펙이라 시작할맘도 없을 거 같습니다.참고로 JP모건 애들이 만드는 콘소시엄체인은 RAFT랑 IstabulBFT 라는것을 쓰는데 패브릭도 BFT계열을 오더링만 하는데 사용 할 바엔 E-O-V 프로세스를 폐기하는게 낫다고 봅니다. 아마 거기 아키텍트도 똑같은 생각하고 있을듯..ㅎㅎ 

(추가작성예정)

 

Hyperledger Fabric - MinBFT

 대체제로 PBFT와 똑같은데, Pre-Prepare 과정이 생략됬다고 생각하면 된다. 따라서 페이즈가 2로 줄었고 2f + 1이면 합의를 이룰수 있다. 이는 Secure Hardware (Intel Software Guard Extensions (SGX)) 를 통한 Primary Node의 안전성을 보장함으로 얻어진다. 근데 SGX 해킹된다던데.... 업데이트가 되었는지는 잘..

 

Istanbul BFT (IBFT)

JP Morgan의 콘소시엄형 블록체인인 GoQuorum (IBFT1.0) 과 ethereum 기반의 Hypereledger besu(GoQuorum의 IBFT1.0을 개선하여 IBFT2.0업그레이드한 버전)에서 채택하여 주목받은 BFT계열 합의로써, 기본적으로 PBFT의 형식을 따라가며 블록을 모아서 전송한다는 개념이 추가되었습니다.  주요 차이점은 Client가 분명하지 않으며, 합의 노드들에는 아무 클라이언트들이 요청을 보낼 수 있으며, 합의노드들은 서로의 존재에 대해 알고 있으며 (Public key 공유) 리더(IBFT에서는 Proposer 노드)는 트랜잭션을 모아 블록을 검증 (논스관련,클라이언트 서명관련, Besu경우 가스관련등등) 하고 만들어서 전파합니다. Prepare단계를 거쳐 Commit 단계에서 블록 커밋을 하며, 비 합의노드에도 블록은 전파됩니다. 각 합의노드들의 인증이 모여서 블록 헤더에 extraData로 들어가게 되며, (인증받은 블록이란걸 검증하기 위함, 따라서 스스로 검증가능하다고 말해 집니다)  Validator는 블록에 서명을 하고 insert 를 하게 되는데 이렇게 되면 블록해쉬가 달라지기 때문에 서명한 부분은 블록해쉬에서 제외 하기도 합니다. 한라운드의 합의가 끝마치게 되면 Validators(Backups)들은 새로운 Proposer를 골라서 새로운 블록을 만들 책임을 지웁니다. 보통 라운드로빈으로 하며 이런 Validators들은 그룹멤버쉽을 통해 새로운 멤버가 추가되거나 삭제 될 수 있으며 각각의 투표는 블록헤더에 기록됩니다.

(Hyperledger besu - IBFT2.0 에서의 트랜잭션 검증도)



RBFT 

간략하게 설명하면 여러개의 BFT 인스턴스들을 생성해서 병렬처리하며, 하나의 인스턴스에서 오더링 하는 구조 입니다. (추가 작성중..) 


Mir-BFT

간략하게 설명하면 트랜잭션의 모음을 몇개의 버켓으로 나누어서 각 버켓을 각 노드들에게 맞기는데 , 각 노드들은 리더가 됩니다. 즉 리더가 여러개이며, 이 버켓들이 병렬적으로 처리되고 마지막에 순서를 갖춰서 커밋되는 구조 입니다. 초기 서명검증을 병렬적으로 할 수 있기 때문에 속도 향상을 꽤 할 수 있습니다.

 

공통

* 모든 방법에는 가쉽네트워크를 통한 블록싱크가 추가되야 한다. (패브릭처럼 합의 네트워크 말고 합의 네트워크의 결과를 받아서 블록체인 공유를 하는 시스템이라면 필요 없고~) 
* 패브릭의 체인코드의 Go코드는 비결정적인데 이를 해소할 방안은 없다. (SIEVE가 가능한데...성능상에 불리하며, VM레이어를 만들어 넣어서 결정적으로 바꿀 수 밖에..)


그 밖에도)

* 사실 EOS도 DPos 합의 아래 계층에서 BFT 변형을 사용한다.
* 스텔라도 BFT 변형을 사용한다. 


부록)

Clique (PoA) 알고리즘 

Hyperledger Besu에서 IBFT 말고 사용 할 수있는 합의 알고리즘. (Go etheurem버전도 있음)  
3라운드인 PBFT계열에 비해서 1라운드이다. 따라서 BFT계열보단 빠르다. (추가 작성 중..) 

aBFT (asynchronous byzantine fault tolerance) 
Hedera Hashgraph에서 사용하는 컨센서스 알고리즘으로 BFT계열 알고리즘 중에서는 가장 속도가 빠를 듯 하며, 그 영향력으로 Hyperledger fabric의 ordering 과 Corda 의 notary 및 기타 엔터프라이즈 블록체인등의 합의 알고리즘으로 포함될 가능성이 크다. 


PS)
개인적 의견으론 Permisioned BlockChain에서는 그냥 RAFT를 사용하는게 좋지 않을까 한다. 
비교적 단순하고, 비잔틴은 없다고 가정하므로 성능이 PBFT계열보단 훨씬 빠르다. 
Hyperledger Fabric도 GoQuorum도 RAFT가 디폴트이다. Besu는 IBFT2.0이지만 RAFT를 지원해야 하지 않을까? 

+ Recent posts