fabric中默认数据存储的方式是levelDB,一个key/value存储的单机数据库。除此之外还提供了另外一种存储方式:couchDB。同样也是一个K/V 数据库,对fabric而言,相比于前者,后者提供更加丰富的查询功能。
而默认的levelDB切换到couchDb也很简单。即所谓的快速拔插。
区块链是文件系统,这个目前不支持更改,历史数据和区块链的索引是LevelDB,这个也不能更改。而对于State Database,由于和业务相关,所以提供了替换数据库,目前支持默认的LevelDB和用户可选择的CouchDB。这里要说到2点,一个是在0.6的时候其实用的RockDB,但是由于License的考虑,所以在1.0改成了LevelDB。另外就是CouchDB也不一定是最优的,很多人还考虑到MongoDB或者MySQL等,但是由于现在Fabric那边开发资源有限,所以在1.0还不会做,以后可能会实现。
1.安装couchDB
正常来讲,我们会为每一个peer节点提供一个couchDB作为数据存储。
执行: docker pull klaemo/couchdb 下载镜像
创建完成后 创建一个文件夹: mkdir couchDb 这个文件夹是用来存储数据的,因为couchDB每次启动时候都需要指定数据存储位置。
实例化一个couchDB实例: docker run -p 5984:5984 -d --name my-couchdb -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v ~/couchdb:/opt/couchdb/data klaemo/couchdb
这是启动一个名字为
my-couchdb,账号为admin,密码为 password的 couchDb实例 本地的5984端口映射到容器的5984端口。
接下来访问界面化操作页面:
http://IP:5984/_utils
显示如下界面:
先不用管里面的数据,因为我这个是后面操作的数据。正常到这一步应该是没有数据。
因为我们正常的fabric网络是默认启动4个peer节点,所以需要启动四个couchDb实例。
创建用来对应剩下的三个peer节点的数据库存储文件夹。
mkdir couchdb2 mkdir couchdb3 mkdir couchdb4
docker run -p 6984:5984 -d --name my-couchdb2 -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v ~/couchdb1:/opt/couchdb/data klaemo/couchdb
docker run -p 7984:5984 -d --name my-couchdb3 -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v ~/couchdb2:/opt/couchdb/data klaemo/couchdb
docker run -p 8984:5984 -d --name my-couchdb4 -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password -v ~/couchdb3:/opt/couchdb/data klaemo/couchdb
2.关联 peer节点和couchDb
到这一步fabric的网络是还没有启动的,上一篇文章启动的e2e-cli的网络。peer节点的相关配置在/root/go/src/github.com/hyperledger/fabric/examples/e2e_cli/下的docker-compose-cli.yaml
vi docker-compose-cli.yaml
编辑四个节点,红色部分为新增:
peer0.org1.example.com:
container_name: peer0.org1.example.com
environment:
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=121.199.63.157:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=password
extends:
file: base/docker-compose-base.yaml
service: peer0.org1.example.com
peer1.org1.example.com:
container_name: peer1.org1.example.com
environment:
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=121.199.63.157:6984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=password
extends:
file: base/docker-compose-base.yaml
service: peer1.org1.example.com
peer0.org2.example.com:
container_name: peer0.org2.example.com
environment:
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=121.199.63.157:7984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=password
extends:
file: base/docker-compose-base.yaml
service: peer0.org2.example.com
peer1.org2.example.com:
container_name: peer1.org2.example.com
environment:
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=121.199.63.157:8984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=password
extends:
file: base/docker-compose-base.yaml
service: peer1.org2.example.com
保存以后启动fabric网络 ./network_setup.sh up
这个时候再查看就会发现多出来的数据。
http://IP:5984/_utils
可以看到以Channel名字创建的Database,另外还有几个是系统数据库。点进去可以查看存储在当前节点的区块数据。
-------------------以下内容转自深蓝大神的博文-----------------------------
https://www.cnblogs.com/studyzy/p/7101136.html
CouchDB的直接查询
接下来我们使用Linux的curl来查询CouchDB数据库。
比如我们要看看mychannel数据库下有哪些数据:
curl http://192.168.100.129:5984/mychannel/_all_docs
可以看到我运行了一些ChainCode后的State DATABASE结果:
{"total_rows":7,"offset":0,"rows":[
{"id":"devinccu0000a","key":"devinccu0000a","value":{"rev":"2-a979bf6c2716ecae6d106999f833a59c"}},
{"id":"devinccu0000b","key":"devinccu0000b","value":{"rev":"2-ad1c549305fd277097180405f96bdcd8"}},
{"id":"lsccu0000devincc","key":"lsccu0000devincc","value":{"rev":"1-05d2cd0b344c4dd8a8d1a3ffd7332544"}},
{"id":"lsccu0000mycc","key":"lsccu0000mycc","value":{"rev":"1-2cba0344b1610b9d9254bbafbda5e9b1"}},
{"id":"myccu0000a","key":"myccu0000a","value":{"rev":"2-588a45b289359afa9dc6e5e7866eaf97"}},
{"id":"myccu0000b","key":"myccu0000b","value":{"rev":"2-54e6639a858b0f91298c9a354484513a"}},
{"id":"statedb_savepoint","key":"statedb_savepoint","value":{"rev":"10-6ccde2a55c71d7d6a70d9333d119fc8e"}}
]}
如果我们要查询其中的一条数据,只需要用/ChannelId/id来查询,比如查询:statedb_savepoint
curl http://192.168.100.129:5984/mychannel/statedb_savepoint
返回的结果:
{"_id":"statedb_savepoint","_rev":"10-6ccde2a55c71d7d6a70d9333d119fc8e","BlockNum":4,"TxNum":0,"UpdateSeq":"19-g1AAAAEzeJzLYWBg4MhgTmHgzcvPy09JdcjLz8gvLskBCjMlMiTJ____PyuRAYeCJAUgmWQPVsOCS40DSE08WA0jLjUJIDX1eO3KYwGSDA1ACqhsPiF1CyDq9mclsuJVdwCi7j4h8x5A1AHdx5kFAI6sYwk"}
麻烦的是业务数据是“ChainCodeNameu0000数据”这样的格式的ID,而如果我们要通过这个ID查询,那么就根本找不到啊!
curl http://192.168.100.129:5984/mychannel/myccu0000a
{"error":"not_found","reason":"missing"}
正确的做法是把u0000替换为%00,也就是说我们的查询应该是:
curl http://192.168.100.129:5984/mychannel/mycc%00a
正确返回结果:
{"_id":"myccu0000a","_rev":"2-588a45b289359afa9dc6e5e7866eaf97","chaincodeid":"mycc","version":"4:0","_attachments":{"valueBytes":{"content_type":"application/octet-stream","revpos":2,"digest":"md5-hhOYXsSeuPdXrmQ56Hm7Kg==","length":2,"stub":true}}}
Fabric可能会遇到的问题
虽然区块链是一个只能插入和查询的数据库,但是我们的业务数据是存放在State Database中的,如果我们直接修改了CouchDB的数据,那么接下来的查询和事务是直接基于修改后的CouchDB的,并不会去检查区块链中的记录,所以理论上是可以通过直接改CouchDB来实现业务数据的修改。
我们以官方的Marble为例,看看修改CouchDB会怎么样?
具体操作步骤如下:
1.Install,instantiate和初始化数据:
peer chaincode install -n marbles02 -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/marbles02 peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/cacerts/ca.example.com-cert.pem -C mychannel -n marbles02 -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/marbles02 -c '{"Args":["init"]}' -P "OR ('Org1MSP.member','Org2MSP.member')" peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/cacerts/ca.example.com-cert.pem -C mychannel -n marbles02 -c '{"Args":["initMarble","marble2","red","50","tom"]}' peer chaincode query -C mychannel -n marbles02 -c '{"Args":["readMarble","marble2"]}'
我们可以看到通过curl直接查询CouchDB中的数据:
curl http://192.168.100.129:5984/mychannel/marbles02%00marble2
{"_id":"marbles02u0000marble2","_rev":"1-a1844f47b9ed94294b430c9a9a6f543b","chaincodeid":"marbles02","data":{"docType":"marble","name":"marble2","color":"red","size":50,"owner":"tom"},"version":"6:0"}
如果我们要修改其中的数据,把颜色改成green,大小改成10,那么我们可以运行:
curl -X PUT http://192.168.100.129:5984/mychannel/marbles02%00marble2 -d '{"_id":"marbles02u0000marble2","_rev":"1-a1844f47b9ed94294b430c9a9a6f543b","chaincodeid":"marbles02","data":{"docType":"marble","name":"marble2","color":"green","size":10,"owner":"tom"},"version":"6:0"}'
系统返回结果:
{"ok":true,"id":"marbles02u0000marble2","rev":"2-6ffc6652cfc707f8352a5f06c3ce1ce6"}
我们在4个CouchDB中都运行这个命令,把4个数据库的数据都改了。
接下来我们通过ChainCode来查询,看看会怎么样。
peer chaincode query -C mychannel -n marbles02 -c '{"Args":["readMarble","marble2"]}'
返回结果:
Query Result: {"color":"green","docType":"marble","name":"marble2","owner":"tom","size":10}
可以看到数据已经变成新的值,那么接下来运行其他的Transaction会怎么样?我们试一试转账操作:
peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/cacerts/ca.example.com-cert.pem -C mychannel -n marbles02 -c '{"Args":["transferMarble","marble2","jerry"]}'
系统返回成功,我们再查一下呢
peer chaincode query -C mychannel -n marbles02 -c '{"Args":["readMarble","marble2"]}'
Query Result: {"color":"green","docType":"marble","name":"marble2","owner":"jerry","size":10}
所以我们对CouchDB数据库的更改都是有效的,在Fabric看来似乎并不知道我们改了CouchDB的内容。