文档章节

Ticket 服务: 一种经济的分布式唯一主键生成方案

laichendong
 laichendong
发布于 2014/06/25 09:27
字数 1870
阅读 580
收藏 7
点赞 0
评论 0
MySQL分库分表早已经不是什么新鲜话题了。甚至已经成了说到MySQL就会说到的话题。在一张表中,MySQL提供了原生的自增主键实现。但是在这样的分布式系统中,怎么保证数据在多张表上的ID是唯一的呢? Flickr提出了一个方案,将文章简单翻译一下给大家,方便大家阅读。嫌弃我翻译水平太烂的,请移步原文: http://code.flickr.net/2010/02/08/ticket-servers-distributed-unique-primary-keys-on-the-cheap/ --------------------------------------------- 我就是分割线 分割线就是我  ----------------------------------------- 这篇文章是“ 在Flickr里使用,广泛使用,扩展MySQL”系列文章的第一弹。 Ticket服务本身其实没什么好说的,但他是Flickr系统里一个重要的组成部分。是我们接下来要谈到的话题的核心,就像sharding和主主复制一样。Ticket服务器给我们提供了一个生成全局(Flickr范围内)唯一的整数的服务,这个整数用来作为我们分布式系统中的主键使用。

为什么(需要这样一种机制)?

Sharding(或者叫 data partition)(译者注:数据分片)是使我们的数据存储能力能够水平扩展的方案。我们不是将我们所有的数据都存在一个物理的数据库上,相反,我们有很多数据库,每个数据库存储一部分数据,然后我们将压力负载均衡到这些数据库上去。但在某些情况下,我们需要在不同的数据库之间进行数据合并,所以我们需要主键是全局唯一的。另外,我们的数据库sharding是基于主主复制的。这意味着我们需要保证,在一个分片内,主键也是唯一的,这样才能避免主键冲突(重复)。我们当然希望能够和其他人一样,使用MySQL的自增字段来生成主键。但是,这种方案在跨多个物理或逻辑数据库时,没有办法保证唯一性。

(使用)GUIDs(行不行)?

看来,我们就是需要一个全局唯一的id,那为什么不用GUID(译者注: GUID=Globally Unique Identifier 全局唯一标示)呢?最大的原因就是GUID太大了,而且他在MySQL中索引效果太差了。为了保证我们的MySQL足够快,我们将所有要查询的条件都索引起来,然后只在索引键上做查询。所以,索引的大小就成了一个关键性的指标。如果你不能将你的索引全部都放到内存里,那你的数据库就不可能足够快。而且,Ticket服务给我们的ID是有序的。这个特点给我们做业务报表和做调试的时候带来了很大的方便性,而且我们还可以再上面做一些缓存的优化方案。

(使用)一致性哈希(行不行)?

像  Amazon’s Dynamo和其他一些系统,在数据存储上面提供了一致性哈希环来解决GUID和分片的问题。这种方案更适合于写廉价的应用场景(比如:  LSMTs),而MySQL是一种针对随机读取专门做过优化的系统。

集中式自增

我们不能让MySQL的自增跨数据库工作,那如果我们只用一个数据库呢?假设在有人上传图片的时候,我们都往这个数据库库中插入一条数据,然后用这个表的自增主键值作为我们所有数据库的唯一主键。 在目前每秒60+张图片上传的情况下,这张表很快就会变得奇大无比。就算在中央数据库中我们只存储图片的id,而不存储其他任何信息,这张表也很快就会大到无法管理的地步。更何况图片的评论,收藏,分组,标签等等等等也都需要唯一ID。

REPLACE INTO

大约小十年前,MySQL在ANSI SQL标准上做了一个非标准的 “REPLACE INTO”扩展。虽然后来有 “INSERT ON DUPLICATE KEY UPDATE”更好的解决了这类问题,但REPLACE INTO现在仍然能用。
REPLACE和INSERT很像。除了在新插入的行中主键或唯一所以中的值在表中已经存在的情况下,会先删除老的那行数据,再插入新的这行数据。
这样的话,我们就可以通过更新(replace)数据库中的某一行来获取一个新的自增主键ID了。

来个总结

