Instagram 小而美的分片和 ID 生成解决方案

分布式系统中生成全局唯一ID方案 本文主要介绍在一个分布式系统中, 如何去生成全局唯一的 ID 阅读详情

Instagram 是一款以图片和短视频分享为主的社交媒体平台,于 2010 年由 Kevin Systrom 和 Mike Krieger 创建。用户可以通过 Instagram 应用发布和编辑照片和视频,添加滤镜和标签,以及与朋友互动。

上期「人均身价超 5 亿的 Instagram,如何用 3 个工程师支撑 1400 万用户」介绍了 Instagram 早期的快速增长阶段遵循的原则和技术栈,本文展开讲解了他们是如何在工程师团队较小的情况下扩展业务的。


Instagram 每秒要处理 25+ 张照片和 90+ 点赞,数据量巨大。为了确保这些重要的数据能迅速载入内存并快速供用户访问,我们开始将数据分片 (shard) 储存:把数据分布在多个小的存储单元中,每个单元负责一部分数据。

我们的应用服务器是 Django,以 PostgreSQL 作为后端数据库。决定对数据进行分片后,我们面临的首要问题是是否继续使用 PostgreSQL 作为主数据库,还是使用其他系统。我们评估了若干种 NoSQL 数据库解决方案,最终认为最符合我们需求的是将数据分片存储在多台 PostgreSQL 服务器上。

然而,在向这些服务器写入数据之前,我们得解决一个关键问题:如何为数据库中的每一项数据(比如每一张上传的照片)分配一个唯一的标识符。当数据需要同时写入多个数据库时,在单个数据库中使用的自增主键就不再适用了。本文将详细介绍我们是如何解决这个问题的。

首先,我们确定了几个系统必须具备的关键功能:

  • 生成的 ID 要能按时间顺序排列(这样一来,我们可以直接对照片 ID 进行排序,而无需额外查询照片的详细信息)。
  • 理想情况下,ID 应为 64 位(这样可以缩小索引的大小,并在 Redis 这类系统中实现更有效的存储)。
  • 尽量减少系统中新增的复杂组件 — 我们之所以能够在工程师团队相对较小的情况下扩展 Instagram 的业务,很大程度上归功于我们选择了那些简单、易懂且可靠的解决方案。

现有解决方案

针对 ID 生成的问题,市面上有多种解决方案,我们考虑了其中几种:

在 Web 应用程序中生成 ID

这种方法完全依赖应用程序来生成 ID,而不是数据库。比如 MongoDB 的 ObjectId 就是一个例子,它包含 12 字节,其中时间戳占据首位。另外一种常见的做法是使用 UUID。

优点

  • 每个应用程序线程都能独立生成 ID,这样可以大幅减少因 ID 生成而引起的系统故障和冲突。
  • 如果 ID 的开头是时间戳,那么这些 ID 就能按时间顺序进行排序。

缺点

  • 为了确保 ID 的唯一性,通常需要更多的存储空间(96 位或更多)。
  • 有些类型的 UUID 是完全随机生成的,无法进行自然排序。

通过特定服务生成 ID

例如,Twitter 开源的雪花算法 (Snowflake) 是一个利用 Apache ZooKeeper 协调各节点并生成 64 位唯一 ID 的解决方案。

优点

  • 生成的 ID 长度为 64 位,只有 UUID 的一半。
  • ID 的开头可以是时间,这使得 ID 可以按时间顺序排列。
  • 它是一个分布式系统,能够处理节点失效的情况。

缺点
引入这种系统会增加我们架构的复杂性,包括需要加入 ZooKeeper 和 Snowflake 服务器等多个新组件。

数据库凭据服务器

这种方法利用数据库自带的自增功能确保数据的唯一性。Flickr 就用这种方式,并设置两台机器对应的参数,一个处理奇数,另一个处理偶数,这样做可以避免系统出现单一故障点。

优点
数据库很好理解,其扩展性相对可预测。

