文章列表

码哥分享为什么要分库分表?如何分?

作者:微信小助手

<h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 1em;color: rgb(0, 0, 153);padding-left: 10px;margin: 1em auto;border-left: 3px solid rgb(0, 0, 153);">为什么要分库分表?</h2> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 1em;color: rgb(0, 0, 153);padding-left: 10px;margin: 1em auto;border-left: 3px solid rgb(0, 0, 153);">数据库相关优化方案</h2> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 1em;color: rgb(0, 0, 153);margin: 0.6em auto;padding-left: 10px;">SQL 调优</h3> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 1em;color: rgb(0, 0, 153);margin: 0.6em auto;padding-left: 10px;">表结构优化</h3> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 1em;color: rgb(0, 0, 153);margin: 0.6em auto;padding-left: 10px;">架构优化</h3> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 1em;color: rgb(0, 0, 153);margin: 0.6em auto;padding-left: 10px;">硬件优化</h3> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 1em;color: rgb(0, 0, 153);padding-left: 10px;margin: 1em auto;border-left: 3px solid rgb(0, 0, 153);">分库分表详解</h2> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 1em;color: rgb(0, 0, 153);margin: 0.6em auto;padding-left: 10px;">单应用单数据库</h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> 商城项目使用单数据库 </figcaption> </figure> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 1em;color: rgb(0, 0, 153);margin: 0.6em auto;padding-left: 10px;">多应用单数据库</h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> 多应用单数据库 </figcaption> </figure> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 1em;color: rgb(0, 0, 153);margin: 0.6em auto;padding-left: 10px;">多应用多数据库</h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> 多应用多数据库 </figcaption> </figure> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 1em;color: rgb(0, 0, 153);margin: 0.6em auto;padding-left: 10px;">分表</h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> 拆分表 </figcaption> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> 单库拆分 </figcaption> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> 多库拆分 </figcaption> </figure> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 1em;color: rgb(0, 0, 153);padding-left: 10px;margin: 1em auto;border-left: 3px solid rgb(0, 0, 153);">分库分表带来的复杂性</h2> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 1em;color: rgb(0, 0, 153);padding-left: 10px;margin: 1em auto;border-left: 3px solid rgb(0, 0, 153);">总结</h2>

批处理框架 Spring Batch 这么强,你会用吗?

作者:微信小助手

