在之前的文章中,我们分享了 Mailbox如何在六星期实现从零到百万用户及日处理亿条消息。其中我们提过Mailbox以14个人的小团队,在6个星期内实现0到百万用户的壮举,而服务日承载信息破亿条。随后在App发布不到3周,他们将自己以1亿美元的价格卖给了Dropbox。
在之前的文章中,我们分享了 Mailbox如何在六星期实现从零到百万用户及日处理亿条消息。其中我们提过Mailbox以14个人的小团队,在6个星期内实现0到百万用户的壮举,而服务日承载信息破亿条。随后在App发布不到3周,他们将自己以1亿美元的价格卖给了Dropbox。这次我们带来的是,Mailbox在快速扩展过程中,MongoDB所遭遇的性能瓶颈及解决途径。
以下为译文:
在Mailbox快速扩展过程中,其中一个性能问题就是MongoDB的数据库级别写锁,在锁等待过程中耗费的时间,直接反应到用户使用服务过程中的延时。为了解决这个长期存在的问题,我们决定将一个常用的MongoDB集合(储存了邮件相关数据)迁移到独立的集群上。根据我们推断,这将减少50%的锁等待时间;同时,我们还可以添加更多的分片,我们还期望可以独立的优化及管理不同类型数据。
我们首先从MongoDB文档开始,很快的就发现了 cloneCollection命令。然而随后悲剧的发现,它不可以在分片集合中使用;同样, renameCollection也不能在分片集合中使用。在否定了其它可能性之后(基于性能问题),我们编写了一个Python脚本用以复制数据,和另一个用于比较原始和目标数据的脚本。在这个过程中,我们还发现了许多有意思的事情,比如 gevent及 pymongo复制大数据集的时间是 mongodump(C++编写)的一半,即使MongoDB客户端和服务器在同台主机上。通过最终努力,我们开发了 Hydra,用于MongoDB迁移的工具集,现已开源。首先,我们建立了MongoDB集合的原始快照。
问题1:悲剧的性能
早期我做了一个实验以测试MongoDB API运作所能达到的极限速度——启用一个简单的使用MongoDB C++ 软件开发工具包的速度。一方面对C++ 感觉厌烦,一方面希望我大多数熟练使用Python的同事可以在其他用途上使用或适应这种代码,我没有更进一步的探索C++的使用,而是发现,如果是针对少量数据,在处理相同任务上,简单的C++应用速度是简单Python应用的5-10倍。
所以,我的研究方向回到了Python,这个Dropbox默认语言。此外,进行了诸如对mongod查询等的一系列远程网络请求时,客户端往往需要耗费大量时间等待服务器响应;似乎也没有很多copy_collection.py (我的MongoDB集合复制工具)需要的CPU密集型操作(部分)。initialcopy_collection.py占很少的CPU使用率也证实了这一点。
然后,MongoDB请求到copy_collection.py.。最初的工作线程实验结果并不理想。但接下来,我们通过Python Queue对象来实现工作线程通信。这样的性能依旧不是很好,因为IPC上的开销让并发带来的提升黯然失色。使用Pipes和其他IPC机制也并没有多大帮助。
接下来,我们尝试了使用单线程Python进行MongoDB异步查询,看看可以有多少性能结余。其中Gevent是实现这个途径常用库之一,我们对它进行了尝试。Gevent 修改了标准Python模块以实现异步操作,比如socket。比较好的一点是,你可以简单的编写异步读取代码,就像同步代码一样。
通常情况下,两个集合之间复制文档的异步代码会是:
import asynclib def copy_documents(source_collection, destination_collection, _ids, callback): """ Given a list of _id's (MongoDB's unique identifier field for each document), copies the corresponding documents from the source collection to the destination collection """ def _copy_documents_callback(...): if error_detected(): callback(error) # copy documents, passing a callback function that will handle errors and # other notifications for _id in _ids: copy_document(source_collection, destination_collection, _id, _copy_documents_callback) # more error handling omitted for brevity callback(None) def copy_document(source_collection, destination_collection, _id, callback): """ Copies document corresponding to the given _id from the source to the destination. """ def _insert_doc(doc): """ callback that takes the document read from the source collection and inserts it into destination collection """ if error_detected(): callback(error) destination_collection.insert(doc, callback) # another MongoDB operation # find the specified document asynchronously, passing a callback to receive # the retrieved data source_collection.find_one({'$id': _id}, callback=_insert_doc)
有了gevent,这些代码不再需要使用callback:
import gevent gevent.monkey.patch_all() def copy_documents(source_collection, destination_collection, _ids): """ Given a list of _id's (MongoDB's unique identifier field for each document), copies the corresponding documents from the source collection to the destination collection """ # copies each document using a separate greenlet; optimizations are certainly # possible but omitted in this example for _id in _ids: gevent.spawn(copy_document, source_collection, destination_collection, _id) def copy_document(source_collection, destination_collection, _id): """ Copies document corresponding to the given _id from the source to the destination. """ # both of the following function calls block without gevent; with gevent they # simply cede control to another greenlet while waiting for Mongo to respond source_doc = source_collection.find_one({'$id': _id}) destination_collection.insert(source_doc) # another MongoDB operation
这种简单的代码可以根据它们的_idfields,从MongoDB源集合拷取代码到目标位置,它们的_idfields是每个MongoDB文档的唯一标识符。opy_documents 会产委派greenlets运行runcopy_document()做文档复制。当greenlets执行一项阻塞操作,比如对MongoDB的任何需求,它会将控制放给其它准备执行的greenlet。因为所有greenlets都在相同的线程和进程中执行,你一般不需要任何形式的内部锁定。
有了gevent,就能够找到比工作者线程池或工作者进程池更快的方法。下面总结了每种方法的性能:
Approach | Performance (higher is better) |
---|---|
single process, no gevent | 520 documents/sec |
thread worker pool | 652 documents/sec |
process worker pool | 670 documents/sec |
single process, with gevent | 2,381 documents/sec |
综合gevent和工作者进程(每个分片一个)可以在性能上得到一个线性提升。有效使用工作进程的关键是尽可能使用更少的IPC。
问题2:快照后的复制修改
因为MongoDB不支持事务,如果你对正在执行修改的大数据集进行读取,你得到的结果可能会因时而异。举个例子,你使用MongoDB find()进行整个数据集上的读取,你的结果集可能是:
- ncluded: document saved before your find()
- included: document saved before your find()
- included: document saved before your find()
- included: document inserted after your find() began
此外,为了在Mailbox后端指向新副本集时能最小化故障时间,尽可能减少从源集群应用到新集群过程中所耗费的时间则至关重要。
类似多数的异步复制存储,MongoDB使用了操作日志oplog记录下了mongod实例上发生的增、改、删操作,用以分配给这个mongod实例的所有副本。鉴于快照,oplog记录下快照发生后的所有改变。
所以这里的工作就变成了在目标集群上应用源集群的oplog记录,从 Kristina Chodorow的教学博客上,我们清楚了oplog的格式。鉴于序列化的格式,增和删都非常容易执行,而改则成为了其中的难点。
改操作的oplog日志记录结构并不是非常友好:在MongoDB 2.2中使用了duplicate key,然而这些duplicate key并 不能通过Mongo shell呈现,更不必说大部分的MongoDB驱动。深思熟虑之后,选择了一个简单的变通方案:将_id嵌入修改源文档,以触发其它的文档副本。因为只是针对修改,虽然不能做到副本集和源实例的完全同步,但是却可以尽可能的减少副本集实时状态与快照之间的差距。下面这个图表显示为何中间版本(v2)并不一定完全相同,但是源副本与目的副本仍能保持最终一致:
在这里同样出现了目标集群的性能问题:虽然为每个分片的ops使用了独立的进程,但是连续的ops性能仍然匹配不了Mailbox的需求。
这样ops的并行就成了必选之路,然而其中的正确性保证却并不容易。特别的是,同_id操作必须被顺序执行。这里采用了一个Python集去维持正在执行修改ops的_id集:当copy_collection.py上发生一个请求正在执行修改操作的文档时,系统会阻塞后申请的所有ops(不管是修改或者是其它),直到旧的操作结束。如图所示:
>
验证复制数据
比较副本集与源实例数据通常是个简单的操作,但是在多进程与多命名空间中进行却是个非常大的挑战。同时基于数据正在不断的被修改,需要考虑的事情就更多了:
首先使用compare_collections.py(为对比数据开发的工具)对最近修改的文档进行数据校验,如果出现不一致则进行提醒,随后再进行复查。然而这对文档的删除并不有效,因为没有最后修改的时间戳。
其次想到的是“ 最终一致性”,因为这在异步场景中非常流行,比如MongoDB的副本集和MySQL的主/从复制。经过非常多的尝试之后(除下大故障情景下),源数据和副本都会保持最终一致。因此又进行了一些反复对比,在连续的重试中不断的增加backoff。发现仍然有一些问题存在,比如数据在两个值之间摇摆不定;然而在修改模式下,迁移的数据并不会出现任何问题。
在执行新旧MongoDB集群的最终转换之前,必须确保最近ops已经被应用,因此我们在compare_collections.py增加了命令行选项,用以对比文档被修改的最近N个操作,这样可以有效的避免不一致性。这个操作并不用耗费太多的时间,单分片执行数十万的ops对比只需短短的几分钟,还能缓和对比和重试途径的压力。
意外情况处理
尽管使用了多种途径去处理错误(重试、发现可能的异常、日志),在产品迁移之前的最终测试中仍然出现了许多未预计的错误。出现了一些不定期的网络问题,一个特定的文档集会一直导致mongos断开与copy_collection.py连接,以及与mongod的偶然连接重置。
而在尝试之后,我们发现针对这些问题制定出专门的解决方案,所以快速的转到了故障恢复方面。我们记录了这些compare_collections.py 检测出的文档_id,然后专门建立了针对这些_id的文档重复制工具。
最终迁移时刻
在产品迁移过程中,copy_collection.py建立了一个上千万电子邮件的原始快照,并且重现了过亿的MongoDB ops。执行原始快照、建立索引,整个复制过程持续了大约9个小时,而我们设定的时限是24个小时。期间我们又使用copy_collection.py重复3次,对需要复制的数据核查了3次。
全部转换直到今日才完成,与MongoDB相关的工作其实很少(只有几分钟)。在一个简洁的维护窗口中,我们使用compare_collections.py对比每个分片的最近的50万个ops。在确保最后操作中没有不一致后,我们又做了一些相关测试,然后将Mailbox后端指向了新集群,并将服务重新为用户开放。而在转换之后,我们未收到任何用户反馈的问题。让用户感觉不到迁移,就是最大的成功。迁移后的提升如下图所示:
写锁上的时间减少远高于50%(原预计)
开源Hydra
Hydra是上文操作所用到的所有工具合集,现已在 GitHub上开源。
Scaling MongoDB at Mailbox(编译/仲浩 审校/周小璐)
更多内容请关注CSDN云计算频道 及@CSDN云计算微博

