Maison  >  Article  >  base de données  >  Comment MySQL utilise le partitionnement pour résoudre le problème de stockage de 50 milliards de données

Comment MySQL utilise le partitionnement pour résoudre le problème de stockage de 50 milliards de données

Guanhui
Guanhuiavant
2020-05-22 11:40:273562parcourir

Comment MySQL utilise le partitionnement pour résoudre le problème de stockage de 50 milliards de données

Il s'agit d'une étude technique sur la façon dont nous répartissons nos données sur plusieurs serveurs MySQL. Nous avons achevé cette approche de partitionnement début 2012, et c'est toujours le système que nous utilisons aujourd'hui pour stocker les données de base.

Avant de discuter de la façon de diviser les données, commençons par comprendre nos données. Éclairage d'ambiance, fraises enrobées de chocolat, citations de Star Trek...

Pinteres est le moteur de découverte de tout ce qui vous intéresse. Du point de vue des données, Pinterest est la plus grande collection d'images d'intérêt humain au monde. Il y a plus de 50 milliards d’épingles enregistrées par les Pinners sur 1 milliard de tableaux. Les utilisateurs épinglent à nouveau, comme les épingles d'autres personnes (en gros, une copie superficielle), suivent d'autres épingleurs, forums et centres d'intérêt, puis affichent toutes les publications des épingleurs abonnés sur la page d'accueil. Très bien! Maintenant, laissez-le évoluer !

Douleurs de croissance

En 2011, nous avons eu du succès. Dans certains rapports d'évaluation, nous grandissons beaucoup plus rapidement que d'autres startups. En septembre 2011, chacun de nos équipements de base a été dépassé. Nous avons appliqué un certain nombre de technologies NoSQL, qui ont toutes abouti à des résultats désastreux. Dans le même temps, le grand nombre de serveurs esclaves MySQL utilisés pour la lecture créait de nombreux bugs gênants, notamment la mise en cache. Nous avons restructuré l'ensemble du modèle de stockage des données. Pour que cela soit efficace, nous formulons soigneusement nos exigences.

Exigences commerciales

L'ensemble de notre système doit être très stable, facile à utiliser et facile à développer. Nous espérons que la base de données prise en charge pourra démarrer avec une petite capacité de stockage et pouvoir s'étendre à mesure que l'entreprise se développe.

Tous les contenus générés par les épingles doivent être facilement accessibles sur le site.

Prend en charge la demande d'accès à N Pins à afficher dans le plan de travail dans un certain ordre (par exemple en fonction de l'heure de création ou dans un ordre spécifique à l'utilisateur). Les amis Pin aimés et la liste Pin des amis Pin peuvent également être affichés dans un ordre spécifique.

Par souci de simplicité, les mises à jour garantissent généralement les meilleurs résultats. Pour obtenir une cohérence éventuelle, vous avez besoin de quelque chose de plus, comme un journal de transactions distribué. C’est une chose intéressante et (pas) simple.

Idées de solution et points clés

La solution nécessite de distribuer des tranches de données massives à plusieurs instances de base de données et ne peut pas utiliser de connexions, de clés étrangères ou d'indexation et d'autres méthodes pour intégrer l'intégralité données. Si vous y réfléchissez bien, les sous-requêtes corrélées ne peuvent pas s'étendre sur différentes instances de base de données.

Notre solution nécessite un accès aux données avec équilibrage de charge. Nous détestons la migration des données, en particulier la migration enregistrement par enregistrement, qui est très sujette aux erreurs et ajoute une complexité inutile au système en raison de la complexité des relations. Si les données doivent être migrées, il est préférable de migrer l'ensemble des nœuds logiques.

Afin de parvenir à une mise en œuvre fiable et rapide de la solution, nous devons utiliser la solution technique la plus simple à mettre en œuvre et la plus robuste sur notre plateforme de données distribuées.

