数据库水平分割中的ID生成器设计
概述
ID生成器独立成一个数据库,数据库名称为:id_generator。数据库中的表设计原则是每一个表对应一个需要获取ID的外部表,不允许多个需要获取ID的外部表共用一个ID生成器里面的一个表。表名的规则是:id_[external_table_names],表的结构如:
CREATE TABLE `id_user` (
`AutoID` INT(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`AutoID`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
ROW_FORMAT=DEFAULT
AUTO_INCREMENT=1
实现原理
ID生成器的程序建立在每个应用服务器的数据访问层DAL中,也就是说每台应用服务器中的ID生成器程序都是一个独立完整体。
ID生成器中内部维护着一个“先进先出”的队列,此队列也起到缓存作用,每次调用ID生成器获取ID时,就从队列取出一个ID给调用者。
ID生成器初始化时,会先向数据库批量写入500次,然后取出最后写入的500个ID,接着写入“先进先出”的队列,供调用者使用。当队列为空了,将再次向数据库写入500次取出最后写入的500个ID写入队列,如此循环。
技术要点说明
为保证每次批量写入数据库并取出来的ID都是正确的,在批量写入数据库时需要启用数据库事务,通过数据库的事务来保证数据的正确性。
当某一个应用服务器重新启动了,ID生成器队列中维护的ID值也将会丢失,但这不会产生ID重复的情况,丢失的ID将是作废的,当ID生成器中队列为空了,会马上从数据库再次获取最新的一批ID回来供调用者使用。如果出现ID丢失的情况,表现出来的结果就是需要ID的目标表的主键ID值和表的总记录数值是不一致的,表的总记录数值将会比表的主键ID的数值小。
性能测试数据
场景一:1次获取获取500个ID和1000个ID的比较,1次就开启一个数据库的connection。
500个 |
1000个 |
60MS |
122MS |
58MS |
119MS |
63MS |
141 |
场景二:10次获取5000个ID和10000个ID的比较,分10次依次调用,顺序的开启了10个数据库的connection。
5000个 |
10000个 |
653MS |
963MS |
745MS |
875MS |
591MS |
915MS |
场景三:5个线程分别获取500个ID和1000个ID的比较,1个线程开启1个数据库的connection。
500个 |
1000个 |
143~219MS |
425~479MS |
171~225MS |
402~460MS |
165~244MS |
380~481MS |
结论
从测试的数据来看,ID生成器的性能表现还是比较理想的,而且整个方案实现起来也比较简单,维护也简单。