缺点

  • 随着时间的推移,写入操作可能成为系统的瓶颈(虽然根据 Flickr 的报告,即使是在非常大的规模下,这也不构成问题)。
  • 需要额外管理几台机器(或 EC2 实例)。
  • 如果只使用一个数据库,它可能成为系统的脆弱点。使用多个数据库时,则不能保证数据随时间保持可排序性。

在所有这些方法中,Twitter 的雪花算法方法最接近我们的需求,但是运行一个专门的 ID 服务的复杂性让我们望而却步。因此,我们选择了一个在概念上相似但更简化的方法,即将此系统集成到 PostgreSQL 中。

我们的方案

我们建立了一个包含数千个「逻辑」分片的系统,这些逻辑分片在编程中映射到较少的物理分片上。利用这种策略,我们最初只需几台数据库服务器即可运行,随后可以通过将一组逻辑分片从一个数据库迁移到另一个,逐步扩大到更多服务器,而无需重新整理数据。我们用了 Postgres 的 schemas 功能来方便脚本编写和系统管理。

Schema(不要与单表的 SQL schema 混淆)是 Postgres 中用于逻辑分组的功能。每个 Postgres 数据库可以包含多个 schema,每个 schema 内可包含一个或多个表。在每个 schema 中,表名必须是唯一的,而默认情况下,Postgres 会将所有内容放置在名为 public 的 schema 中。

在我们的系统中,每个逻辑分片就是一个 Postgres 的 schema,每个分片的表(比如图片的点赞)都设在每个 schema 内。

我们将每个分片内的表的 ID 创建任务委托给了 PL/PGSQL(Postgres 的内部编程语言)和 Postgres 现有的自动递增功能来处理。

我们的每个 ID 结构如下:

  • 41 位用于记录时间(以毫秒计),这样可以保证 41 年内的每个毫秒都有唯一的 ID。
  • 13 位用于标识逻辑分片的 ID。
  • 10 位用于一个自动递增的序列,以 1024 为模。也就是说每个分片在每毫秒内可以生成多达 1024 个 ID。

一个具体的例子:设想现在是 2011 年 9 月 9 日下午 5:00,而我们的「纪元 (epoch)」起始于 2011 年 1 月 1 日。从纪元开始到现在已经过去了 1387263000 毫秒,因此在构造 ID 的时候,我们将这个时间值填充到 ID 的最左边的 41 位,并将其向左移位:

id = 1387263000 <<(64-41)

接下来,我们将获取我们试图插入数据的特定分片 ID。假设我们根据用户 ID 来分片,而总共有 2000 个逻辑分片;如果用户 ID 是 31341,那么计算得到的分片 ID 是 31341 % 2000 -> 1341。我们将这个值填入接下来的 13 位中。

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

最后,我们获取每个 schema 中每个表特有的自增序列的下一个值,并用这个值填充剩余的位数。假设这个表已经生成了 5000 个 ID,那么下一个 ID 就是 5001。我们将这个数字对 1024 取模(以确保它能够适配 10 位空间),并将结果包含在内。

id |= (5001 % 1024)

现在我们生成了 ID,可以通过在 INSERT 语句中使用 RETURNING 关键字,将其返回给应用服务器。

以下是用于实现这一切的 PL/PGSQL 示例 (针对示例 schema insta5):

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;

创建表格时,只需这样操作:

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

就是这样!我们应用中的主键是唯一的,并且(更方便的是)它们包含了分片 ID,以便于更好的数据映射。我们已经将这种方法应用到生产中了,迄今为止相当满意!


💡 更多资讯,请关注 Bytebase 公号:Bytebase

Instagram 使用 Python 的经验 作者|朱雷编辑|GaryPyCon 是全世界最大的以 Python 编程语言 为主题的技术大会,大会由 Python 社区组织,每年举办一次。在 Python 2017 上,Instagram 的工程师们带来了一个有关 Python 在 Instagram 的主题演讲,同时还分享了 Instagram 如何将整个项目运行环境升级到 Python 3 的故事。本文为该次演讲的内容摘要,由 Python 爱好者朱雷撰写,InfoQ 经授权发布。 阅读详情

