우리는 흔히 시스템의 처리 성능을 TPS 로 나타낸다. 말 그대로 초당 몇개의 "Transaction" 을 "처리"할 수 있느냐를 나타내는 수치이다. 

이번에 블록체인의 TPS 성능에 대해 이야기 해보고자 한다. 사람들이 많이 궁굼해 하지만 답변하는 사람들의 답변 내용을 들어봐도 딱히 맞다는 생각이 들지는 않더라.

Blockchain 이 널리 쓰이는 중요한 인프라소프트웨어 가 되려면 반드시 당면하게 될 문제 중 하나가 바로 “Transaction 처리 성능” 이다.


▌Bitcoin Blockchain PoW 방식 에서의 TPS 한계성

현재 Blockchain 은 1MB 의 블록 크기와 10분의 블록 생성을 근거로, 1 트랜잭션의 크기를 1 Input, 1 Output 만을 포함하는 최소한의 Size 로 잡더라도,
(1MB/600초)/약260바이트 = 약 7TPS
가 채 안나오게 된다.

이 7 TPS 라는 수치를 계산해내는 방법을 보았듯이, 우리가 생각하는 일반적인 TPS 와는 그 개념이 다르다. TPS 는 시스템의 "성능"을 측정하는 단위이지만, 블록체인은 그 성능 보다는 "10분 후 전파되는 블록에 담긴 Transaction 수"이다.

아래는 C/S 환경에서의 Transaction 처리를 간략히 표현해본 그림이다.

그림에서 처럼 클라이언트는 서버를 바라보며 요청을 하고, 해당 요청이 처리된 즉시 응답을 받는다. 이러한 요청은 여러 클라이언트가 동시에 할 수 있으며, 서버는 이러한 요청을 초당 몇개 처리할 수 있는지를 TPS 수치로 표현할 수 있다.

그러나, 아래와 같은 Blockchain 환경에서 보면, 이러한 TPS의 의미가 다르게 해석되어야 함을 알 수 있다.


Node 들 중에는 Miner 도 있고, Lightweight Client 들도 있다. SPV 라고 표현하던 것들이다. 이중 일반 Node 가 처리를 요청하면, 요청을 Transaction 메시지로 자신과 연결된 (1)Peer 들에게 전파된다. 모든 Node 들은 이러한 Transaction 에 대해 (2)검증 을 해야 한다. 또한 Transaction 을 검증한 Node 는, 해당 Transaction 을 자신의 Peer 들에게 (3)(4)전파 해야 한다. 그러면 그 트랜잭션은 Miner 에 의해 (5)검증 되며, Transaction Pool 에 담겨있던 Transaction 은 (6)Pow 를 통해 최소 10분 후 블록에 묶이게 된다. 이 블록은 Miner 의  Peer 들에게 (7)전파 되며 해당 Peer 는 받은 블록에 대해 (8)블록검증 을 수행하고, 검증된 블록은 다시 (9)전파 된다. 최종적으로 Transaction 처리에 대한 응답을 확인하고자 하는 Peer 는 이 블록을 받았을 때 (10)응답을 확인 할 수 있게 된다. 그리고 그 블록에는 최대 약 7*60초*10분 = 약4,200 개의 Transaction 이 포함되어있을 수 있다. 

위 시나리오는 매우 정상적인 Case 에서의 동작이며, 이론상 최대한 희망적인 상황에서의 상황이다. 실제로는
A. 여러 Input 과 Output 이 1 트랜잭션에 포함되어 Transaction 크기가 커진다
B. Miner 의 Transaction Pool 에 들어가도, 이미 Mining 중인 Block 이 있다면 트랜잭션은 가장 빨리 블록을 생성해낸 마이너의 다음 마이닝 작업에 대상이 된다. 그러므로 최대 19.9분 후에 블록을 받을 수도 있다
C. 어떤 Node 들은 6 Confirm 이상을 최종 Commit 으로 간주 하므로 약 1시간 뒤에 해당 Transaction 이 최종 “처리” 됨을 인정받을 수 있다.

