我对存储的一些看法


其实计算机主要分成两个部分 计算 + 存储, 存储应该是计算的基石

那么存储其实又主要分成两个部分 在线存储 + 离线存储

离线存储的需求很统一, 就是离线数据分析, 产生报表等等. 也因为这统一的需求, 所以目前hdfs 为首的离线存储基本统一了离线存储这个平台. 离线存储最重要的就是吞吐, 以及资源的利用率. 对性能, 可靠性的要求其实并不多. (所以这也是为什么java系在离线存储这块基本一统的原因, java提供的大量的基础库, 包等等. 而离线存储又对性能, 可靠性没有比较高的要求, 因此java GC等问题也不明显)

所以我们可以看到虽然现在离线的分析工具一直在变, 有hadoop, spark, storm 等等, 但是离线的存储基本都没有变化. 还是hdfs 一统这一套. 所以我认为未来离线存储这块不会有太大的变化

在线存储

指的是直接面向用户请求的存储类型. 由于用户请求的多样性, 因此在线存储通常需要满足各种不同场景的需求.

比如用户系统存储是提供对象的服务, 能够直接通过HTTP接口来访问, 那么自然就诞生了对象存储这样的服务

比如用户希望所存储的数据是关系性数据库的模型, 能够以SQL 的形式来访问, 那么其实就是mysql, 或者现在比较火热的NewSql

比如用户只希望访问key, value的形式, 那么我们就可以用最简单的kv接口, 那么就有Nosql, bada, cassandra 等等就提供这样的服务

当然也有多数据结构的请求, hash, list 等等就有了redis, 有POSIX文件系统接口了请求, 那么就有了CephFs. 有了希望提供跟磁盘一样的iSCSI 这样接口的块设备的需求, 就有了块存储, 就是ceph.

从上面可以看到和离线存储对比, 在线存储的需求更加的复杂, 从接口类型, 从对访问延期的需求, 比如对于kv的接口, 我们一般希望是2ms左右, 那么对于对象存储的接口我们一般在10ms~20ms. 对于SQL, 我们的容忍度可能更高一些, 可以允许有100 ms. 处理延迟的需求, 我们还会有数据可靠性的不同, 比如一般在SQL 里面我们一般需要做到强一致. 但是在kv接口里面我们一般只需要做到最终一致性即可. 同样对于资源的利用也是不一样, 如果存储的是稍微偏冷的数据, 一定是EC编码, 然后存在大的机械盘. 对于线上比较热的数据, 延迟要求比较高. 一定是3副本, 存在SSD盘上

从上面可以看到在线存储的需求多样性, 并且对服务的可靠性要求各种不一样, 因此我们很难看到有一个在线存储能够统一满足所有的需求. 这也是为什么现在没有一个开源的在线存储服务能够像hdfs 那样的使用率. 因此一定是在不同的场景下面有不同的存储的解决方案

可以看到Facebook infrastructure stack 里面就包含的各种的在线存储需求

Imgur

比如里面包含了热的大对象存储Haystack, 一般热的大对象存储f4, 图数据库Tao. key-value 存储memcached 集群等等

同样google 也会有不同的在线存储产品

Imgur

对应于Google 有MegaStore, Spanner 用于线上的SQL 类型的在线存储, BigTable 用于类似稀疏map 的key-value存储等等

个人认为对于在线存储还是比较适合C++来做这一套东西, 因为比较在线存储一般对性能, 可靠性, 延迟的要求比较高.

那么这些不同的存储一般都怎么实现呢?, 很多在线存储比如对象存储的实现一般都是基于底下的key-value进行封装来实现对象存储的接口. ceph 就是这方面这个做法的极致.

ceph 底下的rados 本质是一个对象存储, 这里的对象存储跟s3 的对象存储还不一样, 只是提供了存储以为key 对应的value 是对象的形式. 然后基于上层基于librados 封装了librbd 就实现了块设备的协议, 那么就是一个块存储. 基于librados 实现了Rados Gateway 提供了s3 的对象存储的协议就封装成s3对象存储. 基于librados 实现了POSIX 文件系统的接口, 就封装成了分布式文件系统Ceph FS. (不过我认为ceph 底下的rados实现的还不够纯粹, 因为rados对应的value 是类似于一个对象文件. 比如在基于librados 实现librbd的时候很多对象属性的一些方法是用不上的) Imgur

同样google 的F1 是基于spanner 的key-value 接口实现了SQL了接口. 就封装成了NewSql

因此其实我们也可以这么说对于这么多接口的实现, 其实后续都会转换成基于key-value 接口实现另一种接口的形式, 因为key-value 接口足够简单, 有了稳定的key-value 存储, 只需要在上层提供不同接口转换成key-value 接口的实现即可. 当然不同的接口实现难度还是不太一样, 比如实现SQL接口, POSIX文件系统接口, 图数据库肯定要比实现一个对象存储的接口要容易很多

未来我们应该也在朝这个方向做吧