Instagram架构的分片和ID设计

前言

每秒上传超过25张图和90个“喜欢”,在Instagram我们存了很多数据,为了确保把重要的数据都扔到内存里,达到快速响应用户的请求,我们已经开始把数据进行分片-换句话说,把数据放到更多的小桶子里,每个桶了装一部分数据。

我们的应用服务器跑的是Django和后端是PostgreSQL,在决定要分片后的第一个问题是,是否还继续用PostgreSQL作为主要数据仓库,或者换成别的?我们评估了一些NoSQL的解决方案,但最终决定最好的解决方案是:把数据分片到不同的PostgreSQL数据库。

在写数据到不同服务器之前,还需要解决一个问题,如何给在数据库里的每块数据都标识上唯一的标识(如,发布到我们系统的每张图)。单库好解决,就是用自增主键-但如果数据同时写到多个库就不行了,本博客将回答如果解决这个问题。

开始前,先列出系统的主要实现目标:

  1. 生成的ID可以按时间排序(如,一个图片列表的id,可以不用获取更多信息即可直接排序)
  2. ID最好是64位的(这样索引更小,存储的也更好,像Redis)
  3. 系统最好尽可能地只有部分是“可变因素”-很大部分原因为何在很少工程师的情况下可以扩展Instagram,就是因为我们相信简单好用!

现有的解决方案

很多类似的ID解决方案都有些问题,下面是一小部分例子:

在web应用层生成ID
这类方法把生成ID的任务都扔到应用层实现,而不是数据库层。如,MongoDB’s ObjectId,是一个12字节长的编码的时间戳作为第一部分,另外一种流行的方法是用UUIDs。

优点:

  1. 每个应用服务生成的ID是独立的,生成时将失败和竞争降到最小;
  2. 如果用时间戳作为第一部分,就可以按时间排序

劣势:

  1. 需要更多存储空间(96位或更多)才能保证唯一性;
  2. 一些UUID类型的完全是随机数,没有排序特性;

由单独的服务提供ID生成

如:Twitter的Snowflake,是一个Thrift服务用到Apache ZooKeeper协调各节点并生成一个唯一的64位ID。

优势:

  1. Snowflake生成的ID是64位,只用UUID的一半大小;
  2. 可以把时间排到前面,可以排序;
  3. 分布式系统可以保证服务不会挂掉;

劣势:

  1. 系统会变得更复杂和更多的“可变因素”(ZooKeeper, Snowflake 服务)加入到我们的架构。

数据库计数服务器

用数据库自增字段的能力来保证唯一性(Flickr用了这个方法),但用了两台计数服务器(一台是生成奇数,另外一台是偶数)才能避免单点失效。

优势:

  1. 数据库好理解,扩展很容易预测要考虑的因素;

劣势:

  1. 可能最终变成写入是个瓶颈(尽管Flickr报告过这一点,但在高扩展下并不是个问题);
  2. 新增了两台服务器要管理(或是EC2实例);
  3. 如果用单台数据库,会有单点失效问题,如果用多个库,不能保证他们是可按时间排序的;

所有以上的方法中,Twitter的Snowflake最接近,但添加生成ID服务了复杂调用又冲突了,替换的方案是,我们使用了概念类似的方法,但是从PostgreSQL内部特性实现的。

我们的解决办法

我们的分片系统由几千个逻辑分片组成,由代码指向极少的几个物理分片,用这个方法,我们可用少数几台服务器就可以实施起来,以后也可以扩展到更多,只要简单的将逻辑分片从一台物理数据器移到另外一台,不需要重新聚合各分片的数据,我们用PostgreSQL的schema特性很容易就做到实施和管理。

Schema(不要跟建单个表的SQL schema搞混了)在PostgreSQL是一个逻辑分组的功能,每台PostgreSQL有多个schema,每个schema可包含一张或多张表,表名在每个schema里是唯一的,不是每个库,PostgreSQL默认把所有东西都放到一个叫public的schema里。

我们系统里每个逻辑分片就是一个schema,每个分片的表(如,照片的“喜欢”功能)存在于每个schema中。

