012.MongoDB读写分离
<h2 align="left">一 读写分离概述</h2><h3 align="left">1.1 读写分离描述</h3>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">从应用程序角度来看,使用Replica Set 和使用单台mongo很像。默认的驱动程序会连接primary节点,并且将所有读写请求都路由到主节点。但也可以通过设置驱动程序的Read Preferences 配置其他选项,将读请求路由到其他节点。</span></div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">通常官网中建议不使用向从节点取数据。原因如下:</span></div>
<div style="line-height: normal; -ms-word-break: normal"><ol style="margin: 0; padding-left: 30pt">
<li style="text-align: left; line-height: 1.75; list-style-type: decimal; list-style-position: inside; white-space: pre-wrap; background-color: rgba(0, 0, 0, 0)"><span style="font-family: 微软雅黑; font-size: small">所有的从节点拥有与主节点一样的写入负载,读的加入会增加其负载;</span></li>
<li style="text-align: left; line-height: 1.75; list-style-type: decimal; list-style-position: inside; white-space: pre-wrap; background-color: rgba(0, 0, 0, 0)"><span style="font-family: 微软雅黑; font-size: small">对于分片的集合,在平衡器的关系下,数据的返回结果可能会缺失或者重复某部分数据;</span></li>
<li style="text-align: left; line-height: 1.75; list-style-type: decimal; list-style-position: inside; white-space: pre-wrap; background-color: rgba(0, 0, 0, 0)"><span style="font-family: 微软雅黑; font-size: small">相对而言,官方建议使用shard来分散读写请;</span></li>
<li style="text-align: left; line-height: 1.75; list-style-type: decimal; list-style-position: inside; white-space: pre-wrap; background-color: rgba(0, 0, 0, 0)"><span style="font-family: 微软雅黑; font-size: small">一致性的考虑,对一致性要求比较高的应用程序是不应该从备份节点读取数据,备份节点通常由于加载问题,网络等原因,而落后于主节点几毫秒,几秒,几分钟甚至更多。如果应用程序需要读取它自己的写操作(比如,先插入一个文档,再去查询它),那么不应该从备份节点去读取数据,除非针对写操作,使用Write Concern定义w数值,在复制到所有备份节点之后,再返回执行成功与否。总之,如果从一个落后的备份节点读取数据,就要牺牲一致性。如果希望写入操作返回之前被复制到所有的副本集成员,就要牺牲写入速度。</span></li>
<li style="text-align: left; line-height: 1.75; list-style-type: decimal; list-style-position: inside; white-space: pre-wrap; background-color: rgba(0, 0, 0, 0)"><span style="font-family: 微软雅黑; font-size: small">如果路由到的备份节点,其中一台挂了,那么其他节点将承担其相应的压力,需要注意此时在线节点的负载压力。</span></li>
</ol></div>
<div style="line-height: 1.75; text-indent: 28px; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">因此一般是不建议做读写分离,通常对于写操作很少,大量的读请求的业务,实现读写分离来分担服务器压力,然后逐步过度到分片模式。</span></div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="color: rgba(255, 0, 0, 1); font-family: 微软雅黑; font-size: small"><strong>注意:副本集不是为了提高读性能存在的,在进行oplog的时候,读操作是被阻塞的;</strong></span></div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="color: rgba(255, 0, 0, 1); font-family: 微软雅黑; font-size: small"><strong>提高读取性能应该使用分片和索引,它的存在更多是作为数据冗余,备份;</strong></span></div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="color: rgba(255, 0, 0, 1); font-family: 微软雅黑; font-size: small"><strong>尤其当主库本来就面临着大量的写入压力,对于副本集的节点,也同样会面临写的压力。</strong></span></div>
<h3 align="left">1.2 使用的场景</h3>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">通常官方不推荐使用从节点实现读写分离,但可能存在以下场景需要使用读写分离:</span></div>
<div style="line-height: normal; -ms-word-break: normal">
<ul style="margin: 0; padding-left: 30pt">
<li style="text-align: left; line-height: 1.75; list-style-type: disc; list-style-position: inside; white-space: pre-wrap; background-color: rgba(0, 0, 0, 0)"><span style="font-family: 微软雅黑; font-size: small">异地的分布式部署</span></li>
<li style="text-align: left; line-height: 1.75; list-style-type: disc; list-style-position: inside; white-space: pre-wrap; background-color: rgba(0, 0, 0, 0)"><span style="font-family: 微软雅黑; font-size: small">故障切换,在紧急情况下向从节点读数据</span></li>
</ul>
</div>
<h3 align="left">1.3 延伸读写分离思考</h3>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">该思考来源:https://github.com/smallnewer/bugs/issues/22</span></div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">个人总结如下:</span></div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">主从的写压力基本一样;</span></div>
<div style="line-height: normal; -ms-word-break: normal">
<ul style="margin: 0; padding-left: 30pt">
<li style="text-align: left; line-height: 1.75; list-style-type: disc; list-style-position: inside; white-space: pre-wrap; background-color: rgba(0, 0, 0, 0)"><span style="font-family: 微软雅黑; font-size: small">MongoDB从不会受到主写锁的影响,可通过mongotop 或者 mongostat查看写锁状态;</span></li>
<li style="text-align: left; line-height: 1.75; list-style-type: disc; list-style-position: inside; white-space: pre-wrap; background-color: rgba(0, 0, 0, 0)"><span style="font-family: 微软雅黑; font-size: small">MongoDB从会在主写锁后,在恢复oplog时,进行写锁;</span></li>
<li style="text-align: left; line-height: 1.75; list-style-type: disc; list-style-position: inside; white-space: pre-wrap; background-color: rgba(0, 0, 0, 0)"><span style="font-family: 微软雅黑; font-size: small">从优先读,而且读太多会影响写;</span></li>
<li style="text-align: left; line-height: 1.75; list-style-type: disc; list-style-position: inside; white-space: pre-wrap; background-color: rgba(0, 0, 0, 0)"><span style="font-family: 微软雅黑; font-size: small">从节点读的权限比写锁优先级高(注:主节点反之,应该是写贪婪的),建议当从节点的读太高从而影响了oplog的恢复时,改用分片方案。</span></li>
</ul>
</div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">因此在以下情景下适合使用读写分离:</span></div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">读写比例要大,即读多写少。如果写多读少,从库也会有大量写锁,阻塞读。</span></div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">读多写少,从库虽然有写锁,但由于优先读的原因,读不受写锁阻塞,读的速度会加快。</span></div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">不过从库读压力大的时候,只是暂时把写滞后,如果写滞后的很多,超过了主的oplog上限,会触发整体同步,造成主库压力过大,产生雪崩。</span></div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">在从能轻松顶住读压力的时候,且读写比例是读多写少,可以考虑读写分离,提高读的速度。</span></div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">若从节点不能顶住读压力,最好放弃读写分离,换用分片,将热数据分散到不同的机器上。</span></div>
<h2 align="left">二 读写分离部署</h2>
<h3 align="left">2.1 正常部署副本集</h3>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">参考《006.MongoDB复制(副本集)》。</span></div>
<h3 align="left">2.2 开启Sencondary可读状态</h3>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)">1</span> # mongo --host 172.24.8.72 -u clusteradmin -p clusteradmin
<span style="color: rgba(0, 128, 128, 1)">2</span> my_rep:SECONDARY> db.getMongo().setSlaveOk()
<span style="color: rgba(0, 128, 128, 1)">3</span> # mongo --host 172.24.8.73 -u clusteradmin -p clusteradmin
<span style="color: rgba(0, 128, 128, 1)">4</span> my_rep:SECONDARY> db.getMongo().setSlaveOk() #分别连接两个Sencondary节点服务器,设置为可读状态</pre>
</div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"> </div>
<h3 align="left">2.3 客户端设置读取方式</h3>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">通过修改客户端读取方式实现从节点的读,具体方式包括:</span></div>
<div style="line-height: normal; overflow: auto; -ms-word-break: normal">
<table style="overflow: visible; display: table; white-space: nowrap; border-collapse: collapse; table-layout: fixed; max-width: none; border-spacing: 2px 2px"><colgroup><col width="163"><col width="377"></colgroup>
<tbody>
<tr style="height: 35px">
<td style="padding: 1px; border: 1px solid rgba(167, 167, 167, 1); border-image: none; overflow: hidden; vertical-align: middle; white-space: pre-wrap; -ms-word-wrap: break-word" align="center" data-cell-id="2839-1559280820007-cell-0-0">
<div class="table-cell-line"><span style="font-family: 微软雅黑; font-size: small"><strong>Read Preference模式</strong></span></div>
</td>
<td style="padding: 1px; border: 1px solid rgba(167, 167, 167, 1); border-image: none; overflow: hidden; vertical-align: middle; white-space: pre-wrap; -ms-word-wrap: break-word" align="center" data-cell-id="2839-1559280820007-cell-0-1">
<div class="table-cell-line"><span style="font-family: 微软雅黑; font-size: small"><strong>中文解释</strong></span></div>
</td>
</tr>
<tr style="height: 35px">
<td style="padding: 1px; border: 1px solid rgba(167, 167, 167, 1); border-image: none; overflow: hidden; vertical-align: middle; white-space: pre-wrap; -ms-word-wrap: break-word" align="center" data-cell-id="2839-1559280820007-cell-1-0">
<div class="table-cell-line"><span style="font-family: 微软雅黑; font-size: small">primary</span></div>
</td>
<td style="padding: 1px; border: 1px solid rgba(167, 167, 167, 1); border-image: none; overflow: hidden; vertical-align: middle; white-space: pre-wrap; -ms-word-wrap: break-word" align="center" data-cell-id="2839-1559280820007-cell-1-1">
<div class="table-cell-line"><span style="font-family: 微软雅黑; font-size: small">默认,只从主节点读取数据</span></div>
</td>
</tr>
<tr style="height: 35px">
<td style="padding: 1px; border: 1px solid rgba(167, 167, 167, 1); border-image: none; overflow: hidden; vertical-align: middle; white-space: pre-wrap; -ms-word-wrap: break-word" align="center" data-cell-id="2839-1559280820007-cell-2-0">
<div class="table-cell-line"><span style="font-family: 微软雅黑; font-size: small">primaryPreferred</span></div>
</td>
<td style="padding: 1px; border: 1px solid rgba(167, 167, 167, 1); border-image: none; overflow: hidden; vertical-align: middle; white-space: pre-wrap; -ms-word-wrap: break-word" align="center" data-cell-id="2839-1559280820007-cell-2-1">
<div class="table-cell-line"><span style="font-family: 微软雅黑; font-size: small">在主节点不可用时,从副节点读取数据</span></div>
</td>
</tr>
<tr style="height: 35px">
<td style="padding: 1px; border: 1px solid rgba(167, 167, 167, 1); border-image: none; overflow: hidden; vertical-align: middle; white-space: pre-wrap; -ms-word-wrap: break-word" align="center" data-cell-id="2839-1559280820007-cell-3-0">
<div class="table-cell-line"><span style="font-family: 微软雅黑; font-size: small">secondary</span></div>
</td>
<td style="padding: 1px; border: 1px solid rgba(167, 167, 167, 1); border-image: none; overflow: hidden; vertical-align: middle; white-space: pre-wrap; -ms-word-wrap: break-word" align="center" data-cell-id="2839-1559280820007-cell-3-1">
<div class="table-cell-line"><span style="font-family: 微软雅黑; font-size: small">所有的读操作,从副节点读取数据</span></div>
</td>
</tr>
<tr style="height: 35px">
<td style="padding: 1px; border: 1px solid rgba(167, 167, 167, 1); border-image: none; overflow: hidden; vertical-align: middle; white-space: pre-wrap; -ms-word-wrap: break-word" align="center" data-cell-id="2839-1559280820007-cell-4-0">
<div class="table-cell-line"><span style="font-family: 微软雅黑; font-size: small">secondaryPreferred</span></div>
</td>
<td style="padding: 1px; border: 1px solid rgba(167, 167, 167, 1); border-image: none; overflow: hidden; vertical-align: middle; white-space: pre-wrap; -ms-word-wrap: break-word" align="center" data-cell-id="2839-1559280820007-cell-4-1">
<div class="table-cell-line"><span style="font-family: 微软雅黑; font-size: small">在副节点不可用时,从主节点读取数据</span></div>
</td>
</tr>
<tr style="height: 35px">
<td style="padding: 1px; border: 1px solid rgba(167, 167, 167, 1); border-image: none; overflow: hidden; vertical-align: middle; white-space: pre-wrap; -ms-word-wrap: break-word" align="center" data-cell-id="2839-1559280820007-cell-5-0">
<div class="table-cell-line"><span style="font-family: 微软雅黑; font-size: small">nearest</span></div>
</td>
<td style="padding: 1px; border: 1px solid rgba(167, 167, 167, 1); border-image: none; overflow: hidden; vertical-align: middle; white-space: pre-wrap; -ms-word-wrap: break-word" align="center" data-cell-id="2839-1559280820007-cell-5-1">
<div class="table-cell-line"><span style="font-family: 微软雅黑; font-size: small">从网络延迟最小的节点获取数据</span></div>
<div class="table-cell-line"><span style="font-family: 微软雅黑; font-size: small">该模式不关注成员的类型,不管是primary还是secondary成员。</span></div>
</td>
</tr>
</tbody>
</table>
</div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">客户端演示:略。</span></div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">参考链接:</span></div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">https://docs.mongodb.com/manual/applications/replication/</span></div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span style="font-family: 微软雅黑; font-size: small">https://www.cnblogs.com/magialmoon/p/3268963.html</span></div>
<div style="line-height: 1.75; white-space: pre-wrap; -ms-word-break: normal" align="left"><span><span style="font-family: 微软雅黑; font-size: small">http://www.gaozhy.cn/blog/2018/01/18/%E5%9F%BA%E4%BA%8E%E5%89%AF%E6%9C%AC%E9%9B%86%E7%9A%84%E8%AF%BB%E5%86%99%E5%88%86%E7%A6%BB/</span></span></div>
</div>
<div id="MySignature" role="contentinfo">
<div style="background: #f7acbc; color: #0; font-size: small">
<p>
作者:木二
</p>
<p>
出处:http://www.cnblogs.com/itzgr/
</p>
<p>
关于作者:云计算、虚拟化,Linux,多多交流!
</p>
<p>
本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接!如有其他问题,可邮件(xhy@itzgr.com)咨询。
</p>
</div><br><br>
来源:https://www.cnblogs.com/itzgr/p/11041712.html
頁:
[1]