传统的中心化“云存储”存在很多问题,运用“分布式存储网络IPFS+区块链” 或许可以解决区块链天然不易存储大文件的问题。本文源于京东金融区块链实验室技术专家李冠男分享的《基于Fabric的存储扩展实践》的主题演讲,在实践的过程中,他提出了三个设计方案,希望能给大家一点启发。
以下是李冠男的分享,由整理。
大家都知道,区块链的故事开始于2008年中本聪发表《一种点对点的电子现金系统》,之后比特币横空出世。后来又出现了以太坊,随着市场热度的高涨,人们发现了区块链技术本身的应用价值,各种项目层出不穷,但是这其中的很多场景需要区块链具备文件存储能力。
一般来讲,大家的第一反应是,我能不能把数据都存储在链上?但是现有的主流区块链,比特币就不用说了,以太坊上面存数据是非常昂贵的,按照Gas数据是5Gwei计算,存储1MB数据需要花费3.76ETH。HyperLedger Fabric因为是联盟链,把数据硬要存在上面也是可以的,但现在有个写死的限制,默认数据小于99M,如果大于的话,需要重新编译它的代码。
所以可以看到,数据全部上链并不明智,也没有必要像存储交易数据一样,让千百兆的数据文件存储在每一个节点上。所以通常的做法是: 将文件存储在链外,在链上存储文件的hash ,这样文件其实依然是中心化存储,比如传统的“云存储“。
当前多采用的中心化“云存储”
什么是“云存储”?
传统云存储是让用户上传自己的数据到云端,用户上传完毕后,由服务提供商将数据保存在他们的数据中心。这样用户无论何时何地想要访问这些信息的时候,只需要向数据中心发送一条请求,数据中心将数据发给用户。
中心化的“云存储”存在以下问题:
典型的问题是数据中心都是大型服务器,它需要温控,并且严格维护,成本高昂,而且会有延迟,因为通常数据中心与用户不会距离很近。有人说,可以使用CDN,但问题是它的隐私策略是由服务提供商设计的,他们依然有办法访问和分享用户的个人数据,毕竟是不透明的。而且除了作恶的可能,只要有人工牵扯进去,就很可能会有意外的错误。比如员工误删数据库的事件并不罕见,GitLab事件让人记忆犹新…
采用“分布式存储网络”优点众多
所以我们需要采用分布式存储网络。这个技术并不新鲜,它有很多优点,存储的文件大小不受限制,可以无限扩展存储容量,而且成本低,不受地域限制,还是去中心化的,如果应用特点的技术,也可以保证它的内容不被篡改。
如果将“分布式存储网络”和“区块链”技术结合起来,是不是就可以解决区块链天然不易存储大文件的这种问题?
我选用的就是IPFS技术,中文叫做星际文件系统。
分布式存储IPFS——What?How?
IPFS是什么?
IPFS是分布式存储网络;
IPFS是一个点对点的超媒体协议,目的是让现有的网络更快、更安全、更开放;
IPFS有一个很疯狂的目标:致力于替代HTTP协议,为所有人建造一 个更好的网络 ;
那么它有什么特点呢?
首先,存储在IPFS上的文件,是被打散存储的。就是说每个文件以及所有的文件块都有独一无二的指纹,这个指纹就是一个加密哈希值。其次,IPFS网络可以自动去除重复文件,也可以跟踪每个文件的版本历史 。而且每个网络节点只需要存储自己感兴趣的内容以及一些索引信息,这些索引信息的作用就是用来找到谁存储了什么 。当查找文件的时候,你可以使用Hash询问IPFS网络哪些节点存储了什么内容。最后,每个文件可以通过去中心化的命名系统IPNS获得对人友好的名字 而不是一串看花眼的hash。
IPFS技术栈分为这么几层:
最底层当然是网络、然后是路由、交换层、特定的结构层、Merkledag、命名系统,最上面是应用。IPFS和区块链一样,是技术集大成者,它借鉴了很多相关的技术。最下面三层的作用是转移数据,往上的两层是定义数据,最上面当然就是使用数据了。
在介绍完基础工具后,正式讲解我的尝试。
基于Fabric的存储扩展实践
首先,我明确了三个目标:
1.我希望Fabric能够暴露出 一组接口,使得外部可以通过Fabric使用IPFS;
2.我希望接下来Chaincode可以在有需要时也可以直接使用IPFS这个功能;
3.我希望这个过程中尽量少的修改现有Fabric代码。换句话说,我希望这是一种系统的能力,而不是一种特定的应用层手段。
目标摆在这儿了,最直接的方式是以现有的go-sdk作为粘合剂,将Fabric和IPFS联合起来。
最开始的想法是:对go-sdk进行二次开发,把与IPFS交互的逻辑封装其中,实际上在使用过程中,由sdk先请求 IPFS得到返回,再将返回结果作为交易内容写入Fabric ,和大部分现在的用法是一样的。
另外IPFS有的几个特点需要注意:一是它有自己的垃圾回收机制,当你写入某个节点的数据,只有经过称为“pin”的操作才能保证不被回收掉。二是不同节点之间不会自动备份同步数据,除非主动发起请求 。
基于这些想法,就诞生了第一个方案:
方案一
很简单,通过sdk改造一下,用sdk去操作IPFS网络。把这个文件添加pin之后得到哈希返回,然后把哈希值封装到一般的交易里面,再提交给FabriC网络。
这个方案有几个明显特点: 首先,IPFS与Fabric是相互独立的,没有直接的交互。IPFS作为外部系统由sdk调用 ,这样做的优点是完全不用修改Fabric代码和内部流程。但缺点是,今后办法直接使用IPFS的。
我们来看看Fabric 的Chaincode 的是怎么工作的?大家都知道Chaincode是运行在docker容器中的,它和peer是通过GRPC通信的。
通常,Chaincode首先需要注册,注册之后初始化,然后才能运行存储信息这样的操作,再往后就是一些判活操作了。但是这种交互它其实有一个中间层,是通过Shim组件去交互的,Shim中的 chaincodeStubInterface 定义了在chaincode中可以使用的功能。 所以我就诞生了第二个想法,若是想 chaincode使用IPFS,对shim进行扩展来实现。
方案二
这个方案的想法就是先去扩展shim.ChaincodeStubInterface,添加实现相应的功能函数,光添加函数肯定不行,还需要在Fabric内开辟一个模块,专门用来处理IPFS相关的请求,这样就可以像调用GetState/PutState一样调用类似GetFile/PutFile的函数来获取/存储文件了。
这个方案里,peer是Chaincode 的代理,可以与IPFS网络直接去交互。整个想法其实很简单,但真正实现过程中,我发现并不容易,因为需要修改Fabric的很多代码,另外这个方案仍然是需要应用去主动维护文件的状态。IPFS网络节点是不会主动去备份这些文件的。跟第一个方案相比,它已经实现了让Chaincode直接使用IPFS,虽然缺点很多,但看上去方向应该没错。
这个时候我刚好注意到,Fabric1.2中有一个不错的特性,这也得益于它的架构设计,一切设计都是可插拔的。Fabric1.2中系统链码会在每个新创建的channel自动部署一套 ,并且不同的channel之间实现了隔离。所以我们跳出来看,让chaincode使用IPFS,即让chaincode调用外部的途径都有什么呢? 可不可以借助Fabric系统可插拔的特性去实现这个功能呢?我看到ChaincodeStubInterface中有一个功能函数叫InvokeChaincode,这个功能很好,它可以让一个Chaincode去调用另一个Chaincode,这让我想到了第三个方案。
方案三
我完全可以把与IPFS交互的逻辑包装成一个系统代码,然后应用可插拔特性把它集成进去。然后就可以用InvokeChain怎么登陆火币网code的功能,获得相应的能力。而且好处还不少。首先它可以单独维护,修改和升级都很方便。User Chaincode可以通过我刚说的这个功能,调用IPFScc来使用IPFS,也不用修改代码,并且可以把文件索引存储在IPFScc namespace中,这样由系统实现文件状态监控也可行了 。
而且我可以其实灵活一些,把方案一里的办法集成进来,让sdk去开发一组接口,让它可以和IPFS网络进行交互,得到的hash上传到账本里也是可以的。
还有最后一个问题就是刚才提到的,把文件上传进去之后,如果你不去操作的话,它不会主动备份。这个问题怎么解决?最后我是通过IPFS-cluster,它有自己提供的共识机制,而且能自动备份IPFS网络中的文件,还可以灵活配置备份数量。
这样的话流程就比较清楚了。我可以通过Sdk/CLI上传文件/由chaincode 根据需要在peer端临时生成文件并上载IPFS网络,得到返回hash,通过IPFS- cluster pin 文件,成功后将文件信息及相关IPFS 索引信息写入IPFScc的ledger 。这样的话其实应用的空间也就被打开了。
以上就是我做的实践尝试,这个方案也不完美,但是希望整个过程能给大家带来一些启发。
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。