<h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="font-family: STHeitiSC-Light;color: rgb(14, 136, 235);font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(14, 136, 235);">spring batch简介</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">spring batch是spring提供的一个数据处理框架。企业域中的许多应用程序需要批量处理才能在关键任务环境中执行业务操作。这些业务运营包括:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 无需用户交互即可最有效地处理大量信息的自动化,复杂处理。这些操作通常包括基于时间的事件(例如月末计算,通知或通信)。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 在非常大的数据集中重复处理复杂业务规则的定期应用(例如,保险利益确定或费率调整)。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 集成从内部和外部系统接收的信息,这些信息通常需要以事务方式格式化,验证和处理到记录系统中。批处理用于每天为企业处理数十亿的交易。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Spring Batch是一个轻量级,全面的批处理框架,旨在开发对企业系统日常运营至关重要的强大批处理应用程序。Spring Batch构建了人们期望的Spring Framework特性(生产力,基于POJO的开发方法和一般易用性),同时使开发人员可以在必要时轻松访问和利用更高级的企业服务。Spring Batch不是一个schuedling的框架。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Spring Batch提供了可重用的功能,这些功能对于处理大量的数据至关重要,包括记录/跟踪,事务管理,作业处理统计,作业重启,跳过和资源管理。它还提供更高级的技术服务和功能,通过优化和分区技术实现极高容量和高性能的批处理作业。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Spring Batch可用于两种简单的用例(例如将文件读入数据库或运行存储过程)以及复杂的大量用例(例如在数据库之间移动大量数据,转换它等等) 上)。大批量批处理作业可以高度可扩展的方式利用该框架来处理大量信息。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-family: STHeitiSC-Light;color: rgb(14, 136, 235);font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(14, 136, 235);">Spring Batch架构介绍</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">一个典型的批处理应用程序大致如下:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 从数据库,文件或队列中读取大量记录。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 以某种方式处理数据。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 以修改之后的形式写回数据。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">其对应的示意图如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.19736842105263158" src="/upload/cc71b7d7cc7ec05170aefc845fac7474.png" data-type="png" data-w="912" style="border-radius: 0px 0px 5px 5px;display: block;margin: 3px auto;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;height: auto !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">spring batch的一个总体的架构如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.3983739837398374" src="/upload/42f39c9220207b368bdd8fc8cb3f8f19.png" data-type="png" data-w="738" style="border-radius: 0px 0px 5px 5px;display: block;margin: 3px auto;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;height: auto !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">在spring batch中一个job可以定义很多的步骤step,在每一个step里面可以定义其专属的ItemReader用于读取数据,ItemProcesseor用于处理数据,ItemWriter用于写数据,而每一个定义的job则都在JobRepository里面,我们可以通过JobLauncher来启动某一个job。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-family: STHeitiSC-Light;color: rgb(14, 136, 235);font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(14, 136, 235);">Spring Batch核心概念介绍</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">下面是一些概念是Spring batch框架中的核心概念。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>什么是Job<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Job和Step是spring batch执行批处理任务最为核心的两个概念。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">其中Job是一个封装整个批处理过程的一个概念。Job在spring batch的体系当中只是一个最顶层的一个抽象概念,体现在代码当中则它只是一个最上层的接口,其代码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #75715e;line-height: 26px;">/**<br>&nbsp;*&nbsp;Batch&nbsp;domain&nbsp;object&nbsp;representing&nbsp;a&nbsp;job.&nbsp;Job&nbsp;is&nbsp;an&nbsp;explicit&nbsp;abstraction<br>&nbsp;*&nbsp;representing&nbsp;the&nbsp;configuration&nbsp;of&nbsp;a&nbsp;job&nbsp;specified&nbsp;by&nbsp;a&nbsp;developer.&nbsp;It&nbsp;should<br>&nbsp;*&nbsp;be&nbsp;noted&nbsp;that&nbsp;restart&nbsp;policy&nbsp;is&nbsp;applied&nbsp;to&nbsp;the&nbsp;job&nbsp;as&nbsp;a&nbsp;whole&nbsp;and&nbsp;not&nbsp;to&nbsp;a<br>&nbsp;*&nbsp;step.<br>&nbsp;*/</span><br><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">interface</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">Job</span>&nbsp;</span>{<br>&nbsp;<br>&nbsp;<span style="line-height: 26px;">String&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">getName</span><span style="line-height: 26px;">()</span></span>;<br>&nbsp;<br>&nbsp;<br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">boolean</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">isRestartable</span><span style="line-height: 26px;">()</span></span>;<br>&nbsp;<br>&nbsp;<br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">void</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">execute</span><span style="line-height: 26px;">(JobExecution&nbsp;execution)</span></span>;<br>&nbsp;<br>&nbsp;<br>&nbsp;<span style="line-height: 26px;">JobParametersIncrementer&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">getJobParametersIncrementer</span><span style="line-height: 26px;">()</span></span>;<br>&nbsp;<br>&nbsp;<br>&nbsp;<span style="line-height: 26px;">JobParametersValidator&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">getJobParametersValidator</span><span style="line-height: 26px;">()</span></span>;<br>&nbsp;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">在Job这个接口当中定义了五个方法,它的实现类主要有两种类型的job,一个是simplejob,另一个是flowjob。在spring batch当中,job是最顶层的抽象,除job之外我们还有JobInstance以及JobExecution这两个更加底层的抽象。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">一个job是我们运行的基本单位,它内部由step组成。job本质上可以看成step的一个容器。一个job可以按照指定的逻辑顺序组合step,并提供了我们给所有step设置相同属性的方法,例如一些事件监听,跳过策略。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Spring Batch以SimpleJob类的形式提供了Job接口的默认简单实现,它在Job之上创建了一些标准功能。一个使用java config的例子代码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #75715e;line-height: 26px;">@Bean</span><br><span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;Job&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">footballJob</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">this</span>.jobBuilderFactory.get(<span style="color: #a6e22e;line-height: 26px;">"footballJob"</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.start(playerLoad())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.next(gameLoad())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.next(playerSummarization())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.end()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.build();<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">这个配置的意思是:首先给这个job起了一个名字叫footballJob,接着指定了这个job的三个step,他们分别由方法,playerLoad,gameLoad, playerSummarization实现。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>什么是JobInstance<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">我们在上文已经提到了JobInstance,他是Job的更加底层的一个抽象,他的定义如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">interface</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">JobInstance</span>&nbsp;</span>{<br>&nbsp;<span style="color: #75715e;line-height: 26px;">/**<br>&nbsp;&nbsp;*&nbsp;Get&nbsp;unique&nbsp;id&nbsp;for&nbsp;this&nbsp;JobInstance.<br>&nbsp;&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@return</span>&nbsp;instance&nbsp;id<br>&nbsp;&nbsp;*/</span><br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">long</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">getInstanceId</span><span style="line-height: 26px;">()</span></span>;<br>&nbsp;<span style="color: #75715e;line-height: 26px;">/**<br>&nbsp;&nbsp;*&nbsp;Get&nbsp;job&nbsp;name.<br>&nbsp;&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@return</span>&nbsp;value&nbsp;of&nbsp;'id'&nbsp;attribute&nbsp;from&nbsp;&lt;job&gt;<br>&nbsp;&nbsp;*/</span><br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;String&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">getJobName</span><span style="line-height: 26px;">()</span></span>;&nbsp;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">他的方法很简单,一个是返回Job的id,另一个是返回Job的名字。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">JobInstance指的是job运行当中,作业执行过程当中的概念。Instance本就是实例的意思。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">比如说现在有一个批处理的job,它的功能是在一天结束时执行行一次。我们假定这个批处理job的名字为'EndOfDay'。在这个情况下,那么每天就会有一个逻辑意义上的JobInstance, 而我们必须记录job的每次运行的情况。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>什么是JobParameters<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">在上文当中我们提到了,同一个job每天运行一次的话,那么每天都有一个jobIntsance,但他们的job定义都是一样的,那么我们怎么来区别一个job的不同jobinstance了。不妨先做个猜想,虽然jobinstance的job定义一样,但是他们有的东西就不一样,例如运行时间。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">spring batch中提供的用来标识一个jobinstance的东西是:JobParameters。JobParameters对象包含一组用于启动批处理作业的参数,它可以在运行期间用于识别或甚至用作参考数据。我们假设的运行时间,就可以作为一个JobParameters。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">例如, 我们前面的'EndOfDay'的job现在已经有了两个实例,一个产生于1月1日,另一个产生于1月2日,那么我们就可以定义两个JobParameter对象:一个的参数是01-01, 另一个的参数是01-02。因此,识别一个JobInstance的方法可以定义为:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.2273449920508744" src="/upload/5f1b1d760a32db6301ad3f894b710433.png" data-type="png" data-w="1258" style="border-radius: 0px 0px 5px 5px;display: block;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;height: auto !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">因此,我么可以通过Jobparameter来操作正确的JobInstance</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>什么是JobExecution<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">JobExecution指的是单次尝试运行一个我们定义好的Job的代码层面的概念。job的一次执行可能以失败也可能成功。只有当执行成功完成时,给定的与执行相对应的JobInstance才也被视为完成。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">还是以前面描述的EndOfDay的job作为示例,假设第一次运行01-01-2019的JobInstance结果是失败。那么此时如果使用与第一次运行相同的Jobparameter参数(即01-01-2019)作业参数再次运行,那么就会创建一个对应于之前jobInstance的一个新的JobExecution实例,JobInstance仍然只有一个。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">JobExecution的接口定义如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">interface</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">JobExecution</span>&nbsp;</span>{<br>&nbsp;<span style="color: #75715e;line-height: 26px;">/**<br>&nbsp;&nbsp;*&nbsp;Get&nbsp;unique&nbsp;id&nbsp;for&nbsp;this&nbsp;JobExecution.<br>&nbsp;&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@return</span>&nbsp;execution&nbsp;id<br>&nbsp;&nbsp;*/</span><br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">long</span>&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">getExecutionId</span><span style="line-height: 26px;">()</span></span>;<br>&nbsp;<span style="color: #75715e;line-height: 26px;">/**<br>&nbsp;&nbsp;*&nbsp;Get&nbsp;job&nbsp;name.<br>&nbsp;&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@return</span>&nbsp;value&nbsp;of&nbsp;'id'&nbsp;attribute&nbsp;from&nbsp;&lt;job&gt;<br>&nbsp;&nbsp;*/</span><br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;String&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">getJobName</span><span style="line-height: 26px;">()</span></span>;&nbsp;<br>&nbsp;<span style="color: #75715e;line-height: 26px;">/**<br>&nbsp;&nbsp;*&nbsp;Get&nbsp;batch&nbsp;status&nbsp;of&nbsp;this&nbsp;execution.<br>&nbsp;&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@return</span>&nbsp;batch&nbsp;status&nbsp;value.<br>&nbsp;&nbsp;*/</span><br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;BatchStatus&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">getBatchStatus</span><span style="line-height: 26px;">()</span></span>;<br>&nbsp;<span style="color: #75715e;line-height: 26px;">/**<br>&nbsp;&nbsp;*&nbsp;Get&nbsp;time&nbsp;execution&nbsp;entered&nbsp;STARTED&nbsp;status.&nbsp;<br>&nbsp;&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@return</span>&nbsp;date&nbsp;(time)<br>&nbsp;&nbsp;*/</span><br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;Date&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">getStartTime</span><span style="line-height: 26px;">()</span></span>;<br>&nbsp;<span style="color: #75715e;line-height: 26px;">/**<br>&nbsp;&nbsp;*&nbsp;Get&nbsp;time&nbsp;execution&nbsp;entered&nbsp;end&nbsp;status:&nbsp;COMPLETED,&nbsp;STOPPED,&nbsp;FAILED&nbsp;<br>&nbsp;&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@return</span>&nbsp;date&nbsp;(time)<br>&nbsp;&nbsp;*/</span><br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;Date&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">getEndTime</span><span style="line-height: 26px;">()</span></span>;<br>&nbsp;<span style="color: #75715e;line-height: 26px;">/**<br>&nbsp;&nbsp;*&nbsp;Get&nbsp;execution&nbsp;exit&nbsp;status.<br>&nbsp;&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@return</span>&nbsp;exit&nbsp;status.<br>&nbsp;&nbsp;*/</span><br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;String&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">getExitStatus</span><span style="line-height: 26px;">()</span></span>;<br>&nbsp;<span style="color: #75715e;line-height: 26px;">/**<br>&nbsp;&nbsp;*&nbsp;Get&nbsp;time&nbsp;execution&nbsp;was&nbsp;created.<br>&nbsp;&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@return</span>&nbsp;date&nbsp;(time)<br>&nbsp;&nbsp;*/</span><br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;Date&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">getCreateTime</span><span style="line-height: 26px;">()</span></span>;<br>&nbsp;<span style="color: #75715e;line-height: 26px;">/**<br>&nbsp;&nbsp;*&nbsp;Get&nbsp;time&nbsp;execution&nbsp;was&nbsp;last&nbsp;updated&nbsp;updated.<br>&nbsp;&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@return</span>&nbsp;date&nbsp;(time)<br>&nbsp;&nbsp;*/</span><br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;Date&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">getLastUpdatedTime</span><span style="line-height: 26px;">()</span></span>;<br>&nbsp;<span style="color: #75715e;line-height: 26px;">/**<br>&nbsp;&nbsp;*&nbsp;Get&nbsp;job&nbsp;parameters&nbsp;for&nbsp;this&nbsp;execution.<br>&nbsp;&nbsp;*&nbsp;<span style="font-weight: bold;line-height: 26px;">@return</span>&nbsp;job&nbsp;parameters&nbsp;&nbsp;<br>&nbsp;&nbsp;*/</span><br>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;Properties&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">getJobParameters</span><span style="line-height: 26px;">()</span></span>;<br>&nbsp;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">每一个方法的注释已经解释的很清楚,这里不再多做解释。只提一下BatchStatus,JobExecution当中提供了一个方法getBatchStatus用于获取一个job某一次特地执行的一个状态。BatchStatus是一个代表job状态的枚举类,其定义如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">enum</span>&nbsp;BatchStatus&nbsp;{STARTING,&nbsp;STARTED,&nbsp;STOPPING,&nbsp;<br>&nbsp;&nbsp;&nbsp;STOPPED,&nbsp;FAILED,&nbsp;COMPLETED,&nbsp;ABANDONED&nbsp;}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">这些属性对于一个job的执行来说是非常关键的信息,并且spring batch会将他们持久到数据库当中. 在使用Spring batch的过程当中spring batch会自动创建一些表用于存储一些job相关的信息,用于存储JobExecution的表为<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;">batch_job_execution</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 data-ratio="0.15664961636828645" src="/upload/761a323717a04baf654ffe5a96e955ef.png" data-type="png" data-w="1564" style="border-radius: 0px 0px 5px 5px;display: block;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;height: auto !important;"> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>什么是Step<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">每一个Step对象都封装了批处理作业的一个独立的阶段。事实上,每一个Job本质上都是由一个或多个步骤组成。每一个step包含定义和控制实际批处理所需的所有信息。任何特定的内容都由编写Job的开发人员自行决定。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">一个step可以非常简单也可以非常复杂。例如,一个step的功能是将文件中的数据加载到数据库中,那么基于现在spring batch的支持则几乎不需要写代码。更复杂的step可能具有复杂的业务逻辑,这些逻辑作为处理的一部分。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">与Job一样,Step具有与JobExecution类似的StepExecution,如下图所示:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.7348643006263048" src="/upload/3b317e2983f02e6267147bc9f72415e6.png" data-type="png" data-w="479" style="border-radius: 0px 0px 5px 5px;display: block;margin: 3px auto;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;height: auto !important;"> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>什么是StepExecution<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">StepExecution表示一次执行Step, 每次运行一个Step时都会创建一个新的StepExecution,类似于JobExecution。但是,某个步骤可能由于其之前的步骤失败而无法执行。且仅当Step实际启动时才会创建StepExecution。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">一次step执行的实例由StepExecution类的对象表示。每个StepExecution都包含对其相应步骤的引用以及JobExecution和事务相关的数据,例如提交和回滚计数以及开始和结束时间。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">此外,每个步骤执行都包含一个ExecutionContext,其中包含开发人员需要在批处理运行中保留的任何数据,例如重新启动所需的统计信息或状态信息。下面是一个从数据库当中截图的实例:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.14911366006256518" src="/upload/8eebbeb700fe6de34535569ccd2aaae3.png" data-type="png" data-w="1918" style="border-radius: 0px 0px 5px 5px;display: block;margin: 3px auto;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;height: auto !important;"> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>什么是ExecutionContext<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">ExecutionContext即每一个StepExecution 的执行环境。它包含一系列的键值对。我们可以用如下代码获取ExecutionContext</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">ExecutionContext&nbsp;ecStep&nbsp;=&nbsp;stepExecution.getExecutionContext();<br>ExecutionContext&nbsp;ecJob&nbsp;=&nbsp;jobExecution.getExecutionContext();<br></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>什么是JobRepository<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">JobRepository是一个用于将上述job,step等概念进行持久化的一个类。它同时给Job和Step以及下文会提到的JobLauncher实现提供CRUD操作。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">首次启动Job时,将从repository中获取JobExecution,并且在执行批处理的过程中,StepExecution和JobExecution将被存储到repository当中。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;">@EnableBatchProcessing</code>注解可以为JobRepository提供自动配置。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>什么是JobLauncher<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">JobLauncher这个接口的功能非常简单,它是用于启动指定了JobParameters的Job,为什么这里要强调指定了JobParameter,原因其实我们在前面已经提到了,jobparameter和job一起才能组成一次job的执行。下面是代码实例:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">interface</span>&nbsp;<span style="font-weight: bold;color: white;line-height: 26px;">JobLauncher</span>&nbsp;</span>{<br>&nbsp;<br><span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;JobExecution&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">run</span><span style="line-height: 26px;">(Job&nbsp;job,&nbsp;JobParameters&nbsp;jobParameters)</span><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">throws</span>&nbsp;JobExecutionAlreadyRunningException,&nbsp;JobRestartException,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JobInstanceAlreadyCompleteException,&nbsp;JobParametersInvalidException</span>;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">上面run方法实现的功能是根据传入的job以及jobparamaters从JobRepository获取一个JobExecution并执行Job。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>什么是Item Reader<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">ItemReader是一个读数据的抽象,它的功能是为每一个Step提供数据输入。当ItemReader以及读完所有数据时,它会返回null来告诉后续操作数据已经读完。Spring Batch为ItemReader提供了非常多的有用的实现类,比如JdbcPagingItemReader,JdbcCursorItemReader等等。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">ItemReader支持的读入的数据源也是非常丰富的,包括各种类型的数据库,文件,数据流,等等。几乎涵盖了我们的所有场景。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">下面是一个JdbcPagingItemReader的例子代码:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #75715e;line-height: 26px;">@Bean</span><br><span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;JdbcPagingItemReader&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">itemReader</span><span style="line-height: 26px;">(DataSource&nbsp;dataSource,&nbsp;PagingQueryProvider&nbsp;queryProvider)</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Map&lt;String,&nbsp;Object&gt;&nbsp;parameterValues&nbsp;=&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;HashMap&lt;&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parameterValues.put(<span style="color: #a6e22e;line-height: 26px;">"status"</span>,&nbsp;<span style="color: #a6e22e;line-height: 26px;">"NEW"</span>);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;JdbcPagingItemReaderBuilder&lt;CustomerCredit&gt;()<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.name(<span style="color: #a6e22e;line-height: 26px;">"creditReader"</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.dataSource(dataSource)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.queryProvider(queryProvider)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.parameterValues(parameterValues)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.rowMapper(customerCreditMapper())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.pageSize(<span style="line-height: 26px;">1000</span>)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.build();<br>}<br>&nbsp;<br><span style="color: #75715e;line-height: 26px;">@Bean</span><br><span style="line-height: 26px;"><span style="color: #f92672;font-weight: bold;line-height: 26px;">public</span>&nbsp;SqlPagingQueryProviderFactoryBean&nbsp;<span style="color: #a6e22e;font-weight: bold;line-height: 26px;">queryProvider</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SqlPagingQueryProviderFactoryBean&nbsp;provider&nbsp;=&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;SqlPagingQueryProviderFactoryBean();<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;provider.setSelectClause(<span style="color: #a6e22e;line-height: 26px;">"select&nbsp;id,&nbsp;name,&nbsp;credit"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;provider.setFromClause(<span style="color: #a6e22e;line-height: 26px;">"from&nbsp;customer"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;provider.setWhereClause(<span style="color: #a6e22e;line-height: 26px;">"where&nbsp;status=:status"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;provider.setSortKey(<span style="color: #a6e22e;line-height: 26px;">"id"</span>);<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;provider;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">JdbcPagingItemReader必须指定一个PagingQueryProvider,负责提供SQL查询语句来按分页返回数据。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">下面是一个JdbcCursorItemReader的例子代码:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">private</span>&nbsp;JdbcCursorItemReader&lt;Map&lt;String,&nbsp;Object&gt;&gt;&nbsp;buildItemReader(<span style="color: #f92672;font-weight: bold;line-height: 26px;">final</span>&nbsp;DataSource&nbsp;dataSource,&nbsp;String&nbsp;tableName,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;tenant)&nbsp;{<br>&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JdbcCursorItemReader&lt;Map&lt;String,&nbsp;Object&gt;&gt;&nbsp;itemReader&nbsp;=&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;JdbcCursorItemReader&lt;&gt;();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;itemReader.setDataSource(dataSource);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;itemReader.setSql(<span style="color: #a6e22e;line-height: 26px;">"sql&nbsp;here"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;itemReader.setRowMapper(<span style="color: #f92672;font-weight: bold;line-height: 26px;">new</span>&nbsp;RowMapper());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #f92672;font-weight: bold;line-height: 26px;">return</span>&nbsp;itemReader;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>什么是Item Writer<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">既然ItemReader是读数据的一个抽象,那么ItemWriter自然就是一个写数据的抽象,它是为每一个step提供数据写出的功能。写的单位是可以配置的,我们可以一次写一条数据,也可以一次写一个chunk的数据,关于chunk下文会有专门的介绍。ItemWriter对于读入的数据是不能做任何操作的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">Spring Batch为ItemWriter也提供了非常多的有用的实现类,当然我们也可以去实现自己的writer功能。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>什么是Item Processor<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">ItemProcessor对项目的业务逻辑处理的一个抽象, 当ItemReader读取到一条记录之后,ItemWriter还未写入这条记录之前,I我们可以借助temProcessor提供一个处理业务逻辑的功能,并对数据进行相应操作。如果我们在ItemProcessor发现一条数据不应该被写入,可以通过返回null来表示。ItemProcessor和ItemReader以及ItemWriter可以非常好的结合在一起工作,他们之间的数据传输也非常方便。我们直接使用即可。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>chunk 处理流程<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">spring batch提供了让我们按照chunk处理数据的能力,一个chunk的示意图如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.5497326203208556" src="/upload/270f0eebb1d4a1e90d378c082133fc02.png" data-type="png" data-w="935" style="border-radius: 0px 0px 5px 5px;display: block;margin: 3px auto;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;height: auto !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">它的意思就和图示的一样,由于我们一次batch的任务可能会有很多的数据读写操作,因此一条一条的处理并向数据库提交的话效率不会很高,因此spring batch提供了chunk这个概念,我们可以设定一个chunk size,spring batch 将一条一条处理数据,但不提交到数据库,只有当处理的数据数量达到chunk size设定的值得时候,才一起去commit.</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">java的实例定义代码如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.7247706422018348" src="/upload/d18d711b197b8b5c6790f20f216de12b.png" data-type="png" data-w="654" style="border-radius: 0px 0px 5px 5px;display: block;margin: 3px auto;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;height: auto !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">在上面这个step里面,chunk size被设为了10,当ItemReader读的数据数量达到10的时候,这一批次的数据就一起被传到itemWriter,同时transaction被提交。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>skip策略和失败处理<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">一个batch的job的step,可能会处理非常大数量的数据,难免会遇到出错的情况,出错的情况虽出现的概率较小,但是我们不得不考虑这些情况,因为我们做数据迁移最重要的是要保证数据的最终一致性。spring batch当然也考虑到了这种情况,并且为我们提供了相关的技术支持,请看如下bean的配置:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.4603550295857988" src="/upload/8f345bbcd4456d22acce231450402eb2.png" data-type="png" data-w="845" style="border-radius: 0px 0px 5px 5px;display: block;margin: 3px auto;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;height: auto !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">我们需要留意这三个方法,分别是skipLimit(),skip(),noSkip(),</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">skipLimit方法的意思是我们可以设定一个我们允许的这个step可以跳过的异常数量,假如我们设定为10,则当这个step运行时,只要出现的异常数目不超过10,整个step都不会fail。注意,若不设定skipLimit,则其默认值是0.</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">skip方法我们可以指定我们可以跳过的异常,因为有些异常的出现,我们是可以忽略的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">noSkip方法的意思则是指出现这个异常我们不想跳过,也就是从skip的所以exception当中排除这个exception,从上面的例子来说,也就是跳过所有除FileNotFoundException的exception。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">那么对于这个step来说,FileNotFoundException就是一个fatal的exception,抛出这个exception的时候step就会直接fail</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-family: STHeitiSC-Light;color: rgb(14, 136, 235);font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(14, 136, 235);">批处理操作指南</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">本部分是一些使用spring batch时的值得注意的点</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>批处理原则<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">在构建批处理解决方案时,应考虑以下关键原则和注意事项。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 批处理体系结构通常会影响体系结构 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 尽可能简化并避免在单批应用程序中构建复杂的逻辑结构 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 保持数据的处理和存储在物理上靠得很近(换句话说,将数据保存在处理过程中)。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 最大限度地减少系统资源的使用,尤其是I / O. 在internal memory中执行尽可能多的操作。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 查看应用程序I / O(分析SQL语句)以确保避免不必要的物理I / O. 特别是,需要寻找以下四个常见缺陷: </section></li> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;list-style-type: square;" class="list-paddingleft-2"> <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> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 未在SQL语句的WHERE子句中指定键值。 </section></li> </ul> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 在批处理运行中不要做两次一样的事情。例如,如果需要数据汇总以用于报告目的,则应该(如果可能)在最初处理数据时递增存储的总计,因此您的报告应用程序不必重新处理相同的数据。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 在批处理应用程序开始时分配足够的内存,以避免在此过程中进行耗时的重新分配。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 总是假设数据完整性最差。插入适当的检查和记录验证以维护数据完整性。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 尽可能实施校验和以进行内部验证。例如,对于一个文件里的数据应该有一个数据条数纪录,告诉文件中的记录总数以及关键字段的汇总。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 在具有真实数据量的类似生产环境中尽早计划和执行压力测试。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 在大批量系统中,数据备份可能具有挑战性,特别是如果系统以24-7在线的情况运行。数据库备份通常在在线设计中得到很好的处理,但文件备份应该被视为同样重要。如果系统依赖于文件,则文件备份过程不仅应该到位并记录在案,还应定期进行测试。 </section></li> </ul> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;margin-top: 20px;margin-right: 10px;"><span style="display: none;"></span><span style="font-family: STHeitiSC-Light;color: rgb(14, 136, 235);font-weight: bolder;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(14, 136, 235);">如何默认不启动job</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">在使用java config使用spring batch的job时,如果不做任何配置,项目在启动时就会默认去跑我们定义好的批处理job。那么如何让项目在启动时不自动去跑job呢?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">spring batch的job会在项目启动时自动run,如果我们不想让他在启动时run的话,可以在application.properties中添加如下属性:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;background: #272822;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">spring.batch.job.enabled=<span style="color: #f92672;font-weight: bold;line-height: 26px;">false</span><br></code></pre> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>在读数据时内存不够<span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">在使用spring batch做数据迁移时,发现在job启动后,执行到一定时间点时就卡在一个地方不动了,且log也不再打印,等待一段时间之后,得到如下错误:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.14664981036662453" src="/upload/97c66c91ecae4dc20af6e87c170d5706.png" data-type="png" data-w="1582" style="border-radius: 0px 0px 5px 5px;display: block;margin: 3px auto;object-fit: contain;box-shadow: rgb(132, 161, 168) 0px 10px 15px;height: auto !important;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">红字的信息为:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;">Resource exhaustion event:the JVM was unable to allocate memory from the heap.</code></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">翻译过来的意思就是项目发出了一个资源耗尽的事件,告诉我们java虚拟机无法再为堆分配内存。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 10px;margin-bottom: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">造成这个错误的原因是: 这个项目里的batch job的reader是一次性拿回了数据库里的所有数据,并没有进行分页,当这个数据量太大时,就会导致内存不够用。解决的办法有两个:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 调整reader读数据逻辑,按分页读取,但实现上会麻烦一些,且运行效率会下降 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 增大service内存 </section></li> </ul>

阿里面试这样问:redis 为什么把简单的字符串设计成 SDS?

作者:微信小助手

<figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> </figure> <blockquote data-tool="mdnice编辑器" style="border-width: initial;border-style: none;border-color: initial;font-size: 0.9em;overflow: auto;margin-bottom: 20px;margin-top: 20px;padding-top: 10px;padding-right: 10px;padding-bottom: 10px;line-height: 1.8;border-radius: 0px 0px 10px 10px;color: rgb(14, 136, 235);background: rgb(255, 255, 255);box-shadow: rgb(132, 161, 168) 0px 10px 15px;"> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);">SDS结构</h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);">效率高</h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);">数据溢出</h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);">内存重分配策略</h3> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;">1.空间预分配</h4> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;">2.惰性空间释放</h4> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);">数据格式多样性</h3> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);">总结</h3>

