百分百源码网-让建站变得如此简单! 登录 注册 签到领金币!

主页 | 如何升级VIP | TAG标签

当前位置: 主页>网站教程>数据库> Pinterest MySQL实践应用分片来解决百亿数据的存储题目
分享文章到:

Pinterest MySQL实践应用分片来解决百亿数据的存储题目

发布时间:01/01 来源:未知 浏览: 关键词:
mysql视频教程栏目介绍利用分片解决百亿数据的储备

引荐(免费):mysql视频教程

这是一个关于我们在多个 MySQL效劳器上分割数据的技术研讨。我们在2012年年初完成了这个分片办法,它仍是我们今天用来储备中心数据的系统。

在我们计议怎样分割数据此前,让我们先理解一下我们的数据。表情照明,巧克力草莓,星际迷航语录……

Pinteres 是你感乐趣的所有东西的发明引擎。从数据的角度来说,Pinterest 是世界上最大的人类乐趣图集。有超越500亿的 Pin 被 Pin 友们留存在10亿块图板上。 会员再次 Pin,喜爱其别人的 Pin(粗略地说是一个浅显的复制品),关注其他 Pin 友,画板和乐趣,然后查看主页上所订阅Pin友的所有资讯。 太好了! 此刻让它扩大规模!

成长的痛

在2011年我们取得了成功。 在 一些 评估报告里,我们的开展比其他的初创公司要快得多。在2011年9月,我们每一项根基设备都超出了负载。我们利用了一些 NoSQL 技术,所有这些技术都致使了劫难性的后果。 同时,大量用于读的 MySQL 从效劳器发生了大量令人恼火的 bugs,特殊是缓存。我们重构了整个数据储备模式。为了使之有效,我们细心拟定了我们的要求。

业务要求

  • 我们的全部系统需要非常不乱,易于操纵和易于扩展。 我们但愿支撑数据库能从开端的小储备量,能随着业务开展而扩展。
  • 所有 Pin友 生成的内容在网站上必需随时可以拜访。
  • 支撑以肯定的次序恳求拜访 N 个 Pin在画板中展现(像依照创立的时间,或者依照会员特定的次序)。关于喜爱的 Pin 友和 Pin友的 Pin 列表等也能依照特定的次序展现。
  • 为了简便起见,更新一样要包管最好的结果。为了猎取终究一致性,你需要一些额外的东西,如分布式 事务日志。这是一件有味并(不)简便的事情。

解决思绪及要点备注

解决方案由于需要将海量的数据切片分布到多个数据库实例上,不克不及使用关系数据库的连接、外键或索引等办法整合整个数据。想想就知道,关联的子查询不克不及跨过不一样的数据库实例。

我们的方案需要负载均衡数据拜访。我们憎恨数据迁移,特别是逐个记载停止迁移,因关系的复杂性,这样非常容易发生错误且加重系统不必要的复杂性。假如必需要迁移数据,最好是逻辑节点集的团体迁移。

为了到达方案实施的可靠快速,我们需要在我们的分布式数据平台上使用最易于实现、最强健的技术方案。

每个实例上的所有的数据将被完全复制到一个从实例上,作为数据备份。我们使用的是高可用性的 MapReduce (分布式运算环境) 的 S3 。我们前端的业务逻辑拜访后台数据,只拜访数据库的 主实例永久不要让您的前端业务去读写拜访从实例 。由于它与 主实例 数据同步存在延迟,会造成莫明其妙的错误,一旦将数据切片并分布,没有一丝理由让你前端业务从 从实例 上读写数据。

最后,我们需要精心设计一个优异的方案生成和解析我们所有数据对象的 全局独一标识( UUID )

我们的切片方案

不管怎样,我们需要设计相符我们需求的,强健的,机能优秀和可保护的数据分布解决方案。换句话说,它不克不及稚嫩(未经广泛验证)。因此,我们的根基设计创立在 MySQL 之上,拜见 we chose a mature technology(选中成熟技术) 。设计之初,我们天然会跳开不消那些号称具有主动分布(auto-scaling)新技术能力的数据库产品,诸如 MongoDB,Cassandra 和 Membase 之类的产品,由于它们好像实施简便却适用性太差(常常发生莫明其妙的错误致使崩溃)。

旁白:热烈倡议从底层根基入手,幸免时髦新颖的东东 — 扎扎实实把 MySQL 学好用好。信赖我,字字都是泪。