相关推荐

分库分表后ID的全局唯一性:从算法到实战的终极指南

在单库单表时代,数据库自增ID(AUTO_INCREMENT)是主键的“黄金标准”。然而,当数据量突破千万级、TPS飙升到万级别时,分库分表成为必然选择。但随之而来的问题令人窒息:不同分表中的自增ID可能重复! 优点:简单高效,无需额外逻辑 缺点: 分库分表后,不同分表的字段会从1开始自增,导致冲突 不支持分布式环境下的全局唯一性 2.2 分库分表的ID冲突示例 分库 分表 ID db1 table_0 1, 2, 3… db1 table_1 1, 2, 3… db2 t

墨夶的博客 1093

系统设计 — Instagram的分片与ID设计

引言:Instagram上有大量的数据,每分钟就有超过25张的图片和90个点赞。为了确保所有重要的数据都能被合理存储并且及时得被提取应用,对数据进行了分片(sharding)——也就是说,把数据放到多个桶(bucket)中,每个桶里都有一部分数据。 应用服务器上运行的是Django, 后端数据库是PostgreSQL。对数据分片首先要决定是否要保留PostgreSQL作为主要的数据存储库,是否要采用其他的数据库。经过评估一些不同的数据库解决方案,最终确定最适合的方案是在PostgreSQL数据库集群上实现数

qq_38658567的博客 615

FreeSWITCH编译安装详细文档

本文档详细介绍了在Ubuntu 22.04系统上从源码编译安装FreeSWITCH的完整流程。主要内容包括:1)系统环境准备和依赖库安装;2)关键依赖库spandsp和sofia-sip的编译安装;3)FreeSWITCH源码的特定版本(v1.6.0)编译配置,包括禁用SignalWire模块的配置方法;4)系统服务配置,包括创建专用用户、设置权限以及配置systemd服务文件。文档特别提供了版本控制说明,确保后期能切换到相同的版本环境,并附有详细的命令操作步骤和注意事项。

唯有代码让我痴狂 1371

Instagram 的ID生成策略[翻译]

项目中遇到一个ID生成策略的需求:需要在系统中为每个用户分配一个ID用作以后的用户标示。这个需求应该是非常普遍的,对于使用人数较少的系统而言不会 是一个问题,不过对于向用户众多的互联网系统来讲这不是一个简单的问题。下面是翻译的最近最火爆的Instagram应用开发者的一篇文章,看看他们一个 十几个人的公司是怎么解决这个问题的:   先给出原文链接:http://instagram-e...

心笑峰的csdn blog 984

3D IC中Memory-on-Logic堆叠测试的DFT解决方案与工程实践

在半导体行业,随着摩尔定律逼近物理极限,3D IC技术通过芯片垂直堆叠实现性能提升和异构集成,已成为重要发展方向。其核心原理是利用硅通孔(TSV)或微凸块实现芯片间电气互连,将多个不同功能的芯片(如逻辑芯片与存储芯片)集成在一个封装内。这项技术的核心价值在于能大幅提升系统性能、降低功耗并实现更小的封装尺寸。然而,芯片堆叠后,传统的测试方法面临巨大挑战,尤其是测试访问存在物理屏障,无法直接探测被覆盖的芯片接口。为此,可测试性设计(DFT)成为确保3D IC可靠性与量产可行性的关键技术。它通过在设计阶段植入专用

weixin_42521058的博客 632

VC Spyglass CDC实战:如何快速定位和解决重汇聚问题(附详细调试步骤)

本文深入探讨了在SoC设计中利用VC Spyglass进行CDC验证时,如何高效定位和解决棘手的重汇聚问题。通过实战演练,详细解析了重汇聚的本质、VC Spyglass的检测逻辑,并提供了从报告筛选、GUI原理图分析到制定设计修复或约束豁免方案的全套调试步骤,帮助工程师快速攻克这一常见验证难题。