Netty 百万级推送服务设计与优化!

作者:微信小助手

<blockquote style="line-height: inherit;padding: 15px 15px 15px 1rem;font-size: 0.9em;color: rgb(129, 145, 152);border-left-width: 6px;border-left-color: rgb(220, 230, 240);background: rgb(242, 247, 251);overflow: auto;overflow-wrap: normal;word-break: normal;"> <p style="font-size: inherit;color: inherit;line-height: inherit;"><strong style="font-size: inherit;color: inherit;line-height: inherit;">作者简介:</strong><br>李林锋,2007 年毕业于东北大学,2008 年进入华为公司从事高性能通信软件的设计和开发工作,有 6 年 NIO 设计和开发经验,精通 Netty、Mina 等 NIO 框架。Netty 中国社区创始人,《Netty 权威指南》作者。</p> </blockquote> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">背景</span></h3> <h4 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">话题来源</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">最近很多从事移动互联网和物联网开发的同学给我发邮件或者微博私信我,咨询推送服务相关的问题。问题五花八门,在帮助大家答疑解惑的过程中,我也对问题进行了总结,大概可以归纳为如下几类:</p> <ol style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" clas

高并发下用 MQ 踩过哪些坑?

作者:微信小助手

<p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">通用kafka消费方案:<img data-ratio="0.8169934640522876" src="/upload/2964de7398f57573c01a080e4b1d74a6.png" data-type="png" data-w="1224" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;object-fit: contain;"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">消息积压优化方案:<img data-ratio="0.6901639344262295" src="/upload/227177ed3f0c0d2113a4ad976040a55c.png" data-type="png" data-w="1220" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;object-fit: contain;"></p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzUxODkzNTQ3Nw==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/uL371281oDHlDcdbjNJic1yCwAu2dmJ9AunIQh9DXdm5JE7v9libnPgJQicoaGs9Eiaee2kPeFGWJxsPkZ9zCQbrIw/0?wx_fmt=png" data-nickname="苏三说技术" data-alias="susanSayJava" data-signature="作者就职于知名互联网公司,掘金月度优秀作者,从事开发、架构和部分管理工作。实战经验丰富,对jdk、spring、springboot、springcloud、mybatis等开源框架源码有一定研究,欢迎关注,和我一起交流。" data-from="0"></mpprofile> </section> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);"><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">《<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxODkzNTQ3Nw==&amp;mid=2247486496&amp;idx=1&amp;sn=063f248ea9ae0b594194bcfc9c7449d8&amp;chksm=f9800afacef783ec3034bbf1b065be01d92225c5442039388cf7a1dad16d0120f93034075b69&amp;scene=21#wechat_redirect" textvalue="高并发下如何保证接口的幂等性?" data-itemshowtype="0" tab="innerlink" data-linktype="2">高并发下如何保证接口的幂等性?</a>》</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">这篇文章介绍了高并发下,解决幂等性问题的8种非常实用的方案。文章发表后,被转载的次数有30+,深受广大读者的好评。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.8236245954692557" src="/upload/3ab71512a3474fc7c4b0ff974b541983.png" data-type="png" data-w="1236" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;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;"> <img data-ratio="0.8615635179153095" src="/upload/650813e0c2848e4fc5d092fdb5724255.png" data-type="png" data-w="1228" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);"><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">《<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxODkzNTQ3Nw==&amp;mid=2247486944&amp;idx=1&amp;sn=66131d65fd68d5be3f27aa38e997b366&amp;chksm=f9800b3acef7822ceb628f81e51c36e5c4ecc9d4811b9f151c1613e6bfee69ea81e84f3ea1d9&amp;scene=21#wechat_redirect" textvalue="面霸:mq的6大核心问题" data-itemshowtype="0" tab="innerlink" data-linktype="2">面霸:mq的6大核心问题</a>》</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">这篇文章介绍了mq的6大核心问题,是居家旅行,尤其是面试的必备良药。这篇文章也有20+的转载。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.8578274760383386" src="/upload/ad3324de764588e15753084600c27511.png" data-type="png" data-w="1252" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;object-fit: contain;"> </figure> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;margin-top: 15px;"><span style="display: none;"></span><span style="font-size: 18px;color: #f48a00;display: inline-block;padding-left: 10px;border-left: 4px solid #ffe3a3;">spring 系列</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">《<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxODkzNTQ3Nw==&amp;mid=2247485741&amp;idx=1&amp;sn=7e981b1e781a9e7f9be929fe94baaa2f&amp;chksm=f9800ff7cef786e166f97f6c81c5bd61e1d0e490ae88f1320ef8bc28c0c123b127846e8d139a&amp;scene=21#wechat_redirect" textvalue="spring那些让你爱不释手的代码技巧" data-itemshowtype="0" tab="innerlink" data-linktype="2">spring那些让你爱不释手的代码技巧</a>》</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">这篇文章分享了spring中11个牛逼的小技巧,在项目中使用的话,能够让代码优雅不少。文章发表后,被转载的次数有30+,受到全网各大平台读者的好评。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.8134715025906736" src="/upload/47155010fb81902ab9b38f58a9b4ab30.png" data-type="png" data-w="1158" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;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;"> <img data-ratio="0.8923327895595432" src="/upload/d6b52625524e96f54b7a0f3b78568c02.png" data-type="png" data-w="1226" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);"><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">《<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxODkzNTQ3Nw==&amp;mid=2247485600&amp;idx=1&amp;sn=0c49b94e7fbd35c88c4470e936023e3e&amp;chksm=f9800e7acef7876ca05ab45ce9420ea140f188e84153f23d0af9d044f475458ad38d49a6546a&amp;scene=21#wechat_redirect" textvalue="spring:我是如何解决循环依赖的?" data-itemshowtype="0" tab="innerlink" data-linktype="2">spring:我是如何解决循环依赖的?</a>》</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">这篇文章图文想结合,深入分析了spring循环依赖问题的多方面知识,是目前我看到过的介绍循环问题,最好的一篇文章,看了之后真的受益匪浅。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.5893719806763285" src="/upload/62a8ffacd3a258399acd7dd8d63c8ea5.png" data-type="png" data-w="1242" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;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;"> <img data-ratio="0.7959183673469388" src="/upload/b83ede5ffb698eeb9df22a93cb25ae9d.png" data-type="png" data-w="1274" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);"><br></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">《<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxODkzNTQ3Nw==&amp;mid=2247485642&amp;idx=1&amp;sn=00004fe7df9643c0312769404cc806f3&amp;chksm=f9800e10cef7870683817f43bca47ebd3c2b6db9414a5fa4c9e6faf83d284d1ddca9653f6259&amp;scene=21#wechat_redirect" textvalue="9条消除if...else的锦囊妙计" data-itemshowtype="0" tab="innerlink" data-linktype="2">9条消除if...else的锦囊妙计</a>》</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">这篇文章分享了9条消息if...else的锦囊妙计,里面用到了N多个设计模式。也许你会不经感慨,原来设计模式还可以这样用。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.40064620355411956" src="/upload/b8350a670e6f59265c220f56eee490b0.png" data-type="png" data-w="1238" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;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;"> <img data-ratio="0.8624161073825504" src="/upload/73c6372d0566c16e1d23f663993758b9.png" data-type="png" data-w="1192" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;object-fit: contain;"> </figure> <h3 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 20px;margin-top: 15px;"><span style="display: none;"></span><span style="font-size: 18px;color: #f48a00;display: inline-block;padding-left: 10px;border-left: 4px solid #ffe3a3;">数据库 系列</span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">《<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzUxODkzNTQ3Nw==&amp;mid=2247486138&amp;idx=1&amp;sn=282845b0835e0121026fa706ce4b0083&amp;chksm=f9800c60cef78576a0fa7fc9c13a9f765372fd86ea5089fdc27a9f12c16871bf362dc3fcb52d&amp;scene=21#wechat_redirect" textvalue="卧槽,sql注入竟然把我们系统搞挂了" data-itemshowtype="0" tab="innerlink" data-linktype="2">卧槽,sql注入竟然把我们系统搞挂了</a>》</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">这篇文章从一个线上事故开始,深入分析了sql注入问题的发生,如何解决,以及以后如何预防。可以说面面俱到,是一篇不可多得的佳作。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.6356466876971609" src="/upload/494202347107bf9d8be2d02619203214.png" data-type="png" data-w="1268" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;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;"> <img data-ratio="0.8372827804107424" src="/upload/fca0525c0c231217ff8d0809a7766c47.png" data-type="png" data-w="1266" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">他的硬核文章太多了,我在这里就不一一列举了,你可以从他的公众号中阅读到更多精彩内容。强烈建议关注下方公众号,还在等什么?</p>

