浅谈云原生数据库

云原生数据库shared-nothing算存分离… 这些概念性的东西,网上资料一大把,看完以后感觉懂了,但是尝试用自己的话复述出来时,又感觉没懂。

为什么会有这种感觉呢?我觉得原因在于看完了网上的资料,我知道了what;但是很多资料并没有解释why,所以我无法把知识转变成自己的,也就无法用自己的语言把这些概念解释一遍。只有搞清楚为什么会出现这种设计,才能够消化知识,只知道what的话,只能靠死记硬背才能“掌握”知识。

这张图来自于李飞飞的一片文章,介绍了数据库的过去和未来。我尝试在这张图的基础上补充自己的理解:

单机数据库

经常听到说传统单机数据库是一种shared-everything的架构,怎么理解呢?实际上这里的everything指的是冯·诺依曼架构中的「计算」和「存储」,而shared指的是单机数据库可以随意使用本地的所有「计算」和「存储」资源。

分布式数据库

很快,单机数据库就面临着可扩展性问题,这时就需要通过加资源的方式解决,于是出现了两种解决方案:Scale up和Scale out。

这里Scale up并不是指单机维度的scale up,而是从资源视角的scale up,更具体地说,也就是存储池化:数据库的底层存储由原来的单机磁盘(磁盘阵列)、单机文件系统,演变为基于分布式块存储、分布式文件存储、对象存储等的shared-storage分布式数据库。

Scale out则是各个数据库实例独立运行,实例之间通过raft/paxos等共识算法实现数据同步,而不依赖底层的分布式存储系统。这就是所谓的shared-nothing分布式数据库,数据库不共享任何IaaS层的资源,完全依赖于PaaS层(DB)本身,去做高可用和强一致,实现分布式事务。

云原生数据库

云原生数据库 = 分布式数据库(scale out) + 资源池化(scale up)

云原生 = 云 + 原生。「云」就代表着IaaS资源池化,「原生」意味着应用(PaaS、SaaS)天然就是针对这种池化的特性进行设计的。

现在的分布式数据库大多是shared-nothing的,例如tidb和ob,使用了本地盘。一旦使用本地盘,就意味着上云很困难,因为云的特性就是资源池化,公有云厂商一般会提供网络存储而非本地存储。而云盘的性能没有本地盘好,这就要求应用层,也就是DB这一层,是面向公有云的基础服务进行设计的。这就是云原生的数据库,即在数据库设计的时候,就考虑各种资源是在云上,以池化的方式提供。这种方式意味着shared-nothingshared-everything 的结合:宏观上看,是shared-everything的,计算和存储层由云厂商提供资源池的抽象(未来甚至内存也可能会池化),但从单机角度看,实际上各个实例又是分布式的,shared-nothing

这是算存分离的终态:在单机部署情况下,通信就是计算通过 Memory Bus、IO Bus和内存、存储通信。但在集群部署的情况下,计算和存储的通信就是网络。数据库刚诞生的年代,单机的存储访问速度肯定要快于集群,但是随着网络、存储等基础设施的不断发展,未来这个情况可能就不一定了,池化资源,云原生,是数据库和其他上层应用未来的趋势。

分布式数据库上云

为了追求极致性能,分布式数据库一般会直接部署在物理机甚至定制化的裸金属机上,而不是基于云基础设施。将分布式数据库上云,并依托k8s进行管理,可以看成是云原生数据库的一种过渡形态。

如果使用本地存储,分布式数据库在用k8s进行管理的时候有些水土不服:不支持垂直动态伸缩、节点下线需要迁移数据。如果使用网络存储,就要面对性能和延迟抖动等问题。现有的云原生数据库(比如snowflake)一般都是面向OLAP的数据仓库,原因在于数据仓库对于吞吐的要求其实是更高的,对于延迟并不是那么在意,一个 query 可能跑五秒出结果就行了,不用要求五毫秒之内给出结果。