weixin_29219539的博客 755

Instagram架构的分片和ID设计

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34007886的博客 228

告别JSON!Anthropic发布Tool Calling 2.0,Agent上下文消耗骤降80%

Anthropic发布ToolCalling 2.0更新,彻底革新AI Agent开发模式。四大核心特性:1)程序化工具调用,允许模型直接输出可执行代码替代JSON交互,降低30-50%Token消耗;2)动态网页过滤,自动清洗网页内容减少24%无效信息;3)工具搜索机制,按需加载工具定义,最高优化80%上下文窗口;4)工具使用示例,通过Few-Shot示范提升复杂表单处理准确率至90%。这一升级将Agent范式从"大模型作为路由"推进到"大模型作为引擎",但需注意代

老孙 | Ethan Sun 的博客:AI 智能体与 AI 原生软件的工程实践 797

Sharding & IDs at Instagram, Flickr ID generation

Instagram: http://instagram-engineering.tumblr.com/post/10853187575/sharding-ids-at-instagram Flickr:http://code.flickr.net/2010/02/08/ticket-servers-distributed-unique-primary-keys-on-the-chea...

a923304245的博客 199

Tessent实战:网表扫描链插入全流程解析

本文详细解析了使用Tessent工具为网表插入扫描链(Scan Chain)的全流程。从前期环境配置、网表检查,到扫描链数量、时钟域等核心配置,再到执行扫描单元替换与连接,最后进行结果验证与文件输出。文章提供了关键命令与实用技巧,帮助工程师高效完成DFT设计,确保芯片可测试性。

hhh00的博客 748

Moodle平台题库建设技术

Moodle平台题库建设技术简述1新的改变1功能快捷键1合理的创建标题,有助于目录的生成1如何改变文本的样式1插入链接与图片1如何插入一段漂亮的代码片1生成一个适合你的列表1创建一个表格1设定内容居中、居左、居右1SmartyPants1创建一个自定义列表1如何创建一个注脚注释也是必不可少的1KaTeX数学公式1新的甘特图功能,丰富你的文章1UML 图表1FLowchart流程图1导出与导入导出1...

lxf78的博客 4535

分片(Sharding)的全局ID生成

转自http://blog.youkuaiyun.com/hengyunabc/article/details/19025973 前言 数据在分片时,典型的是分库分表,就有一个全局ID生成的问题。单纯的生成全局ID并不是什么难题,但是生成的ID通常要满足分片的一些要求: 不能有单点故障。以时间为序,或者ID里包含时间。这样一是可以少一个索引,二是冷热数据容易分离。可以控制Shar

马万明的专栏 1366

海思芯片YOLOv8模型部署完整指南:从RPN硬化到8bit量化精度优化

本文详细介绍了在海思芯片平台部署YOLOv8目标检测模型的完整方案,重点解决8bit量化精度损失问题。通过分析海思RPN硬化层的性能优势(1.9ms推理时间),对比不同量化策略(16bit仅损失0.6AP,8bit损失5.2AP),并深入定位到strides计算层是量化误差的主要来源。关键突破在于采用混合精度策略(敏感层16bit,其余8bit),使8bit量化AP回升4.1%,同时保持3.4ms的推理速度和60%的低NPU占用率。文章还提供了量化参数调整、校准数据集优化等进阶技巧,为边缘计算应用提供了性能

FJN110的博客 736

java id值_Java实现数值型ID生成器