Redis 新特性篇:多线程模型解读

作者:微信小助手

<p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">Redis 官方在 2020 年 5 月正式推出 6.0 版本,提供很多振奋人心的新特性,所以备受关注。</p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;text-size-adjust: 100%;line-height: 1.75em;border-radius: 5px;box-sizing: inherit;border-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-color: rgb(255, 191, 82);background: rgb(255, 248, 230);"> <span style="color: #f48a00;font-size: 32px;line-height: 0.6;margin-left: -15px;">❝</span> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;line-height: 26px;margin-top: -15px;color: rgba(0, 0, 0, 0.85);">Redis 6.0 提供了啥特性呀?知道了我能加薪么?</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">主要特性如下:</p> <ol data-tool="mdnice编辑器" style="font-size: 15px;margin-top: 8px;margin-bottom: 8px;padding-left: 20px;color: rgb(255, 191, 82);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 多线程处理网络 IO; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 客户端缓存; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 细粒度权限控制(ACL); </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> <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: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">RESP3</code> 协议的使用; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 用于复制的 RDB 文件不在有用,将立刻被删除; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> RDB 文件加载速度更快; </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">其中备受关注的就是「<strong>多线程模型 + 客户端缓存</strong>」,我们只有掌握了新特性原理,才能判断什么时候使用 6.0 版本,如何用的更好更快,不踩坑。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">本篇先从 <strong>Redis 多线程模型</strong>开始,至于客户端缓存、等且听下回分解。<span style="letter-spacing: 0.1em;word-spacing: 0.1em;"></span></p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;text-size-adjust: 100%;line-height: 1.75em;border-radius: 5px;box-sizing: inherit;border-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-color: rgb(255, 191, 82);background: rgb(255, 248, 230);"> <span style="color: #f48a00;font-size: 32px;line-height: 0.6;margin-left: -15px;">❝</span> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;line-height: 26px;margin-top: -15px;color: rgba(0, 0, 0, 0.85);">Redis 6.0 之前为什么不使用多线程?</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">官方答复:</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;margin-top: 8px;margin-bottom: 8px;padding-left: 20px;color: rgb(255, 191, 82);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> <p style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">使用 Redis 时,几乎不存在 CPU 成为瓶颈的情况, Redis 主要受限于内存和网络。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> <p style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">在一个普通的 Linux 系统上,Redis 通过使用<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: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">pipelining</code> 每秒可以处理 100 万个请求,所以如果应用程序主要使用 O(N) 或O(log(N)) 的命令,它几乎不会占用太多 CPU。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> <p style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">使用了单线程后,可维护性高。多线程模型虽然在某些方面表现优异,但是它却引入了程序执行顺序的不确定性,带来了并发读写的一系列问题,增加了系统复杂度、同时可能存在线程切换、甚至加锁解锁、死锁造成的性能损耗。</p> </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">Redis 通过 AE 事件模型以及 IO 多路复用等技术,处理性能非常高,因此没有必要使用多线程。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);"><strong>单线程机制让 Redis 内部实现的复杂度大大降低,Hash 的惰性 Rehash、Lpush 等等『线程不安全』的命令都可以无锁进行</strong>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);"><strong>在《<a href="https://mp.weixin.qq.com/s?__biz=MzkzMDI1NjcyOQ==&amp;mid=2247487752&amp;idx=1&amp;sn=72a1725e1c86bb5e883dd8444e5bd6c4&amp;chksm=c27c533ef50bda288417c31f5210bb16a70361b2e2c344dfffdb079b54b241cd6c62202d9775&amp;scene=21#wechat_redirect" style="color: rgb(244, 138, 0);border-bottom: 1px solid rgb(244, 138, 0);font-family: STHeitiSC-Light;font-weight: normal;" data-linktype="2">Redis 为什么这么快?</a>》码哥有详细介绍快的原理</strong>。</p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;text-size-adjust: 100%;line-height: 1.75em;border-radius: 5px;box-sizing: inherit;border-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-color: rgb(255, 191, 82);background: rgb(255, 248, 230);"> <span style="color: #f48a00;font-size: 32px;line-height: 0.6;margin-left: -15px;">❝</span> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;line-height: 26px;margin-top: -15px;color: rgba(0, 0, 0, 0.85);">Redis 6.0 之前单线程指的是 Redis 只有一个线程干活么?</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">非也,<strong>Redis 在处理客户端的请求时,包括获取 (socket 读)、解析、执行、内容返回 (socket 写) 等都由一个顺序串行的主线程处理,这就是所谓的「单线程」</strong>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">其中执行命令阶段,由于 Redis 是单线程来处理命令的,所有每一条到达服务端的命令不会立刻执行,所有的命令都会进入一个 Socket 队列中,当 socket 可读则交给单线程事件分发器逐个被执行。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.3979496738117428" src="/upload/4bd469eeae322398a002fe13b0c57c34.png" data-type="png" data-w="1073" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;object-fit: contain;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">此外,有些命令操作可以用后台线程或子进程执行(比如数据删除、快照生成、AOF 重写)。</p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;text-size-adjust: 100%;line-height: 1.75em;border-radius: 5px;box-sizing: inherit;border-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-color: rgb(255, 191, 82);background: rgb(255, 248, 230);"> <span style="color: #f48a00;font-size: 32px;line-height: 0.6;margin-left: -15px;">❝</span> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;line-height: 26px;margin-top: -15px;color: rgba(0, 0, 0, 0.85);">那 Redis 6.0 为啥要引入多线程呀?</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">随着硬件性能提升,Redis 的性能瓶颈可能出现网络 IO 的读写,也就是:<strong>单个线程处理网络读写的速度跟不上底层网络硬件的速度</strong>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">读写网络的 <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: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">read/write</code> 系统调用占用了Redis 执行期间大部分CPU 时间,瓶颈主要在于网络的 IO 消耗, 优化主要有两个方向:</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;margin-top: 8px;margin-bottom: 8px;padding-left: 20px;color: rgb(255, 191, 82);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 提高网络 IO 性能,典型的实现比如使用 <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: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">DPDK</code>来替代内核网络栈的方式。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 使用多线程充分利用多核,提高网络请求读写的并行度,典型的实现比如 <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: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">Memcached</code>。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">添加对用户态网络协议栈的支持,需要修改 Redis 源码中和网络相关的部分(例如修改所有的网络收发请求函数),这会带来很多开发工作量。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">而且新增代码还可能引入新 Bug,导致系统不稳定。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">所以,Redis 采用多个 IO 线程来处理网络请求,提高网络请求处理的并行度。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);"><strong>需要注意的是,Redis 多 IO 线程模型只用来处理网络读写请求,对于 Redis 的读写命令,依然是单线程处理</strong>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">这是因为,网络处理经常是瓶颈,通过多线程并行处理可提高性能。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">而继续使用单线程执行读写命令,不需要为了保证 Lua 脚本、事务、等开发多线程安全机制,实现更简单。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);"><strong>架构图如下</strong>:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.4848800834202294" src="/upload/fca90a633ccee813954540aced50e561.png" data-type="png" data-w="959" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;object-fit: contain;"> <figcaption style="margin-top: 5px;font-size: 13px;color: rgba(0, 0, 0, 0.55);text-align: right;"> 图片来源:后端研究所 </figcaption> </figure> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;text-size-adjust: 100%;line-height: 1.75em;border-radius: 5px;box-sizing: inherit;border-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-color: rgb(255, 191, 82);background: rgb(255, 248, 230);"> <span style="color: #f48a00;font-size: 32px;line-height: 0.6;margin-left: -15px;">❝</span> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;line-height: 26px;margin-top: -15px;color: rgba(0, 0, 0, 0.85);">主线程与 IO 多线程是如何实现协作呢?</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">如下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="1.5067567567567568" src="/upload/b25a67f5506e7af597515b93b92a3dc4.png" data-type="png" data-w="740" style="border-radius: 5px;display: block;margin-right: 10px;margin-bottom: auto;margin-left: 10px;width: 100%;height: 100%;object-fit: contain;"> <figcaption style="margin-top: 5px;font-size: 13px;color: rgba(0, 0, 0, 0.55);text-align: right;"> Redis多线程与IO线程 </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);"><strong>主要流程</strong>:</p> <ol data-tool="mdnice编辑器" style="font-size: 15px;margin-top: 8px;margin-bottom: 8px;padding-left: 20px;color: rgb(255, 191, 82);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 主线程负责接收建立连接请求,获取 <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: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">socket</code> 放入全局等待读处理队列; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 主线程通过轮询将可读 <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: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">socket</code> 分配给 IO 线程; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 主线程阻塞等待 IO 线程读取 <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: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">socket</code> 完成; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 主线程执行 IO 线程读取和解析出来的 Redis 请求命令; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 主线程阻塞等待 IO 线程将指令执行结果回写回 <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: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">socket</code>完毕; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 主线程清空全局队列,等待客户端后续的请求。 </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">思路:<strong>将主线程 IO 读写任务拆分出来给一组独立的线程处理,使得多个 socket 读写可以并行化,但是 Redis 命令还是主线程串行执行。</strong></p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;text-size-adjust: 100%;line-height: 1.75em;border-radius: 5px;box-sizing: inherit;border-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-color: rgb(255, 191, 82);background: rgb(255, 248, 230);"> <span style="color: #f48a00;font-size: 32px;line-height: 0.6;margin-left: -15px;">❝</span> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;line-height: 26px;margin-top: -15px;color: rgba(0, 0, 0, 0.85);">如何开启多线程呢?</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">Redis 6.0 的多线程默认是禁用的,只使用主线程。如需开启需要修改 <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: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">redis.conf</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: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">io-threads-do-reads yes</code>。</p> <blockquote data-tool="mdnice编辑器" style="font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;text-size-adjust: 100%;line-height: 1.75em;border-radius: 5px;box-sizing: inherit;border-width: 1px;border-top-style: solid;border-right-style: solid;border-bottom-style: solid;border-color: rgb(255, 191, 82);background: rgb(255, 248, 230);"> <span style="color: #f48a00;font-size: 32px;line-height: 0.6;margin-left: -15px;">❝</span> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.1em;font-size: 16px;word-spacing: 0.1em;text-align: justify;line-height: 26px;margin-top: -15px;color: rgba(0, 0, 0, 0.85);">码老湿,线程数是不是越多越好?</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">当然不是,关于线程数的设置,官方有一个建议:4 核的机器建议设置为 2 或 3 个线程,8核的建议设置为 6 个线程,线程数一定要小于机器核数。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">线程数并不是越大越好,官方认为超过了 8 个基本就没什么意义了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);"><strong>另外,开启多线程后,还需要设置线程数,否则是不生效的</strong>。</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(&quot;https://mmbiz.qpic.cn/mmbiz_svg/7N2JRaWooRCWUcW3cJYFoibAqfMMxz9wacljKYbu7c71IuqwCeicIHwZyOEKFx8jvFjrOYiaoia9SrhCEEPYERHAGDM2PkfPan2e/640?wx_fmt=svg&quot;) 10px 10px / 40px no-repeat rgb(39, 40, 34);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #ddd;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #272822;border-radius: 5px;">io-threads&nbsp;4<br></code></pre> <h1 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 24px;text-align: center;line-height: 95px;margin-top: 10px;margin-bottom: 10px;"><span style="display: none;"></span><span style="font-size: 22px;color: #f48a00;border-bottom: 2px solid #ffbf52;">总结与思考</span></h1> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">随着互联网的飞速发展,互联网业务系统所要处理的线上流量越来越大,Redis 的单线程模式会导致系统消耗很多 CPU 时间在网络 I/O 上从而降低吞吐量,要提升 Redis 的性能有两个方向:</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;margin-top: 8px;margin-bottom: 8px;padding-left: 20px;color: rgb(255, 191, 82);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 优化网络 I/O 模块 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 提高机器内存读写的速度 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">后者依赖于硬件的发展,暂时无解。所以只能从前者下手,网络 I/O 的优化又可以分为两个方向:</p> <ul data-tool="mdnice编辑器" style="font-size: 15px;margin-top: 8px;margin-bottom: 8px;padding-left: 20px;color: rgb(255, 191, 82);" class="list-paddingleft-2"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 零拷贝技术或者 DPDK 技术 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;letter-spacing: 0.1em;word-spacing: 0.1em;color: rgba(0, 0, 0, 0.55);"> 利用多核优势 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);"><strong>模型缺陷</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">Redis 的多线程网络模型实际上并不是一个标准的 <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: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(244, 138, 0);">Multi-Reactors/Master-Workers</code>模型。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">Redis 的多线程方案中,I/O 线程任务仅仅是通过 socket 读取客户端请求命令并解析,却没有真正去执行命令。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">所有客户端命令最后还需要回到主线程去执行,因此对多核的利用率并不算高,而且每次主线程都必须在分配完任务之后忙轮询等待所有 I/O 线程完成任务之后才能继续执行其他逻辑。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-top: 5px;margin-bottom: 5px;line-height: 1.75;letter-spacing: 0.1em;word-spacing: 0.1em;text-align: justify;color: rgba(0, 0, 0, 0.85);">在我看来,Redis 目前的多线程方案更像是一个折中的选择:既保持了原系统的兼容性,又能利用多核提升 I/O 性能。<span style="letter-spacing: 1.6px;word-spacing: 1.6px;"></span></p> <section class="mp_profile_iframe_wrp"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzkzMDI1NjcyOQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/EoJib2tNvVtf7icAmS0BQH6oDVG37Q8NzcfdguS5qAqOhfxvZyIKqmuX5BbnDjynrBbZzktp1EiaeFLzapp1nHysw/0?wx_fmt=png" data-nickname="码哥字节" data-alias="MageByte" data-signature="既有硬核文章,又有诗和远方。" data-from="0"></mpprofile> </section>

