作者:微信小助手
<section data-role="outer" label="edit by 135editor" data-mpa-powered-by="yiban.io"> <p style="text-align:justify;margin: 20px 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">曾经有一家巨头公司和我们公司进行战略合作,经过双方的不懈努力及精诚合作,双方公司决定共同举办一场秒杀活动,我们公司提供优质商品和强有力的吸引价格以及使用场景,对方公司提供巨大的用户流量,再加上我们公司自己的用户流量,粗略估算下来有5000万的用户流量。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">其实,当时我们的架构是完全支撑不了千万级流量的瞬时冲击的,但是双方老板已经达成协议就要快速干起来,而且给了一个基本无法完成的时间期限。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">由于时间紧急,我们公司技术部召开了紧急会议,最终得出结论就是在原有架构基础上增加秒杀的相关接口,增加两个H5页面作为前端秒杀活动的承接页面,然后等待洪水般流量的到来。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">当秒杀活动真正开始时,流量远超过我们的估算,很快就卡住不动了,后台服务器内存、CPU、数据库负载等全满负荷了。期间,正常下单的用户也不能正常访问公司App以及下单。不难猜出,这个结果老板肯定是不满意的,要求必须解决,不能终止本次活动。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color: #C00000;"><strong><span style="font-size: 15px;letter-spacing: 1px;font-family: Helvetica, Arial, sans-serif;">最后的解决办法是:使用金钱来砸——立刻增加120多台云服务器来承载当时的秒杀活动。</span></strong></span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">那次活动对于技术部门来讲无疑是一个痛苦的经历,也是一个“不光彩”的经历。于是,后面增加了针对秒杀架构的设计。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><br></p> <section data-id="98856" data-tools="135编辑器"> <section style="margin: 10px auto;text-align: center;"> <section style="display: flex;flex-direction: column;justify-content: center;align-items: center;" hm_fix="225:661"> <section style="color:#c00000;font-size: 60px;" data-original-title="" title=""> <strong>1</strong> </section> <section style="width: 15%;height: 1px;background: rgb(192, 0, 0);margin-top: -35px;overflow: hidden;max-width: 15% !important;" data-width="15%"> <br> </section> </section> <section data-brushtype="text" style="font-size: 16px;letter-spacing: 1.5px;padding: 0px 10px;background: #fff;padding: 8px;transform: rotate(0deg);-webkit-transform: rotate(0deg);-moz-transform: rotate(0deg);-ms-transform: rotate(0deg);-o-transform: rotate(0deg);"> <span style="font-size:17px;"><strong>需求分析</strong></span> </section> </section> </section> <h2 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color: rgb(59, 59, 59);font-size: 15px;letter-spacing: 1px;caret-color: red;font-family: Helvetica, Arial, sans-serif;">“秒杀”这个词在电商行业中出现的频率较高,如京东或者淘宝平台的各种“秒杀”活动,最典型的就是“双11抢购”。</span></h2> <h2 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color: rgb(59, 59, 59);font-size: 15px;letter-spacing: 1px;caret-color: red;font-family: Helvetica, Arial, sans-serif;">“秒杀”是指在有限的时间内对有限的商品数量进行抢购的一种行为,这是商家以“低价量少”的商品来获取用户的一种营销手段。</span><br></h2> <h3 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 17px;color: #C00000;"><strong><span style="letter-spacing: 1px;font-family: Helvetica, Arial, sans-serif;">01. 功能性需求</span></strong></span></h3> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">其实,整个秒杀的业务场景并不复杂,可即查看参与秒杀的商品信息,加上购买和支付的动作,如下图所示。</span></p> <p style="text-align:center;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.8692307692307693" src="/upload/2091fa138f8e9a9850df2ab9ec37535d.png" data-type="png" data-w="1040" style="box-sizing: border-box;vertical-align: inherit;border-width: 1px;border-style: solid;border-color: rgb(151, 152, 153);background-color: rgb(255, 255, 255);border-radius: 0px;padding: 4px;width: 448px;height: 389.406px;"></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(192, 0, 0);font-family: Helvetica, Arial, sans-serif;">秒杀业务最大的挑战在于3点:</span></strong></p> <section data-role="list"> <ul class="list-paddingleft-1" style="padding-left: 30px;"> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">瞬时:</span></strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">持续时间极短,对于热门且具备极强竞争力的商品通常只有一秒。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">流量巨大:</span></strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">因为价格低廉,商品性价比高,而且正常买是需要很高的价格,所以才会吸引大量的用户来争抢。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">数量有限:</span></strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">因为商品的低价且性价比高,所以只有很有限的商品数量参与秒杀。</span></p></li> </ul> </section> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">同时,在保证高并发流量承接的前提下,为了增强用户的体验和活动规则的公平性,以及防止遭到恶意破坏等,特此增加如下需求:</span></p> <section data-tools="135编辑器" data-id="86005"> <section data-autoskip="1" style="overflow: auto;font-size: 15px;margin-bottom: 16px;line-height: 1.45;padding: 16px;border-radius: 3px;overflow-wrap: normal;background-color: rgb(247, 247, 247);"> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">(1)用户在秒杀页面无需一直刷新“抢购”按钮,待秒杀活动开始时,按钮自动点亮。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">(2)在公平以及防止恶意破坏的原则下,在下单之前增加验证码的录入,或者答题的相关环节。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">(3)库存不能出现问题,即不多扣也不少扣。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">(4)整个秒杀活动过程持续10分钟。</span></p> </section> </section> <h3 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color: #C00000;font-size: 17px;"><strong><span style="letter-spacing: 1px;font-family: Helvetica, Arial, sans-serif;">02. 性能指标预估</span></strong></span></h3> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">通过秒杀的需求描述可得出,当前秒杀活动主要需要预估三块的性能指标:存储容量、并发量、网络带宽。</span></p> <h4 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">1)存储容量</span></strong></h4> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">由于是秒杀活动,且参与的商品基本都是低价高性价比的,数量是非常有限的。所以,在订单存储上基本不用去过多考虑。</span></p> <h4 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">2)并发量</span></strong></h4> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">针对5000万用户平均每人访问2次,则并发量为每秒16.7万左右(5000w*2/10*60),在预留一部分,可以预估到每秒25万左右(也可以进行double下)。</span></p> <h4 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">3)网络带宽</span></strong></h4> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">在带宽方面,需要进行相关优化,采取数据传输越少越好,假设单条传输在0.5KB,则根据并发量预估网络带宽为:977Mb左右(25w*0.5KB=122MB*8bit=977Mb)。</span></p> <h3 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color:#c00000;"><strong><span style="letter-spacing: 1px;font-size: 17px;font-family: Helvetica, Arial, sans-serif;">03. 非功能性需求</span></strong></span></h3> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">做任何系统都要考虑非功能性需求,特别是公司的核心系统,</span><span style="color:#c00000;"><strong><span style="font-size: 15px;letter-spacing: 1px;font-family: Helvetica, Arial, sans-serif;">当前秒杀业务系统非功能性需求主要体现在如下几点:</span></strong></span></p> <section data-role="list"> <section data-role="list"> <ul class="list-paddingleft-1" style="padding-left: 30px;"> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">高可用</span></strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">,在秒杀活动的整个持续期间内,都能对用户提供服务。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">高性能</span></strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">,让每个用户都能感受到极快的秒杀响应,不能出现大批量用户延迟较高的现象。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">可扩展</span></strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">,当流量比预期更高时,有平滑扩展的策略(也有部分产品设计成友好的拒绝策略)。</span></p></li> </ul> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;"></span></p> </section> </section> <section data-id="98856" data-tools="135编辑器"> <section style="margin: 10px auto;text-align: center;"> <section style="display: flex;flex-direction: column;justify-content: center;align-items: center;" hm_fix="213:645"> <section style="color:#c00000;font-size: 60px;" data-original-title="" title="" data-num="2"> 2 </section> <section style="width: 15%;height: 1px;background: rgb(192, 0, 0);margin-top: -35px;overflow: hidden;max-width: 15% !important;" data-width="15%"> <br> </section> </section> <section data-brushtype="text" style="font-size: 16px;letter-spacing: 1.5px;padding: 0px 10px;background: #fff;padding: 8px;transform: rotate(0deg);-webkit-transform: rotate(0deg);-moz-transform: rotate(0deg);-ms-transform: rotate(0deg);-o-transform: rotate(0deg);"> <strong>概要设计</strong> </section> </section> </section> <h2 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color: rgb(59, 59, 59);font-size: 15px;letter-spacing: 1px;caret-color: red;font-family: Helvetica, Arial, sans-serif;">通过对秒杀业务的本身认知以及上面提到的秒杀业务需求,</span><span style="color:#c00000;"><strong><span style="font-size: 15px;letter-spacing: 1px;caret-color: red;font-family: Helvetica, Arial, sans-serif;">本次秒杀系统需要着重设计如下几点:</span></strong></span></h2> <section data-tools="135编辑器" data-id="86005"> <section data-autoskip="1" style="overflow: auto;font-size: 15px;margin-bottom: 16px;line-height: 1.45;padding: 16px;border-radius: 3px;overflow-wrap: normal;background-color: rgb(247, 247, 247);"> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">(1)动静分离:如何保证用户在不刷新页面的情况下,依然能进行秒杀相关数据的获取且不会耽误秒杀活动的开始。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">(2)流量分层,针对巨大流量,如何进行有效的防控,以免造成后台服务的不堪重负,以及如何避免前端页面的卡死。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">(3)高可用:如何确保后台持续提供服务。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">(4)扣减库存:如何有效扣减库存。</span></p> </section> </section> <h3 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color: #C00000;font-size: 17px;"><strong><span style="letter-spacing: 1px;font-family: Helvetica, Arial, sans-serif;">01. 动静分离</span></strong></span></h3> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">动静分离是指,将静态页面与动态页面(或者静态数据与动态数据)解耦分离,用不同系统承载对应流量。这样可以提升整个服务访问性能和可维护性。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">商品秒杀页面的静态数据以及动态数据,均是不同的地方提供,如下图所示。</span></p> <p style="text-align:center;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color: rgb(59, 59, 59);font-size: 15px;letter-spacing: 1px;caret-color: red;font-family: Helvetica, Arial, sans-serif;"><img class="rich_pages wxw-img" data-ratio="0.2601851851851852" src="/upload/1fed04ecf9b2eefcff04e2555bbfe732.png" data-type="png" data-w="1080" style="box-sizing: border-box;vertical-align: inherit;width: 100%;"> </span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">静态数据是指,页面中几乎不怎么变化的数据(即不依据用户的Cookie、基本信息、地域,及时间等各种属性来生成的数据),例如:</span></p> <section data-role="list"> <ul class="list-paddingleft-1" style="padding-left: 30px;"> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">CSS和JavaScript中的静态文件。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">活动页中的HTML静态文件。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">图片等相关资源文件。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">其他与用户信息无关的静态数据。</span></p></li> </ul> </section> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">对于这种分离出来的静态数据可以进行缓存。在缓存之后,这些静态数据的访问效率就提高了,系统也更快了。可以使用代理服务器进行静态数据的缓存。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">动态数据是指,依据当前用户属性动态生成的数据,在浏览淘宝首页时,每个用户所看到的商品都是不一样的,这就是淘宝的“千人千面”——针对不同用户做不同的推荐;在百度搜索中是依据不同用户的输入条件,以及用户的习惯给出不同的结果页。这其中的数据就是动态数据。</span></p> <h3 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color: #C00000;font-size: 17px;"><strong><span style="letter-spacing: 1px;font-family: Helvetica, Arial, sans-serif;">02. 流量分层</span></strong></span></h3> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">在“秒杀”业务中,商品价格具有强大的吸引力,所以会受到很多用户的关注,但是商品数量是有限的。所以,在千万的用户中可能只有100人能得到商品,对于系统来说,有90%以上的流量属于无效流量。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">“秒杀”业务希望有大量的用户来关注“秒杀”活动,但是在用户真正下单时又不能将这些流量全部放过,所以,需要设计一套高效的流量管控方案,来有效地控制请求流量,过滤掉没必要的流量。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">对于瞬时流量洪峰可以采用倒三角的分层级逐层控制方式,共分为CDN、反向代理(Nginx)、后端服务及DB这四个层级。接下来,就来看看每一层级是怎么控制流量的,如下图所示。</span></p> <p style="text-align:center;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.7956521739130434" data-type="png" data-w="690" src="/upload/ba5076e2325f77af0c3b6c971e5d8f6c.png" style="box-sizing: border-box;vertical-align: inherit;width: 261px;height: 208px;"></p> <h3 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color: #C00000;font-size: 17px;"><strong><span style="letter-spacing: 1px;font-family: Helvetica, Arial, sans-serif;">03. 高可用</span></strong></span></h3> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">要想在整个“秒杀”活动持续期间内,依然能对用户提供良好的体验,则秒杀系统架构在设计时不能设计成单节点的架构。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">单节点是所有系统设计中的大忌,因为单节点系统意味着系统的不稳定性较高,可能会出现不可用的情况,会给企业带来直接的损失。在系统设计(特别是“秒杀”这类对高并发要求极高的系统)时,必须保证系统的高可用,如下图所示。</span></p> <p style="text-align:center;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.526431718061674" src="/upload/608a6e4e9765bcdd64e7083cf225d2b3.png" data-type="png" data-w="908" style="box-sizing: border-box;vertical-align: inherit;width: 392px;height: 206px;"></p> <h3 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color: #C00000;font-size: 17px;"><strong><span style="letter-spacing: 1px;font-family: Helvetica, Arial, sans-serif;">04. 扣减库存</span></strong></span></h3> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">对于“秒杀”活动,通常,公司是不允许商品超卖(即下单成功的数量不能大于商品存存数量)的。一旦超卖,则会给公司造成损失。如果被恶意流量利用,则损失是巨大的。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">库存对于电商平台来说是一个重要的业务指标,所以在技术上需要合理设计扣减库存,不能出现“超卖”现象。通常,扣减库存常有以下3种方式:</span></p> <section data-role="list"> <ul class="list-paddingleft-1" style="padding-left: 30px;"> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">下单扣库存:在用户下单后就扣减库存。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">支付扣库存:用户付完款后再扣减库存。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">预扣库存:在用户下完订单后,系统会为其锁定库存一段时间,在超过锁定时间后会自动释放锁定的库存。</span></p></li> </ul> </section> <h3 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color:#c00000;"><strong><span style="letter-spacing: 1px;font-size: 17px;font-family: Helvetica, Arial, sans-serif;">05. 系统架构设计</span></strong></span></h3> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">根据上面讨论,针对当前秒杀架构如下图所示。</span></p> <p style="text-align:center;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="1.0804162724692525" src="/upload/bf0020c9cfd743fc2ab53a743014bc94.png" data-type="png" data-w="1057" style="box-sizing: border-box;vertical-align: inherit;width: 361px;height: 390px;"></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color:#c00000;"><strong><span style="font-size: 15px;letter-spacing: 1px;font-family: Helvetica, Arial, sans-serif;">如上架构比较简洁,主要分为以下5层。</span></strong></span></p> <section data-role="list"> <ul class="list-paddingleft-1" style="padding-left: 30px;"> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">用户层:用户端的展现部分,主要涉及商品的相关信息及当前“秒杀”活动的信息。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">CDN层:缓存“秒杀”活动的静态资源文件。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">负载均衡层:拦截请求及分发路由等。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">服务层:“秒杀”活动的具体交易的相关逻辑处理。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">基础设施层:数据存储、大数据计算及消息推送相关操作。</span></p></li> </ul> </section> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">其部署架构图如下:</span></p> <p style="text-align:center;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.4965437788018433" src="/upload/8a80900bd775d0afbfd60458dae7a1d0.png" data-type="png" data-w="868" style="box-sizing: border-box;vertical-align: inherit;width: 436px;height: 216px;"></p> <section data-id="98856" data-tools="135编辑器"> <section style="margin: 10px auto;text-align: center;"> <section style="display: flex;flex-direction: column;justify-content: center;align-items: center;"> <section style="color:#c00000;font-size: 60px;" data-original-title="" title="" data-num="3"> 3 </section> <section style="width: 15%;height: 1px;background: rgb(192, 0, 0);margin-top: -35px;overflow: hidden;max-width: 15% !important;" data-width="15%"> <br> </section> </section> <section data-brushtype="text" style="font-size: 16px;letter-spacing: 1.5px;padding: 0px 10px;background: #fff;padding: 8px;transform: rotate(0deg);-webkit-transform: rotate(0deg);-moz-transform: rotate(0deg);-ms-transform: rotate(0deg);-o-transform: rotate(0deg);" hm_fix="240:536"> <span style="font-size:17px;"><strong>详细设计</strong></span> </section> </section> </section> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color: rgb(192, 0, 0);"><strong><span style="letter-spacing: 1px;caret-color: red;font-family: Helvetica, Arial, sans-serif;">01. 动静分离设计</span></strong></span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">实施动静分离架构可以采用“分而治之”的办法,即将动态数据和静态数据解耦,分别使用各自的架构系统来承载对应的流量:</span></p> <section data-role="list"> <ul class="list-paddingleft-1" style="padding-left: 30px;"> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">对于静态数据,推荐缩短用户请求路径,因为路径越短,访问速度也就越快。另外,即尽可能将静态数据缓存起来。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">对于动态数据,一般用户端需要和服务端进行交互才能获取,所以,请求路径较长,访问速度会慢一点。下图展示了动静分离方案。</span></p></li> </ul> </section> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">静态数据访问速度很快,而动态数据访问速度较慢。那么试想下,可以将需要动态获取的数据给提前生成好,然后使用静态页面加速技术来访问吗?如果这样可以,那动态数据访问的速度就变快了。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">这样是可以的,需要用到比较流行的“页面静态化”技术。页面静态化技术是指,直接缓存HTTP连接,而不仅是缓存数据。如下图所示,代理服务器根据请求的URL直接将HTTP对应的响应头及响应消息体返回,流程简洁且高效。</span></p> <section> <p style="text-align:center;"><img class="rich_pages wxw-img" data-ratio="0.49428208386277" src="/upload/75c4e0156d707b690298645f9d52b5cb.png" data-type="png" data-w="787" style="box-sizing: border-box;vertical-align: inherit;width: 417px;height: 206px;"></p> </section> <h3 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color:#c00000;"><strong><span style="letter-spacing: 1px;font-size: 17px;font-family: Helvetica, Arial, sans-serif;">02. 流量分层设计</span></strong></span></h3> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">流量分层主要体现在对于CDN层、反向代理层、后端服务层以及数据层流量进行控制。</span></p> <h4 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">1)CDN层流量控制</span></strong></h4> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);text-shadow: rgb(250, 192, 143) 0.2em 0.2em 0.8em;font-family: Helvetica, Arial, sans-serif;">由动静分离技术可以想到:</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">应尽量将尽可能多的数据提前生成,然后将其放入CDN节点缓存中(因为CDN层在物理架构上离用户比较近)。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">所以,如果绝大部分的流量都在这一层获取数据,则到达后端的流量会减少很多,如下图所示。</span></p> <p style="text-align:center;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.6380165289256199" src="/upload/7fda7bb181573899d48f6d7e47a100b6.png" data-type="png" data-w="605" style="box-sizing: border-box;vertical-align: inherit;width: 366px;height: 234px;"></p> <h4 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">2)反向代理层流量控制</span></strong></h4> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">在动静分离方案中,讲到通过“页面静态化技术”加速动态数据的获取,即提前将动态数据生成好,然后对其进行静态化处理。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">所以,这里就可以依据页面静态化加速技术,通过后端服务Job的方式定时提前生成前端需要静态的数据;然后,将其发送到内容分发服务上;最后,分发服务会将这些静态化页面数据分发到所有的反向代理服务器上,如下图所示。</span></p> <p style="text-align:center;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.25031446540880503" src="/upload/12605ac975b92be3a9742897531b83dd.png" data-type="png" data-w="795" style="box-sizing: border-box;vertical-align: inherit;width: 441px;height: 110px;"></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">在“秒杀”业务中,活动详情页上有一个倒计时的模块,用户可以看到当前“秒杀”活动还剩余多少时间开始。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);text-shadow: rgb(250, 192, 143) 0.2em 0.2em 0.8em;font-family: Helvetica, Arial, sans-serif;">这种逻辑简单的功能可以直接使用Nginx来实现:</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">利用nginx-lua插件,使用lua脚本获取当前Nginx服务器的时间进行计算倒计时。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">另外,商品库存数据也可以通过Nginx直接访问分布式缓存来获取,如下图所示。</span></p> <p style="text-align:center;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.23796033994334279" src="/upload/ad4b09c6cef7a906eaa41f62d90e1d61.png" data-type="png" data-w="1059" style="box-sizing: border-box;vertical-align: inherit;width: 100%;"></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">“秒杀”业务中的商品价格很低,对于用户有很大的吸引力,所以可能会有人利用“秒杀器”进行不公平竞争,且有可能存在竞争对手恶意刷请求的情况。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">如果存在这样的情况,那本次活动就是有风险的,万一被恶意流量独占了库存,则会导致正常用户不能抢购商品,也有可能这种恶意的请求会对后端系统造成严重冲击,甚至造成后端系统瘫痪。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);text-shadow: rgb(250, 192, 143) 0.2em 0.2em 0.8em;font-family: Helvetica, Arial, sans-serif;">对于这种恶意请求,最好有一套机制能提前感知,并将恶意请求提前封存。</span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">可以在Nginx层中控制;也可以在Nginx中配置用户的访问频率(例如每分钟只能访问10次);还可以使用Lua脚本编写一些简单业务逻辑的接口,例如,通过调用接口直接封掉指定IP地址或UserAgent的请求。</span></p> <h4 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">3)后端服务层流量控制</span></strong></h4> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);text-shadow: rgb(250, 192, 143) 0.2em 0.2em 0.8em;font-family: Helvetica, Arial, sans-serif;">对于服务层的流量控制,有以下几点建议:</span></p> <section data-role="list"> <ul class="list-paddingleft-1" style="padding-left: 30px;"> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">在程序开发上,代码独立,不要与平台其他项目一起。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">在部署时,应用独立部署,分散流量,避免不合适的流量影响主体业务。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">使用独立域名,或者按照一定的URL规则在反向代理层进行路由。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">做好系统保护和限流,进一步减少不必要的流量。</span></p></li> </ul> </section> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">当“到达系统中的请求数”明显大于“系统能够处理的最大请求数”时,可以直接拒绝这些多余的请求,直接返回“秒杀”活动结束的信息。例如,活动开始时的商品库存是100,目前库存只剩50了,如果“每台服务器待处理的请求数”已经超过“商品总库存数(100)”了,则可以直接终止掉多余的请求。</span></p> <h4 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">4)数据库层流量控制</span></strong></h4> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">对于请求到数据中的流量,写入的流量就是真正下单成功的流量,即需要扣减库存的动作。有如下建议:</span></p> <section data-role="list"> <ul class="list-paddingleft-1" style="padding-left: 30px;"> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">如果不是临时的活动,则建议使用独立的数据库作为“秒杀”活动的数据库。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">将数据库配置成读写分离。</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">尝试去除行锁。</span></p></li> </ul> </section> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">对于数据库行锁的优化,可以通过将商品进行拆分来实现——增加ID,如下图所示。对于单一的“秒杀”活动这会得到显著效果。</span></p> <p style="text-align:center;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><img class="rich_pages wxw-img" data-ratio="0.7359307359307359" src="/upload/b77e8030a92f155e2ae60f82e345448d.png" data-type="png" data-w="693" style="box-sizing: border-box;vertical-align: inherit;width: 313px;height: 230px;"></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">从流量分层控制方案可看出,瞬时流量就像被漏斗过滤了似的,应尽量将数据和请求量一层一层地过滤掉。这种流量分层控制核心思想:在不同的层级中尽可能地过滤掉无效的请求,到达“倒三角”最末端的请求才是有效的请求。</span></p> <h4 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">5)高可用</span></strong></h4> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">在系统设计时想要做到高可用,避免单节点的一个小妙招:将服务无状态化。如果无法完全无状态化(如存储系统),则可以通过冗余多个备份节点的方案来避免单节点。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">由于篇幅原因,高可用此处就不再赘述,大家可以查看</span><span style="color:#c00000;"><strong><span style="font-size: 15px;letter-spacing: 1px;font-family: Helvetica, Arial, sans-serif;">《高并发系统实战派》</span></strong></span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">一书里面针对高并发系统的真实设计案例,毫无保留的分享出了企业级高并发系统实战。</span></p> <h3 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color: #C00000;font-size: 17px;"><strong><span style="letter-spacing: 1px;font-family: Helvetica, Arial, sans-serif;">03. 扣减库存设计</span></strong></span></h3> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">由于在“秒杀”场景中商品一般优惠力度很大,对用户很具有吸引力,所以,在这种场景中使用“下单扣库存”方式更为合适。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">在“秒杀”场景中,大部分用户抱着“抢到就是赚到”的想法,基本都会去付款的,但如果真有竞争对手恶意下单不付款,那我们该怎么办?前面在流量管控中已经说到,可以对请求日志进行实时分析,让风控系统选择出恶意用户,然后将其封停。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">在“秒杀”场景中,通过流量分层控制可以分层管控大量的“读”请求。但是,依然会有很大的流量进入真正的下单逻辑。对于这么大的流量,除前面说的数据库隔离外,还需要进一步优化库存,否则数据库读/写依然是系统的瓶颈。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">接下来看看如何优化大流量“秒杀”场景中的库存数量扣减操作。</span></p> <h4 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">1)利用缓存技术</span></strong></h4> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">在“秒杀”场景中,如果只是一个扣减库存数量这样的简单流程,则可以先将库存数量直接放在缓存中,然后用分布式缓存(如Redis)的超高性能去应对这种瞬时流量洪峰下的系统挑战。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">使用缓存是存在一定风险的,比如,缓存节点出现了异常,那库存数量该怎么算?</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">使用缓存,不仅要考虑分布式缓存高可用(如何设计可以查看我的新书“高并发系统实战派”),还要考虑各种限流容错机制,以确保分布式缓存对外提供服务。</span></p> <h4 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">2)异步处理技术</span></strong></h4> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">如果是复杂的扣减库存(如涉及商品信息本身或牵连其他系统),则建议使用数据库进行库存数量的扣减,可以使用异步的方式来应对这种高并发的库存的更新。</span></p> <section data-tools="135编辑器" data-id="86005"> <section data-autoskip="1" style="overflow: auto;font-size: 15px;margin-bottom: 16px;line-height: 1.45;padding: 16px;border-radius: 3px;overflow-wrap: normal;background-color: rgb(247, 247, 247);"> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">①在用户下单时,不立刻生成订单,而是将所有订单依次放入队列。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">②下单模块依据自身的处理速度,从队列中依次获取订单进行“下单扣库存”操作。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">③在订单生成成功后,用户即可进行支付操作了。</span></p> </section> </section> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">这种方式是针对“秒杀”场景的,依据“先到先得”原则来保证公平公正,所有用户都可以抢购,然后等待订单处理,最后生成订单(如果库存不足,则生成订单失败)。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">这样的逻辑,对用户来说体验不是很差。</span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">具体排队逻辑如下图所示。</span></p> <p style="text-align:center;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;"><img class="rich_pages wxw-img" data-ratio="0.15458015267175573" src="/upload/5f3459f51981ba06a1cf0e25a3df938d.png" data-type="png" data-w="1048" style="box-sizing: border-box;vertical-align: inherit;width: 407px;height: 63px;"></span></p> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><img data-ratio="1" data-type="gif" data-w="1" src="/upload/bf5651c2a95fc53ac68a1807c94852b7.jpg" style="vertical-align:inherit;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;"> </span></p> <section data-id="98856" data-tools="135编辑器"> <section style="margin: 10px auto;text-align: center;"> <section style="display: flex;flex-direction: column;justify-content: center;align-items: center;"> <section style="color:#c00000;font-size: 60px;" data-original-title="" title="" data-num="4"> 4 </section> <section style="width: 15%;height: 1px;background: rgb(192, 0, 0);margin-top: -35px;overflow: hidden;max-width: 15% !important;" data-width="15%"> <br> </section> </section> <section data-brushtype="text" style="font-size: 16px;letter-spacing: 1.5px;padding: 0px 10px;background: #fff;padding: 8px;transform: rotate(0deg);-webkit-transform: rotate(0deg);-moz-transform: rotate(0deg);-ms-transform: rotate(0deg);-o-transform: rotate(0deg);" hm_fix="239:554"> <strong><span style="font-size:17px;">搭建千万级流量“秒杀”系统需要哪些技术</span></strong> </section> </section> </section> <h2 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="color: rgb(59, 59, 59);font-size: 15px;letter-spacing: 1px;caret-color: red;font-family: Helvetica, Arial, sans-serif;">前面介绍了千万级流量“秒杀”系统的基本架构、“秒杀”系统的设计原则、如何做动静分离方案和流量控制,以及扣减库存方面内容。这些都是设计高并发“秒杀”系统必须要考虑的。</span><br></h2> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">“秒杀”系统的流程并不复杂——只是一个“下单扣库存”的动作,但由于其独特的业务特点,所以在进行系统设计时不能大意。对于瞬时流量洪峰的高并发“秒杀”系统,我们需要什么技术呢?下面来总结一下。</span></p> <h3 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">(1)数据的静态化的技术</span></strong></h3> <p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">用来应对高并发读的请求,主要涉及以下内容,这些在</span><span style="color:#c00000;"><strong><span style="font-size: 15px;letter-spacing: 1px;font-family: Helvetica, Arial, sans-serif;">《高并发系统实战派》</span></strong></span><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">一书中详细分享了真实使用场景已经技术方案:</span></p> <section data-role="list"> <ul class="list-paddingleft-1" style="padding-left: 30px;"> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">各层级缓存的处理(即多级缓存的技术)</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">分布式缓存技术</span></p></li> </ul> </section> <h3 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">(2)负载均衡反向代理技术</span></strong></h3> <section data-role="list"> <ul class="list-paddingleft-1" style="padding-left: 30px;"> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">LVS</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">Nginx</span></p></li> </ul> </section> <h3 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">(3)异步处理技术</span></strong></h3> <section data-role="list"> <ul class="list-paddingleft-1" style="padding-left: 30px;"> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">消息队列技术</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">排队系统技术</span></p></li> </ul> </section> <h3 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">(4)系统架构设计技术</span></strong></h3> <section data-role="list"> <ul class="list-paddingleft-1" style="padding-left: 30px;"> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">系统模块化划分</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">微服务架构思想</span></p></li> </ul> </section> <h3 style="margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><strong><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">(5)系统监控技术</span></strong></h3> <section data-role="list"> <section data-role="list"> <ul class="list-paddingleft-1" style="padding-left: 30px;"> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">日志监控</span></p></li> <li><p style="text-align:justify;margin-left: 8px;margin-right: 8px;margin-bottom: 20px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(59, 59, 59);font-family: Helvetica, Arial, sans-serif;">服务监控</span></p></li> </ul> </section> </section> </section>
作者:じ☆ve不哭
## 原因 > 在阿里云在线扩容并支付订单后,登陆控制台发现磁盘容量没有变化! ## 安装growpart ``` yum install -y cloud-utils-growpart gdisk ``` ## 查看磁盘实际大小 运行` fdisk -l` 命令查看磁盘实际大小。 ``` [root@root /]# fdisk -l Disk /dev/vda: 200 GB, 200018364800 bytes, 402430400 sectors Units = sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disk label type: dos Disk identifier: 0x0008d73a Device Boot Start End Blocks Id System /dev/vda1 * 2048 419428351 209713152 83 Linux ``` **说明:磁盘(/dev/vda)实际大小为:200 G。** ## 查看磁盘分配大小 运行` df -h `命令查看磁盘分配大小。 ``` [root@root /]# df -h Filesystem Size Used Avail Use% Mounted on devtmpfs 7.8G 0 7.8G 0% /dev tmpfs 7.8G 0 7.8G 0% /dev/shm tmpfs 7.8G 1.5M 7.8G 1% /run tmpfs 7.8G 0 7.8G 0% /sys/fs/cgroup /dev/vda1 100G 95G 5G 95% / tmpfs 1.6G 0 1.6G 0% /run/user/0 ``` 说明:磁盘(/dev/vda)分配大小为:100 G。意味着还有100G未分配 ## 自适应分区扩容 运行 `growpart <DeviceName> <PartionNumber> `命令,调用 `growpart` 为需要扩容的云盘和对应的第几个分区扩容。 `growpart /dev/vda 1` ,表示为系统盘的第一个分区(/dev/vda1)扩容。 ``` [root@root /]# growpart /dev/vda 1 CHANGED: partition=1 start=2048 old: size=104855519 end=104857567 new: size=402230400 end=402430400 ``` ## 重设分区大小 运行` resize2fs <PartitionName> `命令调用 `resize2fs` 扩容文件系统。 ``` [root@root /]# resize2fs /dev/vda1 resize2fs 1.42.9 (28-Dec-2013) Filesystem at /dev/vda1 is mounted on /; on-line resizing required old_desc_blocks = 3, new_desc_blocks = 4 The filesystem on /dev/vda1 is now 13106939 blocks long. ``` ## 再次查看磁盘分区大小 ``` [root@root /]# sudo df -h Filesystem Size Used Avail Use% Mounted on devtmpfs 7.8G 0 7.8G 0% /dev tmpfs 7.8G 0 7.8G 0% /dev/shm tmpfs 7.8G 1.5M 7.8G 1% /run tmpfs 7.8G 0 7.8G 0% /sys/fs/cgroup /dev/vda1 200G 95G 150G 48% / tmpfs 1.6G 0 1.6G 0% /run/user/0 ``` 可以看到分区(/dev/vda1)容量已经是200GiB,表示已经成功扩容。 在整个过程中,无需重启服务器,所以不会影响到服务器上正在运行的服务。
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Roboto, Oxygen, Ubuntu, Cantarell, PingFangSC-regular, PingFangTC-regular, "Open Sans", "Helvetica Neue", sans-serif;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">最近在做 Java8 到 Java17 的迁移工作,前期做了一些准备,但是在升级过程还是有些问题,太emo了,一些信息记录如下,分为几个部分:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 14px;line-height: 25px;letter-spacing: 1.5px;color: rgb(51, 51, 51);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 25px;"> 编译相关 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 25px;"> 参数迁移相关 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 25px;"> 运行相关 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">前人栽树后人乘凉,有需要升级的可以参考一下,避免踩坑。。。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;font-weight: bold;font-size: 22px;border-bottom: 2px solid rgb(89, 89, 89);margin-bottom: 30px;color: rgb(89, 89, 89);"><span style="display: none;"></span><span style="font-size: 18px;display: inline-block;border-bottom: 2px solid rgb(89,89,89);"><em style="color: rgb(71, 193, 168);">*编译相关*</em></span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: rgb(89, 89, 89);"><span style="display: none;"></span>JEP 320<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">在 Java11 中引入了一个提案 JEP 320: Remove the Java EE and CORBA Modules (openjdk.org/jeps/320) 提案,移除了 Java EE and CORBA 的模块,如果项目中用到需要手动引入。比如代码中用到了 <code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);">javax.annotation.*</code> 下的包:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/icFTnRoibgibp9RVUbVPQia7rOianQjlc2Az6pxBsiaCiadiahLSazJsoM3ynqnCk1E5AVSkDsq0scKbVxdc2hcqib1fGWZPfG5VXj0UL/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">public abstract class FridayAgent <br> @PreDestroy<br> public void <span style="line-height: 26px;"><span style="color: #61aeee;line-height: 26px;">destroy</span></span>() {<br> agentClient.close();<br> }<br>} <br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">在编译时会找不到相关的类。这是因为 Java EE 已经在 <code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);">Java 9</code> 中被标记为 deprecated,Java 11 中被正式移除,可以手动引入 javax 的包:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/icFTnRoibgibp9RVUbVPQia7rOianQjlc2Az6pxBsiaCiadiahLSazJsoM3ynqnCk1E5AVSkDsq0scKbVxdc2hcqib1fGWZPfG5VXj0UL/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><dependency><br> <groupId>javax.annotation</groupId><br> <artifactId>javax.annotation-api</artifactId><br> <version>1.3.2</version><br></dependency><br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: rgb(89, 89, 89);"><span style="display: none;"></span>使用了 sun.misc.* 下的包<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">比如 sun.misc.BASE64Encoder,这个简单,替换一下工具类即可。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/icFTnRoibgibp9RVUbVPQia7rOianQjlc2Az6pxBsiaCiadiahLSazJsoM3ynqnCk1E5AVSkDsq0scKbVxdc2hcqib1fGWZPfG5VXj0UL/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">[ERROR] symbol: class BASE64Encoder<br>[ERROR] location: package sun.misc<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">netty 低版本使用了 sun.misc.*,编译错误信息如下</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/icFTnRoibgibp9RVUbVPQia7rOianQjlc2Az6pxBsiaCiadiahLSazJsoM3ynqnCk1E5AVSkDsq0scKbVxdc2hcqib1fGWZPfG5VXj0UL/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">Caused by: java.lang.NoClassDefFoundError: Could not initialize class io.netty.util.internal.PlatformDependent0<br> at io.netty.util.internal.PlatformDependent.getSystemClassLoader(PlatformDependent.java:694) ~[netty-all-4.0.42.Final.jar!/:4.0.42.Final]<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">对应的源码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/icFTnRoibgibp9RVUbVPQia7rOianQjlc2Az6pxBsiaCiadiahLSazJsoM3ynqnCk1E5AVSkDsq0scKbVxdc2hcqib1fGWZPfG5VXj0UL/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">/**<br> * The {@link PlatformDependent} operations <span style="color: #e6c07b;line-height: 26px;">which</span> requires access to {@code sun.misc.*}.<br> */<br>final class PlatformDependent0 {<br>}<br><br>https://github.com/netty/netty/issues/6855<br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: rgb(89, 89, 89);"><span style="display: none;"></span>lombok 使用了 com.sun.tools.javac.* 下的包<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">错误信息如下:</p> <blockquote data-tool="mdnice编辑器" style=" overflow: auto;background: rgba(0, 0, 0, 0.05);margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px; line-height: 1.8;border-width: initial;border-style: none;border-color: initial;font-size: 14px;color: rgb(51, 51, 51); "> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 1.5px;line-height: 26px;display: inline;">Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.2:compile (default-compile) on project encloud-common: Fatal error compiling: java.lang.ExceptionInInitializerError: Unable to make field private com.sun.tools.javac.processing.JavacProcessingEnvironment$DiscoveredProcessors com.sun.tools.javac.processing.JavacProcessingEnvironment.discoveredProcs accessible: module jdk.compiler does not "opens com.sun.tools.javac.processing" to unnamed module</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">如果你的项目中使用 lombok,而且是低版本的话,就会出现,lombok 的原理是在编译期做一些手脚,用到了 <code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);">com.sun.tools.javac</code> 下的文件,升级到最新版可以解决。ps,个人很不喜欢 lombok, 调试的时候代码和 class 对不上真的很恶心。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/icFTnRoibgibp9RVUbVPQia7rOianQjlc2Az6pxBsiaCiadiahLSazJsoM3ynqnCk1E5AVSkDsq0scKbVxdc2hcqib1fGWZPfG5VXj0UL/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><dependency><br> <groupId>org.projectlombok</groupId><br> <artifactId>lombok</artifactId><br> <!-- <version>1.16.4</version>--><br> <version>1.18.24</version><br></dependency><br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: rgb(89, 89, 89);"><span style="display: none;"></span>kotlin 版本限制<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">我们后端在很多年前就 all-in Kotlin,Kotlin 的升级也是我们的重中之重。</p> <blockquote data-tool="mdnice编辑器" style=" overflow: auto;background: rgba(0, 0, 0, 0.05);margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px; line-height: 1.8;border-width: initial;border-style: none;border-color: initial;font-size: 14px;color: rgb(51, 51, 51); "> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 1.5px;line-height: 26px;display: inline;">[ERROR] Failed to execute goal org.jetbrains.kotlin:kotlin-maven-plugin:1.2.71:compile (compile) on project encloud-core: Compilation failure [ERROR] Unknown JVM target version: 17 [ERROR] Supported versions: 1.6, 1.8</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">Kotlin 在 1.6.0 版本开始支持 Java17 的字节码,低于 1.6.0 的编译会直接报错</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: rgb(89, 89, 89);"><span style="display: none;"></span>废弃依赖分析<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">可以用 <code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);">jdeps --jdk-internals --multi-release 17 --class-path . encloud-api.jar</code> 来做项目的依赖分析</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img src="/upload/d224919c72549e5ec465fe7bec868b91.jpg" style="display: block;margin-right: auto;margin-left: auto;width: 85%;border-radius: 5px;background: none rgb(224, 224, 224);box-shadow: rgba(0, 0, 0, 0.043) 0px 0px 2.1px, rgba(0, 0, 0, 0.063) 0px 0px 5px, rgba(0, 0, 0, 0.075) 0px 0px 9.4px, rgba(0, 0, 0, 0.09) 0px 0px 16.8px, rgba(0, 0, 0, 0.11) 0px 0px 31.3px, rgba(0, 0, 0, 0.15) 0px 0px 75px;" data-ratio="0.3787037037037037" data-w="1080" class="rich_pages wxw-img"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> 图片 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">这样你就可以知道哪些库需要做升级了。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;font-weight: bold;font-size: 22px;border-bottom: 2px solid rgb(89, 89, 89);margin-bottom: 30px;color: rgb(89, 89, 89);"><span style="display: none;"></span><span style="font-size: 18px;display: inline-block;border-bottom: 2px solid rgb(89,89,89);"><em style="color: rgb(71, 193, 168);">*参数迁移*</em></span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: rgb(89, 89, 89);"><span style="display: none;"></span>什么是 Unified Logging<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">在 Java 领域,有广为人知的日志框架,slf4j、log4j 等,这些框架提供了统一的编程接口,让用户可以通过简单的配置实现日志输出的个性化配置,比如日志 tag、级别(info、debug 等)、上下文(线程 id、行号、时间等),在 JVM 内部之前一直缺乏这样的规范,于是出来了 Unified Logging,实现了日志格式的大一统,这就是我们接下来要介绍的重点 <code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);">Unified Logging</code>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">我们接触最多的是 gc 的日志,在 java8 中,我们配置 gc 日志的参数是 <code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);">-Xloggc:/tmp/gc.log</code>。在 JVM 中除了 GC,还有大量的其它相关的日志,比如线程、os 等,在新的 Unified Logging 日志中,日志输出的方式变更为了 <code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);">java -Xlog:xxx</code>,GC 不再特殊只是做为日志的一种存在形式。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/icFTnRoibgibp9RVUbVPQia7rOianQjlc2Az6pxBsiaCiadiahLSazJsoM3ynqnCk1E5AVSkDsq0scKbVxdc2hcqib1fGWZPfG5VXj0UL/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">java -Xlog -version<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">输出结果如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img src="/upload/f3a7f228c6e29d947efa51c416af7b45.jpg" style="display: block;margin-right: auto;margin-left: auto;width: 85%;border-radius: 5px;background: none rgb(224, 224, 224);box-shadow: rgba(0, 0, 0, 0.043) 0px 0px 2.1px, rgba(0, 0, 0, 0.063) 0px 0px 5px, rgba(0, 0, 0, 0.075) 0px 0px 9.4px, rgba(0, 0, 0, 0.09) 0px 0px 16.8px, rgba(0, 0, 0, 0.11) 0px 0px 31.3px, rgba(0, 0, 0, 0.15) 0px 0px 75px;" data-ratio="0.32037037037037036" data-w="1080" class="rich_pages wxw-img"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> 图片 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">可以看到日志输出里,不仅有 GC 相关的日志,还有 os 线程相关的信息。事实上 java 的日志的生产者有非常多部分,比如 thread、class load、unload、safepoint、cds 等。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img src="/upload/7acd43b6917784564df2cedff65cb395.jpg" style="display: block;margin-right: auto;margin-left: auto;width: 85%;border-radius: 5px;background: none rgb(224, 224, 224);box-shadow: rgba(0, 0, 0, 0.043) 0px 0px 2.1px, rgba(0, 0, 0, 0.063) 0px 0px 5px, rgba(0, 0, 0, 0.075) 0px 0px 9.4px, rgba(0, 0, 0, 0.09) 0px 0px 16.8px, rgba(0, 0, 0, 0.11) 0px 0px 31.3px, rgba(0, 0, 0, 0.15) 0px 0px 75px;" data-ratio="0.25925925925925924" data-w="1080" class="rich_pages wxw-img"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> 图片 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">归根到底,日志打印,需要回答清楚三个问题:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 14px;line-height: 25px;letter-spacing: 1.5px;color: rgb(51, 51, 51);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 25px;"> what:要输出什么信息(tag),以什么日志级别输出(level) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 25px;"> where:输出到哪里(console 还是 file) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 25px;"> decorators:日志如何 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: rgb(89, 89, 89);"><span style="display: none;"></span>输出什么信息(selectors)<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">首先来看 what 的部分,如何指定要输出哪些信息,这个在 JVM 内部被称之为 selectors。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">JVM 采用的是 <code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);"><tag-set>=<level></code>的形式来表示 selectors,默认情况下,tag 为<code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);">all</code>,表示所有的 tag,level 为 <code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);">INFO</code>,<code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);">java -Xlog -version</code> 等价于下面的形式</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/icFTnRoibgibp9RVUbVPQia7rOianQjlc2Az6pxBsiaCiadiahLSazJsoM3ynqnCk1E5AVSkDsq0scKbVxdc2hcqib1fGWZPfG5VXj0UL/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">java -Xlog:all=info -version<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">如果我们想输出tag 为 gc,日志级别为 debug 的日志,可以用 <code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);">java -Xlog:gc=debug</code> 的形式:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/icFTnRoibgibp9RVUbVPQia7rOianQjlc2Az6pxBsiaCiadiahLSazJsoM3ynqnCk1E5AVSkDsq0scKbVxdc2hcqib1fGWZPfG5VXj0UL/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">$ java -Xlog:gc=debug -version<br>[0.023s][info][gc] Using G1<br>[0.023s][debug][gc] ConcGCThreads: 3 offset 22<br>[0.023s][debug][gc] ParallelGCThreads: 10<br>[0.024s][debug][gc] Initialize mark stack with 4096 chunks, maximum 524288<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">这样就输出了 tag 为 gc,级别为 debug 的日志信息。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">不过这里有一个比较坑的点是,这里的 tag 匹配规则是精确匹配,如果某条日志的 tag 是 <code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);">gc,metaspace</code>,通过上面的规则是匹配不到的,我们可以手动指定的方式来输出。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/icFTnRoibgibp9RVUbVPQia7rOianQjlc2Az6pxBsiaCiadiahLSazJsoM3ynqnCk1E5AVSkDsq0scKbVxdc2hcqib1fGWZPfG5VXj0UL/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">$ java -Xlog:gc+metaspace -version<br><br>[0.022s][info][gc,metaspace] CDS archive(s) mapped at: ... size 12443648.<br>[0.022s][info][gc,metaspace] Compressed class space mapped at: reserved size:...<br>[0.022s][info][gc,metaspace] Narrow klass base:..., Narrow <br>klass <span style="color: #e6c07b;line-height: 26px;">shift</span>: 0, Narrow klass range: 0x100000000<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;font-size: 14px;color: rgb(51, 51, 51);margin-top: 8px;margin-bottom: 8px;line-height: 35px;letter-spacing: 1.5px;">这里的 selector 也是可以进行组合的,不同的 selector 之间用逗号分隔即可。比如同时输出 <code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);">gc</code> 和 <code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;font-size: 12px;color: rgb(71, 193, 168);">gc+metaspace</code> 这两类 tag 的日志,就可以这么写:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/icFTnRoibgibp9RVUbVPQia7rOianQjlc2Az6pxBsiaCiadiahLSazJsoM3ynqnCk1E5AVSkDsq0scKbVxdc2hcqib1fGWZPfG5VXj0UL/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">$ java -Xlog:gc=debug,gc+metaspace -version<br><br>[0.020s][info][gc] Using G1<br>[0.020s][debug][gc] ConcGCThreads: 3 offset 22<br>[0.020s][debug][gc] ParallelGCThreads: 10<br>[0.020s][debug][gc] Initialize mark stack with 4096 chunks, maximum 524288<br>[0.022s][info ][gc,metaspace]&nbs
作者:微信小助手
<section data-id="115225" data-tools="135编辑器" style="margin-bottom: 0px;outline: 0px;max-width: 100%;color: rgb(34, 34, 34);letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);caret-color: rgb(34, 34, 34);text-size-adjust: inherit;visibility: visible;font-family: system-ui, -apple-system, BlinkMacSystemFont, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin: 20px auto;outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="padding: 2px;outline: 0px;max-width: 100%;border-width: 1px;border-style: solid;border-color: rgb(227, 108, 9);border-radius: 0px 25px;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="padding: 25px 15px;outline: 0px;max-width: 100%;border-width: 1px;border-style: solid;border-color: rgb(227, 108, 9);border-radius: 0px 15px;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="padding-top: 15px;outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-autoskip="1" style="outline: 0px;max-width: 100%;line-height: 1.75em;letter-spacing: 1.5px;font-size: 14px;color: rgb(51, 51, 51);visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="margin-bottom: 15px;outline: 0px;max-width: 100%;vertical-align: inherit;visibility: visible;line-height: 2em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="outline: 0px;max-width: 100%;visibility: visible;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="outline: 0px;max-width: 100%;caret-color: red;visibility: visible;letter-spacing: 0.5px;color: rgb(227, 108, 9);font-family: 微软雅黑, "Microsoft YaHei";box-sizing: border-box !important;overflow-wrap: break-word !important;">近日,OpenSergo 社区联合 ShardingSphere 共同发布了面向微服务场景下的数据库治理标准</span></strong><span style="outline: 0px;max-width: 100%;caret-color: red;visibility: visible;letter-spacing: 0.5px;font-family: 微软雅黑, "Microsoft YaHei";box-sizing: border-box !important;overflow-wrap: break-word !important;">,进一步完善了云原生微服务体系下的数据库治理生态。</span></p> </section> </section> </section> </section> </section> </section> <h2 style="padding-bottom: 0.3em;margin-bottom: 16px;font-weight: 600;box-sizing: border-box;font-size: 1.5em;line-height: 1.25;border-bottom: 1px solid rgb(234, 236, 239);color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";text-align: start;white-space: normal;">为什么需要微服务治理与 OpenSergo?</h2> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: left;white-space: normal;">在经典微服务架构中,我们通常将服务调用中各角色划分为三部分:服务提供者、服务消费者、注册中心。经典的微服务架构可以解决微服务能调通、可以运行起来的问题。随着分布式服务架构的不断演进、业务规模的扩张,诸多复杂的稳定性与易用性问题显现出来,这时候就需要一些手段来针对日益复杂的微服务架构进行“治理”。微服务治理就是通过流量治理、服务容错、安全治理等技术手段来减少甚至避免发布和管理大规模应用过程中遇到的稳定性问题,对微服务领域中的各个组件进行治理。服务提供者、消费者、注册中心、服务治理,构成现代微服务架构中重要的几环。</p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;"><img class="rich_pages wxw-img" data-ratio="0.2425828970331588" src="/upload/6442931a080561ec16c7002abcbd0462.png" data-type="png" data-w="3438" style="box-sizing: content-box;border-style: none;background-color: rgb(255, 255, 255);"></p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">微服务治理是把微服务做稳做好的关键一环。但是,业界微服务治理存在概念不统一、配置形式不统一、能力不统一、多框架统一管控较为复杂等问题。比如我们希望配置流量灰度规则,在 Spring Cloud Alibaba 中可能需要通过 YAML 方式配置,在 Dubbo 中需要通过另一种配置格式进行配置,在 Istio 体系内中可能又需要通过 Istio CRD 的方式进行配置。<span style="box-sizing: border-box;font-weight: 600;">不同框架治理配置方式的不一致使得微服务统一治理管控的复杂度相当高</span>。另外,业界的各种框架支持的服务治理能力都不统一,且通常比较基础,很多时候无法覆盖生产级的场景。</p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;"><img class="rich_pages wxw-img" data-ratio="0.39412866958151155" src="/upload/24fbcb70a28ea5eafa58ab72b3b1465b.png" data-type="png" data-w="3202" style="box-sizing: content-box;border-style: none;background-color: rgb(255, 255, 255);"></p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">基于上面这些痛点,阿里巴巴在2022年1月开始和 bilibili、字节等企业讨论服务治理如何规范化和更加普及,从而共同发起了 OpenSergo 项目。<span style="box-sizing: border-box;font-weight: 600;">OpenSergo 是开放通用的,覆盖微服务及上下游关联组件的微服务治理项目,从微服务的角度出发,涵盖流量治理、服务容错、服务元信息治理、安全治理等关键治理领域,提供一系列的治理能力与标准、生态适配与最佳实践,支持 Java, Go, Rust 等多语言生态</span>。OpenSergo 的最大特点就是以统一的一套配置/DSL/协议定义服务治理规则,面向多语言异构化架构,覆盖微服务框架及上下游关联组件。无论微服务的语言是 Java, Go, Node.js 还是其它语言,无论是标准微服务还是 Mesh 接入,从网关到微服务调用,再到微服务对数据库/缓存的访问,开发者都可以通过同一套 OpenSergo CRD 标准配置进行统一的治理管控,而无需关注各框架、语言的差异点,降低异构化、全链路微服务治理管控的复杂度。</p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;"><img class="rich_pages wxw-img" data-ratio="0.5202156334231806" src="/upload/af027ad1e0399ed47e6a98f46210cbf2.png" data-type="png" data-w="2226" style="box-sizing: content-box;border-style: none;background-color: rgb(255, 255, 255);"></p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">OpenSergo 提供 Java、Go 等多语言的 SDK,各个框架生态可以非常方便地通过 OpenSergo SDK 来对接 OpenSergo 标准配置,接入到 OpenSergo 生态中,通过 OpenSergo 控制平面 (Control Plane) 统一管理服务治理规则。</p> <h2 style="padding-bottom: 0.3em;margin-top: 24px;margin-bottom: 16px;font-weight: 600;box-sizing: border-box;font-size: 1.5em;line-height: 1.25;border-bottom: 1px solid rgb(234, 236, 239);color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";text-align: start;white-space: normal;">微服务视角的数据库治理是保障服务稳定性的关键一环</h2> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">提到“微服务治理”,很多开发者会首先想到针对微服务之间的调用流量进行治理,但很多时候大家容易忽视掉微服务访问存储与其它中间件的这部分流量。在一个真实的业务生产环境中,流量首先先进入入口网关(如 Nginx、Envoy),再流转到后端 Web Server,再流转到微服务之间的 RPC 调用,再流转到针对数据库、缓存、消息等存储/中间件的访问。在这样一个全链路的架构中,仅仅关注微服务之间的调用是不够的,我们需要针对链路中的每一环分别进行针对性的治理。<strong>其中微服务对数据库的访问是非常普遍的,也是容易出现稳定性问题的一环。</strong>比如:</p> <ul style="padding-left: 2em;margin-bottom: 16px;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;" class="list-paddingleft-1"> <li style="box-sizing: border-box;"><p>某个应用某类报表 SQL 访问量非常大,且查询非常消耗性能,把数据库 CPU 打满</p></li> <li style="margin-top: 0.25em;box-sizing: border-box;"><p>慢 SQL 访问非常多,占满连接池/业务线程池,导致服务无法处理正常请求,甚至导致级联雪崩</p></li> <li style="margin-top: 0.25em;box-sizing: border-box;"><p>连接池参数配置不合理,导致大量 SQL 写操作时无法有效获取连接,业务大量报错</p></li> <li style="margin-top: 0.25em;box-sizing: border-box;"><p>数据库访问需要按环境标进行隔离,比如灰度数据写入到灰度表中</p></li> </ul> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;"><img class="rich_pages wxw-img" data-ratio="0.5432926829268293" src="/upload/4e9fdc05445330619f2d4f8475608b41.png" data-type="png" data-w="3280" style="box-sizing: content-box;border-style: none;background-color: rgb(255, 255, 255);"></p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">对于大多数的后端应用来讲,系统性能扩展的瓶颈主要受限于数据库。尤其在微服务的环境下,数据库的性能治理问题往往也是团队优先级最高的几类工作之一,数据库治理自然也成为微服务治理中必不可少的一环。我们期望开发者可以结合数据库治理能力,来保障微服务访问数据库的稳定性(保护微服务自身不被拖垮),同时也保障数据库的稳定性。</p> <h2 style="padding-bottom: 0.3em;margin-top: 24px;margin-bottom: 16px;font-weight: 600;box-sizing: border-box;font-size: 1.5em;line-height: 1.25;border-bottom: 1px solid rgb(234, 236, 239);color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";text-align: start;white-space: normal;">OpenSergo 联合 ShardingSphere 社区共建数据库治理标准</h2> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">基于以上背景,OpenSergo 社区期望结合企业与开源社区的经验,抽出一套通用的、从微服务视角出发的数据库治理标准规范。ShardingSphere 作为数据库治理领域的标杆项目,沉淀了非常丰富的最佳实践与技术经验,可以很好地为 OpenSergo 补充数据库治理领域的空缺。<span style="box-sizing: border-box;font-weight: 600;color: rgb(255, 104, 39);">因此 OpenSergo 社区联合 ShardingSphere 社区共建微服务视角的数据库治理标准,扩充治理边界,让社区能够以标准化的方式针对不同数据层框架与流量进行统一治理管控,共同推进治理领域技术与生态演进。</span></p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;"><img class="rich_pages wxw-img" data-ratio="0.45657418576598313" src="/upload/212b2f0c81c6a4160bf7d4d83c18008c.png" data-type="png" data-w="3316" style="box-sizing: content-box;border-style: none;background-color: rgb(255, 255, 255);"></p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">对于此次 OpenSergo 与 ShardingSphere 社区之间的合作,双方社区负责人都对此次合作表达了自己的观点:</p> <blockquote style="padding-top: 0px;padding-right: 1em;padding-left: 1em;margin-top: 0px;margin-bottom: 16px;box-sizing: border-box;color: rgb(106, 115, 125);border-left-width: 0.25em;border-left-color: rgb(223, 226, 229);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;"> <p style="box-sizing: border-box;"><span style="box-sizing: border-box;font-weight: 600;color: rgb(255, 104, 39);">Apache ShardingSphere PMC Chair 张亮</span><span style="color: rgb(0, 0, 0);">: 在微服务领域,服务间的交互与协作已日臻完善,而服务对数据库的访问却依然缺失行之有效的标准。ShardingSphere 自开源以来,一直持续不断的践行着“连接、增强、可插拔”的设计哲学。其中,“连接”则是希望提供标准化的协议和接口,打破开发语言访问异构数据库的壁垒。OpenSergo 提出了微服务治理的标准,并首次将数据库的访问放在了标准中,非常具备前瞻性。作为访问数据库重要入口的微服务,我非常希望 ShardingSphere 和 OpenSergo 共建标准。</span></p> </blockquote> <blockquote style="padding-top: 0px;padding-right: 1em;padding-left: 1em;margin-top: 0px;margin-bottom: 16px;box-sizing: border-box;color: rgb(106, 115, 125);border-left-width: 0.25em;border-left-color: rgb(223, 226, 229);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;"> <p style="box-sizing: border-box;"><span style="box-sizing: border-box;font-weight: 600;color: rgb(255, 104, 39);">OpenSergo && Sentinel 社区负责人 赵奕豪(宿何)</span><span style="color: rgb(0, 0, 0);">:在微服务治理领域中,除了微服务本身的治理之外,针对数据库访问的治理也是保障业务可靠性与连续性的关键一环。ShardingSphere 作为数据库治理领域的标杆项目,沉淀了非常丰富的最佳实践与技术经验,可以很好地为 OpenSergo 补充数据库治理领域的空缺。因此我们联合 ShardingSphere 社区共建微服务视角的数据库治理标准,扩充治理边界,期待让社区能够以标准化的方式针对不同数据层框架与流量进行统一治理管控,共同推进治理领域技术与生态演进。</span></p> </blockquote> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">OpenSergo 微服务视角的数据库治理标准主要包括以下几部分:</p> <h3 style="margin-top: 24px;margin-bottom: 16px;font-weight: 600;box-sizing: border-box;font-size: 1.25em;line-height: 1.25;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";text-align: start;white-space: normal;">对数据库 workload 及访问对象的抽象</h3> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">在治理规则中,我们通常需要指定规则作用的数据库实例(或实例组),或者满足的 SQL 条件。针对这一部分,我们在 OpenSergo 数据库治理标准中针对数据库 target workload 及访问对象进行了一些抽象。</p> <ul style="padding-left: 2em;margin-bottom: 16px;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;" class="list-paddingleft-1"> <li style="box-sizing: border-box;"><p><span style="box-sizing: border-box;font-weight: 600;">虚拟数据库 (VirtualDatabase)</span>:在数据库治理中,不管是读写分离、分库分表、影子库,还是加密、审计和访问控制等,都需要作用在一个具体的数据库之上。在这里将这样的一个逻辑的数据库称为虚拟数据库,即 VirtualDatabase。VirtualDatabase 在应用看来是一组特定的数据库访问信息,并通过绑定特定的治理策略实现相应的治理能力</p></li> <li style="margin-top: 0.25em;box-sizing: border-box;"><p><span style="box-sizing: border-box;font-weight: 600;">数据库端点 (DatabaseEndpoint)</span>:在数据库治理中,通过 VirtualDatabase 向应用声明了可以使用的逻辑数据库,而数据的真实存储则依赖于这样的一个物理的数据库,这里称为数据库访问端点,即 DatabaseEndpoint。DatabaseEndpoint 对应用无感知,它只能被 VirtualDatabase 通过特定治理策略所绑定然后连接和使用。</p></li> </ul> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">针对访问对象的条件抽象:</p> <ul style="padding-left: 2em;margin-bottom: 16px;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;" class="list-paddingleft-1"> <li style="box-sizing: border-box;"><p><span style="box-sizing: border-box;font-weight: 600;">数据库访问对象 (DatabaseAccessTarget)</span>:定义一组匹配条件,如针对某个实例/库/表的访问、针对某类 SQL 性质(读/写操作)、按 SQL pattern 匹配、按 SQL 参数匹配等。将 DatabaseAccessTarget 与具体的治理规则结合,我们可以实现细粒度的数据库流量治理。</p></li> </ul> <h3 style="margin-top: 24px;margin-bottom: 16px;font-weight: 600;box-sizing: border-box;font-size: 1.25em;line-height: 1.25;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";text-align: start;white-space: normal;">流量治理在数据库访问的体现</h3> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">在微服务对数据库的访问中,流量路由、流量隔离、流控降级与容错等相关流量治理能力是数据库治理中非常重要的一块。</p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">在流控降级与容错领域,我们复用了 OpenSergo 流控降级与容错标准。OpenSergo 流控降级与容错 spec 定义了三要素:Target(针对怎样的流量)、Strategy(对应怎样的流量治理策略)、FallbackAction(触发策略之后的行为)。在针对数据库访问的治理中,我们将流量条件抽象为 <code style="padding: 0.2em 0.4em;box-sizing: border-box;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;">DatabaseAccessTarget</code>,结合 OpenSergo 自有的流控、并发控制、熔断等策略,即可以实现细粒度的流控降级与容错。</p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;"><img class="rich_pages wxw-img" data-ratio="0.45134383688600554" src="/upload/a747a82407c5772bcd63ee8e2245dfed.png" data-type="png" data-w="2158" style="box-sizing: content-box;border-style: none;background-color: rgb(255, 255, 255);"></p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">同时数据库流量治理体系中还有一些关键的、数据库领域特有的治理能力:</p> <ul style="padding-left: 2em;margin-bottom: 16px;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;" class="list-paddingleft-1"> <li style="box-sizing: border-box;"><p><span style="box-sizing: border-box;font-weight: 600;">读写流量路由 (ReadWriteSplitting)</span>:读写分离是常用的数据库扩展方式之一,主库用于事务性的读写操作,从库主要用于查询等操作。读写流量路由规则可以指定将读 SQL 路由到读库,事务性的读写操作路由到主库。</p></li> <li style="margin-top: 0.25em;box-sizing: border-box;"><p><span style="box-sizing: border-box;font-weight: 600;">分库分表路由 (Sharding)</span>:数据分片路由是基于数据属性一种扩展策略,对数据属性进行计算后将请求路由到特定的数据后端,目前分为分片键分片和自动分片。其中分片键分片中需要指明需要分片的表、列、以及进行分片的算法。</p></li> <li style="margin-top: 0.25em;box-sizing: border-box;"><p><span style="box-sizing: border-box;font-weight: 600;">数据流量隔离 (影子库表 Shadow)</span>:影子库表可以帮助在灰度环境或者测试环境中,接收灰度流量或者测试数据请求,结合影子算法等灵活配置多种路由方式。</p></li> <li style="margin-top: 0.25em;box-sizing: border-box;"><p><span style="box-sizing: border-box;font-weight: 600;">数据加密 (Encryption)</span>:企业往往因为安全审计和合规的要求,需要对数据存储提供多种安全加固措施,比如数据加密。数据加密通过对用户输入的 SQL 进行解析,并依据用户提供的加密规则对 SQL 进行改写,从而实现对原文数据进行加密,并将原文数据(可选)及密文数据同时存储到底层数据库。在用户查询数据时,它仅从数据库中取出密文数据,并对其解密,最终将解密后的原始数据返回给用户。</p></li> </ul> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;"><img class="rich_pages wxw-img" data-ratio="0.2725947521865889" src="/upload/bc4ea933e4fbc9c3d2ad8985e2f9ea88.png" data-type="png" data-w="2744" style="box-sizing: content-box;border-style: none;background-color: rgb(255, 255, 255);"></p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">以下是一个读写流量路由规则的示例:</p> <pre style="padding: 16px;margin-bottom: 16px;box-sizing: border-box;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;overflow-wrap: normal;overflow: auto;line-height: 1.45;background-color: rgb(246, 248, 250);border-radius: 3px;color: rgb(36, 41, 46);text-align: start;"><code style="padding: 0.5em;box-sizing: border-box;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;border-radius: 3px;word-break: normal;border-width: 0px;border-style: initial;border-color: initial;display: block;overflow: auto visible;line-height: inherit;overflow-wrap: normal;"><span style="box-sizing: border-box;color: rgb(153, 153, 136);font-style: italic;"># 虚拟数据库配置</span><br><span style="box-sizing: border-box;">apiVersion:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">database.opensergo.io/v1alpha1</span><br><span style="box-sizing: border-box;">kind:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">VirtualDatabase</span><br><span style="box-sizing: border-box;">metadata:</span><br><span style="box-sizing: border-box;"> name:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">readwrite_splitting_db</span><br><span style="box-sizing: border-box;">spec:</span><br><span style="box-sizing: border-box;"> services:</span><br><span style="box-sizing: border-box;"> - name:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">readwrite_splitting_db</span><br><span style="box-sizing: border-box;"> databaseMySQL:</span><br><span style="box-sizing: border-box;"> db:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">readwrite_splitting_db</span><br><span style="box-sizing: border-box;"> host:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">localhost</span><br><span style="box-sizing: border-box;"> port:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">3306</span><br><span style="box-sizing: border-box;"> user:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">root</span><br><span style="box-sizing: border-box;"> password:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">root</span><br><span style="box-sizing: border-box;"> readWriteSplitting:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">"readwrite"</span> <span style="box-sizing: border-box;color: rgb(153, 153, 136);font-style: italic;"># 声明所需要的读写分离策略</span><br><span style="box-sizing: border-box;color: rgb(153, 153, 153);font-weight: bold;">---</span><br><span style="box-sizing: border-box;color: rgb(153, 153, 136);font-style: italic;"># 写数据源的数据库端点配置</span><br><span style="box-sizing: border-box;">apiVersion:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">database.opensergo.io/v1alpha1</span><br><span style="box-sizing: border-box;">kind:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">DatabaseEndpoint</span><br><span style="box-sizing: border-box;">metadata:</span><br><span style="box-sizing: border-box;"> name:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">write_ds</span><br><span style="box-sizing: border-box;">spec:</span><br><span style="box-sizing: border-box;"> database:</span><br><span style="box-sizing: border-box;"> MySQL:</span> <span style="box-sizing: border-box;color: rgb(153, 153, 136);font-style: italic;"># 声明后端数据源的类型及相关信息</span><br><span style="box-sizing: border-box;"> url:</span> <span style="box-sizing: border-box;">jdbc:mysql://192.168.1.110:3306/demo_write_ds?serverTimezone=UTC&useSSL=false</span><br><span style="box-sizing: border-box;"> username:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">root</span><br><span style="box-sizing: border-box;"> password:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">root</span><br><span style="box-sizing: border-box;"> connectionTimeout:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">30000</span><br><span style="box-sizing: border-box;"> idleTimeoutMilliseconds:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">60000</span><br><span style="box-sizing: border-box;"> maxLifetimeMilliseconds:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">1800000</span><br><span style="box-sizing: border-box;"> maxPoolSize:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">50</span><br><span style="box-sizing: border-box;"> minPoolSize:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">1</span><br><span style="box-sizing: border-box;color: rgb(153, 153, 153);font-weight: bold;">---</span><br><span style="box-sizing: border-box;color: rgb(153, 153, 136);font-style: italic;"># 第一个读数据源的数据库端点配置</span><br><span style="box-sizing: border-box;">apiVersion:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">database.opensergo.io/v1alpha1</span><br><span style="box-sizing: border-box;">kind:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">DatabaseEndpoint</span><br><span style="box-sizing: border-box;">metadata:</span><br><span style="box-sizing: border-box;"> name:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">read_ds_0</span><br><span style="box-sizing: border-box;">spec:</span><br><span style="box-sizing: border-box;"> database:</span><br><span style="box-sizing: border-box;"> MySQL:</span> <span style="box-sizing: border-box;color: rgb(153, 153, 136);font-style: italic;"># 声明后端数据源的类型及相关信息</span><br><span style="box-sizing: border-box;"> url:</span> <span style="box-sizing: border-box;">jdbc:mysql://192.168.1.110:3306/demo_read_ds_0?serverTimezone=UTC&useSSL=false</span><br><span style="box-sizing: border-box;"> username:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">root</span><br><span style="box-sizing: border-box;"> password:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">root</span><br><span style="box-sizing: border-box;"> connectionTimeout:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">30000</span><br><span style="box-sizing: border-box;"> idleTimeoutMilliseconds:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">60000</span><br><span style="box-sizing: border-box;"> maxLifetimeMilliseconds:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">1800000</span><br><span style="box-sizing: border-box;"> maxPoolSize:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">50</span><br><span style="box-sizing: border-box;"> minPoolSize:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">1</span> <br><span style="box-sizing: border-box;color: rgb(153, 153, 153);font-weight: bold;">---</span><br><span style="box-sizing: border-box;color: rgb(153, 153, 136);font-style: italic;"># 第二个读数据源的数据库端点配置</span><br><span style="box-sizing: border-box;">apiVersion:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">database.opensergo.io/v1alpha1</span><br><span style="box-sizing: border-box;">kind:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">DatabaseEndpoint</span><br><span style="box-sizing: border-box;">metadata:</span><br><span style="box-sizing: border-box;"> name:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">read_ds_1</span><br><span style="box-sizing: border-box;">spec:</span><br><span style="box-sizing: border-box;"> database:</span><br><span style="box-sizing: border-box;"> MySQL:</span> <span style="box-sizing: border-box;color: rgb(153, 153, 136);font-style: italic;"># 声明后端数据源的类型及相关信息</span><br><span style="box-sizing: border-box;"> url:</span> <span style="box-sizing: border-box;">jdbc:mysql://192.168.1.110:3306/demo_read_ds_1?serverTimezone=UTC&useSSL=false</span><br><span style="box-sizing: border-box;"> username:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">root</span><br><span style="box-sizing: border-box;"> password:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">root</span><br><span style="box-sizing: border-box;"> connectionTimeout:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">30000</span><br><span style="box-sizing: border-box;"> idleTimeoutMilliseconds:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">60000</span><br><span style="box-sizing: border-box;"> maxLifetimeMilliseconds:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">1800000</span><br><span style="box-sizing: border-box;"> maxPoolSize:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">50</span><br><span style="box-sizing: border-box;"> minPoolSize:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">1</span><br><span style="box-sizing: border-box;color: rgb(153, 153, 153);font-weight: bold;">---</span><br><span style="box-sizing: border-box;color: rgb(153, 153, 136);font-style: italic;"># 静态读写分离配置</span><br><span style="box-sizing: border-box;">apiVersion:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">database.opensergo.io/v1alpha1</span><br><span style="box-sizing: border-box;">kind:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">ReadWriteSplitting</span><br><span style="box-sizing: border-box;">metadata:</span><br><span style="box-sizing: border-box;"> name:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">readwrite</span><br><span style="box-sizing: border-box;">spec:</span><br><span style="box-sizing: border-box;"> rules:</span><br><span style="box-sizing: border-box;"> staticStrategy:</span><br><span style="box-sizing: border-box;"> writeDataSourceName:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">"write_ds"</span><br><span style="box-sizing: border-box;"> readDataSourceNames:</span> <br><span style="box-sizing: border-box;color: rgb(153, 0, 115);"> -</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">"read_ds_0"</span><br><span style="box-sizing: border-box;color: rgb(153, 0, 115);"> -</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">"read_ds_1"</span><br><span style="box-sizing: border-box;"> loadBalancerName:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">"random"</span><br><span style="box-sizing: border-box;"> loadBalancers:</span><br><span style="box-sizing: border-box;"> - loadBalancerName:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">"random"</span><br><span style="box-sizing: border-box;"> type:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">"RANDOM"</span><br></code></pre> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">以下是一个针对某个 SQL 进行并发控制的示例。这个规则会针对 foo 应用针对 <code style="padding: 0.2em 0.4em;box-sizing: border-box;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;background-color: rgba(27, 31, 35, 0.05);border-radius: 3px;">SELECT * FROM users WHERE id = ?</code> 的 SQL 访问进行并发控制,单机并发数不超过 8。</p> <pre style="padding: 16px;margin-bottom: 16px;box-sizing: border-box;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;font-size: 13.6px;overflow-wrap: normal;overflow: auto;line-height: 1.45;background-color: rgb(246, 248, 250);border-radius: 3px;color: rgb(36, 41, 46);text-align: start;"><code style="padding: 0.5em;box-sizing: border-box;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;border-radius: 3px;word-break: normal;border-width: 0px;border-style: initial;border-color: initial;display: block;overflow: auto visible;line-height: inherit;overflow-wrap: normal;"><span style="box-sizing: border-box;">apiVersion:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">traffic.opensergo.io/v1alpha1</span><br><span style="box-sizing: border-box;">kind:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">DatabaseAccessTarget</span><br><span style="box-sizing: border-box;">metadata:</span><br><span style="box-sizing: border-box;"> name:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">target-foo-user-select-sql</span><br><span style="box-sizing: border-box;">spec:</span><br><span style="box-sizing: border-box;"> sqlMatch:</span><br><span style="box-sizing: border-box;"> - exactMatch:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">"SELECT * FROM users WHERE id = ?"</span><br><span style="box-sizing: border-box;color: rgb(153, 153, 153);font-weight: bold;">---</span><br><span style="box-sizing: border-box;">apiVersion:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">fault-tolerance.opensergo.io/v1alpha1</span><br><span style="box-sizing: border-box;">kind:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">ConcurrencyLimitStrategy</span><br><span style="box-sizing: border-box;">metadata:</span><br><span style="box-sizing: border-box;"> name:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">concurrency-limit-foo</span><br><span style="box-sizing: border-box;">spec:</span><br><span style="box-sizing: border-box;"> maxConcurrency:</span> <span style="box-sizing: border-box;color: rgb(0, 128, 128);">8</span><br><span style="box-sizing: border-box;"> limitMode:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">'Local'</span><br><span style="box-sizing: border-box;color: rgb(153, 153, 153);font-weight: bold;">---</span><br><span style="box-sizing: border-box;">apiVersion:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">fault-tolerance.opensergo.io/v1alpha1</span><br><span style="box-sizing: border-box;">kind:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">FaultToleranceRule</span><br><span style="box-sizing: border-box;">metadata:</span><br><span style="box-sizing: border-box;"> name:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">my-sql-conc-limit-rule</span><br><span style="box-sizing: border-box;">spec:</span><br><span style="box-sizing: border-box;"> selector:</span><br><span style="box-sizing: border-box;"> app:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">foo</span><br><span style="box-sizing: border-box;"> targets:</span><br><span style="box-sizing: border-box;"> - targetRef:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">target-foo-user-select-sql</span><br><span style="box-sizing: border-box;"> strategies:</span> <br><span style="box-sizing: border-box;"> - name:</span> <span style="box-sizing: border-box;color: rgb(221, 17, 68);">concurrency-limit-foo</span><br></code></pre> <h3 style="margin-top: 24px;margin-bottom: 16px;font-weight: 600;box-sizing: border-box;font-size: 1.25em;line-height: 1.25;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";text-align: start;white-space: normal;">其它数据库治理能力</h3> <ul style="padding-left: 2em;margin-bottom: 16px;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;" class="list-paddingleft-1"> <li style="box-sizing: border-box;"><p><span style="box-sizing: border-box;font-weight: 600;">数据库发现 (DatabaseDiscovery)</span>:数据库自动发现指的是根据数据库高可用配置,通过探测的方式感知数据源状态变化,并对流量策略做出相应的调整。比如后端数据源为 MySQL MGR,那么可以配置数据库发现类型为 MYSQL.MGR,指定 group-name,并配置相应的探测心跳节律。</p></li> <li style="margin-top: 0.25em;box-sizing: border-box;"><p><span style="box-sizing: border-box;font-weight: 600;">分布式事务配置 (DistributedTransaction)</span>:声明分布式事务相关的配置,目前支持声明事务的类型。</p></li> </ul> <h2 style="padding-bottom: 0.3em;margin-top: 24px;margin-bottom: 16px;font-weight: 600;box-sizing: border-box;font-size: 1.5em;line-height: 1.25;border-bottom: 1px solid rgb(234, 236, 239);color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";text-align: start;white-space: normal;">展望</h2> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">微服务视角的数据库治理是保障微服务稳定性的重要一环。OpenSergo 社区将持续与 ShardingSphere 及 Database Mesh 社区进行合作,不断完善与丰富数据库治理标准及场景。接下来社区会开展 ShardingSphere 与 OpenSergo 的集成工作,将数据库治理 spec 落地到社区实现。</p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">微服务治理是微服务改造深入到一定阶段之后的必经之路,是将微服务做稳做好的关键。OpenSergo 社区持续与 ShardingSphere、Database Mesh、CloudWeGo、Kratos、Spring Cloud Alibaba、Dubbo 等社区共同建设 OpenSergo 微服务治理标准,将企业与社区中微服务治理的场景与最佳实践共同提取成标准规范,也欢迎更多社区与企业一起参与 OpenSergo 微服务治理标准的共建。</p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">OpenSergo 社区现在处于高速发展阶段,从微服务治理标准定义,到 Control Plane 的实现,再到 Java/Go/C++/Rust 等多语言 SDK 与治理功能的实现,再到各个微服务生态的整合与落地,都还有大量的演进工作,欢迎社区一起参与标准完善与代码贡献。</p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;"><img class="rich_pages wxw-img" data-ratio="0.2858942065491184" src="/upload/7c2bb7c3833669d6b617431a6ae7d768.png" data-type="png" data-w="3176" style="box-sizing: content-box;border-style: none;background-color: rgb(255, 255, 255);"></p> <p style="margin-bottom: 16px;box-sizing: border-box;color: rgb(36, 41, 46);font-family: -apple-system, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;"><span style="color: rgb(255, 104, 39);"><strong>OpenSergo 开源贡献小组正在火热招募贡献者</strong></span><strong>。</strong>如果您有时间,有热情,有意愿,欢迎联系社区加入开源贡献小组,一起共同完善 OpenSergo 和 Sentinel,一起主导微服务治理技术与标准演进。Now let's start hacking!</p> <section class="mp_profile_iframe_wrp"> <mp-common-profile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzI2NzAwNTMwNQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/Eg8NzgBfvFpTpfVXVKAW86TNuuAOLh816Ga420O56eM0fNnvib1QpRjrS56cqmw1PwdBicQ5JEL6gTfKY0MNnChQ/0?wx_fmt=png" data-nickname="OpenSergo" data-alias="OpenSergo" data-signature="OpenSergo: 开放的微服务治理标准与最佳实践" data-from="0" data-is_biz_ban="0"></mp-common-profile> </section> <section style="text-align: left;"> 相关链接: <br> </section> <ul class="list-paddingleft-1" style="list-style-type: disc;"> <li> <section style="text-align: left;"> OpenSergo 项目官网: <span style="color: rgb(2, 30, 170);">https://opensergo.io/zh-cn/</span> </section></li> <li> <section style="text-align: left;"> Apache ShardingSphere 项目官网: <span style="color: rgb(2, 30, 170);">https://shardingsphere.apache.org/</span> </section></li> </ul> <section style="text-align: left;"> <span style="color: rgb(2, 30, 170);"></span> </section> <section style="text-align: left;"> <span style="color: rgb(2, 30, 170);"><span style="color: rgb(28, 30, 33);font-family: system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;">点击了解 OpenSergo 微服务治理社区 10月动态:</span><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzI2NzAwNTMwNQ==&mid=2458112382&idx=1&sn=de7d7b2b740a9b6da907e4eb77ce318f&chksm=fdf20d68ca85847ece9bd08d038d7dd9dc6c7cff3dd17b4961437d1734c1ff1bf0c44c8bb232&scene=21#wechat_redirect" textvalue="Go 生态支持、流量染色... OpenSergo 10月最新动态来啦!" linktype="text" imgurl="" imgdata="null" data-itemshowtype="0" tab="innerlink" data-linktype="2" style="font-family: system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell, "Noto Sans", sans-serif, "system-ui", "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size: 16px;text-align: start;white-space: normal;">Go 生态支持、流量染色... OpenSergo 10月最新动态来啦!</a></span> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;text-align: left;padding: 5px;font-size: 16px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">目前nacos越来越广泛,大多数的企业在使用微服务架构的时候,基本上都会选择nacos作为注册中心和配置中心。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">那nacos其实也是阿里开源的一个项目,存在漏洞,至少难免的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">那我们今天就来分享一下nacos存在的漏洞问题,主要是一些安全漏洞的问题。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">毕竟现在很多政务的项目,都会做等保测试这块。等保做得多了,漏洞也就多了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这不,今天就又有一个漏洞了。那就开始修复喽!!!</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.6129032258064516" src="/upload/4429c37b4b8737bb4490010c9a37e32c.png" data-type="png" data-w="372" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(234, 84, 41);letter-spacing: 0.5444px;padding-bottom: 10px;border-bottom: 2px solid rgb(234, 84, 41);visibility: visible;">1.nacos权限绕过漏洞</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">详情可查看nacos官网:https%3A%2F%2Fnacos.io%2Fzh-cn%2Fdocs%2Fauth.html</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.5" src="/upload/fff7ac38c8d2d326a56194d2c935587e.png" data-type="png" data-w="912" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这个漏洞是在nacos已经开启账号密码访问的时候,当header添加了user-agent:Nacos-Server时,就会绕过权限访问,直接获取到nacos配置等信息。关注公众号:码猿技术专栏,回复关键:1111 获取阿里内部Java调优手册</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">nacos版本:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">1.4.2</code></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">详情如下:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">不加账号密码访问(403)</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.4713275726630008" src="/upload/32b098198fb8c1a7d7a5b45637d9672.png" data-type="png" data-w="1273" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">添加账号密码访问(正常)</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.5689243027888446" src="/upload/6b768671b4126dff6a395ce4d68058e1.png" data-type="png" data-w="1255" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">不加账号密码访问,但添加header(正常)</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.3717504332755633" src="/upload/3a7c2848bcf8beb05d2b2e1daab400f5.png" data-type="png" data-w="1154" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.5055205047318612" src="/upload/8b5970efd09802ce1a6944212ea668d9.png" data-type="png" data-w="1268" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);border-left-width: 2px;padding: 8px 10px 8px 15px;background: rgb(255, 249, 249);border-left-color: rgb(239, 112, 96);margin-top: 0px;margin-bottom: 20px;letter-spacing: 0.5444px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(53, 53, 53);font-size: 16px;margin-right: 10px;margin-left: 10px;">由此可见,header加上<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">user-agent:Nacos-Server</code>,确实能绕过nacos认证。</p> </blockquote> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(234, 84, 41);letter-spacing: 0.5444px;padding-bottom: 10px;border-bottom: 2px solid rgb(234, 84, 41);visibility: visible;">2.漏洞修复</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">升级到nacos目前最新版:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">2.1.1</code></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">下载地址:https%3A%2F%2Fnacos.io%2Fzh-cn%2Fdocs%2Fquick-start.html</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.5975073313782991" src="/upload/71b5562836515f1993f1fb94048c48b2.png" data-type="png" data-w="1364" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.45551894563426687" src="/upload/2dec0c712a3fee1672c8c8a46f34b5b5.png" data-type="png" data-w="1214" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">下载地址:https%3A%2F%2Fgithub.com%2Falibaba%2Fnacos%2Freleases%2Fdownload%2F2.1.1%2Fnacos-server-2.1.1.zip</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">从<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">1.4.2</code>升级到<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">2.1.1</code>,nacos官网有详细的文档说明:https%3A%2F%2Fnacos.io%2Fzh-cn%2Fdocs%2F2.0.0-upgrading.html</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">对于我们现在的环境升级,这里记录下注意的事项:</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">2.1 nacos配置文件的修改</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">vi nacos/conf/application.properties</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oey2F0JZ6AzlEoZRh4QA35sH93ocZtOu7ZA3jNtVG9sFzmvOtofiaia29vT3MphkXk9aLKzTFqu2R7GutjDRDznTt1/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(255, 255, 255);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: black;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fff;border-radius: 5px;">#122行<br>server.tomcat.basedir=file:.<br><br>#148行<br>nacos.core.auth.enable.userAgentAuthWhite=false<br>nacos.core.auth.server.identity.key=serverIdentity<br>nacos.core.auth.server.identity.value=security<br></code></pre> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);border-left-width: 2px;padding: 8px 10px 8px 15px;background: rgb(255, 249, 249);border-left-color: rgb(239, 112, 96);margin-top: 0px;margin-bottom: 20px;letter-spacing: 0.5444px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(53, 53, 53);font-size: 16px;margin-right: 10px;margin-left: 10px;">这里要修改成这个,否则启动报错。</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">2.2 nacos数据库修改</span><span style="display: none;"></span></h3> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oey2F0JZ6AzlEoZRh4QA35sH93ocZtOu7ZA3jNtVG9sFzmvOtofiaia29vT3MphkXk9aLKzTFqu2R7GutjDRDznTt1/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(255, 255, 255);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: black;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fff;border-radius: 5px;"><span style="color: #007400;line-height: 26px;">/*config_info表增加字段*/</span><br><span style="color: #aa0d91;line-height: 26px;">ALTER</span> <span style="color: #aa0d91;line-height: 26px;">TABLE</span> jxbp_nacos.config_info <span style="color: #aa0d91;line-height: 26px;">ADD</span> <span style="color: #aa0d91;line-height: 26px;">COLUMN</span> encrypted_data_key <span style="color: #5c2699;line-height: 26px;">text</span> <span style="color: #aa0d91;line-height: 26px;">NULL</span> <span style="color: #aa0d91;line-height: 26px;">COMMENT</span> <span style="color: #c41a16;line-height: 26px;">'秘钥'</span>;<br><br><span style="color: #007400;line-height: 26px;">/*his_config_info表增加字段*/</span><br><span style="color: #aa0d91;line-height: 26px;">ALTER</span> <span style="color: #aa0d91;line-height: 26px;">TABLE</span> jxbp_nacos.his_config_info <span style="color: #aa0d91;line-height: 26px;">ADD</span> <span style="color: #aa0d91;line-height: 26px;">COLUMN</span> encrypted_data_key <span style="color: #5c2699;line-height: 26px;">text</span> <span style="color: #aa0d91;line-height: 26px;">NULL</span> <span style="color: #aa0d91;line-height: 26px;">COMMENT</span> <span style="color: #c41a16;line-height: 26px;">'秘钥'</span>;<br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">2.3 nacos启动后测试</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">不加账号密码访问,但添加header(403)</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.3426763110307414" src="/upload/a0b85b6eba3a7cff809f426dcdcc482c.png" data-type="png" data-w="1106" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.5918181818181818" src="/upload/4c5600c6f693ded9aab9f56a41858041.png" data-type="png" data-w="1100" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);border-left-width: 2px;padding: 8px 10px 8px 15px;background: rgb(255, 249, 249);border-left-color: rgb(239, 112, 96);margin-top: 0px;margin-bottom: 20px;letter-spacing: 0.5444px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(53, 53, 53);font-size: 16px;margin-right: 10px;margin-left: 10px;">由此可见,该漏洞已被修复</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">加账号密码访问,不添加header(正常)</span></p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.6034172661870504" src="/upload/f3907fb934d42df2122d5a88e2e7b3ec.png" data-type="png" data-w="1112" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);border-left-width: 2px;padding: 8px 10px 8px 15px;background: rgb(255, 249, 249);border-left-color: rgb(239, 112, 96);margin-top: 0px;margin-bottom: 20px;letter-spacing: 0.5444px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: rgb(53, 53, 53);font-size: 16px;margin-right: 10px;margin-left: 10px;">经测试,正常了。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">注意:</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">当然<span style="font-weight: 700;color: rgb(248, 57, 41);">不想升级的话</span>,也是可以的,直接在<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">1.4.2</code>的基础上对配置文件进行修改:</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">vi nacos/conf/application.properties</code></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oey2F0JZ6AzlEoZRh4QA35sH93ocZtOu7ZA3jNtVG9sFzmvOtofiaia29vT3MphkXk9aLKzTFqu2R7GutjDRDznTt1/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(255, 255, 255);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: black;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fff;border-radius: 5px;">#148行<br>nacos.core.auth.enable.userAgentAuthWhite=false<br>nacos.core.auth.server.identity.key=serverIdentity<br>nacos.core.auth.server.identity.value=security<br></code></pre> <hr data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;height: 1px;border-width: initial;border-style: none;border-color: initial;text-align: center;background-image: linear-gradient(to right, rgba(248, 57, 41, 0), rgba(248, 57, 41, 0.75), rgba(248, 57, 41, 0));"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">看到这里,是不是觉得自己折腾了大半天,最终解决的方式,还有更简单的方法。</p> </section>
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;text-align: left;padding: 5px;font-size: 16px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;" data-mpa-powered-by="yiban.io"> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(234, 84, 41);letter-spacing: 0.5444px;padding-bottom: 10px;border-bottom: 2px solid rgb(234, 84, 41);visibility: visible;">编译</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">简单就是把代码跑一哈,然后我们的代码 .java文件 就被编译成了 .class 文件</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.3788135593220339" src="/upload/4992a213dd42d4493d6be3ab91fac182.png" data-type="png" data-w="1180" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(234, 84, 41);letter-spacing: 0.5444px;padding-bottom: 10px;border-bottom: 2px solid rgb(234, 84, 41);visibility: visible;">反编译</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">就是针对编译生成的 jar/war 包 里面的 .class 文件 逆向还原回来,可以看到你的代码写的啥。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">比较常用的反编译工具 JD-GUI ,直接把编译好的jar丢进去,大部分都能反编译看到源码:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.6442542787286064" src="/upload/849884626d7ad574cce423eb11601401.png" data-type="png" data-w="818" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">那如果不想给别人反编译看自己写的代码呢?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">怎么做?</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(234, 84, 41);letter-spacing: 0.5444px;padding-bottom: 10px;border-bottom: 2px solid rgb(234, 84, 41);visibility: visible;">混淆</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">该篇玩的代码混淆 ,是其中一种手段。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">我给你看,但你反编译看到的不是真正的代码。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">先看一张效果示例图 :</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.46729857819905213" src="/upload/edb372d0afa236c932bca2ad8a3c8211.png" data-type="png" data-w="1055" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">开搞</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(234, 84, 41);letter-spacing: 0.5444px;padding-bottom: 10px;border-bottom: 2px solid rgb(234, 84, 41);visibility: visible;">正文</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">先看一下我们混淆一个项目代码,要做啥?</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="1.7215909090909092" src="/upload/68fa80c46b2dfcf85d585eaf0ba91648.png" data-type="png" data-w="352" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">一共就两步</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">第一步, 在项目路径下,新增一份文件 proguard.cfg :</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">proguard.cfg</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oey2F0JZ6AzlEj3eibI0KbfIwN4tLvhaAmsccia7O0Lia70Zs05xeRHIXcNjpovH5Ptkzee90XUATkx37y2aSMxVQX7/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(255, 255, 255);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: black;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fff;border-radius: 5px;"><span style="color: #643820;line-height: 26px;">#</span><span style="line-height: 26px;">指定Java的版本</span><br>-target 1.8<br><span style="color: #643820;line-height: 26px;">#</span><span style="line-height: 26px;">proguard会对代码进行优化压缩,他会删除从未使用的类或者类成员变量等</span><br>-dontshrink<br><span style="color: #643820;line-height: 26px;">#</span><span style="line-height: 26px;">是否关闭字节码级别的优化,如果不开启则设置如下配置</span><br>-dontoptimize<br><span style="color: #643820;line-height: 26px;">#</span><span style="line-height: 26px;">混淆时不生成大小写混合的类名,默认是可以大小写混合</span><br>-dontusemixedcaseclassnames<br><span style="color: #643820;line-height: 26px;">#</span><span style="line-height: 26px;"> 对于类成员的命名的混淆采取唯一策略</span><br>-useuniqueclassmembernames<br><span style="color: #643820;line-height: 26px;">#</span><span style="line-height: 26px;">混淆时不生成大小写混合的类名,默认是可以大小写混合</span><br>-dontusemixedcaseclassnames<br><span style="color: #643820;line-height: 26px;">#</span><span style="line-height: 26px;">混淆类名之后,对使用Class.forName(<span style="color: #c41a16;line-height: 26px;">'className'</span>)之类的地方进行相应替代</span><br>-adaptclassstrings<br><span style="color: #643820;line-height: 26px;"> <br>#</span><span style="line-height: 26px;">对异常、注解信息予以保留</span><br>-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod<br><span style="color: #643820;line-height: 26px;">#</span><span style="line-height: 26px;"> 此选项将保存接口中的所有原始名称(不混淆)--></span><br>-keepnames interface ** { *; }<br><span style="color: #643820;line-height: 26px;">#</span><span style="line-height: 26px;"> 此选项将保存所有软件包中的所有原始接口文件(不进行混淆)</span><br><span style="color: #643820;line-height: 26px;">#</span><span style="line-height: 26px;">-keep interface * extends * { *; }</span><br><span style="color: #643820;line-height: 26px;">#</span><span style="line-height: 26px;">保留参数名,因为控制器,或者Mybatis等接口的参数如果混淆会导致无法接受参数,xml文件找不到参数</span><br>-keepparameternames<br><span style="color: #643820;line-height: 26px;">#</span><span style="line-height: 26px;"> 保留枚举成员及方法</span><br>-keepclassmembers enum * { *; }<br><span style="color: #643820;line-height: 26px;">#</span><span style="line-height: 26px;"> 不混淆所有类,保存原始定义的注释-</span><br>-keepclassmembers class * {<br> @org.springframework.context.annotation.Bean *;<br> @org.springframework.beans.factory.annotation.Autowired *;<br> @org.springframework.beans.factory.annotation.Value *;<br> @org.springframework.stereotype.Service *;<br> @org.springframework.stereotype.Component *;<br> }<br><span style="color: #643820;line-height: 26px;"> <br>#</span><span style="line-height: 26px;">忽略warn消息</span><br>-ignorewarnings<br><span style="color: #643820;line-height: 26px;">#</span><span style="line-height: 26px;">忽略note消息</span><br>-dontnote<br><span style="color: #643820;line-height: 26px;">#</span><span style="line-height: 26px;">打印配置信息</span><br>-printconfiguration<br>-keep public class com.example.myproguarddemo.MyproguarddemoApplication {<br> public static void main(java.lang.String[]);<br> }<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">注意点:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.5777988614800759" src="/upload/b88c67c70a65c57dc4739a249904c0c5.png" data-type="png" data-w="1054" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">其余的看注释,可以配置哪些类不参与混淆,哪些枚举保留,哪些方法名不混淆等等。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">第二步,在pom文件上 加入proguard 混淆插件 :</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">build标签里面改动加入一下配置</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oey2F0JZ6AzlEj3eibI0KbfIwN4tLvhaAmsccia7O0Lia70Zs05xeRHIXcNjpovH5Ptkzee90XUATkx37y2aSMxVQX7/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(255, 255, 255);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: black;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fff;border-radius: 5px;"><span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">build</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">plugins</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">plugin</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">groupId</span>></span>com.github.wvengen<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">groupId</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">artifactId</span>></span>proguard-maven-plugin<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">artifactId</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">version</span>></span>2.6.0<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">version</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">executions</span>></span><br> <span style="color: #007400;line-height: 26px;"><!-- 以下配置说明执行mvn的package命令时候,会执行proguard--></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">execution</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">phase</span>></span>package<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">phase</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">goals</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">goal</span>></span>proguard<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">goal</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">goals</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">execution</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">executions</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">configuration</span>></span><br> <span style="color: #007400;line-height: 26px;"><!-- 就是输入Jar的名称,我们要知道,代码混淆其实是将一个原始的jar,生成一个混淆后的jar,那么就会有输入输出。 --></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">injar</span>></span>${project.build.finalName}.jar<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">injar</span>></span><br> <span style="color: #007400;line-height: 26px;"><!-- 输出jar名称,输入输出jar同名的时候就是覆盖,也是比较常用的配置。 --></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">outjar</span>></span>${project.build.finalName}.jar<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">outjar</span>></span><br> <span style="color: #007400;line-height: 26px;"><!-- 是否混淆 默认是true --></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">obfuscate</span>></span>true<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">obfuscate</span>></span><br> <span style="color: #007400;line-height: 26px;"><!-- 配置一个文件,通常叫做proguard.cfg,该文件主要是配置options选项,也就是说使用proguard.cfg那么options下的所有内容都可以移到proguard.cfg中 --></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">proguardInclude</span>></span>${project.basedir}/proguard.cfg<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">proguardInclude</span>></span><br> <span style="color: #007400;line-height: 26px;"><!-- 额外的jar包,通常是项目编译所需要的jar --></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">libs</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">lib</span>></span>${java.home}/lib/rt.jar<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">lib</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">lib</span>></span>${java.home}/lib/jce.jar<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">lib</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">lib</span>></span>${java.home}/lib/jsse.jar<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">lib</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">libs</span>></span><br> <span style="color: #007400;line-height: 26px;"><!-- 对输入jar进行过滤比如,如下配置就是对META-INFO文件不处理。 --></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">inLibsFilter</span>></span>!META-INF/**,!META-INF/versions/9/**.class<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">inLibsFilter</span>></span><br> <span style="color: #007400;line-height: 26px;"><!-- 这是输出路径配置,但是要注意这个路径必须要包括injar标签填写的jar --></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">outputDirectory</span>></span>${project.basedir}/target<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">outputDirectory</span>></span><br> <span style="color: #007400;line-height: 26px;"><!--这里特别重要,此处主要是配置混淆的一些细节选项,比如哪些类不需要混淆,哪些需要混淆--></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">options</span>></span><br> <span style="color: #007400;line-height: 26px;"><!-- 可以在此处写option标签配置,不过我上面使用了proguardInclude,故而我更喜欢在proguard.cfg中配置 --></span><br> <span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">options</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">configuration</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">plugin</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">plugin</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">groupId</span>></span>org.springframework.boot<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">groupId</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">artifactId</span>></span>spring-boot-maven-plugin<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">artifactId</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">executions</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">execution</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">goals</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">goal</span>></span>repackage<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">goal</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">goals</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">configuration</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"><<span style="line-height: 26px;">mainClass</span>></span>com.example.myproguarddemo.MyproguarddemoApplication<span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">mainClass</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">configuration</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">execution</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">executions</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">plugin</span>></span><br> <span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">plugins</span>></span><br><span style="color: #aa0d91;line-height: 26px;"></<span style="line-height: 26px;">build</span>></span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">注意点:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.13383458646616542" src="/upload/c41cb8ee79036cc7a8e7680ec5ea1274.png" data-type="png" data-w="665" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.3795534665099882" src="/upload/2b782d5053e538cf2dc3525815f5a395.png" data-type="png" data-w="851" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">然后可以看到:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="1.3373205741626795" src="/upload/949291388891debd4295c43e5a451446.png" data-type="png" data-w="418" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">然后点击package,正常执行编译打包流程就可以 :</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.4485887096774194" src="/upload/5f2144b87e3ee78cce827cbe1d0218b1.png" data-type="png" data-w="992" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">然后可以看到jar的生成:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.539553752535497" src="/upload/a23c3b55689b8a2c747ad867d4a46d99.png" data-type="png" data-w="493" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">看看效果:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;border-radius: 16px;overflow: hidden;"> <img class="rich_pages wxw-img" data-ratio="0.6295843520782396" src="/upload/bb0c12ce4e56d6bce7145918755d340e.png" data-type="png" data-w="818" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">好了,该篇就到这。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;text-align: right;"><span style="color: rgb(178, 178, 178);font-size: 14px;">来源:https://blog.csdn.net/qq_35387940</span></p> </section>
作者:微信小助手
<section class="mp_profile_iframe_wrp" data-mpa-powered-by="yiban.io"> <mp-common-profile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzkyNTI5NTQ1NQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/wxcY9TH8dPsYAnrjaZktBe0iahF8ic9QkF26cAw8pK6HPR1bfFEImdyJspvkQvQwmnYxP4eEVW60ewVVickcWXnrQ/0?wx_fmt=png" data-nickname="架构文摘" data-alias="ArchDigest" data-signature="每天一篇架构领域重磅好文,涉及一线互联网公司应用架构(高可用、高性能、高稳定)、大数据、机器学习、Java架构等各个热门领域。" data-from="0" data-is_biz_ban="0"></mp-common-profile> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding: 0px 10px;line-height: 1.6;word-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;margin-bottom: 24px;"> <span style="color:#000000;font-family:Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, PingFang SC, Cambria, Cochin, Georgia, Times, Times New Roman, serif;"><span style="font-size: 16px;letter-spacing: 0px;justify-content: center;align-items: center;"> <figure data-tool="mdnice编辑器" style="margin: 0;margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"></figure></span></span> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;"><span style="letter-spacing: 0px;">其实实现短链服务并不是很难,最主要还是需要知道一些设计思路,还需要有一些基础技术知识,例如:</span><span style="letter-spacing: 0px;">哈希算法、全局发号器等。</span></p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">下面一起来学习如何设计一个短链服务吧!</p> <h2 data-tool="mdnice编辑器" style="color: rgb(0, 13, 131);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 22px;letter-spacing: 5px;margin-top: 30px;margin-bottom: 15px;font-weight: bold;padding: 20px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/AVWicyZuuClHY9LkyFGYJYL1Xib6HGM0P5dfMffgkZ2LqKbJXnia2R5JbRuau1vf2Zpy1g7kvq4OiaaMuqoIpagqFA/640?wx_fmt=png");background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-position: center -10px;background-size: 150px;"><span style="padding-bottom: 12px;border-bottom: 2px solid #000d83;">短链的价值</span></h2> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">网址大家都知道,很长的一串字符串,很多时候我们还会在后面添加非常多的参数,用来便于做数据统计。下面就是微信公众号一篇文章的地址,可以看到其特别长,估计将近有几百个字符。</p> <pre data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">https://mp.weixin.qq.com/s?__biz=MzA4MjIyNTY0MQ==&mid=2647743787&idx=1&sn=1caec8eb1b81d6ee5dd7ba7fa05ac0f1&chksm=87ad0dadb0da84bb7beb5e4373a14e89fba1130c1bd2a51f4baa8021ec0abe496ce94603b6b4&token=894028224&lang=zh_CN<span style="color: #5c6370;font-style: italic;line-height: 26px;">#rd</span><br></code></pre> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">我们可以用百度的短网址功能,把上面的网址缩短成只有差不多 10 个字符串的长度,如下所示。</p> <pre data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">http://dwz.cn/iijg<br></code></pre> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">用短链代替长链,有下面几个常见的好处:</p> <ol data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: decimal;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <strong style="font-weight: bold;color: black;">更加简洁。</strong> 比起一长串无意义的问题,只有差不多 10 个字符的字符串显然更加简洁。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <strong style="font-weight: bold;color: black;">便于使用。</strong> 第一,有些平台对内容长度有限制(微博只能发 140 个字),此时短网址就可以输入更多内容。第二,我们将链接转为二维码时,短链接生成的二维码更容易识别。第三,有些平台无法识别特殊的长链参数,转为短链就没这个问题。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <strong style="font-weight: bold;color: black;">节省成本。</strong> 当我们需要发短信的时候,短信是按照长度计费的,短网址可以节省成本。 </section></li> </ol> <h2 data-tool="mdnice编辑器" style="color: rgb(0, 13, 131);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 22px;letter-spacing: 5px;margin-top: 30px;margin-bottom: 15px;font-weight: bold;padding: 20px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/AVWicyZuuClHY9LkyFGYJYL1Xib6HGM0P5dfMffgkZ2LqKbJXnia2R5JbRuau1vf2Zpy1g7kvq4OiaaMuqoIpagqFA/640?wx_fmt=png");background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-position: center -10px;background-size: 150px;"><span style="padding-bottom: 12px;border-bottom: 2px solid #000d83;">短链的原理</span></h2> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">短链能够给我们带来这么多好处,但它是怎么工作的呢?</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;"><strong style="font-weight: bold;color: black;">当我们输入短链时,其实访问的是短链服务器的地址。短链服务器获取到对应的长链地址之后,返回一个 302 的 HTTP 响应,在响应中包含了长链接地址。浏览器收到响应后,转而去请求长链接地址。</strong> 访问短链的整个流程如下图所示:</p> <figure data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin: 10px 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.5660749506903353" src="/upload/3684016dfd3e8b10e352ea7390043751.jpg" data-type="jpeg" data-w="507" style="display: block;margin: 0 auto;max-width: 100%;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> 短链访问原理 - 来自网络 </figcaption> </figure> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">从上面的流程中可以知道,短链涉及到的技术原理主要有两点,分别是:<strong style="font-weight: bold;color: black;">HTTP 重定向和短链服务的设计。</strong></p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">对于 HTTP 重定向来说,301 和 302 都是重定向,那么到底应该用哪个呢?</p> <ul data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: disc;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 301 代表永久重定向。它表示第一次拿到长链接之后,下次浏览器如果再去请求短链的话,不会再向短链服务器请求了,而是直接从浏览器的缓存中获取。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 302 代表临时重定向。它表示每次请求短链都会去请求短链服务器,不会从浏览器缓存中获取。微信搜索公众号:Java后端编程,回复:java 领取资料 。 </section></li> </ul> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;"><strong style="font-weight: bold;color: black;">如果我们希望统计短链接的点击次数信息,从而来分析活动的效果的话。那么我们就需要使用 302 重定向码,这样才能获取到每次的请求数据。</strong> 一般情况下,我们都是需要获取到请求的数据的,因此对于短链服务都是用 302 临时重定向。</p> <h2 data-tool="mdnice编辑器" style="color: rgb(0, 13, 131);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 22px;letter-spacing: 5px;margin-top: 30px;margin-bottom: 15px;font-weight: bold;padding: 20px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/AVWicyZuuClHY9LkyFGYJYL1Xib6HGM0P5dfMffgkZ2LqKbJXnia2R5JbRuau1vf2Zpy1g7kvq4OiaaMuqoIpagqFA/640?wx_fmt=png");background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-position: center -10px;background-size: 150px;"><span style="padding-bottom: 12px;border-bottom: 2px solid #000d83;">实现思路</span></h2> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">让大家设计这样一个系统,大家会有啥思路呢?</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">我们可以先分析一下整个系统的处理流程:</p> <ol data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: decimal;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 用户访问短链生成页面,输入长链字符串,短链服务返回生成的短链。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 用户访问短链,短链服务返回 302 响应,用户浏览器跳转到长链地址。 </section></li> </ol> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">如果我们要实现上面的系统流程,我们大致的处理思路是:</p> <ol data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: decimal;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <strong style="font-weight: bold;color: black;">生成短链。</strong> 生成短链时,短链服务获取到长链,随后生成一个短链,并把短链与长链的映射关系保存下来,最后将短链返回给用户。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <strong style="font-weight: bold;color: black;">找到长链。</strong> 访问短链时,短链服务获取到短链,根据短链去获取到长链,返回返回 302 响应。 </section></li> </ol> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">根据上面的分析,我们可以知道短链系统设计主要得解决如下两个问题:</p> <ol data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: decimal;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 如何根据长链生成唯一短链? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 如何保存短链与长链的映射关系? </section></li> </ol> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">对于第 2 点,保存短链与长链的映射关系,考虑到持久性的问题,我们肯定需要落库,所以使用 MySQL 表保存即可。<span style="letter-spacing: 0px;">如果有需要的话,可以在 MySQL 前做一层缓存。</span><span style="letter-spacing: 0px;">因此第 2 点相对来说比较简单。</span></p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">对于第 1 点,我们有 2 个思路生成一个唯一短链,分别是:</p> <ol data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: decimal;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 使用哈希算法生成唯一值 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 使用分布式唯一 ID 生成作为锻炼 ID </section></li> </ol> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">下面我们针对这两个方案进行详细的分析。</p> <h3 data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 20px;letter-spacing: 0px;margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;">哈希算法生成短链</h3> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">要生成一个短链,我们可以将原有的长链做一次哈希,然后就可以得到一个哈希值,如下面所示。</p> <pre data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">https://mp.weixin.qq.com/s?__biz=MzA4MjIyNTY0MQ==&mid=2647743787&idx=1&sn=1caec8eb1b81d6ee5dd7ba7fa05ac0f1&chksm=87ad0dadb0da84bb7beb5e4373a14e89fba1130c1bd2a51f4baa8021ec0abe496ce94603b6b4&token=894028224&lang=zh_CN<span style="color: #5c6370;font-style: italic;line-height: 26px;">#rd</span><br> ↓<br>29541341303115543223957290326355<br></code></pre> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;"><strong style="font-weight: bold;color: black;">那么我们遇到的第一个问题:使用什么哈希算法?</strong></p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">我们都知道哈希算法是一种摘要算法,它的作用是:对任意一组输入数据进行计算,得到一个固定长度的输出摘要。我们常见的哈希算法有:MD5、SHA-1、SHA-256、SHA-512 算法等。但我们最好还是使用另一种叫做 MurmurHash 的哈希算法。为什么呢?</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">因为 MD5 和 SHA 哈希算法,它们都是加密的哈希算法,也就是说我们无法从哈希值反向推导出原文,从而保证了原文的保密性。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">但对于我们这个场景而言,我们并不关心安全性,我们关注的是运算速度以及哈希冲突。而 MurmurHash 算法是一个非加密哈希算法,所以它的速度回更快。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;"><strong style="font-weight: bold;color: black;">这时候我们会遇到第二个问题:哈希冲突</strong></p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">学过 HashMap 的同学都知道,哈希冲突是哈希算法不可避免的问题。而解决哈希冲突的方式有两种,分别是:链表法和重哈希法。HashMap 使用了链表法,但我们这里使用的是重哈希法。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">所谓的重哈希法,指的是当发生哈希冲突的时候,我们在原有长链后面加上固定的特殊字符,后续拿出长链时再将其去掉,如下所示。</p> <pre data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">原有长链:https://mp.weixin.qq.com/s1caec8eb1b81d6ee5dd7b<br> ↓↓ <br> 发生哈希冲突<br> ↓↓ <br>补上特殊字符:https://mp.weixin.qq.com/s1caec8eb1b81d6ee5dd7b[SPECIAL-CHARACTER]<br> ↓↓ <br> 再次进行哈希<br></code></pre> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">通过这种办法,我们就可以解决哈希冲突的问题了。如果再次发生,那么就再进行哈希,一直到不冲突位置。一般来说,哈希冲突的可能性微乎其微。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">好了,现在我们通过哈希算法得到了一个哈希值:<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">29541341303115543223957290326355</code>,变成了这样:<code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">http://dwz.com/29541341303115543223957290326355</code>。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">原本很长的网址变得比较短了,但整体看起来还是有点长。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;"><strong style="font-weight: bold;color: black;">有没有办法让网址变得再短一点呢?</strong></p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">我们知道在网址 URL 中,常用的合法字符有 0~9、a~z、A~Z 这样 62 个字符。如果我们用哈希值与 62 取余,那么余数肯定是在 0-61 之间。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">这 62 个数字刚好与 62 个合法网址字符一一对应。接着,我们再用除 62 得到的值,再次与 62 取余,一直到位 0 为止。通过这样的处理,我们就可以得到一个字符为 62 个字符、长度很短的字符串了。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">上面讲有点晦涩难懂,我们来举个例子。假设我们得到的哈希值为 181338494,那么上面的处理流程为:</p> <ol data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: decimal;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 将 181338494 除以 62,得到结果为 2924814,余数为 26,此时余数 26 对应字符为 q。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 将 2924814 除以 62,得到结果为 47174,余数为 26,此时余数 26 对应字符为 q。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 将 47174 除以 62,得到结果为 760,余数为 54,此时余数 54 对应字符为 S。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 省略剩余步骤 </section></li> </ol> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">整个处理流程如下图所示:</p> <figure data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin: 10px 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.6322188449848024" src="/upload/5aa35d0bcf5822534779340e2535cae3.jpg" data-type="jpeg" data-w="658" style="display: block;margin: 0 auto;max-width: 100%;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> 转为 16 进制数示意图 - 来自极客时间 </figcaption> </figure> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">可以看到,我们把 181338494 这个十进制数,转成了由合法网址字符组成的「62 进制数」—— <code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;color: #1e6bb8;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;">cgSqq</code>。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">到这里,我们不仅生成了短链,还将短链的长度极大地缩短了。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">这就是使用哈希算法生成唯一锻炼的全部内容了,我们总结一下:<strong style="font-weight: bold;color: black;">首先,使用 MurmurHash 生成哈希值,并且用重哈希法解决哈希冲突的问题。接着,将 10 进制的哈希值转成 62 进制的合法网址字符,从而缩短网址长度。</strong></p> <h3 data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 20px;letter-spacing: 0px;margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;">分布式 ID 生成短链</h3> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">上面使用哈希算法生成唯一短链的方式,相对来说是比较形象的。但其实我们也可以用分布式 ID 的方式,来完成唯一短链的生成。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">例如第一次请求的长链,我们为其生成一个唯一 ID,将其长链与唯一 ID 对应起来。第二次请求,我们再为其生成一个唯一 ID,再次将长链与唯一 ID 对应起来,如下所示。</p> <pre data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">第一次请求:https://mp.weixin.qq.com/s1caec8eb1b81d6ee5dd7b<br> ↓↓ <br>生成短链:https://dwz.com/1021000001<br><br>第一次请求:https://mp.weixin.qq.com/s1caec8eb1b81d6ee5ff7b<br> ↓↓ <br>生成短链:https://dwz.com/1021000002<br></code></pre> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">因为生成的唯一 ID 也可能非常长,因此我们可以采用上面同样的方式,将 10 进制的唯一 ID 转成 62 进制的合法网址字符,从而缩短字符长度。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">那么接下来的问题就变成了:如何设计一个全局唯一 ID 发号器了。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">对于如何设计一个全局唯一的 ID 发号器,就属于另外一个话题,我们这里就不深入探讨了。</p> <h2 data-tool="mdnice编辑器" style="color: rgb(0, 13, 131);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 22px;letter-spacing: 5px;margin-top: 30px;margin-bottom: 15px;font-weight: bold;padding: 20px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/AVWicyZuuClHY9LkyFGYJYL1Xib6HGM0P5dfMffgkZ2LqKbJXnia2R5JbRuau1vf2Zpy1g7kvq4OiaaMuqoIpagqFA/640?wx_fmt=png");background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-position: center -10px;background-size: 150px;"><span style="padding-bottom: 12px;border-bottom: 2px solid #000d83;">性能优化</span></h2> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">看到这里,我们基本上有了一个完整的思路:拿到长链地址后,可以用哈希算法或唯一 ID 分号器获取唯一字符串,从而建立长链与短链的映射关系。<span style="letter-spacing: 0px;">为了缩短短链长度,我们还可以将其用 62 进制数表示,整个短链生成过程如下图所示。</span></p> <figure data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin: 10px 0px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.8706099815157117" src="/upload/8240a8761fb28327661f2b660399543f.png" data-type="png" data-w="541" style="display: block;margin: 0 auto;max-width: 100%;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> 短链生成示意图 </figcaption> </figure> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">短链生成完,并且已经存到了数据库中,接下里该使用了。通常的做法是会根据请求的短链字符串,从数据库中找到数据,然后返回 HTTP 重定向原始地址。而在不断使用过程中,还有一些可能发现的优化点,这里简单讲讲。</p> <h3 data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 20px;letter-spacing: 0px;margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;">索引优化</h3> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">如果使用关系型数据库的话,对于短链字段需要创建唯一索引,从而加快查询速度。</p> <h3 data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 20px;letter-spacing: 0px;margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;">增加缓存</h3> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">并发量小的时候,我们都是直接访问数据库。但当并发量再次升高时,需要加上缓存抗住热点数据的访问。</p> <h3 data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 20px;letter-spacing: 0px;margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;">读写分离</h3> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">短链服务肯定是读远大于写的,因此对于短链服务,可以做好读写分离。</p> <h3 data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 20px;letter-spacing: 0px;margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;">分库分表</h3> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">如果是商用的短链服务,那么数据量上亿是很正常的,更不用说常年累月积累下的量了。这时候可以一开始就做好分库分表操作,避免后期再大动干戈。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">对于分库分表来说,最关键的便是根据哪个字段去作为分库分表的依据了。对于短链服务来说,当然是用转化后的 62 进制数字做分表依据了,因为它是唯一的嘛。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">至于怎么分库分表,就涉及到分库分表方面的知识,以及对于系统容量的预估了,这里就不细说了。有机会的话,我们找个时间来深入讲讲这方面的内容。</p> <h3 data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 20px;letter-spacing: 0px;margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;">防止恶意攻击</h3> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">开放到公网的服务,什么事情都可能发生,其中一个可能的点就是被恶意攻击,不断循环调用。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">一开始我们可以做一下简单地限流操作,例如:</p> <ol data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: decimal;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 没有授权的用户,根据 IP 进行判断,1 分钟最多只能请求 10 次。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> 没有授权的用户,所有用户 1 分钟最多只能请求 4000 次,防止更换 IP 进行攻击。 </section></li> </ol> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">简单地说,就是要不断提高攻击的成本,使得最坏情况下系统依然可以正常提供服务。</p> <h2 data-tool="mdnice编辑器" style="color: rgb(0, 13, 131);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 22px;letter-spacing: 5px;margin-top: 30px;margin-bottom: 15px;font-weight: bold;padding: 20px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/AVWicyZuuClHY9LkyFGYJYL1Xib6HGM0P5dfMffgkZ2LqKbJXnia2R5JbRuau1vf2Zpy1g7kvq4OiaaMuqoIpagqFA/640?wx_fmt=png");background-repeat: no-repeat;background-attachment: initial;background-origin: initial;background-clip: initial;background-position: center -10px;background-size: 150px;"><span style="padding-bottom: 12px;border-bottom: 2px solid #000d83;">总结</span></h2> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">本文首先讲了短链存在的三个价值:简洁、易于使用、节省成本,接着讲了短链的原理是 HTTP 重定向,最后着重讲了短链服务的设计思路。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">在短链服务的设计思路上,最重要是解决两个问题:根据长链生成短链、根据短链找到长链。在根据长链生成短链的思路上,我们讲了两种实现思路,分别是:哈希算法生成短链、分布式全局 ID 生成短链,其中哈希算法涉及到哈希算法的选择,以及哈希冲突的处理。</p> <p data-tool="mdnice编辑器" style="color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0px;padding-top: 8px;padding-bottom: 8px;margin: 0px;line-height: 2em;">最后我们还列举了一些短链服务后续可能的优化点,包括:如何让网址变得更短、索引优化、增加热点数据、读写分离、分库分表、防止恶意攻击等等。</p> </section>
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="line-height: 1.6;word-break: break-word;text-align: left;padding: 5px;font-size: 16px;color: rgb(53, 53, 53);word-spacing: 0.8px;letter-spacing: 0.8px;border-radius: 16px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">是的,今早一到公司就收到了机器人的告警,从异常日志来看是数据库连接已关闭,然后我在解决这个问题的过程中发现了几个问题,不急,听我一一道来<img class="rich_pages wxw-img" data-ratio="0.9128630705394191" src="/upload/ed97ff6d6059f57fbffd7cb5b060965a.png" data-type="png" data-w="482" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"></p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(234, 84, 41);letter-spacing: 0.5444px;padding-bottom: 10px;border-bottom: 2px solid rgb(234, 84, 41);visibility: visible;">异常被try后没有继续抛出,导致继续执行后续操作</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">我们看到前文示例代码会发现我们在 try 之后只是 rollback 了,对于异常也只是打印一下并没有继续抛出。<img class="rich_pages wxw-img" data-ratio="0.14583333333333334" src="/upload/aba5664abf1cbdcae504a6a2a56c23f6.png" data-type="png" data-w="576" style="border-radius: 6px;display: block;margin: 20px auto;max-width: 95%;object-fit: contain;"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">那么就会导致一种情况:假设你在 Service 层中调用多个调用数据库的修改方法,那么第一个操作失败后异常没有抛出,Service 层不知道,就会继续向后面执行,修复很简单,只需要将异常抛出即可:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oey2F0JZ6AzlEsyfdBnSxxUQ7nDia8OUfAhJwE9EuFZoKcKdyERbZxR50FHSXibZEic4kicbh4ico6Y4HYNOmH9RlwPbJ/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(255, 255, 255);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: black;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fff;border-radius: 5px;"><span style="color: #007400;line-height: 26px;">// 案例1:参考MybatisPlus的com.baomidou.mybatisplus.extension.toolkit.SqlHelper##executeBatch()实现</span><br>batchSqlSession.rollback();<br>Throwable unwrapped = ExceptionUtil.unwrapThrowable(e);<br><span style="color: #aa0d91;line-height: 26px;">if</span> (unwrapped <span style="color: #aa0d91;line-height: 26px;">instanceof</span> RuntimeException) {<br> MyBatisExceptionTranslator myBatisExceptionTranslator<br> = <span style="color: #aa0d91;line-height: 26px;">new</span> MyBatisExceptionTranslator(sqlSessionFactory.getConfiguration().getEnvironment().getDataSource(), <span style="color: #aa0d91;line-height: 26px;">true</span>);<br> <span style="color: #aa0d91;line-height: 26px;">throw</span> Objects.requireNonNull(myBatisExceptionTranslator.translateExceptionIfPossible((RuntimeException) unwrapped));<br>}<br><span style="color: #aa0d91;line-height: 26px;">throw</span> <span style="color: #aa0d91;line-height: 26px;">new</span> CommonException(unwrapped);<br><br><span style="color: #007400;line-height: 26px;">// 案例2:简单来说,只要能把异常抛出去即可,并不定需要像上面这么复杂</span><br>batchSqlSession.rollback();<br><span style="color: #aa0d91;line-height: 26px;">throw</span> <span style="color: #aa0d91;line-height: 26px;">new</span> CustomException(e);<br></code></pre> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(234, 84, 41);letter-spacing: 0.5444px;padding-bottom: 10px;border-bottom: 2px solid rgb(234, 84, 41);visibility: visible;">大事务/长事务导致 connection closed</span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">代码场景</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">我们来看一段业务功能的伪代码,大致如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oey2F0JZ6AzlEsyfdBnSxxUQ7nDia8OUfAhJwE9EuFZoKcKdyERbZxR50FHSXibZEic4kicbh4ico6Y4HYNOmH9RlwPbJ/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(255, 255, 255);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: black;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fff;border-radius: 5px;"><span style="color: #643820;line-height: 26px;">@Transactional</span>(rollbackFor = Exception<span style="line-height: 26px;">.<span style="color: #aa0d91;line-height: 26px;">class</span>)<br>@<span style="color: #5c2699;line-height: 26px;">Override</span><br><span style="color: #5c2699;line-height: 26px;">public</span> <span style="color: #5c2699;line-height: 26px;">Integer</span> <span style="color: #5c2699;line-height: 26px;">billCheck</span>() </span>{<br> <span style="color: #007400;line-height: 26px;">// 获取对应的策略</span><br> 策略 = getStrategy();<br> <span style="color: #007400;line-height: 26px;">// 前置参数校验</span><br> <span style="color: #aa0d91;line-height: 26px;">if</span> (必要参数是否存在){<br> <span style="color: #aa0d91;line-height: 26px;">return</span> <span style="color: #aa0d91;line-height: 26px;">false</span>;<br> }<br> <span style="color: #aa0d91;line-height: 26px;">try</span> {<br> <span style="color: #007400;line-height: 26px;">// 解析文件</span><br> 文件里的数据集合 = 策略.parseFile(file);<br> <span style="color: #007400;line-height: 26px;">// 将文件里的数据插入数据库表</span><br> 影响的行数 = 策略.handleFileData(文件里的数据);<br> <span style="color: #aa0d91;line-height: 26px;">if</span> (影响的行数 > <span style="color: #1c00cf;line-height: 26px;">0</span>) {<br> <span style="color: #007400;line-height: 26px;">// 将文件里的数据和本地的数据进行对比操作</span><br> 对比后的数据 = 策略.doBillCheck(参数);<br> <span style="color: #007400;line-height: 26px;">// 将对比的结果分开插入到数据库中</span><br> batchUtils.batchUpdateOrInsert(成功的数据,<br> 某Mapper<span style="line-height: 26px;">.<span style="color: #aa0d91;line-height: 26px;">class</span>,<br> (<span style="color: #5c2699;line-height: 26px;">billErr</span>, <span style="color: #5c2699;line-height: 26px;">mapper</span>) -> <span style="color: #5c2699;line-height: 26px;">mapper</span>.<span style="color: #5c2699;line-height: 26px;">insert</span>(<span style="color: #5c2699;line-height: 26px;">data</span>))</span>;<br> batchUtils.batchUpdateOrInsert(失败的数据,<br> 某Mapper<span style="line-height: 26px;">.<span style="color: #aa0d91;line-height: 26px;">class</span>,<br> (<span style="color: #5c2699;line-height: 26px;">billErr</span>, <span style="color: #5c2699;line-height: 26px;">mapper</span>) -> <span style="color: #5c2699;line-height: 26px;">mapper</span>.<span style="color: #5c2699;line-height: 26px;">insert</span>(<span style="color: #5c2699;line-height: 26px;">data</span>))</span>;<br> batchUtils.batchUpdateOrInsert(需要更新的数据,<br> 某Mapper<span style="line-height: 26px;">.<span style="color: #aa0d91;line-height: 26px;">class</span>,<br> (<span style="color: #5c2699;line-height: 26px;">billErr</span>, <span style="color: #5c2699;line-height: 26px;">mapper</span>) -> <span style="color: #5c2699;line-height: 26px;">mapper</span>.<span style="color: #5c2699;line-height: 26px;">update</span>(<span style="color: #5c2699;line-height: 26px;">data</span>))</span>;<br> }<br> <span style="color: #007400;line-height: 26px;">// 发送企业微信机器人通知</span><br> 策略.sendRobotMessage();<br> log.info(<span style="color: #c41a16;line-height: 26px;">"耗时:{}毫秒"</span>, 耗时);<br> } <span style="color: #aa0d91;line-height: 26px;">catch</span> (Exception e) {<br> log.error(<span style="color: #c41a16;line-height: 26px;">"对账出错"</span>, e);<br> <span style="color: #aa0d91;line-height: 26px;">throw</span> <span style="color: #aa0d91;line-height: 26px;">new</span> CommonException(<span style="color: #c41a16;line-height: 26px;">"对账出错"</span>);<br> }<br> <span style="color: #aa0d91;line-height: 26px;">return</span> 影响的行数;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">我们梳理一下,这是一个普通的模板方法 + 策略模式的应用,因为业务场景中不管是哪个通道的文件都会必经如下几个步骤,所以就将其抽象了。我们可以发现这个方法里面做了很多数据库操作,并且使用了声明式事务注解,然后里面大致有如下几个步骤:</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 解析文件 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 将文件里的数据插入数据库表 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 将文件里的数据和本地的数据进行对比操作 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 将对比的结果分开插入到数据库中 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">然后我们再来看一段配置,它来自 <span style="font-weight: 700;color: rgb(248, 57, 41);">druid</span> 连接池框架,如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oey2F0JZ6AzlEsyfdBnSxxUQ7nDia8OUfAhJwE9EuFZoKcKdyERbZxR50FHSXibZEic4kicbh4ico6Y4HYNOmH9RlwPbJ/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(255, 255, 255);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: black;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fff;border-radius: 5px;"><span style="color: #836C28;line-height: 26px;">spring:</span><br> <span style="color: #836C28;line-height: 26px;">datasource:</span><br> <span style="color: #836C28;line-height: 26px;">druid:</span><br> <span style="color: #836C28;line-height: 26px;">remove-abandoned:</span> <span style="color: #aa0d91;line-height: 26px;">true</span><br> <span style="color: #007400;line-height: 26px;">## 单位:秒</span><br> <span style="color: #836C28;line-height: 26px;">remove-abandoned-timeout:</span> <span style="color: #1c00cf;line-height: 26px;">60</span><br> <span style="color: #836C28;line-height: 26px;">log-abandoned:</span> <span style="color: #aa0d91;line-height: 26px;">true</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">以上三条属性一般是用来<span style="font-weight: 700;color: rgb(248, 57, 41);">防止连接泄露</span>的,说明如下:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">removeAbandoned</span>:要求获取到连接后,如果空闲时间超过 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">removeAbandonedTimeoutMillis</code> 秒后没有 close,druid 会强制回收,默认false; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">logAbandoned</span>:如果回收了连接,是否要打印一条 log,默认 false; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> <span style="font-weight: 700;color: rgb(248, 57, 41);">removeAbandonedTimeoutMillis</span>:连接回收的超时时间,默认5分钟; </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">看到这里我想大部分同学可能已经知道是什么问题了,没错,<span style="font-weight: 700;color: rgb(248, 57, 41);">肯定是因为拿到了连接,但拿的时间超过了这个限制,导致 druid 直接强制回收了该连接</span>,但是知根知底方能百战百胜,这么好的机会怎么能不深入了解一下?关注公号:码猿技术专栏,回复关键词:1111 获取阿里内部性能调优手册~</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">什么时候获取的连接?</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">是的,既然是连接超时被关闭,那我们肯定要先找到是什么时候拿到的连接,是方法中第一次操作数据库【将文件里的数据插入数据库表】的时候?那当然不是,我们知道 Mybatis 有一个 Executor_ _接口,感兴趣的可以自行了解,它定义了数据库操作的基本方法,它才是SQL语句幕后的执行者,我们直接来看获取连接的地方 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">org.apache.ibatis.executor.BaseExecutor##getConnection</code>:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oey2F0JZ6AzlEsyfdBnSxxUQ7nDia8OUfAhJwE9EuFZoKcKdyERbZxR50FHSXibZEic4kicbh4ico6Y4HYNOmH9RlwPbJ/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(255, 255, 255);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: black;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fff;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #aa0d91;line-height: 26px;">protected</span> Connection <span style="color: #1c00cf;line-height: 26px;">getConnection</span><span style="color: #5c2699;line-height: 26px;">(Log statementLog)</span> <span style="color: #aa0d91;line-height: 26px;">throws</span> SQLException </span>{<br> Connection connection = transaction.getConnection();<br> <span style="color: #aa0d91;line-height: 26px;">if</span> (statementLog.isDebugEnabled()) {<br> <span style="color: #aa0d91;line-height: 26px;">return</span> ConnectionLogger.newInstance(connection, statementLog, queryStack);<br> } <span style="color: #aa0d91;line-height: 26px;">else</span> {<br> <span style="color: #aa0d91;line-height: 26px;">return</span> connection;<br> }<br> }<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">我们可以看出来,我们是通过 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">Transaction</code> 去获取连接的,但如果我们是第一次操作的时候才去获取的连接,那怎么会连接超时呢?所以我初步推断是开启事务的时候可能就已经获取连接了,那我们来求证一下,来到 Spring 的事务管理器 <span style="font-weight: 700;color: rgb(248, 57, 41);">PlatformTransactionManager</span>,Mybatis 用的是它的实现类 <span style="font-weight: 700;color: rgb(248, 57, 41);">DataSourceTransactionManager</span>, 然后我们一路跟 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">getTransaction</code> 方法来到 <span style="font-weight: 700;color: rgb(248, 57, 41);">AbstractPlatformTransactionManager##getTransaction</span>,再到 <span style="font-weight: 700;color: rgb(248, 57, 41);">DataSourceTransactionManager##doBegin</span></p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oey2F0JZ6AzlEsyfdBnSxxUQ7nDia8OUfAhJwE9EuFZoKcKdyERbZxR50FHSXibZEic4kicbh4ico6Y4HYNOmH9RlwPbJ/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(255, 255, 255);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: black;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fff;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #aa0d91;line-height: 26px;">public</span> <span style="color: #aa0d91;line-height: 26px;">final</span> TransactionStatus <span style="color: #1c00cf;line-height: 26px;">getTransaction</span><span style="color: #5c2699;line-height: 26px;">(@Nullable TransactionDefinition definition)</span> <span style="color: #aa0d91;line-height: 26px;">throws</span> TransactionException </span>{<br> <span style="color: #007400;line-height: 26px;">// 省略无关代码 ...</span><br> doBegin(transaction, definition);<br> <span style="color: #007400;line-height: 26px;">// 省略无关代码 ...</span><br>}<br><br><span style="color: #643820;line-height: 26px;">@Override</span><br><span style="line-height: 26px;"><span style="color: #aa0d91;line-height: 26px;">protected</span> <span style="color: #aa0d91;line-height: 26px;">void</span> <span style="color: #1c00cf;line-height: 26px;">doBegin</span><span style="color: #5c2699;line-height: 26px;">(Object transaction, TransactionDefinition definition)</span> </span>{<br> DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;<br> Connection con = <span style="color: #aa0d91;line-height: 26px;">null</span>;<br><br> <span style="color: #aa0d91;line-height: 26px;">try</span> {<br> <span style="color: #007400;line-height: 26px;">// 如果数据源事务对象的ConnectionHolder为null或者是事务同步的 </span><br> <span style="color: #aa0d91;line-height: 26px;">if</span> (!txObject.hasConnectionHolder() ||<br> txObject.getConnectionHolder().isSynchronizedWithTransaction()) {<br> <span style="color: #007400;line-height: 26px;">// 获取当前数据源的数据库连接 </span><br> Connection newCon = obtainDataSource().getConnection();<br> <span style="color: #aa0d91;line-height: 26px;">if</span> (logger.isDebugEnabled()) {<br> logger.debug(<span style="color: #c41a16;line-height: 26px;">"Acquired Connection ["</span> + newCon + <span style="color: #c41a16;line-height: 26px;">"] for JDBC transaction"</span>);<br> }<br> txObject.setConnectionHolder(<span style="color: #aa0d91;line-height: 26px;">new</span> ConnectionHolder(newCon), <span style="color: #aa0d91;line-height: 26px;">true</span>);<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">就是这!它其实在进入方法的最开始,开启事务的时候就已经获取了连接,然后由于【解析文件】耗时过长,导致整个方法的执行时间超过了 60s 被强制回收连接,但你以为这就结束了?没错,当时出现这个问题的时候,我还手动触发了一次,结果第二次通过了,你说诡异不诡异?两次执行的时间都是 90s。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">druid removeAbandoned 背后的秘密</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">所以我们继续看一下 druid 是怎么强制回收连接的,Druid每隔 <span style="font-weight: 700;color: rgb(248, 57, 41);">timeBetweenEvictionRunsMillis</span>(默认1分钟)会调用DestroyTask,在这里会判断是否可以回收泄露的连接,就是因为它是1分钟执行一次,所以可能第二次正好它执行的时候还没超过 60s,所以这次简直就是玄学了啊。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oey2F0JZ6AzlEsyfdBnSxxUQ7nDia8OUfAhJwE9EuFZoKcKdyERbZxR50FHSXibZEic4kicbh4ico6Y4HYNOmH9RlwPbJ/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(255, 255, 255);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: black;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fff;border-radius: 5px;"><span style="color: #aa0d91;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #aa0d91;line-height: 26px;">class</span> <span style="color: #5c2699;line-height: 26px;">DestroyTask</span> <span style="color: #aa0d91;line-height: 26px;">implements</span> <span style="color: #5c2699;line-height: 26px;">Runnable</span> </span>{<br> <span style="line-height: 26px;"><span style="color: #aa0d91;line-height: 26px;">public</span> <span style="color: #1c00cf;line-height: 26px;">DestroyTask</span><span style="color: #5c2699;line-height: 26px;">()</span> </span>{<br><br> }<br><br> <span style="color: #643820;line-height: 26px;">@Override</span><br> <span style="line-height: 26px;"><span style="color: #aa0d91;line-height: 26px;">public</span> <span style="color: #aa0d91;line-height: 26px;">void</span> <span style="color: #1c00cf;line-height: 26px;">run</span><span style="color: #5c2699;line-height: 26px;">()</span> </span>{<br> shrink(<span style="color: #aa0d91;line-height: 26px;">true</span>, keepAlive);<br> <span style="color: #007400;line-height: 26px;">// 判断removeAbandoned是否为true,默认是false</span><br> <span style="color: #aa0d91;line-height: 26px;">if</span> (isRemoveAbandoned()) {<br> removeAbandoned();<br> }<br> }<br><br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">然后我们看到 removeAbandoned 方法,这里面有一段代码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oey2F0JZ6AzlEsyfdBnSxxUQ7nDia8OUfAhJwE9EuFZoKcKdyERbZxR50FHSXibZEic4kicbh4ico6Y4HYNOmH9RlwPbJ/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(255, 255, 255);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: black;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fff;border-radius: 5px;"><span style="color: #aa0d91;line-height: 26px;">for</span> (; iter.hasNext();) {<br> DruidPooledConnection pooledConnection = iter.next();<br><br> <span style="color: #007400;line-height: 26px;">// 判断该连接是否还在运行,只回收不运行的连接</span><br> <span style="color: #007400;line-height: 26px;">// Druid会在连接执行query,update的时候设置为正在运行,</span><br> <span style="color: #007400;line-height: 26px;">// 并在回收后设置为不运行</span><br> <span style="color: #aa0d91;line-height: 26px;">if</span> (pooledConnection.isRunning()) {<br> <span style="color: #aa0d91;line-height: 26px;">continue</span>;<br> }<br><br> <span style="color: #aa0d91;line-height: 26px;">long</span> timeMillis = (currrentNanos - pooledConnection.getConnectedTimeNano()) / (<span style="color: #1c00cf;line-height: 26px;">1000</span> * <span style="color: #1c00cf;line-height: 26px;">1000</span>);<br><br> <span style="color: #007400;line-height: 26px;">//判断连接借出去的时间大小</span><br> <span style="color: #aa0d91;line-height: 26px;">if</span> (timeMillis >= removeAbandonedTimeoutMillis) {<br> iter.remove();<br> pooledConnection.setTraceEnable(<span style="color: #aa0d91;line-height: 26px;">false</span>);<br> abandonedList.add(pooledConnection);<br> }<br>}<br><br><span style="color: #007400;line-height: 26px;">//判断是否要记录连接回收日志,这个很重要,可以及时发现项目中是否有连接泄露</span><br><span style="color: #aa0d91;line-height: 26px;">if</span> (isLogAbandoned()) {<br> StringBuilder buf = <span style="color: #aa0d91;line-height: 26px;">new</span> StringBuilder();<br> buf.append(<span style="color: #c41a16;line-height: 26px;">"abandon connection, owner thread: "</span>);<br> buf.append(pooledConnection.getOwnerThread().getName());<br> buf.append(<span style="color: #c41a16;line-height: 26px;">", connected at : "</span>);<br> buf.append(pooledConnection.getConnectedTimeMillis());<br> buf.append(<span style="color: #c41a16;line-height: 26px;">", open stackTrace\n"</span>);<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">是的,如果你的连接被强制回收了的话,你只需要将 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 93, 108);">LogAbandoned</code> 设置为 true,就可以通过日志看到相关信息了</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 20px;"><span style="display: none;"></span><span style="font-size: 16px;color: #222;">解决方案</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">到这,问题就基本都发现了,那么我最后是怎么解决的呢?原本我是想的把不需要事务的动作抽离出来新建一个方法,后面我发现这样子好像模板方法并不好使了,我就采用了<span style="font-weight: 700;color: rgb(248, 57, 41);">编程式事务</span>,感兴趣的可以自己在了解一下,最后伪代码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/A7sq8BD8oey2F0JZ6AzlEsyfdBnSxxUQ7nDia8OUfAhJwE9EuFZoKcKdyERbZxR50FHSXibZEic4kicbh4ico6Y4HYNOmH9RlwPbJ/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(255, 255, 255);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: black;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #fff;border-radius: 5px;"><span style="color: #643820;line-height: 26px;">@Autowired</span><br><span style="color: #aa0d91;line-height: 26px;">private</span> TransactionTemplate transactionTemplate;<br><br><span style="color: #643820;line-height: 26px;">@Transactional</span>(rollbackFor = Exception<span style="line-height: 26px;">.<span style="color: #aa0d91;line-height: 26px;">class</span>)<br>@<span style="color: #5c2699;line-height: 26px;">Override</span><br><span style="color: #5c2699;line-height: 26px;">public</span> <span style="color: #5c2699;line-height: 26px;">Integer</span> <span style="color: #5c2699;line-height: 26px;">billCheck</span>() </span>{<br> <span style="color: #007400;line-height: 26px;">// 获取对应的策略</span><br> 策略 = getStrategy();<br> <span style="color: #007400;line-height: 26px;">// 前置参数校验</span><br> <span style="color: #aa0d91;line-height: 26px;">if</span> (必要参数是否存在){<br> <span style="color: #aa0d91;line-height: 26px;">return</span> <span style="color: #aa0d91;line-height: 26px;">false</span>;<br> }<br> <span style="color: #aa0d91;line-height: 26px;">try</span> {<br> <span style="color: #007400;line-height: 26px;">// 解析文件</span><br> 文件里的数据集合 = 策略.parseFile(file);<br> <span style="color: #007400;line-height: 26px;">// 编程式事务</span><br> 影响的行数 = transactionTemplate.execute(transactionStatus -> {<br> <span style="color: #007400;line-height: 26px;">// 将文件里的数据插入数据库表</span><br> <span style="color: #aa0d91;line-height: 26px;">return</span> 策略.handleFileData(文件里的数据);<br> });<br> <span style="color: #aa0d91;line-height: 26px;">if</span> (影响的行数 > <span style="color: #1c00cf;line-height: 26px;">0</span>) {<br> <span style="color: #007400;line-height: 26px;">// 将文件里的数据和本地的数据进行对比操作</span><br> 对比后的数据 = 策略.doBillCheck(参数);<br> <span style="color: #007400;line-height: 26px;">// 编程式事务</span><br> transactionTemplate.execute(transactionStatus -> {<br> <span style="color: #007400;line-height: 26px;">// 将对比的结果分开插入到数据库中</span><br> batchUtils.batchUpdateOrInsert(成功的数据,<br> 某Mapper<span style="line-height: 26px;">.<span style="color: #aa0d91;line-height: 26px;">class</span>,<br> (<span style="color: #5c2699;line-height: 26px;">billErr</span>, <span style="color: #5c2699;line-height: 26px;">mapper</span>) -> <span style="color: #5c2699;line-height: 26px;">mapper</span>.<span style="color: #5c2699;line-height: 26px;">insert</span>(<span style="color: #5c2699;line-height: 26px;">data</span>))</span>;<br> batchUtils.batchUpdateOrInsert(失败的数据,<br> 某Mapper<span style="line-height: 26px;">.<span style="color: #aa0d91;line-height: 26px;">class</span>,<br> (<span style="color: #5c2699;line-height: 26px;">billErr</span>, <span style="color: #5c2699;line-height: 26px;">mapper</span>) -> <span style="color: #5c2699;line-height: 26px;">mapper</span>.<span style="color: #5c2699;line-height: 26px;">insert</span>(<span style="color: #5c2699;line-height: 26px;">data</span>))</span>;<br> batchUtils.batchUpdateOrInsert(需要更新的数据,<br> 某Mapper<span style="line-height: 26px;">.<span style="color: #aa0d91;line-height: 26px;">class</span>,<br> (<span style="color: #5c2699;line-height: 26px;">billErr</span>, <span style="color: #5c2699;line-height: 26px;">mapper</span>) -> <span style="color: #5c2699;line-height: 26px;">mapper</span>.<span style="color: #5c2699;line-height: 26px;">update</span>(<span style="color: #5c2699;line-height: 26px;">data</span>))</span>;<br> <span style="color: #aa0d91;line-height: 26px;">return</span> Boolean.TRUE;<br> });<br> }<br> <span style="color: #007400;line-height: 26px;">// 发送企业微信机器人通知</span><br> 策略.sendRobotMessage();<br> log.info(<span style="color: #c41a16;line-height: 26px;">"耗时:{}毫秒"</span>, 耗时);<br> } <span style="color: #aa0d91;line-height: 26px;">catch</span> (Exception e) {<br> log.error(<span style="color: #c41a16;line-height: 26px;">"对账出错"</span>, e);<br> <span style="color: #aa0d91;line-height: 26px;">throw</span> <span style="color: #aa0d91;line-height: 26px;">new</span> CommonException(<span style="color: #c41a16;line-height: 26px;">"对账出错"</span>);<br> }<br> <span style="color: #aa0d91;line-height: 26px;">return</span> 影响的行数;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">这样子,我们将解析文件和对比数据(只是查询)这种耗时操作放在了事务外,并且将原本一个事务里的操作拆成了两个小事务,这样子基本就避免了大事务的问题了,完结撒花~</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(234, 84, 41);letter-spacing: 0.5444px;padding-bottom: 10px;border-bottom: 2px solid rgb(234, 84, 41);visibility: visible;">大事务/长事务可能造成的影响</span></h2> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: rgb(248, 57, 41);" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 并发情况下,数据库连接池容易被撑爆 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 锁定太多的数据,造成大量的阻塞和锁超时 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 执行时间长,容易造成主从延迟 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> 回滚所需要的时间比较长 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(53, 53, 53);"> undo log膨胀 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;">所以在业务涉及中,你一定要对大事务特别对待,比如业务设计时,把大事务拆成小事务。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-size: 18px;color: rgb(234, 84, 41);letter-spacing: 0.5444px;padding-bottom: 10px;border-bottom: 2px solid rgb(234, 84, 41);visibility: visible;">总结</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;"><span style="font-weight: 700;color: rgb(248, 57, 41);">声明式事务有一个局限,那就是他的最小粒度要作用在方法上</span>!所以大家在用的时候要格外格外注意大事务的问题,尽量避免在事务中做一些无关数据库的操作,比如RPC远程调用、文件解析等,都是血泪的教训啊!!</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 1.75;margin-top: 0.8em;margin-bottom: 0.8em;text-align: right;"><span style="font-size: 12px;color: rgb(178, 178, 178);">来源:https://juejin.cn/post/7089346387925696520</span></p> </section>
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding-right: 10px;padding-left: 10px;text-align: left;line-height: 1.6;letter-spacing: 0.034em;color: rgb(63, 63, 63);font-size: 16px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">大家好,我是老三,大家对电商购物应该都比较熟悉了,我们应该注意到,在下单之后,通常会有一个倒计时,如果超过支付时间,订单就会被自动取消。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="2.1700680272108843" src="/upload/86733c3db71b600c11f602e5f64c04e2.png" data-type="png" data-w="588" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;font-family: PingFangSC-Light;"> 下单 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">今天,我们来聊聊订单超时未支付自动取消的几种方案。</p> <section class="mp_profile_iframe_wrp"> <mp-common-profile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzkwODE5ODM0Ng==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/PMZOEonJxWdFLJg0sAOqwHB1mb24icMADUgxm1qZQft5aN3H37NAmQnOvpGB7J9JVHxC6NSiacxbBP1DYdhIAeyA/0?wx_fmt=png" data-nickname="三分恶" data-alias="Fighter3FullStack" data-signature="CSDN博客专家、优质创作者,华为云云享专家;肝过外包、混过国企,目前在一家跨境电商搬砖;写过诗,打过拳,佛系小码农。认真讲技术,随性侃人生,关注我,我们一起走的更远。" data-from="0" data-is_biz_ban="0"></mp-common-profile> </section> <h1 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 24px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/PMZOEonJxWet6dkExtrdrG1hWr2LicsD4bQMLqHJHs2Gib0wrcG8oKqODiaN0UgfUUyONX0bB2OQjEaPgMNV6MmCQ/640?wx_fmt=png");background-position: center top;background-repeat: no-repeat;background-size: 75px;line-height: 95px;margin-top: 38px;margin-bottom: 10px;"><span style="font-size: 20px;color: #48b378;border-bottom: 2px solid #2e7950;">1.定时任务</span></h1> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">这是最容易想到的办法,定时任务去轮询数据库,取消即将超时的订单。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.863013698630137" src="/upload/b3c6beae2daf61e87a4336ba13554857.png" data-type="png" data-w="730" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;font-family: PingFangSC-Light;"> 订单轮询 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">定时任务实现方式有很多种,大概可以分为两类:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">本地定时任务</code>和<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">分布式定时任务</code>。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.8498098859315589" src="/upload/f15fd1eb6a4656614ae3513dddb1a9f5.png" data-type="png" data-w="1052" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;font-family: PingFangSC-Light;"> 定时任务实现 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">本地定时任务,适用于单机版的业务系统,实现方式非常多样:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 永动机线程:开启一个线程,通过sleep去完成定时,一些开源中间件的某些定时任务是通过这种方式实现的。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> JDK Timer:JDK提供了Timer API,也提供了很多周期性的方法。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 延迟线程池:JDK还提供了延迟线程池ScheduledExecutorService,API和Timer类似。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> Spring Task:Sprig框架也提供了一些定时任务的实现,使用起来更加简单。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> Quartz:Quartz框架更进一步,提供了可以动态配置的线程池。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">分布式定时任务:适用于分布式的业务系统,主要的实现框架有两种:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> xxl-job:大众点评的许雪里开源的,一款基于MySQL的轻量级分布式定时任务框架。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> elastic-job:当当开发的弹性分布式任务调度系统,功能很强大,相对重一些。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">定时任务实现的优点是开发起来比较简单,但是它也有一些缺点:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 对数据库的压力很大,定时任务造成人为的波峰,执行的时刻数据库的压力会陡增 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 计时不准,定时任务做不到非常精确的时间控制,比如半小时订单过期,但是定时任务很难卡准这个点 </section></li> </ul> <h1 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 24px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/PMZOEonJxWet6dkExtrdrG1hWr2LicsD4bQMLqHJHs2Gib0wrcG8oKqODiaN0UgfUUyONX0bB2OQjEaPgMNV6MmCQ/640?wx_fmt=png");background-position: center top;background-repeat: no-repeat;background-size: 75px;line-height: 95px;margin-top: 38px;margin-bottom: 10px;"><span style="font-size: 20px;color: #48b378;border-bottom: 2px solid #2e7950;">2.被动取消</span></h1> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">在文章开头的那个倒计时器,大家觉得是怎么做的呢?一般是客户端计时+服务端检查。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">什么意思呢?就是这个倒计时由客户端去做,但是客户端定时去服务端检查,修正倒计时的时间。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">那么,这个订单超时自动取消,也可以由客户端去做:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 用户留在收银台的时候,客户端倒计时+主动查询订单状态,服务端每次都去检查一下订单是否超时、剩余时间 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 用户每次进入订单相关的页面,查询订单的时候,服务端也检查一下订单是否超时 </section></li> </ul> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.9067796610169492" src="/upload/fdaf368f1bb467aa601eed6556882202.png" data-type="png" data-w="708" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;font-family: PingFangSC-Light;"> 被动取消 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">这种方式实现起来也比较简单,但是它也有缺点:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 依赖客户端,如果客户端不发起请求,订单可能永远没法过期,一直占用库存 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">当然,也可以<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">被动取消</code>+<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(40, 202, 113);">定时任务</code>,通过定时任务去做兜底的操作。</p> <h1 data-tool="mdnice编辑器" style="font-weight: bold;color: black;font-size: 24px;text-align: center;background-image: url("https://mmbiz.qpic.cn/mmbiz_png/PMZOEonJxWet6dkExtrdrG1hWr2LicsD4bQMLqHJHs2Gib0wrcG8oKqODiaN0UgfUUyONX0bB2OQjEaPgMNV6MmCQ/640?wx_fmt=png");background-position: center top;background-repeat: no-repeat;background-size: 75px;line-height: 95px;margin-top: 38px;margin-bottom: 10px;"><span style="font-size: 20px;color: #48b378;border-bottom: 2px solid #2e7950;">3.延时消息</span></h1> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">第三种方案,就是利用延时消息了,可以使用RocketMQ、RabbitMQ、Kafka的延时消息,消息发送后,有一定延时才会投递。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.584958217270195" src="/upload/f7d64eeb906c2a35a37d24ece08bb3ec.png" data-type="png" data-w="718" style="display: block;margin-right: auto;margin-left: auto;border-radius: 4px;margin-bottom: 25px;"> <figcaption style="margin-top: 5px;text-align: center;color: rgb(136, 136, 136);font-size: 12px;font-family: PingFangSC-Light;"> 延时消息 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">我们用的就是这种,消息队列采用的是RocketMQ,其实RocketMQ延时也是利用定时任务实现的。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">使用延时消息的优点是比较高效、好扩展,缺点是引入了新的技术组件,增加了复杂度。</p> <hr data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;height: 1px;border-width: initial;border-style: none;border-color: initial;text-align: center;background-image: linear-gradient(to right, rgba(93, 186, 133, 0), rgba(93, 186, 133, 0.75), rgba(93, 186, 133, 0));"> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">除了上面的三种,其实还有一些其它的方式,例如本地延迟队列、时间轮算法、Redis过期监听……</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">但是我觉得,应该不会有人真考虑过在生产上使用这些方法。</p> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;">这里再给大家提个小问题,假如我们接入了一种支付方式,支付的周期非常长,我们需要延长订单的有效时间,这种情况下,大家会怎么实现订单超时未支付自动取消呢?</p> <hr data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;height: 1px;border-width: initial;border-style: none;border-color: initial;text-align: center;background-image: linear-gradient(to right, rgba(93, 186, 133, 0), rgba(93, 186, 133, 0.75), rgba(93, 186, 133, 0));"> <br data-tool="mdnice编辑器"> <p data-tool="mdnice编辑器" style="padding-bottom: 8px;padding-top: 1em;color: rgb(74, 74, 74);line-height: 1.75em;"><big><strong>参考:</strong></big></p> <section style="line-height: normal;"> <span style="font-size: 10px;">[1].Java中定时任务的6种实现方式,你知道几种?:https://juejin.cn/post/6992719702032121864</span> </section> <section style="line-height: normal;"> <span style="font-size: 10px;">[2].订单超时未支付自动取消8种实现方案:https://blog.csdn.net/Anenan/article/details/126368753:</span> </section> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> 操作系统概述 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> Linux 操作系统安装 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> Linux 文件系统 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> Linux 命令操作 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> Linux 权限管理 </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 用户和用户组 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 用户操作命令 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 权限操作 </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> Linux 进程管理 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> Linux 其他常用命令大全 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> Linux 系统软件安装 </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 常用软件安装 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 软件安装常用命令 </section></li> </ul> </ul> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;margin: 20px auto 5px;border-top: 1px solid rgb(221, 221, 221);"><span style="display: none;"></span><span style="margin-top: -1px;padding-top: 6px;padding-right: 5px;padding-left: 5px;font-size: 17px;border-top: 2px solid rgb(33, 33, 34);display: inline-block;line-height: 1.1;">操作系统概述</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-bottom: 16px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;font-size: 15px;white-space: normal;text-size-adjust: auto;line-height: 1.75em;">操作系统 Operating System 简称 OS,通俗讲就是一款软件,不过和一般的软件不同,操作系统是管理和控制计算机硬件与软件资源的计算机程序,是直接运行在“裸机”上的最基本的系统软件,任何其他的软件都必须在操作系统的支持下才能运行。</p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;margin: 20px auto 5px;border-top: 1px solid rgb(221, 221, 221);"><span style="display: none;"></span><span style="margin-top: -1px;padding-top: 6px;padding-right: 5px;padding-left: 5px;font-size: 17px;border-top: 2px solid rgb(33, 33, 34);display: inline-block;line-height: 1.1;">Linux 操作系统安装</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-bottom: 16px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;font-size: 15px;white-space: normal;text-size-adjust: auto;line-height: 1.75em;">关于 Linux 的安装看这篇——Linux的安装教程</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;background: rgba(0, 0, 0, 0.05);padding: 10px 1em;border-left-color: rgb(221, 221, 221);margin-top: 1.2em;margin-bottom: 1.2em;border-left-width: 4px;color: rgb(119, 119, 119);quotes: none;"> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> https://blog.csdn.net/huaijiu123/article/details/82083452 </section></li> </ul> </blockquote> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;margin: 20px auto 5px;border-top: 1px solid rgb(221, 221, 221);"><span style="display: none;"></span><span style="margin-top: -1px;padding-top: 6px;padding-right: 5px;padding-left: 5px;font-size: 17px;border-top: 2px solid rgb(33, 33, 34);display: inline-block;line-height: 1.1;">Linux 文件系统</span><span style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <p style="padding-top: 8px;padding-bottom: 8px;color: black;margin-bottom: 16px;white-space: normal;text-size-adjust: auto;line-height: 1.75em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">/var</code>:包含在正常操作中被改变的文件、假脱机文件、记录文件、加锁文件、临时文件和页格式化文件等。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <p style="padding-top: 8px;padding-bottom: 8px;color: black;margin-bottom: 16px;white-space: normal;text-size-adjust: auto;line-height: 1.75em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">/home</code>:包含用户的文件:参数设置文件、个性化文件、文档、数据、EMALL、缓存数据等,每增加一个用户,系统就会根据其用户名在 home 目录下新建和其他用户同名的文件夹,用于保存其用户配置。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <p style="padding-top: 8px;padding-bottom: 8px;color: black;margin-bottom: 16px;white-space: normal;text-size-adjust: auto;line-height: 1.75em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">/proc</code>:包含虚幻的文件,他们实际上并不存在于磁盘上,也不占用任何空间(用 ls-l 可以显示它们的大小)当查看这些文件时,实际上是在访问存在内存中的信息,这些信息用于访问系统。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <p style="padding-top: 8px;padding-bottom: 8px;color: black;margin-bottom: 16px;white-space: normal;text-size-adjust: auto;line-height: 1.75em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">/bin</code>:包含系统启动时需要的执行文件(二进制),这些文件可以被普通用户使用。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <p style="padding-top: 8px;padding-bottom: 8px;color: black;margin-bottom: 16px;white-space: normal;text-size-adjust: auto;line-height: 1.75em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">/etc</code>:为操作系统的配置文件目录(防火墙、启动项)</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <p style="padding-top: 8px;padding-bottom: 8px;color: black;margin-bottom: 16px;white-space: normal;text-size-adjust: auto;line-height: 1.75em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">/root</code>:为系统管理员(也叫超级用户或根用户)的 Home 目录。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <p style="padding-top: 8px;padding-bottom: 8px;color: black;margin-bottom: 16px;white-space: normal;text-size-adjust: auto;line-height: 1.75em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">/dev</code>:为设备目录,Linux 下设备被当成文件,这样一来硬件被抽象化、便于读写、网络共享以及需要临时装载到文件系统中,正常情况下,设备会有一个独立的子目录,这些设备的内容会出现在独立的子目录下。</p> </section></li> </ul> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;margin: 20px auto 5px;border-top: 1px solid rgb(221, 221, 221);"><span style="display: none;"></span><span style="margin-top: -1px;padding-top: 6px;padding-right: 5px;padding-left: 5px;font-size: 17px;border-top: 2px solid rgb(33, 33, 34);display: inline-block;line-height: 1.1;">Linux 命令操作</span><span style="display: none;"></span></h3> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <strong style="color: black;">查看当前目录命令:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">pwd</code></strong> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <strong style="color: black;">打开文件夹命令:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cd</code></strong> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 打开指定文件夹: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cd [目录名称]</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 打开当前用户的根目录: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cd ~</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 返回上级目录: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cd …</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 返回进入目录: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cd -</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 打开根目录: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cd /</code> </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <strong style="color: black;">浏览目录下的文件列表命令:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">ls</code></strong> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 以列的方式查看当前目录下的文件列表: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">ls -l</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 查看当前目录下所有的文件(包括隐藏文件): <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">ls -a</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 以列表的方式查看当前目录下的所有文件: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">ls -la</code> </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <strong style="color: black;">创建文件目录命令:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">mkdir</code></strong> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 新建文件目录: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">mkdir 文件夹名称</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 递归新建多级目录: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">mkdir -p 文件夹名称</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 例如在用户目录下新建 test 目录,命令这样写: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">mkdir -p test/test1/test2/test3</code> 递归新建多级目录的写法 </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <strong style="color: black;">删除文件目录命令:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">rmkdir</code></strong> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 删除指定目录: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">rmkdir 目录名称</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 递归删除指定目录及中间目录: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">rmdir -p 目录名称</code> 这里没有写错,没有字母 k </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <strong style="color: black;">删除文件或者目录命令:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">rm</code></strong> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 常用命令: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">rm -rf [目录或文件]</code> <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">rm -ri [目录或文件]</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 强制删除文件或目录: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">rm -rf 目录或者文件</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 在删除前询问是否确认删除: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">rm -ri 目录或文件</code> </section></li> </ul> </ul> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;background: rgba(0, 0, 0, 0.05);padding: 10px 1em;border-left-color: rgb(221, 221, 221);margin-top: 1.2em;margin-bottom: 1.2em;border-left-width: 4px;color: rgb(119, 119, 119);quotes: none;"> <p style="padding-top: 8px;padding-bottom: 8px;white-space: normal;text-size-adjust: auto;font-size: 15px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;line-height: 1.75em;">因为强制删除的后果不太好,一般不建议使用 <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">rm -rf</code> 进行文件删除</p> <p style="padding-top: 8px;padding-bottom: 8px;white-space: normal;text-size-adjust: auto;font-size: 15px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;line-height: 1.75em;">rm 命令中不跟 r 参数,无法删除目录,只能删除文件</p> </blockquote> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <strong style="color: black;">复制文件或目录命令:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cp</code></strong> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 递归复制目录1下的所有的文件和文件夹到目录2: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cp -r [目录1][目录2]</code> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 执行复制操作时覆盖原有目录前询问用户: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">cp -ri [目录1][目录2]</code> </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <strong style="color: black;">移动文件、修改文件名命令:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">mv</code></strong> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 将文件夹1名称更改为文件夹2: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">mv 文件1 文件2</code> (给文件更名) </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 将目录1的文件移动到目录2: <code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">mv 目录2 目录2</code> (将目录1的文件移动到目录2) </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <strong style="color: black;">创建文件命令:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">touch</code></strong> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> touch 文件名称 </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;"> <strong style="color: black;">查看、编辑文件命令:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(239, 112, 96);">vi</code></strong> </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: square;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> vi 命令为 UNIX 操作系统或者类 UNIX 操作系统都有具有的功能强大的文件编辑命令,用户输入 vi ++ 文件名,便可以进入 vi 模式进行文件内容的查看和编辑,如果文件已经存在,则直接打开文件,如果文件不存在,则系统将打开一个全新的空文件。 </section></li> </ul> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-bottom: 16px;font-family: "Helvetica Neue", Helvetica, "