Hyperledger Fabric v1.4のRaft Orderingサービスを試してみる

(株)日立製作所 研究開発グループ  サービスコンピューティング研究部の渡辺です。

Hyperledger Fabric(以下、HLF) は、コンセンサスアルゴリズム（Orderingのサービス実装）として従来のKafkaやSoloに加え、v1.4.1より新たにRaftをサポートしました。本記事では、Raft OrderingサービスによるHLFv1.4.4環境(2019/11/30執筆時点で最新)を構築し、Build Your First Network(以下、BYFN)チュートリアルに従い動作確認をします。また、冗長構成をとるOrdererサービスのRaft Leaderダウン時の挙動も確認をした内容を記事後半で紹介させていただきます。

本記事では以下を参考にさせて頂きました。


> HLF公式ドキュメントー What"s new in v1.4  / Raft ordering service
>     https://hyperledger-fabric.readthedocs.io/en/release-1.4/whatsnew.html

> HLF公式ドキュメントー The Ordering Service
>     https://hyperledger-fabric.readthedocs.io/en/release-1.4/orderer/ordering_service.html

> Hyperledger Fabric v1.4 公式ドキュメントーBuilding Your First Network
>     https://hyperledger-fabric.readthedocs.io/en/release-1.4/build_network.html

> Coinmonks ー Hyperledger Fabric — The Taste of Raft
>     https://medium.com/coinmonks/hyperledger-fabric-the-taste-of-raft-4f9f0df20b5e



## 1. セットアップ
#### 1.1. HLF前提環境のセットアップ

HLFネットワークを構築するに先立ち前提環境をセットアップします。

|前提コンポーネント|バージョン             | 前提条件             |
|----------|-------|--------|
|Ubuntu| 18.04.1 LTS(Bionic Beaver)  | -             |
|Docker| v19.03.5 | v17.06.2-ce以上             |
|Docker Compose | v1.25.0 | v1.14.0以上   |
|Go           | v1.12.13 | v1.12.x             |
|Node.js           | v10.17.0 (LTS/dubnium)| v8.9.4以上(v8の場合)、v10.15.3以上(v10の場合)             |
|NPM                  | v6.11.3|                                                                                                                              |
|Python    | v2.7.15   | v2.7.x    |


> 参考URL：
> Hyperledger Fabric v1.4 公式ドキュメント GettingStarted  - Prerequisites
> https://hyperledger-fabric.readthedocs.io/en/release-1.4/prereqs.html


```
$ sudo apt-get update

### Dockerのインストール
$ curl -sSL https://get.docker.com/ | sh
$ sudo usermod -aG docker $(whoami)
$ docker -v
Docker version 19.03.5, build 633a0ea838


### Docker-Composeのインストール
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose version
docker-compose version 1.25.0, build 0a186604
docker-py version: 4.1.0
CPython version: 3.7.4
OpenSSL version: OpenSSL 1.1.0l  10 Sep 2019


### Goのインストール
$ wget https://dl.google.com/go/go1.12.13.linux-amd64.tar.gz
$ sudo tar -C /usr/local/ -xzf go1.12.13.linux-amd64.tar.gz
$ sudo vim /etc/profile.d/golang.sh
$ echo <<END >> /etc/profile.d/golang.sh
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin
END
$ . /etc/profile.d/golang.sh
$ echo <<END >> ~/.bash_profile
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
END
$ . ~/.bash_profile
$ go version
go version go1.12.13 linux/amd64

### Node.jsとNPMのインストール
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.1/install.sh | bash
$ echo <<END >> ~/.bash_profile
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
END
$ . ~/.bash_profile
$ nvm install v10.17.0
$ node -v
v10.17.0
$ npm -v
6.11.3

### Pythonのインストール
$ sudo apt-get install python
$ python --version
Python 2.7.15+
```

#### 1.2. HLFとサンプルプログラム（fabric-sample)の取得
以下のコマンドを実行します。バージョン指定しないと最新バージョンのHLF（2019/11/29時点でv1.4.4）がgit cloneされます。

```
$ curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh | bash -s
```

