if(kakao) 2020 Nonce 그게 뭔데?

남태우·2020년 11월 22일
0

Nonce 블록체인 서비스를 개발하는데 있어서 중요한 역할을 합니다.

논스는 왜 필요할까 ?

논스를 알기 위해서 Tx을 알아야 합니다.
Tx : 일종의 사용자의 요청(송금을 한다. 블록체인 위에서 동작하는 스마트 컨택트를 실행하는데 사용)
Nonce : 대기표라 생각할 수 있습니다. Nonce는 Tx를 처리하기 위해 순서를 정해줍니다.

1. "철수에게 200원 송금 - 2"
2. "영희에게 100원 송금 - 1"
3. "릭에게 10000원 송금 - 3"
4. "영희에게 100원 송금 - 4"

각각의 트랜잭션의 논스를 지정하게 되면, 2번 1번 3번 4번 순으로 진행될 것입니다.

Nonce가 없다면 ?


Klaytn에서는 노드가 서로가 연결되어 있습니다. 연결된 노드에게 Tx를 전파합니다.
노드가 Tx를 담아 블록을 생성하는데 어떤 노드에서 블록을 생성하는지 모르니 최대한 Tx를 모든 노드에게 전파해야만 빠르게 Tx가 처리 될 수 있습니다.
블록체인은 일종의 글로벌 디비입니다. Tx를 담아 블록을 생성하면 Tx의 내용이 디비에 반영됩니다.

사용자의 어떤 요청이 A노드가 받게 되면, 노드는 연결된 B, C에게 Tx를 전파합니다.

노드는 Tx를 받게되면, 다시 서로 연결 되어 있는 B, C에게 전달합니다.

모든 노드는 같은 Tx를 공유하게 되는데, 이 때 각 노드들이 블록을 한 번씩 생성한다면, 동일한 Tx가 3번 반영되게 됩니다.
노드는 이미 Tx가 처리된건지 안된건지 알 수가 없기 때문에 모든 블록에 Tx를 적용하여 생성하게 됩니다.

1. "철수에게 200원 송금"
2. "영희에게 100원 송금"
3. "릭에게 10000원 송금"
4. "영희에게 100원 송금"

만일 nonce가 없다면 2번 4번은 내용이 같이 때문에 구분할 수 없습니다. 모두 처리해줘야 합니다.
nonce는 순서를 정해주고 이미 처리된 Tx인지 아닌지 구분해주는 역할을 할 수 있습니다.

논스 법칙

nonce에는 크게 2가지 법칙이 적용됩니다.

Domino Rule

어렸을 때 한 번씩 했던 도미노를 생각해보겠습니다.
1번이 쓰러지면 2번이 쓰러지고 ... 차례대로 쓰러질 것입니다.
만약 3번째가 없다면, 2번째까지만 쓰러질 것입니다.

Tx도 똑같이 3번 nonce가 적용된 Tx가 없다면 4번 논스가 적용된 Tx는 처리되지 않을 것입니다.

Unique Rule

모든 nonce는 유일해야 합니다.
동일한 nonce을 사용하는 Tx가 있다면 한 Tx는 처리되지 않을 것입니다.
블록체인에서 Tx를 생성할 때 동일한 nonce들을 사용해서 만들거나 이미 사용한 nonce을 재사용하면 안됩니다.

어떻게 구현 할까 ?


클레이튼은 사용자가 사용할 수 있는 nonce 이미 알고 있습니다.
Tx를 만들기 전에 클레이튼에게 논스를 묻고 응답 받은 nonce을 Tx에 적용하여 네트워크에 보내게됩니다.
그 후에, 반영이 되었는지 확인해야 합니다.
반영 확인을 하는 이유는 만일 Tx를 반영되지 않는 상태에서 nonce을 다시 묻게 된다면 동일한 nonce을 받게 되어 Unique Rule에 위배 됩니다.

클레이튼은 다른 블록체인에 비해 블록을 빠르게 만듭니다.(1초에 1블록)
논스를 묻고 확인하는 과정을 갖는다면 모든 Tx를 1초의 시간이 걸리게 될것입니다.
100개의 요청을 한다면 운이 좋으면, 한 2분쯤 걸릴 것입니다.

좀 더 빠른 방법

nonce을 묻는 과정을 제외하고 서비스 내부에서 nonce을 저장하는 변수를 두는 것입니다.
Tx는 nonce을 저장한 변수로부터 nonce을 읽습니다.
그리고 해당하는 nonce을 Tx 적용 한 뒤 전송해줍니다.
다음 요청을 처리하기 위해서 nonce의 값을 업데이트해줍니다.
이후 계속 반복을 하게 됩니다.

스케일 아웃

일반적인 서비스에서는 많은 사용자의 처리하기 위해서 스케일 아웃을 사용합니다.

하지만 약간의 문제 발생합니다.
서버를 2개 띄운다고 발생하면,

날리고 논스값을 업데이트 할 것이며, 계속해서 진행할 것입니다.

Unique Rule이 발생하게 됩니다.

공용 저장소가 필요합니다.

공용 저장소를 사용하기 때문에 Unique Rule에 위배되지 않고 진행할 수 있습니다.

데이터 레이스

두 서버가 동시에공용 저장소 에 접근하면 데이터 레이스라는 문제가 발생합니다.
두 서버가 공용 저장소 동시에 접근하면 동일한 nonce을 얻게 되어 Unique Rule에 위배됩니다.

위의 문제를 해결하기 위해서 Redis INCR 명령을 사용
값을 순차적으로 증가시키고 1을 반환해줍니다.
key값을 해당하는 변수를 1씩 증가시켜줍니다.
이 명령을 atomic 해서 순차적으로 처리해줍니다.

Tx처리가 실패한다면?

서버가 죽어서 nonce가 1인 것이 실패하고 다른 서버가 nonce가 2인 것을 보내게 된다면 Domino Rule에 위배됩니다.
그래서 실패한 Nonce를 재활용 하게 됩니다.


우선순위 큐 를 사용하여 실패한 nonce를 저장합니다.
실패한 nonce가 있다면 우선순위 큐에서 뽑아서 사용하고 우선순위 큐가 비어있다면 INCR 명령을 사용합니다.

우선순위 큐는 레디스의 Sorted Sets을 이용하면 쉽게 구현이 가능합니다.

더 쉬운 방법

문제가 생기는 이유들은 Tx를 서비스에서 생성하고 관리하기 때문입니다
(https://if.kakao.com/session/45)

profile
brand-new

0개의 댓글