我们在每个分片的每张表里用PL/PGSQL(PostgreSQL内部编程语言)和自增特性来创建ID。

每个ID包含有:

41位的毫秒时间(可以用41年的ID);
15位表示逻辑ID;
10位自增序列,与1024取模,意味着每个分片每毫秒可以生成1024 个ID;

看个例子:

假设现在是2011年9月9号下午5:00,系统的纪元开始是2011年9月1日,从纪元开始到现在已经经过了1387263000毫秒,为生成ID,用左移方法填充最左边41位值是:

id = 1387263000 << (64-41)

下一步,如果生成这个要插入数据的分片的ID呢?假设我们用用户ID(user ID)来分片,同时已经有2000个逻辑分片,如果用户ID是31341,那么分片ID是 31341 % 2000 -> 1341,用这个值也填充接下来的13位:

id |= 1341 << (64-41-13)

最后,来生成最后自增的序列值(这个序列对每个schema每张表是唯一的)并填充完剩下的几位,假设这张表已经生成了5000个ID,下一个值即是5001,跟1024取模(刚好10位),加进来:

id |= (5001 % 1024)

ID生成了!用RETURNING返回给应用层用来作INSERT用。

下面是完整的PL/PGSQL代码(例子中的schema是 insta5):

<code>CREATE OR REPLACE FUNCTION insta5.next_id(OUT result bigint) AS $
DECLARE
    our_epoch bigint := 1314220021721;
    seq_id bigint;
    now_millis bigint;
    shard_id int := 5;
BEGIN
    SELECT nextval(‘insta5.table_id_seq‘) %% 1024 INTO seq_id;

    SELECT FLOOR(EXTRACT(EPOCH FROM clock_timestamp()) * 1000) INTO now_millis;
    result := (now_millis - our_epoch) << 23;
    result := result | (shard_id << 10);
    result := result | (seq_id);
END;
$ LANGUAGE PLPGSQL;
</code>

用下面的代码创建表:

<code>CREATE TABLE insta5.our_table (
    "id" bigint NOT NULL DEFAULT insta5.next_id(),
    ...rest of table schema...
)</code>

就这些!主键在所有应用层都是唯一的(另外的好处是,包含了分片ID这样做映射就很容易),这个方法我们已经用到生产环境了,结果到目前为止令人满意,如果您对扩展问题能帮助我们,我们正在招人!

Mike Krieger, co-founder

英文原文 http://instagram-engineering.tumblr.com/post/10853187575/sharding-ids-at-instagram

<译者:朱淦 [email protected] 2015.7.29>

时间: 2024-08-08 10:18:54

Instagram架构的分片和ID设计的相关文章

微信房卡麻将棋牌架设之游戏服务器架构的详细设计(一) 内核设计

题目:微信房卡麻将棋牌架设之游戏服务器架构的详细设计(一) 内核设计 今天向大家介绍一下游戏服务器的设计,着重讲解一下微信房卡麻将棋牌架设(aqiulian.com)的服务器搭建,如果有什么不懂得可以咨询我Q_212303635,欢迎大家的咨询.那么我们开始进去主题吧. 内核的几个组件被设计成Service,也就是说这几个模块都要实现如下接口: 图1  IService接口 Start方法用来启动服务. Stop 方法用来关闭服务. IsService 方法用于查询当前服务是否正在工作. 内核中

朱晔的互联网架构实践心得S1E9:架构评审一百问和设计文档五要素

朱晔的互联网架构实践心得S1E9:架构评审一百问和设计文档五要素 [下载文本PDF进行阅读] 本文我会来说说我认为架构评审中应该看的一些点,以及我写设计文档的一些心得.助你在架构评审中过五关斩六将,助你写出能让人收藏点赞的设计文档. 技术架构评审 架构评审或技术方案评审的价值在于集众人的力量大家一起来分析看看方案里是否有坑,方案上线后是否会遇到不可逾越的重大技术问题,提前尽可能把一些事情先考虑到提出质疑其实对项目的健康发展有很大的好处.很多公司都有架构评审委员会都有架构评审的流程,做业务的兄弟要

微服务架构设计基础之领域驱动设计