一个Flickr Ticket服务器是一个只包含一个数据库独立的数据库服务器。然后这个数据库里包含了一些类似Ticket32和Ticket64的表(分别用于提供32位整型主键和64位长整型主键)。 Tickets64 的Sckeme大概像这样:
CREATE TABLE `Tickets64` (
  `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 Tickets64 返回的一行数据大概像这样:
+-------------------+------+
| id                | stub |
+-------------------+------+
| 72157623227190423 |    a |
+-------------------+------+
当我们需要一个新的64位的主键的时候,我们可以通过执行下面的SQL得到:
REPLACE INTO Tickets64 (stub) VALUES ('a');
SELECT LAST_INSERT_ID();

单点问题

你绝对不愿意看到你的ID服务器因为单点问题挂掉。我们实现“高可用”的方法是跑两个Ticket服务。但在两个机器之间进行写入/更新的复制是会有问题的,由于必要的锁的存在,会严重降低整个网站的性能。我们的做法是将ID生成的职责均分到两个服务上,一个生成奇数,一个生成偶数。设置如下:
TicketServer1:
auto-increment-increment = 2
auto-increment-offset = 1

TicketServer2:
auto-increment-increment = 2
auto-increment-offset = 2
然后我们使用轮询的方式去轮流访问这两个服务器,来达到负载均衡的目的和应对停机的情况。如果有一边不能保持同步了(停机了),那最多就是可能会有连续的几十万个奇数(或者偶数)的ID。但这不会有任何副作用。

更多的队列

在Ticket服务器中,除了Ticket32和Ticket64这样的两张表,我们其实还有其他更多的表。我们的图片,账号, 离线任务,组等等都有自己独立的ID队列。离线任务有它自己独立的ID队列是因为它太多了,然后我们又不希望有不必要的因素导致队列增长(译者注:前面提到,ID的大小一定程度上反应了业务的数据量)。分组和账号有他们自己的ID队列是因为我们很少拿他们来做比较。图片有自己的ID队列是因为我们要保证切换之后要和之前单表的自增ID保持同步,因为之前的自增id我们可以很方便的知道我们总共上传了多少张图片。

就是这样

虽然,这个方案看起来不是特别优雅。但令人震惊的是从2006年1月13号我们上线到现在,在生产环境跑的都非常好。这个设计已经成为我们Flickr工程师的一个设计理念——“ 在最坏的情况下也能工作”的一个典型代表了。

© 著作权归作者所有

共有 人打赏支持
laichendong
粉丝 8
博文 85
码字总数 71483
作品 0
朝阳
程序员
互联网分库分表主键的生成-一个小思路

几乎所有的大型项目都涉及到分库分表(使用关系型数据库),为了应对递增的数据增长采用分库分表的策略,分库分表后面临的首要问题就是主键的生成。主键的关系涉及几个重要的因素: 1,如果只...

wangshuaixin ⋅ 2016/12/26 ⋅ 0

【死磕Sharding-jdbc】—–分布式ID

原文作者:阿飞Javaer 原文链接:https://www.jianshu.com/p/7f0661ddd6dd 实现动机 传统数据库软件开发中,主键自动生成技术是基本需求。而各大数据库对于该需求也提供了相应的支持,比如M...

飞哥-Javaer ⋅ 05/05 ⋅ 0

数据库分库分表中间件 Sharding-JDBC 源码分析 —— 分布式主键

关注微信公众号:【芋道源码】有福利: RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表 RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址 您对于源码的疑问每条留言都将...

芋艿V ⋅ 2017/09/24 ⋅ 0

数据库分库分表(sharding)系列(二) 全局主键生成策略

本文将主要介绍一些常见的全局主键生成策略,然后重点介绍flickr使用的一种非常优秀的全局主键生成方案。关于分库分表(sharding)的拆分策略和实施细则,请参考该系列的前一篇文章:数据库分库...

bluishglc ⋅ 2012/07/03 ⋅ 0

分布式唯一ID极简教程

一,题记 所有的业务系统,都有生成ID的需求,如订单id,商品id,文章ID等。这个ID会是数据库中的唯一主键,在它上面会建立聚集索引! 阅读本文,建议大家已经掌握了扎实的互联网技术,可参考...

架构师小秘圈 ⋅ 2017/11/24 ⋅ 0

分布式系统中的ID生成

问题 在分布式系统中常遇到ID生成问题: 场景1,在分库分表中需要保证某类ID唯一,这样使用主键自增的策略就不再合适 场景2,需要某类ID需要具有同一特性来标识 诸如此类。 方案 有很多解决方...

chaun ⋅ 2015/12/01 ⋅ 0

AliSQL · 开源 · Sequence Engine

Introduction 单调递增的唯一值,是在持久化数据库系统中常见的需求,无论是单节点中的业务主键,还是分布式系统中的全局唯一值,亦或是多系统中的幂等控制。不同的数据库系统有不同的实现方...

阿里云RDS-数据库内核组 ⋅ 2017/02/02 ⋅ 0

分布式ID生成器的解决方案总结

在互联网的业务系统中,涉及到各种各样的ID,如在支付系统中就会有支付ID、退款ID等。那一般生成ID都有哪些解决方案呢?特别是在复杂的分布式系统业务场景中,我们应该采用哪种适合自己的解决...

Java技术栈 ⋅ 01/11 ⋅ 0

幂等性戒心

理解HTTP幂等性 基于HTTP协议的Web API是时下最为流行的一种分布式服务提供方式。无论是在大型互联网应用还是企业级架构中,我们都见到了越来越多的SOA或RESTful的Web API。为什么Web API如此...

leesama ⋅ 2014/06/06 ⋅ 1

​理解HTTP幂等性

理解HTTP幂等性 基于HTTP协议的Web API是时下最为流行的一种分布式服务提供方式。无论是在大型互联网应用还是企业级架构中,我们都见到了越来越多的SOA或RESTful的Web API。为什么Web API如此...

無雙 ⋅ 2014/03/06 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Spring Boot整合模板引擎thymeleaf

项目结构 引入依赖pom.xml <!-- 引入 thymeleaf 模板依赖 --><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId......

yysue ⋅ 14分钟前 ⋅ 0

ConstraintLayout使用解析

AndroidStudio3.0创建Project默认的布局就是ConstraintLayout。 AndroidStudio3.0前的可以自己修改,使用ConstraintLayout。 为了要使用ConstraintLayout,我们需要在app/build.gradle文件中...

_OUTMAN_ ⋅ 26分钟前 ⋅ 0

OSChina 周三乱弹 —— 这样的女人私生活太混乱了

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @ 胖达panda :你经历过体验到人生的大起大落吗?我一朋友在10秒内体验了,哈哈。@小小编辑 请点一首《almost lover》送给他。 《almost love...

小小编辑 ⋅ 59分钟前 ⋅ 9

自己动手写一个单链表

文章有不当之处,欢迎指正,如果喜欢微信阅读,你也可以关注我的微信公众号:好好学java,获取优质学习资源。 一、概述 单向链表(单链表)是链表的一种,其特点是链表的链接方向是单向的,对...

公众号_好好学java ⋅ 今天 ⋅ 0

Centos7重置Mysql 8.0.1 root 密码

问题产生背景: 安装完 最新版的 mysql8.0.1后忘记了密码,向重置root密码;找了网上好多资料都不尽相同,根据自己的问题总结如下: 第一步:修改配置文件免密码登录mysql vim /etc/my.cnf 1...

豆花饭烧土豆 ⋅ 今天 ⋅ 0

熊掌号收录比例对于网站原创数据排名的影响[图]

从去年下半年开始,我在写博客了,因为我觉得业余写写博客也还是很不错的,但是从2017年下半年开始,百度已经推出了原创保护功能和熊掌号平台,为此,我也提交了不少以前的老数据,而这些历史...

原创小博客 ⋅ 今天 ⋅ 0

LVM讲解、磁盘故障小案例

LVM LVM就是动态卷管理,可以将多个硬盘和硬盘分区做成一个逻辑卷,并把这个逻辑卷作为一个整体来统一管理,动态对分区进行扩缩空间大小,安全快捷方便管理。 1.新建分区,更改类型为8e 即L...

蛋黄Yolks ⋅ 今天 ⋅ 0

Hadoop Yarn调度器的选择和使用

一、引言 Yarn在Hadoop的生态系统中担任了资源管理和任务调度的角色。在讨论其构造器之前先简单了解一下Yarn的架构。 上图是Yarn的基本架构,其中ResourceManager是整个架构的核心组件,它负...

p柯西 ⋅ 今天 ⋅ 0

uWSGI + Django @ Ubuntu

创建 Django App Project 创建后, 可以看到路径下有一个wsgi.py的问题 uWSGI运行 直接命令行运行 利用如下命令, 可直接访问 uwsgi --http :8080 --wsgi-file dj/wsgi.py 配置文件 & 运行 [u...

袁祾 ⋅ 今天 ⋅ 0

JVM堆的理解

在JVM中,我们经常提到的就是堆了,堆确实很重要,其实,除了堆之外,还有几个重要的模块,看下图: 大 多数情况下,我们并不需要关心JVM的底层,但是如果了解它的话,对于我们系统调优是非常...

不羁之后 ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部