もし、バージョン（以下の例ではv1.4.4）を明示して指定する場合は以下のようにして引数指定して実行します。

```
$ curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh | bash -s -- 1.4.4 1.4.4 0.4.18
```

このスクリプトは以下のものをダウンロードします。
    
- fabric-samplesソースコード

```
$ tree . -L2
.
└── fabric-samples
  　  ├── CODE_OF_CONDUCT.md
  　  ├── CONTRIBUTING.md
  　  ├── Jenkinsfile
  　  ├── LICENSE
  　  ├── MAINTAINERS.md
  　  ├── README.md
  　  ├── SECURITY.md
  　  ├── balance-transfer
  　  ├── basic-network
  　  ├── bin
  　  ├── chaincode
  　  ├── chaincode-docker-devmode
  　  ├── ci
  　  ├── ci.properties
  　  ├── commercial-paper
  　  ├── config
  　  ├── docs
  　  ├── fabcar
  　  ├── first-network
  　  ├── high-throughput
  　  ├── interest_rate_swaps
  　  ├── off_chain_data
  　  └── scripts
```

- Platform-Specificバイナリ (暗号鍵生成、genesisblock生成のためのバイナリ)

```
$ tree fabric-samples/bin
fabric-samples/bin
├── configtxgen
├── configtxlator
├── cryptogen
├── discover
├── fabric-ca-client
├── idemixgen
├── orderer
└── peer
```

- HLFネットワーク設定ファイルとノード設定ファイル

```
$ tree fabric-samples/config
fabric-samples/config
├── configtx.yaml
├── core.yaml
└── orderer.yaml
```

- Dockerイメージ

```bash
$ docker images
REPOSITORY                     TAG                 IMAGE ID            CREATED             SIZE
hyperledger/fabric-javaenv     1.4.4               4648059d209e        12 days ago         1.7GB
hyperledger/fabric-javaenv     latest              4648059d209e        12 days ago         1.7GB
hyperledger/fabric-ca          1.4.4               62a60c5459ae        13 days ago         150MB
hyperledger/fabric-ca          latest              62a60c5459ae        13 days ago         150MB
hyperledger/fabric-tools       1.4.4               7552e1968c0b        2 weeks ago         1.49GB
hyperledger/fabric-tools       latest              7552e1968c0b        2 weeks ago         1.49GB
hyperledger/fabric-ccenv       1.4.4               ca4780293e4c        2 weeks ago         1.37GB
hyperledger/fabric-ccenv       latest              ca4780293e4c        2 weeks ago         1.37GB
hyperledger/fabric-orderer     1.4.4               dbc9f65443aa        2 weeks ago         120MB
hyperledger/fabric-orderer     latest              dbc9f65443aa        2 weeks ago         120MB
hyperledger/fabric-peer        1.4.4               9756aed98c6b        2 weeks ago         128MB
hyperledger/fabric-peer        latest              9756aed98c6b        2 weeks ago         128MB
hyperledger/fabric-zookeeper   0.4.18              ede9389347db        3 weeks ago         276MB
hyperledger/fabric-zookeeper   latest              ede9389347db        3 weeks ago         276MB
hyperledger/fabric-kafka       0.4.18              caaae0474ef2        3 weeks ago         270MB
hyperledger/fabric-kafka       latest              caaae0474ef2        3 weeks ago         270MB
hyperledger/fabric-couchdb     0.4.18              d369d4eaa0fd        3 weeks ago         261MB
hyperledger/fabric-couchdb     latest              d369d4eaa0fd        3 weeks ago         261MB
```



#### 1.3. HLFネットワークの起動

以下のコマンドを実行し、HLFネットワークを起動します。

