flickr 的全局主键生成方案
类似于京东的数据库设计,我们的用户分库有 Shop_1/2/3/4 … 那么uid怎样生成?
现在的做法是在用一张索引表 Shop_share.user_index 取其自增主键,insert_id 便是uid。但缺点是,有单点负载的风险。
flickr提供了一个扩展的更好的方案: 他们把 user_index 抽出一个专门用作生成 uid 的表,例如取名叫 uid_sequence,并拆成若干的字表,自增步长设置为2(机器数目),这两张表可以放在不同的物理机器上。 其中一个表负责生成奇数uid,另一个负责生成偶数uid
uid_sequence 表的设计
比如创建64位的自增id:
CREATE TABLE `uid_sequence` (
`id` bigint(20) unsigned NOT NULL auto_increment,
`stub` char(1) NOT NULL default '',
PRIMARY KEY (`id`),
UNIQUE KEY `stub` (`stub`)
) ENGINE=MyISAM;
SELECT * from uid_sequence 输出:
+-------------------+------+
| id | stub |
+-------------------+------+
| 72157623227190423 | a |
如果我需要一个全局的唯一的64位uid,则执行:
REPLACE INTO uid_sequence (stub) VALUES ('a');
SELECT LAST_INSERT_ID();
- 用 REPLACE INTO 代替 INSERT INTO 的好处是避免表行数太大,还要另外定期清理。
- stub 字段要设为唯一索引,这个 sequence 表只有一条纪录,但也可以同时为多张表生成全局主键,例如 user_ship_id。除非你需要表的主键是连续的,那么就另建一个 user_ship_id_sequence 表。
- 经过实际对比测试,使用 MyISAM 比 Innodb 有更高的性能。
这里flickr使用两台数据库作为自增序列生成,通过这两台机器做主备和负载均衡。
TicketServer1:
auto-increment-increment = 2
auto-increment-offset = 1
TicketServer2:
auto-increment-increment = 2
auto-increment-offset = 2
MySQL 中 last_insert_id() 的并发问题
因为是两条SQL语句,所以这两条语句之间会不会有并发问题?
答案是不会,因为 last_insert_id() 是 Connection 级别的,是单个连接客户端里执行的insert语句最近一条,客户端之间是不会影响,没必要锁定和事务处理。