Microsoft Word文档在保存时包含一些元数据。这些详细信息用于在文档上识别,例如创建时间、作者是谁、修改日期等。它还具有其他信息,例如字符数,字数,段落数等等。如果您可能想要删除作者或上次修改的信息或任何其他信息,以便其他人不知道这些值,那么有一种方法。在本文中,让我们看看如何删除文档的作者和上次修改的信息。删除微软Word文档中的作者和最后修改的信息步骤 1 –转到

本篇文章给大家带来了关于mysql的相关知识,其中主要介绍了关于索引优化器工作原理的相关内容,其中包括了MySQL Server的组成,MySQL优化器选择索引额原理以及SQL成本分析,最后通过 select 查询总结整个查询过程,下面一起来看一下,希望对大家有帮助。

使用系统信息单击“开始”,然后输入“系统信息”。只需单击程序,如下图所示。在这里,您可以找到大多数系统信息,而显卡信息也是您可以找到的一件事。在“系统信息”程序中,展开“组件”,然后单击“显示”。让程序收集所有必要的信息,一旦准备就绪,您就可以在系统上找到特定于显卡的名称和其他信息。即使您有多个显卡,您也可以从这里找到与连接到计算机的专用和集成显卡相关的大多数内容。使用设备管理器Windows11就像大多数其他版本的Windows一样,您也可以从设备管理器中找到计算机上的显卡。单击“开始”,然后