```
$ cd fabric-samples/first-network/

## 証明書生成〜チャネル生成〜チャネル上に各組織のアンカーピアを生成
$ echo y | ./byfn.sh generate -o etcdraft

## HLFネットワークの起動（各種Dockerコンテナの生成と起動）
$ echo y | ./byfn.sh up -o etcdraft
...
CONTAINER ID        IMAGE                               COMMAND             CREATED             STATUS                  PORTS                      NAMES
cfb7abffc553        hyperledger/fabric-tools:latest     "/bin/bash"         1 second ago        Up Less than a second                              cli
57393aafb10b        hyperledger/fabric-peer:latest      "peer node start"   11 seconds ago      Up 3 seconds            0.0.0.0:10051->10051/tcp   peer1.org2.example.com
be24ebc743c7        hyperledger/fabric-orderer:latest   "orderer"           11 seconds ago      Up 8 seconds            0.0.0.0:8050->7050/tcp     orderer2.example.com
96a650ddbda4        hyperledger/fabric-orderer:latest   "orderer"           11 seconds ago      Up 9 seconds            0.0.0.0:11050->7050/tcp    orderer5.example.com
33a0d9bf8421        hyperledger/fabric-peer:latest      "peer node start"   11 seconds ago      Up 4 seconds            0.0.0.0:7051->7051/tcp     peer0.org1.example.com
cd359ed55dbe        hyperledger/fabric-orderer:latest   "orderer"           11 seconds ago      Up 5 seconds            0.0.0.0:9050->7050/tcp     orderer3.example.com
c68a964a7e09        hyperledger/fabric-peer:latest      "peer node start"   11 seconds ago      Up 6 seconds            0.0.0.0:8051->8051/tcp     peer1.org1.example.com
faa0fd93854e        hyperledger/fabric-peer:latest      "peer node start"   11 seconds ago      Up 1 second             0.0.0.0:9051->9051/tcp     peer0.org2.example.com
975b594c061b        hyperledger/fabric-orderer:latest   "orderer"           11 seconds ago      Up 2 seconds            0.0.0.0:10050->7050/tcp    orderer4.example.com
b3363ac48a53        hyperledger/fabric-orderer:latest   "orderer"           11 seconds ago      Up 7 seconds            0.0.0.0:7050->7050/tcp     orderer.example.com
Sleeping 15s to allow etcdraft cluster to complete booting

 ____    _____      _      ____    _____
/ ___|  |_   _|    / \    |  _ \  |_   _|
\___ \    | |     / _ \   | |_) |   | |
 ___) |   | |    / ___ \  |  _ <    | |
|____/    |_|   /_/   \_\ |_| \_\   |_|

Build your first network (BYFN) end-to-end test

Channel name : mychannel
Creating channel...
+ peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/channel.tx --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
+ res=0
+ set +x
2019-11-29 06:43:48.128 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-11-29 06:43:48.155 UTC [cli.common] readBlock -> INFO 002 Got status: &{NOT_FOUND}
2019-11-29 06:43:48.161 UTC [channelCmd] InitCmdFactory -> INFO 003 Endorser and orderer connections initialized
2019-11-29 06:43:48.363 UTC [cli.common] readBlock -> INFO 004 Got status: &{SERVICE_UNAVAILABLE}
2019-11-29 06:43:48.366 UTC [channelCmd] InitCmdFactory -> INFO 005 Endorser and orderer connections initialized
2019-11-29 06:43:48.568 UTC [cli.common] readBlock -> INFO 006 Got status: &{SERVICE_UNAVAILABLE}
2019-11-29 06:43:48.572 UTC [channelCmd] InitCmdFactory -> INFO 007 Endorser and orderer connections initialized
2019-11-29 06:43:48.774 UTC [cli.common] readBlock -> INFO 008 Got status: &{SERVICE_UNAVAILABLE}
2019-11-29 06:43:48.778 UTC [channelCmd] InitCmdFactory -> INFO 009 Endorser and orderer connections initialized
2019-11-29 06:43:48.980 UTC [cli.common] readBlock -> INFO 00a Got status: &{SERVICE_UNAVAILABLE}
2019-11-29 06:43:48.985 UTC [channelCmd] InitCmdFactory -> INFO 00b Endorser and orderer connections initialized
2019-11-29 06:43:49.187 UTC [cli.common] readBlock -> INFO 00c Got status: &{SERVICE_UNAVAILABLE}
2019-11-29 06:43:49.194 UTC [channelCmd] InitCmdFactory -> INFO 00d Endorser and orderer connections initialized
2019-11-29 06:43:49.398 UTC [cli.common] readBlock -> INFO 00e Received block: 0
===================== Channel 'mychannel' created =====================

Having all peers join the channel...
+ peer channel join -b mychannel.block
+ res=0
+ set +x
2019-11-29 06:43:49.482 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-11-29 06:43:49.557 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
===================== peer0.org1 joined channel 'mychannel' =====================

+ peer channel join -b mychannel.block
+ res=0
+ set +x
2019-11-29 06:43:52.633 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-11-29 06:43:52.678 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
===================== peer1.org1 joined channel 'mychannel' =====================

+ peer channel join -b mychannel.block
+ res=0
+ set +x
2019-11-29 06:43:55.754 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-11-29 06:43:55.823 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
===================== peer0.org2 joined channel 'mychannel' =====================

+ peer channel join -b mychannel.block
+ res=0
+ set +x
2019-11-29 06:43:58.894 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-11-29 06:43:58.950 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
===================== peer1.org2 joined channel 'mychannel' =====================

Updating anchor peers for org1...
+ peer channel update -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/Org1MSPanchors.tx --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
+ res=0
+ set +x
2019-11-29 06:44:02.028 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-11-29 06:44:02.045 UTC [channelCmd] update -> INFO 002 Successfully submitted channel update
===================== Anchor peers updated for org 'Org1MSP' on channel 'mychannel' =====================

Updating anchor peers for org2...
+ peer channel update -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/Org2MSPanchors.tx --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
+ res=0
+ set +x
2019-11-29 06:44:05.117 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-11-29 06:44:05.135 UTC [channelCmd] update -> INFO 002 Successfully submitted channel update
===================== Anchor peers updated for org 'Org2MSP' on channel 'mychannel' =====================

Installing chaincode on peer0.org1...
+ peer chaincode install -n mycc -v 1.0 -l golang -p github.com/chaincode/chaincode_example02/go/
+ res=0
+ set +x
2019-11-29 06:44:08.221 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2019-11-29 06:44:08.221 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2019-11-29 06:44:08.552 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" >
===================== Chaincode is installed on peer0.org1 =====================

Install chaincode on peer0.org2...
+ peer chaincode install -n mycc -v 1.0 -l golang -p github.com/chaincode/chaincode_example02/go/
+ res=0
+ set +x
2019-11-29 06:44:08.628 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2019-11-29 06:44:08.628 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2019-11-29 06:44:08.947 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" >
===================== Chaincode is installed on peer0.org2 =====================

Instantiating chaincode on peer0.org2...
+ peer chaincode instantiate -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 -l golang -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P 'AND ('\''Org1MSP.peer'\'','\''Org2MSP.peer'\'')'
+ res=0
+ set +x
2019-11-29 06:44:09.033 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2019-11-29 06:44:09.033 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
===================== Chaincode is instantiated on peer0.org2 on channel 'mychannel' =====================

Querying chaincode on peer0.org1...
===================== Querying on peer0.org1 on channel 'mychannel'... =====================
Attempting to Query peer0.org1 ...3 secs
+ peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'
+ res=0
+ set +x

100
===================== Query successful on peer0.org1 on channel 'mychannel' =====================
Sending invoke transaction on peer0.org1 peer0.org2...
+ 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:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["invoke","a","b","10"]}'
+ res=0
+ set +x
2019-11-29 06:44:43.529 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200
===================== Invoke transaction successful on peer0.org1 peer0.org2 on channel 'mychannel' =====================

Installing chaincode on peer1.org2...
+ peer chaincode install -n mycc -v 1.0 -l golang -p github.com/chaincode/chaincode_example02/go/
+ res=0
+ set +x
2019-11-29 06:44:43.604 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2019-11-29 06:44:43.604 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2019-11-29 06:44:43.906 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" >
===================== Chaincode is installed on peer1.org2 =====================

Querying chaincode on peer1.org2...
===================== Querying on peer1.org2 on channel 'mychannel'... =====================
Attempting to Query peer1.org2 ...3 secs
+ peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'
+ res=0
+ set +x

90
===================== Query successful on peer1.org2 on channel 'mychannel' =====================

========= All GOOD, BYFN execution completed ===========


 _____   _   _   ____
| ____| | \ | | |  _ \
|  _|   |  \| | | | | |
| |___  | |\  | | |_| |
|_____| |_| \_| |____/


```