Toutes les données de chaque instance seront entièrement copiées sur une instance esclave en tant que sauvegarde de données. Nous utilisons S3, un MapReduce (environnement informatique distribué) hautement disponible. Notre logique métier frontale accède aux données d'arrière-plan et accède uniquement à l'instance principale de la base de données. Ne donnez jamais à votre entreprise front-end un accès en lecture et en écriture aux instances esclaves. Étant donné qu'il y a un retard dans la synchronisation des données avec l'instance maître, cela provoquera des erreurs inexplicables. Une fois les données découpées et distribuées, il n'y a aucune raison pour que votre entreprise frontale lise et écrive des données à partir de l'instance esclave.

Enfin, nous devons concevoir soigneusement une excellente solution pour générer et analyser l'identifiant universellement unique (UUID) de tous nos objets de données.

Notre solution de slicing

Quoi qu'il en soit, nous devons concevoir une solution de distribution de données qui répond à nos besoins, qui soit robuste, performante et maintenable. En d’autres termes, cela ne peut pas être naïf (sans une validation approfondie). Par conséquent, notre conception de base est basée sur MySQL, nous avons donc choisi une technologie mature. Au début de la conception, nous éviterions naturellement d'utiliser des produits de bases de données qui prétendent disposer de nouvelles technologies telles que l'auto-scaling, comme MongoDB, Cassandra et Membase, car ils semblent simples à mettre en œuvre mais ont une faible applicabilité (souvent un problème inexplicable). une erreur s'est produite provoquant un crash).

Narration : Il est fortement recommandé de commencer par les bases et d'éviter les nouveautés et les tendances - apprenez et utilisez bien MySQL de manière terre-à-terre. Croyez-moi, chaque mot est rempli de larmes.

MySQL est un produit de base de données relationnelle mature, stable et facile à utiliser. Non seulement nous l'utilisons, mais de nombreuses grandes entreprises renommées l'utilisent également comme support de données back-end pour stocker d'énormes quantités de données. (Annotation : il y a environ quelques années, MySQL a été acquis par Oracle avec SUN et est devenu Oracle. De nombreuses entreprises, telles que Google, Facebook, etc., s'inquiétaient du problème open source de MySQL et sont passées à un autre celui développé par l'auteur original de MySQL. La base de données open source MariaDB (sous) MySQL prend en charge nos exigences techniques pour les demandes de données séquentielles à la base de données, l'interrogation d'une plage spécifiée de données et le traitement des transactions au niveau de la ligne (enregistrement). MySQL possède de nombreuses fonctionnalités, mais nous n'en avons pas besoin. Puisque MySQL lui-même est une solution monolithique, nous devons découper nos données. (Annotation : le sens ici est qu'une seule instance gère des quantités massives de données, ce qui entraînera inévitablement des problèmes de performances. Désormais, le découpage d'une masse de données globales en ensembles de données individuels nécessite une solution technique puissante pour séparer chaque donnée individuelle. Les monolithes sont intégrés dans un tout, améliorant les performances sans se tromper) Voici notre plan de conception :

Nous avons commencé avec 8 serveurs EC2, chaque serveur exécutant une instance MySQL :

Comment MySQL utilise le partitionnement pour résoudre le problème de stockage de 50 milliards de données

Chaque serveur MySQL est répliqué maître-maître sur un hôte redondant pour la reprise après sinistre. Notre activité front-end lit/écrit uniquement les données de l’instance de service principale. Je vous recommande de faire de même, cela simplifie beaucoup de choses et évite les problèmes de retard. (Annotation : la réplication maître-maître est une fonction fournie par la base de données MySQL elle-même. Elle fait référence à un mode dans lequel deux machines se sauvegardent mutuellement. Par rapport à d'autres modes, tels que la sauvegarde maître-esclave, les données des deux machines sont complètement Synchronisation en arrière-plan cohérente, chaque machine a sa propre adresse IP indépendante et est accessible simultanément. Cependant, l'auteur de l'article original a souligné à plusieurs reprises que bien que les deux machines soient redondantes et utilisent une sauvegarde primaire-primaire, elles sont logiquement accessibles. maître et esclave, lisez/écrivez toujours à partir de l'un d'eux. Par exemple, comme le montre la figure, il existe une sauvegarde maître-maître entre MySQL001A et MySQL001B, mais vous ne lisez/écrivez qu'à partir de MySQL001A. Un autre : ils utilisent 16 machines. , les 8 autres machines esclaves peuvent ne pas être EC2 ou non)