이렇게 “처리”의 개념이 일반적인 C/S 아키텍쳐와 다르며, 그 이유는 “합의” 라는 과정과 “P2P” 라는 환경으로 인해 발생하는 것이다. 이 두가지 과정으로 인해 “처리 Latency" 가 높아지게 되며, 이것은 전체적인 시스템의 처리 성능이 매우 늦어지게 되는 결과를 초래한다.

아래 흐름을 보자. 우선, 설명을 위해 매우 단순한 CS 구성에서의 Transaction 처리 시나리오이다.

그림 처럼, client_1 과 client_2 는 Transaction 을 "직접 서버로" 전달한다. Client 3,4,5,6,... 모두 Server 에게 직접 Transaction 을 전달하며, 서버는 Transaction 을 처리하고 처리된 결과나 처리되었음을 알리는 Notification 을 Client 에게 전달한다. Client 에게 1 TX 처리에는 0.001초가 걸린 것이며, 서버의 입장에서는 1초에 1,000 TPS 를 처리한 것이 된다.

다음은 Blockchain 의 경우이다. 설명을 위해 node2 가 Miner 역할을 하며, node1,3,4 등은 SPV 로 간주하면 되겠다.

node 들은 P2P 환경으로 구성되어있다. node1 이 운 좋게 miner 인 node_2 를 peer 로 직접 추가하고 있거나, node1 자체가 miner 인 경우에도 최소 1 Transaction 이 처리되어 처리된 결과를 자신의 State 에 반영할 수 있는데 까지는 최소 10분 이상이 소요된다. node4 의 경우, node3 의 peer 인 경우로, 이 경우 node3 으로의 TX 전파와 node3 의 TX 검증 단계를 거친 후 miner 에게 전달될 수 있다. 만약 node1 이 Miner 라고 하더라도 Block 이 나오는데 까지는 10분이 소요되므로 사실상 "의미있는" Transaction 의 완전한 처리는 최소 10분이 되는 것이다.
이 경우, Miner 는 최대 7 TPS 로 10분 만에 Transaction 을 Commit 을 하게 된 것이며, Client 의 입장에서는 1 TX 를 처리하는데 10분이 걸린 것이다.

“처리”를 어디까지 볼것인가. 1:1 상황에서의 “전달” 과 "Transaction 검증", “(블록없이 Transaction 만만으로의)State 전이 완료 (Pre-Mined State)” 까지를 Transaction 처리 완료 시점이라고 정한다면 상당히 높은 성능의 시스템 구현이 가능하겠지만, 다수가 참여해야 하는 P2P 환경에서는 이러한 기준은 무의미 하다시피 하다. 

위 그림의 Pending TX 범위안에 있는 Transaction 들로 Miner 는 Block 을 만들게 되는데, 만약 Transaction 의 합이 Block Header 를 포함하여 총 1MB 를 넘게 되면, 1MB 내에서 Pending TX 를 잘라내고 잘라낸 만큼만을 Block 으로 만들게 된다. Mike Hearn 이 이야기 했던 1MB 의 블록 용량의 한계는 바로 이때문이다. 만약 비트코인 거래가 더 활발해져서 Transaction 수가 더 많아진다면, 저 Pending TX 의 용량은 조만간 1MB 를 넘을 것이다. 아래 그림을 보자.


노란색 그래프가 Block 의 평균 크기 이며, 이미 700KB 선이다. 7 TPS 의 트랜잭션도 안되며, 만약 700KB 로 계산해보면, 4~5 TPS 정도의 트랜잭션 발생에 블럭의 크기가 저렇게 된 것이다.