DDD早于微服务「出道」十年,这两个「忘年交」的软件设计哲学是如何相爱相杀的? 背景 微服务现在可以说是软件研发领域无人不提的话题,然而业界流行的对比多数都是所谓的Monolithic(单体应用),而大量的系统在十几年前都已经是以SOA(面向服务架构)为基础的分布式系统了,那么微服务作为新的架构标准与SOA有什么差异点呢?其本质区别在于设计原理,微服务是去中心化设计,SOA是「集成」形成中心设计: 另外,笔者认为以下几点并不是微服务和SOA的区别点: CI/CD:持续集成.持续部署本身与敏捷.D

【转载】Instagram架构分析笔记

原文地址:http://chengxu.org/p/401.html Instagram 架构分析笔记 全部 技术博客 Instagram团队上个月才迎来第 7 名员工,是的,7个人的团队.作为 iPhone 上最火爆的图片类工具,instagram 用户数量已经超过 1400 万,图片数量超过 1.5 亿张.不得不说,这真他妈是个业界奇迹. 几天前,只有三个人的 Instagram 工程师团队发布了一篇文章:What Powers Instagram: Hundreds of Instance

instagram架构分析_转

转自:http://www.eit.name/blog/read.php?504 Instagram 团队上个月才迎来第 7 名员工,是的,7个人的团队.作为 iPhone 上最火爆的图片类工具,instagram 用户数量已经超过 1400 万,图片数量超过 1.5 亿张.不得不说,这真他妈是个业界奇迹. 几天前,只有三个人的 Instagram 工程师团队发布了一篇文章:What Powers Instagram: Hundreds of Instances, Dozens of Techn

Instagram 架构分析笔记(转)

原文:http://dbanotes.net/?s=Instagram+%E6%9E%B6%E6%9E%84%E5%88%86%E6%9E%90%E7%AC%94%E8%AE%B0 作者:冯大辉 Instagram 团队上个月才迎来第 7 名员工,是的,7个人的团队.作为 iPhone 上最火爆的图片类工具,instagram 用户数量已经超过 1400 万,图片数量超过 1.5 亿张.不得不说,这真他妈是个业界奇迹. 几天前,只有三个人的 Instagram 工程师团队发布了一篇文章:What

ID设计

ID设计 在分布式系统中,经常需要使用全局唯一ID查找对应的数据.产生这种ID需要保证系统全局唯一,而且要高性能以及占用相对较少的空间. 全局唯一ID在数据库中一般会被设成主键,这样为了保证数据插入时索引的快速建立,还需要保持一个有序的趋势. 这样全局唯一ID就需要保证这两个需求: 全局唯一 趋势有序 全局ID产生的几种方式 数据库自增 当服务使用的数据库只有单库单表时,可以利用数据库的auto_increment来生成全局唯一递增ID. 优势: 简单,无需程序任何附加操作 保持定长的增量 在单

Hive架构层面优化之五合理设计表分区(静态分区和动态分区)

合理建表分区有效提高查询速度. 重要数据采用外部表存储,CREATE EXTERNAL TABLE,数据和表只是一个location的关联,drop表后数据不会丢失: 内部表也叫托管表,drop表后数据丢失:所以重要数据的表不能采用内部表的方式存储. 在全天的数据里查询某个时段的数据,性能很低效------可以通过增加小时级别的分区来改进! Trackreal为例,有三个分区: 日增量: 按日期分区: 小时增量:按日期.小时分区: 10分钟增量:按日期.小时.step分区:每个小时要导6次. 场

26. ClustrixDB 分布式架构/数据分片

数据分片 介绍 共享磁盘vs.无共享 分布式数据库系统可分为两大类数据存储架构:(1)共享磁盘和(2)无共享. Shared Disk Architecture Shared Nothing Architecture 共享磁盘方法在协调对单个中心资源的访问时受到几个固有的体系结构限制.在这样的系统中,随着集群中节点数量的增加,协调开销也随之增加.虽然一些工作负载可以通过共享磁盘很好地扩展(例如,由大量读操作控制的小型工作集),但是大多数工作负载的扩展能力都很差——尤其是具有大量写负载的工作负载.