Chaque instance MySQL peut avoir plusieurs bases de données :

Comment MySQL utilise le partitionnement pour résoudre le problème de stockage de 50 milliards de données

Notez que chaque base de données est de manière unique nommez db00000, db00001, jusqu'à dbNNNN. Chaque base de données est un fragment de notre base de données. Nous avons conçu une conception pour qu'une fois qu'une donnée est allouée à une partition, elle ne soit pas déplacée hors de cette partition. Cependant, vous pouvez obtenir plus de capacité en déplaçant des fragments vers d'autres machines (nous en discuterons plus tard).

Nous maintenons une table de base de données de configuration, qui enregistre sur quelle machine se trouve la base de données de tranches :

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

Cette table de configuration n'est modifiée que lorsque la base de données de tranches est migrée ou que l'hôte est remplacé. Par exemple, si un hôte d'instance maître tombe en panne, nous promouvrons son hôte d'instance esclave au rang d'instance maître, puis le remplacerons par une nouvelle machine en tant qu'hôte d'instance esclave dès que possible. Le script de configuration est conservé sur ZooKeeper. Lorsque les modifications ci-dessus se produisent, le script est envoyé à la machine qui gère le service de découpage pour les modifications de configuration. (Annotation : vous pouvez trouver l'avantage que l'auteur original a toujours souligné que l'entreprise frontale ne lit et n'écrit que les données de l'instance principale logique).

Chaque base de données de tranches conserve la même table de base de données et la même structure de table, telles que les broches, les tableaux, les utilisateurs_has_pins, les utilisateurs_likes_pins, les pin_liked_by_user et d'autres tables de base de données. Créez de manière synchrone au moment du déploiement.

Plan de conception pour la distribution des données aux serveurs de tranches

Nous combinons l'ID de fragment (ID de fragment), l'identification du type de données et l'ID local (ID local) pour former un 64 -bit d'identification (ID) unique au monde. L'ID de tranche (ID de fragment) occupe 16 bits (bit), l'identifiant de type de données occupe 10 bits (bit) et l'ID local (ID local) occupe 36 bits (bit). Quiconque a un œil averti remarquera immédiatement qu’il ne s’agit que de 62 bits. Mon expérience passée dans la distribution et l’intégration de données me dit qu’en conserver quelques-unes pour l’expansion n’a pas de prix. J'ai donc gardé 2 bits (mis à 0). (Annotation : laissez-moi vous expliquer ici. D'après les opérations et explications suivantes, l'ID d'identification unique de tout objet est de 64 bits, les 2 bits les plus élevés sont toujours 0, suivis d'une identification locale de 36 bits, suivis d'un 10 bits identification de type, et enfin un 16 bits L'identifiant de tranche peut représenter 2^36 jusqu'à plus de 60 milliards d'ID. Le type de données peut représenter 2^10 jusqu'à 1024 types d'objets, et l'identifiant de tranche peut être subdivisé en 2^16. jusqu'à 65536 bases de données de tranches. Couper 4096 bases de données de tranches)

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