C/S 환경에서는 서버의 DB 에 최종 Commit 만 되었다면 이 즉시 모든 클라이언트가 전이된 State 를 기반으로 다음 작업을 할 수 있다. 그러나 Blockchain 의 경우, Block 이 적어도 다음 Transaction 을 발생시켜야 하는 Client 에게는 전달되었고 그 Block 에 의해 변이된 State 가 “옳다” 라는 “합의”가 되어지지 않는다면 다른 Peer 들은 내 Transaction 을 무시하게 될 것이다.

Pending Transaction 을 기반으로 작업을 한다면 Double Spending 을 막을 수 없다. 내가 매우 빠른속도로 어떤 네트워크에서 잔고 1,000 원에서 100원을 이체시키고, 다른 네트워크(또는 다른 멀리 있는 피어)로 이체 이전 상태인 1,000 원 상태에서 다시 500원을 이체하도록 한다면, 10분 뒤 블록이 나오기 이전에 Pending Transaction 을 기반으로 거래를 확정한 상대 시스템은 10분 후에나 문제가 있었음을 알 수 있으며, 어쩌면 그 다음 블럭인 20분 후에 이 사실을 알게된다.

Bitcoin 에서 최종 거래확정에 6 Confirm 을 권고하는 이유도, 1 Confirm 으로 들어온 블록이 Best Blockchain 이라고 말하기 어렵기 때문이며, 이후 들어온 블록을 기반으로 뒤따라 마이너들이 지속적으로 블록을 연결했다면, 결국 이전에 받은 1 Confirm 블록 내에 Double Spending 중 하나가 섞여있었을 수도 있기 때문이다.

"만약, Bitcoin 으로 한사람이 편의점에서 담배를 결재한 후 10분 이내에 라이터를 추가결재 하려 한다면, 이 거래는 현재 Bitcoin 내에서는 불가해야 한다" 왜냐하면, 아직 1 Confirm 도 떨어지지 않았을 것이기 때문이다. 물론 작은 금액의 거래에 대해서는 1 Confirm, 심지어 Pending Transaction 에 있어도 인정하는 추세이기는 하지만 어디까지나 이건 위험하다.

▌블럭을 크게, 생성 주기를 빠르게 하면? 

블럭 생성을 빠르게 한다면 Bitcoin 보다 더 빠른 응답속도가 가능해지며, Block 의 사이즈가 커진다면 블록에 더 많은 Transaction 을 담을 수 있게된다. Ethereum 의 경우, 0x0D (13초)를 블록 생성주기로 맞추어 놓고 있으며, 아직까지는 Block 의 사이즈를 제한하지는 않고, 대신 Block 의 Gas Limit 을 두어 Gas Limit 내에서 Transaction 을 담을 수 있게 하였다.

이러한 방식은 Bitcoin Blockchain (이제 Blockchain 1.0 이라고 하겠다) 에 적용했을 때 문제가 발생하게 되는데, 바로 다수의 Miner 가 동시에 생성해내는 Block 이 많아지는 문제가 생기는 것이다. Stale Block, Ethereum 에서는 Uncle 이라고 불리우는 Fork 들인데, 이러한 Fork 가 많아지게 되면 발생하는 문제는 State 의 불안정성이다.

Fork 를 인정하지 않는 Blockchain 1.0 방식으로 가게되면, Best Block Chain 이 바뀌는 순간 State 가 출렁일 수 있다. 특정 Account 의 Nonce 가 100 까지 올라간 Block을 받아서 State 가 올라갔는데, 새로 들어온 같은 Block Number의 Block 에는 이 State 변이를 실행했던 Transaction 이 제외되어 있으나 새로들어온 Block 의 Chain Total Difficulty 가 이전의 Difficulty 보다 높았다면 Best Blockchain 이 버뀌면서 State 가 Nonce 100 에서 99로 다시 바뀔 수 있다.

