当前位置: 首页 > 科技观察

id是用单个数据库自增key生成的,后面怎么分库?哎,这个坑好大啊!

时间:2023-03-14 18:40:54 科技观察

星球水友“coder”提问:沉老师,我们的用户中心是单库单表。uid使用数据库自??增主键。uid与许多业务相关联,无法更改。现在用户中心的数据量在逐渐增加,需要分库。如何从单个数据库升级到多个数据库,保持历史uid不变,新生成的数据不冲突。有什么好办法吗?==问题描述结束==应该有很多公司是用数据库“插入数据自动增加id”作为业务id的。这种方式会使业务和id生成强耦合,导致id生成算法难以升级。今天就和大家简单探讨下id生成应该考虑哪些要素。画外音:别误会,不是“自增id”不好,而是它与业务耦合,很难升级。1、id生成需要考虑的技术点几乎所有的业务都会有一个唯一的业务标识:用户ID:uid(user-id)消息ID:mid(msg-id)订单ID:oid(order-id)在存储中system,一般是主键,主键使用聚集索引(clustered-index),即在物理存储上按这个id排序。所以,对这个id有要求:唯一性,有递增趋势。画外音:索引《1分钟了解不同索引的差异》。这个标识也经常用于流量负载均衡和数据负载均衡的基础,即id在统计上必须是完全随机的。所以对这个id有一个要求:随机性。同时,id生成算法升级理论上对业务系统是透明的。因此,这个id的生成有:独立性要求。为了保证生成id的上述特性,必须要有uint64_tGenID()这个独立的方法(或独立接口)来生成id,生成id的目的是什么,这个方法无所谓,可以作为uid,或者它可以用来做oid,甚至是log-id。当然,业务不需要关心id生成的具体细节。即GenID()内部实现可以使用数据库的自增id,也可以使用时间自增。目前业界最流行的是像snowflake一样生成分布式id。这种封装屏蔽了id生成的细节,保留了程序升级的可能性,是系统设计上解耦的体现。如果采用这种方式生成业务ID,数据库很容易从单库扩展到多库:确定路由算法,如hash取模;通过这种路由算法将单个数据库中的数据迁移到多个数据库中,以减少单个数据库中的数据量;使用此路由算法查找数据(读取);使用此路由算法插入数据(写入);如果架构设计事先没有考虑独立id生成,后期实现单库拆多库,怎么办?2.对于星球水友提到的例子,已经形成了历史坑。没有解耦id的生成方式,也没有办法批量修改id。我应该怎么办?假设单库拆成3个库,可以这样玩:做一个1主2从的数据库集群,相当于把每条数据复制成3份;设置路由算法为模散列算法,%3;第一个库,%3=0,删除剩余1个和剩余2个的uid;第二库,%3=1,删除剩余0和剩余2的uid;第三库,%3=2,删除剩余0的uid,剩余1删除uid;设置每个库的自增步长为3,这样每个库的id生成就不会重复;升级用户中心,根据路由算法查询uid数据;done,拆库扩容:单库数据量减少到原来的1/3;读写实例数扩大到??原来的3倍;而且id的生成和查询不会冲突;我希望这个棘手的方法可以帮助你。但是希望大家事先考虑到id生成的唯一性、随机性、递增趋势、独立性。系统地考虑问题,知其然,知其所以然。【本文为专栏作者《58神剑》原创稿件,转载请联系原作者】点此阅读更多该作者好文