On peut voir que cet objet Pin est dans la base de données de 3429 tranches. Supposons que l'identifiant du type de données de l'objet Pin est 1 et que son enregistrement se trouve dans la ligne d'enregistrement 7075733 de la table de données Pin de la base de données de tranches 3429. Par exemple, en supposant que la base de données de la tranche 3429 se trouve dans MySQL012A, nous pouvons utiliser l'instruction suivante pour obtenir son enregistrement de données : (Annotation : l'auteur original donne ici un exemple général. D'après l'exemple précédent, 3429 devrait être sur 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 查询其具体信息。

Nous mappons ces relations uniquement au niveau de la couche d'application métier, telles que board_id -> pin_ids -> objets pin (à partir de l'ID du tableau blanc -> ID de note -> Objets de note). Une fonctionnalité intéressante de cette conception est que vous pouvez mettre en cache ces paires de cartes relationnelles séparément. Par exemple, nous mettons en cache le mappage de la relation pin_id -> pin object (ID de note -> objet de note) sur le serveur de cluster memcache (cache mémoire), et la relation board_id -> cache de mappage sur Redis sur le serveur de cluster. De cette façon, il peut être très approprié pour notre stratégie technologique de mise en cache d’optimisation.

Augmenter les capacités de service

Dans notre système, il existe trois façons principales d'améliorer les capacités de traitement des services. Le plus simple est de mettre à niveau la machine (espace plus grand, vitesse du disque dur plus rapide, plus de mémoire, quelle que soit la mise à niveau qui peut résoudre le goulot d'étranglement du système)

Une autre façon consiste à élargir la plage de découpage. Initialement, nous avons conçu uniquement pour découper 4096 bases de données. Par rapport à l'ID de tranche de 16 bits que nous avons conçu, il y a encore beaucoup d'espace, car 16 bits peuvent représenter 65 536 nombres. À un moment donné, si nous fournissons 8 machines supplémentaires pour exécuter 8 instances de base de données MySQL et fournissons des bases de données de découpage de 4096 à 8192, alors les nouvelles données ne seront stockées que dans les bases de données de découpage de cette plage. Il existe 16 bases de données informatiques parallèles et les capacités de service vont inévitablement s'améliorer.

La dernière méthode consiste à migrer l'hôte de la base de données de découpage vers un nouvel hôte de découpage (extension de découpage local) pour améliorer les capacités. Par exemple, nous souhaitons étendre et distribuer l'hôte de découpage MySQL001A de l'exemple précédent (sur lequel se trouvent les bases de données de découpage numérotées de 0 à 511) à 2 hôtes de découpage. Comme nous l'avons conçu, nous créons une nouvelle paire d'hôtes de sauvegarde mutuelle maître-maître en tant que nouveaux hôtes de tranche (nommés MySQL009A et B) et copions entièrement les données de MySQL001A.

Comment MySQL utilise le partitionnement pour résoudre le problème de stockage de 50 milliards de données

Une fois la copie des données terminée, nous modifions la configuration du découpage. MySQL001A est uniquement responsable de la base de données de découpage de 0 à 255, et MySQL009A est uniquement responsable de la base de données de découpage. de 256 à 511. Désormais, chacun des deux hôtes n'est responsable que de la moitié des tâches dont l'hôte précédent était responsable, et la capacité de service a été améliorée.

Comment MySQL utilise le partitionnement pour résoudre le problème de stockage de 50 milliards de données

Quelques descriptions de fonctionnalités

Pour les données d'objet métier générées par l'ancien système, les objets métier doivent être générés selon le conception Avec les UUID dans le nouveau système, vous devez comprendre que leur destination (quelle base de données de tuiles) vous décidez dépend de vous. (Annotation : vous pouvez planifier la distribution des anciennes données sur la base de données slice) Cependant, lors de leur mise dans la base de données slice, uniquement lors de l'insertion d'un enregistrement, la base de données renverra l'ID local de l'objet inséré. Avec cela, l'UUID de. l'objet peut être construit.

(Annotation : lors de la migration, vous devez envisager l'établissement de relations entre les objets métier via l'UUID)