在iOS17中,有一个新的AirDrop功能,让你通过触摸两部iPhone来与某人交换联系信息。它被称为NameDrop,这是它的工作原理。NameDrop允许您简单地将iPhone放在他们的iPhone附近以交换联系方式,而不是输入新人的号码来给他们打电话或发短信,以便他们拥有您的号码。将两个设备放在一起将自动弹出联系人共享界面。点击弹出窗口会显示一个人的联系信息及其联系人海报(您可以自定义和编辑自己的照片,也是iOS17的新功能)。该屏幕还包括“仅接收”或共享您自己的联系信息作为响应的选项。

数据库系统由4个部分构成:1、数据库,是指长期存储在计算机内的,有组织,可共享的数据的集合;2、硬件,是指构成计算机系统的各种物理设备,包括存储所需的外部设备;3、软件,包括操作系统、数据库管理系统及应用程序;4、人员,包括系统分析员和数据库设计人员、应用程序员(负责编写使用数据库的应用程序)、最终用户(利用接口或查询语言访问数据库)、数据库管理员(负责数据库的总体信息控制)。

目前图像 3D 重建工作通常采用恒定自然光照条件下从多个视点(multi-view)捕获目标场景的多视图立体重建方法(Multi-view Stereo)。然而,这些方法通常假设朗伯表面,并且难以恢复高频细节。另一种场景重建方法是利用固定视点但不同点光源下捕获的图像。例如光度立体 (Photometric Stereo) 方法就采用这种设置并利用其 shading 信息来重建非朗伯物体的表面细节。然而,现有的单视图方法通常采用法线贴图(normal map)或深度图(depth map)来表征可