MySQL 是成熟、不乱并且就是好使的关系型数据库产品。不仅我们用它,包罗很多知名大公司也使用它作为后台数据支撑,储备着海量的数据。(译注:大约几年前,由于MySQL随着 SUN 被 Oracle 的收购,归到 Oracle 名下。很多公司,如 google,facebook 等由于担忧 MySQL 的开源问题,纷纷转到由 MySQL 原作者开发的另一个开源数据库 MariaDB 下)MySQL 支撑我们对数据库要求按序数据恳求,查询指定范畴数据及行(记载)级上的事务处置的技术要求。MySQL有一堆功效特性,但我们不需要那些。由于 MySQL 本身是个单体解决方案,可我们却要把我们的数据切片。(译注:此处的意思是,一个单实例治理海量的数据,势必造成机能问题。此刻把一个海量团体数据切片成一个个单体数据集,需要一个强有力的技术解决方案,把一个个的单体整合成一个团体,提高机能还不出错)下面是我们的设计方案:

我们起始使用8台 EC2 效劳器,每台效劳器都运转一个 MySQL 实例:

每个 MySQL 效劳器各自以 主-主备份( master-master replicated )到1台冗余主机作为劫难复原。我们前台业务只从主效劳实例读/写数据 。我倡议你也这么做,它简化很多事情,幸免延迟故障。(译注:主-主备份( master-master replicated ) 是MySQL数据库本身供给的功效,指两台机器互做备份的一种模式,相对其它模式,如 主-从备份,两台机器数据完全一致,后台同步,每台机器有本人独自 IP 都可拜访,可并发读/写拜访。但原文作者一再强调的是虽然这两台互为冗余使用 主-主备份,都可拜访。但你逻辑上区分 主-从,永久只从其中一个停止读/写。例如,图中所示, MySQL001A 和 MySQL001B 间 主-主备份,但你只从 MySQL001A 停止读/写拜访。另:他们使用了16台机器,另8台做从机的大概不是 EC2 也未必)

每个 MySQL 实例可以有多个数据库:

留意每个数据库是怎样独一地命名为 db00000,db00001,直到 dbNNNN。每个数据库都是我们数据库的分片。我们做了一个设计,一旦一块数据被分配到一个分片中,它就不会移出阿谁分片。但是,你可以通过将分片移动到其他机器来获得更大的容量(我们将在后面计议这一点)。

我们保护着一个配置数据库表,此表中记载这切片数据库在哪台机器上:

[
{“range”: (0,511), “master”: “MySQL001A”, “slave”: “MySQL001B”},
{“range”: (512, 1023), “master”: “MySQL002A”, “slave”: “MySQL002B”},
 ...
{“range”: (3584, 4095), “master”: “MySQL008A”, “slave”: “MySQL008B”}
]

这个配置表仅当迁移切片数据库或更换主机时修改。例如,一个主实例主机宕掉了,我们会晋升它的从实例主机为主实例,然后尽快顶替一个新机器当从实例主机。配置足本保存在 ZooKeeper 上,当显现上述修改时,通过足本发送到保护切片效劳的机器上停止配置改动。(译注:可发明原作者不断强调的,前端业务仅从逻辑主实例读写数据的好处)。

每个切片数据库保持雷同的数据库表及表构造,诸如,有 pins ,boards ,users_has_pins ,users_likes_pins ,pin_liked_by_user 等数据库表。 在布署时同步构建。

分布数据到切片效劳器设计方案

我们组合 切片 ID(shard ID) 、数据类型标识和 部分 ID(local ID) 构成64位的 全局独一标识(ID)切片 ID(shard ID) 占16个位(bit), 数据类型标识占10个位(bit), 部分 ID(local ID) 占36个位(bit)。 明眼人立刻会发明,这才62位。我过去的分布及整合数据经历告诉我,保存几位留做扩展是无价宝。因此,我保存了2位(设为0)。(译注:这里说明一下,按照后面的运算和说明,任何对象的独一标识 ID 是64位,最高2位始终为0,之后是36位的部分标识,之后是10位类型标识,最后是16位的切片标识。部分标识可表示 2^36达600多亿个 ID 。数据类型可表示2^10达1024个对象类型,切片标识可细分成2^16达65536个切片数据库。前面说的方案切了4096个切片数据库)

ID = (shard ID << 46) | (type ID << 36) | (local ID<<0)

以 Pin: https://www.pinterest.com/pin/241294492511... 为例,让我们解构这个 Pin 对象的 全局 ID 标识 241294492511762325 :

Shard ID = (241294492511762325 >> 46) & 0xFFFF = 3429
Type ID  = (241294492511762325 >> 36) & 0x3FF = 1
Local ID = (241294492511762325 >>  0) & 0xFFFFFFFFF = 7075733