Pour les tables de base de données qui contiennent déjà une grande quantité de données, j'ai utilisé la table de modification commande de structure (ALTER) - comme l'ajout d'un champ - vous savez que c'est un processus très long et douloureux. Notre conception est de ne jamais utiliser de commandes de niveau ALTER sur MySQL (lorsque les données sont déjà disponibles). Sur notre système d'entreprise, Pinterest, la dernière instruction ALTER que nous avons utilisée remonte à environ 3 ans. Pour les objets de la table d'objets, si vous devez ajouter un champ d'attribut d'objet, vous l'ajoutez au champ blob JOSON des données d'objet. Vous pouvez définir une valeur par défaut pour les propriétés du nouvel objet. Lors de l'accès aux données de l'ancien objet, si l'ancien objet n'a pas de nouvelles propriétés, vous pouvez lui ajouter une nouvelle valeur par défaut de propriété. Pour les tables de mappage relationnel, créez simplement une nouvelle table de mappage relationnel pour répondre à vos besoins. Vous savez tout cela ! Laissez votre système décoller !

Partage de base de données Mod

Le nom du fragment de mod est similaire à Mod Squad, mais en fait il est complètement différent.

Certains objets métier doivent être accessibles via une requête sans ID. (Traduction : cet identifiant fait référence à l'UUID 64 bits dans la description de conception précédente) Par exemple, si un Pinner s'inscrit et se connecte à notre plateforme commerciale avec son compte Facebook enregistré. Nous devons mapper leur identifiant Facebook avec notre identifiant Pinner. Pour notre système, l'identifiant Facebook n'est qu'une série de chiffres binaires. (Annotation : cela implique que nous ne pouvons pas déconstruire les identifiants d'autres plates-formes comme la conception de notre plate-forme système, ni parler de la façon de concevoir des tranches. Nous les sauvegardons simplement et les concevons pour qu'elles correspondent à nos identifiants) Par conséquent, nous devons Enregistrez-les, ils doivent également être enregistrés respectivement dans la base de données de tranches. Nous appelons cela un fragment de mod. D'autres exemples incluent les adresses IP, les noms d'utilisateur et les adresses e-mail des utilisateurs.

模转数据切片(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=&#39;1.2.3.4&#39;”)

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

最后的提醒

这个系统作为 Pinterest 的数据支撑已良好运行了 3.5 年,现在看来还会继续运行下去。设计实现这样的系统是直观、容易的。但是让它运行起来,尤其迁移旧数据却太不易了。若您的业务平台面临着急速增长的痛苦且您想切片自己的数据库。建议您考虑建立一个后端集群服务器(优先建议 pyres)脚本化您迁移旧数据到切片数据库的逻辑,自动化处理。我保证无论您想得多周到,多努力,您一定会丢数据或丢失数据之间的关联。我真的恨死隐藏在复杂数据关系中的那些捣蛋鬼。因此,您需要不断地迁移,修正,再迁移... 你需要极大的耐心和努力。直到您确定您不再需要为了旧数据迁移而往您的切片数据库中再操作数据为止。

这个系统的设计为了数据的分布切片,已尽最大的努力做到最好。它本身不能提供给你数据库事务 ACID 四要素中的 Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)哇呕!听起来很坏呀,不用担心。您可能不能利用数据库本身提供的功能很好地保证这些。但是,我提醒您,一切尽在您的掌握中,您只是让它运行起来,满足您的需要就好。设计简单直接就是王道,(译注:也许需要您做许多底层工作,但一切都在您的控制之中)主要是它运行起来超快! 如果您担心 A(原子性)、I(隔离性)和 C(一致性),写信给我,我有成堆的经验让您克服这些问题。

还有最后的问题,如何灾难恢复,啊哈? 我们创建另外的服务去维护着切片数据库,我们保存切片配置在 ZooKeeper 上。当单点主服务器宕掉时,我们有脚本自动地提升主服务器对应的从服务器立即顶上。之后,以最快的速度运行新机器顶上从服务器的缺。直至今日,我们从未使用过类似自动灾难恢复的服务。

推荐教程:《MySQL教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer