高并发网站如何解决数据库主键自增的时候出现重复?

WBOY
Release: 2016-06-17 08:30:44
Original
2553 people have browsed it

这种问题应该在各种流量极大的微博,论坛,贴吧等地方都会碰到的吧!

回复内容:

全局id生成器。
我们日订单也有一万,说多不多说少不少,当然比起贴吧微博不在一个量级。
改天介绍一下

--------------------------2015/5/27
1 设置主键自增为何不可取
这样的话,数据库本身是单点,不可拆库,因为id会重复。

2 依赖数据库自增机制达到全局ID唯一
使用如下语句:
REPLACE INTO Tickets64 (stub) VALUES ('a');
SELECT LAST_INSERT_ID();
这样可以保证全局ID唯一,但这个Tickets64表依旧是个单点。

3 依赖数据库自增机制达到全局ID唯一并消除单点
在2的基础上,部署两个(多个)数据库实例,
设置自增步长为2(多个则为实例数),即auto-increment-increment = 2
设置auto-increment-offset分别为1,2.....
这样第一台数据库服务器的自增id为 1 3 5 7 9
第二台为2 4 6 8 10

4 解决每次请求全局ID都读库写库压力过大的问题
比如第一次启动业务服务,会请求一个唯一id为3559
如果是2、3的方法,则id为3559,这样每次都请求数据库,对数据库压力比较大
可以用3559 * 65536(举个例子,并不一定是65536)+ 内存自增变量来作为id
当内存自增变量到达65535时,从数据库重新获取一个自增id
这样即使有多台业务服务器,id也不会重复:
第一台 3559 * 65536 + 1,2,3.....65535
第二台 3560 * 65536 + 1,2,3.....65535
然后第一台到65535了,换一个数据库自增id,这时候可能是3561 * 65536 + 1,2,3....

我们目前采用4 Sharding & IDs at Instagram
里面提到instagram是怎么生成uuid的,微信朋友圈也是用类似的方法。

里面提到了这个服务 twitter/snowflake · GitHub用于生成uuid. 很多方法,举几个栗子:

1、用UUID而非自增字段。这个主要的阻碍在于编程麻烦一点,很多框架不支持,程序员的智力理解不了的也遇到过。另外UUID不可迷信,其实也有出现过UUID撞车的。
2、全局用一个唯一id生成服务,Google公开的架构文档,有介绍他们用一个单独的oracle节点生成全局唯一自增id。买个 Oracle 就为了一个 sequnece ,这脑洞也确实有点大。有钱任性。
3、用一些协商算法,保证每个节点的自增id跟别的节点不冲突。缺点是很难找到一个扩展性良好的算法。 说到GUID占用空间比较大,我也觉得的确应该找个方法弄一下,于是用Go语言写了个函数放到Github上了,etworker/idxgen · GitHub

目的就是将每个字符的可选范围从GUID的[0-9a-z]只有16个,变成[0-9a-zA-Z_-]共64个。

权衡之后,选择了8位长度,虽然空间比GUID的小很多,但是实测效果还行,测试时候跑了几个1千万的生成,在我的破笔记本上耗时约30s,偶尔会有1次重复。如果担心唯一性的,就自己实现里面的IsUniqueIdx()函数就可以了。

对了,我把这个东西塞进Docker,部署到云雀里面了,地址是idxgen-etworker.alaudacn.me:49662,刷新一次就出来一个新的ID,不妨试试。 Snowflake 主要思路就是“怎么在短时间内生成多个ID不重复”。
利用数据库写入时的自增能实现不重复,但是由于并发量过大会造成延时;
将自增的量直接写在内存或缓存中能加快生成速度,但是可能会掉电丢失,因此可以定时写入数据库中或者文件中(写入时还要对比递增中的和库中的,取大者);
为了保险起见,防止上述情况失效,再在ID中加一个时间,现在一般也就精确到微秒吧,也就是时间(微秒级)+自增因子
如果为了应付更大访问,或者容灾,或者分布式,再加一个机器标志位,也就是机器标志+时间(微秒级)+自增因子
我们现在用这个方案来生成1000个/s左右并发量的ID,算是一个比较稳定安全的方案。
当然,各个位置的长度要考虑数据的量,保存的时间等。如果像淘宝这种,肯定是用户ID+购物记录ID+时间等各个组合成一个购买记录的ID的。毕竟数据量太大了 Ticket Servers: Distributed Unique Primary Keys on the Cheap 如果自增主键都能出现重复,只能说你的代码有个天大的bug。 我们基本都用guid,guid算法的实现各个版本略有不同,不过应该不用担心撞车的问题。guid就是比较占地方。 擦,解决不了就慢慢来,也不至于把所有数据库都删了啊!
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template