也谈分布式数据库部署:主键的类型以及生成方式的选择
也谈分布式数据库部署:主键的类型以及生成方式的选择
最近遇到给数据库做“分布式”的需求,期间遇到数据库主键的生成问题。
先说说数据库“分布式”部署,我所遇到的数据库分布式部署方式主要有两种:
1.读写分离: www.zzzyk.com
即Insert、Update、Delete操作都针对主库,然后通过推送或者订阅的方式与多个从库同步,大量的查询都查询从库。
这是一种较常见的“分布式”部署方式,能较好的分散查询压力。对于写少读多的系统是非常有效的提高性能的方式。
2.分布式存储:(如将订单表分拆为多个分表部署到多个服务器上,且每个表都可以进行写操作)
相对上一种,这种部署方式,主要针对写操作并发量较大的的系统,比如微博、淘宝的订单系统等等。
无论是哪种“分布式”部署方式,其中都会遇到一个问题,即“主键的类型以及生成方式的选择”。
先说类型的选择,主要有两种:数字类型、GUID。
我们从唯一性、可同步性、高效性、存储空间大小、体验友好性 几点来分析:(可能不是很准确,但是相对来讲,可供参考)
1.从唯一性、可同步性上来说,当然是GUID完胜。
2.从高效性、存储空间大小、体验友好性来看,数字类型则更胜一筹。
我的选择:
1.本人有些许洁癖,所以自然觉得数字类型更友好,如果一个页面有N个参数(可以看下淘宝的搜索),都是GUID的话,那会非常的不爽。
2.开发过程中免不了与一些其他的系统对接,相当多的系统的主键都是用数字作为主键的。(上次与一淘对接时就被拒之门外了!人家要求编号必须要是数字)
3.唯一性、可同步性方面也是可以想办法弥补的。
4.观微博ID、淘宝订单号等这些超级分布式系统中的主键,几乎均为数字类型。
所以综上,我选择了使用数字类型来作为我分布式部署中数据库的主键。
www.zzzyk.com
既然做了选择,那就想办法弥补数字类型作为主键的不足就好了,上面分析数字主键主要存在唯一性、可同步性两个方面的不足。
可同步性:这个主要是针对自增ID作为主键,这个好说,不用自增就好了。
唯一性:主要难点就体现在唯一性上,下面就来讲讲如何实现唯一性。
第一步:我想到的也是比较主流的一种方法:使用一张全局的表记录所有的表名和此表主键ID的最大值。您肯定想到了,这样必然会有性能问题。那么,请看第二步→
第二步:我在此方法之上做了一些改进:在内存中做“自增操作”,当然操作中会“加锁”。您肯定又想到了,内存不安全,宕机了咋办?那么请看第三步→
第三步:宕机了?肯定要重启吧,系统重启时,查一下所有的表的主键最大值,将第一步中的“全局表”再初始化一下就好了。
OK,唯一性(全局加锁自增)、性能(内存操作)都基本搞定,问题基本解决。
好像还有点不对劲,为啥要用“基本”搞定,“基本”解决呢?您还想到什么问题了么?
对了,当并发灰常大的时候,这种“全局 内存 加锁 自增”的方式也会遭遇性能瓶颈。那么我们就再改进改进。
www.zzzyk.com
注:这就是为什么说好的系统不是开发出来的,而是长期改出来的!我想上面的三步,基本上可以解决较大系统的需求,如果还是遭遇性能瓶颈,那么请往下看→
对于性能问题,我觉得最好的方式之一就是“分”,那我们就看看怎么个“分”法。
第四步:对于较大并发的表,我们可以分出单独的“服务”甚至物理服务器来做这个生成主键的操作。
第五步:对于把一张表分拆到N个服务器上的“分布式存储”(每张表都可以进行写操作),那么我们可以按找服务器分段的规则给每个分表分配一个单独的“服务”甚至物理服务器来做这个生成主键的操作。
好了到此为止吧,我想如果这样还是不能满足您的并发需求,我也无能为力了,期待牛人们的分享!
总结:主要就是以下四个词:①全局 ②内存 ③加锁自增 ④分
作者 FMP-FMP