基于Twitter ID 生成策略每秒能生成几十万条 IDID 生成要以一种非协作的(uncoordinated)的方式进行,例如不能利用一个全局的原子变量。ID 大致有序,就是说生成时间相近的两个ID,它们的值也应当相近按 ID 排序后满足 k-sorted 条件。如果序列 A 要满足 k-sorted,当且仅当对于任意的 p, q,如果 1 <= p <= q - k (1 &lt...

weixin_42349272的博客 755

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

idcenter java_Java实现数值型ID生成器

基于Twitter ID 生成策略每秒能生成几十万条 IDID 生成要以一种非协作的(uncoordinated)的方式进行,例如不能利用一个全局的原子变量。ID 大致有序,就是说生成时间相近的两个ID,它们的值也应当相近按 ID 排序后满足 k-sorted 条件。如果序列 A 要满足 k-sorted,当且仅当对于任意的 p, q,如果 1 <= p <= q - k (1 &lt...

weixin_39626181的博客 259

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

基于Twitter ID 生成策略

每秒能生成几十万条 ID ID 生成要以一种非协作的(uncoordinated)的方式进行,例如不能利用一个全局的原子变量。 ID 大致有序,就是说生成时间相近的两个ID,它们的值也应当相近 按 ID 排序后满足 k-sorted 条件。如果序列 A 要满足 k-sorted,当且仅当对于任意的 p, q,如果 1 解决方案 Twitter 解决这两个问题的方案非常简单高

程序猿开发日志【学习永无止境】 2461

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

推荐使用:基于 Go-PG 的 PostgreSQL 分片解决方案

推荐使用:基于 Go-PG 的 PostgreSQL 分片解决方案 shardingPostgreSQL sharding for go-pg and Golang项目地址:https://gitcode.com/gh_mirrors/sha/sharding 在大数据场景下,数据库的扩展性是至关重要的,而有效的数据分片策略能有效地解决这一问题。这款开源项目——go-pg/sharding 是一...

gitblog_00047的博客 549

分布式ID生成器解决方案

GitHub:https://github.com/wangzhiwubigdata/God-Of-BigData 关注公众号,内推,面试,资源下载,关注更多大数据技术~ 大数据成神之路~预计更新500+篇文章,已经更新50+篇~ 本文主要介绍在一个分布式系统中, 怎么样生成全局唯一的 ID 一, 问题描述 在分布式...

微信搜:import_bigdata,大数据领域硬核原创作者 357

Sharding & IDs at Instagram

原文:http://instagram-engineering.tumblr.com/post/10853187575/sharding-ids-at-instagram Instagram的存储量非常大,差不多每秒25-90张照片。为了保证我们的重要的数据能够合理的存储以便快速的提取应用,我们对数据进行了分片 -- 换句话说,将数据放到很多小的桶(buckets)中,每个桶存储一部分的数据。 ...

weixin_30572613的博客 135

mysql高并发生成id_高并发分布式系统中生成全局唯一Id汇总

一 twitter (id分发中心)twitter在把存储系统从MySQL迁移到Cassandra的过程中由于Cassandra没有顺序ID生成机制,于是自己开发了一套全局唯一ID生成服务:Snowflake。1 41位的时间序列(精确到毫秒,41位的长度可以使用69年)2 10位的机器标识(10位的长度最多支持部署1024个节点)3 12位的计数顺序号(12位的计数顺序号支持每个节点每毫秒产生4...

weixin_34886431的博客 497

如何登上统一排行榜?AgentLab Leaderboard 结果提交指南

AgentLab 是一个用于开发、测试和评测 Web Agent 的开源框架,它构建在 BrowserGym 生态之上,支持 WebArena、WorkArena、VisualWebArena、MiniWoB 等多种基准,并提供了一个跨基准对比不同 Agent 结果的官方统一排行榜(Leaderboard)。如果你已经跑完一次 Agent 评测,想把成绩提交到 AgentLab 统一排行榜,本文会

gitblog_00140的博客 862

sharding-ids-at-instagram

原文链接 Sharding & IDs at Instagram With more than 25 photos & 90 likes every second, we store a lot of data here at Instagram. To make sure all of our important data fits into memory

再见伍德 1056
上一篇: Bytebase 签约 Xendit,助力东南亚 Stripe数据库变更自动化
下一篇: Bytebase 2.16.0 - 支持 Oracle 和 SQL Server DML 变更的事前备份
Bytebase
博客等级 码龄5年 1349粉丝 258原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值