MySql知识体系总结(SQL优化篇)

作者:微信小助手

<p data-mpa-powered-by="yiban.io"><span style="color: rgb(77, 77, 77);font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;font-size: 16px;text-align: start;background-color: rgb(255, 255, 255);">本篇是MySQL知识体系总结系列的第二篇,该篇的主要内容是通过explain逐步分析sql,并通过修改sql语句与建立索引的方式对sql语句进行调优,也可以通过查看日志的方式,了解sql的执行情况,还介绍了MySQL数据库的行锁和表锁。</span></p> <p><br></p> <h2 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 24px;color: rgb(79, 79, 79);line-height: 32px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">一、explain返回列简介</h2> <h3 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 22px;color: rgb(79, 79, 79);line-height: 30px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">1、type常用关键字</h3> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;">system &gt; const &gt; eq_ref &gt; ref &gt; range &gt; index &gt; all。</p> <ol class="list-paddingleft-2" style="list-style-type: decimal;"> <li><p>system:表仅有一行,基本用不到;</p></li> <li><p>const:表最多一行数据配合,主键查询时触发较多;</p></li> <li><p>eq_ref:对于每个来自于前面的表的行组合,从该表中读取一行。这可能是最好的联接类型,除了const类型;</p></li> <li><p>ref:对于每个来自于前面的表的行组合,所有有匹配索引值的行将从这张表中读取;</p></li> <li><p>range:只检索给定范围的行,使用一个索引来选择行。当使用=、&lt;&gt;、&gt;、&gt;=、&lt;、&lt;=、IS NULL、&lt;=&gt;、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用range;</p></li> <li><p>index:该联接类型与ALL相同,除了只有索引树被扫描。这通常比ALL快,因为索引文件通常比数据文件小;</p></li> <li><p>all:全表扫描;</p></li> </ol> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;">实际sql优化中,最后达到ref或range级别。</p> <h3 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 22px;color: rgb(79, 79, 79);line-height: 30px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">2、Extra常用关键字</h3> <p>Using index:只从索引树中获取信息,而不需要回表查询;</p> <p><br></p> <p>Using where:WHERE子句用于限制哪一个行匹配下一个表或发送到客户。除非你专门从表中索取或检查所有行,如果Extra值不为Using where并且表联接类型为ALL或index,查询可能会有一些错误。需要回表查询。</p> <p><br></p> <p>Using temporary:mysql常建一个临时表来容纳结果,典型情况如查询包含可以按不同情况列出列的GROUP BY和ORDER BY子句时;</p> <h2 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 24px;color: rgb(79, 79, 79);line-height: 32px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">二、触发索引代码实例</h2> <h3 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 22px;color: rgb(79, 79, 79);line-height: 30px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">1、建表语句 + 联合索引</h3> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="sql"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">CREATE</span> <span class="code-snippet__keyword">TABLE</span> <span class="code-snippet__string">`student`</span> (</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`id`</span> <span class="code-snippet__built_in">int</span>(<span class="code-snippet__number">10</span>) <span class="code-snippet__keyword">NOT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`name`</span> <span class="code-snippet__built_in">varchar</span>(<span class="code-snippet__number">20</span>) <span class="code-snippet__keyword">NOT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`age`</span> <span class="code-snippet__built_in">int</span>(<span class="code-snippet__number">10</span>) <span class="code-snippet__keyword">NOT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`sex`</span> <span class="code-snippet__built_in">int</span>(<span class="code-snippet__number">11</span>) <span class="code-snippet__keyword">DEFAULT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`address`</span> <span class="code-snippet__built_in">varchar</span>(<span class="code-snippet__number">100</span>) <span class="code-snippet__keyword">DEFAULT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`phone`</span> <span class="code-snippet__built_in">varchar</span>(<span class="code-snippet__number">100</span>) <span class="code-snippet__keyword">DEFAULT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`create_time`</span> <span class="code-snippet__built_in">timestamp</span> <span class="code-snippet__literal">NULL</span> <span class="code-snippet__keyword">DEFAULT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`update_time`</span> <span class="code-snippet__built_in">timestamp</span> <span class="code-snippet__literal">NULL</span> <span class="code-snippet__keyword">DEFAULT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`deleted`</span> <span class="code-snippet__built_in">int</span>(<span class="code-snippet__number">11</span>) <span class="code-snippet__keyword">DEFAULT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> PRIMARY <span class="code-snippet__keyword">KEY</span> (<span class="code-snippet__string">`id`</span>),</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">KEY</span> <span class="code-snippet__string">`student_union_index`</span> (<span class="code-snippet__string">`name`</span>,<span class="code-snippet__string">`age`</span>,<span class="code-snippet__string">`sex`</span>)</span></code><code><span class="code-snippet_outer">) <span class="code-snippet__keyword">ENGINE</span>=<span class="code-snippet__keyword">InnoDB</span> <span class="code-snippet__keyword">DEFAULT</span> <span class="code-snippet__keyword">CHARSET</span>=utf8;</span></code></pre> </section> <h3 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 22px;color: rgb(79, 79, 79);line-height: 30px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">2、使用主键查询</h3> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;"><img data-ratio="0.2028262676641729" src="/upload/dc7ecaf34513b4319722777f313021d2.png" data-type="png" data-w="1203" height="140" style="box-sizing: border-box;outline: none;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;" width="690"></p> <h3 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 22px;color: rgb(79, 79, 79);line-height: 30px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">3、使用联合索引查询</h3> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;line-height: 26px !important;"><img data-ratio="0.12413793103448276" src="/upload/b65f3df3cb18ac1dd32fdd721a0a206f.png" data-type="png" data-w="1450" style="box-sizing: border-box;outline: none;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;"></p> <h3 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 22px;color: rgb(79, 79, 79);line-height: 30px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">4、联合索引,但与索引顺序不一致</h3> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;"><img data-ratio="0.1785983421250942" src="/upload/298b72396ccc6db944b0d0066b91167d.png" data-type="png" data-w="1327" style="box-sizing: border-box;outline: none;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;"></p> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;">备注:因为mysql优化器的缘故,与索引顺序不一致,也会触发索引,但实际项目中尽量顺序一致。</p> <h3 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 22px;color: rgb(79, 79, 79);line-height: 30px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">5、联合索引,但其中一个条件是 &gt;</h3> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;"><img data-ratio="0.12413793103448276" src="/upload/b65f3df3cb18ac1dd32fdd721a0a206f.png" data-type="png" data-w="1450" style="box-sizing: border-box;outline: none;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;"></p> <h3 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 22px;color: rgb(79, 79, 79);line-height: 30px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">6、联合索引,order by</h3> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;"><img data-ratio="0.12542837559972583" src="/upload/154ed68be325ef88a4397c7121ee5701.png" data-type="png" data-w="1459" style="box-sizing: border-box;outline: none;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;"></p> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;">where和order by一起使用时,不要跨索引列使用。</p> <p><br></p> <h2 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 24px;color: rgb(79, 79, 79);line-height: 32px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">三、单表sql优化</h2> <h3 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 22px;color: rgb(79, 79, 79);line-height: 30px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">1、删除student表中的联合索引。</h3> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;"><img data-ratio="0.1557943207981581" src="/upload/9e6db6bcbefba8c2d63c1154571f178a.png" data-type="png" data-w="1303" style="box-sizing: border-box;outline: none;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;"></p> <p style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 22px;color: rgb(79, 79, 79);line-height: 30px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">2、添加索引</p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="sql"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">alter</span> <span class="code-snippet__keyword">table</span> student <span class="code-snippet__keyword">add</span> <span class="code-snippet__keyword">index</span> student_union_index(<span class="code-snippet__keyword">name</span>,age,sex);</span></code></pre> </section> <p style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 22px;color: rgb(79, 79, 79);line-height: 30px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.14685792349726776" src="/upload/bcf75127d97a8775dd6f4ae0ed22ec88.png" data-type="png" data-w="1464"></p> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;">优化一点,但效果不是很好,因为type是index类型,extra中依然存在using where。</p> <h3 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 22px;color: rgb(79, 79, 79);line-height: 30px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">3、更改索引顺序</h3> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;">因为sql的编写过程</p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="sql"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">select</span> <span class="code-snippet__keyword">distinct</span> ... <span class="code-snippet__keyword">from</span> ... <span class="code-snippet__keyword">join</span> ... <span class="code-snippet__keyword">on</span> ... <span class="code-snippet__keyword">where</span> ... <span class="code-snippet__keyword">group</span> <span class="code-snippet__keyword">by</span> ... <span class="code-snippet__keyword">having</span> ... <span class="code-snippet__keyword">order</span> <span class="code-snippet__keyword">by</span> ... <span class="code-snippet__keyword">limit</span> ...</span></code></pre> </section> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;">解析过程</p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">from</span> ... <span class="code-snippet__keyword">on</span> ... <span class="code-snippet__keyword">join</span> ... <span class="code-snippet__keyword">where</span> ... <span class="code-snippet__keyword">group</span> <span class="code-snippet__keyword">by</span> ... having ... <span class="code-snippet__keyword">select</span> distinct ... order <span class="code-snippet__keyword">by</span> ... limit ...</span></code></pre> </section> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;">&nbsp;因此我怀疑是联合索引建的顺序问题,导致触发索引的效果不好。are you sure?试一下就知道了。</p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="sql"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">alter</span> <span class="code-snippet__keyword">table</span> student <span class="code-snippet__keyword">add</span> <span class="code-snippet__keyword">index</span> student_union_index2(age,sex,<span class="code-snippet__keyword">name</span>);</span></code></pre> </section> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;">删除旧的不用的索引:</p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="sql"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">drop</span> <span class="code-snippet__keyword">index</span> student_union_index <span class="code-snippet__keyword">on</span> student</span></code></pre> </section> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;">索引改名</p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="sql"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">ALTER</span> <span class="code-snippet__keyword">TABLE</span> student <span class="code-snippet__keyword">RENAME</span> <span class="code-snippet__keyword">INDEX</span> student_union_index2 <span class="code-snippet__keyword">TO</span> student_union_index</span></code></pre> </section> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;">更改索引顺序之后,发现type级别发生了变化,由index变为了range。</p> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;">range:只检索给定范围的行,使用一个索引来选择行。</p> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;"><img data-ratio="0.15537555228276878" src="/upload/aee103e2334925ea53b1fe2d87a89254.png" data-type="png" data-w="1358" style="box-sizing: border-box;outline: none;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;"></p> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;">备注:in会导致索引失效,所以触发using where,进而导致回表查询。</p> <h3 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 22px;color: rgb(79, 79, 79);line-height: 30px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">4、去掉in</h3> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;"><img data-ratio="0.16083395383469842" src="/upload/1b7da2274f0a68c2b095c85b801c3f77.png" data-type="png" data-w="1343" style="box-sizing: border-box;outline: none;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;"></p> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;">ref:对于每个来自于前面的表的行组合,<span style="outline: 0px;color: rgb(254, 44, 36);">所有有匹配索引值的行</span>将从这张表中读取;</p> <p style="outline: 0px;margin-bottom: 16px;font-size: 16px;color: rgb(77, 77, 77);overflow: auto hidden;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);line-height: 26px !important;">index 提升为ref了,优化到此结束。</p> <h3 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 22px;color: rgb(79, 79, 79);line-height: 30px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">5、小结</h3> <ol style="outline: 0px;margin-bottom: 24px;list-style: none;font-size: 16px;font-family: -apple-system, &quot;SF UI Text&quot;, Arial, &quot;PingFang SC&quot;, &quot;Hiragino Sans GB&quot;, &quot;Microsoft YaHei&quot;, &quot;WenQuanYi Micro Hei&quot;, sans-serif, SimHei, SimSun;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li style="outline: 0px;margin-top: 8px;margin-left: 40px;list-style: decimal;"><p>保持索引的定义和使用顺序一致性;</p></li> <li style="outline: 0px;margin-top: 8px;margin-left: 40px;list-style: decimal;"><p>索引需要逐步优化,不要总想着一口吃成胖子;</p></li> <li style="outline: 0px;margin-top: 8px;margin-left: 40px;list-style: decimal;"><p>将含in的范围查询,放到where条件的最后,防止索引失效;</p></li> </ol> <h2 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 24px;color: rgb(79, 79, 79);line-height: 32px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">四、双表sql优化</h2> <h3 style="outline: 0px;margin-top: 8px;margin-bottom: 16px;font-weight: 700;font-family: &quot;PingFang SC&quot;, &quot;Microsoft YaHei&quot;, SimHei, Arial, SimSun;font-size: 22px;color: rgb(79, 79, 79);line-height: 30px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">1、建表语句</h3> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="sql"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">CREATE</span> <span class="code-snippet__keyword">TABLE</span> <span class="code-snippet__string">`student`</span> (</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`id`</span> <span class="code-snippet__built_in">int</span>(<span class="code-snippet__number">10</span>) <span class="code-snippet__keyword">NOT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`name`</span> <span class="code-snippet__built_in">varchar</span>(<span class="code-snippet__number">20</span>) <span class="code-snippet__keyword">NOT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`age`</span> <span class="code-snippet__built_in">int</span>(<span class="code-snippet__number">10</span>) <span class="code-snippet__keyword">NOT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`sex`</span> <span class="code-snippet__built_in">int</span>(<span class="code-snippet__number">11</span>) <span class="code-snippet__keyword">DEFAULT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`address`</span> <span class="code-snippet__built_in">varchar</span>(<span class="code-snippet__number">100</span>) <span class="code-snippet__keyword">DEFAULT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`phone`</span> <span class="code-snippet__built_in">varchar</span>(<span class="code-snippet__number">100</span>) <span class="code-snippet__keyword">DEFAULT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`create_time`</span> <span class="code-snippet__built_in">timestamp</span> <span class="code-snippet__literal">NULL</span> <span class="code-snippet__keyword">DEFAULT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`update_time`</span> <span class="code-snippet__built_in">timestamp</span> <span class="code-snippet__literal">NULL</span> <span class="code-snippet__keyword">DEFAULT</span> <span class="code-snippet__literal">NULL</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__string">`deleted`</span> <span class="code-snippet__built_in">int</span>(<span class="code-snippet__number">11</span>) <span class="code-snippet__keyword">DEFAULT</span> <

系统架构设计:平滑发布和ABTesting

作者:微信小助手

<section class="mp_profile_iframe_wrp" data-mpa-powered-by="yiban.io"> <mpprofile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzA3ODIxNjYxNQ==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/Baq5lYpIw7WIvzVfHZ61VvJoaTzb7HDxtsJoicXicBJJ5uc9FrPG3eVztG6eBfUfdwIYmoqu8ibM5APCTDBUBPLrg/0?wx_fmt=png" data-nickname="架构文摘" data-alias="ArchDigest" data-signature="每天一篇架构领域重磅好文,涉及一线互联网公司应用架构(高可用、高性能、高稳定)、大数据、机器学习、Java架构等各个热门领域。" data-from="0"></mpprofile> </section> <h2 offset="1" style="margin-top: 10px;margin-bottom: 10px;font-size: 21px;font-weight: bold;color: rgb(68, 68, 68);line-height: 1.5;font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">平滑发布的介绍&nbsp;<br></h2> <h3 offset="2" style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;color: rgb(68, 68, 68);line-height: 1.5;font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">背景&nbsp;</h3> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">单位的云办公相关系统没有成熟的平滑发布方案,导致每一次发布都是直接发布,dll文件或配置文件的变更会引起站点的重启。&nbsp;</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">云办公系统的常驻用户有10000+,即使短短半分多钟,也会收到一堆投诉。基于此,我们梳理了一套平滑发布的方案。</p> <h3 offset="2" style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;color: rgb(68, 68, 68);line-height: 1.5;font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">实施方案</h3> <p>1、跟nginx代理服务器约定了一个健康检查的接口</p> <p>2、通过接口返回的http状态码来让ngx是否分流用户请求(这个我们单位的技术部那边有标准的做法)</p> <p>3、根据提供的这个服务健康检查的接口:nginx判断只要某个实例的接口返回5xx的状态码,即把该实例下线(nginx不会把流量转发到该实例)</p> <p>&nbsp;</p> <p><img data-ratio="1.1861738535249828" src="/upload/ee5bde05733835e45c7df9598943496.png" data-type="png" data-w="2922"></p> <p>&nbsp;</p> <p>&nbsp;</p> <h3 offset="2" style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;color: rgb(68, 68, 68);line-height: 1.5;">发布流程</h3> <p style="margin: 10px auto;">目的主要是为了发布的时候能够平滑发布,所以QA与开发人员在发布得时候按照如下步骤操作:</p> <p style="margin: 10px auto;">1、打开系统的nginx列表管理页面:[/publish/ngxconfig]</p> <p style="margin: 10px auto;">2、下架某一个实例(假设系统集群有A、B、C个实例),比如A实例</p> <p style="margin: 10px auto;"><img data-ratio="0.44865258557902404" src="/upload/40a9cde1cff17b75bc50e8f05d1b5430.png" data-type="png" data-w="1373"></p> <p style="margin: 10px auto;">3、查看是否下架成功:这个就是我们跟nginx约定的健康检查接口,正常在线状态下是200的statu,切离线后,这个接口返回的是401的statu。</p> <p style="margin: 10px auto;">在线情况:</p> <p style="margin: 10px auto;"><img data-ratio="0.49706457925636005" src="/upload/7170bdf36bdd12332e3ee0f5eb33240a.png" data-type="png" data-w="1022"></p> <p style="margin: 10px auto;">&nbsp;</p> <p style="margin: 10px auto;">离线情况:</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.4256505576208178" src="/upload/83d19d8b49074d65af4505f5ed4cb734.png" data-type="png" data-w="1076" height="287" style="border-width: 0px;border-style: initial;border-color: initial;max-width: 700px;cursor: -webkit-zoom-in;transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1) 0s !important;" title="点击查看大图" width="681"></p> <p style="margin: 10px auto;">4、观察监控站点,直至该实例下的Req、Connnectiuon流量都消失<br></p> <p style="margin: 10px auto;">&nbsp;<img data-ratio="0.22013926084627744" src="/upload/369e7a2937d5e94704ad9a3f8448f2ce.png" data-type="png" data-w="1867"></p> <p style="margin: 10px auto;">5、在该实例下进行版本发布</p> <p style="margin: 10px auto;">6、打开Fidller,host到待发布的实例,然后判断是否发布成功(发布dll、配置文件时,IIS站点会短暂重启)</p> <p style="margin: 10px auto;">7、QA同学走查灰度的A实例服务器,保证它正常运行,如此循环,直到所有服务器都发布。</p> <p>&nbsp;&nbsp;</p> <h2 offset="1" style="margin-top: 10px;margin-bottom: 10px;font-size: 21px;font-weight: bold;color: rgb(68, 68, 68);line-height: 1.5;font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">进一步ABTesting的优化&nbsp;</h2> <h3 offset="2" style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;color: rgb(68, 68, 68);line-height: 1.5;font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">背景&nbsp;&nbsp;</h3> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">平滑发布做完之后,确实给我带来很大的便利,不用每次发布都发公告,不重要的或者非功能性的内容发布了就是了。</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">但是用久了,客户量上去之后,又遇到一个问题,那就是每一次业务大变更,大型发布都是直接发布到生产,这样可能存在风险。设计师设计的功能,用户不一定完全接受,一旦上线新版本,</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">收到一大堆的吐槽,都是用户呀,如果能在小范围人群内进行灰度试用,完成平稳的过度和使用反馈之后,优化后再上到生产会更好一点。</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">所以这边需要思考和设计一套统一的技术方案,未来无论云办公还是其他的业务系统,都能通过灰度发布在可指定的小范围内先进行体验和功能验证。</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">基于上面的平滑,我们在Nginx反向代理服务器上动心思,让nginx来帮我们做ABTesting的方案。以下是我们尝试的几种方案:</p> <h3 offset="2" style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;color: rgb(68, 68, 68);line-height: 1.5;font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">1、Nginx反向代理:来路IP策略&nbsp;</h3> <h4 offset="3" style="margin-top: 10px;margin-bottom: 10px;font-size: 14px;font-weight: bold;color: rgb(68, 68, 68);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">流程</h4> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.687984496124031" src="/upload/bce9adcb24aa6e6e08262b3408e590f5.png" data-type="png" data-w="1032" height="480" style="border-width: 0px;border-style: initial;border-color: initial;max-width: 700px;cursor: -webkit-zoom-in;transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1) 0s !important;" title="点击查看大图" width="698"></p> <h4 offset="3" style="margin-top: 10px;margin-bottom: 10px;font-size: 14px;font-weight: bold;color: rgb(68, 68, 68);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">步骤<br></h4> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">1、进入云办公系统,进入Nginx反代服务器</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">2、Nginx读取来路IP的AB名单</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">3、根据IP AB名单进行流量转发(名单A走特定实例,名单B走云办公原有集群实例)</p> <p><br></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="nginx"><code><span class="code-snippet_outer"><span class="code-snippet__section">server</span> {</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">listen</span> <span class="code-snippet__number">80</span>;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">server_name</span> officecloud.com;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">access_log</span> officecloud.com/logs main;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">ip_list</span> <span class="code-snippet__number">192.168.254.4</span>,<span class="code-snippet__number">192.168.254.170</span></span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">set <span class="code-snippet__variable">$group</span> default;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">if</span> (<span class="code-snippet__variable">$remote_addr</span> in iplist) {</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">set</span> <span class="code-snippet__variable">$group</span> ACluster;</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">location</span> / { </span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">proxy_pass</span> http://<span class="code-snippet__variable">$group</span>;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">proxy_set_header</span> Host <span class="code-snippet__variable">$host</span>;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">proxy_set_header</span> X-Real-IP <span class="code-snippet__variable">$remote_addr</span>;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">proxy_set_header</span> X-Forwarded-For <span class="code-snippet__variable">$proxy_add_x_forwarded_for</span>;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">index</span> index.html index.htm;</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p><br></p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><br></p> <h4 offset="3" style="margin-top: 10px;margin-bottom: 10px;font-size: 14px;font-weight: bold;color: rgb(68, 68, 68);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">优缺点</h4> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">1、配置简单,原资源平台的灰度升级就是根据IP名单来划分设计升级的</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">2、外部计算机很多都是非固定IP,这个适合在公司内网实现,比如只是配置公司内网的IP。</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">&nbsp;</p> <h3 offset="2" style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;color: rgb(68, 68, 68);line-height: 1.5;font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">2、Nginx反向代理:$.Cookies策略&nbsp;</h3> <h4 offset="3" style="margin-top: 10px;margin-bottom: 10px;font-size: 14px;font-weight: bold;color: rgb(68, 68, 68);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">流程</h4> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.7094594594594594" src="/upload/3e6b8ae5a2e0ea4a77f189bb8a9bdc64.png" data-type="png" data-w="1036" height="522" style="border-width: 0px;border-style: initial;border-color: initial;max-width: 700px;cursor: -webkit-zoom-in;transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1) 0s !important;" title="点击查看大图" width="736"></p> <h4 offset="3" style="margin-top: 10px;margin-bottom: 10px;font-size: 14px;font-weight: bold;color: rgb(68, 68, 68);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">步骤<br></h4> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">1、进入云办公系统,进入Nginx反代服务器</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">2、Nginx读取Http请求的Cokie的version信息(也可以是别的key)</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">3、根据Key的版本来进行流量转发(比如Version1.1走特定集群,Version1.0走通用集群实例)&nbsp;</p> <p><br></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="nginx"><code><span class="code-snippet_outer"><span class="code-snippet__section">server</span> {</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">listen</span> <span class="code-snippet__number">80</span>;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">server_name</span> officecloud.com;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">access_log</span> officecloud.com/logs main;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">ip_list</span> <span class="code-snippet__number">192.168.254.4</span>,<span class="code-snippet__number">192.168.254.170</span></span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer">set <span class="code-snippet__variable">$group</span> default;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">if</span> (<span class="code-snippet__variable">$http_cookie</span> <span class="code-snippet__regexp">~* "version=V1.0")</span>{</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">set</span> default;</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">if</span> (<span class="code-snippet__variable">$http_cookie</span> <span class="code-snippet__regexp">~* "version=V1.1")</span>{</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">set</span> <span class="code-snippet__variable">$group</span> ACluster;</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">location</span> / { </span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">proxy_pass</span> http://<span class="code-snippet__variable">$group</span>;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">proxy_set_header</span> Host <span class="code-snippet__variable">$host</span>;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">proxy_set_header</span> X-Real-IP <span class="code-snippet__variable">$remote_addr</span>;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">proxy_set_header</span> X-Forwarded-For <span class="code-snippet__variable">$proxy_add_x_forwarded_for</span>;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__attribute">index</span> index.html index.htm;</span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p><br></p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><br></p> <h4 offset="3" style="margin-top: 10px;margin-bottom: 10px;font-size: 14px;font-weight: bold;color: rgb(68, 68, 68);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">优缺点</h4> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">1、配置简单,根据Nginx的 $COOKIE_version 属性来判断</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">2、相对稳定,对需要开放名单的用户,在Cookie头部加入特定的版本即可,应用只要少许的开发量</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">3、首次访问静态页面可能不会产生cookie</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><span style="color: rgb(255, 0, 0);">备注:这是团队内认为最好的Nginx代理方案,同理,User-Agent和Header都可以做此种类型的判断,但是Header需要侵入底层HttpRequest去业务添加,不建议。</span></p> <h3 offset="2" style="margin-top: 10px;margin-bottom: 10px;font-weight: bold;color: rgb(68, 68, 68);line-height: 1.5;font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">3、AB集群+业务代理方式&nbsp;</h3> <h4 offset="3" style="margin-top: 10px;margin-bottom: 10px;font-size: 14px;font-weight: bold;color: rgb(68, 68, 68);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">流程</h4> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><img data-ratio="0.6194444444444445" src="/upload/75afbd91a7cb4b12aa0c4b220842a4ed.png" data-type="png" data-w="1080" height="534" style="border-width: 0px;border-style: initial;border-color: initial;max-width: 700px;cursor: -webkit-zoom-in;transition: transform 0.3s cubic-bezier(0.2, 0, 0.2, 1) 0s !important;" title="点击查看大图" width="863"></p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">步骤<br></p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">1、进入云办公系统,两种方式进入系统,一种是登录页登录:~/login ,一种是default页面带uckey登录:~/default?usertoken=#usertoken#</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">2、登录的时候和usertoken传入的时候进去 路由代理模块,进行用户信息校验,根据不同的人员和部门(人员和部门配置归属AB名单)分流到两个不同的AB集群</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">3、根据转发跳到具体的实例集群域名下(可以配置AB集群拥有不同域名,更容易区分)</p> <h4 offset="3" style="margin-top: 10px;margin-bottom: 10px;font-size: 14px;font-weight: bold;color: rgb(68, 68, 68);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">优缺点&nbsp;</h4> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">1、与Nginx剥离,不用依赖公司的通用平台和技术部的实现</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">2、需要申请AB集群,AB集群拥有不同的域名。</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">3、如果是前后端分离情况下,需要保证静态站点和服务站点均申请AB集群</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">4、所有入口需要统一做代理,有一定的开发量</p> <h4 offset="3" style="margin-top: 10px;margin-bottom: 10px;font-size: 14px;font-weight: bold;color: rgb(68, 68, 68);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">应用</h4> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">目前手上2个系统已经根据该方案实现了</p> <h2 offset="1" style="margin-top: 10px;margin-bottom: 10px;font-size: 21px;font-weight: bold;color: rgb(68, 68, 68);line-height: 1.5;font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">参考资料</h2> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">https://github.com/CNSRE/ABTestingGateway ABTestingGateway</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">ABTestingGateway是新浪开源的一个动态路由系统。ABTestingGateway是一个可以动态设置分流策略的灰度发布系统,工作在7层,</p> <p style="margin: 10px auto;color: rgb(0, 0, 0);font-family: 'Helvetica Neue', Helvetica, Verdana, Arial, sans-serif;font-size: 14px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">基于nginx和ngx-lua开发,使用redis作为分流策略数据库,可以实现动态调度功能。</p>

Spring为什么建议构造器注入?

作者:微信小助手

<h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">前言</h3> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">本章的内容主要是想探讨我们在进行Spring 开发过程当中,关于依赖注入的几个知识点。感兴趣的读者可以先看下以下问题:</p> <ul style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;font-size: 15px;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);" class="list-paddingleft-2"> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="color: rgb(53, 179, 120);"><code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);word-break: break-all;">@Autowired</code>,&nbsp;<code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);word-break: break-all;">@Resource</code>,&nbsp;<code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);word-break: break-all;">@Inject</code>&nbsp;三个注解的区别</strong> </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="color: rgb(53, 179, 120);">当你在使用<code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);word-break: break-all;">@Autowired</code>时,是否有出现过<code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);word-break: break-all;">Field injection is not recommended</code>的警告?你知道这是为什么吗?</strong> </section></li> <li> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);"> <strong style="color: rgb(53, 179, 120);">Spring 依赖注入有哪几种方式?官方是怎么建议使用的呢?</strong> </section></li> </ul> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">如果你对上述问题都了解,那我个人觉得你的开发经验应该是不错的👍。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">下面我们就依次对上述问题进行解答,并且总结知识点。</p> <h3 style="margin-top: 1.2em;margin-bottom: 1em;color: rgb(53, 179, 120);font-weight: bold;font-size: 20px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><code style="font-size: 1em;font-family: source-code-pro, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace;">@Autowired</code>,&nbsp;<code style="font-size: 1em;font-family: source-code-pro, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace;">@Resource</code>,&nbsp;<code style="font-size: 1em;font-family: source-code-pro, Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace;">@Inject</code>&nbsp;三个注解的区别</h3> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">Spring 支持使用<code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(53, 179, 120);background-color: rgba(27, 31, 35, 0.05);word-break: break-all;">@Autowired</code>,&nbsp;<code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(53, 179, 120);background-color: rgba(27, 31, 35, 0.05);word-break: break-all;">@Resource</code>,&nbsp;<code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(53, 179, 120);background-color: rgba(27, 31, 35, 0.05);word-break: break-all;">@Inject</code>&nbsp;三个注解进行依赖注入。下面来介绍一下这三个注解有什么区别。</p> <h4 style="margin-top: 30px;margin-bottom: 15px;color: black;font-weight: bold;font-size: 18px;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">@Autowired</h4> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);"><code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(53, 179, 120);background-color: rgba(27, 31, 35, 0.05);word-break: break-all;">@Autowired</code>为Spring 框架提供的注解,需要导入包<code style="font-size: 14px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(53, 179, 120);background-color: rgba(27, 31, 35, 0.05);word-break: break-all;">org.springframework.beans.factory.annotation.Autowired</code>。</p> <p style="margin: 1em 4px;font-size: 16px;padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, &quot;PingFang SC&quot;, Cambria, Cochin, Georgia, Times, &quot;Times New Roman&quot;, serif;letter-spacing: 0.75px;text-align: left;white-space: normal;background-color: rgb(255, 255, 255);">这里先给出一个示例代码,方便讲解说明:</p> <pre style="font-size: 15px;font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace;margin-top: 10px;margin-bottom: 10px;overflow: auto;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;color: rgb(89, 89, 89);letter-spacing: 0.75px;text-align: left;background-color: rgb(255, 255, 255);"><code style="font-size: 12px;font-family: &quot;Operator Mono&quot;, Consolas, Monaco, Menlo, monospace;display: -webkit-box;overflow-x: auto;padding: 15px 16px 16px;color: rgb(171, 178, 191);background: rgb(40, 44, 52);border-radius: 5px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">interface</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">Svc</span>&nbsp;</span>{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">void</span>&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">sayHello</span><span style="line-height: 26px;">()</span></span>;<br>}<br><br><span style="color: rgb(97, 174, 238);line-height: 26px;">@Service</span><br><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">class</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">SvcA</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">implements</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">Svc</span>&nbsp;</span>{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">@Override</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">void</span>&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">sayHello</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(152, 195, 121);line-height: 26px;">"hello,&nbsp;this&nbsp;is&nbsp;service&nbsp;A"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br><br><span style="color: rgb(97, 174, 238);line-height: 26px;">@Service</span><br><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">class</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">SvcB</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">implements</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">Svc</span>&nbsp;</span>{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">@Override</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">void</span>&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">sayHello</span><span style="line-height: 26px;">()</span>&nbsp;</span>{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(<span style="color: rgb(152, 195, 121);line-height: 26px;">"hello,&nbsp;this&nbsp;is&nbsp;service&nbsp;B"</span>);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br><br><span style="color: rgb(97, 174, 238);line-height: 26px;">@Service</span><br><span style="color: rgb(198, 120, 221);line-height: 26px;">public</span>&nbsp;<span style="line-height: 26px;"><span style="color: rgb(198, 120, 221);line-height: 26px;">class</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">SvcC</span>&nbsp;<span style="color: rgb(198, 120, 221);line-height: 26px;">implements</span>&nbsp;<span style="color: rgb(230, 192, 123);line-height: 26px;">Svc</span>&nbsp;</span>{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: rgb(97, 174, 238);line-height: 26px;">@Override</span><br>&nbsp;&nbsp;&nbsp;&nbsp;<span style="line-height: 26px;"><s

MySQL 5.7.28 一键安装脚本-shell

作者:じ☆ve不哭

``` #!/bin/bash function loginfo() { if [[ $? -eq 0 ]];then echo -e "\033[32m[INFO][$(date +"%F %T")] $1 succeed! \033[0m" else echo -e "\033[31m[ERROR][$(date +"%F %T")] $1 failed! \033[0m" fi } function install_mysql() { echo -e "\033[32mBegin install mysql V5.7.28 ...\033[0m" # 安装依赖 sudo yum install libaio -y >/dev/null 2>&1 loginfo "libaio install" BASE_DIR=$(pwd) MYSQL_PKG_PATH=$BASE_DIR/mysql-5.7.28-linux-glibc2.12-x86_64.tar.gz DEPLOY_PATH="/opt" USER=$(whoami) GROUP=$(groups) MYSQL_URL="http://download.mrlapulga.com/Linux/Mysql/software/generic/mysql-5.7.28-linux-glibc2.12-x86_64.tar.gz" # 下载解压创建目录 echo -e "\033[32mBegin download mysql V5.7.28 ...\033[0m" sudo curl -o ${DEPLOY_PATH}/mysql-5.7.28-linux-glibc2.12-x86_64.tar.gz ${MYSQL_URL} >/dev/null 2>&1 loginfo "mysql software download" sudo tar xf ${MYSQL_PKG_PATH} -C ${DEPLOY_PATH}/ loginfo "mysql software decompression" if [[ -d ${DEPLOY_PATH}/mysql ]];then rm -rf ${DEPLOY_PATH}/mysql fi sudo ln -s ${DEPLOY_PATH}/mysql-5.7.28-linux-glibc2.12-x86_64 ${DEPLOY_PATH}/mysql loginfo "create mysql dir soft link" if [[ -d /data/mysql ]];then rm -rf /data/mysql fi sudo mkdir -p /data/mysql loginfo "create mysql data dir" # 修改启动脚本 sudo sed -i '46s#basedir=#basedir=/opt/mysql#' ${DEPLOY_PATH}/mysql/support-files/mysql.server sudo sed -i '47s#datadir=#datadir=/data/mysql#' ${DEPLOY_PATH}/mysql/support-files/mysql.server sudo cp ${DEPLOY_PATH}/mysql/support-files/mysql.server /etc/init.d/mysqld sudo chmod 755 /etc/init.d/mysqld # 创建用户 if ! grep -q '^mysql:' /etc/group then sudo groupadd mysql loginfo "create user mysql" fi if ! grep -q '^mysql:' /etc/passwd then sudo useradd -r -g mysql -s /bin/false mysql loginfo "create group mysql" fi # 赋予data目录和base目录普通用户组 sudo chown -R ${USER}.${GROUP} ${DEPLOY_PATH}/mysql/ sudo chown -R ${USER}.${GROUP} /data/ if [ ! -f /usr/bin/mysql ] then sudo ln -s /opt/mysql/bin/mysql /usr/bin/ fi # 创建配置文件 if [ -f /etc/my.cnf ] then sudo rm -f /etc/my.cnf fi sudo bash -c "cat >> /etc/my.cnf" <<EOF [mysqld] datadir = /data/mysql basedir = /opt/mysql #tmpdir = /data/mysql/tmp_mysql port = 3306 socket = /data/mysql/mysql.sock pid-file = /data/mysql/mysql.pid max_connections = 8000 max_connect_errors = 100000 max_user_connections = 3000 check_proxy_users = on mysql_native_password_proxy_users = on local_infile = OFF symbolic-links = FALSE group_concat_max_len = 4294967295 max_join_size = 18446744073709551615 max_execution_time = 20000 lock_wait_timeout = 60 autocommit = 1 lower_case_table_names = 1 thread_cache_size = 64 disabled_storage_engines = "MyISAM,FEDERATED" character_set_server = utf8mb4 character-set-client-handshake = FALSE collation_server = utf8mb4_general_ci init_connect = 'SET NAMES utf8mb4' transaction-isolation = "READ-COMMITTED" skip_name_resolve = ON explicit_defaults_for_timestamp = ON log_timestamps = SYSTEM local_infile = OFF event_scheduler = OFF query_cache_type = OFF query_cache_size = 0 sql_mode = NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO log_error = /data/mysql/mysql.err slow_query_log = ON slow_query_log_file = /data/mysql/slow.log long_query_time = 1 general_log = OFF general_log_file = /data/mysql/general.log expire_logs_days = 99 log-bin = /data/mysql/mysql-bin log-bin-index = /data/mysql/mysql-bin.index max_binlog_size = 500M binlog_format = mixed binlog_rows_query_log_events = ON binlog_cache_size = 128k binlog_stmt_cache_size = 128k log-bin-trust-function-creators = 1 max_binlog_cache_size = 2G max_binlog_stmt_cache_size = 2G relay_log = /data/mysql/relay relay_log_index = /data/mysql/relay.index max_relay_log_size = 500M relay_log_purge = ON relay_log_recovery = ON server_id = 1 read_buffer_size = 1M read_rnd_buffer_size = 2M sort_buffer_size = 64M join_buffer_size = 64M tmp_table_size = 64M max_allowed_packet = 128M max_heap_table_size = 64M connect_timeout = 43200 wait_timeout = 43200 back_log = 512 interactive_timeout = 300 net_read_timeout = 30 net_write_timeout = 30 skip_external_locking = ON key_buffer_size = 16M bulk_insert_buffer_size = 16M concurrent_insert = ALWAYS open_files_limit = 65000 table_open_cache = 16000 table_definition_cache = 16000 default_storage_engine = InnoDB default_tmp_storage_engine = InnoDB internal_tmp_disk_storage_engine = InnoDB [client] socket = /data/mysql/mysql.sock default_character_set = utf8mb4 [mysql] default_character_set = utf8mb4 [ndatad default] TransactionDeadLockDetectionTimeOut = 20000 EOF sudo chown -R ${USER}.${GROUP} /etc/my.cnf loginfo "configure my.cnf" # 创建SSL证书 # sudo mkdir -p ${DEPLOY_PATH}/mysql/ca-pem/ # sudo ${DEPLOY_PATH}/mysql/bin/mysql_ssl_rsa_setup -d ${DEPLOY_PATH}/mysql/ca-pem/ --uid=mysql # sudo chown -R ${USER}.${GROUP} ${DEPLOY_PATH}/mysql/ca-pem/ # sudo bash -c "cat >> /data/mysql/init_file.sql" <<EOF # set global sql_safe_updates=0; # set global sql_select_limit=50000; # EOF # sudo chown -R ${USER}.${GROUP} /data/mysql/init_file.sql # sudo chown -R ${USER}.${GROUP} /etc/init.d/mysqld # 初始化 ${DEPLOY_PATH}/mysql/bin/mysqld --initialize --user=mysql --basedir=${DEPLOY_PATH}/mysql --datadir=/data/mysql loginfo "initialize mysql" # 过滤初始密码 mysql_passwd=$(grep 'A temporary password is generated' /data/mysql/mysql.err |awk '{print $NF}') # 启动服务 /etc/init.d/mysqld start loginfo "start mysqld" # 修改初始密码 ${DEPLOY_PATH}/mysql/bin/mysqladmin -uroot -p${mysql_passwd} password '123456' if [ $? -ne 0 ];then loginfo "initialize root password" fi # 客户端环境变量 echo "export PATH=\$PATH:${DEPLOY_PATH}/mysql/bin" | sudo tee /etc/profile.d/mysql.sh source /etc/profile.d/mysql.sh loginfo "configure envirement" } install_mysql ``` 转载:[https://github.com/luckman666/mysql5.28/blob/main/installmysql528](https://github.com/luckman666/mysql5.28/blob/main/installmysql528)