Ethereum 은 이러한 상황을 예상하여 GHOST(Greedy Heaviest Observed Subtree) 라는 프로토콜을 응용하여 자신들의 State Tree 인 Patricia Tree 를 구성할 때 Uncle Block 을 포함하도록 하였으며, 새로운 Block 이 생성될 때 자신이 참고하는 Uncle Block 을 포함시키도록 하였다. Uncle Block 에 대해서도 93.75% 의 Reward 를 주며, 이를 포함하는 Block 이 Best Block 이 되었을 때에는 각 Uncle Block 의 Reward 의 3.125% 를 Best Block 의 Coinbase 에 추가하도록 하였다.

이외에도 많은 부분을 생각해야 한다. 사이즈가 큰 블록은 네트워크 전파 속도가 느려지게되어 결국 더 많은 Uncle Block 들이 생기게 되고, 너무 작은 블록도 오버헤드를 높여 전체적인 성능을 저하시킨다. 특히나 시간이 짧아질수록 평균 Hashrate 를 기반으로한 블록 생성속도의 오차율은 커지게 되는데, 아래 그림(블록생성시간)처럼 블록생성시간의 오차범위는 매우 커지게 된다.


Ethereum 의 지금 시각 평균 Hashrate 는 etherstat 리포팅을 하고있는 node 들 기준으로 1.4TH/s 정도 되며, Difficulty 는 14~15초 정도 되는 20.34 TH 정도로 맞추어져있다.


빨라지는 주기를 PoW 로 때우기 위해서는 Block 생성 시간이 안정적이어야 하고 ASIC 같은 돈버러지를 떼어내야 하는데, 이때문에 Ethereum 은 DAG (Dagger Hashimoto)와 같은 방법을 썼고, 현재는 ethash 알고리즘으로 약1GB 정도의 Hash Cache 를 위한 Seed Table 을 생성하게 해놨으며, 100시간 정도 되는 30,000 블럭 주기로 이 DAG 를 전체 재생성 하도록 해놓았다. 이게 생성되는 것만도 십수분은 걸린다.

▌Authority 기반 블록 생성은?

권한 기반의 블록체인은 이미 작년 부터 Private Blockchain 과 Consorthium Blockchain의 필요성이 나오면서 구현체들이 나왔고, Ethereum 조차도 C++ eth 에서 이 PoA 를 flu 라는 CLI 를 통해 제공했었다. 현재는 Homestead 런칭으로 기능을 삭제한 상태이며 이전에 구현했던 방식도 그다지 세련되지 않은 방식이었다.

Authority 기반의 블록체인의 기본적인 핵심은 "블록을 생성할 수 있는 권한을 부여"하는 것부터 출발하는 것이다. PoW 를 하건, PoS 를 하건 최종 블록을 만들어내는건 "권한"을 가진 Node 가 만들어내게 하는 것이다. 

권한이 있고 이 권한을 신뢰하여 Blockchain 을 구성한다면 궂이 Nonce 를 찾을 이유도 없다. 전제조건은 경제관념이 없어야 제대로 돌아갈 수 있으며 권한이 있는 모든 노드들은 모두 신뢰된 관계여야 한다는 것이다. 경제관념이 생긴다면 그중 어떤 Node 는 더 많은 Token 을 얻으려 할 것이며, 이러다 보면 다시 권한이 있는 노드들 간에 합의가 필요하게 된다.

신뢰된 관계 또한 매우 중요하다. 권한이 있는 Node 이더라도 악의적 행위를 할 수 있다라고 판단되는 경우 이는 다시 합의가 필요한 상황으로 치닫게 된다. 또한 이러한 신뢰관계를 어떻게 시스템 간에 구현 할 것이냐는 것에 대해서도 충분히 고민하여야 한다. 

아무생각 없이 Genesis 에 Key 박아두거나 권한 Key 를 누군가 관리하며 추가 발급한 후에 "응용 업데이트 됐습니다. 다운받으세요." 하는거나 "신뢰는 별도의 보안솔루션이 있쟎아" 라고 하는거면 고개를 몇번 갸우뚱~ 해봐야 하지 않겠나 싶다.