可知这个 Pin 对象在3429切片数据库里。 假设 Pin 对象 数据类型标识为 1,它的记载在3429切片数据库里的 pin 数据表中的 7075733 记载行中。举例,假设切片3429数据库在 MySQL012A中,我们可利用下面语句得到其数据记载:(译注:这里原作者泛泛举例,若按其前面方案例子来说,3429应在MySQL007A 上)

conn = MySQLdb.connect(host=”MySQL012A”)
conn.execute(“SELECT data FROM db03429.pins where local_id=7075733”)

有两品种型的数据:对象或关系。对象包括对象本身细节。 如 Pin 。

储备对象的数据库表

对象库表中的每个记载,表示我们前端业务中的一个对象,诸如:Pins(钉便签), users(会员),boards(白板)和 comments(注释),每个这样的记载在数据库表中设计一个标识 ID 字段(这个字段在表中作为记载的 自增主键「auto-incrementing primary key」 ,也就是我们前面提到的 部分 ID「 local ID」 ),和一个 blob 数据字段 -- 使用 JSON 留存对象的详细数据 --。

CREATE TABLE pins (
  local_id INT PRIMARY KEY AUTO_INCREMENT,
  data TEXT,
  ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

举例,一个 Pin 对象外形如下:

{“details”: “New Star Wars character”, “link”: “http://webpage.com/asdf”, “user_id”: 241294629943640797, “board_id”: 241294561224164665, …}

创立一个 Pin 对象,收集所有的数据构成 JSON blob 数据。然后,肯定它的 切片 ID「 shard ID」 (我们更乐意把 Pin 对象的切片数据放到跟其所在 白板「 board」 对象雷同的切片数据库里,这不是强迫设计规则)。Pin 对象的数据类型标识为 1。连接到 切片 ID 指示的切片数据库,插入(insert)Pin 对象的 JOSON 数据到 Pin 对象数据库表中,MySQL 操纵成功后将会返回 自增主键「auto-incrementing primary key」 给你,这个作为此 Pin 对象的 部分 ID「 local ID」。此刻,我们有了 shard 、类型值、local ID 这些必要信息,就可以构建出此 Pin 对象的64位 ID 。(译注:原作者提到的,他们的前端业务所用到的每种对象都留存在一个对象数据库表里,每个对象记载都通过一个全局独一 ID去寻到它,但这个全局独一 ID并不是数据库表中的 部分ID,由于切片的原因。原作者不断在讲这个设计及其道理。这样设计的目的为了海量数据切片提高机能,还要易用,可保护,可扩展。后面,作者会顺次讲解到)

编纂一个 Pin 对象,使用 MySQL 事务「transaction」 在 Pin 对象的数据记载上 读出--修改--写回「read-modify-write」 Pin 对象的 JOSON 数据字段:

> BEGIN
> SELECT blob FROM db03429.pins WHERE local_id=7075733 FOR UPDATE
[修改 json blob]
> UPDATE db03429.pins SET blob=’<修改后的 blob>’ WHERE local_id=7075733
> COMMIT

编纂一个 Pin 对象,您当然可以直接删除这个对象在 MySQL 数据库表中的数据记载。但是,请细心想一下,可否在对象的 JSON 数据上加个叫做「 active」的域,把剔除工作交由前端中心业务逻辑去处置或许会更好呢。

(译注:学过关系数据库的应知道,自增主键在记载表中是固实,在里面删除记载,会造成孔洞。当多了,势必造成数据库机能下落。数据库只负责留存数据和高机能地查询、读写数据,其数据间的关系完全靠设计精良的对象全局ID通过中心件逻辑去保护 这样的设计理念不断贯穿在作者的行文中。只要懂得了这点您才能抓住这篇文章的中心)

关系映射数据库表

关系映射表表示的是前端业务对象间的关系。诸如:一个白板(board)上是什么钉便签(Pin), 一个钉便签(Pin)在哪些白板(board)上等等。表示这种关系的 MySQL 数据库表包罗3个字段:一个64位的「from」ID, 一个64位的「to」ID和一个次序号。每个字段上都做索引利便快速查询。其记载留存在按照「from」字段 ID 解构出来的切片 ID 指示出的切片数据库上。

CREATE TABLE board_has_pins (
  board_id INT,
  pin_id INT,
  sequence INT,
  INDEX(board_id, pin_id, sequence)
) ENGINE=InnoDB;

(译注:这里的关系映射指前端业务对象间的关系用数据库表来运维,并不指我上节注释中说到的关系数据库的关系映射。作者开篇就讲到,由于切片,不克不及做关系数据库表间的关系映射的,如一对一,一对多,多对多等关系关联)

关系映射表是单向的,如 board_has_pins(板含便签)表利便按照 board (白板)ID查询其上有多少 Pin(钉便签)。若您需要按照 Pin(钉便签)ID查询其都在哪些 board(白板)上,您可另建个表 pin_owned_by_board(便签属于哪些白板)表,其中 sequence 字段表示 Pin 在 board 上的次序号。(由于数据分布在切片数据库上,我们的 ID 本身没法表示其次序)我们平常将一个新的 Pin 对象加到 board 上时,将其 sequence 设为当时的系统时间。sequence 可被设为任意整数,设为当时的系统时间,包管创建的对象的 sequence 总是大于旧对象的。这是个利便易行的办法。您可通过下面的语句从关系映射表中查询对象数据集:

SELECT pin_id FROM board_has_pins 
WHERE board_id=241294561224164665 ORDER BY sequence 
LIMIT 50 OFFSET 150

语句会查出50个 pin_ids(便签 ID ),随后可用这些对象 ID 查询其详细信息。

我们只在业务利用层停止这些关系的映射,如 board_id -> pin_ids -> pin objects (从 白板 ID -> 便签 IDs -> 便签对象)。 这种设计一个非常棒的特性是,您可以分开缓存这些关系映射对。例如,我们缓存 pin_id -> pin object (便签 ID -> 便签对象)关系映射在 memcache(内存缓存)集群效劳器上,board_id -> pin_ids (白板 ID -> 便签 IDs)关系映射缓存在 redis 集群效劳器上。这样,可以非常适合我们优化缓存技术战略。

增大效劳能力

在我们的系统中,晋升效劳处置能力主要三个途径。最容易的是升级机器(更大的空间,更快的硬盘速度,更多的内存,不管什么解决系统瓶颈的升级都算)

另一个途径,扩大切片范畴。最初,我们设计只切片了4096个数据库,比拟我们设计的16位的切片 ID,还有很多空间,由于16位可表示65536个数。某些时间节点,若我们再供给8台机器运转8个 MySQL 数据库实例,供给从 4096 到 8192 的切片数据库,之后,新的数据将只往这个区间的切片数据库上存置。并行运算的数据库有16台,效劳能力必定晋升。

最后的途径,迁移切片数据库主机到新切片主机(部分切片扩容)以晋升能力。例如,我们想将前例中的 MySQL001A 切片主机(其上是 0 到 511 编号的切片数据库)扩展分布到2台切片主机上。同我们设计地,我们创立一个新的 master-master 互备份主机对作为新切片主机(命名为 MySQL009A 和 B)并从 MySQL001A 上团体复制数据。

当数据复制完成后,我们修改切片配置,MySQL001A 只负责 0 到 255 的切片数据库,MySQL009A 只负责 256 到 511 的切片数据库。此刻2台中每台主机只负责过去主机负责的一半的任务,效劳能力晋升。

一些特性说明

关于旧系统已发生的业务对象数据,要按照设计,对业务对象要生成它们在新系统中的 UUIDs,你应意识到它们放到哪儿(哪个切片数据库)由你决议。(译注:你可以计划旧数据在切片数据库上的分布)但是,在放入到切片数据库时,只要在插入记载时,数据库才会返回插入对象的 local ID,有了这个,才能构建对象的 UUID。
(译注:在迁移时要思考好业务对象间关系的创立,通过UUID)

关于那些在已有大量数据的数据库表,曾使用过修改表构造类命令 (ALTERs)--诸如增加个字段之类的 -- 的人来说,您知道那是一个 非常 漫长和疾苦的历程。我们的设计是绝不使用 MySQL 上 ALTERs 级别的命令(当已有数据时)。在我们的业务系统 Pinterest 上,我们使用最后一个 ALTER 语句大约是在3年前了。 关于对象表中对象,假如您需要增加个对象属性字段,您增加到对象数据的 JOSON blob 字段里。您可以给新对象属性设定个默许值,当拜访到旧对象的数据时,若旧对象没有新属性,您可以给其增加上新属性默许值。关于关系映射表来说,干脆,直接创立新的关系映射表以相符您的需要。这些您都分明了!让您的系统扬帆起行吧!

模转(mod)数据库的切片

模转数据切片(mod shard)名称仅仅是像 Mod Squad,实则完全不一样。

一些业务对象需要通过非 ID (non-ID)的方式查询拜访。(译注: 此 ID 指此前设计说明中的64位 UUID)举例来说,假如一位 Pin友(Pinner)是以他(她)的 facebook 注册帐号注册登录我们的业务平台上的。我们需将其 facebook ID 与我们的 Pin友(Pinner)的 ID 映射。 facebook ID 关于我们系统只是一串二进制位的数。(译注:默示我们不克不及像我们系统平台的设计那样解构别的平台的 ID,也谈不上怎样设计切片,只是把它们留存起来,并设计使之与我们的 ID 映射)因此,我们需要留存它们,也需要把它们离别留存在切片数据库上。我们称之为模转数据切片(mod shard)其它的例子还包罗 IP 地址、会员名和会员电子邮件等。

模转数据切片(mod shard)相似前述我们业务系统的数据切片设计。但是,你需要依照其输入的原样停止查询。怎样肯定其切片位置,需要用到哈希和模数运算。哈希函数将任意字串转换成定长数值,而模数设为系统已有切片数据库的切片数目,取模后,其必定落在某个切片数据库上。结果是其数据将留存在已有切片数据库上。举例:

shard = md5(“1.2.3.4") % 4096

(译注:mod shard 这个词,我网上寻遍了,试图寻到一个较准确权威的中文翻译!无果,由于 mod 这个词有几种意思,比来的是module 模块、模组,同时它也是模运算符(%)。我按照原辞意思,翻译为 模转 。或可翻译为 模式,但个人感受意思含糊。不妥之处,请指正。另,原作者举的例子是以 IP 地址举例的,哈希使用的是 md5,比拟其它,虽老但机能最好)

在这个例子中分片是1524。 我们保护一个相似于ID分片的配置文件:

[{“range”:    (0,  511), “master”: “msdb001a”, “slave”: “msdb001b”},
  {“range”:  (512, 1023), “master”: “msdb002a”, “slave”: “msdb002b”},
  {“range”: (1024, 1535), “master”: “msdb003a”, “slave”: “msdb003b”},
…]

因此,为了寻到 IP 为1.2.3.4的数据,我们将这样做:

conn = MySQLdb.connect(host=”msdb003a”)
conn.execute(“SELECT data FROM msdb001a.ip_data WHERE ip='1.2.3.4'”)

你失去了一些分片好的属性,例如空间位置。你必需从一开端就设定分片的密钥(它不会为你制作密钥)。最好使用不变的id来表示系统中的对象。这样,当会员更换其会员名时,您就不必更新很多援用。

最后的提示

这个系统作为 Pinterest 的数据支撑已良好运转了3.5年,此刻看来还会连续运转下去。设计实现这样的系统是直不雅、容易的。但是让它运转起来,特别迁移旧数据却太不易了。若您的业务平台面临焦急速增长的疾苦且您想切片本人的数据库。倡议您思考创立一个后端集群效劳器(优先倡议 pyres)足本化您迁移旧数据到切片数据库的逻辑,主动化处置。我包管不管您想得多周密,多努力,您必然会丢数据或丧失数据之间的关联。我真的恨死潜藏在复杂数据关系中的那些捣蛋鬼。因此,您需要不竭地迁移,批改,再迁移... 你需要极大的耐心和努力。直到您肯定您不再需要为了旧数据迁移而往您的切片数据库中再操纵数据为止。

这个系统的设计为了数据的分布切片,已尽最大的努力做到最好。它本身不克不及供给给你数据库事务 ACID 四要素中的 Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)哇呕!听起来很坏呀,不消担忧。您大概不克不及利用数据库本身供给的功效很好地包管这些。但是,我提示您,一切尽在您的把握中,您只是让它运转起来,知足您的需要就好。设计简便直接就是王道,(译注:或许需要您做很多底层工作,但一切都在您的操纵之中)主如果它运转起来超快! 假如您担忧 A(原子性)、I(隔离性)和 C(一致性),写信给我,我有成堆的经历让您克制这些问题。

还有最后的问题,怎样劫难复原,啊哈? 我们创立别的的效劳去保护着切片数据库,我们留存切片配置在 ZooKeeper 上。当单点主效劳器宕掉时,我们有足本主动地晋升主效劳器对应的从效劳器马上顶上。之后,以最快的速度运转新机器顶上从效劳器的缺。直至今日,我们从未使用过相似主动劫难复原的效劳。

以上就是Pinterest MySQL实践利用分片来解决百亿数据的储备问题的具体内容,更多请关注百分百源码网其它相关文章!

打赏

打赏

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

百分百源码网 建议打赏1~10元,土豪随意,感谢您的阅读!

共有150人阅读,期待你的评论!发表评论
昵称: 网址: 验证码: 点击我更换图片
最新评论

本文标签

广告赞助

能出一分力是一分吧!

订阅获得更多模板

本文标签

广告赞助

订阅获得更多模板