Raft는 분산 합의를 구현하기 위한 프로토콜이다
노드는 3가지 상태 중, 한 가지 상태를 가짐
1. Follwer
2. Candidate
3. Leader
1. 모든 리더는 Follower 상태에서 시작됨
Follower는 Leader로부터 일정시간 신호를 못 받으면 Candidate 상태가 된다
2. Candidate는 자기 자신에게 투표 후 다른 노드에게 투표 요청을 보내 자신에게 투표하기를 요청
3. 아직 투표를 하지 않은 노드들은 투표 요청에 응답을 한다(투표는 한 텀에 한 번만 가능)
4. Candidate가 과반수 이상의 응답을 받으면 Leader가 된다
어떤 Candidate도 과반수 이상의 응답을 받지 못하면 1번으로 돌아가 새 투표 시작
5. 이제 모든 변화는 Leader노드를 통해 이루어 진다
1. Leader는 Client로부터 데이터를 수신한다.(모든 데이터는 노드의 로그에 저장됨)
2. Leader는 Follower에게 수신한 데이터를 복사해 전송한 다음 Follower들의 응답을 기다린다.
(Append Entries 메시지에 데이터가 덧붙여져서 전송됨)
Follwer들은 Leader에게 Commit 메세지 받으면 Leader에게 Acknowledge 메시지 전송
3. 과반수 이상의 Follower에게 응답을 받으면 데이터를 적용 후 Follower 들에게 commit 되었다는 메시지를 보낸다
Follwer들은 Leader에게 수신한 데이터 반영
각 노드에는 리더 선출을 제어하기 위한 두 가지의 타이머가 존재
1. Election timeout
2. HeartBeat Timeout
Follower들이 Append Entries 메시지 받지 못하면 새로운 텀이 시작되고 새로운 리더를 선출함
1. 두 그룹으로 분리된 노드들은 각 그룹에서 새로운 Leader를 선출함
2. 두 그룹의 Leader는 Client로부터 각각 다른 데이터를 수신함
한 그룹의 Leader는 과반수 이상의 Acknowledge 메시지를 받지 못해 수신 받은 데이터를 commit하지 못함
다른 그룹의 Leader는 과반수 이상의 Acknowledge 메시지를 받아 수신 받은 데이터를 commit함
3. 네트워크 장애가 해결되서 두 그룹이 하나로 뭉쳐짐
텀이 더 낮은 로그는 더 높은 텀의 로그로 갱신됨
두 그룹의 Leader는 uncommit된 데이터를 롤백 후 텀이 더 높은 그룹의 Leader의 데이터로 노드에 저장된 값 일치시킴
Host1
Host2
Docker Swarm을 사용한 멀티호스트 환경
cd fabric-samples/first-network
# Host1
docker swarm init --advertise-addr <Host1 아이피>
docker swarm join-token manager
docker network create --attachable --driver overlay first-network
# Host2
<join-token manager 출력 값> --advertise-addr <Host2 아이피>
crypto-config.yaml 수정
configtx.yaml 수정
base/docker-compose-base.yaml 수정
.env 생성
host1.yaml 생성
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
version: '2'
volumes:
orderer.example.com:
orderer2.example.com:
orderer5.example.com:
orderer7.example.com:
peer0.org1.example.com:
peer1.org1.example.com:
networks:
byfn:
external:
name: first-network
services:
orderer.example.com:
extends:
file: base/docker-compose-base.yaml
service: orderer.example.com
container_name: orderer.example.com
networks:
- byfn
orderer5.example.com:
extends:
file: base/peer-base.yaml
service: orderer-base
container_name: orderer5.example.com
networks:
- byfn
volumes:
- ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer5.example.com/msp:/var/hyperledger/orderer/msp
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer5.example.com/tls/:/var/hyperledger/orderer/tls
- orderer5.example.com:/var/hyperledger/production/orderer
ports:
- 8050:7050
orderer2.example.com:
extends:
file: base/peer-base.yaml
service: orderer-base
container_name: orderer2.example.com
networks:
- byfn
volumes:
- ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/msp:/var/hyperledger/orderer/msp
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/:/var/hyperledger/orderer/tls
- orderer2.example.com:/var/hyperledger/production/orderer
ports:
- 9050:7050
orderer7.example.com:
extends:
file: base/peer-base.yaml
service: orderer-base
container_name: orderer7.example.com
networks:
- byfn
volumes:
- ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer7.example.com/msp:/var/hyperledger/orderer/msp
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer7.example.com/tls/:/var/hyperledger/orderer/tls
- orderer7.example.com:/var/hyperledger/production/orderer
ports:
- 10050:7050
peer0.org1.example.com:
container_name: peer0.org1.example.com
extends:
file: base/docker-compose-base.yaml
service: peer0.org1.example.com
networks:
- byfn
peer1.org1.example.com:
container_name: peer1.org1.example.com
extends:
file: base/docker-compose-base.yaml
service: peer1.org1.example.com
networks:
- byfn
cli:
container_name: cli
image: hyperledger/fabric-tools:$IMAGE_TAG
tty: true
stdin_open: true
environment:
- SYS_CHANNEL=$SYS_CHANNEL
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
#- FABRIC_LOGGING_SPEC=DEBUG
- FABRIC_LOGGING_SPEC=INFO
- CORE_PEER_ID=cli
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
- CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: /bin/bash
volumes:
- /var/run/:/host/var/run/
- ./../chaincode/:/opt/gopath/src/github.com/chaincode
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
- ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
depends_on:
- orderer.example.com
- peer0.org1.example.com
networks:
- byfn
host2.yaml 생성
# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#
version: '2'
volumes:
orderer3.example.com:
peer0.org2.example.com:
orderer4.example.com:
orderer6.example.com:
peer1.org2.example.com:
networks:
byfn:
external:
name: first-network
services:
orderer3.example.com:
extends:
file: base/peer-base.yaml
service: orderer-base
container_name: orderer3.example.com
networks:
- byfn
volumes:
- ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/msp:/var/hyperledger/orderer/msp
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/tls/:/var/hyperledger/orderer/tls
- orderer3.example.com:/var/hyperledger/production/orderer
ports:
- 7050:7050
peer0.org2.example.com:
container_name: peer0.org2.example.com
extends:
file: base/docker-compose-base.yaml
service: peer0.org2.example.com
networks:
- byfn
orderer4.example.com:
extends:
file: base/peer-base.yaml
service: orderer-base
container_name: orderer4.example.com
networks:
- byfn
volumes:
- ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer4.example.com/msp:/var/hyperledger/orderer/msp
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer4.example.com/tls/:/var/hyperledger/orderer/tls
- orderer4.example.com:/var/hyperledger/production/orderer
ports:
- 9050:7050
peer1.org2.example.com:
container_name: peer1.org2.example.com
extends:
file: base/docker-compose-base.yaml
service: peer1.org2.example.com
networks:
- byfn
orderer6.example.com:
extends:
file: base/peer-base.yaml
service: orderer-base
container_name: orderer6.example.com
networks:
- byfn
volumes:
- ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer6.example.com/msp:/var/hyperledger/orderer/msp
- ./crypto-config/ordererOrganizations/example.com/orderers/orderer6.example.com/tls/:/var/hyperledger/orderer/tls
- orderer6.example.com:/var/hyperledger/production/orderer
ports:
- 8050:7050
# 암호자료 생성
../bin/cryptogen generate --config=./crypto-config.yaml
# 제네시스 블록 생성
export FABRIC_CFG_PATH=$PWD
mkdir channel-artifacts
../bin/configtxgen -profile SampleMultiNodeEtcdRaft -outputBlock ./channel-artifacts/genesis.block
# 채널 트랜잭션 생성
../bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
# 조직별 앵커피어 트랜잭션 생성
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
# 다른 호스트에게 디렉터리 복사
# Host1
cd ..
tar -czf raft-4node-swarm.tar raft-4node-swarm
# Host2
scp hyperledger@<Host1 아이피>:/home/hyperledger/fabric-samples/raft-4node-swarm.tar /home/hyperledger/fabric-samples
tar -xzf raft-4node-swarm.tar
# 피어노드 실행
# Host1
docker-compose -f host1.yaml up -d
# Host2
docker-compose -f host2.yaml up -d
# peer0.org1.example.com
docker exec -it cli bash
peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/channel.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
# peer0.org1.example.com
export CHANNEL_NAME=mychannel
peer channel join -b mychannel.block
peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org1MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
#peer1.org1.example.com
docker exec -it -e CORE_PEER_ADDRESS=peer1.org1.example.com:8051 -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt cli bash
peer channel join -b mychannel.block
#peer0.org2.example.com
docker exec -it -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp -e CORE_PEER_ADDRESS=peer0.org2.example.com:7051 -e CORE_PEER_LOCALMSPID="Org2MSP" -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt cli bash
export CHANNEL_NAME=mychannel
peer channel join -b mychannel.block
peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org2MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
#peer1.org2.example.com
docker exec -it -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp -e CORE_PEER_ADDRESS=peer1.org2.example.com:8051 -e CORE_PEER_LOCALMSPID="Org2MSP" -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt cli bash
peer channel join -b mychannel.block
# peer0.org1.example.com
# peer1.org1.example.com
# peer0.org2.example.com
# peer1.org2.example.com
peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/fabcar/go/
# peer0.org1.example.com
peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n mycc -v 1.0 -c '{"Args":[]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')"
# 체인코드 실행
# peer0.org1.example.com
peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["initLedger"]}'
# 체인코드 질의
# peer0.org1.example.com
peer chaincode query -n mycc -C mychannel -c '{"Args":["queryCar","CAR0"]}'
# peer0.org2.example.com
peer chaincode query -n mycc -C mychannel -c '{"Args":["queryCar","CAR0"]}'
# 체인코드 실행( orderer7.example.com 사용)
# peer0.org1.example.com
peer chaincode invoke -o orderer7.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["changeCarOwner","CAR0","KC"]}'
# 체인코드 실행( orderer4.example.com 사용)
# peer0.org2.example.com
peer chaincode invoke -o orderer4.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["changeCarOwner","CAR0","KC2"]}'
http://thesecretlivesofdata.com/raft/ 참고