▌Proof of Stake 에서는?

Proof of Stake 는 자신의 지분이 곧 블록생성권 지분율이 되는 형태이다. Public Blockchain 에서는 자신의 Balance 가 크면 블록을 생성할 수 있는 권한이 생기게 되며 블록을 Accept 할 때에도 Miner 의 지분율을 보아야 한다. PoW 대비 블록 생성 주기가 매우 짧아질 수 있으나 가장 지분이 큰 Miner 가 꺼져있거나 하는 상황에서는 전체 네트워크의 Node 상태를 알지 못하는 이상 어떤 블록이 Best Block 인지 판단하기 쉽지 않다는 단점와 빈익빈 부익부 현상이 나타날 수 있다는 부작용이 있다.
이러한 부분을 개선하는 노력들을 많이 해왔으며 Coin Ages Selection 방식이나 Random 방식, PoSV (Velocity) 방식, Voting 방식 등이 블록 채택을 위한 PoS 알고리즘으로 나와있다.

대량의 Transaction이 빠르게 처리되어야 한다면 고려해야하는 모델이며, 특히나 Consortium Blockchain 의 경우 고려할 필요가 있는 방식이 아닐까 생각한다. 

Eris 의 경우, PoS 의 Voting 방식을 채택하고있는데, 모든 권한있는 Node 가 Voting 을 하게 되어있다. Voting Message 를 통해서 Block Proposal 에 대해서 투표하고, 최종 Confirm 은 2/3 의 Token (Voting Power)이 확인되고 Signature 로 Voter 가 확인하면 최종 Step 에서는 Precommit 후 Commit 하여 해당 Transaction List 를 승인하도록 되어있다.

이러한 방식은 블록 생성과 전파 대비 효율적이긴 하나 Public 에서 사용하기에는 효율성이 떨어질 수 있으며, Voting Power 에 해당하는 Token 을 무엇에 맵핑할것인지 생각해야 한다. Eris 는 이러한 Token 을 Genesis 에 Key 와 함께 부여할 수 있도록 하였다. 좀 문제이긴 하다.

그러나 PoW 대비 Transaction 처리의 Confirm 속도는 확연히 차이가 나며 Eris 를 실제 구동해보면 1~3초 이내에 Commit 이 되는것을 볼 수 있다. (Node 3대로 테스트라 좀 그렇긴 하다).


▌그래서 ?

그래서 결론은,
  1. Blockchain 에서의 TPS 를 이야기 할 때에는 부디 C/S 아키텍쳐에서의 TPS 잣대를 들이대지 말자.
  2. 합의 방식에 따라 Transaction 처리 방법과 시스템 전체 성능은 달라진다.
  3. 합의 필요 없고 완전 믿을 수 있는 네트워크라면 그냥 합의하지 말아라. (블록체인 불필요)
  4. 높은 TPS 성능만 필요한거라면, 차라리 성능 좋은 분산 DB 와 Messaging M/W 를 쓰고 참여자 간 인터페이스 통일해라. 

Blockchain 이 풀어낸 가장 큰 문제는 "신뢰" 를 증명하는 방법이다. 
스티븐 코비의 "신뢰의 속도" 라는 책이 떠오른다. 어떠한 일이든 가장 빠른 방법은 "신뢰"를 바탕으로 했을 때이지, 신뢰할 수 없는 환경에서가 아니다.
보안, 위변조, 합의, 정합성, ... 믿을 수 있다면 무엇이든 빠르고 좋은걸 해라. 그리고 다른것에 더 힘을 쏟아라.

(이상 책상에 앉아서 계획없이 생각나는대로 함 써봤다.. 훑어보니 내용이 좀 산으로 갔네요.. 졸려서 이만..^^)


반응형
블로그 이미지

Good Joon

IT Professionalist Since 1999

,