Python是一种强大而灵活的编程语言,全世界有数百万开发人员使用它来构建他们的应用程序。Python开发人员通常使用MongoDB主机(最流行的NoSQL数据库)进行应用部署,这并不奇怪,因为它很灵活且对模式没有要求。
那么,在Python中使用MongoDB的最佳方式是什么?PyMongo是一个Python发行版库,它包含用于使用MongoDB的工具,以及推荐的PythonMongoDB驱动程序。它是一个相当成熟的驱动程序,支持数据库的大多数常见操作,你可以查看本教程来了解PyMongo驱动程序的介绍。
Python学习交流群:1004391443,这里有资源共享,技术解答,还有小编从最基础的Python资料到项目实战的学习资料都有整理,希望能帮助你更了解python,学习python
在生产环境中部署时,强烈建议你使用一个MongoDB副本集配置进行设置,以便你的数据在地理上合理分布,从而获得高可用性。我还建议你启用SSL连接来加密客户机-数据库通信。我们经常对各种MongoDB驱动程序的故障转移特性进行测试,以使它们适用于生产用例,或者在我们的客户向我们咨询时。在本文中,我们将向你展示如何使用PyMongo连接到一个配置了自签名证书且启用了SSL的MongoDB副本集,以及如何测试代码中的MongoDB故障转移行为。
使用自签名证书连接到MongoDB SSL
第一步是确保安装了正确版本的PyMongo及其依赖项。这个指南会帮助你整理依赖性,驱动程序兼容性列表也可以在这里找到。
为了使用自签名证书连接到一个启用了SSL的MongoDB端点,mongo_client.MongoClient中的ssl和ss_ca_cert参数是我们所关心的。 我们必须将ssl设置为True,并且ss_ca_cert必须指向CA证书文件。
如果你是一个ScaleGrid客户,可以从ScaleGrid控制台下载你的MongoDB集群的CA证书文件,如下所示:
<tt-image data-tteditor-tag="tteditorTag" contenteditable="false" class="syl1559373334363" data-render-status="finished" data-syl-blot="image" style="box-sizing: border-box; cursor: text; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: block;"><input class="pgc-img-caption-ipt" placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 187.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 375px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;"></tt-image>
因此,一个连接片段应该是这样的:
<tt-image data-tteditor-tag="tteditorTag" contenteditable="false" class="syl1559373334367" data-render-status="finished" data-syl-blot="image" style="box-sizing: border-box; cursor: text; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: block;"><input class="pgc-img-caption-ipt" placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 187.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 375px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;"></tt-image>
如果你使用自己的自签名证书,主机名验证可能会失败,那么你还必须将ssl_match_hostname参数设置为False。正如驱动程序文档所述,不建议你这样做,因为这会使连接容易受到中间人攻击。
测试故障转移行为
在MongoDB部署中,故障转移不像在传统数据库管理系统中那样被认为是主要事件。尽管大多数MongoDB驱动程序都试图抽象这个事件,但是开发人员应该理解并为这种行为设计他们的应用程序,因为应用程序应该能预料到短暂的网络错误,并在渗透错误之前进行重试。
你可以通过在工作负载运行时诱导故障转移来测试应用程序的弹性。诱导故障转移最简单的方法是运行rs.stepDown()命令:
<tt-image data-tteditor-tag="tteditorTag" contenteditable="false" class="syl1559373334371" data-render-status="finished" data-syl-blot="image" style="box-sizing: border-box; cursor: text; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: block;"><input class="pgc-img-caption-ipt" placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 187.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 375px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;"></tt-image>
我喜欢的一个测试驱动程序的方式是通过编写一个简单的“永久”写入器应用。这将是一些简单的代码,它会持续写入数据库,除非被用户打断,并且它会打印所有遇到的异常,来帮助我们理解驱动程序和数据库的行为。我还对它写入的数据进行跟踪,以确保测试过程中没有未报告的数据丢失。下面是测试代码的相关部分,我们将使用它来测试我们的MongoDB的故障转移行为:
<tt-image data-tteditor-tag="tteditorTag" contenteditable="false" class="syl1559373334375" data-render-status="finished" data-syl-blot="image" style="box-sizing: border-box; cursor: text; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: block;"><input class="pgc-img-caption-ipt" placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 187.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 375px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;"></tt-image>
上述代码写入的条目看起来像这样:
<tt-image data-tteditor-tag="tteditorTag" contenteditable="false" class="syl1559373334380" data-render-status="finished" data-syl-blot="image" style="box-sizing: border-box; cursor: text; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: block;"><input class="pgc-img-caption-ipt" placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 187.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 375px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;"></tt-image>
处理ConnectionFailure异常
注意,我们捕获ConnectionFailure异常来处理由于故障转移我们可能遇到的所有与网络相关的问题——我们打印异常并继续尝试写入数据库。驱动程序文档建议你:
如果某个操作由于一个网络错误而失败,则会引发ConnectionFailure异常,并且客户端会在后台进行重新连接。应用程序代码应该处理这个异常(认识到操作失败),然后继续执行。
我们来运行它,并在它执行期间执行一个数据库故障转移。下面是这期间发生的事情:
<tt-image data-tteditor-tag="tteditorTag" contenteditable="false" class="syl1559373334382" data-render-status="finished" data-syl-blot="image" style="box-sizing: border-box; cursor: text; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: block;"><input class="pgc-img-caption-ipt" placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 187.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 375px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;"></tt-image>
注意,驱动程序需要大约12秒的时间来理解新拓扑,连接到新的Primary并继续写入。这里捕获的异常是errors.AutoReconnect,它是ConnectionFailure的子类。
你可以再运行几次,看看还有哪些异常出现。例如,下面是我遇到的另一个异常跟踪:
<tt-image data-tteditor-tag="tteditorTag" contenteditable="false" class="syl1559373334387" data-render-status="finished" data-syl-blot="image" style="box-sizing: border-box; cursor: text; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: block;"><input class="pgc-img-caption-ipt" placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 187.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 375px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;"></tt-image>
这个异常也是ConnectionFailure的子类。
‘retryWrites’参数
测试MongoDB故障转移行为的另一个领域是观察其他参数变化如何影响结果。一个与之相关的参数是'retryWrites':
retryWrites:(布尔型)在MongoDB3.6+上发生网络错误后,是否重试写入在这个MongoClient中执行的操作。默认值为False。
让我们看看这个参数在故障转移时是如何工作的。对代码进行的唯一更改是:
<tt-image data-tteditor-tag="tteditorTag" contenteditable="false" class="syl1559373334391" data-render-status="finished" data-syl-blot="image" style="box-sizing: border-box; cursor: text; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: block;"><input class="pgc-img-caption-ipt" placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 187.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 375px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;"></tt-image>
让我们现在运行它,然后执行一个数据库系统故障转移:
<tt-image data-tteditor-tag="tteditorTag" contenteditable="false" class="syl1559373334395" data-render-status="finished" data-syl-blot="image" style="box-sizing: border-box; cursor: text; color: rgb(34, 34, 34); font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif; font-size: 16px; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: left; text-indent: 0px; text-transform: none; white-space: pre-wrap; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial; display: block;"><input class="pgc-img-caption-ipt" placeholder="图片描述(最多50字)" value="" style="box-sizing: border-box; outline: 0px; color: rgb(102, 102, 102); position: absolute; left: 187.5px; transform: translateX(-50%); padding: 6px 7px; max-width: 100%; width: 375px; text-align: center; cursor: text; font-size: 12px; line-height: 1.5; background-color: rgb(255, 255, 255); background-image: none; border: 0px solid rgb(217, 217, 217); border-radius: 4px; transition: all 0.2s cubic-bezier(0.645, 0.045, 0.355, 1) 0s;"></tt-image>
请注意,虽然故障转移后的插入大约需要12秒,但由于retryWrites参数会确保重试失败的写操作,所以插入成功。请记住,设置此参数并不免除您处理ConnectionFailure异常的责任—您需要担心读取和其他操作,因为它们的行为不受此参数影响。它不能完全解决问题,即使是对支持的操作来说——有时故障转移可能需要很长的时间来完成,仅仅进行retryWrites是不够的。
配置网络超时值
rs.stepdown()会引发一个相当快的故障转移,因为副本集的Primary会被强制变成一个Secondary,而Secondary会进行一次选举来确定新的Primary。在生产部署中,网络负载、分区和其他此类问题会延迟Primary服务器的不可用性检测操作,从而延长你的故障转移时间。你在网络故障或故障转移时也会经常遇到像errors.ServerSelectionTimeoutError、errors.NetworkTimeout等这类的错误。
如果这种情况经常发生,那你就必须调整超时参数。相关的MongoClient超时参数是serverSelectionTimeoutMS、connectTimeoutMS和socketTimeoutMS。其中,为serverSelectionTimeoutMS选择一个较大的值通常有助于在故障转移期间处理错误:
serverSelectionTimeoutMS:(整数)控制驱动程序需要等待多长时间(以毫秒为单位)以便找到一个可用且合适的服务器来执行数据库操作;在等待期间,控制驱动程序可以执行多个服务器监视操作,每个操作由connectTimeoutMS控制。默认值为30000(30秒)。
准备好在你的Python应用程序中使用MongoDB了吗? 请查看我们关于Python和MongoDB入门的文章,了解如何仅通过5个简单的步骤来启动和运行它们。ScaleGrid是惟一的MongoDB DBaaS提供者,它为你提供了对实例的完全SSH访问,因此您可以在与你的MongoDB服务器相同的机器上运行Python服务器。你可以在AWS、Azure或DigitalOcean上自动化进行MongoDB云部署,它们提供专用服务器、高可用性和灾难恢复等功能,这样你就可以专注于开发你的Python应用程序了。
网友评论