5つのRaftベースのordererサービス、4つのPeerサービス（組織毎に2つのPeerサービスの構成で2組織）からなるHLFネットワークが構成されました。また、HLFネットワークが起動した後e2eテストが実行され、正常に動作していることが確認できました。

- 参考情報（ワークアラウンド）
     - 初回起動で失敗する場合、一旦停止した後、再び起動すると正常動作することがあります。

```
$ ./byfn.sh -m down
$ ./byfn.sh -m up -o etcdraft
```

-----------------------------------------



2. 挙動確認
=========

ここでは、冗長構成をとっているOrderer ServiceのRaft Leader ダウン時の挙動を確認します。

#### Raft Leaderをkill (1/5停止状態)
現行のRaft Leaderを特定します。以下のログだとorderer3がRaft Leaderです。

```
$ docker logs orderer3.example.com
....
2019-11-29 07:03:53.544 UTC [orderer.consensus.etcdraft] Start -> INFO 02d Starting Raft node channel=mychannel node=3
...
2019-11-29 07:06:55.560 UTC [orderer.consensus.etcdraft] serveRequest -> INFO 06d Raft leader changed: 0 -> 3 channel=mychannel node=3
...
```

現行のRaft Leaderをkillします。

```
$ docker stop orderer3.example.com
```

