莫名奇妙的接手了区块链业务的探索,技术栈选型就成了当务之急。这篇随便,因为是探讨技术选型,所以我略过业务的部分,也跳过区块链的一些列的科普,比如Merkle根和pbft之类,而是简单记录我在技术选型上的分支探索的笔记和当前技术水平下的一些思考,以便日后回溯和复盘。
技术需求:利用区块链技术实现一个安全不可篡改多备份的分布式数据库,去保存一些高价值数据
好吧,不提这个需求是否符合区块链的“核心价值观”,组织说已经决定,就这么做吧。 对于这个需求,主流的两个技术选型,一是fabric, 利用它的key value数据库,然后一切的trick集中在如何巧妙的设计key,以便后续查询可以优化。另一个思路是以太坊搭建一个Dapp, 搞定这个需求也是有可行性,可是感觉又要去研究solidity,脑壳疼。 我抱怨了一波,不就是存个数据,你搭建个私有git不就结了,非要区块链么。。。。
查阅资料,突然发现有一个东西,可以很好的匹配上述的需求,那就是IPFS (星际文件系统)。IPFS是p2p文件共享系统,远景宏达,旨在从根本上改变信息在全球及全球范围内分发的方式,可以说最终期望取代http协议。不讨论它的终极野心,从技术看,类似于区块链,它也是一组技术的综合体,包括BitTorrent, git ,分布式哈希表,自验证文件系统,Merkle DAG/Tree。 (注:分割线之间的内容大量引自参考文献[1])
HTTP非常适合加载网站,但它并不是为传输大量数据(例如音频和视频文件)而设计的。这些限制可能使替代文件共享系统(如Napster(音乐)和BitTorrent(电影以及几乎所有东西))的出现和主流成功。IPFS尝试通过新颖的p2p文件共享系统解决客户端-服务器模型和HTTP Web的缺陷。
流行的文件共享系统Bittorrent能够依靠创新的数据交换协议成功地协调数百万个节点之间的数据传输,但仅限于torrent生态系统。IPFS实现了该协议的通用版本,称为BitSwap,它可作为任何类型的数据的市场。
merkle DAG是Merkle树和有向无环图(DAG)的混合。默克尔树可确保在p2p网络上交换的数据块是正确,未损坏和未更改的。通过使用密码哈希函数组织数据块来完成此验证。这只是一个接受输入并计算与该输入相对应的唯一字母数字字符串(哈希)的函数。容易检查输入是否会导致给定的哈希,但是很难从哈希中猜测输入。 Merkle DAG结构的另一个强大功能是,它允许您构建分布式版本控制系统(VCS)。最受欢迎的示例是Github,它使开发人员可以轻松地同时在项目上进行协作。Github上的文件使用merkle DAG存储和版本控制。它允许用户独立地复制和编辑文件的多个版本,存储这些版本,然后将编辑内容与原始文件合并。
IPFS的另一个基本组成部分是自认证文件系统(SFS)。它是一种分布式文件系统,不需要特殊权限即可进行数据交换。这是“自我认证”,因为提供给客户端的数据通过文件名(由服务器签名)进行认证。(隐患:您可以通过本地存储的透明性来安全地访问远程内容。) IPFS在此概念的基础上创建了行星际名称空间(IPNS)。它是一个使用公用密钥加密技术对网络用户发布的对象进行自我认证的SFS 。IPFS上的所有对象都可以唯一标识,但这也扩展到了节点。网络上的每个节点都有一组公用密钥,专用密钥和一个节点ID,该ID是其公用密钥的哈希。因此,节点可以使用其私钥对发布的任何数据对象进行“签名”,并且可以使用发送者的公钥来验证此数据的真实性。
那么,为什么所有这些都很重要?
IPFS提供高吞吐量,低延迟,数据分发。它也是分散和安全的。这打开了几个有趣且令人兴奋的用例。它可用于将内容传送到网站,使用自动版本控制和备份在全球存储文件,促进安全的文件共享和加密的通信。
结束了IPFS的科普之后,我就在想,我能否基于ipfs搭建一个私网,这样就可以完美解决需求。操作如下;(以下内容大量参考文献[2])
1) 搭建一个ipfs节点:
# 拉取go-ipfs镜像
docker pull ipfs/go-ipfs:latest
# 配置staging和data的volume映射文件
ipfs_staging=/tmp/ipfs_staging
mkdir -p $ipfs_staging
ipfs_data=/tmp/ipfs_data
mkdir -p $ipfs_data
# 启动ipfs节点
docker run -d --name ipfs_host \
-v $ipfs_staging:/export \
-v $ipfs_data:/data/ipfs \
-p 4001:4001 \
-p 127.0.0.1:8080:8080 \
-p 127.0.0.1:5001:5001 \
ipfs/go-ipfs:latest
启动docker : docker logs -f ipfs_host
在浏览器地址栏输入这个地址 http://localhost:5001/webui ,会自动跳转到ipfs的explorer的web ui界面。
2) 搭建单节点私网, 生成swarm key
# 关闭前面启动的ipfs节点
docker stop ipfs_host
docker rm -f ipfs_host
# 配置staging和data的volume映射文件
ipfs_staging=/tmp/ipfs_staging
mkdir -p $ipfs_staging
ipfs_data=/tmp/ipfs_data
mkdir -p $ipfs_data
# 拉取ipfs swarm key工具 ,也可以直接用
go get github.com/Kubuxu/go-ipfs-swarm-key-gen/ipfs-swarm-key-gen
# 生成swarm key
$GOPATH/bin/ipfs-swarm-key-gen > $ipfs_data/swarm.key
# 启动ipfs节点
docker run -d --name ipfs_host \
-v $ipfs_staging:/export \
-v $ipfs_data:/data/ipfs \
-p 4001:4001 \
-p 127.0.0.1:8080:8080 \
-p 127.0.0.1:5001:5001 \
ipfs/go-ipfs:latest
之后,移除默认的bootstrap
docker exec ipfs_host ipfs bootstrap rm --all
3) 添加新的节点
第一个私有节点启动后,可以再添加若干个新的节点,这样一个多节点的IPFS私有网络就搭好了。添加新节点时要注意:1)在添加新节点的之前,要把前面生成的swarm key复制到ipfs_data目录下;2)在新节点启动后,要指定bootstrap信息。
new_peer_suffix=_1
ipfs_staging=/tmp/ipfs_staging$new_peer_suffix
mkdir -p $ipfs_staging
ipfs_data=/tmp/ipfs_data$new_peer_suffix
mkdir -p $ipfs_data
cp /tmp/ipfs_data/swarm.key $ipfs_data/swarm.key
# 启动ipfs节点
docker run -d --name ipfs_host$new_peer_suffix \
-v $ipfs_staging:/export \
-v $ipfs_data:/data/ipfs \
-p 4101:4001 \
-p 127.0.0.1:8180:8080 \
-p 127.0.0.1:5101:5001 \
ipfs/go-ipfs:latest
当然,2和3的整个过程也可以写个脚本搞定,start.sh 注意后面要有个参数,值为启动的节点数目 ,stop.sh也可以写一个,就是前面的docker stop, docker rm, 比较简单,就不赘述了。
#!/bin/bash
function bootIpfsPeer {
index=$1
hostName=ipfs_host_${index}
ipfs_staging=/tmp/ipfs_staging_${index}
rm -rf $ipfs_staging
mkdir -p $ipfs_staging
ipfs_data=/tmp/ipfs_data_${index}
rm -rf $ipfs_data
mkdir -p $ipfs_data
cp ./data/swarm.key $ipfs_data
echo "Creating ${hostName} ..."
sudo docker run -d --name ${hostName} \
-v ${ipfs_staging}:/export \
-v ${ipfs_data}:/data/ipfs \
-p $((4001 + index*10)):4001 \
-p $((5001 + index*10)):5001 \
-p 127.0.0.1:$((8080 + index)):8080 \
ipfs/go-ipfs:latest
echo "Remove bootstrap for ${hostName} ..."
docker exec ${hostName} ipfs bootstrap rm --all
}
function setupIpfsNetwork {
for (( i=0; i<$1; i++ ))
do
bootIpfsPeer ${i}
done
}
function createSwarmKey {
rm -rf ./data
mkdir -p ./data
cp ./swarm.key ./data/swarm.key
}
function rmIpfsHosts {
dockerContainers=$(docker ps -a | awk '$2~/ipfs/ {print $1}')
if [ "$dockerContainers" != "" ]; then
echo "Deleting existing docker containers ..."
docker rm -f $dockerContainers
fi
}
function showResult {
docker ps -a
}
function main {
rmIpfsHosts
createSwarmKey
setupIpfsNetwork $1
showResult
}
if [ "$#" -ne 1 ]; then
echo "ERROR: Peers number must be set for private ipfs network"
echo "usage: start.sh \${peerNumber}"
echo "For example: Run this command"
echo " ./start.sh 3"
echo " A private ipfs network with 3 peers will be setup locally"
exit 1
else
main $1
fi
4) 网络搭建完毕,终于到了可以测试的时候了
首先,进入一个节点
docker exec -it ipfs_host /bin/sh
# 上传文件,文件各种格式都支持,你大可以传个图片啥的,这里当然是使用新手必备hello world
echo "hello world" > hello.txt
ipfs add hello.txt
然后那个 hash码就成了这个文件的唯一标识。。。。各种查看方法,比如ipfs cat,或者浏览器 查看http://localhost:8080/ipfs/[------IPFS_URL-----]
那么问题来了, 一通操作猛如虎,需求满足了么?
首先,安全性,私网都用一个swarm key, 分发和管理秘钥就是个严重的问题
其次,批量的查询,如果不做个缓存的中间层索引,还是0
最后,身份管理,权限管理啊这些最重要的部分,目前看来都没有直接的解决方案
总体看来,想搭建一个ipfs私网就解决问题,看来行不通。还是得fabric搭建联盟链。但是ipfs作为链上链下的解决方案的数据层,似乎很有潜力。
参考文献:
1)IPFS星际大陆,《最全解析:一文入门IPFS》,https://www.8btc.com/media/572061
2) 安心读书,《MAC上搭建私有IPFS网络》,https://blog.csdn.net/weixin_41459401/article/details/84563258
网友评论