作者:微信小助手
<section style="box-sizing: border-box;font-size: 16px;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="padding-top: 10px;padding-right: 10px;padding-left: 10px;box-sizing: border-box;background-color: rgb(239, 239, 239);"> <span style="display: inline-block;width: 5%;line-height: 0.8;font-weight: bolder;font-size: 48px;box-sizing: border-box;" title="" opera-tn-ra-cell="_$.pages:0.layers:0.comps:0.txt1"> <section style="box-sizing: border-box;"> “ </section></span> <section style="display: inline-block;vertical-align: top;float: right;width: 90%;line-height: 1.5;font-size: 15px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><span style="letter-spacing: 1px;">周末无聊刷着手机,某宝网 App 突然蹦出来一条消息“为了回馈老客户,女朋友买一送一,活动仅限今天!”。</span></p> </section> <section style="clear: both;box-sizing: border-box;"></section> </section> </section> </section> <p style="line-height: 1.75em;"><br></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.5602322206095791" data-s="300,640" src="/upload/712eb438f5e20559a905ec7bb1b07aef.png" data-type="png" data-w="689" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">买一送一还有这种好事,那我可不能错过!忍不住立马点了去。于是选了两个最新款,下单、支付一气呵成!满足的躺在床上,想着马上有女朋友了,竟然幸福的失眠了……</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">第二天正常上着班,突然接到快递小哥的电话:</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">小哥:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">“你是 xx 吗?你的女朋友到了,我现在在你楼下,你来拿一下吧!”。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">“这……我在上班呢,可以晚上送过来吗?“。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">小哥:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">“晚上可不行哦,晚上我也下班了呢!”。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">于是两个人僵持了很久……</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">最后小哥说,要不我帮你放到楼下小芳便利店吧,你晚上下班了过来拿,尴尬的局面这才得以缓解!</span></p> <p style="line-height: normal;"><br></p> <section class="ui-sortable-handle" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="menu-title" style="box-sizing: border-box;">为什么需要消息队列</p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">回到正题,如果没有小芳便利店,那快递小哥和我的交互图就应:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><img class="" data-ratio="0.37397034596375617" src="/upload/7aabe0c29e1d0a2009b06677027cee3a.png" data-type="png" data-w="607" style="line-height: 1.75em;box-sizing: content-box;border: 0px none;vertical-align: middle;"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">会出现什么情况呢?</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">为了这个女朋友,我请假回去拿(老板不批)。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">小哥一直在你楼下等(小哥还有其他的快递要送)。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">周末再送(显然等不及)。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这个女朋友我不要了(绝对不可能)!</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">小芳便利店出现后,交互图如下:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="" data-ratio="0.3684210526315789" src="/upload/75fa203b114dfae53cecd7a5376da477.png" data-type="png" data-w="608" style="line-height: 1.75em;box-sizing: content-box;border: 0px none;vertical-align: middle;"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在上面例子中,“快递小哥”和“买女朋友的我”就是需要交互的两个系统,小芳便利店就是我们本文要讲的消息中间件。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">总结下来小芳便利店(消息中间件)出现后有如下好处:</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section class="ui-sortable-handle" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong>解耦</strong></p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">快递小哥手上有很多快递需要送,他每次都需要先电话一一确认收货人是否有空、哪个时间段有空,然后再确定好送货的方案。这样完全依赖收货人了!如果快递一多,快递小哥估计得忙疯了……</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如果有了便利店,快递小哥只需要将同一个小区的快递放在同一个便利店,然后通知收货人来取货就可以了,这时候快递小哥和收货人就实现了解耦!</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section class="ui-sortable-handle" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong>异步</strong></p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">快递小哥打电话给我后需要一直在你楼下等着,直到我拿走你的快递他才能去送其他人的。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">快递小哥将快递放在小芳便利店后,又可以干其他的活儿去了,不需要等待你到来而一直处于等待状态,提高了工作的效率。</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section class="ui-sortable-handle" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;"><strong>削峰</strong></p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">假设双十一我买了不同店里的各种商品,而恰巧这些店发货的快递都不一样,有中通、圆通、申通、各种通等……更巧的是他们都同时到货了!</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">中通的小哥打来电话叫我去北门取快递、圆通小哥叫我去南门、申通小哥叫我去东门。我一时手忙脚乱……</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们能看到在系统需要交互的场景中,使用消息队列中间件真的是好处多多,基于这种思路,就有了丰巢、菜鸟驿站等比小芳便利店更专业的“中间件”了。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">最后,上面的故事纯属虚构……</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section class="ui-sortable-handle" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">消息队列通信的模式</p> </section> </section> </section> </section> <p style="line-height: normal;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <h1></h1> <h1 style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">通过上面的例子我们引出了消息中间件,并且介绍了消息队列出现后的好处,</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">这里就需要介绍消息队列通信的两种模式了:</span></h1> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section class="ui-sortable-handle" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="menu-title" style="box-sizing: border-box;"><strong>点对点模式</strong></p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.47079439252336447" data-s="300,640" src="/upload/dff0634939d901edc482dbeb056f8d3f.png" data-type="png" data-w="856"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如上图所示,点对点模式通常是基于拉取或者轮询的消息传送模型,这个模型的特点是发送到队列的消息被一个且只有一个消费者进行处理。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">生产者将消息放入消息队列后,由消费者主动的去拉取消息进行消费。点对点模型的优点是消费者拉取消息的频率可以由自己控制。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">但是消息队列是否有消息需要消费,在消费者端无法感知,所以在消费者端需要额外的线程去监控。</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section class="ui-sortable-handle" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="menu-title" style="box-sizing: border-box;"><strong>发布订阅模式</strong></p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.4712778429073857" data-s="300,640" src="/upload/d8b582f3402de8f713ce788fdcbc6e18.png" data-type="png" data-w="853"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如上图所示,发布订阅模式是一个基于消息送的消息传送模型,该模型可以有多种不同的订阅者。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">生产者将消息放入消息队列后,队列会将消息推送给订阅过该类消息的消费者(类似微信公众号)。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">由于是消费者被动接收推送,所以无需感知消息队列是否有待消费的消息!但是 Consumer1、Consumer2、Consumer3 由于机器性能不一样,所以处理消息的能力也会不一样,但消息队列却无法感知消费者消费的速度!</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">所以推送的速度成了发布订阅模式的一个问题!假设三个消费者处理速度分别是 8M/s、5M/s、2M/s,如果队列推送的速度为 5M/s,则 Consumer3 无法承受!</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如果队列推送的速度为 2M/s,则 Consumer1、Consumer2 会出现资源的极大浪费!</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section class="ui-sortable-handle" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">Kafka</p> </section> </section> </section> </section> <p style="line-height: normal;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <h1></h1> <h1 style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">上面简单的介绍了为什么需要消息队列以及消息队列通信的两种模式,接下来就到了我们本文的主角 Kafka 闪亮登场的时候了!</span></h1> <p style="line-height: normal;"><br></p> <h1></h1> <h1 style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Kafka 是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据,具有高性能、持久化、多副本备份、横向扩展能力……… </span></h1> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section class="ui-sortable-handle" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="menu-title" style="box-sizing: border-box;"><strong>基础架构及术语</strong></p> </section> </section> </section> </section> <p style="line-height: normal;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <h2 class="menu-title"></h2> <h2 class="menu-title" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">话不多说,先看图,通过这张图我们来捋一捋相关的概念及之间的关系:</span></h2> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.6811881188118812" data-s="300,640" src="/upload/ee57256660da62d5de4c0b8c3fb1f9a8.png" data-type="png" data-w="1010"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如果看到这张图你很懵逼,木有关系!我们先来分析相关概念:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Producer:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Producer 即生产者,消息的产生者,是消息的入口。<br style="box-sizing: border-box;"></span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Kafka Cluster:</span></strong></p><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Broker:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Broker 是 Kafka 实例,每个服务器上有一个或多个 Kafka 的实例,我们姑且认为每个 Broker 对应一台服务器。</span></p><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">每个 Kafka 集群内的 Broker 都有一个不重复的编号,如图中的 Broker-0、Broker-1 等……</span></p><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Topic:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">消息的主题,可以理解为消息的分类,Kafka 的数据就保存在 Topic。在每个 Broker 上都可以创建多个 Topic。</span></p><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Partition:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Topic 的分区,每个 Topic 可以有多个分区,分区的作用是做负载,提高 Kafka 的吞吐量。</span></p><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">同一个 Topic 在不同的分区的数据是不重复的,Partition 的表现形式就是一个一个的文件夹!</span></p><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Replication:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">每一个分区都有多个副本,副本的作用是做备胎。当主分区(Leader)故障的时候会选择一个备胎(Follower)上位,成为 Leader。</span></p><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在 Kafka 中默认副本的最大数量是 10 个,且副本的数量不能大于 Broker 的数量,Follower 和 Leader 绝对是在不同的机器,同一机器对同一个分区也只可能存放一个副本(包括自己)。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Message:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">每一条发送的消息主体。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Consumer:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">消费者,即消息的消费方,是消息的出口。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Consumer Group:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们可以将多个消费组组成一个消费者组,在 Kafka 的设计中同一个分区的数据只能被消费者组中的某一个消费者消费。</span></p><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"></span><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">同一个消费者组的消费者可以消费同一个 Topic 的不同分区的数据,这也是为了提高 Kafka 的吞吐量!</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Zookeeper:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Kafka 集群依赖 Zookeeper 来保存集群的的元信息,来保证系统的可用性。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section class="ui-sortable-handle" style="box-sizing: border-box;" powered-by="xiumi.us"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="menu-title" style="box-sizing: border-box;"><strong>工作流程分析</strong></p> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">上面介绍了 Kafka 的基础架构及基本概念,不知道大家看完有没有对 Kafka 有个大致印象,如果还比较懵也没关系!</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们接下来再结合上面的结构图分析 Kafka 的工作流程,最后再回来整个梳理一遍我相信你会更有收获!</span></p> <p style="line-height: normal;"><br></p> <h3 class="menu-title" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 16px;"><strong><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">发送数据</span></strong></span></h3> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们看上面的架构图中,Producer 就是生产者,是数据的入口。注意看图中的红色箭头,Producer 在写入数据的时候永远在找 Leader,不会直接将数据写入 Follower!</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">那 Leader 怎么找呢?写入的流程又是什么样的呢?我们看下图:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.47399411187438667" data-s="300,640" src="/upload/11a94a2d688f9384a8fcd1f5e19f88a9.png" data-type="png" data-w="1019"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">发送的流程就在图中已经说明了,就不单独在文字列出来了!需要注意的一点是,消息写入 Leader 后,Follower 是主动的去 Leader 进行同步的!</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Producer 采用 Push 模式将数据发布到 Broker,每条消息追加到分区中,顺序写入磁盘,所以保证同一分区内的数据是有序的!</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">写入示意图如下:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.4966292134831461" data-s="300,640" src="/upload/d24171b8aa69a23129b65e68ad55e23b.png" data-type="png" data-w="890"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">上面说到数据会写入到不同的分区,那 Kafka 为什么要做分区呢?相信大家应该也能猜到,</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">分区的主要目的是:</span></p> <ul class=" list-paddingleft-2" style="margin-left: 8px;margin-right: 8px;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">方便扩展。</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">因为一个 Topic 可以有多个 Partition,所以我们可以通过扩展机器去轻松的应对日益增长的数据量。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">提高并发。</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">以 Partition 为读写单位,可以多个消费者同时消费数据,提高了消息的处理效率。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">熟悉负载均衡的朋友应该知道,当我们向某个服务器发送请求的时候,服务端可能会对请求做一个负载,将流量分发到不同的服务器。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">那在 Kafka 中,如果某个 Topic 有多个 Partition,Producer 又怎么知道该将数据发往哪个 Partition 呢?</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">Kafka 中有几个原则:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Partition 在写入的时候可以指定需要写入的 Partition,如果有指定,则写入对应的 Partition。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如果没有指定 Partition,但是设置了数据的 Key,则会根据 Key 的值 Hash 出一个 Partition。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如果既没指定 Partition,又没有设置 Key,则会轮询选出一个 Partition。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">保证消息不丢失是一个消息队列中间件的基本保证,那 Producer 在向 Kafka 写入消息的时候,怎么保证消息不丢失呢?</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">其实上面的写入流程图中有描述出来,那就是通过 ACK 应答机制!在生产者向队列写入数据的时候可以设置参数来确定是否确认 Kafka 接收到数据,</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">这个参数可设置的值为 0、1、all:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">0 代表 Producer 往集群发送数据不需要等到集群的返回,不确保消息发送成功。安全性最低但是效率最高。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">1 代表 Producer 往集群发送数据只要 Leader 应答就可以发送下一条,只确保 Leader 发送成功。</span></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">all 代表 Producer 往集群发送数据需要所有的 Follower 都完成从 Leader 的同步才会发送下一条,确保 Leader 发送成功和所有的副本都完成备份。安全性最高,但是效率最低。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">最后要注意的是,如果往不存在的 Topic 写数据,能不能写入成功呢?Kafka 会自动创建 Topic,分区和副本的数量根据默认配置都是 1。</span></p> <p style="line-height: normal;"><br></p> <h3 class="menu-title" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 16px;"><strong><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">保存数据</span></strong></span></h3> <p style="line-height: normal;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <h3 class="menu-title"></h3> <h3 class="menu-title" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Producer 将数据写入 Kafka 后,集群就需要对数据进行保存了!Kafka 将数据保存在磁盘,可能在我们的一般的认知里,写入磁盘是比较耗时的操作,不适合这种高并发的组件。</span></h3> <p style="line-height: normal;"><br></p> <h3 class="menu-title"></h3> <h3 class="menu-title" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Kafka 初始会单独开辟一块磁盘空间,顺序写入数据(效率比随机写入高)。</span></h3> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">①Partition 结构</span></strong></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">前面说过了每个 Topic 都可以分为一个或多个 Partition,如果你觉得 Topic 比较抽象,那 Partition 就是比较具体的东西了!</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Partition 在服务器上的表现形式就是一个一个的文件夹,每个 Partition 的文件夹下面会有多组 Segment 文件。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">每组 Segment 文件又包含 .index 文件、.log 文件、.timeindex 文件(早期版本中没有)三个文件。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Log 文件就是实际存储 Message 的地方,而 Index 和 Timeindex 文件为索引文件,用于检索消息。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.8819444444444444" data-s="300,640" src="/upload/69a73ab49a465dc53866b6e6d55e2210.png" data-type="png" data-w="432"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如上图,这个 Partition 有三组 Segment 文件,每个 Log 文件的大小是一样的,但是存储的 Message 数量是不一定相等的(每条的 Message 大小不一致)。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">文件的命名是以该 Segment 最小 Offset 来命名的,如 000.index 存储 Offset 为 0~368795 的消息,Kafka 就是利用分段+索引的方式来解决查找效率的问题。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">②Message 结构</span></strong></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">上面说到 Log 文件就实际是存储 Message 的地方,我们在 Producer 往 Kafka 写入的也是一条一条的 Message。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">那存储在 Log 中的 Message 是什么样子的呢?</span><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">消息主要包含消息体、消息大小、Offset、压缩类型……等等!</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">我们重点需要知道的是下面三个:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Offset:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Offset 是一个占 8byte 的有序 id 号,它可以唯一确定每条消息在 Parition 内的位置!</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">消息大小:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">消息大小占用 4byte,用于描述消息的大小。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">消息体:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">消息体存放的是实际的消息数据(被压缩过),占用的空间根据具体的消息而不一样。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">③存储策略</span></strong></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">无论消息是否被消费,Kafka 都会保存所有的消息。</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">那对于旧数据有什么删除策略呢?</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">基于时间,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">默认配置是 168 小时(7 天)。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">基于大小,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">默认配置是 1073741824。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">需要注意的是,Kafka 读取特定消息的时间复杂度是 O(1),所以这里删除过期的文件并不会提高 Kafka 的性能!</span></p> <p style="line-height: normal;"><br></p> <h3 class="menu-title" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 16px;"><strong><span style="color: rgb(89, 89, 89);letter-spacing: 1px;">消费数据</span></strong></span></h3> <p style="line-height: normal;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <h3 class="menu-title"></h3> <h3 class="menu-title" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">消息存储在 Log 文件后,消费者就可以进行消费了。在讲消息队列通信的两种模式的时候讲到过点对点模式和发布订阅模式。</span></h3> <p style="line-height: normal;"><br></p> <h3 class="menu-title"></h3> <h3 class="menu-title" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Kafka 采用的是点对点的模式,消费者主动的去 Kafka 集群拉取消息,与 Producer 相同的是,消费者在拉取消息的时候也是找 Leader 去拉取。</span></h3> <p style="line-height: normal;"><br></p> <h3 class="menu-title"></h3> <h3 class="menu-title" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">多个消费者可以组成一个消费者组(Consumer Group),每个消费者组都有一个组 id!</span></h3> <p style="line-height: normal;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <h3 class="menu-title"></h3> <h3 class="menu-title" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">同一个消费组者的消费者可以消费同一 Topic 下不同分区的数据,但是不会组内多个消费者消费同一分区的数据!</span></h3> <h3 class="menu-title" style="line-height: normal;"><br></h3> <h3 class="menu-title" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="color: rgb(71, 193, 168);"><span style="font-size: 15px;letter-spacing: 1px;">是不是有点绕?</span><span style="font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">我们看下图:</span></span></h3> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.40836012861736337" data-s="300,640" src="/upload/4fcbe01b6cba90afa5948f0bc29d38ea.png" data-type="png" data-w="933"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">图示是消费者组内的消费者小于 Partition 数量的情况,所以会出现某个消费者消费多个 Partition 数据的情况,消费的速度也就不及只处理一个 Partition 的消费者的处理速度!</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如果是消费者组的消费者多于 Partition 的数量,那会不会出现多个消费者消费同一个 Partition 的数据呢?</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">上面已经提到过不会出现这种情况!多出来的消费者不消费任何 Partition 的数据。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">所以在实际的应用中,建议消费者组的 Consumer 的数量与 Partition 的数量一致!</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在保存数据的小节里面,我们聊到了 Partition 划分为多组 Segment,每个 Segment 又包含 .log、.index、.timeindex 文件,存放的每条 Message 包含 Offset、消息大小、消息体……</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们多次提到 Segment 和 Offset,查找消息的时候是怎么利用 Segment+Offset 配合查找的呢?</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">假如现在需要查找一个 Offset 为 368801 的 Message 是什么样的过程呢?</span><span style="line-height: 29.75px;font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">我们先看看下面的图:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.3535958904109589" data-s="300,640" src="/upload/270814fefc20645b7ce03acde2292800.png" data-type="png" data-w="1168"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">①先找到 Offset 的 368801message 所在的 Segment 文件(利用二分法查找),这里找到的就是在第二个 Segment 文件。<br></span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">②打开找到的 Segment 中的 .index 文件(也就是 368796.index 文件,该文件起始偏移量为 368796+1。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们要查找的 Offset 为 368801 的 Message 在该 Index 内的偏移量为 368796+5=368801,所以这里要查找的相对 Offset 为 5)。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">由于该文件采用的是稀疏索引的方式存储着相对 Offset 及对应 Message 物理偏移量的关系,所以直接找相对 Offset 为 5 的索引找不到。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这里同样利用二分法查找相对 Offset 小于或者等于指定的相对 Offset 的索引条目中最大的那个相对 Offset,所以找到的是相对 Offset 为 4 的这个索引。<br></span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">③根据找到的相对 Offset 为 4 的索引确定 Message 存储的物理偏移位置为 256。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">打开数据文件,从位置为 256 的那个地方开始顺序扫描直到找到 Offset 为 368801 的那条 Message。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这套机制是建立在 Offset 为有序的基础上,利用 Segment+有序 Offset+稀疏索引+二分查找+顺序查找等多种手段来高效的查找数据!</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">至此,消费者就能拿到需要处理的数据进行处理了。那每个消费者又是怎么记录自己消费的位置呢?</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在早期的版本中,消费者将消费到的 Offset 维护在 Zookeeper 中,Consumer 每间隔一段时间上报一次,这里容易导致重复消费,且性能不好!</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在新的版本中消费者消费到的 Offset 已经直接维护在 Kafka 集群的 __consumer_offsets 这个 Topic 中!</span></p> <p style="line-height: normal;"><br></p> <p style="white-space: normal;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);letter-spacing: 1px;"><em><span style="font-size: 14px;">作者:苏静</span></em></span></p> <p style="white-space: normal;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);letter-spacing: 1px;"><em><span style="font-size: 14px;">简介:有过多年大型互联网项目的开发经验,对高并发、分布式、以及微服务技术有深入的研究及相关实践经验。经历过自学,热衷于技术研究与分享!格言:始终保持虚心学习的态度! </span></em></span></p> <p style="white-space: normal;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);letter-spacing: 1px;"><em><span style="font-size: 14px;">编辑:陶家龙、孙淑娟</span></em></span><br></p> <p style="white-space: normal;line-height: 1.75em;"><span style="font-size: 14px;letter-spacing: 1px;color: rgb(89, 89, 89);"><em>出处:17coding 技术博客:http://www.17coding.info/</em></span></p> <p style="text-align: center;"><img class="rich_pages" data-copyright="0" data-ratio="0.3939393939393939" src="/upload/58a14061a632a0fe87d40beb73c1aa.gif" data-type="gif" data-w="660" style=""></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="margin-top: 0.5em;margin-bottom: 0.5em;box-sizing: border-box;" powered-by="xiumi.us"> <section style="font-size: 15px;border-style: solid;border-width: 0px 0px 1px;color: rgb(89, 89, 89);border-bottom-color: rgba(215, 215, 215, 0.960784);box-sizing: border-box;"> <p style="box-sizing: border-box;"><span style="letter-spacing: 1px;"><strong>精彩文章推荐:</strong></span></p> </section> </section> </section> <p style="line-height: 2em;"><a href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&mid=2655824554&idx=3&sn=aeccfc4f704474f513688c706a71ec94&chksm=bd74e77d8a036e6bae85c18675ab9163d61176634cbd85b6bdda281359a9e625d13781a9ac33&scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;text-decoration: none;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">谷歌全球大规模宕机4小时,苹果iCloud也遭殃!</span></a><br></p> <p style="line-height: 2em;"><a href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&mid=2655824527&idx=1&sn=cecf1587164d836a82ec6b3a7b13cdd7&chksm=bd74e7588a036e4e75ca783dae0f60e56b001b49b99f6da4dff9a369b6a3544fa04cb616d6bb&scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;text-decoration: none;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">让美国颤抖的5G,到底牛在哪?</span></a><br></p> <p style="line-height: 2em;"><a href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&mid=2655824452&idx=1&sn=ac4d469f248f5a689ef83525138ad356&chksm=bd74e7938a036e85ed8398815097df89748eaa1b856dd749e69b7b7a822d0080777d00c1a3a2&scene=21#wechat_redirect" target="_blank" data-itemshowtype="0" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;text-decoration: none;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">看完这篇文章,我奶奶都懂了HTTPS原理</span></a><br></p>
作者:微信小助手
<p style="white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(121, 123, 170);font-size: 16px;box-sizing: border-box !important;word-wrap: break-word !important;">作者:阿进的写字台</span></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(121, 123, 170);font-size: 16px;box-sizing: border-box !important;word-wrap: break-word !important;">cnblogs.com/homejim/p/9909657.html</span></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;box-sizing: border-box !important;word-wrap: break-word !important;"><br></p> <p style="text-align: center;"><img class="" data-ratio="0.8494318181818182" data-s="300,640" src="/upload/fcace737833c3bd94bb6d929707eac8e.png" data-type="png" data-w="352" style=""></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;box-sizing: border-box !important;word-wrap: break-word !important;"><br></p> <h1 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 28px;white-space: normal;line-height: 1.5;">0 一起来学习 mybatis</h1> <hr style="white-space: normal;border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px 0px;transform: scale(1, 0.5);"> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">MyBatis 令人喜欢的一大特性就是动态 SQL。 在使用 JDBC 的过程中, 根据条件进行 SQL 的拼接是很麻烦且很容易出错的。 MyBatis 动态 SQL 的出现, 解决了这个麻烦。</p> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">MyBatis通过 OGNL 来进行动态 SQL 的使用的。</p> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">目前, 动态 SQL 支持以下几种标签</p> <table> <thead> <tr class="header"> <th style="padding: 8px 14px;border-top-width: 1px;border-color: silver;background-color: rgb(250, 250, 250);border-collapse: collapse;">元素</th> <th style="padding: 8px 14px;border-top-width: 1px;border-color: silver;background-color: rgb(250, 250, 250);border-collapse: collapse;">作用</th> <th style="padding: 8px 14px;border-top-width: 1px;border-color: silver;background-color: rgb(250, 250, 250);border-collapse: collapse;">备注</th> </tr> </thead> <tbody> <tr class="odd"> <td style="padding: 8px 14px;border-color: silver;border-collapse: collapse;">if</td> <td style="padding: 8px 14px;border-color: silver;border-collapse: collapse;">判断语句</td> <td style="padding: 8px 14px;border-color: silver;border-collapse: collapse;">单条件分支</td> </tr> <tr class="even"> <td style="padding: 8px 14px;border-color: silver;border-collapse: collapse;">choose(when、otherwise)</td> <td style="padding: 8px 14px;border-color: silver;border-collapse: collapse;">相当于 Java 中的 if else</td> <td style="padding: 8px 14px;border-color: silver;border-collapse: collapse;">多条件分支</td> </tr> <tr class="odd"> <td style="padding: 8px 14px;border-color: silver;border-collapse: collapse;">trim(where、set)</td> <td style="padding: 8px 14px;border-color: silver;border-collapse: collapse;">辅助元素</td> <td style="padding: 8px 14px;border-color: silver;border-collapse: collapse;">用于处理 SQL 拼接问题</td> </tr> <tr class="even"> <td style="padding: 8px 14px;border-color: silver;border-collapse: collapse;">foreach</td> <td style="padding: 8px 14px;border-color: silver;border-collapse: collapse;">循环语句</td> <td style="padding: 8px 14px;border-color: silver;border-collapse: collapse;">批量插入, 更新, 查询时经常用到</td> </tr> <tr class="odd"> <td style="padding: 8px 14px;border-color: silver;border-collapse: collapse;">bind</td> <td style="padding: 8px 14px;border-color: silver;border-collapse: collapse;">创建一个变量, 并绑定到上下文中</td> <td style="padding: 8px 14px;border-color: silver;border-collapse: collapse;">用于兼容不同的数据库, 防止 SQL 注入等</td> </tr> </tbody> </table> <h1 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 28px;white-space: normal;line-height: 1.5;">1 数据准备</h1> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">为了后面的演示, 创建了一个 Maven 项目 mybatis-dynamic, 创建了对应的数据库和表</p> <pre style="margin-top: 10px;margin-bottom: 10px;padding: 0px;white-space: pre-wrap;word-wrap: break-word;"><code class="hljs sql" style="margin: auto;padding: 5px !important;vertical-align: middle;display: block;background: rgb(255, 255, 255);height: auto;overflow-x: auto;color: rgb(0, 0, 0);line-height: 1.5 !important;font-family: "Courier New", sans-serif !important;border-width: 1px !important;border-style: solid !important;border-color: rgb(204, 204, 204) !important;border-radius: 3px !important;"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">DROP</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">TABLE</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">IF</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">EXISTS</span> <span class="hljs-string" style="color: rgb(163, 21, 21);">`student`</span>;<span class="hljs-keyword" style="color: rgb(0, 0, 255);">CREATE</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">TABLE</span> <span class="hljs-string" style="color: rgb(163, 21, 21);">`student`</span> ( <span class="hljs-string" style="color: rgb(163, 21, 21);">`student_id`</span> <span class="hljs-built_in" style="color: rgb(0, 0, 255);">int</span>(<span class="hljs-number">10</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 255);">unsigned</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">NOT</span> <span class="hljs-literal" style="color: rgb(163, 21, 21);">NULL</span> AUTO_INCREMENT <span class="hljs-keyword" style="color: rgb(0, 0, 255);">COMMENT</span> <span class="hljs-string" style="color: rgb(163, 21, 21);">'编号'</span>, <span class="hljs-string" style="color: rgb(163, 21, 21);">`name`</span> <span class="hljs-built_in" style="color: rgb(0, 0, 255);">varchar</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 255);">DEFAULT</span> <span class="hljs-literal" style="color: rgb(163, 21, 21);">NULL</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">COMMENT</span> <span class="hljs-string" style="color: rgb(163, 21, 21);">'姓名'</span>, <span class="hljs-string" style="color: rgb(163, 21, 21);">`phone`</span> <span class="hljs-built_in" style="color: rgb(0, 0, 255);">varchar</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 255);">DEFAULT</span> <span class="hljs-literal" style="color: rgb(163, 21, 21);">NULL</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">COMMENT</span> <span class="hljs-string" style="color: rgb(163, 21, 21);">'电话'</span>, <span class="hljs-string" style="color: rgb(163, 21, 21);">`email`</span> <span class="hljs-built_in" style="color: rgb(0, 0, 255);">varchar</span>(<span class="hljs-number">50</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 255);">DEFAULT</span> <span class="hljs-literal" style="color: rgb(163, 21, 21);">NULL</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">COMMENT</span> <span class="hljs-string" style="color: rgb(163, 21, 21);">'邮箱'</span>, <span class="hljs-string" style="color: rgb(163, 21, 21);">`sex`</span> tinyint(<span class="hljs-number">4</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 255);">DEFAULT</span> <span class="hljs-literal" style="color: rgb(163, 21, 21);">NULL</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">COMMENT</span> <span class="hljs-string" style="color: rgb(163, 21, 21);">'性别'</span>, <span class="hljs-string" style="color: rgb(163, 21, 21);">`locked`</span> tinyint(<span class="hljs-number">4</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 255);">DEFAULT</span> <span class="hljs-literal" style="color: rgb(163, 21, 21);">NULL</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">COMMENT</span> <span class="hljs-string" style="color: rgb(163, 21, 21);">'状态(0:正常,1:锁定)'</span>, <span class="hljs-string" style="color: rgb(163, 21, 21);">`gmt_created`</span> datetime <span class="hljs-keyword" style="color: rgb(0, 0, 255);">DEFAULT</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">CURRENT_TIMESTAMP</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">COMMENT</span> <span class="hljs-string" style="color: rgb(163, 21, 21);">'存入数据库的时间'</span>, <span class="hljs-string" style="color: rgb(163, 21, 21);">`gmt_modified`</span> datetime <span class="hljs-keyword" style="color: rgb(0, 0, 255);">DEFAULT</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">CURRENT_TIMESTAMP</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">ON</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">UPDATE</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">CURRENT_TIMESTAMP</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">COMMENT</span> <span class="hljs-string" style="color: rgb(163, 21, 21);">'修改的时间'</span>, <span class="hljs-string" style="color: rgb(163, 21, 21);">`delete`</span> <span class="hljs-built_in" style="color: rgb(0, 0, 255);">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 255);">DEFAULT</span> <span class="hljs-literal" style="color: rgb(163, 21, 21);">NULL</span>, PRIMARY <span class="hljs-keyword" style="color: rgb(0, 0, 255);">KEY</span> (<span class="hljs-string" style="color: rgb(163, 21, 21);">`student_id`</span>) ) <span class="hljs-keyword" style="color: rgb(0, 0, 255);">ENGINE</span>=<span class="hljs-keyword" style="color: rgb(0, 0, 255);">InnoDB</span> AUTO_INCREMENT=<span class="hljs-number">7</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">DEFAULT</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">CHARSET</span>=utf8mb4 <span class="hljs-keyword" style="color: rgb(0, 0, 255);">COLLATE</span>=utf8mb4_0900_ai_ci <span class="hljs-keyword" style="color: rgb(0, 0, 255);">COMMENT</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">'学生表'</span>;</code></pre> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">对应的项目结构</p> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;"><img class="" data-ratio="1.277992277992278" src="/upload/31d305e28cd7a0a53ef9650ed447246d.png" data-type="png" data-w="259" style="max-width: 660px;border-width: 0px;border-style: initial;border-color: initial;"></p> <h1 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 28px;white-space: normal;line-height: 1.5;">2 if 标签</h1> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">if 标签是我们最常使用的。 在查询、删除、更新的时候很可能会使用到。 必须结合 test 属性联合使用。</p> <h2 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 21px;white-space: normal;line-height: 1.5;">2.1 在 WHERE 条件中使用 if 标签</h2> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">这是常见的一种现象, 我们在进行按条件查询的时候, 可能会有多种情况。</p> <h3 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;white-space: normal;line-height: 1.5;">2.1.1 查询条件</h3> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">根据输入的学生信息进行条件检索</p> <ol class=" list-paddingleft-2" style=""> <li><p>当只输入用户名时, 使用用户名进行模糊检索;</p></li> <li><p>当只输入性别时, 使用性别进行完全匹配</p></li> <li><p>当用户名和性别都存在时, 用这两个条件进行查询匹配查询</p></li> </ol> <h3 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;white-space: normal;line-height: 1.5;">2.1.2 动态 SQL</h3> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">接口函数</p> <pre style="margin-top: 10px;margin-bottom: 10px;padding: 0px;white-space: pre-wrap;word-wrap: break-word;"><code class="hljs php" style="margin: auto;padding: 5px !important;vertical-align: middle;display: block;background: rgb(255, 255, 255);height: auto;overflow-x: auto;color: rgb(0, 0, 0);line-height: 1.5 !important;font-family: "Courier New", sans-serif !important;border-width: 1px !important;border-style: solid !important;border-color: rgb(204, 204, 204) !important;border-radius: 3px !important;"> <span class="hljs-comment" style="color: green;">/** * 根据输入的学生信息进行条件检索 * 1. 当只输入用户名时, 使用用户名进行模糊检索; * 2. 当只输入邮箱时, 使用性别进行完全匹配 * 3. 当用户名和性别都存在时, 用这两个条件进行查询匹配的用 * <span class="hljs-doctag" style="color: gray;">@param</span> student * <span class="hljs-doctag" style="color: gray;">@return</span> */</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">List</span><Student> selectByStudentSelective(Student student);</code></pre> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">对应的动态 SQL</p> <pre style="margin-top: 10px;margin-bottom: 10px;padding: 0px;white-space: pre-wrap;word-wrap: break-word;"><code class="hljs vbnet" style="margin: auto;padding: 5px !important;vertical-align: middle;display: block;background: rgb(255, 255, 255);height: auto;overflow-x: auto;color: rgb(0, 0, 0);line-height: 1.5 !important;font-family: "Courier New", sans-serif !important;border-width: 1px !important;border-style: solid !important;border-color: rgb(204, 204, 204) !important;border-radius: 3px !important;"> <<span class="hljs-keyword" style="color: rgb(0, 0, 255);">select</span> id=<span class="hljs-string" style="color: rgb(163, 21, 21);">"selectByStudentSelective"</span> resultMap=<span class="hljs-string" style="color: rgb(163, 21, 21);">"BaseResultMap"</span> parameterType=<span class="hljs-string" style="color: rgb(163, 21, 21);">"com.homejim.mybatis.entity.Student"</span>> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">select</span> <include refid=<span class="hljs-string" style="color: rgb(163, 21, 21);">"Base_Column_List"</span> /> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">from</span> student <span class="hljs-keyword" style="color: rgb(0, 0, 255);">where</span> <span class="hljs-number">1</span>=<span class="hljs-number">1</span> <<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> test=<span class="hljs-string" style="color: rgb(163, 21, 21);">"name != null and name !=''"</span>> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">and</span> name <span class="hljs-keyword" style="color: rgb(0, 0, 255);">like</span> concat(<span class="hljs-comment" style="color: green;">'%', #{name}, '%')</span> </<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span>> <<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> test=<span class="hljs-string" style="color: rgb(163, 21, 21);">"sex != null"</span>> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">and</span> sex=<span class="hljs-meta" style="color: rgb(43, 145, 175);">#{sex}</span> </<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span>> </<span class="hljs-keyword" style="color: rgb(0, 0, 255);">select</span>></code></pre> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">在此 SQL 语句中, where 1=1 是多条件拼接时的小技巧, 后面的条件查询就可以都用 and 了。</p> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">同时, 我们添加了 if 标签来处理动态 SQL</p> <pre style="margin-top: 10px;margin-bottom: 10px;padding: 0px;white-space: pre-wrap;word-wrap: break-word;"><code class="hljs lua" style="margin: auto;padding: 5px !important;vertical-align: middle;display: block;background: rgb(255, 255, 255);height: auto;overflow-x: auto;color: rgb(0, 0, 0);line-height: 1.5 !important;font-family: "Courier New", sans-serif !important;border-width: 1px !important;border-style: solid !important;border-color: rgb(204, 204, 204) !important;border-radius: 3px !important;"> <<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> test=<span class="hljs-string" style="color: rgb(163, 21, 21);">"name != null and name !=''"</span>> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">and</span> name like <span class="hljs-built_in" style="color: rgb(0, 0, 255);">concat</span>(<span class="hljs-string" style="color: rgb(163, 21, 21);">'%'</span>, #{name}, <span class="hljs-string" style="color: rgb(163, 21, 21);">'%'</span>) </<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span>> <<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> test=<span class="hljs-string" style="color: rgb(163, 21, 21);">"sex != null"</span>> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">and</span> sex=#{sex} </<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span>></code></pre> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">此 if 标签的 test 属性值是一个符合 OGNL 的表达式, 表达式可以是 true 或 false。 如果表达式返回的是数值, 则0为 false, 非 0 为 true;</p> <h3 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;white-space: normal;line-height: 1.5;">2.1.3 测试</h3> <pre style="margin-top: 10px;margin-bottom: 10px;padding: 0px;white-space: pre-wrap;word-wrap: break-word;"><code class="hljs cs" style="margin: auto;padding: 5px !important;vertical-align: middle;display: block;background: rgb(255, 255, 255);height: auto;overflow-x: auto;color: rgb(0, 0, 0);line-height: 1.5 !important;font-family: "Courier New", sans-serif !important;border-width: 1px !important;border-style: solid !important;border-color: rgb(204, 204, 204) !important;border-radius: 3px !important;"> @<span class="hljs-function">Test <span class="hljs-keyword" style="color: rgb(0, 0, 255);">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">void</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">selectByStudent</span>() </span>{ SqlSession sqlSession = <span class="hljs-literal" style="color: rgb(163, 21, 21);">null</span>; sqlSession = sqlSessionFactory.openSession(); StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class); Student search = <span class="hljs-keyword" style="color: rgb(0, 0, 255);">new</span> Student(); search.setName(<span class="hljs-string" style="color: rgb(163, 21, 21);">"明"</span>); System.<span class="hljs-keyword" style="color: rgb(0, 0, 255);">out</span>.println(<span class="hljs-string" style="color: rgb(163, 21, 21);">"只有名字时的查询"</span>); List<Student> studentsByName = studentMapper.selectByStudentSelective(search); <span class="hljs-keyword" style="color: rgb(0, 0, 255);">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> i = <span class="hljs-number">0</span>; i < studentsByName.size(); i++) { System.<span class="hljs-keyword" style="color: rgb(0, 0, 255);">out</span>.println(ToStringBuilder.reflectionToString(studentsByName.<span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>(i), ToStringStyle.MULTI_LINE_STYLE)); } search.setName(<span class="hljs-literal" style="color: rgb(163, 21, 21);">null</span>); search.setSex((<span class="hljs-keyword" style="color: rgb(0, 0, 255);">byte</span>) <span class="hljs-number">1</span>); System.<span class="hljs-keyword" style="color: rgb(0, 0, 255);">out</span>.println(<span class="hljs-string" style="color: rgb(163, 21, 21);">"只有性别时的查询"</span>); List<Student> studentsBySex = studentMapper.selectByStudentSelective(search); <span class="hljs-keyword" style="color: rgb(0, 0, 255);">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> i = <span class="hljs-number">0</span>; i < studentsBySex.size(); i++) { System.<span class="hljs-keyword" style="color: rgb(0, 0, 255);">out</span>.println(ToStringBuilder.reflectionToString(studentsBySex.<span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>(i), ToStringStyle.MULTI_LINE_STYLE)); } System.<span class="hljs-keyword" style="color: rgb(0, 0, 255);">out</span>.println(<span class="hljs-string" style="color: rgb(163, 21, 21);">"姓名和性别同时存在的查询"</span>); search.setName(<span class="hljs-string" style="color: rgb(163, 21, 21);">"明"</span>); List<Student> studentsByNameAndSex = studentMapper.selectByStudentSelective(search); <span class="hljs-keyword" style="color: rgb(0, 0, 255);">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> i = <span class="hljs-number">0</span>; i < studentsByNameAndSex.size(); i++) { System.<span class="hljs-keyword" style="color: rgb(0, 0, 255);">out</span>.println(ToStringBuilder.reflectionToString(studentsByNameAndSex.<span class="hljs-keyword" style="color: rgb(0, 0, 255);">get</span>(i), ToStringStyle.MULTI_LINE_STYLE)); } sqlSession.commit(); sqlSession.close(); }</code></pre> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;"><strong>只有名字时的查询</strong>, 发送的语句和结果</p> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;"><img class="" data-ratio="0.12890231621349446" src="/upload/57d97d03d65874b2b57ff9169c2ec6a.png" data-type="png" data-w="993" style="max-width: 660px;border-width: 0px;border-style: initial;border-color: initial;"></p> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">查询的条件只发送了</p> <pre style="margin-top: 10px;margin-bottom: 10px;padding: 0px;white-space: pre-wrap;word-wrap: break-word;"><code class="hljs lua" style="margin: auto;padding: 5px !important;vertical-align: middle;display: block;background: rgb(255, 255, 255);height: auto;overflow-x: auto;color: rgb(0, 0, 0);line-height: 1.5 !important;font-family: "Courier New", sans-serif !important;border-width: 1px !important;border-style: solid !important;border-color: rgb(204, 204, 204) !important;border-radius: 3px !important;">where <span class="hljs-number">1</span>=<span class="hljs-number">1</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">and</span> name like <span class="hljs-built_in" style="color: rgb(0, 0, 255);">concat</span>(<span class="hljs-string" style="color: rgb(163, 21, 21);">'%'</span>, ?, <span class="hljs-string" style="color: rgb(163, 21, 21);">'%'</span>) </code></pre> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;"><strong>只有性别时的查询</strong>, 发送的语句和结果</p> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;"><img class="" data-ratio="0.18327183271832717" src="/upload/eff5680cdaac55ad9159940dcb3c92c7.png" data-type="png" data-w="813" style="max-width: 660px;border-width: 0px;border-style: initial;border-color: initial;"></p> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">查询的条件只发送了</p> <pre style="margin-top: 10px;margin-bottom: 10px;padding: 0px;white-space: pre-wrap;word-wrap: break-word;"><code class="hljs vbnet" style="margin: auto;padding: 5px !important;vertical-align: middle;display: block;background: rgb(255, 255, 255);height: auto;overflow-x: auto;color: rgb(0, 0, 0);line-height: 1.5 !important;font-family: "Courier New", sans-serif !important;border-width: 1px !important;border-style: solid !important;border-color: rgb(204, 204, 204) !important;border-radius: 3px !important;"> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">where</span> <span class="hljs-number">1</span>=<span class="hljs-number">1</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">and</span> sex=? </code></pre> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;"><strong>姓名和性别同时存在的查询</strong>, 发送的语句和结果</p> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;"><img class="" data-ratio="0.1154639175257732" src="/upload/4820dd7d3d47b15ee05588a6b9bb5748.png" data-type="png" data-w="970" style="max-width: 660px;border-width: 0px;border-style: initial;border-color: initial;"></p> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">查询条件</p> <pre style="margin-top: 10px;margin-bottom: 10px;padding: 0px;white-space: pre-wrap;word-wrap: break-word;"><code class="hljs lua" style="margin: auto;padding: 5px !important;vertical-align: middle;display: block;background: rgb(255, 255, 255);height: auto;overflow-x: auto;color: rgb(0, 0, 0);line-height: 1.5 !important;font-family: "Courier New", sans-serif !important;border-width: 1px !important;border-style: solid !important;border-color: rgb(204, 204, 204) !important;border-radius: 3px !important;">where <span class="hljs-number">1</span>=<span class="hljs-number">1</span> <span class="hljs-keyword" style="color: rgb(0, 0, 255);">and</span> name like <span class="hljs-built_in" style="color: rgb(0, 0, 255);">concat</span>(<span class="hljs-string" style="color: rgb(163, 21, 21);">'%'</span>, ?, <span class="hljs-string" style="color: rgb(163, 21, 21);">'%'</span>) <span class="hljs-keyword" style="color: rgb(0, 0, 255);">and</span> sex=? </code></pre> <h2 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;font-size: 21px;white-space: normal;line-height: 1.5;">2.2 在 UPDATE 更新列中使用 if 标签</h2> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">有时候我们不希望更新所有的字段, 只更新有变化的字段。</p> <h3 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;white-space: normal;line-height: 1.5;">2.2.1 更新条件</h3> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">只更新有变化的字段, 空值不更新。</p> <h3 style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;white-space: normal;line-height: 1.5;">2.2.1 动态 SQL</h3> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">接口方法</p> <pre style="margin-top: 10px;margin-bottom: 10px;padding: 0px;white-space: pre-wrap;word-wrap: break-word;"><code class="hljs cpp" style="margin: auto;padding: 5px !important;vertical-align: middle;display: block;background: rgb(255, 255, 255);height: auto;overflow-x: auto;color: rgb(0, 0, 0);line-height: 1.5 !important;font-family: "Courier New", sans-serif !important;border-width: 1px !important;border-style: solid !important;border-color: rgb(204, 204, 204) !important;border-radius: 3px !important;"> <span class="hljs-comment" style="color: green;">/** * 更新非空属性 */</span> <span class="hljs-function"><span class="hljs-keyword" style="color: rgb(0, 0, 255);">int</span> <span class="hljs-title" style="color: rgb(163, 21, 21);">updateByPrimaryKeySelective</span><span class="hljs-params">(Student record)</span></span>;</code></pre> <p style="margin: 10px auto;white-space: normal;line-height: 1.5 !important;">对应的 SQL</p> <pre style="margin-top: 10px;margin-bottom: 10px;padding: 0px;white-space: pre-wrap;word-wrap: break-word;"><code class="hljs bash" style="margin: auto;padding: 5px !important;vertical-align: middle;display: block;background: rgb(255, 255, 255);height: auto;overflow-x: auto;color: rgb(0, 0, 0);line-height: 1.5 !important;font-family: "Courier New", sans-serif !important;border-width: 1px !important;border-style: solid !important;border-color: rgb(204, 204, 204) !important;border-radius: 3px !important;"> <update id=<span class="hljs-string" style="color: rgb(163, 21, 21);">"updateByPrimaryKeySelective"</span> parameterType=<span class="hljs-string" style="color: rgb(163, 21, 21);">"com.homejim.mybatis.entity.Student"</span>> update student <<span class="hljs-built_in" style="color: rgb(0, 0, 255);">set</span>> <<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> <span class="hljs-built_in" style="color: rgb(0, 0, 255);">test</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"name != null"</span>> `name` = <span class="hljs-comment" style="color: green;">#{name,jdbcType=VARCHAR},</span> </<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span>> <<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> <span class="hljs-built_in" style="color: rgb(0, 0, 255);">test</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"phone != null"</span>> phone = <span class="hljs-comment" style="color: green;">#{phone,jdbcType=VARCHAR},</span> </<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span>> <<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> <span class="hljs-built_in" style="color: rgb(0, 0, 255);">test</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"email != null"</span>> email = <span class="hljs-comment" style="color: green;">#{email,jdbcType=VARCHAR},</span> </<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span>> <<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> <span class="hljs-built_in" style="color: rgb(0, 0, 255);">test</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"sex != null"</span>> sex = <span class="hljs-comment" style="color: green;">#{sex,jdbcType=TINYINT},</span> </<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span>> <<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> <span class="hljs-built_in" style="color: rgb(0, 0, 255);">test</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"locked != null"</span>> locked = <span class="hljs-comment" style="color: green;">#{locked,jdbcType=TINYINT},</span> </<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span>> <<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> <span class="hljs-built_in" style="color: rgb(0, 0, 255);">test</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"gmtCreated != null"</span>> gmt_created = <span class="hljs-comment" style="color: green;">#{gmtCreated,jdbcType=TIMESTAMP},</span> </<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span>> <<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span> <span class="hljs-built_in" style="color: rgb(0, 0, 255);">test</span>=<span class="hljs-string" style="color: rgb(163, 21, 21);">"gmtModified != null"</span>> gmt_modified = <span class="hljs-comment" style="color: green;">#{gmtModified,jdbcType=TIMESTAMP},</span> </<span class="hljs-keyword" style="color: rgb(0, 0, 255);">if</span>> </<span class="hljs-built_in" style="color: rgb(0, 0, 255);">set</span>> <span class="hljs-built_in" style="color: rgb(0, 0, 255);">where</span> student_id = <span class="hljs-comment" style="color: green;">#{studentId,jdbcType=I
作者:微信小助手
<section style="box-sizing: border-box;font-size: 16px;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="padding-top: 10px;padding-right: 10px;padding-left: 10px;box-sizing: border-box;background-color: rgb(239, 239, 239);"> <span style="display: inline-block;width: 5%;line-height: 0.8;font-weight: bolder;font-size: 48px;box-sizing: border-box;" title="" opera-tn-ra-cell="_$.pages:0.layers:0.comps:0.txt1"> <section style="box-sizing: border-box;"> “ </section></span> <section style="display: inline-block;vertical-align: top;float: right;width: 90%;line-height: 1.5;font-size: 15px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="box-sizing: border-box;">面试的时候,面试官问:用户在电商网站中购买成功了,那么它在微服务中经历了什么?你该如何作答? </p> </section> <section style="clear: both;box-sizing: border-box;"></section> </section> </section> </section> <p style="line-height: 1.75em;"><br></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.5386740331491713" data-s="300,640" src="/upload/2763c74a9c2e4d8d245df668615bc246.png" data-type="png" data-w="724" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">当我傻啊,用户在电商网站购买成功,还在微服务中,那肯定就是有一套微服务架构的电商系统。</span></p> <p style="text-align: center;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="1" data-s="300,640" src="/upload/32882757984b6c1c8c448e89058fb3dc.jpg" data-type="jpeg" data-w="224" style="line-height: 29.75px;white-space: normal;"></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">设计一套电商系统还不简单?</span><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">简单想象一下,既然是一个电商系统,有用户去购买,就肯定得有一个用户模块,购买什么东西总不是西北风吧,购买肯定是商品吧,省掉购物车,就得有商品模块吧。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">商品总得有库存吧,库存就暂时跟商品放一起吧,什么仓储物流先别管,就当作是虚拟商品好了,反正题目也没说不能是虚拟商品。<span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 26.25px;">^_^</span></span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="color: rgb(89, 89, 89);font-size: 15px;letter-spacing: 1px;line-height: 1.75em;">购买成功了,那就必须有订单吧,加个订单模块,下完单总得支付吧,不付钱人家凭什么把东西给你,那就得有个支付模块。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.5466666666666666" data-s="300,640" src="/upload/23ca507d076b7484ffc7e1392d27845.jpg" data-type="jpeg" data-w="300" style="line-height: 27.2px;text-align: center;white-space: normal;"></p> <h4 class="heading" data-id="heading-1" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">简单粗暴,四个模块,如上图:</span></h4> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">用户模块</span></strong></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">商品模块(库存)</span></strong></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">订单模块</span></strong></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">支付模块</span></strong></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">好,几个模块搞定,外加下单流程图:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.2145985401459854" data-s="300,640" src="/upload/d68ad7aca9e55ccf1f0c313f73b9fe81.jpg" data-type="jpeg" data-w="685" style=""></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.8666666666666667" data-s="300,640" src="/upload/c411bf507f061aa75dffb55b2e6f482d.jpg" data-type="jpeg" data-w="180" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">等等,貌似题目说是微服务,既然是微服务就涉及到拆分服务的问题。</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="heading" style="box-sizing: border-box;">DDD 领域驱动设计</p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">刚刚确实是梳理了一下模块,既然是微服务,就得进行服务的拆分,服务怎么进行拆分呢?</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">貌似按照刚次梳理模块来划分也是可以的,不过这样好像显得我很是不专业,听说现在很多人都要使用 DDD(领域驱动设计)来指导微服务的拆分。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.7154377880184332" data-s="300,640" src="/upload/60d16fae6c86aa45c0c3ca43c687abd8.jpg" data-type="jpeg" data-w="868" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">参考 DDD 的设计,DDD 官方的架构草图,总体架构分为四层:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Infrastructure(基础实施层)</span></strong></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Domain(领域层)</span></strong></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Application(应用层)</span></strong></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Interfaces(表示层,也叫用户界面层或是接口层)</span></strong></p></li> </ul> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="heading" style="box-sizing: border-box;"><strong>微服务结合 DDD</strong></p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">不过对于领域设计而言,代码层其实不是最重要,最重要的是如何去划分领域,划分好边界。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">而对于微服务而言,非常适合从业务上去划分各个 Modules,划分好各个业务板块,微服务 + DDD,个人觉得首先从微服务的角度考虑去划分大的业务模块,每个微服务都应该是一个可以独立部署,各司其职的模块。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">简单的说,在微服务实际的开发中,结合 DDD 的思想去划分所有属于自己的领域。</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="heading" style="box-sizing: border-box;"><strong>实施 DDD 的关键</strong></p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">第一点是使用通过的语言建立所有的聚合,实体,值对象。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">第二点也就是最关键的“建模”:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">划分“战略建模”,从一种宏观的角度去审核整个项目,划分出“界限上下文”,形成具有上帝视角的“上下文映射图”。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">还有一个建模是“战术建模”,在我们的“战略建模”划分出来的“界限上下文”中进行“聚合”,“实体”,“值对象”,并按照模块分组。</span></p></li> </ul> <h5 class="heading" data-id="heading-5" style="line-height: normal;"><br></h5> <section style="box-sizing: border-box;font-size: 16px;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="heading" style="box-sizing: border-box;"><strong>构建电商系统的上下文映射图</strong></p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">先来确定我们的战略核心的领域是什么?我们的目的是什么?</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">作为一个电商系统,我们的核心肯定是卖出更多的商品,获取更多订单更多的利润,那么销售可以作为我们的一个核心的领域。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这个作为一个明确核心域确立下来:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.5615763546798029" data-s="300,640" src="/upload/24319270bd3f568ad41657ca60d6b238.jpg" data-type="jpeg" data-w="609" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">确定完核心子域后,根据对这个领域的理解划分出各个上下文,然后根据上下文再确定其他的相关领域。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.6480836236933798" data-s="300,640" src="/upload/11e4d47f2a7eff4ff90d6e6d4ac0a87e.jpg" data-type="jpeg" data-w="861" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">初步我们可以看出围绕销售核心域的包含的几大块内容,价格,销售方式,购买的方式,已经购买。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">然后我们对支撑着核心域的子域也做了划分,支撑着核心域的有商品域,用户域,通用域有订单域,物流域,支付域。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">回到我们的主题,我们这次没有购物车,也没有各个会员销售价格,把一些上下文拿掉,并建立映射。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.7247838616714697" data-s="300,640" src="/upload/fa02ac2cd911f1fe3c8c4f321fdea90d.jpg" data-type="jpeg" data-w="694" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">领域驱动设计看似简单,其实很难实施,因为在各个环节中都需要对应的领域专家的参加或指导,这样才能设计出最符合实际的上下文映射图。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">而且我们花费的精力可能相比以后的数据驱动开发模式更多,但在整体对项目的把控性能上说,领域比数据驱动更加抽象,更加的顶层设计,在对应互联网的多变情况看得更远。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">我们将微服务拆分为 5 个领域,分别是:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">销售域</span></strong></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">商品域</span></strong></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">用户域</span></strong></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">订单域</span></strong></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">支付域</span></strong></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">完美,接下来就可以开始开发了。 ^ _ ^</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.8666666666666667" data-s="300,640" src="/upload/c411bf507f061aa75dffb55b2e6f482d.jpg" data-type="jpeg" data-w="180" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">等等,兵马未动,粮草先行;代码未动,图先行,先把时序图画出来。</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="heading" style="box-sizing: border-box;">时序图</p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">一个简单的下单流程,涵盖了几个领域:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.6292466765140325" data-s="300,640" src="/upload/9843c170b746c0e731b25ca69f1d6ac.jpg" data-type="jpeg" data-w="677" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">完美,接下来就可以开发微服务了。^ _ ^</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.8666666666666667" data-s="300,640" src="/upload/c411bf507f061aa75dffb55b2e6f482d.jpg" data-type="jpeg" data-w="180" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">等等,微服务的技术栈还未选型。</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="heading" style="box-sizing: border-box;">微服务技术栈选型</p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">服务拆分完了,时序图也画完了,可以开始我们的微服务之旅了,目前主流的微服务有阿里大名鼎鼎的 Dubbo 和 Spring Cloud 全家桶,还有新浪的 Motan。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">比较熟悉的还是 Dubbo 和 Spring Cloud,也都使用过,究竟应该选用哪一个呢?</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">因为之前都使用过,做点简单,粗暴的总结。Dubbo 在很早之前就开始使用,当时的微服务还没有现在这么火,很多理论体系也未完善,Dubbo 更像是一套 RPC 整合框架,Spring Cloud 则更倾向微服务架构的生态。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">相比 Dubbo,Spring Cloud 可以说是微服务一整套的解决方案,在功能上是 Dubbo 的一个超级。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Dubbo 和 Spring Cloud 比喻,Dubbo 架构的微服务就像组装电脑,各个环节自由度很高。Spring Cloud 更像品牌机。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">基于不折腾,简单快捷,更倾向选择 Spring Cloud。OK,就定下来技术栈使用 Spring Cloud,愉快的决定。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.8666666666666667" data-s="300,640" src="/upload/c411bf507f061aa75dffb55b2e6f482d.jpg" data-type="jpeg" data-w="180" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">等等,就这么草率就决定用 Spring Cloud 做为微服务,难道不需要把微服务的利弊先弄清楚吗?</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="heading" style="box-sizing: border-box;">微服务的利和弊</p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">既然选择了微服务,就得知道微服务的利和弊,特别是弊,引入了微服务,就等于引入了一套复杂的体系,一套复杂的体系带来的各种挑战必须事先了解清楚。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.5147744945567652" data-s="300,640" src="/upload/217ce2d0158a9da4ba39871727d75ec8.jpg" data-type="jpeg" data-w="643" style=""></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="heading" style="box-sizing: border-box;"><strong>利</strong></p> </section> </section> </section> <p style="line-height: normal;"><br></p> <h5 class="heading" data-id="heading-10" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">①强模块化边界</span></strong></h5> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我们知道做软件架构,软件设计,模块化是非常重要的一点,一开始我们写程序做软件,我们采用类的方式来做模块化,后面开始采用组件或类库的方式做模块化,可以做到工程上的重用和分享给其他团队来使用。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">微服务在组件的层次上面又高了一层,以服务的方式来做模块化,每个团队独立开始和维护自己的服务,有明显的一个边界。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">开发完一个服务,其他团队可以直接调用这个服务,不需要像组件通过 Jar 或源码的方式去进行分享,所以微服务的边界是比较清晰的。</span></p> <p style="line-height: normal;"><br></p> <h5 class="heading" data-id="heading-11" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">②可独立部署</span></strong></h5> <p style="line-height: normal;"><br></p> <h5 class="heading" data-id="heading-12" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">③技术多样性</span></strong></h5> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="heading" style="box-sizing: border-box;"><strong>弊(或者说挑战)</strong></p> </section> </section> </section> <p style="line-height: normal;"><br></p> <h5 class="heading" data-id="heading-14" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">①分布式复杂性</span></strong></h5> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在原来单块应用就是一个应用,一个对单块应用的架构比较熟悉的人可以对整个单块应用有一个很好的把控。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">但是到了分布式系统,微服务化了以后可能涉及到的服务有好几十个,一些大公司可能涉及到的服务上百个,服务与服务之间是通过相互沟通来实现业务。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">那么这个时候整个系统就变成非常复杂,一般的开发人员或一个团队都无法理解整个系统是如何工作的,这个就是分布式带来的复杂性。</span></p> <p style="line-height: normal;"><br></p> <h5 class="heading" data-id="heading-15" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">②最终一致性</span></strong></h5> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">微服务的数据是分散式治理的,每个团队都有自己的数据源和数据拷贝,比方说团队 A 有订单数据,B 团队也有订单数据,团队 A 修改了订单数据是否应该同步给团队 B 的数据呢?</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这里就涉及到数据一致性问题,如果没有很好的解决一致性问题,就可能造成数据的不一致,这个在业务上是不可以接受的。</span></p> <p style="line-height: normal;"><br></p> <h5 class="heading" data-id="heading-16" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">③运维复杂性</span></strong></h5> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">以往的运维需要管理的是机器+单块的应用,分布式系统和单块应用不一样的是,分布式系统需要很多的服务,服务与服务之间相互协同。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">那么对分布式系统的资源,容量规划,监控,对整个系统的可靠性稳定性都非常具备挑战的。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">只有在清楚了解微服务带来的挑战,明知道山有虎偏向虎山行,才能够真正的胜任挑战,最重要的是,要清楚明了里面有什么坑,怎么避免踩坑。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">完美,已经了解微服务带来的好处和挑战,接下来就可以开始开发了。^ _ ^</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.8666666666666667" data-s="300,640" src="/upload/c411bf507f061aa75dffb55b2e6f482d.jpg" data-type="jpeg" data-w="180" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">等等,微服务还没有做逻辑分层。</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="heading" style="box-sizing: border-box;">微服务怎么做逻辑分层</p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">目前我们的微服务里面有几个服务,分别是订单,商品,用户。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如果客户端向查看 “我的订单” 这么一个接口;如果客户端假定是 PC 端,就需要请求三次接口,分别对接订单,商品,用户三个服务,分别拿完三次调用数据,再将三次调用数据进行整合输出展示。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">要知道 PC 调用后端服务是走外网,这无疑大大增加了网络的开销,而且让 PC 端变成更为复杂。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">假定在中间加多一个层为聚合服务层,即对网络开销进行减少,因为微服务内部是通过内网进行数据传输,也让 PC 端的业务变得比较简单。</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="1.0106609808102345" data-s="300,640" src="/upload/a9b1330c8fcbf9cdf85d821b50ce46b5.jpg" data-type="jpeg" data-w="469" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">图中的 “PC 聚合服务” 也是一个微服务,只不过它是属于聚合服务中间层,我们将为微服务进行逻辑划分,分为 2 个层:</span></p> <p style="text-align: center;line-height: 1.75em;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.4463087248322148" data-s="300,640" src="/upload/60682961fc5852038c233630b297036a.jpg" data-type="jpeg" data-w="894" style=""></p> <h5 class="heading" data-id="heading-18" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">①微服务基础服务层</span></strong></h5> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">基础服务一般属于互联网平台基础性的支撑服务,比方说,电商网站的基础服务有订单服务,商品服务,用户服务等。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这些都属于比较基础和原子性,下沉一个公司的基础设施的低层,向下承接存储,向上提供业务能力,有些公司叫基础服务,中间层服务,公共服务,Netflix 成为中间层服务。我们暂且统称为基础服务。</span></p> <p style="line-height: normal;"><br></p> <h5 class="heading" data-id="heading-19" style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">②微服务聚合服务层</span></strong></h5> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">已经有了基础服务能提供业务能力,为什么还需要聚合服务,因为我们有不同的接入端,如 App 和 H5,PC 等等,它们看似调用大致相同的数据,但其实存在很多差异。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">例如 PC 需要展示更多信息,App 需要做信息裁剪等等。一般低层服务都是比较通用的,基础服务应该对外输出相对统一的服务,在抽象上做得比较好。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">但是对不同的外界 App 和 PC 的接入,我们需要作出不同的适配,这个时候需要有一个层去做出聚合裁剪的工作。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">例如一个商品详情在 PC 端展示和 App 端的展示,PC 可能会展示更多的信息,而 App 则需要对信息作出一些裁剪。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如果基础服务直接开放接口给到 PC 和 App,那么基础服务也需要去做成各种设配,这个很不利于基础服务的抽象。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">所以我们在基础层之上加入聚合服务层,这个层可以针对 PC 和 App 做成适当的设配进行相应的裁剪。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">那么我们的微服务中,又增加了一个服务,属于聚合服务。</span></p> <p style="text-align: center;line-height: 1.75em;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.4784688995215311" data-s="300,640" src="/upload/7a2befd8899e5ef7442c209d532ba1a0.jpg" data-type="jpeg" data-w="1045" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">好了,接下来可以愉快的 Coding...</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.8045267489711934" data-s="300,640" src="/upload/c889727f22a36c6a92c663f73f226581.jpg" data-type="jpeg" data-w="486" style=""></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.8666666666666667" data-s="300,640" src="/upload/c411bf507f061aa75dffb55b2e6f482d.jpg" data-type="jpeg" data-w="180" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">等等,貌似不对,如果是单块应用加上事务应该没问题,这里是分布式,恐怕得考虑加分布式事务。</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="border-bottom-width: 1px;border-bottom-style: solid;border-bottom-color: black;margin-top: 0.5em;margin-bottom: 0.5em;line-height: 1.2;box-sizing: border-box;" powered-by="xiumi.us"> <section style="display: inline-block;border-bottom-width: 6px;border-bottom-style: solid;border-color: rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="heading" style="box-sizing: border-box;">分布式事务</p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">我们来理一理创建订单和扣件库存模块之间的关系:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.5957446808510638" data-s="300,640" src="/upload/ac9da68cf040cfd92c3adde9aee9667a.jpg" data-type="jpeg" data-w="423" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">可以发现,因为微服务的原因,我们把服务进行了分布式,随着各个数据库也随着变成分布式每个数据库不一定存在相同的物理机中。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">那么这个时候单个数据库的 ACID 已经不能适应这种情况,而在这种集群中想去保证集群的 ACID 几乎很难达到,或者即使能达到那么效率和性能会大幅下降,最为关键的是再很难扩展新的分区了。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">这个时候如果再追求集群的 ACID 会导致我们的系统变得很差,这时我们就需要引入一个新的理论原则来适应这种集群的情况,就是 CAP。</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="heading" style="box-sizing: border-box;"><strong>CAP 定理</strong></p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">CAP 必须满足以下的 3 个属性:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">一致性(C):</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">可用性(A):</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">分区容错性(P):</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在 C 和 A 之间做出选择。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">简单的来说,在一个分布式系统中,最多能支持上面的两种属性。但显然既然是分布式注定我们是必然要进行分区,既然分区,我们就无法百分百避免分区的错误。因此,我们只能在一致性和可用性去作出选择。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在分布式系统中,我们往往追求的是可用性,它的重要性比一致性要高,那么如何实现高可用,这里又有一个理论,就是 BASE 理论,它给 CAP 理论做了进一步的扩充。</span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-size: 16px;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;" powered-by="xiumi.us"> <section style="width: 0.6em;display: inline-block;vertical-align: middle;box-sizing: border-box;"> <span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.2;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span> <strong><span style="width: 0.6em;height: 0.6em;display: block;opacity: 0.6;margin-top: 2px;margin-bottom: 2px;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span><span style="width: 0.6em;height: 0.6em;display: block;opacity: 1;box-sizing: border-box;background-color: rgb(89, 89, 89);"></span></strong> </section> <section style="display: inline-block;vertical-align: middle;font-size: 18px;padding-left: 5px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p class="heading" style="box-sizing: border-box;"><strong>BASE 理论</strong></p> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">BASE 理论指出:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Basically Available(基本可用)</span></strong></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Soft state(软状态)</span></strong></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Eventually consistent(最终一致性)</span></strong></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">BASE 理论是对 CAP 中的一致性和可用性进行一个权衡的结果,理论的核心思想就是:我们无法做到强一致,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">好了,说了一大顿理论,程序员们都等急了,赶快来看看分布式事务的解决方案有哪些,可以进行接下去的 Coding...</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">来吧,讨论技术方案:</span></p> <p style="text-align: center;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"><img class="rich_pages" data-copyright="0" data-ratio="0.7647058823529411" data-s="300,640" src="/upload/7758d2aa75682a72bfa582ae17b3915c.jpg" data-type="jpeg" data-w="748" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">几个方案拿出来了,因为我们不是专门来讲解分布式事务的机制和原理,主要还是来做分布式事务的技术选型。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">先排除掉我们应该不会选择的方案,一个是 XA 两阶段提交,这个在很多传统型公司会被使用,但不适合互联网微服务的分布式系统,锁定资源时间长,性能影响大,排除。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">另一个是阿里的 GTS,并没有开源,目前已经开源了 Fescar,不过目前尚缺少调研,可能在下个阶段研究后会使用,目前先排除。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);
作者:微信小助手
<section class="xmteditor" style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"></section> <h2 style="box-sizing: border-box;margin-bottom: 1rem;color: rgb(21, 153, 87);line-height: 1.35;font-size: 22px;text-align: start;white-space: normal;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">前言</h2> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">好久没写博客了,我原先的标题是 <strong style="box-sizing: border-box;color: rgb(0, 0, 0);">“从输入url到页面加载完成的XXX”?</strong></p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">但想着,这是别人嚼烂很多次的内容,缺乏挑战性,而且,页面操作过程中能优化的地方实在太多了。</p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">那就干脆给自己挖个坑吧,好歹也在运维开发部待过一年的时间。</p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: center;white-space: normal;"><img class="" data-ratio="0.9666666666666667" src="/upload/c8f488344b4b1a43dae91c81c983bcd3.png" data-type="png" data-w="240" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">本文将尝试从<strong style="box-sizing: border-box;color: rgb(0, 0, 0);">前后端或运维多个角度</strong>,来述说整个站点从解析到操作过程中的优化。</p> <h2 style="box-sizing: border-box;margin-top: 1.5rem;margin-bottom: 1rem;color: rgb(21, 153, 87);line-height: 1.35;font-size: 22px;text-align: start;white-space: normal;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">1. 流程回顾</h2> <h3 style="box-sizing: border-box;margin-top: 1.5rem;margin-bottom: 1rem;color: rgb(21, 153, 87);line-height: 1.35;font-size: 18px;text-align: start;white-space: normal;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">1. URL的输入到浏览器解析的一系列事件</h3> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">很多大公司面试喜欢问这样一道面试题,输入URL到看见页面发生了什么?,今天我们来总结一下。 简单来说,共有以下几个过程</p> <ol style="" class=" list-paddingleft-2"> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">浏览器中输入网址</span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">域名解析( <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">DNS</span></code>),找到IP服务器</span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">发起 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">TCP</span></code>连接, <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">HTTP</span></code>三次握手,发送请求( <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="typ" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">Request</span></code>)</span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">服务器响应HTTP(Response)</span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">浏览器下载资源 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">html css js images</span></code>等</span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">浏览器解析代码(如果服务器有 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">gzip</span></code>压缩,浏览器先解压)</span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">浏览器渲染呈现给用户</span></span></p></li> </ol> <h3 style="box-sizing: border-box;margin-top: 1.5rem;margin-bottom: 1rem;color: rgb(21, 153, 87);line-height: 1.35;font-size: 18px;text-align: start;white-space: normal;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">2. 结合操作页面到关闭标签页</h3> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">我们在页面渲染完成之后执行某些操作:</p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">按钮重复点击</span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">滚动操作</span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">条件查询检索</span></span></p></li> </ul> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">姑且将以上都归为 <strong style="box-sizing: border-box;color: rgb(0, 0, 0);">==> 8. 界面操作</strong></p> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">还在<strong style="box-sizing: border-box;color: rgb(0, 0, 0);">步骤3:发起TCP连接</strong> 前插入:</p> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">浏览器允许的并发请求优化</span></span></p></li> </ul> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">下面就让我们从DNS解析开始...</p> <h2 style="box-sizing: border-box;margin-top: 1.5rem;margin-bottom: 1rem;color: rgb(21, 153, 87);line-height: 1.35;font-size: 22px;text-align: start;white-space: normal;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">2. DNS解析流程</h2> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;">以 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="typ" style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;font-size: 14px;">Chrome</span></code>浏览器为例:</p> <ol style="" class=" list-paddingleft-2"> <li><p><br></p><p style="box-sizing: border-box;margin-bottom: 15px;">Chrome浏览器 会首先搜索浏览器自身的DNS缓存。</p><p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;">(缓存时间比较短,默认只有1分钟,且只能容纳1000条缓存)</p><p><br></p></li> </ol> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;white-space: normal;"><img class="" data-backh="232" data-backw="552" data-before-oversubscription-url="https://mmbiz.qlogo.cn/mmbiz_png/icnrNBicEhkVUa6ibSsDhPmicArlBVuwYJUneLb9pnMblBmPuiadYAp1sOPvWHmEmrksEWxBcaDzRhs3wO86H86fCbQ/0?wx_fmt=png" data-ratio="0.42003853564547206" src="/upload/96ee54f78cef0868e28ac1b4e30f0e11.png" data-type="png" data-w="1038" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;width: 100%;height: auto;">注: <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;font-size: 14px;">chrome</span><span class="pun" style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;font-size: 14px;">:</span><span class="com" style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;font-size: 14px;">//net-internals/#dns</span></code>来进行查看 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="typ" style="box-sizing: border-box;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;font-size: 14px;">Chrome</span></code>自身的缓存)</p> <ol style="" class=" list-paddingleft-2"> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">如果浏览器自身的缓存里面没有找到对应的条目,那么 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="typ" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">Chrome</span></code>会搜索操作系统自身的DNS缓存</span></span></p></li> </ol> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p><br></p><p style="box-sizing: border-box;margin-bottom: 15px;"><code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="typ" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">Windows</span></code> - 在 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="typ" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">Windows</span></code>中查看 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">DNS</span></code>缓存条目的过程非常简单。只需打开命令提示符并输入以下命令: <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">ipconfig</span><span class="pun" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">/</span><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">displaydns</span></code>。</p><p><br></p></li> <li><p><br></p><p style="box-sizing: border-box;margin-bottom: 15px;"><code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="typ" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">Mac</span></code> - 在 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="typ" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">Mac</span></code>上查看 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">DNS</span></code>缓存条目的过程略有不同。需要先打开控制台应用,从左侧边栏选择设备,然后输入: <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">any</span><span class="pun" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">:</span><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">mdnsresponder</span></code>进入搜索栏。接下来,打开命令行并输入以下命令:</p><pre class="prettyprint linenums prettyprinted" style="box-sizing: border-box;padding-top: 8px;padding-bottom: 6px;background: rgb(244, 243, 236);border-radius: 0px;overflow-y: auto;font-size: 10px;line-height: 12px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 1px !important;border-style: solid !important;border-color: rgb(226, 226, 226) !important;"><span style="font-family: Menlo, Monaco, Consolas, "Courier New", monospace;font-size: 12px;text-align: left;white-space: pre;background-color: rgb(248, 248, 248);">sudo </span><span class="hljs-built_in" style="color: rgb(0, 134, 179);font-family: Menlo, Monaco, Consolas, "Courier New", monospace;font-size: 12px;text-align: left;white-space: pre;">log</span><span style="font-family: Menlo, Monaco, Consolas, "Courier New", monospace;font-size: 12px;text-align: left;white-space: pre;background-color: rgb(248, 248, 248);"> config --mode </span><span class="hljs-string" style="color: rgb(221, 17, 68);font-family: Menlo, Monaco, Consolas, "Courier New", monospace;font-size: 12px;text-align: left;white-space: pre;">"private_data:on"</span><span style="font-family: Menlo, Monaco, Consolas, "Courier New", monospace;font-size: 12px;text-align: left;white-space: pre;background-color: rgb(248, 248, 248);">sudo killall -INFO mDNSResponder</span></pre><p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;">然后,返回控制台应用程序并查看缓存的DNS记录列表。例如,下面的屏幕截图显示了 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">wx</span><span class="pun" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">.</span><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">qlogo</span><span class="pun" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">.</span><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">cn</span></code>的缓存 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">CNAME</span></code>记录。</p><p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;"><img class="" data-ratio="0.3930530164533821" src="/upload/ac50e6720d66fb526f5a621763f7d844.png" data-type="png" data-w="2188" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p></li> </ul> <ol style="" class=" list-paddingleft-2"> <li><p><br></p><p style="box-sizing: border-box;margin-bottom: 15px;">如果在系统的DNS缓存也没有找到,那么尝试读取 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">hosts</span></code>文件。看看这里面有没有该域名对应的IP地址,如果有则解析成功。</p><p><br></p></li> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p>注: <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="typ" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">Windows</span></code>位于 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">C</span><span class="pun" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">:</span><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">WindowsSystem32driversetc</span></code>, <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="typ" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">Mac</span></code>则是 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="str" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">/etc/</span><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">hosts</span></code>。</p></li> <li><p><strong style="box-sizing: border-box;color: rgb(0, 0, 0);">这种操作系统级别的域名解析通常会被不怀好意的人利用,通过修改你 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;font-weight: 400;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">hosts</span></code>文件里的内容把域名解析到他指定的 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;font-weight: 400;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">ip</span></code>地址上,造成所谓的域名劫持,所以将 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;font-weight: 400;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">hosts</span></code>文件设置成了只读模式,防止被恶意篡改。</strong></p></li> </ul> <li><p><br></p><p style="box-sizing: border-box;margin-bottom: 15px;">如果在 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">hosts</span></code>文件中也没有找到对应的条目,浏览器就会发起一个 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">DNS</span></code>的系统调用,请求本地域名服务器 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">localDNS</span></code>( <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">LDNS</span></code>)来解析这个域名。</p><p><br></p></li> </ol> <ul style="list-style-type: square;" class=" list-paddingleft-2"> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">通过 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">UDP</span></code>协议向 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">DNS</span></code>的53端口发起请求,这个请求是递归的请求,也就是运营商的 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">DNS</span></code>服务器必 须得提供给我们该域名的 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">IP</span></code>地址)</span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">第一次就会请求本地域名服务器( <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">LDNS</span></code>)来解析这个域名,这台服务一般在你城市的某个角落,距离不会很远,并且他的性能很好,一般都会缓存域名解析结果,大概80%的域名解析到这里都结束了。</span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">如果本地域名解析服务器也没有该域名的记录,则开始递归+迭代解析</span></span></p></li> </ul> <blockquote style="box-sizing: border-box;margin-bottom: 1.2em;padding: 15px 15px 15px 1rem;color: rgb(129, 145, 152);border-left-width: 6px;border-left-color: rgb(220, 230, 240);font-size: 14px;line-height: 18px;background: rgb(242, 247, 251);font-family: Helvetica, Arial, sans-serif;text-align: start;white-space: normal;"> <p style="box-sizing: border-box;">直到这里,浏览器能做的所有DNS解析已完成,接下来的步骤就是和服务器相关了。不想看的可以忽略。</p> </blockquote> <p style="box-sizing: border-box;margin-top: 15px;margin-bottom: 15px;color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: center;white-space: normal;"><img class="" data-ratio="0.9966555183946488" src="/upload/bd8a8a9c6de20184b3cc91580db6a5f9.png" data-type="png" data-w="299" style="box-sizing: border-box;border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <ol style="" class=" list-paddingleft-2"> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">如果 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">localDNS</span></code>仍然没有命中,就直接到 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="typ" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">Root</span><span class="typ" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">Server</span></code>域名服务器请求解析。</span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">根域名服务器返回给本地域名服务器一个所查询的主域名服务器( <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">gTLD</span><span class="typ" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">Server</span></code>)地址。 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">gTLD</span></code>是国际顶级域名服务器,如 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pun" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">.</span><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">com</span></code>、 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pun" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">.</span><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">cn</span></code>、. <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">org</span></code>等,全球只有13台左右。</span></span></p></li> <li><p><span style="box-sizing: border-box;color: rgb(74, 74, 74);font-size: 14px !important;"><span style="box-sizing: border-box;">本地域名服务器 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;display: inline-block;padding-right: 2px;padding-left: 2px;">localDNS</span></code>再向上一步返回的 <code class="prettyprint code-in-text prettyprinted" style="box-sizing: border-box;background: rgb(243, 241, 241);color: rgb(88, 88, 88);font-size: 16px;line-height: 18px;font-family: consolas, menlo, courier, monospace, "Microsoft Yahei"!important;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="pln" style="box-sizing: border-box;font-size: 14px;background-image: initial;backgr
作者:微信小助手
<section class="KolEditor" style="margin-top: 20px;max-width: 100%;overflow: hidden;font-family: 微软雅黑, 'Microsoft YaHei', Arial, sans-serif;font-size: 16px;font-variant-ligatures: normal;orphans: 2;white-space: normal;widows: 2;border: 0px none;box-sizing: border-box !important;word-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;white-space: pre-wrap;box-sizing: border-box !important;word-wrap: break-word !important;"><img class="" data-ratio="0.13125" src="/upload/42e5a05956be7bb0e6e2c13280cc2e01.gif" data-type="gif" data-w="640" style="box-sizing: border-box !important;word-wrap: break-word !important;"></p> </section> <p style="max-width: 100%;min-height: 1em;white-space: pre-wrap;font-family: 微软雅黑, 'Microsoft YaHei', Arial, sans-serif;font-size: 16px;font-variant-ligatures: normal;orphans: 2;widows: 2;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="font-size: 15px;line-height: 1.6;font-family: 'Helvetica Neue', Helvetica, 'Hiragino Sans GB', 'Microsoft YaHei', Arial, sans-serif;">在上周,我密集面试了若干位Java后端的候选人,工作经验在3到5年间。我的标准其实不复杂:第一能干活,第二Java基础要好,第三最好熟悉些分布式框架,我相信其它公司招初级开发时,应该也照着这个标准来面的。</span><br></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">我也知道,不少候选人能力其实不差,但面试时没准备或不会说,这样的人可能在进团队干活后确实能达到期望,但可能就无法通过面试,但面试官总是只根据面试情况来判断。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">但现实情况是,大多数人可能面试前没准备,或准备方法不得当。要知道,我们平时干活更偏重于业务,不可能大量接触到算法,数据结构,底层代码这类面试必问的问题点,换句话说,面试准备点和平时工作要点匹配度很小。</span></p> <p><span style="font-size: 15px;line-height: 1.6;"> </span></p> <p><span style="font-size: 15px;line-height: 1.6;">作为面试官,我只能根据候选人的回答来决定面试结果。不过,与人方便自己方便,所以我在本文里,将通过一些常用的问题来介绍面试的准备技巧。大家在看后一定会感叹:只要方法得当,准备面试第一不难,第二用的时间也不会太多。</span></p> <p><span style="font-size: 15px;line-height: 1.6;"> <mpcpc js_editor_cpcad="" class="js_cpc_area res_iframe cpc_iframe" data-category_id_list="48|26|1|28|44|45|35|41|5|31|7|37|11|40|47|15|36|43|16|42" src="/cgi-bin/readtemplate?t=tmpl/cpc_tmpl"></mpcpc></span></p> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section data-width="100%" style="width: 558px;box-sizing: border-box;background-image: -webkit-linear-gradient(left, rgb(51, 116, 163), rgba(255, 247, 234, 0));background-attachment: initial;background-color: rgb(162, 215, 196);background-size: initial;background-origin: initial;background-clip: initial;background-position: initial;background-repeat: initial;"> <section style="box-sizing: border-box;"> <section style="margin-top: 20px;margin-bottom: 20px;box-sizing: border-box;"> <section data-width="100%" style="padding: 10px;display: inline-block;width: 558px;border-width: 0px 0px 0px 10px;border-style: solid;border-left-color: rgb(240, 112, 153);border-right-color: rgb(240, 112, 153);box-shadow: rgb(0, 0, 0) 0px 0px 0px;box-sizing: border-box;"> <section style="box-sizing: border-box;"> <strong><span style="color: rgb(255, 255, 255);font-size: 16px;"><span style="color: rgb(255, 255, 255);line-height: 24px;">1 框架是重点,但别让人感觉你只会山寨别人的代码</span></span></strong> </section> </section> </section> </section> </section> </section> </section> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;color: rgb(62, 62, 62);"></section> <p><span style="font-size: 15px;line-height: 1.6;">在面试前,我会阅读简历以查看候选人在框架方面的项目经验,在候选人的项目介绍的环节,我也会着重关注候选人最近的框架经验,目前比较热门的是SSM。</span><br></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">不过,一般工作在5年内的候选人,大多仅仅是能“山寨”别人的代码,也就是说能在现有框架的基础上,照着别人写的流程,扩展出新的功能模块。比如要写个股票挂单的功能模块,是会模仿现有的下单流程,然后从前端到后端再到数据库,依样画葫芦写一遍,最多把功能相关的代码点改掉。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">其实我们每个人都这样过来的,但在面试时,如果你仅仅表现出这样的能力,就和大多数人的水平差不多了,在这点就没法体现出你的优势了。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">我们知道,如果单纯使用SSM框架,大多数项目都会有痛点。比如数据库性能差,或者业务模块比较复杂,并发量比较高,用Spring MVC里的Controller无法满足跳转的需求。所以我一般还会主动问:你除了依照现有框架写业务代码时,还做了哪些改动?</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">我听到的回答有:增加了Redis缓存,以避免频繁调用一些不变的数据。或者,在MyBitas的xml里,select语句where条件有isnull,即这个值有就增加一个where条件,对此,会对任何一个where增加一个不带isnull的查询条件,以免该语句当传入参数都是null时,做全表扫描。或者,干脆说,后端异步返回的数据量很大,时间很长,我在项目里就调大了异步返回的最大时间,或者对返回信息做了压缩处理,以增加网络传输性能。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">对于这个问题,我不在乎听到什么回答,我只关心回答符不符逻辑。一般只要答对,我就会给出“在框架层面有自己的体会,有一定的了解”,否则,我就只会给出“只能在项目经理带领下编写框架代码,对框架本身了解不多”。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">其实,在准备面试时,归纳框架里的要点并不难,我就不信所有人在做项目时一点积累也没,只要你说出来,可以说,这方面你就碾压了将近7成的竞争者。 </span></p> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section data-width="100%" style="width: 558px;box-sizing: border-box;background-image: -webkit-linear-gradient(left, rgb(51, 116, 163), rgba(255, 247, 234, 0));background-attachment: initial;background-color: rgb(162, 215, 196);background-size: initial;background-origin: initial;background-clip: initial;background-position: initial;background-repeat: initial;"> <section style="box-sizing: border-box;"> <section style="margin-top: 20px;margin-bottom: 20px;box-sizing: border-box;"> <section data-width="100%" style="padding: 10px;display: inline-block;width: 558px;border-width: 0px 0px 0px 10px;border-style: solid;border-left-color: rgb(240, 112, 153);border-right-color: rgb(240, 112, 153);box-shadow: rgb(0, 0, 0) 0px 0px 0px;box-sizing: border-box;"> <section style="box-sizing: border-box;"> <span style="color: rgb(255, 255, 255);font-size: 16px;"><strong><span style="color: rgb(255, 255, 255);line-height: 24px;">2 别单纯看单机版的框架,适当了解些分布式</span></strong></span> </section> </section> </section> </section> </section> </section> </section> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;color: rgb(62, 62, 62);"></section> <p><span style="font-size: 15px;line-height: 1.6;">此外,在描述项目里框架技术时,最好你再带些分布式的技术。下面我列些大家可以准备的分布式技术。</span><br></p> <p style="text-align: center;"><img class="" data-ratio="0.5472972972972973" src="/upload/9d9b75e3ef198a5a0b424eb93107c77.png" data-type="png" data-w="592" height="252" style="border: 0px none rgb(75, 75, 75);box-sizing: border-box;height: 251.75px;max-width: 900px;" width="460"></p> <p><span style="font-size: 15px;"> 1 反向代理方面,nginx的基本配置,比如如何通过lua语言设置规则,如何设置session粘滞。如果可以,再看些nginx的底层,比如协议,集群设置,失效转移等。</span></p> <p><span style="font-size: 15px;"><br></span></p> <p><span style="font-size: 15px;"> 2 远程调用dubbo方面,可以看下dubbo和zookeeper整合的知识点,再深一步,了解下dubbo底层的传输协议和序列化方式。</span></p> <p><span style="font-size: 15px;"><br></span></p> <p><span style="font-size: 15px;"> 3 消息队列方面,可以看下kafka或任意一种组件的使用方式,简单点可以看下配置,工作组的设置,再深入点,可以看下Kafka集群,持久化的方式,以及发送消息是用长连接还是短拦截。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">以上仅仅是用3个组件举例,大家还可以看下Redis缓存,日志框架,MyCAT分库分表等。准备的方式有两大类,第一是要会说怎么用,这比较简单,能通过配置文件搭建成一个功能模块即可,第二是可以适当读些底层代码,以此了解下协议,集群和失效转移之类的高级知识点。 </span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">如果能在面试中侃侃而谈分布式组件的底层,那么得到的评价就会比较好了,比如“深入了解框架底层”,或“框架经验丰富”,这样就算去面试架构师也行了,更何况是高级开发。</span></p> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section data-width="100%" style="width: 558px;box-sizing: border-box;background-image: -webkit-linear-gradient(left, rgb(51, 116, 163), rgba(255, 247, 234, 0));background-attachment: initial;background-color: rgb(162, 215, 196);background-size: initial;background-origin: initial;background-clip: initial;background-position: initial;background-repeat: initial;"> <section style="box-sizing: border-box;"> <section style="margin-top: 20px;margin-bottom: 20px;box-sizing: border-box;"> <section data-width="100%" style="padding: 10px;display: inline-block;width: 558px;border-width: 0px 0px 0px 10px;border-style: solid;border-left-color: rgb(240, 112, 153);border-right-color: rgb(240, 112, 153);box-shadow: rgb(0, 0, 0) 0px 0px 0px;box-sizing: border-box;"> <section style="box-sizing: border-box;"> <span style="color: rgb(255, 255, 255);font-size: 16px;"><strong><span style="color: rgb(255, 255, 255);line-height: 24px;">3 数据库方面,别就知道增删改查,得了解性能优化</span></strong></span> </section> </section> </section> </section> </section> </section> </section> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;color: rgb(62, 62, 62);"></section> <p><span style="font-size: 15px;line-height: 1.6;">在实际项目里,大多数程序员用到的可能仅仅是增删改查,当我们用Mybatis时,这个情况更普遍。不过如果你面试时也这样表现,估计你的能力就和其它竞争者差不多了。</span><br></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">这方面,你可以准备如下的技能。</span></p> <p><span style="font-size: 15px;"> 1 SQL高级方面,比如group by, having,左连接,子查询(带in),行转列等高级用法。</span></p> <p><span style="font-size: 15px;"> 2 建表方面,你可以考虑下,你项目是用三范式还是反范式,理由是什么?</span></p> <p><span style="font-size: 15px;"> 3 尤其是优化,你可以准备下如何通过执行计划查看SQL语句改进点的方式,或者其它能改善SQL性能的方式(比如建索引等)。</span></p> <p><span style="font-size: 15px;"> 4 如果你感觉有能力,还可以准备些MySQL集群,MyCAT分库分表的技能。比如通过LVS+Keepalived实现MySQL负载均衡,MyCAT的配置方式。同样,如果可以,也看些相关的底层代码。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">哪怕你在前三点表现一般,那么至少也能超越将近一般的候选人,尤其当你在SQL优化方面表现非常好,那么你在面试高级开发时,数据库层面一定是达标的,如果你连第四点也回答非常好,那么恭喜你,你在数据库方面的能力甚至达到了初级架构的级别。</span></p> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section data-width="100%" style="width: 558px;box-sizing: border-box;background-image: -webkit-linear-gradient(left, rgb(51, 116, 163), rgba(255, 247, 234, 0));background-attachment: initial;background-color: rgb(162, 215, 196);background-size: initial;background-origin: initial;background-clip: initial;background-position: initial;background-repeat: initial;"> <section style="box-sizing: border-box;"> <section style="margin-top: 20px;margin-bottom: 20px;box-sizing: border-box;"> <section data-width="100%" style="padding: 10px;display: inline-block;width: 558px;border-width: 0px 0px 0px 10px;border-style: solid;border-left-color: rgb(240, 112, 153);border-right-color: rgb(240, 112, 153);box-shadow: rgb(0, 0, 0) 0px 0px 0px;box-sizing: border-box;"> <section style="box-sizing: border-box;"> <span style="color: rgb(255, 255, 255);font-size: 16px;"><strong><span style="color: rgb(255, 255, 255);line-height: 24px;">4 Java核心方面,围绕数据结构和性能优化准备面试题</span></strong></span> </section> </section> </section> </section> </section> </section> </section> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;color: rgb(62, 62, 62);"></section> <p><span style="font-size: 15px;line-height: 1.6;">Java核心这块,网上的面试题很多,不过在此之外,大家还应当着重关注集合(即数据结构)和多线程并发这两块,在此基础上,大家可以准备些设计模式和虚拟机的说辞。</span><br></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">下面列些我一般会问的部分问题:</span></p> <p><span style="font-size: 15px;"> 1 String a = "123"; String b = "123"; a==b的结果是什么? 这包含了内存,String存储方式等诸多知识点。</span></p> <p><span style="font-size: 15px;"> 2 HashMap里的hashcode方法和equal方法什么时候需要重写?如果不重写会有什么后果?对此大家可以进一步了解HashMap(甚至ConcurrentHashMap)的底层实现。</span></p> <p><span style="font-size: 15px;"> 3 ArrayList和LinkedList底层实现有什么差别?它们各自适用于哪些场合?对此大家也可以了解下相关底层代码。</span></p> <p><span style="font-size: 15px;"> 4 volatile关键字有什么作用?由此展开,大家可以了解下线程内存和堆内存的差别。</span></p> <p><span style="font-size: 15px;"> 5 CompletableFuture,这个是JDK1.8里的新特性,通过它怎么实现多线程并发控制?</span></p> <p><span style="font-size: 15px;"> 6 JVM里,new出来的对象是在哪个区?再深入一下,问下如何查看和优化JVM虚拟机内存。</span></p> <p><span style="font-size: 15px;"> 7 Java的静态代理和动态代理有什么差别?最好结合底层代码来说。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">通过上述的问题点,我其实不仅仅停留在“会用”级别,比如我不会问如何在ArrayList里放元素。大家可以看到,上述问题包含了“多线程并发”,“JVM优化”,“数据结构对象底层代码”等细节,大家也可以举一反三,通过看一些高级知识,多准备些其它类似面试题。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">我们知道,目前Java开发是以Web框架为主,那么为什么还要问Java核心知识点呢?我这个是有切身体会的。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">之前在我团队里,我见过两个人,一个是就会干活,具体表现是会用Java核心基本的API,而且也没有深入了解的意愿(估计不知道该怎么深入了解),另一位平时专门会看些Java并发,虚拟机等的高级知识。过了半年以后,后者的能力快速升级到高级开发,由于对JAVA核心知识点了解很透彻,所以看一些分布式组件的底层实现没什么大问题。 而前者,一直在重复劳动,能力也只一直停留在“会干活”的层面。 </span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">而在现实的面试中,如果不熟悉Java核心知识点,估计升高级开发都难,更别说是面试架构师级别的岗位了。 </span><span style="font-size: 15px;line-height: 1.6;"> </span></p> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section data-width="100%" style="width: 558px;box-sizing: border-box;background-image: -webkit-linear-gradient(left, rgb(51, 116, 163), rgba(255, 247, 234, 0));background-attachment: initial;background-color: rgb(162, 215, 196);background-size: initial;background-origin: initial;background-clip: initial;background-position: initial;background-repeat: initial;"> <section style="box-sizing: border-box;"> <section style="margin-top: 20px;margin-bottom: 20px;box-sizing: border-box;"> <section data-width="100%" style="padding: 10px;display: inline-block;width: 558px;border-width: 0px 0px 0px 10px;border-style: solid;border-left-color: rgb(240, 112, 153);border-right-color: rgb(240, 112, 153);box-shadow: rgb(0, 0, 0) 0px 0px 0px;box-sizing: border-box;"> <section style="box-sizing: border-box;"> <span style="color: rgb(255, 255, 255);font-size: 16px;"><strong><span style="color: rgb(255, 255, 255);line-height: 24px;">5 Linux方面,至少了解如何看日志排查问题</span></strong></span> </section> </section> </section> </section> </section> </section> </section> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;color: rgb(62, 62, 62);"></section> <p><span style="font-size: 15px;line-height: 1.6;">如果候选人能证明自己有“排查问题”和“解决问题”的能力,这绝对是个加分项,但怎么证明?</span></p> <p><span style="font-size: 15px;line-height: 1.6;"><br></span></p> <p><span style="font-size: 15px;line-height: 1.6;">目前大多数的互联网项目,都是部署在Linux上,也就是说,日志都是在Linux,下面归纳些实际的Linux操作。</span><br></p> <p><span style="font-size: 15px;line-height: 1.6;"><br></span></p> <p><span style="font-size: 15px;"> 1 能通过less命令打开文件,通过Shift+G到达文件底部,再通过?+关键字的方式来根据关键来搜索信息。</span></p> <p><span style="font-size: 15px;"> 2 能通过grep的方式查关键字,具体用法是, grep 关键字 文件名,如果要两次在结果里查找的话,就用grep 关键字1 文件名 | 关键字2 --color。最后--color是高亮关键字。</span></p> <p><span style="font-size: 15px;"> 3 能通过vi来编辑文件。</span></p> <p><span style="font-size: 15px;"> 4 能通过chmod来设置文件的权限。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">当然,还有更多更实用的Linux命令,但在实际面试过程中,不少候选人连一条linux命令也不知道。还是这句话,你哪怕知道些很基本的,也比一般人强了。</span></p> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section data-width="100%" style="width: 558px;box-sizing: border-box;background-image: -webkit-linear-gradient(left, rgb(51, 116, 163), rgba(255, 247, 234, 0));background-attachment: initial;background-color: rgb(162, 215, 196);background-size: initial;background-origin: initial;background-clip: initial;background-position: initial;background-repeat: initial;"> <section style="box-sizing: border-box;"> <section style="margin-top: 20px;margin-bottom: 20px;box-sizing: border-box;"> <section data-width="100%" style="padding: 10px;display: inline-block;width: 558px;border-width: 0px 0px 0px 10px;border-style: solid;border-left-color: rgb(240, 112, 153);border-right-color: rgb(240, 112, 153);box-shadow: rgb(0, 0, 0) 0px 0px 0px;box-sizing: border-box;"> <section style="box-sizing: border-box;"> <span style="color: rgb(255, 255, 255);font-size: 16px;"><strong><span style="color: rgb(255, 255, 255);line-height: 24px;">6 通读一段底层代码,作为加分项</span></strong></span> </section> </section> </section> </section> </section> </section> </section> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;color: rgb(62, 62, 62);"></section> <p><span style="font-size: 15px;line-height: 1.6;">如何证明自己对一个知识点非常了解?莫过于能通过底层代码来说明。我在和不少工作经验在5年之内的程序员沟通时,不少人认为这很难?确实,如果要通过阅读底层代码了解分布式组件,那难度不小,但如果如下部分的底层代码,并不难懂。</span></p> <p><span style="font-size: 15px;line-height: 1.6;"><br></span></p> <p><span style="font-size: 15px;line-height: 1.6;"> 1 ArrayList,LinkedList的底层代码里,包含着基于数组和链表的实现方式,如果大家能以此讲清楚扩容,“通过枚举器遍历“等方式,绝对能证明自己。</span></p> <p><span style="font-size: 15px;"> 2 HashMap直接对应着Hash表这个数据结构,在HashMap的底层代码里,包含着hashcode的put,get等的操作,甚至在ConcurrentHashMap里,还包含着Lock的逻辑。我相信,如果大家在面试中,看看而言ConcurrentHashMap,再结合在纸上边说边画,那一定能征服面试官。</span></p> <p><span style="font-size: 15px;"> 3 可以看下静态代理和动态代理的实现方式,再深入一下,可以看下Spring AOP里的实现代码。</span></p> <p><span style="font-size: 15px;"> 4 或许Spirng IOC和MVC的底层实现代码比较难看懂,但大家可以说些关键的类,根据关键流程说下它们的实现方式。 </span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">其实准备的底层代码未必要多,而且也不限于在哪个方面,比如集合里基于红黑树的TreeSet,基于NIO的开源框架,甚至分布式组件的Dubbo,都可以准备。而且准备时未必要背出所有的底层(事实上很难做到),你只要能结合一些重要的类和方法,讲清楚思路即可(比如讲清楚HashMap如何通过hashCode快速定位)。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">那么在面试时,如何找到个好机会说出你准备好的上述底层代码?在面试时,总会被问到集合,Spring MVC框架等相关知识点,你在回答时,顺便说一句,“我还了解这块的底层实现”,那么面试官一定会追问,那么你就可以说出来了。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">不要小看这个对候选人的帮助,一旦你讲了,只要意思到位,那么最少能得到个“肯积极专业“的评价,如果描述很清楚,那么评价就会升级到“熟悉Java核心技能(或Spring MVC),且基本功扎实”。要知道,面试中,很少有人能讲清楚底层代码,所以你抛出了这个话题,哪怕最后没达到预期效果,面试官也不会由此对你降低评价。所以说,准备这块绝对是“有百利而无一害”的挣钱买卖。</span></p> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section data-width="100%" style="width: 558px;box-sizing: border-box;background-image: -webkit-linear-gradient(left, rgb(51, 116, 163), rgba(255, 247, 234, 0));background-attachment: initial;background-color: rgb(162, 215, 196);background-size: initial;background-origin: initial;background-clip: initial;background-position: initial;background-repeat: initial;"> <section style="box-sizing: border-box;"> <section style="margin-top: 20px;margin-bottom: 20px;box-sizing: border-box;"> <section data-width="100%" style="padding: 10px;display: inline-block;width: 558px;border-width: 0px 0px 0px 10px;border-style: solid;border-left-color: rgb(240, 112, 153);border-right-color: rgb(240, 112, 153);box-shadow: rgb(0, 0, 0) 0px 0px 0px;box-sizing: border-box;"> <section style="box-sizing: border-box;"> <span style="color: rgb(255, 255, 255);font-size: 16px;"><strong><span style="color: rgb(255, 255, 255);line-height: 24px;">7 一切的一切,把上述技能嵌入到你做过的项目里</span></strong></span> </section> </section> </section> </section> </section> </section> </section> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;color: rgb(62, 62, 62);"></section> <p><span style="font-size: 15px;line-height: 1.6;">在面试过程中,我经常会听到一些比较遗憾的回答,比如候选人对SQL优化技能讲得头头是道,但最后得知,这是他平时自学时掌握的,并没用在实际项目里。</span><br></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">当然这总比不说要好,所以我会写下“在平时自学过SQL优化技能”,但如果在项目里实践过,那么我就会写下“有实际数据库SQL优化的技能”。大家可以对比下两者的差别,一个是偏重理论,一个是直接能干活了。其实,很多场景里,我就不信在实际项目里一定没有实践过SQL优化技能。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">从这个案例中,我想告诉大家的是,你之前费了千辛万苦(其实方法方向得到,也不用费太大精力)准备的很多技能和说辞,最后应该落实到你的实际项目里。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">比如你有过在Linux日志里查询关键字排查问题的经验,在描述时你可以带一句,在之前的项目里我就这样干的。又如,你通过看底层代码,了解了TreeSet和HashSet的差别以及它们的适用范围,那么你就可以回想下你之前做的项目,是否有个场景仅仅适用于TreeSet?如果有,那么你就可以适当描述下项目的需求,然后说,通过读底层代码,我了解了两者的差别,而且在这个实际需求里,我就用了TreeSet,而且我还专门做了对比性试验,发现用TreeSet比HashSet要高xx个百分点。</span></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">请记得,“实践经验”一定比“理论经验”值钱,而且大多数你知道的理论上的经验,一定在你的项目里用过。所以,如果你仅仅让面试官感觉你只有“理论经验”,那就太亏了。</span></p> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section data-width="100%" style="width: 558px;box-sizing: border-box;background-image: -webkit-linear-gradient(left, rgb(51, 116, 163), rgba(255, 247, 234, 0));background-attachment: initial;background-color: rgb(162, 215, 196);background-size: initial;background-origin: initial;background-clip: initial;background-position: initial;background-repeat: initial;"> <section style="box-sizing: border-box;"> <section style="margin-top: 20px;margin-bottom: 20px;box-sizing: border-box;"> <section data-width="100%" style="padding: 10px;display: inline-block;width: 558px;border-width: 0px 0px 0px 10px;border-style: solid;border-left-color: rgb(240, 112, 153);border-right-color: rgb(240, 112, 153);box-shadow: rgb(0, 0, 0) 0px 0px 0px;box-sizing: border-box;"> <section style="box-sizing: border-box;"> <span style="color: rgb(255, 255, 255);font-size: 16px;"><strong><span style="color: rgb(255, 255, 255);line-height: 24px;">8 小结:本文更多讲述的准备面试的方法</span></strong></span> </section> </section> </section> </section> </section> </section> </section> <section class="_editor" style="font-size: 16px;line-height: 25.6px;white-space: normal;color: rgb(62, 62, 62);"></section> <p><span style="font-size: 15px;line-height: 1.6;">本文给出的面试题并不多,但本文并没有打算给出太多的面试题。从本文里,大家更多看到的是面试官发现的诸多候选人的痛点。</span><br></p> <p><span style="font-size: 15px;"> </span></p> <p><span style="font-size: 15px;">本文的用意是让大家别再重蹈别人的覆辙,这还不算,本文还给出了不少准备面试的方法。你的能力或许比别人出众,但如果你准备面试的方式和别人差不多,或者就拿你在项目里干的活来说事,而没有归纳出你在项目中的亮点,那么面试官还真的会看扁你。</span></p> <p><br></p> <blockquote> <p><span style="font-size: 14px;">来源:https://www.cnblogs.com/</span></p> <p><span style="font-size: 14px;">JavaArchitect/p/10011253.html</span></p> </blockquote> <section> <mpcps frameborder="0" class="js_editor_cps" data-datakey="1543237074459_0.5534070121612307" style="width:100% !important;border:0;" data-uid="1543237074489" data-type="1" data-product="" data-templateid="list" data-pid="12136095" data-packid="" data-smartnum="" data-color="#fa7834" data-categoryid="3" data-appid="wxbdbc4659744ed70d" data-report="s0%3D3%26s1%3D0%26s2%3D0%26s3%3DJava%2BWeb%25E8%25BD%25BB%25E9%2587%258F%25E7%25BA%25A7%25E5%25BC%2580%25E5%258F%2591%25E9%259D%25A2%25E8%25AF%2595%25E6%2595%2599%25E7%25A8%258B%26s4%3D0%26s5%3D10%26pid%3Dwxbdbc4659744ed70d_12136095%26uuid%3D3084760457394535811%26title%3DJava%2BWeb%25E8%25BD%25BB%25E9%2587%258F%25E7%25BA%25A7%25E5%25BC%2580%25E5%258F%2591%25E9%259D%25A2%25E8%25AF%2595%25E6%2595%2599%25E7%25A8%258B%26sid%3D1%26cid%3D3%26ratio%3D16.00%2525%26price%3D65.90%26"></mpcps> </section> <section> <mpcps frameborder="0" class="js_editor_cps" data-datakey="1543237074460_0.9650986816760927" style="width:100% !important;border:0;" data-uid="1543237074490" data-type="1" data-product="" data-templateid="list" data-pid="12421187" data-packid="" data-smartnum="" data-color="#fa7834" data-categoryid="3" data-appid="wxbdbc4659744ed70d" data-report="s0%3D3%26s1%3D0%26s2%3D0%26s3%3DJava%25E6%25A0%25B8%25E5%25BF%2583%25E6%258A%2580%25E6%259C%25AF%25E5%258F%258A%25E9%259D%25A2%25E8%25AF%2595%25E6%258C%2587%25E5%258D%2597%26s4%3D0%26s5%3D10%26pid%3Dwxbdbc4659744ed70d_12421187%26uuid%3D30847604571012925282%26title%3DJava%25E6%25A0%25B8%25E5%25BF%2583%25E6%258A%2580%25E6%259C%25AF%25E5%258F%258A%25E9%259D%25A2%25E8%25AF%2595%25E6%258C%2587%25E5%258D%2597%26sid%3D1%26cid%3D3%26ratio%3D16.00%2525%26price%3D43.00%26"></mpcps> </section> <p style="text-align: center;"><img class="" data-copyright="0" data-ratio="0.5555555555555556" data-s="300,640" src="/upload/37af8b01bf35a7fd4e8ca81af9df2437.png" data-type="png" data-w="900" style=""></p>
作者:微信小助手
<p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: center;" data-mpa-powered-by="yiban.io"><img class="" data-copyright="0" data-ratio="0.5625" data-s="300,640" src="/upload/9161ac3753105145cb8a5e0cf5042378.jpg" data-type="jpeg" data-w="1280" style="width: 68%;height: auto !important;"></p> <p style="margin-left: 16px;margin-right: 16px;text-align: center;line-height: normal;"><span style="letter-spacing: normal;color: rgb(178, 178, 178);font-size: 12px;">作者:孤独烟</span></p> <p style="margin-left: 16px;margin-right: 16px;text-align: center;line-height: normal;"><span style="letter-spacing: normal;color: rgb(178, 178, 178);font-size: 12px;">来源:http://rjzheng.cnblogs.com/</span></p> <p><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">绝大部分写业务的程序员,在实际开发中使用 Redis 的时候,只会 Set Value 和 Get Value 两个操作,对 Redis 整体缺乏一个认知。这里对<strong> Redis 常见问题做一个总结,解决大家的知识盲点。</strong></span></p> <p><br></p> <section class=""> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <h1 style="margin-left: 16px;margin-right: 16px;"><strong><em><span style="letter-spacing: 1px;color: rgb(255, 169, 0);font-size: 18px;">1、</span></em></strong><span style="color: rgb(255, 169, 0);"><strong><span style="font-size: 17px;">为什么使用 Redis</span></strong></span></h1> </section> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">在项目中使用 Redis,主要考虑两个角度:性能和并发。</span></strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">如果只是为了分布式锁这些其他功能,还有其他中间件 ZooKpeer 等代替,并非一定要使用 Redis。</span></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <h1 style="margin-right: 16px;margin-left: 16px;white-space: normal;"><span style="color: rgb(255, 169, 0);"><strong><span style="font-size: 17px;"><br></span></strong></span></h1> <h1 style="margin-right: 16px;margin-left: 16px;white-space: normal;"><span style="color: rgb(217, 33, 66);font-size: 14px;letter-spacing: 1px;"><strong>性能:</strong></span></h1> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">如下图所示,我们在碰到需要执行耗时特别久,且结果不频繁变动的 SQL,就特别适合将运行结果放入缓存。这样,后面的请求就去缓存中读取,使得请求能够迅速响应。</span></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><img class="" data-copyright="0" data-ratio="0.38729763387297633" data-s="300,640" src="/upload/9fa632d18ceb6741f210edeaf2386676.null" data-type="png" data-w="803" style=""></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">根据交互效果的不同,响应时间没有固定标准。在理想状态下,我们的页面跳转需要在瞬间解决,对于页内操作则需要在刹那间解决。</span></p> <p style="line-height: normal;"><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <h1 style="margin-right: 16px;margin-left: 16px;white-space: normal;"><span style="color: rgb(217, 33, 66);font-size: 14px;letter-spacing: 1px;"><strong>并发:</strong></span></h1> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">如下图所示,在大并发的情况下,所有的请求直接访问数据库,数据库会出现连接异常。这个时候,就需要使用 Redis 做一个缓冲操作,让请求先访问到 Redis,而不是直接访问数据库。</span></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><img class="" data-copyright="0" data-ratio="0.5846994535519126" data-s="300,640" src="/upload/a43e9b6c63f39553b7f835da0b1c7bc9.null" data-type="png" data-w="732" style=""></p> <section class=""> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <h1 style="margin-right: 16px;margin-left: 16px;white-space: normal;"><span style="font-size: 14px;color: rgb(217, 33, 66);"><strong>使用 Redis 的常见问题</strong></span></h1> </section> </section> </section> </section> </section> <ul class=" list-paddingleft-2" style="list-style-type: disc;margin-left: 16px;margin-right: 16px;"> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">缓存和数据库双写一致性问题</span></p></li> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">缓存雪崩问题</span></p></li> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">缓存击穿问题</span></p></li> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">缓存的并发竞争问题</span></p></li> </ul> <p><br></p> <section class=""> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <h1 style="margin-right: 16px;margin-left: 16px;white-space: normal;"><strong><em><span style="letter-spacing: 1px;color: rgb(255, 169, 0);font-size: 18px;">2、</span></em></strong><span style="color: rgb(255, 169, 0);"><strong><span style="font-size: 17px;">单线程的 Redis 为什么这么快</span></strong></span></h1> </section> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">这个问题是对 Redis 内部机制的一个考察。很多人都不知道 Redis 是单线程工作模型。</span></p> <p style="line-height: normal;"><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><strong><span style="font-size: 14px;letter-spacing: 1px;color: rgb(217, 33, 66);">原因主要是以下三点:</span></strong></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;margin-left: 16px;margin-right: 16px;"> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">纯内存操作</span></p></li> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">单线程操作,避免了频繁的上下文切换</span></p></li> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">采用了非阻塞 I/O 多路复用机制</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">仔细说一说 I/O 多路复用机制,打一个比方:小曲在 S 城开了一家快递店,负责同城快送服务。小曲因为资金限制,雇佣了一批快递员,然后小曲发现资金不够了,只够买一辆车送快递。</span></p> <p style="line-height: normal;"><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="font-size: 14px;letter-spacing: 1px;">经营方式一</span></strong></span></p> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">客户每送来一份快递,小曲就让一个快递员盯着,然后快递员开车去送快递。慢慢的小曲就发现了这种经营方式存在下述问题:</span></p> <ul class=" list-paddingleft-2" style="margin-left: 16px;margin-right: 16px;"> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">时间都花在了抢车上了,大部分快递员都处在闲置状态,抢到车才能去送快递。</span></p></li> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">随着快递的增多,快递员也越来越多,小曲发现快递店里越来越挤,没办法雇佣新的快递员了。</span></p></li> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">快递员之间的协调很花时间。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">综合上述缺点,小曲痛定思痛,提出了经营方式二。</span></p> <p><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><strong><span style="font-size: 14px;letter-spacing: 1px;color: rgb(217, 33, 66);">经营方式二</span></strong></p> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">小曲只雇佣一个快递员。当客户送来快递,小曲按送达地点标注好,依次放在一个地方。最后,让快递员依次去取快递,一次拿一个,再开着车去送快递,送好了就回来拿下一个快递。上述两种经营方式对比,很明显第二种效率更高。</span></p> <p style="margin-left: 16px;margin-right: 16px;text-align: justify;line-height: normal;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;"><br></span></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="font-size: 14px;letter-spacing: 1px;">在上述比喻中:</span></strong></span></p> <ul class=" list-paddingleft-2" style="margin-left: 16px;margin-right: 16px;"> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">每个快递员→每个线程</span></p></li> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">每个快递→每个 Socket(I/O 流)</span></p></li> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">快递的送达地点→Socket 的不同状态</span></p></li> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">客户送快递请求→来自客户端的请求</span></p></li> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">小曲的经营方式→服务端运行的代码</span></p></li> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">一辆车→CPU 的核数</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="font-size: 14px;letter-spacing: 1px;">于是有了如下结论:</span></strong></span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;margin-left: 16px;margin-right: 16px;"> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">经营方式一就是传统的并发模型,每个 I/O 流(快递)都有一个新的线程(快递员)管理。</span></p></li> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">经营方式二就是 I/O 多路复用。只有单个线程(一个快递员),通过跟踪每个 I/O 流的状态(每个快递的送达地点),来管理多个 I/O 流。</span></p></li> </ul> <p><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">下面类比到真实的 Redis 线程模型,如图所示:</span></strong></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><img class="" data-copyright="0" data-ratio="0.40976645435244163" data-s="300,640" src="/upload/a0dfb8541d708983439d7cbf1144b962.null" data-type="png" data-w="942" style=""></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">Redis-client 在操作的时候,会产生具有不同事件类型的 Socket。在服务端,有一段 I/O 多路复用程序,将其置入队列之中。然后,文件事件分派器,依次去队列中取,转发到不同的事件处理器中。</span></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><br></p> <section class=""> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <h1 style="margin-right: 16px;margin-left: 16px;white-space: normal;"><strong><em><span style="letter-spacing: 1px;color: rgb(255, 169, 0);font-size: 18px;">3、</span></em></strong><span style="color: rgb(255, 169, 0);"><strong><span style="font-size: 17px;">Redis 的数据类型及使用场景</span></strong></span></h1> </section> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">一个合格的程序员,这五种类型都会用到。</span></p> <p style="line-height: normal;"><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="color: rgb(217, 33, 66);font-size: 14px;letter-spacing: 1px;">String</span></strong></span></p> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">最常规的 set/get 操作,Value 可以是 String 也可以是数字。一般做一些复杂的计数功能的缓存。</span></p> <p style="line-height: normal;"><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="color: rgb(217, 33, 66);font-size: 14px;letter-spacing: 1px;">Hash</span></strong></span></p> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">这里 Value 存放的是结构化的对象,比较方便的就是操作其中的某个字段。我在做单点登录的时候,就是用这种数据结构存储用户信息,以 CookieId 作为 Key,设置 30 分钟为缓存过期时间,能很好的模拟出类似 Session 的效果。</span></p> <p><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="color: rgb(217, 33, 66);font-size: 14px;letter-spacing: 1px;">List</span></strong></span></p> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">使用 List 的数据结构,可以做简单的消息队列的功能。另外,可以利用 lrange 命令,做基于 Redis 的分页功能,性能极佳,用户体验好。</span></p> <p><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="font-size: 14px;letter-spacing: 1px;">Set</span></strong></span></p> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">因为 Set 堆放的是一堆不重复值的集合。所以可以做全局去重的功能。我们的系统一般都是集群部署,使用 JVM 自带的 Set 比较麻烦。另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。</span></p> <p><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="font-size: 14px;letter-spacing: 1px;">Sorted Set</span></strong></span></p> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">Sorted Set 多了一个权重参数 Score,集合中的元素能够按 Score 进行排列。可以做排行榜应用,取 TOP N 操作。Sorted Set 可以用来做延时任务。</span></p> <section class=""> <p><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <h1 style="margin-right: 16px;margin-left: 16px;white-space: normal;"><strong><em><span style="letter-spacing: 1px;color: rgb(255, 169, 0);font-size: 18px;">4、</span></em></strong><span style="color: rgb(255, 169, 0);"><strong><span style="font-size: 17px;">Redis 的过期策略和内存淘汰机制</span></strong></span></h1> </section> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">Redis 是否用到家,从这就能看出来。比如你 Redis 只能存 5G 数据,可是你写了 10G,那会删 5G 的数据。<strong>怎么删的,这个问题思考过么?</strong></span></p> <p style="line-height: normal;"><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">正解:Redis 采用的是定期删除+惰性删除策略。</span></strong></p> <p><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="font-size: 14px;letter-spacing: 1px;">为什么不用定时删除策略</span></strong></span></p> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">定时删除,用一个定时器来负责监视 Key,过期则自动删除。虽然内存及时释放,但是十分消耗 CPU 资源。在大并发请求下,CPU 要将时间应用在处理请求,而不是删除 Key,因此没有采用这一策略。</span></p> <p><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><strong><span style="font-size: 14px;letter-spacing: 1px;color: rgb(217, 33, 66);">定期删除+惰性删除如何工作</span></strong></p> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">定期删除,Redis 默认每个 100ms 检查,有过期 Key 则删除。需要说明的是,Redis 不是每个 100ms 将所有的 Key 检查一次,而是随机抽取进行检查。如果只采用定期删除策略,会导致很多 Key 到时间没有删除。于是,惰性删除派上用场。</span></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;"><br></span></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="color: rgb(217, 33, 66);font-size: 14px;letter-spacing: 1px;">采用定期删除+惰性删除就没其他问题了么</span></strong></span></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">不是的,如果定期删除没删除掉 Key。并且你也没及时去请求 Key,也就是说惰性删除也没生效。<strong>这样,Redis 的内存会越来越高。那么就应该采用内存淘汰机制。</strong></span></p> <p><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="font-size: 14px;letter-spacing: 1px;">在 redis.conf 中有一行配置:</span></strong></span></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <section class=""> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;"># maxmemory-policy volatile-lru</span></p> </section> </section> </section> </section> </section> </section> </section> </section> <p style="line-height: normal;"><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">该配置就是配内存淘汰策略的:</span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;margin-left: 16px;margin-right: 16px;"> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">noeviction:</span></strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">当内存不足以容纳新写入数据时,新写入操作会报错。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">allkeys-lru:</span></strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 Key。</span><span style="letter-spacing: 1px;font-size: 13px;color: rgb(136, 136, 136);">(<span style="font-size: 13px;letter-spacing: 1px;text-align: justify;">推荐使用,目前项目在用这种</span>)</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">allkeys-random:</span></strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">当内存不足以容纳新写入数据时,在键空间中,随机移除某个 Key。</span><span style="letter-spacing: 1px;color: rgb(136, 136, 136);font-size: 13px;">(<span style="color: rgb(136, 136, 136);letter-spacing: 1px;text-align: justify;">应该也没人用吧,你不删最少使用 Key,去随机删</span>)</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">volatile-lru:</span></strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 Key。这种情况一般是把 Redis 既当缓存,又做持久化存储的时候才用。</span><span style="letter-spacing: 1px;color: rgb(136, 136, 136);font-size: 13px;">(<span style="color: rgb(136, 136, 136);letter-spacing: 1px;text-align: justify;">不推荐</span>)</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">volatile-random:</span></strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个 Key。</span><span style="letter-spacing: 1px;color: rgb(136, 136, 136);font-size: 13px;">(<span style="color: rgb(136, 136, 136);letter-spacing: 1px;text-align: justify;">依然不推荐</span>)</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">volatile-ttl:</span></strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的 Key 优先移除。<span style="color: rgb(136, 136, 136);font-size: 13px;letter-spacing: 1px;text-align: justify;">(不推荐)</span></span></p></li> </ul> <h3></h3> <section class=""> <p><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <h1 style="margin-right: 16px;margin-left: 16px;white-space: normal;"><strong><em><span style="letter-spacing: 1px;color: rgb(255, 169, 0);font-size: 18px;">5、</span></em></strong><span style="color: rgb(255, 169, 0);"><strong><span style="font-size: 17px;">Redis 和数据库双写一致性问题</span></strong></span></h1> <p style="margin-left: 16px;margin-right: 16px;text-align: justify;line-height: normal;"><br></p> </section> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">一致性问题还可以再分为最终一致性和强一致性。</span></strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">数据库和缓存双写,就必然会存在不一致的问题。前提是如果对数据有强一致性要求,不能放缓存。我们所做的一切,只能保证最终一致性。</span></p> <p><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">另外,我们所做的方案从根本上来说,只能降低不一致发生的概率</span></strong><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">。因此,有强一致性要求的数据,不能放缓存。首先,采取正确更新策略,先更新数据库,再删缓存。其次,因为可能存在删除缓存失败的问题,提供一个补偿措施即可,例如利用消息队列。</span></p> <p><br></p> <section class=""> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <h1 style="margin-right: 16px;margin-left: 16px;white-space: normal;"><span style="letter-spacing: 1px;"><strong><em><span style="color: rgb(255, 169, 0);font-size: 18px;">6、</span></em></strong><span style="color: rgb(255, 169, 0);"><strong><span style="font-size: 17px;">如何应对缓存穿透和缓存雪崩问题</span></strong></span></span></h1> <p style="margin-left: 16px;margin-right: 16px;text-align: justify;line-height: normal;"><br></p> </section> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">这两个问题,一般中小型传统软件企业很难碰到。如果有大并发的项目,流量有几百万左右,这两个问题一定要深刻考虑。缓存穿透,即黑客故意去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而数据库连接异常。</span></p> <p style="line-height: normal;"><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="font-size: 14px;letter-spacing: 1px;">缓存穿透解决方案:</span></strong></span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;margin-left: 16px;margin-right: 16px;"> <li><p style="text-align: justify;line-height: 1.75em;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">采用异步更新策略,无论 Key 是否取到值,都直接返回。Value 值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)操作。</span></p></li> <li><p style="text-align: justify;line-height: 1.75em;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">提供一个能迅速判断请求是否有效的拦截机制,比如,利用布隆过滤器,内部维护一系列合法有效的 Key。迅速判断出,请求所携带的 Key 是否合法有效。如果不合法,则直接返回。</span></p></li> </ul> <p style="line-height: normal;"><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">缓存雪崩,即缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而导致数据库连接异常。</span></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;"><br></span></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="font-size: 14px;letter-spacing: 1px;">缓存雪崩解决方案:</span></strong></span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;margin-left: 16px;margin-right: 16px;"> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">给缓存的失效时间,加上一个随机值,避免集体失效。</span></p></li> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">使用互斥锁,但是该方案吞吐量明显下降了。</span></p></li> <li><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">双缓存。我们有两个缓存,缓存 A 和缓存 B。缓存 A 的失效时间为 20 分钟,缓存 B 不设失效时间。自己做缓存预热操作。</span></p><p style="line-height: 1.5em;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">然后细分以下几个小点:从缓存 A 读数据库,有则直接返回;A 没有数据,直接从 B 读数据,直接返回,并且异步启动一个更新线程,更新线程同时更新缓存 A 和缓存 B。</span></p></li> </ul> <h3></h3> <section class=""> <p><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <h1 style="margin-right: 16px;margin-left: 16px;white-space: normal;"><strong><em><span style="letter-spacing: 1px;color: rgb(255, 169, 0);font-size: 18px;">7、</span></em></strong><span style="color: rgb(255, 169, 0);"><strong><span style="font-size: 17px;">如何解决 Redis 的并发竞争 Key 问题</span></strong></span></h1> <p style="margin-left: 16px;margin-right: 16px;text-align: justify;line-height: normal;"><br></p> </section> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">这个问题大致就是,同时有多个子系统去 Set 一个 Key。这个时候要注意什么呢?大家基本都是推荐用 Redis 事务机制。</span></p> <p style="line-height: normal;"><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">但是我并不推荐使用 Redis 的事务机制。<strong>因为我们的生产环境,基本都是 Redis 集群环境,做了数据分片操作。</strong>你一个事务中有涉及到多个 Key 操作的时候,这多个 Key 不一定都存储在同一个 redis-server 上。因此,Redis 的事务机制,十分鸡肋。</span></p> <p><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="font-size: 14px;letter-spacing: 1px;">如果对这个 Key 操作,不要求顺序</span></strong></span></p> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">这种情况下,准备一个分布式锁,大家去抢锁,抢到锁就做 set 操作即可,比较简单。</span></p> <p><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="font-size: 14px;letter-spacing: 1px;">如果对这个 Key 操作,要求顺序</span></strong></span></p> </section> </section> </section> </section> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">假设有一个 key1,系统 A 需要将 key1 设置为 valueA,系统 B 需要将 key1 设置为 valueB,系统 C 需要将 key1 设置为 valueC。</span></p> <p><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">期望按照 key1 的 value 值按照 valueA > valueB > valueC 的顺序变化。这种时候我们在数据写入数据库的时候,需要保存一个时间戳。</span></p> <p><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);"><strong><span style="font-size: 14px;letter-spacing: 1px;">假设时间戳如下:</span></strong></span></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <section class=""> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">系统 A key 1 {valueA 3:00}<br style="box-sizing: border-box;">系统 B key 1 {valueB 3:05}<br style="box-sizing: border-box;">系统 C key 1 {valueC 3:10}</span></p> </section> </section> </section> </section> </section> </section> </section> </section> <p><br></p> <p style="line-height: 1.5em;margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;">那么,假设系统 B 先抢到锁,将 key1 设置为{valueB 3:05}。接下来系统 A 抢到锁,发现自己的 valueA 的时间戳早于缓存中的时间戳,那就不做 set 操作了,以此类推。其他方法,比如利用队列,将 set 方法变成串行访问也可以。</span></p> <section class=""> <p><br></p> <section> <section class="Powered-by-XIUMI V5" powered-by="xiumi.us"> <section class=""> <section class=""> <h1 style="margin-right: 16px;margin-left: 16px;white-space: normal;"><strong><span style="font-style: italic;letter-spacing: 1px;color: rgb(255, 169, 0);font-size: 18px;">8、</span><span style="color: rgb(255, 169, 0);font-size: 17px;">总结</span></strong></h1> </section> </section> </section> </section> </section> <p style="color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;letter-spacing: 0.544px;text-align: justify;white-space: normal;background-color: rgb(255, 255, 255);margin-left: 16px;margin-right: 16px;line-height: 1.5em;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif;">Redis 在国内各大公司都能看到其身影</span><span style="font-size: 14px;letter-spacing: 1px;color: rgb(86, 86, 86);font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif;">,比如我们熟悉的</span><span style="font-size: 14px;letter-spacing: 1px;font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif;color: rgb(217, 33, 66);"><strong>新浪,阿里,腾讯,百度,美团,小米等</strong></span><span style="font-size: 14px;letter-spacing: 1px;color: rgb(86, 86, 86);font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif;">。</span><strong style="letter-spacing: 0.544px;font-size: 14px;"><span style="font-family: "Helvetica Neue", Helvetica;letter-spacing: 1px;color: rgb(86, 86, 86);">学习 Redis,这几方面尤其重要</span></strong><span style="font-size: 14px;font-family: "Helvetica Neue", Helvetica;letter-spacing: 1px;color: rgb(86, 86, 86);">:</span><span style="font-size: 14px;font-family: "Helvetica Neue", Helvetica;letter-spacing: 1px;color: rgb(102, 102, 102);">Redis 客户端、Redis 高级功能、Redis 持久化和开发运维常用问题探讨、Redis 复制的原理和优化策略、Redis 分布式解决方案等。</span></p> <p style="color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;letter-spacing: 0.544px;text-align: justify;white-space: normal;background-color: rgb(255, 255, 255);margin-left: 16px;margin-right: 16px;line-height: normal;"><span style="font-family: "Helvetica Neue", Helvetica;letter-spacing: 1px;color: rgb(102, 102, 102);font-size: 14px;"><br></span></p> <p style="color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;letter-spacing: 0.544px;text-align: justify;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.5em;margin-left: 16px;margin-right: 16px;"><span style="font-size: 14px;"><strong><span style="font-size: 14px;font-family: "Helvetica Neue", Helvetica;letter-spacing: 1px;color: rgb(102, 102, 102);">想要系统而全面的剖析 Redis 的应用,入门课程必不可少——</span></strong></span></p> <p style="color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;line-height: 1.5em;margin-left: 16px;margin-right: 16px;"><span style="color: rgb(255, 169, 0);font-size: 14px;"><strong><span style="color: rgb(255, 169, 0);font-size: 14px;font-family: "Helvetica Neue", Helvetica;letter-spacing: 1px;">《Redis 入门到分布式实践》</span></strong></span></p> <p style="color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 17px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;line-height: 1.5em;margin-left: 16px;margin-right: 16px;"><img class="" data-ratio="1" data-w="64" src="/upload/29316807de8eec165a101cfe6173a39c.null" style="max-height: 20px !important;width: 20px !important;visibility: visible !important;"></p> <p style="text-align: center;margin-left: 16px;margin-right: 16px;"><img class="" data-copyright="0" data-ratio="1.7777777777777777" data-s="300,640" src="/upload/333fa4319880a5b737c8de2cbb6f9762.jpg" data-type="jpeg" data-w="720" style=""></p> <p style="text-align: justify;margin-left: 16px;margin-right: 16px;line-height: normal;"><span style="color: rgb(86, 86, 86);letter-spacing: 1px;font-size: 14px;"><br></span></p> <p style="margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;text-align: justify;">本文对 Redis 的常见问题做了一个总结。大部分是自己在工作中遇到,以及之前面试别人的时候,爱问的一些问题。另外,不推荐大家临时抱佛脚,真正碰到一些有经验的工程师,几下就能把你问懵。</span></p> <p style="margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;text-align: justify;"><br></span></p> <p style="margin-left: 16px;margin-right: 16px;text-align: center;"><strong><span style="font-size: 14px;letter-spacing: 1px;text-align: justify;color: rgb(255, 169, 0);">#今日大奖评论#</span></strong></p> <p style="margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);letter-spacing: 1px;text-align: justify;font-size: 13px;">关于 Redis 你还有什么想要了解?欢迎来留言讨论,我们将会在评论中筛选出优质回答送出一个月的<strong> GitChat 精英会员奖励</strong>!!</span></p> <p style="margin-left: 16px;margin-right: 16px;text-align: justify;line-height: normal;"><span style="color: rgb(86, 86, 86);letter-spacing: 1px;text-align: justify;font-size: 13px;"><br></span></p> <p style="margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(217, 33, 66);font-size: 13px;"><strong><span style="color: rgb(217, 33, 66);font-size: 13px;letter-spacing: 1px;text-align: justify;">精英会员权益:</span></strong></span></p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="margin-left: 16px;margin-right: 16px;"><span style="font-size: 13px;color: rgb(136, 136, 136);">全场 Chat 免费订</span></p></li> <li><p style="margin-left: 16px;margin-right: 16px;"><span style="font-size: 13px;color: rgb(136, 136, 136);">每月免费学习 2 门达人课</span></p></li> <li><p style="margin-left: 16px;margin-right: 16px;"><span style="font-size: 13px;color: rgb(136, 136, 136);">全站文章和实录免费下载、阅读</span></p></li> <li><p style="margin-left: 16px;margin-right: 16px;"><span style="font-size: 13px;color: rgb(136, 136, 136);">进入上百位专家的读者圈,无限互动与追问</span></p></li> </ul> <p style="margin-left: 16px;margin-right: 16px;text-align: justify;line-height: normal;"><span style="color:#565656;"><span style="font-size: 14px;letter-spacing: 1px;"><br></span></span></p> <p style="margin-left: 16px;margin-right: 16px;text-align: justify;"><strong><span style="color:#565656;"><span style="font-size: 14px;letter-spacing: 1px;">赶快来留言,说不定获得精英会员的就是你!!</span></span></strong></p> <p style="margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;text-align: justify;"><br></span></p> <p style="margin-left: 16px;margin-right: 16px;text-align: justify;"><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;text-align: justify;">对<span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;text-align: justify;"> Redis </span>感兴趣的同学,也可点击 </span><span style="font-size: 14px;letter-spacing: 1px;text-align: justify;color: rgb(217, 33, 66);"><strong>阅读原文</strong></span><span style="color: rgb(86, 86, 86);font-size: 14px;letter-spacing: 1px;text-align: justify;">,试读了解。</span></p>
作者:微信小助手
<p style="white-space: normal;text-align: center;"><span style="color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;font-size: 14px;letter-spacing: 0.544px;">点击蓝色“</span><span style="font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;font-size: 14px;letter-spacing: 0.544px;color: rgb(0, 128, 255);">程序猿DD</span><span style="color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;font-size: 14px;letter-spacing: 0.544px;">”关注我</span></p> <p style="white-space: normal;text-align: center;"><span style="color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;font-size: 14px;letter-spacing: 0.544px;">回复“</span><span style="font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;font-size: 14px;letter-spacing: 0.544px;color: rgb(0, 128, 255);">资源</span><span style="color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;font-size: 14px;letter-spacing: 0.544px;">”获取独家整理的学习资料!</span></p> <p style="white-space: normal;text-align: center;"><span style="color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;font-size: 14px;letter-spacing: 0.544px;">来源:</span><span style="color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;font-size: 12px;max-width: 100% !important;box-sizing: border-box !important;overflow-wrap: break-word !important;">cnblogs.com/peng104/p/10296717.html</span></p> <h2 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.2em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;color: rgb(21, 153, 87);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(0, 0, 0);"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">1、引言</span></strong></span></h2> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;color: rgb(21, 153, 87);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">1.1 Docker是什么</span></h3> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">Docker 最初是 dotCloud 公司创始人 Solomon Hykes 在法国期间发起的一个公司内部项目,于 2013 年 3 月以 Apache 2.0 授权协议开源,主要项目代码在 GitHub 上进行维护。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">Docker 使用 Google 公司推出的 Go 语言 进行开发实现。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">docker是linux容器的一种封装,提供简单易用的容器使用接口。它是最流行的Linux容器解决方案。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">docker的接口相当简单,用户可以方便的创建、销毁容器。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">docker将应用程序与程序的依赖,打包在一个文件里面。运行这个文件就会生成一个虚拟容器。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">程序运行在虚拟容器里,如同在真实物理机上运行一样,有了docker,就不用担心环境问题了。</p> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;color: rgb(21, 153, 87);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">1.2 应用场景</span></h3> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">web应用的自动化打包和发布</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">自动化测试和持续集成、发布</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">在服务型环境中部署和调整数据库或其他应用</p> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;color: rgb(21, 153, 87);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">1.3 区别</span></h3> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">1、物理机</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="" data-ratio="0.48383084577114427" src="/upload/3e0d0d2fa30a68eceee1ad4d0a2117fc.png" data-type="png" data-w="804" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">2、虚拟机</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="" data-ratio="0.44569288389513106" src="/upload/6e0230a918fc13fd438d0fae3f008951.png" data-type="png" data-w="801" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">3、docker容器</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="" data-ratio="0.42431466030989273" src="/upload/2ada32e1f60baee91925b56c92f0aec4.png" data-type="png" data-w="839" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 677px !important;visibility: visible !important;"></p> <h3 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.1em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;color: rgb(21, 153, 87);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;line-height: inherit;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">1.4 Docker的三大概念及优势</span></h3> <ul class=" list-paddingleft-2" style="list-style-type: square;"> <li><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">镜像 image</span></p></li> <li><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">容器 container</span></p></li> <li><p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;">仓库 repository</span></p></li> </ul> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 17px;box-sizing: border-box !important;overflow-wrap: break-word !important;">docker容器的优势</span></strong></span></p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;color: inherit;font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">1、更高效的利用系统资源</strong></p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">由于容器不需要进行硬件虚拟以及运行完整操作系统等额外开销,Docker 对系统 资源的利用率更高。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">无论是应用执行速度、内存损耗或者文件存储速度,都要比传 统虚拟机技术更高效。因此,相比虚拟机技术,一个相同配置的主机,往往可以运 行更多数量的应用。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;color: inherit;font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">2、更快速的启动时间</strong></p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接 运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启 动时间。大大的节约了开发、测试、部署的时间。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;color: inherit;font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">3、一致的运行环境</strong></p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环 境不一致,导致有些 bug 并未在开发过程中被发现。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">而 Docker 的镜像提供了除内 核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 “这段代码 在我机器上没问题啊” 这类问题。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;color: inherit;font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">4、持续交付和部署</strong></p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">对开发和运维(DevOps)人员来说,最希望的就是一次创建或配置,可以在任意 地方正常运行。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">使用 Docker 可以通过定制应用镜像来实现持续集成、持续交付、部署。开发人员 可以通过 Dockerfile 来进行镜像构建,并结合持续集成(Continuous Integration) 系 统进行集成测试,而运维人员则可以直接在生产环境中快速部署该镜像,甚至结合 持续部署(Continuous Delivery/Deployment) 系统进行自动部署。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">而且使用 Dockerfile 使镜像构建透明化,不仅仅开发团队可以理解应用运行环 境,也方便运维团队理解应用运行所需条件,帮助更好的生产环境中部署该镜像。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;color: inherit;font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">5、更轻松的迁移</strong></p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">由于 Docker 确保了执行环境的一致性,使得应用的迁移更加容易。Docker 可以在 很多平台上运行,无论是物理机、虚拟机、公有云、私有云,甚至是笔记本,其运 行结果是一致的。</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">因此用户可以很轻易的将在一个平台上运行的应用,迁移到另一 个平台上,而不用担心运行环境的变化导致应用无法正常运行的情况。</p> <hr style="margin-top: 1.5rem;margin-bottom: 1.5rem;max-width: 100%;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;border-style: dashed none none;border-top-color: rgb(165, 165, 165);height: 1px;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <h2 style="margin-top: 1.3em;margin-bottom: 1.3em;font-size: 1.2em;max-width: 100%;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;color: rgb(21, 153, 87);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="color: rgb(0, 0, 0);"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: inherit;line-height: inherit;box-sizing: border-box !important;overflow-wrap: break-word !important;">2、Docker安装</span></strong></span></h2> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">系统环境:docker最低支持centos7且在64位平台上,内核版本在3.10以上</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;font-size: 15px;color: rgb(62, 62, 62);line-height: inherit;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;text-align: start;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">版本:社区版,企业版(包含了一些收费服务)</p> <p style="margin-top: 1.3em;margin-bottom: 1.3em;max-width: 100%;min-height: 1em;letter-spacing:
作者:微信小助手
<section class="xmteditor" style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn"></section> <p style="text-align: center;"><img class="rich_pages" data-copyright="0" data-ratio="0.66640625" data-s="300,640" src="/upload/ebd6b540b063e43751c45d9f892960c4.jpg" data-type="jpeg" data-w="1280" style="box-shadow: rgb(170, 170, 170) 0px 0px 14px 0px;border-radius: 8px;width:95%;height:auto;"></p> <p style="box-sizing: border-box;margin: 10px;font-size: 16px;white-space: normal;text-align: right;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"><span style="font-size: 14px;">原文地址:</span><span style="font-size: 14px;">http://suo.im/5d3qii</span></p> <p style="box-sizing: border-box;margin: 10px;font-size: 16px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;">构建数据库写程序避免不了使用日期和时间,对于数据库来说,有多种日期时间字段可供选择,如 timestamp 和 datetime 以及使用 int 来存储 unix timestamp。</p> <p style="box-sizing: border-box;margin: 10px;font-size: 16px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;">经常会有人用字符串存储日期型的数据(不正确的做法)</p> <ul class=" list-paddingleft-2" style="list-style-type: disc;"> <li><p style="box-sizing: border-box;margin: 10px;font-size: 16px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;">缺点 1:无法用日期函数进行计算和比较</p></li> <li><p style="box-sizing: border-box;margin: 10px;font-size: 16px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;">缺点 2:用字符串存储日期要占用更多的空间</p></li> </ul> <p style="box-sizing: border-box;margin: 10px;font-size: 16px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;">不仅新手,包括一些有经验的程序员还是比较迷茫,究竟我该用哪种类型来存储日期时间呢?</p> <p style="box-sizing: border-box;margin: 10px;font-size: 16px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;">那我们就一步一步来分析他们的特点,这样我们根据自己的需求选择合适的字段类型来存储 (优点和缺点是比较出来的, 跟父母从小喜欢拿邻居小孩子跟自己比一样的)</p> <h2 style="box-sizing: border-box;margin: 80px 10px 40px;font-weight: bold;white-space: normal;text-align: center;color: rgb(63, 63, 63);line-height: 1.5;font-size: 22.4px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;">datetime 和 timestamp</h2> <p style="box-sizing: border-box;margin-top: 20px;margin-right: 10px;margin-bottom: 20px;padding-left: 20px;font-size: 16px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.5;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"><span style="box-sizing: border-box;margin: 10px;line-height: 1.5;text-indent: -20px;display: block;"><span style="box-sizing: border-box;margin-right: 10px;">•</span>datetime 更像日历上面的时间和你手表的时间的结合,就是指具体某个时间。</span><span style="box-sizing: border-box;margin: 10px;line-height: 1.5;text-indent: -20px;display: block;"><span style="box-sizing: border-box;margin-right: 10px;">•</span>timestamp 更适合来记录时间,比如我在东八区时间现在是 2016-08-02 10:35:52, 你在日本(东九区此时时间为 2016-08-02 11:35:52),我和你在聊天,数据库记录了时间,取出来之后,对于我来说时间是 2016-08-02 10:35:52,对于日本的你来说就是 2016-08-02 11:35:52。所以就不用考虑时区的计算了。</span><span style="box-sizing: border-box;margin: 10px;line-height: 1.5;text-indent: -20px;display: block;"><span style="box-sizing: border-box;margin-right: 10px;">•</span>时间范围是 timestamp 硬伤(1970-2038),当然 datetime (1000-9999)也记录不了刘备什么时候出生(161 年)。</span></p> <h2 style="box-sizing: border-box;margin: 80px 10px 40px;font-weight: bold;white-space: normal;text-align: center;color: rgb(63, 63, 63);line-height: 1.5;font-size: 22.4px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;">timestamp 和 UNIX timestamp</h2> <p style="box-sizing: border-box;margin-top: 20px;margin-right: 10px;margin-bottom: 20px;padding-left: 20px;font-size: 16px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.5;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"><span style="box-sizing: border-box;margin: 10px;line-height: 1.5;text-indent: -20px;display: block;"><span style="box-sizing: border-box;margin-right: 10px;">•</span>显示直观,出问题了便于排错,比好多很长的 int 数字好看多了</span><span style="box-sizing: border-box;margin: 10px;line-height: 1.5;text-indent: -20px;display: block;"><span style="box-sizing: border-box;margin-right: 10px;">•</span>int 是从 1970 年开始累加的,但是 int 支持的范围是 1901-12-13 到 2038-01-19 03:14:07,如果需要更大的范围需要设置为 bigInt。但是这个时间不包含毫秒,如果需要毫秒,还需要定义为浮点数。datetime 和 timestamp 原生自带 6 位的微秒。</span><span style="box-sizing: border-box;margin: 10px;line-height: 1.5;text-indent: -20px;display: block;"><span style="box-sizing: border-box;margin-right: 10px;">•</span>timestamp 是自带时区转换的,同上面的第 2 项。</span><span style="box-sizing: border-box;margin: 10px;line-height: 1.5;text-indent: -20px;display: block;"><span style="box-sizing: border-box;margin-right: 10px;">•</span>用户前端输入的时间一般都是日期类型,如果存储 int 还需要存前取后处理</span></p> <h2 style="box-sizing: border-box;margin: 80px 10px 40px;font-weight: bold;white-space: normal;text-align: center;color: rgb(63, 63, 63);line-height: 1.5;font-size: 22.4px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;">总结</h2> <p style="box-sizing: border-box;margin-top: 20px;margin-right: 10px;margin-bottom: 20px;padding-left: 20px;font-size: 16px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.5;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"><span style="box-sizing: border-box;margin: 10px;line-height: 1.5;text-indent: -20px;display: block;"><span style="box-sizing: border-box;margin-right: 10px;">•</span>timestamp 记录经常变化的更新 / 创建 / 发布 / 日志时间 / 购买时间 / 登录时间 / 注册时间等,并且是近来的时间,够用,时区自动处理,比如说做海外购或者业务可能拓展到海外</span><span style="box-sizing: border-box;margin: 10px;line-height: 1.5;text-indent: -20px;display: block;"><span style="box-sizing: border-box;margin-right: 10px;">•</span>datetime 记录固定时间如服务器执行计划任务时间 / 健身锻炼计划时间等,在任何时区都是需要一个固定的时间要做某个事情。超出 timestamp 的时间,如果需要时区必须记得时区处理</span><span style="box-sizing: border-box;margin: 10px;line-height: 1.5;text-indent: -20px;display: block;"><span style="box-sizing: border-box;margin-right: 10px;">•</span>UNIX timestamps 使用起来并不是很方便,至于说比较取范围什么的,timestamp 和 datetime 都能干。</span><span style="box-sizing: border-box;margin: 10px;line-height: 1.5;text-indent: -20px;display: block;"><span style="box-sizing: border-box;margin-right: 10px;">•</span>如果你不考虑时区,或者有自己一套的时区方案,随意了,喜欢哪个上哪个了</span><span style="box-sizing: border-box;margin: 10px;line-height: 1.5;text-indent: -20px;display: block;"><span style="box-sizing: border-box;margin-right: 10px;">•</span>laravel 是国际化设计的框架,为了程序员方便、符合数据库设计标准,所以 <code style="box-sizing: border-box;padding: 3px 5px;color: rgb(255, 53, 2);line-height: 1.5;font-size: 14.4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;background: rgb(248, 245, 236);border-radius: 2px;">created_at</code> <code style="box-sizing: border-box;padding: 3px 5px;color: rgb(255, 53, 2);line-height: 1.5;font-size: 14.4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;background: rgb(248, 245, 236);border-radius: 2px;">updated_at</code> 使用了 timestamp 是无可厚非的。</span><span style="box-sizing: border-box;margin: 10px;line-height: 1.5;text-indent: -20px;display: block;"><span style="box-sizing: border-box;margin-right: 10px;">•</span>有没有一个时间类型即解决了范围、时区的问题?这是不可能的,不是还有 tinyInt BigInt 吗?取自己所需,并且 MySQL 是允许数据库字段变更的。</span><span style="box-sizing: border-box;margin: 10px;line-height: 1.5;text-indent: -20px;display: block;"><span style="box-sizing: border-box;margin-right: 10px;">•</span>生日可以使用多个字段来存储,比如 year/month/day,这样就可以很方便的找到某天过生日的用户 (<code style="box-sizing: border-box;padding: 3px 5px;color: rgb(255, 53, 2);line-height: 1.5;font-size: 14.4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;background: rgb(248, 245, 236);border-radius: 2px;">User::where(['month' => 8, 'day' => 12])->get()</code>)</span></p> <p style="box-sizing: border-box;margin: 10px;font-size: 16px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;">构建项目的时候需要认真思考一下,自己的业务场景究竟用哪种更适合。选哪个?需求来定。</p> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(255, 169, 0);font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Microsoft YaHei", "Source Han Sans SC", "Noto Sans CJK SC", "WenQuanYi Micro Hei", sans-serif;font-size: 18px;letter-spacing: 1.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;">推荐阅读</strong></p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485181&idx=1&sn=7a7a7ce0671e8c5456add8da098501c2&scene=21#wechat_redirect" title="不就是个短信登录API嘛,有这么复杂吗?" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">不就是个短信登录API嘛,有这么复杂吗?</a></p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485159&idx=1&sn=c97c087c45ad6dfc0ef61d80a9d0f702&scene=21#wechat_redirect" title="盘点阿里巴巴 15 款开发者工具" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">盘点阿里巴巴 15 款开发者工具</a></p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485147&idx=1&sn=90e525a83a451d8c20298a7ef2d35ab9&scene=21#wechat_redirect" title="蚂蚁金服2019实习生面经总结(已拿口头offer)" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">蚂蚁金服2019实习生面经总结(已拿口头offer)</a></p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485070&idx=1&sn=31894a1bdda357d897962a9fc3a994b7&chksm=cea24945f9d5c0531db568321f1d8d7a4e848e04aa2df18e589db9ba4aafee0fb0cebb965252&token=463285003&lang=zh_CN&scene=21#wechat_redirect" title="记一次蚂蚁金服的面试经历" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">记一次蚂蚁金服的面试经历</a></p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485113&idx=1&sn=e4dd1bb22778e4e9139bf29d98a7492b&chksm=cea24972f9d5c064e5b454b84b9bc0d42f4aec007f20f79b564398e6dec7c0cdcda0e64193b5&token=183738038&lang=zh_CN&scene=21#wechat_redirect" title="Java学习必备书籍推荐终极版!" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">Java学习必备书籍推荐终极版!</a></p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485059&idx=1&sn=a881a1ba6013c1214b64bbed23420b88&chksm=cea24948f9d5c05edbd94bdc705da6d10ccc5c4213b7320f64b88b9a503d1c3adfe2b88fc6d7&token=463285003&lang=zh_CN&scene=21#wechat_redirect" title="我觉得技术人员该有的提问方式" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">我觉得技术人员该有的提问方式</a></p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484744&idx=1&sn=9db31dca13d327678845054af75efb74&chksm=cea24a83f9d5c3956f4feb9956b068624ab2fdd6c4a75fe52d5df5dca356a016577301399548&token=1082669959&lang=zh_CN&scene=21#wechat_redirect" title="Java 8 新特性最佳指南" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">Java 8 新特性最佳指南</a></p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484746&idx=1&sn=a519a9e3d638bff5c65008f7de167e4b&scene=21#wechat_redirect" title="做公众号这一年的经历和一件“大事”(2018-03-10)" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">做公众号这一年的经历和一件“大事”(2018-03-10)</a></p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484789&idx=1&sn=2ad9fabb8fc7fae3bd3756ea05594344&chksm=cea24abef9d5c3a889b6cb8e00cb18abbb694d189c84a24fa1ed337ad4c56194cd39316dc6a5&token=1082669959&lang=zh_CN&scene=21#wechat_redirect" title="盘点一下Github上开源的Java面试/学习相关的仓库,看完弄懂薪资至少增加10k" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">盘点一下Github上开源的Java面试/学习相关的仓库,看完弄懂薪资至少增加10k</a>( 2018-12-24)</p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484840&idx=1&sn=cf4611ac290ae3cbb381fe52aa76b60b&chksm=cea24a63f9d5c375215f7539ff0f3d6320f091d5f8b73e95c724ec9a31d3b5baa98c3f5a1012&token=1082669959&lang=zh_CN&scene=21#wechat_redirect" title="可能是一份最适合你的后端面试指南(部分内容前端同样适用)" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">可能是一份最适合你的后端面试指南(部分内容前端同样适用)</a></p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484858&idx=1&sn=8e222ea6115e0b69cac91af14d2caf36&chksm=cea24a71f9d5c367148dccec3d5ddecf5ecd8ea096b5c5ec32f22080e66ac3c343e99151c9e0&token=1082669959&lang=zh_CN&scene=21#wechat_redirect" title="redis 总结——重构版" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">redis 总结——重构版</a></p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484850&idx=1&sn=3238360bfa8105cf758dcf7354af2814&chksm=cea24a79f9d5c36fb2399aafa91d7fb2699b5006d8d037fe8aaf2e5577ff20ae322868b04a87&token=1082669959&lang=zh_CN&scene=21#wechat_redirect" title="史上最全Redis高可用技术解决方案大全" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">史上最全Redis高可用技术解决方案大全</a></p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485068&idx=1&sn=c37267fe59978dbfcd6a9a54eee1c502&chksm=cea24947f9d5c051008233a6a938e802b710ccf919f4215f84dcc0bf1fdad7d0101d37497d33&token=42880587&lang=zh_CN&scene=21#wechat_redirect" title="听说又被 JVM 内存区域方面的面试题给虐了?看看这篇文章吧!" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">听说又被 JVM 内存区域方面的面试题给虐了?看看这篇文章吧!</a></p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247484877&idx=1&sn=f54d41b68f0cd6cc7c0348a2fddbda9f&chksm=cea24a06f9d5c3102bfef946ba6c7cc5df9a503ccb14b9b141c54e179617e4923c260c0b0a01&token=1082669959&lang=zh_CN&scene=21#wechat_redirect" title="搞定 JVM 垃圾回收就是这么简单" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">搞定 JVM 垃圾回收就是这么简单</a></p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485097&idx=1&sn=84c89da477b1338bdf3e9fcd65514ac1&scene=21#wechat_redirect" title="一条SQL语句在MySQL中如何执行的" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">一条SQL语句在MySQL中如何执行的</a></p> <p style="margin: 10px;max-width: 100%;box-sizing: border-box;min-height: 1em;letter-spacing: 0.544px;white-space: normal;font-size: 16px;text-align: center;color: rgb(63, 63, 63);line-height: 1.6;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;overflow-wrap: break-word !important;"><a href="https://mp.weixin.qq.com/s?__biz=Mzg2OTA0Njk0OA==&mid=2247485085&idx=1&sn=01e5c29c49f32886bc897af7632b34ba&chksm=cea24956f9d5c040a07e4d335219f11f888a2d32444c16cade3f69c294ae0a1e416bcd221fb6&token=1613452699&lang=zh_CN&scene=21#wechat_redirect" title="一文带你轻松搞懂事务隔离级别(图文详解)" data-linktype="2" style="color: rgb(20, 140, 228);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);max-width: 100%;box-sizing: border-box;overflow-wrap: break-word !important;">一文带你轻松搞懂事务隔离级别(图文详解)</a></p> <p style="max-width: 100%;min-height: 1em;white-space: normal;font-size: 16px;text-align: center;letter-spacing: 1.5px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-copyright="0" data-ratio="1" data-s="300,640" src="/upload/f3ae1a3f6e273647b029f8dbb898bdcd.jpg" data-type="jpeg" data-w="258" style="box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 175px !important;"></p> <p style="max-width: 100%;min-height: 1em;white-space: normal;font-size: 16px;text-align: center;letter-spacing: 1.5px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box;font-weight: 600;color: rgb(36, 41, 46);text-align: start;overflow-wrap: break-word !important;">欢迎关注<img class="" data-ratio="1" src="/upload/dcb8ad1f510316ba1893da9b8a07e274.png" data-type="png" data-w="19" style="display: inline-block;vertical-align: text-bottom;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 19px !important;">点个再看<img class="" data-ratio="1" src="/upload/5f7454d24a334e968c32b8ce9ae53c5.png" data-type="png" data-w="18" style="display: inline-block;vertical-align: text-bottom;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 18px !important;"></span></p>
作者:じ☆ve宝贝

作者:じ☆ve宝贝
**XSS攻击**:跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS。 ###解决办法: 首先添加一个jar包:**commons-lang-2.5.jar** ,然后在后台调用这些函数: ``` StringEscapeUtils.escapeHtml(string); StringEscapeUtils.escapeJavaScript(string); StringEscapeUtils.escapeSql(string); ``` 或者调用: ``` public static String cleanXSS(String value) { //You'll need to remove the spaces from the html entities below value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;"); value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;"); value = value.replaceAll("'", "& #39;"); value = value.replaceAll("eval\\((.*)\\)", ""); value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\""); value = value.replaceAll("script", ""); return value; } ```