Raft LeaderをkillしてもHLFネットワークは正常に動作しています。

```
$ docker exec -it cli bash

root# peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
90

root# peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile 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 $CHANNEL_NAME -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:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["invoke","a","b","10"]}'
     
2019-11-29 07:34:20.421 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200
     
root# peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
80
```

Raft Leaderはorderer2になっています。

```
$ docker logs orderer4.example.com
2019-11-29 07:06:55.560 UTC [orderer.consensus.etcdraft] serveRequest -> INFO 06d Raft leader changed: 0 -> 2 channel=mychannel node=2
```

####再びRaft Leaderをkill (2/5停止状態)

Raft Leaderをkillします。

```
$ docker stop orderer2.example.com
```

Raft Leaderがorderer5に切り替わります。

```
$ docker logs orderer.example.com
2019-11-29 07:54:02.065 UTC [orderer.consensus.etcdraft] serveRequest -> INFO 085 Raft leader changed: 0 -> 5 channel=mychannel node=1
```

#### 再びRaft Leaderをkill(3/5停止状態)

```
$ docker stop orderer5.example.com
```

以下のログにRaft Leader切り替りのログが出力されず、今度は新たなRaft Leaderに切り替わらないことがわかります。5台中3台のOrdererが停止しMajority Ruleが守れない構成となったためです。

```
$ docker logs orderer.example.com
```

#### killしたordererを復活 (2/5停止状態)
Raft Leaderが選出されたことがログからわかります。

```
2019-11-29 08:00:02.062 UTC [orderer.consensus.etcdraft] run -> INFO 363 raft.node: 1 elected leader 4 at term 5 channel=mychannel node=1
2019-11-29 08:00:02.063 UTC [orderer.consensus.etcdraft] serveRequest -> INFO 364 Raft leader changed: 0 -> 4 channel=mychannel node=1
```

### まとめ
以上のように、HLFv1.4.1より新たにサポートしたRaft Orderingサービス構成にてHLF環境を構築し動作状況を確認できました。また、構築したHLF環境において、冗長構成をとるOrdererサービスのRaft Leaderを一つずつダウンさせたときの挙動も確認できました。HLFでは、現在も様々な新機能の実装が続いています。動向を引き続きウォッチし、ご紹介していきたいと思います。

### 参考
ブロックチェーンの特徴やユースケースについて
https://www.hitachi.co.jp/products/it/blockchain/index.html