在iOS17中,有一项新的AirDrop功能,可让您通过同时触摸两部iPhone来与某人交换联系信息。它被称为NameDrop,这是它的实际工作原理。NameDrop无需输入新人的号码来给他们打电话或发短信,以便他们拥有您的号码,您只需将iPhone靠近他们的iPhone即可交换联系方式。将两台设备放在一起会自动弹出联系人共享界面。点击弹出窗口会显示一个人的联系信息和他们的联系人海报(您可以自定义和编辑的您自己的照片,也是iOS17的新功能)。该屏幕还包括“仅接收”或共享您自己的联系信息作为响应

微信收到信息延迟的原因可能是网络问题、服务器负载、版本问题、设备问题、消息发送问题或其他因素等。详细介绍:1、网络问题,微信收到信息的延迟可能与网络连接有关,如果网络连接不稳定或信号弱,可能导致信息传输延迟,请确保手机已经连接到稳定的网络,并且网络信号强度良好;2、服务器负载,当微信服务器负载较高时,可能会导致信息传输的延迟,特别是在繁忙的时间段或大量用户同时使用微信时等等。


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

AI Hentai Generator
Generate AI Hentai for free.

Hot Article

Hot Tools

SublimeText3 Linux new version
SublimeText3 Linux latest version

Notepad++7.3.1
Easy-to-use and free code editor

Atom editor mac version download
The most popular open source editor

WebStorm Mac version
Useful JavaScript development tools

ZendStudio 13.5.1 Mac
Powerful PHP integrated development environment
