作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com"> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;background: rgba(0, 0, 0, 0.05);padding: 10px 1em;border-left-color: rgb(221, 221, 221);margin-top: 1.2em;margin-bottom: 1.2em;border-left-width: 4px;color: rgb(119, 119, 119);quotes: none;"> <p style="padding-top: 8px;padding-bottom: 8px;text-wrap: wrap;text-size-adjust: auto;font-size: 15px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;line-height: 1.75em;">Seata 如何实现 RC ?保证事务的隔离性?</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-bottom: 16px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;font-size: 15px;text-wrap: wrap;text-size-adjust: auto;line-height: 1.75em;">最近有小伙伴在面试阿里,又遇到了相关的面试题。小伙伴懵了,因为没有遇到过,所以支支吾吾的说了几句,面试官不满意,面试挂了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin-bottom: 16px;font-family: "Helvetica Neue", Helvetica, "Segoe UI", Arial, freesans, sans-serif;font-size: 15px;text-wrap: wrap;text-size-adjust: auto;line-height: 1.75em;">所以,尼�
作者:微信小助手
<p><span style="font-size: 14px;letter-spacing: 0.578px;text-indent: 0em;">Trino是一个分布式SQL查询引擎,设计用来查询大规模的数据集存储在Hadoop、SQL和NoSQL数据库、对象存储等多种数据源中。它支持跨多个数据源的联合查询,对数据的位置透明,使得用户可以在一个系统中分析所有的数据。Trino的设计目标是提供快速(即时)的分析查询,它使用了许多优化技术来实现高查询性能。</span><br></p> <section style="line-height: 1.6em;text-align: justify;margin: 0px 0px 24px;text-indent: 0em;"> <span style="letter-spacing: 0.578px;text-decoration: none solid rgba(0, 0, 0, 0.9);font-size: 14px;">Trino官网:https://trino.io/</span> </section> <section style="line-height: 1.6em;text-align: justify;margin: 0px 0px 24px;text-indent: 0em;"> <img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100004064" data-ratio="0.5054151624548736" data-s="300,640" src="/upload/95f71423f5664c3e46abb25435be8150.png" data-type="png" data-w="554" style="text-align: center;font-size: var(--articleFontsize);letter-spacing: 0.034em;"> </section> <p><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">Trino</span>目前支持的数据源包括<span style="font-family: Calibri;">Accumulo</span>、<span style="font-family: Calibri;">Atop</span>、<span style="font-family: Calibri;">BigQuery</span>、<span style="font-family: Calibri;">Black Hole</span>、<span style="font-family: Calibri;">Cassandra</span>、<span style="font-family: Calibri;">ClickHouse</span>、<span style="font-family: Calibri;">Delta Lake</span>、<span style="font-family: Calibri;">Druid</span>、<span style="font-family: Calibri;">Elasticsearch</span>、<span style="font-family: Calibri;">Google Sheets</span>、<span style="font-family: Calibri;">Hive</span>、<span style="font-family: Calibri;">Hudi</span>、<span style="font-family: Calibri;">Iceberg</span>、<span style="font-family: Calibri;">Ignite</span>、<span style="font-family: Calibri;">JMX</span>、<span style="font-family: Calibri;">Kafka</span>、<span style="font-family: Calibri;">Kinesis</span>、<span style="font-family: Calibri;">Kudu</span>、<span style="font-family: Calibri;">Local File</span>、<span style="font-family: Calibri;">MariaDB</span>、<span style="font-family: Calibri;">Memory</span>、<span style="font-family: Calibri;">MongoDB</span>、<span style="font-family: Calibri;">MySQL</span>、<span style="font-family: Calibri;">OpenSearch</span>、<span style="font-family: Calibri;">Oracle</span>、<span style="font-family: Calibri;">Phoenix</span>、<span style="font-family: Calibri;">Pinot</span>、<span style="font-family: Calibri;">PostgreSQL</span>、<span style="font-family: Calibri;">Prometheus</span>、<span style="font-family: Calibri;">Redis</span>、<span style="font-family: Calibri;">Redshift</span>、<span style="font-family: Calibri;">SingleStore</span>、<span style="font-family: Calibri;">SQL Server</span>、<span style="font-family: Calibri;">System</span>、<span style="font-family: Calibri;">Thrift</span>、<span style="font-family: Calibri;">TPCDS</span>、<span style="font-family: Calibri;">TPCH</span>。 <o:p></o:p></span></p> <p><span style="font-size: 14px;"><span style="font-family: 等线;"><span style="font-family: 等线;">本文介绍</span><span style="font-family: Calibri;">trino</span><span style="font-family: 等线;">安装及使用Trino进行联邦查询</span><span style="font-family: Calibri;">mysql</span><span style="font-family: 等线;">和</span><span style="font-family: Calibri;">sqlserver</span><span style="font-family: 等线;">中的数据。</span></span><span style="font-family: Calibri;"> <o:p></o:p></span></span></p> <p><strong><span style="font-size: 14px;font-family: 等线;">1.<span style="font-family: Calibri;">Trino</span><span style="font-family: 等线;">安装</span></span></strong><span style="font-size: 14px;font-family: Calibri;"> <o:p></o:p></span></p> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">1.1 </span><span style="font-family: 等线;">设置</span><span style="font-family: Calibri;">java17</span></span></strong><span style="font-size: 14px;font-family: Calibri;"> <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: Calibri;">Trino 400 <span style="font-family: 等线;">需要 </span><span style="font-family: Calibri;">64 </span><span style="font-family: 等线;">位版本的 </span><span style="font-family: Calibri;">Java 17</span><span style="font-family: 等线;">,最低版本要求为 </span><span style="font-family: Calibri;">17.0.3</span><span style="font-family: 等线;">。早期的主要版本(例如 </span><span style="font-family: Calibri;">Java 8 </span><span style="font-family: 等线;">或 </span><span style="font-family: Calibri;">Java 11</span><span style="font-family: 等线;">)不起作用。</span> <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: 等线;"><span style="font-family: 等线;">如果你安装的是</span><span style="font-family: Calibri;">java8</span><span style="font-family: 等线;">,可以使用以下方式同时安装</span><span style="font-family: Calibri;">java17+</span></span></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">update-alternatives --install /usr/bin/java java /opt/software/jdk-18/bin/java 1</span></code></pre> </section> <p><span style="font-size: 14px;letter-spacing: 0.034em;font-family: 等线;">其中 </span><span style="font-size: 14px;letter-spacing: 0.034em;font-family: Calibri;">/opt/software/jdk-18</span><span style="font-size: 14px;letter-spacing: 0.034em;font-family: 等线;"> 是<span style="font-family: Calibri;">jdk-18</span>的安装目录</span><br></p> <p><span style="font-family: 等线;font-size: 14px;">需要切换到<span style="font-family: Calibri;">jdk-18</span>可以使用<span style="font-family: Calibri;">update-alternatives --config java </span>命令进行切换,选择对用的<span style="font-family: Calibri;">jdk</span>版本就可以</span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="37" data-backw="503" data-galleryid="" data-imgfileid="100004066" data-ratio="0.073558648111332" data-s="300,640" src="/upload/9ad4423aa3805a0497930290b8f53b08.png" data-type="png" data-w="503" style="width: 100%;height: auto;"></p> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">1.2 </span><span style="font-family: 等线;">安装</span><span style="font-family: Calibri;">python2.6+</span></span></strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;"></span> <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: 等线;"><span style="font-family: 等线;">这里建议使用</span><span style="font-family: Calibri;">anaconda</span><span style="font-family: 等线;">安装</span> <o:p></o:p></span></p> <p><a href="https://mp.weixin.qq.com/s?__biz=Mzg5Mzg3MzkwNA==&mid=2247484316&idx=1&sn=dd571faa66971d97f999b7d9b0dfb288&scene=21#wechat_redirect" style="font-family: Calibri;color: rgb(0, 0, 255);text-decoration: underline;font-size: 14px;" data-linktype="2"><span style="font-family: Calibri;color: rgb(0, 0, 255);text-decoration: underline;font-size: 14px;">https://mp.weixin.qq.com/s/PWaPQhftDnd64mHn-W3X9Q</span></a><span style="font-family: Calibri;font-size: 14px;"> <o:p></o:p></span></p> <p><a href="https://mp.weixin.qq.com/s?__biz=Mzg5Mzg3MzkwNA==&mid=2247484344&idx=1&sn=b88558dc8646cd7dc293eb5a76faa665&scene=21#wechat_redirect" style="font-family: Calibri;color: rgb(0, 0, 255);text-decoration: underline;font-size: 14px;" data-linktype="2"><span style="font-family: Calibri;color: rgb(0, 0, 255);text-decoration: underline;font-size: 14px;">https://mp.weixin.qq.com/s/FC1QyWvzpWNUwAS7QS62RQ</span></a><span style="mso-spacerun:'yes';font-family:Calibri;mso-fareast-font-family:等线;mso-bidi-font-family:'Times New Roman';"> <o:p></o:p></span></p> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">1.3 </span><span style="font-family: 等线;">下载</span><span style="font-family: Calibri;">Trino</span></span></strong><span style="font-size: 14px;font-family: Calibri;"> <o:p></o:p></span></p> <p><span style="font-family: Calibri;font-size: 14px;">下载地址:</span><span style="font-family: Calibri;color: rgb(0, 0, 255);text-decoration: underline;font-size: 14px;">https://repo.maven.apache.org/maven2/io/trino/trino-server/</span><span style="mso-spacerun:'yes';font-family:Calibri;mso-fareast-font-family:等线;mso-bidi-font-family:'Times New Roman';"> <o:p></o:p></span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="275" data-backw="515" data-galleryid="" data-imgfileid="100004067" data-ratio="0.5339805825242718" data-s="300,640" src="/upload/7210eadeef95f8b80f72d3314de55be4.png" data-type="png" data-w="515" style="width: 100%;height: auto;"></p> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">1.4 </span><span style="font-family: 等线;">解压</span><span style="font-family: Calibri;">Trino</span></span></strong><span style="font-size: 14px;font-family: 等线;"> <o:p></o:p></span></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">tar -zxvf trino-server-392.tar.gz -C /opt/software</span></code></pre> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="164" data-backw="518" data-galleryid="" data-imgfileid="100004068" data-ratio="0.3166023166023166" data-s="300,640" src="/upload/0ead3c56555b5372412ee7185802a919.png" data-type="png" data-w="518" style="width: 100%;height: auto;"></p> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">1.5 </span><span style="font-family: 等线;">配置 </span><span style="font-family: Calibri;">Trino</span></span></strong><span style="font-size: 14px;font-family: 等线;"> <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: Calibri;"><span style="font-family: 等线;">在安装目录中创建一个</span>etc<span style="font-family: 等线;">目录,我们会在该目录中配置以下:</span> <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: Calibri;">trino<span style="font-family: 等线;">节点配置:配置每个</span><span style="font-family: Calibri;">trino</span><span style="font-family: 等线;">节点的环境。</span> <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: Calibri;">JVM<span style="font-family: 等线;">配置:配置</span><span style="font-family: Calibri;">JVM</span><span style="font-family: 等线;">的相关参数。</span> <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: Calibri;">Config<span style="font-family: 等线;">属性:配置</span><span style="font-family: Calibri;">trino</span><span style="font-family: 等线;">服务器。</span> <o:p></o:p></span></p> <p><span style="font-family: Calibri;font-size: 14px;">Catalog<span style="font-family: 等线;">属性:配置</span>trino<span style="font-family: 等线;">的</span>connector<span style="font-family: 等线;">(数据源)</span></span><span style="mso-spacerun:'yes';font-family:Calibri;mso-fareast-font-family:等线;mso-bidi-font-family:'Times New Roman';"> <o:p></o:p></span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="249" data-backw="466" data-galleryid="" data-imgfileid="100004069" data-ratio="0.5343347639484979" data-s="300,640" src="/upload/8c438110bbe8acec30cd9d12b8b22dd9.png" data-type="png" data-w="466" style="width: 100%;height: auto;"></p> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">1.5.1 </span><span style="font-family: 等线;">创建配置目录</span></span></strong><span style="font-size: 14px;font-family: 等线;"> <o:p></o:p></span></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">mkdir /opt/software/trino-server-392/etc</span></code></pre> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="250" data-backw="469" data-galleryid="" data-imgfileid="100004070" data-ratio="0.5330490405117271" data-s="300,640" src="/upload/7f73f65b7ef27ab55dd1101f2eea35ac.png" data-type="png" data-w="469" style="width: 100%;height: auto;"></p> <p><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">1.5.2 </span><span style="font-family: 等线;">配置节点属性</span></span></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="ruby"><code><span class="code-snippet_outer">vi etc/node.properties</span></code><code><span class="code-snippet_outer"># 环境的名字。集群中所有的Trino节点必须具有相同的环境名称。</span></code><code><span class="code-snippet_outer">node.environment=test</span></code><code><span class="code-snippet_outer"># 此Trino安装的唯一标识符。这对于每个节点都必须是唯一的。</span></code><code><span class="code-snippet_outer">node.id=ffffffff-ffff-ffff-ffff-ffffffffffff</span></code><code><span class="code-snippet_outer"># 数据目录的位置(文件系统路径)。Trino在这里存储日志和其他数据。</span></code><code><span class="code-snippet_outer">node.data-dir=/opt/software/trino/data</span></code></pre> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="41" data-backw="472" data-galleryid="" data-imgfileid="100004071" data-ratio="0.08686440677966102" data-s="300,640" src="/upload/a55a792e391ac20fb167944b6d997d05.png" data-type="png" data-w="472" style="width: 100%;height: auto;"></p> <p><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">1.5.3 JVM</span><span style="font-family: 等线;">配置</span> <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: Calibri;"><span style="font-family: 等线;">每个节点可以配置不同的容量</span>,<span style="font-family: 等线;">根据服务器实际性能进行修改</span></span></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="diff"><code><span class="code-snippet_outer">vi etc/jvm.config</span></code><code><span class="code-snippet_outer">-server</span></code><code><span class="code-snippet_outer">-Xmx16G</span></code><code><span class="code-snippet_outer">-XX:InitialRAMPercentage=80</span></code><code><span class="code-snippet_outer">-XX:MaxRAMPercentage=80</span></code><code><span class="code-snippet_outer">-XX:G1HeapRegionSize=32M</span></code><code><span class="code-snippet_outer">-XX:+ExplicitGCInvokesConcurrent</span></code><code><span class="code-snippet_outer">-XX:+ExitOnOutOfMemoryError</span></code><code><span class="code-snippet_outer">-XX:+HeapDumpOnOutOfMemoryError</span></code><code><span class="code-snippet_outer">-XX:-OmitStackTraceInFastThrow</span></code><code><span class="code-snippet_outer">-XX:ReservedCodeCacheSize=512M</span></code><code><span class="code-snippet_outer">-XX:PerMethodRecompilationCutoff=10000</span></code><code><span class="code-snippet_outer">-XX:PerBytecodeRecompilationCutoff=10000</span></code><code><span class="code-snippet_outer">-Djdk.attach.allowAttachSelf=true</span></code><code><span class="code-snippet_outer">-Djdk.nio.maxCachedBufferSize=2000000</span></code><code><span class="code-snippet_outer">-XX:+UnlockDiagnosticVMOptions</span></code><code><span class="code-snippet_outer">-XX:+UseAESCTRIntrinsics</span></code><code><span class="code-snippet_outer"># Disable Preventive GC for performance reasons (JDK-8293861)</span></code><code><span class="code-snippet_outer">-XX:-G1UsePreventiveGC</span></code></pre> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="131" data-backw="504" data-galleryid="" data-imgfileid="100004072" data-ratio="0.25992063492063494" data-s="300,640" src="/upload/055d834fcd884fd3b44160edb78d8815.png" data-type="png" data-w="504" style="width: 100%;height: auto;"></p> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">1.5.4 </span><span style="font-family: 等线;">配置</span><span style="font-family: Calibri;">Trino</span><span style="font-family: 等线;">服务器</span></span></strong></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="php"><code><span class="code-snippet_outer">vi etc/config.properties</span></code><code><span class="code-snippet_outer">#如果您要设置一台机器进行测试,它既充当协调器又充当工作人员,请使用以下配置:</span></code><code><span class="code-snippet_outer">coordinator=true</span></code><code><span class="code-snippet_outer">node-scheduler.include-coordinator=true</span></code><code><span class="code-snippet_outer">http-server.http.port=8080</span></code><code><span class="code-snippet_outer">discovery.uri=http://192.168.31.128:8080</span></code></pre> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="57" data-backw="504" data-galleryid="" data-imgfileid="100004073" data-ratio="0.1130952380952381" data-s="300,640" src="/upload/b1e53c5715b25c3f7d9da35f5a790c36.png" data-type="png" data-w="504" style="width: 100%;height: auto;"></p> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">1.5.5 </span><span style="font-family: 等线;">配置日志级别</span></span></strong></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="cpp"><code><span class="code-snippet_outer">设置日志级别,有四个级别:DEBUG, INFO, WARN and ERROR</span></code><code><span class="code-snippet_outer">vi etc/log.properties</span></code><code><span class="code-snippet_outer">io.trino=INFO</span></code></pre> </section> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">1.5.6 </span><span style="font-family: 等线;">配置</span><span style="font-family: Calibri;">trino catalog</span></span></strong><span style="font-size: 14px;font-family: 等线;"> <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: Calibri;">Trino<span style="font-family: 等线;">访问数据通过</span><span style="font-family: Calibri;">connector,</span><span style="font-family: 等线;">它配置在</span><span style="font-family: Calibri;">catalog</span><span style="font-family: 等线;">目录内,我们创建</span><span style="font-family: Calibri;">etc/catalog</span><span style="font-family: 等线;">目录</span> <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: Calibri;">mysql<span style="font-family: 等线;">源配置如下,我们在</span><span style="font-family: Calibri;">catalog</span><span style="font-family: 等线;">目录下创建</span><span style="font-family: Calibri;">mysql.properties</span> <o:p></o:p></span></p> <p><span style="font-size: 14px;"><span style="font-family: 等线;"><span style="font-family: Calibri;">sqlserver</span><span style="font-family: 等线;">源配置如下,</span></span><span style="font-family: Calibri;"><span style="font-family: 等线;">我们在</span>catalog<span style="font-family: 等线;">目录下创建</span>sqlserver.properties <o:p></o:p></span></span></p> <p><span style="font-size: 14px;font-family: Calibri;"><span style="font-family: 等线;">不同的数据源参考这里</span>https://trino.io/docs/current/connector.html</span></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="bash"><code><span class="code-snippet_outer">mkdir etc/catalog</span></code><code><span class="code-snippet_outer">vi etc/catalog/mysql.properties</span></code><code><span class="code-snippet_outer">connector.name=mysql</span></code><code><span class="code-snippet_outer">connection-url=jdbc:mysql://192.168.154.128:3306?useUnicode=true&useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC</span></code><code><span class="code-snippet_outer">connection-user=root</span></code><code><span class="code-snippet_outer">connection-password=Admin@123</span></code></pre> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="53" data-backw="553" data-galleryid="" data-imgfileid="100004074" data-ratio="0.09584086799276673" data-s="300,640" src="/upload/6ec8acf36e4ad56e05bd68dc3bbdb46d.png" data-type="png" data-w="553" style="width: 100%;height: auto;"></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="javascript"><code><span class="code-snippet_outer">vi etc/catalog/sqlserver.properties</span></code><code><span class="code-snippet_outer">connector.name=sqlserver</span></code><code><span class="code-snippet_outer">connection-url=jdbc:sqlserver://192.168.154.128:1433;databaseName=exampledb;encrypt=false</span></code><code><span class="code-snippet_outer">connection-user=sa</span></code><code><span class="code-snippet_outer">connection-password=Wuzongyun0!</span></code></pre> </section> <p><strong><span style="font-size: 14px;font-family: Calibri;">2 Trino<span style="font-family: 等线;">启动命令</span></span></strong><span style="font-size: 14px;font-family: Calibri;"> <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: Calibri;"><span style="font-family: 等线;">启动</span>/<span style="font-family: 等线;">关闭</span><span style="font-family: Calibri;">/</span><span style="font-family: 等线;">查看运行状态</span></span></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">bin/launcher start</span></code><code><span class="code-snippet_outer">bin/launcher stop</span></code><code><span class="code-snippet_outer">bin/launcher status</span></code><code><span class="code-snippet_outer">访问trino web页面</span></code></pre> </section> <p><span style="font-size: 14px;text-decoration: underline;"><span style="font-family: Calibri;color: rgb(0, 0, 255);">http://192.168.154.128:80</span><span style="color: rgb(0, 0, 255);font-family: Calibri;">80</span><span style="font-family: Calibri;color: rgb(0, 0, 255);">/</span></span><span style="mso-spacerun:'yes';font-family:Calibri;mso-fareast-font-family:等线;mso-bidi-font-family:'Times New Roman';"> <o:p></o:p></span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="259" data-backw="514" data-galleryid="" data-imgfileid="100004075" data-ratio="0.5038910505836576" data-s="300,640" src="/upload/6ace6aa56b295456c6a7822d1123fd93.png" data-type="png" data-w="514" style="width: 100%;height: auto;"></p> <p><span style="font-family: 等线;font-size: 14px;">名称自定义,第一次输入什么,以后就用什么用户登录</span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="259" data-backw="512" data-galleryid="" data-imgfileid="100004076" data-ratio="0.505859375" data-s="300,640" src="/upload/7f7545af15be5e0e48b6bffb727f67c8.png" data-type="png" data-w="512" style="width: 100%;height: auto;"></p> <p><strong><span style="font-size: 14px;"><span style="font-family: 等线;"><span style="font-family: Calibri;">3 </span><span style="font-family: 等线;">安装</span></span><span style="font-family: Calibri;">Trino<span style="font-family: 等线;">客户端</span></span></span></strong><span style="font-size: 14px;font-family: Calibri;"> <o:p></o:p></span></p> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">3.1 </span><span style="font-family: 等线;">安装</span><span style="font-family: Calibri;">trino</span><span style="font-family: 等线;">客户端</span></span></strong><span style="font-size: 14px;font-family: 等线;"> <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: Calibri;"><span style="font-family: 等线;">下载地址</span>https://repo1.maven.org/maven2/io/trino/trino-cli/392/trino-cli-392-executable.jar <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: Calibri;"><span style="font-family: 等线;">将其重命名为</span>trino<span style="font-family: 等线;">,使用 使其可执行 ,然后运行它以显示</span></span></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="properties"><code><span class="code-snippet_outer">mv trino-cli-392-executable.jar trino-cli</span></code><code><span class="code-snippet_outer">chmod +x trino-cli</span></code></pre> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="253" data-backw="473" data-galleryid="" data-imgfileid="100004077" data-ratio="0.5348837209302325" data-s="300,640" src="/upload/af554731edf48279a63ba8aa7feef13a.png" data-type="png" data-w="473" style="width: 100%;height: auto;"></p> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">3.1 </span><span style="font-family: 等线;">启动</span><span style="font-family: Calibri;">trino</span><span style="font-family: 等线;">客户端</span></span></strong><span style="font-size: 14px;font-family: 等线;"> <o:p></o:p></span></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">./trino-cli --server 192.168.154.128:8080</span></code></pre> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="89" data-backw="476" data-galleryid="" data-imgfileid="100004078" data-ratio="0.1869747899159664" data-s="300,640" src="/upload/2b578be98c666492e1b5cac980ddfbda.png" data-type="png" data-w="476" style="width: 100%;height: auto;"></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></code><code><span class="code-snippet_outer">#显示所有的catalog</span></code><code><span class="code-snippet_outer">show catalogs;</span></code></pre> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="109" data-backw="553" data-galleryid="" data-imgfileid="100004079" data-ratio="0.19710669077757687" data-s="300,640" src="/upload/1f655777d9e746a4e08edf879cb30755.png" data-type="png" data-w="553" style="width: 100%;height: auto;"></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">#查看所有的schemas</span></code><code><span class="code-snippet_outer">show schemas from mysql;</span></code></pre> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="178" data-backw="553" data-galleryid="" data-imgfileid="100004080" data-ratio="0.321880650994575" data-s="300,640" src="/upload/5591248d2a27ba48174eedc641b31dd2.png" data-type="png" data-w="553" style="width: 100%;height: auto;"></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="apache"><code><span class="code-snippet_outer">#退出客户端</span></code><code><span class="code-snippet_outer">quit;</span></code></pre> </section> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">4 </span><span style="font-family: 等线;">使用</span><span style="font-family: Calibri;">dbeaver</span><span style="font-family: 等线;">操作</span><span style="font-family: Calibri;">trino</span></span></strong><span style="font-size: 14px;font-family: Calibri;"> <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: 等线;"><span style="font-family: 等线;">为了可以更方便的使用</span><span style="font-family: Calibri;">trino</span><span style="font-family: 等线;">,可以使用</span><span style="font-family: Calibri;">dbeaver</span><span style="font-family: 等线;">链接</span><span style="font-family: Calibri;">trino</span><span style="font-family: 等线;">进行数据处理</span> <o:p></o:p></span></p> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">4.1 </span><span style="font-family: 等线;">下载 </span><span style="font-family: Calibri;">jdbc</span><span style="font-family: 等线;">驱动</span></span></strong><span style="font-size: 14px;font-family: Calibri;"> <o:p></o:p></span></p> <p><span style="font-size: 14px;"><span style="font-family: 等线;">下载地址</span><span style="font-family: Calibri;">https://repo.maven.apache.org/maven2/io/trino/trino-jdbc</span><span style="font-family: 等线;"><span style="font-family: Calibri;">/trino-jdbc-392.jar</span> <o:p></o:p></span></span></p> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">4.2 dbeaver </span><span style="font-family: 等线;">安装 </span><span style="font-family: Calibri;">trino</span><span style="font-family: 等线;">驱动(如果</span><span style="font-family: Calibri;">dbeaver</span><span style="font-family: 等线;">没有</span><span style="font-family: Calibri;">trino</span><span style="font-family: 等线;">驱动)</span></span></strong><span style="font-size: 14px;font-family: 等线;"> <o:p></o:p></span></p> <p><span style="font-family: 等线;font-size: 14px;">数据库<span style="font-family: Calibri;">-></span>驱动管理器<span style="font-family: Calibri;">-></span>新建</span><span style="mso-spacerun:'yes';font-family:等线;mso-ascii-font-family:Calibri;mso-hansi-font-family:Calibri;mso-bidi-font-family:'Times New Roman';"> <o:p></o:p></span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100004082" data-ratio="0.5333333333333333" data-s="300,640" src="/upload/0944d22b19d3a3c24f9bfcc9e2b38888.png" data-type="png" data-w="1080" style=""></p> <p><span style="font-size: 14px;font-family: 等线;"><span style="font-family: 等线;">编辑信息:驱动名称、驱动类型、类名、</span><span style="font-family: Calibri;">URL</span><span style="font-family: 等线;">模板、端口</span> <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: 等线;"><span style="font-family: 等线;">添加文件:选择到下载下来的</span><span style="font-family: Calibri;">jar</span><span style="font-family: 等线;">包</span> <o:p></o:p></span></p> <p><span style="font-family: 等线;font-size: 14px;">找到类:选择驱动类</span><span style="mso-spacerun:'yes';font-family:Calibri;mso-fareast-font-family:等线;mso-bidi-font-family:'Times New Roman';"> <o:p></o:p></span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100004083" data-ratio="0.5185185185185185" data-s="300,640" src="/upload/d35d1eda643e68b5a91298ebf366af92.png" data-type="png" data-w="1080" style=""></p> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">4.3 dbeaver</span><span style="font-family: 等线;">链接</span><span style="font-family: Calibri;">trino</span></span></strong><span style="font-size: 14px;font-family: 等线;"> <o:p></o:p></span></p> <p><span style="font-family: 等线;font-size: 14px;">填写<span style="font-family: Calibri;">jdbc-url</span>、主机、端口、用户名</span><span style="mso-spacerun:'yes';font-family:Calibri;mso-fareast-font-family:等线;mso-bidi-font-family:'Times New Roman';"> <o:p></o:p></span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100004084" data-ratio="0.5351851851851852" data-s="300,640" src="/upload/6fabd340e42fddff43bf4afe9077e267.png" data-type="png" data-w="1080" style=""></p> <p><strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: Calibri;">4.4 </span><span style="font-family: 等线;">查询数据</span></span></strong><span style="font-size: 14px;font-family: 等线;"><span style="font-family: 等线;"></span> <o:p></o:p></span></p> <p><span style="font-size: 14px;font-family: 等线;"><span style="font-family: 等线;">关联</span><span style="font-family: Calibri;">mysql</span><span style="font-family: 等线;">中的数据和</span><span style="font-family: Calibri;">sqlserver</span><span style="font-family: 等线;">中的数据进行联邦查询</span> <o:p></o:p></span></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">from</span> mysql.x2ddl.x2ddl datamapping a <span class="code-snippet__keyword">inner</span> <span class="code-snippet__keyword">join</span> sqlserver.cdc.captured <span class="code-snippet__keyword">columns</span> b <span class="code-snippet__keyword">on</span> a.id = b.object <span class="code-snippet__keyword">id</span> ;</span></code></pre> </section> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100004085" data-ratio="0.5361111111111111" data-s="300,640" src="/upload/33b7f825b3a69607eacaa4d4caf70c64.png" data-type="png" data-w="1080" style=""></p> <p><span style="font-family: 等线;font-size: 14px;">查看执行任务详情,进入网页端</span><span style="mso-spacerun:'yes';font-family:等线;mso-ascii-font-family:Calibri;mso-hansi-font-family:Calibri;mso-bidi-font-family:'Times New Roman';"> <o:p></o:p></span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="280" data-backw="554" data-galleryid="" data-imgfileid="100004086" data-ratio="0.5054151624548736" data-s="300,640" src="/upload/9598833219824420115e25ff4be646e2.png" data-type="png" data-w="554" style="width: 100%;height: auto;"></p> <p><span style="font-family: 等线;font-size: 14px;">点击任务<span style="font-family: Calibri;">ID</span></span><span style="mso-spacerun:'yes';font-family:等线;mso-ascii-font-family:Calibri;mso-hansi-font-family:Calibri;mso-bidi-font-family:'Times New Roman';"> <o:p></o:p></span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="280" data-backw="554" data-galleryid="" data-imgfileid="100004087" data-ratio="0.5054151624548736" data-s="300,640" src="/upload/5abe5b8adad109af2796117ec5694cb7.png" data-type="png" data-w="554" style="width: 100%;height: auto;"></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-backh="280" data-backw="554" data-galleryid="" data-imgfileid="100004088" data-ratio="0.5054151624548736" data-s="300,640" src="/upload/97537a9c4159501194701f32b3f5f001.png" data-type="png" data-w="554" style="width: 100%;height: auto;"></p> <section class="mp_profile_iframe_wrp"> <mp-common-profile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="Mzg5Mzg3MzkwNA==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/mZpqbZwlCSQ3SvW4umad8CibQ6YxFaicraoibJL4I9bxNVEkpsFcxcs4bibe1cJXiax5R2SLRblxmBea1L7meZbKnug/0?wx_fmt=png" data-nickname="大数据技能圈" data-alias="ByteTeach" data-signature="包含30+大数据组件;内容包含基础学习、项目实战、面试面经、源码解析、测试数据等;在同一个项目中完成所有组件的学习,保证学习的连贯性,助你快速成长为合格的大数据开发工程师" data-from="0" data-is_biz_ban="0"></mp-common-profile> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<blockquote style="box-sizing: border-box;margin: 10px 0px;padding: 0.5em 1em;color: rgb(102, 102, 102);border-left: 0.25em solid rgb(51, 122, 183);background-color: rgb(240, 248, 255);overflow: auto;font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"> <p style="box-sizing: border-box;margin: 0px;padding: 0px;">Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言。—— Go - wikipedia.org</p> </blockquote> <p><span style="line-height: 0px;"></span><br></p> <h2 style="box-sizing: border-box;margin: -55px 0px 5px;padding: 60px 0px 0px;font-size: 1.5em;font-weight: 500;color: rgba(0, 0, 0, 0.9);font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;">1 Go 安装</h2> <p style="box-sizing: border-box;margin: 10px 0px;padding: 0px;color: rgba(0, 0, 0, 0.9);font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;">最新版本下载地址官方下载 golang.org,当前是 1.13.6。如无法访问,可以在 <strong style="box-sizing: border-box;font-weight: 600;">studygolang.com/dl</strong> 下载</p> <p style="box-sizing: border-box;margin: 10px 0px;padding: 0px;color: rgba(0, 0, 0, 0.9);font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif;font-size: 16px;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;background-color: rgb(255, 255, 255);text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;">使用 Linux,可以用如下方式快速安装。</p> <p><span style="line-height: 0px;"><br></span></p> <figure style="box-sizing: border-box;margin: 10px 0px 20px;padding: 15px;overflow: auto;font-size: 13px;color: rgb(36, 41, 46);background: rgb(246, 248, 250);line-height: 1.8;font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif;font-style: normal;font-variant-ligatures: normal;font-variant-caps: normal;font-weight: 400;letter-spacing: normal;orphans: 2;text-align: start;text-indent: 0px;text-transform: none;white-space: normal;widows: 2;word-spacing: 0px;-webkit-text-stroke-width: 0px;text-decoration-thickness: initial;text-decoration-style: initial;text-decoration-color: initial;"> <table style="box-sizing: border-box;border-collapse: collapse;border-spacing: 0px;margin: 0px;display: block;width: auto;overflow: auto;border-width: initial;border-style: none;border-color: initial;"> <tbody style="box-sizing: border-box;"> <tr style="box-sizing: border-box;background-color: transparent;border-top: none;"> <td style="box-sizing: border-box;padding: 0px;text-align: left;border-width: initial !important;border-style: none !important;border-color: initial !important;"><pre style="box-sizing: border-box;margin: 0px;padding: 1px 20px 1px 1px;font-family: SFMono-Regular, Consolas, "Liberation Mono", Menlo, Courier, monospace;overflow-wrap: normal;overflow: auto;line-height: 1.8;background: rgb(246, 248, 250);border-radius: 3px;font-size: 13px;color: rgb(102, 102, 102);border-width: initial;border-style: none;border-color: initial;text-align: right;"><span style="box-sizing: border-box;height: 20px;">1</span><br style="box-sizing: border-box;"><span style="box-sizing: border-box;height: 20px;">2</span><br style="box-sizing: border-box;"><span style="box-sizing: border-box;height: 20px;">3</span><br style="box-sizing: border-box;"><span style="box-sizing: border-box;height: 20px;">4</span><br style="box-sizing: border-box;"><span style="box-sizing: border-box;height: 20px;">5</span><br style="box-sizing: border-box;"><span style="box-sizing: border-box;height: 20px;">6</span><br style="box-sizing: border-box;"></pre></td> <td style="box-sizing: border-box;padding: 0px;text-align: left;border-width: initial !important;border-style: none !import
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding: 0px 10px;line-height: 1.6;word-spacing: 0px;letter-spacing: 0px;word-break: break-word;overflow-wrap: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;margin-bottom: 24px;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><br><em><span style="font-size: 15px;color: rgb(2, 30, 170);"></span></em></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">在云计算时代,我们经常创建 Serverless 应用(一种云原生开发模式,允许开发人员构建和运行应用程序,而无需管理服务器)。当我们的项目采用这种模式,那基础设施维护预算将排在首位。如果我们的服务负载很低,它实际上近乎是免费的。但是如果出现问题,你将为此付出很多!当谈到金钱时,你肯定会以某方式对它做出反应。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">当你的 VPS 运行着多个服务应用,但其中一个有时会占用所有的资源,以至于都无法通过 ssh 访问服务器。你转到使用 Kubernetes 集群,为所有应用程序设置限制。随后看到一些应用程序被重新启动,因为 OOM-killer 解决了内存”泄漏“问题。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">当然, OOM 并不总是泄漏问题,也可能是资源超支。泄漏问题大概率是由程序错误引起的,我们今天谈论的主题是如何尽量避免这种情况。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;"><em style="font-style: italic;color: black;">过多的资源消耗会伤害钱包,这意味着我们需要立即采取行动。</em></span></p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 22px;border-bottom: 4px rgba(160, 249, 176) solid;display: flex;padding: 0;"><span style="width: 100%;display: flex;color: rgba(160, 249, 176);padding: 0.5rem 1rem;border-top-left-radius: 4px;border-top-right-radius: 4px;background: #181a21 !important;">不要过早优化</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">现在让我们谈谈优化。希望你能明白为什么我们不要过早优化!</span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span style="font-size: 15px;">第一,优化可能是无用的工作。因为我们应该先研究整个应用程序,而你的代码很可能不会成为瓶颈。我们需要的是快速的结果,MVP(Minimum Viable Product,最简可行产品),然后才会考虑它的问题。</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span style="font-size: 15px;">第二,优化都必须有所依据。也就是说,每次优化都应该建立在基准上,我们必须证明它给我们带来了多少利润。</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span style="font-size: 15px;">第三,优化也许会带来复杂。你需要知道的是,大多数优化会使代码的可读性变差。你需要把握好这种平衡。</span> </section></li> </ul> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 22px;border-bottom: 4px rgba(160, 249, 176) solid;display: flex;padding: 0;"><span style="width: 100%;display: flex;color: rgba(160, 249, 176);padding: 0.5rem 1rem;border-top-left-radius: 4px;border-top-right-radius: 4px;background: #181a21 !important;">优化建议</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">现在我们按照 Go 中的标准实体分类,来给出一些实用建议。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 18px;">1. 数组与切片</h4> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">提前为切片分配内存</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">尽量使用第三个参数:</span><code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #000000;background: rgba(14, 210, 247, 0.15);"><span style="font-size: 15px;">make([]T, 0, len)</span></code></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">如果不知道元素确切的数量并且切片是短暂的,可以分配更大一点,保障切片在运行时不会增长。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">不要忘记使用 copy</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">尽量不要在复制时使用 append,例如在合并两个或多个切片时。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">正确迭代</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">一个包含许多元素或大元素的切片,使用 for 去获取单个元素。通过这种方法,将避免不必要的复制。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">复用切片</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">如果对传入的切片进行某种操作并返回已经修改的结果,我们可以返回它。这样能避免新的内存分配。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">不要留下不使用的切片部分</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">如果需要从切片中切下一小块并仅使用它,该切片的主要部分也将被保留。正确的做法是,为这小块切片使用新的副本,而将旧的切片扔给 GC。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 18px;">2. 字符串</h4> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">正确拼接</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">如果拼接字符串可以在一个语句中完成,那就使用 </span><code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #000000;background: rgba(14, 210, 247, 0.15);"><span style="font-size: 15px;">+</span></code><span style="font-size: 15px;"> 操作符。如果需要在循环中执行此操作,使用 </span><code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #000000;background: rgba(14, 210, 247, 0.15);"><span style="font-size: 15px;">string.Builder</span></code><span style="font-size: 15px;">,并使用它的 </span><code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #000000;background: rgba(14, 210, 247, 0.15);"><span style="font-size: 15px;">Grow</span></code><span style="font-size: 15px;"> 方法预先指定 </span><code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #000000;background: rgba(14, 210, 247, 0.15);"><span style="font-size: 15px;">Builder</span></code><span style="font-size: 15px;"> 的大小,减少内存分配次数。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">转换优化</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">string 和 []byte 在底层结构上非常相近,有时这两种类型之间可以通过强转换来避免内存分配。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">字符串驻留</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">可以池化字符串,从而帮助编译器只存储一次相同的字符串。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">避免分配</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">我们可以使用 map(级联)而不是复合键,我们可以使用字节切片。尽量不使用 </span><code style="font-size: 14px;word-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin: 0 2px;background-color: rgba(27,31,35,.05);font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;word-break: break-all;color: #000000;background: rgba(14, 210, 247, 0.15);"><span style="font-size: 15px;">fmt</span></code><span style="font-size: 15px;"> 包,因为它所有的方法都用到了反射。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 18px;">3. 结构体</h4> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">避免拷贝大结构体</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">我们理解的小结构体是不超过4个字段不超过一个机器字大小。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">一些典型的拷贝场景</span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span style="font-size: 15px;">投射到 interface</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span style="font-size: 15px;">通道的接收和发送</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span style="font-size: 15px;">替换 map 中的元素</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span style="font-size: 15px;">向切片添加元素</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span style="font-size: 15px;">迭代(range)</span> </section></li> </ul> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">避免通过指针访问结构体字段</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">解引用是昂贵的,我们应该尽可能少地这样做,尤其是在循环中。同时它也失去了使用快速寄存器的能力。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">处理小结构体</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">这项工作由编辑器进行优化,这意味着它很便宜。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">使用对齐减小结构体大小</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">我们可以对齐结构体(根据字段的大小,以正确的顺序排列它们),以此减小结构体本身的大小。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 18px;">4. 函数</h4> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">使用内联函数或自己内联它们</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">尝试编写可供编译器内联的小函数,它会很快,甚至快过自己在函数中嵌入代码。对于热路径(hot path)尤其如此。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">哪些不会内联</span></p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;list-style-type: disc;" class="list-paddingleft-1"> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span style="font-size: 15px;">recovery</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span style="font-size: 15px;">select 块</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span style="font-size: 15px;">类型声明</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span style="font-size: 15px;">defer</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span style="font-size: 15px;">goroutine</span> </section></li> <li style="font-size: 15px;"> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;text-align: left;color: rgb(1,1,1);font-weight: 500;"> <span style="font-size: 15px;">for-range</span> </section></li> </ul> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">合理地选择函数参数</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">尝试使用小参数,因为它们的复制将被优化。尝试复制和栈增长在GC负载保持平衡。避免大量参数,让你的程序使用快速寄存器(它们的数量是有限的)。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">命名返回值</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">这似乎比在函数体中声明这些变量更高效。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">保存中间结果</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">帮助编译器优化你的代码,保存中间结果,然后会有更多的选项来优化你的代码。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">仔细地使用 defer</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">尽量不要使用 defer,或者至少不要在循环中使用它。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">助力 hot path</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">避免在热路径分配内存,尤其是短生命对象。制作最常见分支(if,switch)</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 18px;">5. Map</h4> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">提前分配内存</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">和 slice 一样,初始化 map 时,指定其大小。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">使用空结构体为值</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">struct{} 什么都不是(不占内存),因此例如传递信号时,使用它是非常有益的。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">清空 map</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">map 只能增长,不能缩小。我们需要重置 map 时,删除其所有元素是无济于事的。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">尽量不在键和值中使用指针</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">如果 map 中不包含指针,那么 GC 就不会在上面浪费宝贵的时间。字符串也使用了指针,因此应该使用字节数组而不是字符串作为键。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">减少修改次数</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">同样,我们不想使用指针,但我们可以使用 map 和 slice 的组合,将键存储在 map 中,将值存在 slice。这样我们就可以不受限制地更改值。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 18px;">6. Interface</h4> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">计算内存分配</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">请记住,要为接口分配值时,首先需要将其复制到某处,然后将指针黏贴给它。关键是复制。事实证明,接口的装箱和拆箱的成本将近似于结构体大小的一次分配。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">选择最优类型</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">在某些情况下,接口的装箱和拆箱期间没有分配。例如,变量和常量的小值或布尔值、具有一个简单字段的结构体、指针(包括 map、channel、func)</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">避免内存分配</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">与其他地方一样,尽量避免不必要的分配。例如将一个接口分配给另一个接口,而不是装箱两次。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">仅在需要时使用</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">避免在频繁调用的函数参数和返回结果中使用接口。我们不需要额外的拆装包操作。减少使用接口方法调用的频率,因为它会阻止内联。</span></p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 18px;">7. 指针、通道、边界检查</h4> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">避免不必要的解引用</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">尤其是在循环中,因为事实证明它太昂贵了。解引用是我们不想自费执行的操作。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">使用通道效率低下</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">channel 同步比其他同步原语方法慢。另外, select 中的 case 越多,我们的程序就越慢。但是,select,case 加 default 有被优化。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">避免不必要的边界检查</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">这也很昂贵,我们应该避免它。例如,只检查(获取)一次最大切片索引,而不是多次。最好立即尝试获得极端选项。</span></p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;color: black;font-size: 22px;border-bottom: 4px rgba(160, 249, 176) solid;display: flex;padding: 0;"><span style="width: 100%;display: flex;color: rgba(160, 249, 176);padding: 0.5rem 1rem;border-top-left-radius: 4px;border-top-right-radius: 4px;background: #181a21 !important;">总结</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">在整篇文章中,我们看到了一些相同的优化规则。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">帮助编译器做出正确的决定,它会感谢你的。在编译时分配内存,使用中间结果,并尽量保持你的代码可读。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">我再次重申,对于隐式优化,基准是强制性的。如果因为编译器在不同版本之间变化太快,昨天工作的东西明天就不能工作,反之亦然。</span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">不要忘记使用 Go 内置的分析和跟踪工具。</span></p> <h6 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;padding: 0px;font-weight: bold;color: black;font-size: 16px;">译者有话说</h6> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 0;line-height: 26px;color: black;font-size: 17px;word-spacing: 3px;letter-spacing: 1px;"><span style="font-size: 15px;">注意,作者的建议并不一定是对的。就像原文中有人评价,为什么不在每条建议下面列出优化代码。因为作者更希望开发人员把这些建议当做一张备忘单,知道这些瓶颈并主动去寻找如何做优化。</span></p> </section>
作者:微信小助手
<p style="text-align: left;" data-mpa-powered-by="yiban.io"><strong style="letter-spacing: 0.034em;font-size: 16px;text-align: justify;">目录</strong><br></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 什么是责任链 </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> <section mpa-from-tpl="t"> <section data-mpa-category="模板" data-mid="" mpa-from-tpl="t"> <section data-mid="" mpa-from-tpl="t"> <section data-mid="" mpa-from-tpl="t"> <br> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t"> <section mpa-from-tpl="t"> <section style="width:100%;text-align:center;" data-width="100%" mpa-from-tpl="t"> <section style="display:inline-block;width:auto;" mpa-from-tpl="t"> <section style="width: 45px;margin-right: auto;margin-bottom: -12px;margin-left: auto;background-color: #fefefe;transform: translateZ(10px);-webkit-transform: translateZ(10px);-moz-transform: translateZ(10px);-ms-transform: translateZ(10px);-o-transform: translateZ(10px);" mpa-from-tpl="t"> <img class="rich_pages wxw-img" data-imgfileid="100126414" data-ratio="1" src="/upload/2f587a759a9336e658edf1970c0a8632.png" data-w="100" data-width="100%" style="display: block;width: 100%;"> </section> <section style="display:inline-block;width:auto;height:auto;" mpa-from-tpl="t"> <section style="border-width: 1px;border-style: solid;border-color: rgb(102, 102, 102);height: 40px;" mpa-from-tpl="t"> <br> </section> <section style="margin-top:-37px;margin-right:-3px;margin-bottom:-3px;margin-left:3px;" mpa-from-tpl="t"> <section style="display: inline-block;height: 40px;line-height: 40px;padding-right: 15px;padding-left: 15px;border-width: 1px;border-style: solid;border-color: rgb(255, 116, 128);width: 100%;" data-width="100%" mpa-from-tpl="t"> <p mpa-is-content="t">前言</p> </section> </section> </section> </section> </section> </section> </section> <p><br mpa-from-tpl="t"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">最近,我让团队内一位成员写了一个导入功能。他使用了责任链模式,代码堆的非常多,bug 也多,没有达到我预期的效果。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">实际上,针对导入功能,我认为模版方法更合适!为此,隔壁团队也拿出我们的案例,进行了集体 code review。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">学好设计模式,且不要为了练习,强行使用!让原本 100 行就能实现的功能,写了 3000 行!对错暂且不论,我们先一起看看责任链设计模式吧!</p> <section data-mid="" mpa-from-tpl="t" style="margin-bottom: 0px;"> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-mpa-category="模板" style="width: 100%;padding: 0 15px;" data-mid="" mpa-from-tpl="t"> <section style="width: 100%;padding: 15px 17px 20px;background: #ebf4ff;font-size: 14px;font-weight: 400;color: #6273aa;line-height: 20px;" data-mid="" mpa-from-tpl="t"> <p data-mid="" mpa-is-content="t" style="text-align: left;">文章来源:https://blog.csdn.net/q1472750149/article/details/121886327</p> </section> <section style="width: 100%;display: flex;justify-content: flex-end;align-items: flex-start;padding-right: 5px;" data-mid="" mpa-from-tpl="t"> <section data-mid="" mpa-from-tpl="t" style="width: 23px;height: 27px;background: url("https://mmbiz.qpic.cn/mmbiz_png/dLHvdVqeWINyJQzMVmQzxIcFqDsaiaK6ATCCANPe11FbZKCApfz0TbDtfc5gfSQNgJpic86YejM6qcNU5gubeetQ/640") no-repeat;background-size: contain;background-position: center center;margin-top: -27px;z-index: 10;"> <br> </section> </section> <section style="width: 100%;display: flex;justify-content: flex-start;align-items: flex-start;" data-mid="" mpa-from-tpl="t"> <section style="width: 52.3%;height: 8px;background: #6273AA;margin-top: -6px;" data-mid="" mpa-from-tpl="t"> <br> </section> <section style="width: 10px;height: 8px;background: #6273AA;transform: skew(35deg);margin-left: -5px;margin-top: -6px;" data-mid="" mpa-from-tpl="t"> <br> </section> </section> <section style="width: 100%;display: flex;justify-content: flex-end;align-items: flex-start;" data-mid="" mpa-from-tpl="t"> <section style="width: 10px;height: 3px;background: #6273AA;transform: skew(35deg);margin-right: -5px;margin-top: -3px;" data-mid="" mpa-from-tpl="t"> <br> </section> <section style="width: 42.2%;height: 3px;background: #6273AA;margin-top: -3px;" data-mid="" mpa-from-tpl="t"> <br> </section> </section> </section> </section> </section> <section data-mid="" mpa-from-tpl="t" style="margin-bottom: 0px;"> <section data-mid="" mpa-from-tpl="t"> <br style="color: rgb(0, 0, 0);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: normal;text-align: left;text-wrap: wrap;"> </section> </section> <h2 data-tool="mdnice编辑器"><span style="display: none;"></span><br mpa-from-tpl="t"></h2> <section data-mpa-template="t" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 25.6px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;color: rgb(68, 153, 231);" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;text-align: center;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto -38px;padding: 0px 15px;max-width: 100%;display: inline-block;background-color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;clear: both;min-height: 1em;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"><span style="font-family: Arial, Helvetica, sans-serif;"><strong mpa-from-tpl="t"><span style="border-color: rgb(68, 153, 231);color: rgb(255, 255, 255);font-size: 16px;">什么是责任链</span></strong></span></p> </section> <section style="margin: -40px 25px 50px;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 3px 0px 0px;padding: 10px 0px;max-width: 100%;box-sizing: border-box;display: inline-block;width: 495px;color: rgb(68, 153, 231);float: left;border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 1em 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);clear: both;color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px 0px -3px;padding: 0px;max-width: 100%;float: right;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: 0px 0px -2px;padding: 0px;max-width: 100%;text-align: left;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: -20px 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;text-decoration: inherit;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-top: 1px solid rgb(68, 153, 231);width: 495px;float: left;border-right-color: rgb(68, 153, 231);border-bottom-color: rgb(68, 153, 231);border-left-color: rgb(68, 153, 231);color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <br> </section> </section> </section> </section> </section> </section> </blockquote> </section> </section> </blockquote> </section> <p><br mpa-from-tpl="t"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。</p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-imgfileid="100126415" data-ratio="0.2884333821376281" data-s="300,640" src="/upload/f76f6798384481d7850d3a3586a2b55a.png" data-type="png" data-w="683" style=""></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;"><span style="font-size: 16px;letter-spacing: 0px;"></span></p> <h2 data-tool="mdnice编辑器"><span style="display: none;"></span><br mpa-from-tpl="t"></h2> <section data-mpa-template="t" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 25.6px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;color: rgb(68, 153, 231);" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;text-align: center;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto -38px;padding: 0px 15px;max-width: 100%;display: inline-block;background-color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;clear: both;min-height: 1em;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"><span style="font-family: Arial, Helvetica, sans-serif;"><strong mpa-from-tpl="t"><span style="border-color: rgb(68, 153, 231);color: rgb(255, 255, 255);font-size: 16px;">使用场景</span></strong></span></p> </section> <section style="margin: -40px 25px 50px;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 3px 0px 0px;padding: 10px 0px;max-width: 100%;box-sizing: border-box;display: inline-block;width: 495px;color: rgb(68, 153, 231);float: left;border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 1em 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);clear: both;color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px 0px -3px;padding: 0px;max-width: 100%;float: right;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: 0px 0px -2px;padding: 0px;max-width: 100%;text-align: left;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: -20px 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;text-decoration: inherit;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-top: 1px solid rgb(68, 153, 231);width: 495px;float: left;border-right-color: rgb(68, 153, 231);border-bottom-color: rgb(68, 153, 231);border-left-color: rgb(68, 153, 231);color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <br> </section> </section> </section> </section> </section> </section> </blockquote> </section> </section> </blockquote> </section> <p><br mpa-from-tpl="t"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 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-1"> <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;"> ERP 系统流程审批:总经理、人事经理、项目经理 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);fon
作者:じ☆ve宝贝
> idea 开发Java,注释使用不太方便,节后live template,打造一款方便的注释生成。 Editor -> Live Templates -> Java Abbreviation: * Description: 方法注释 Template text: ``` * * TODO $params$ $return$ */ ``` Expand with: Enter Reformat according to style: 勾选 Shorten FQ names: 勾选 Edit Variables: ``` name:params Expression:groovyScript( "if(\"${_1}\".length() == 2) { return '*'; } else { def result='*\\n'; def valid = 'false'; def params=\"${_1}\".replaceAll('[\\\\[|\\\\]|\\\\s]', '').split(',').toList(); for(i = 0; i < params.size(); i++) { valid = params[i]+'' == 'null' ? 'true' : 'false'; if(i<(params.size()-1)){ result+='* @param ' + params[i] + '\\n'; }else{ result+='* @param ' + params[i] } }; def res = valid == 'true' ? '*' : result; return res; }", methodParameters()); ----------------------------------------------------------- name:return Expression: groovyScript( "if(\"${_1}\" == 'void'){ def result = '' } else { def returnType = \"${_1}\"; def valid = returnType+'' == 'null' ? 'true' : 'false'; def result = valid == 'true' ? '' : '\\r\\n * @return ' + returnType; return result; }", methodReturnType()); ----------------------------------------------------------- name:returnName groovyScript("def result=''; def params=\"${_1}\".replaceAll('[\\\\[|\\\\]|\\\\s]', '').split('<').toList(); for(i = 0; i < params.size(); i++) {if(i!=0){result+='<';}; def p1=params[i].split(',').toList(); for(i2 = 0; i2 < p1.size(); i2++) { def p2=p1[i2].split('\\\\.').toList(); result+=p2[p2.size()-1]; if(i2!=p1.size()-1){result+=','} } ; }; return result", methodReturnType()); ``` 点击OK。 ## 测试 依次输入 /** 回车 即可查看效果
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;" data-mpa-powered-by="yiban.io"> <section class="mp_profile_iframe_wrp"> <mp-common-profile class="custom_select_card mp_profile_iframe mp_common_widget" data-pluginname="mpprofile" data-id="MzAwMTk4NjM1MA==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/PxMzT0Oibf4gcBzLSUNh2cgXUsuLIsvQYJE1lzZd74qpC3iciaM6gcYIfOVV0KjDDkeN4CTLTn4ETPtaHOAuTWSWA/0?wx_fmt=png" data-nickname="JAVA日知录" data-alias="javadaily" data-signature="写代码的架构师,做架构的程序员! 实战、源码、数据库、架构...只要你来,你想了解的这里都有!" data-from="0"></mp-common-profile> </section> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">背景</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">在高并发下,Java程序的GC问题属于很典型的一类问题,带来的影响往往会被进一步放大。不管是「GC频率过快」还是「GC耗时太长」,由于GC期间都存在Stop The World问题,因此很容易导致服务超时,引发性能问题。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">事情最初是线上某应用垃圾收集出现Full GC异常的现象,应用中个别实例Full GC时间特别长,持续时间约为15~30秒,平均每2周左右触发一次;</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035934" data-ratio="0.4083333333333333" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/cefc89ecf33644c16e68925421cdc4e6.png"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035933" data-ratio="0.4597222222222222" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/f107c99f17c44e19df841693a6014855.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">JVM参数配置:</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(239, 112, 96);background: rgb(255, 249, 249);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">-Xms2048M –Xmx2048M –Xmn1024M –XX:MaxPermSize=512M</p> </blockquote> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035935" data-ratio="0.30416666666666664" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/49e1ab065d516199bc361e78576cc665.png"> </figure> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">排查过程</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>分析 GC 日志<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">GC 日志它记录了每一次的 GC 的执行时间和执行结果,通过分析 GC 日志可以调优堆设置和 GC 设置,或者改进应用程序的对象分配模式。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这里Full GC的reason是Ergonomics,是因为开启了UseAdaptiveSizePolicy,jvm自己进行自适应调整引发的Full GC。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这份日志主要体现GC前后的变化,目前为止看不出个所以然来。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035937" data-ratio="0.5125" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/60cb355ee072db47bb97d248adcf376a.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">开启GC日志,需要添加如下 JVM 启动参数:</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(239, 112, 96);background: rgb(255, 249, 249);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/export/log/risk_pillar/gc.log</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">常见的 Young GC、Full GC 日志含义如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035936" data-ratio="0.6194444444444445" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/d216a5617aa19528f7b963421f3e53c8.png"> </figure> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>进一步查看服务器性能指标<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">获取到了GC耗时的时间后,通过监控平台获取到各个监控项,开始排查这个时点有异常的指标,最终分析发现,在5.06分左右(GC的时点),CPU占用显著提升,而SWAP出现了释放资源、memory资源增长出现拐点的情况(详见下图红色框,橙色框中的变化是因修改配置导致,后面会介绍,暂且可忽略)</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035941" data-ratio="0.4777777777777778" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/4fa8efcf5ae8b77bc77bc55684784a74.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">JVM用到了swap?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">是因为GC导致的CPU突然飙升,并且释放了swap交换区这部分内存到memory?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">为了验证JVM是否用到swap,我们通过检查proc下的进程内存资源占用情况</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/V0mhkIwf3EFGsyVp9XEqnn4iawLRHSs3AvCoIed6JIoHAOWD9z6rKxyUxWEpZuL0aTibiaqIyq7XiazJcIGZ56jUbl7Kssm4GJicT/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #f8f8f8;border-radius: 5px;"><span style="font-weight: bold;line-height: 26px;">for</span> i <span style="font-weight: bold;line-height: 26px;">in</span> (<span style="color: #0086b3;line-height: 26px;">cd</span>/proc;ls∣grep<span style="color: #d14;line-height: 26px;">"[0−9]"</span>∣awk′0 >100<span style="color: #d14;line-height: 26px;">');<br>do awk '</span>/Swap:/{a=a+2}END{<span style="color: #0086b3;line-height: 26px;">print</span> <span style="color: #d14;line-height: 26px;">'"i"'</span>,a/1024<span style="color: #d14;line-height: 26px;">"M"</span>}<span style="color: #d14;line-height: 26px;">' /proc/$i/smaps 2>/dev/null;<br>done | sort -k2nr | head -10 <br><br># head -10 表示 取出 前10个内存占用高的进程 <br># 取出的第一列为进程的id 第二列进程占用swap大小<br></span></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">看到确实有用到305MB的swap</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035938" data-ratio="0.3597222222222222" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/46291ea27e8eba5c8b83b61aef056938.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这里简单介绍下什么是swap?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">swap指的是一个交换分区或文件,主要是在内存使用存在压力时,触发内存回收,这时可能会将部分内存的数据交换到swap空间,以便让系统不会因为内存不够用而导致oom或者更致命的情况出现。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当某进程向OS请求内存发现不足时,OS会把内存中暂时不用的数据交换出去,放在swap分区中,这个过程称为swap out。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当某进程又需要这些数据且OS发现还有空闲物理内存时,又会把swap分区中的数据交换回物理内存中,这个过程称为swap in。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">为了验证GC耗时与swap操作有必然关系,我抽查了十几台机器,重点关注耗时长的GC日志,通过时间点确认到GC耗时的时间点与swap操作的时间点确实是一致的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">进一步查看虚拟机各实例 swappiness 参数,一个普遍现象是,凡是发生较长Full GC的实例都配置了参数 vm.swappiness = 30(值越大表示越倾向于使用swap);而GC时间相对正常的实例配置参数 vm.swappiness = 0(最大限度地降低使用swap)。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">swappiness 可以设置为 0 到 100 之间的值,它是Linux的一个内核参数,控制系统在进 行swap时,内存使用的相对权重。</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> swappiness=0: 表示最大限度使用物理内存,然后才是 swap空间 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> swappiness=100: 表示积极的使用swap分区,并且把内存上的数据及时的交换到swap空间里面 </section></li> </ul> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035939" data-ratio="0.3277777777777778" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/1d05d9145b6f8c1f461dd3ee609f7ab7.png"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035940" data-ratio="0.4625" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/69e077f94d105cfe31ee0abd3e3f33a6.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">对应的物理内存使用率和swap使用情况如下</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035942" data-ratio="0.13055555555555556" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/beec4051cf9a57b33d72fb436e2c2b3b.png"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035946" data-ratio="0.41388888888888886" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/5bb350e74fc88c280047f6d35bb85eec.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">至此,矛头似乎都指向了swap。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">问题分析</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当内存使用率达到水位线(vm.swappiness)时,linux会把一部分暂时不使用的内存数据放到磁盘swap去,以便腾出更多可用内存空间;</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">当需要使用位于swap区的数据时,再将其换回内存中,当JVM进行GC时,需要对相应堆分区的已用内存进行遍历;</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">假如GC的时候,有堆的一部分内容被交换到swap空间中,遍历到这部分的时候就需要将其交换回内存,由于需要访问磁盘,所以相比物理内存,它的速度肯定慢的令人发指,GC停顿的时间一定会非常非常恐怖;</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">进而导致Linux对swap分区的回收滞后(内存到磁盘换入换出操作十分占用CPU与系统IO),在高并发/QPS服务中,这种滞后带来的结果是致命的(STW)。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">问题解决</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">至此,答案似乎很清晰,我们只需尝试把swap关闭或释放掉,看看能否解决问题?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>如何释放swap?</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">设置vm.swappiness=0(重启应用释放swap后生效),表示尽可能不使用交换内存</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">方案 a:临时设置方案,重启后不生效</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 设置vm.swappiness为0,sysctl vm.swappiness=0 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 查看swappiness值,cat /proc/sys/vm/swappiness </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">方案b:永久设置方案,重启后仍然生效</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> vi /etc/sysctl.conf </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 关闭交换分区swapoff –a(前提:首先要保证内存剩余要大于等于swap使用量,否则会报Cannot allocate memory!swap分区一旦释放,所有存放在swap分区的文件都会转存到物理内存上,可能会引发系统IO或者其他问题。) </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">查看当前swap分区挂载在哪:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035943" data-ratio="0.07398843930635839" data-type="png" data-w="865" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/99250e74089179b08abefe523bbab1ff.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">关停分区:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035944" data-ratio="0.12716763005780346" data-type="png" data-w="865" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/159c2d73c499b3b701963f201ff0af03.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">关闭swap交换区后的内存变化见下图橙色框,此时swap分区的文件都转存到了物理内存上</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035945" data-ratio="0.5347222222222222" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/5460d613b6aa463ee3526760bb464cbc.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">关闭Swap交换区后,于2.23再次发生Full GC,耗时190ms,问题得到解决。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035947" data-ratio="0.5069444444444444" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/118e14e6673587092936f8d4e350e4e2.png"> </figure> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">疑惑</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 是不是只要开启了swap交换区的JVM,在GC的时候都会耗时较长呢? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 既然JVM对swap如此不待见,为何JVM不明令禁止使用呢? </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> swap工作机制是怎样的?这台物理内存为8g的server,使用了交换区内存(swap),说明物理内存不够使用了,但是通过free命令查看内存使用情况,实际物理内存似乎并没有占用那么多,反而Swap已占近1G? </section></li> </ol> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035948" data-ratio="0.13108614232209737" data-type="png" data-w="801" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/73915807ac03ea76905287e9b9dfc961.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">free:除了buff/cache剩余了多少内存</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">shared:共享内存</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">buff/cache:缓冲、缓存区内存数(使用过高通常是程序频繁存取文件)</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">available:真实剩余的可用内存数</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">进一步思考</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">大家可以想想,关闭交换磁盘缓存意味着什么?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">其实大可不必如此激进,要知道这个世界永远不是非0即1的,大家都会或多或少选择走在中间,不过有些偏向0,有些偏向1而已。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">很显然,在swap这个问题上,JVM可以选择偏向尽量少用,从而降低swap影响,要降低swap影响有必要弄清楚Linux内存回收是怎么工作的,这样才能不遗漏任何可能的疑点。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>先来看看swap是如何触发的?</strong></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Linux会在两种场景下触发内存回收,一种是在内存分配时发现没有足够空闲内存时会立刻触发内存回收;另一种是开启了一个守护进程(kswapd进程)周期性对系统内存进行检查,在可用内存降低到特定阈值之后主动触发内存回收。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过如下图示可以很容易理解,详细信息参见:</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;border-left-color: rgb(239, 112, 96);background: rgb(255, 249, 249);"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">http://hbasefly.com/2017/05/24/hbase-linux/</p> </blockquote> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035952" data-ratio="0.4638888888888889" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/cbb7062fc9306b3d0b5f7cad01cedf0c.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">是不是只要开启了swap交换区的JVM,在GC的时候都会耗时较长?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">笔者去查了一下另外的一个应用,相关指标信息请见下图。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">实名服务的QPS是非常高的,同样能看到应用了swap,GC平均耗时 576ms,这是为什么呢?</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035950" data-ratio="0.4486111111111111" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/e60a1e41efa538c4a13cdfc5bde0a031.png"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035951" data-ratio="0.5138888888888888" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/eae037c835b017a2405fd20ec4c42ce6.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过把时间范围聚焦到发生GC的某一时间段,从监控指标图可以看到swapUsed没有任何变化,也就是说没有swap活动,进而没有影响到垃级回收的总耗时。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035949" data-ratio="0.41944444444444445" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/8d691e61decb205860edcbd778125da0.png"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035953" data-ratio="0.4722222222222222" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/63a1bee63a666cca01eb253246168f40.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过如下命令列举出各进程swap空间占用情况,很清楚的看到实名这个服务swap空间占用的较少(仅54.2MB)</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035956" data-ratio="0.5069444444444444" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/9d283b590923d17f3fc000def42fef1e.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">另一个显著的现象是实名服务Full GC间隔较短(几个小时一次),而我的服务平均间隔2周一次Full GC</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035954" data-ratio="0.5138888888888888" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/2ae8994c85e80628e5deca5bcb6a1371.png"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035957" data-ratio="0.44583333333333336" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/ffd170d4c571552fbb4d66abc2fd909a.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">基于以上推测</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 实名服务由于 GC 间隔较短,内存中的东西根本没有机会置换到swap中就被回收了,GC的时候不需要将swap分区中的数据交换回物理内存中,完全基于内存计算,所以要快很多 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 将哪些内存数据置换进swap交换区的筛选策略应该是类似于LRU算法(最近最少使用原则) </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">为了证实上述猜测,我们只需跟踪swap变更日志,监控数据变化即可得到答案,这里采用一段shell 脚本实现</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/V0mhkIwf3EFGsyVp9XEqnn4iawLRHSs3AvCoIed6JIoHAOWD9z6rKxyUxWEpZuL0aTibiaqIyq7XiazJcIGZ56jUbl7Kssm4GJicT/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(248, 248, 248);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #333;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #f8f8f8;border-radius: 5px;"><span style="color: #999;font-weight: bold;line-height: 26px;">#!/bin/bash </span><br><span style="color: #0086b3;line-height: 26px;">echo</span> -e `date +%y%m%d%H%M%S` <br><span style="color: #0086b3;line-height: 26px;">echo</span> -e <span style="color: #d14;line-height: 26px;">"PID\t\tSwap\t\tProc_Name"</span> <br><br><span style="color: #998;font-style: italic;line-height: 26px;">#拿出/proc目录下所有以数字为名的目录(进程名是数字才是进程,其他如sys,net等存放的是其他信息) </span><br><span style="font-weight: bold;line-height: 26px;">for</span> pid <span style="font-weight: bold;line-height: 26px;">in</span> `ls -l /proc | grep ^d | awk <span style="color: #d14;line-height: 26px;">'{ print $9 }'</span>| grep -v [^0-9]` <br><span style="font-weight: bold;line-height: 26px;">do</span> <br> <span style="font-weight: bold;line-height: 26px;">if</span> [ <span style="color: #008080;line-height: 26px;">$pid</span> -eq 1 ];<span style="font-weight: bold;line-height: 26px;">then</span> <span style="color: #0086b3;line-height: 26px;">continue</span>;<span style="font-weight: bold;line-height: 26px;">fi</span> <br> grep -q <span style="color: #d14;line-height: 26px;">"Swap"</span> /proc/<span style="color: #008080;line-height: 26px;">$pid</span>/smaps 2>/dev/null <br> <span style="font-weight: bold;line-height: 26px;">if</span> [ $? -eq 0 ];<span style="font-weight: bold;line-height: 26px;">then</span> <br> swap=$(gawk <span style="color: #d14;line-height: 26px;">'/Swap/{ sum+=$2;} END{ print sum }'</span> /proc/<span style="color: #008080;line-height: 26px;">$pid</span>/smaps) <span style="color: #998;font-style: italic;line-height: 26px;">#统计占用的swap分区的 大小 单位是KB </span><br> proc_name=$(ps aux | grep -w <span style="color: #d14;line-height: 26px;">"<span style="color: #008080;line-height: 26px;">$pid</span>"</span> | awk <span style="color: #d14;line-height: 26px;">'!/grep/{ for(i=11;i<=NF;i++){ printf("%s ",$i); }}'</span>) <span style="color: #998;font-style: italic;line-height: 26px;">#取出进程的名字 </span><br> <span style="font-weight: bold;line-height: 26px;">if</span> [ <span style="color: #008080;line-height: 26px;">$swap</span> -gt 0 ];<span style="font-weight: bold;line-height: 26px;">then</span> <span style="color: #998;font-style: italic;line-height: 26px;">#判断是否占用swap 只有占用才会输出 </span><br> <span style="color: #0086b3;line-height: 26px;">echo</span> -e <span style="color: #d14;line-height: 26px;">"<span style="color: #008080;line-height: 26px;">${pid}</span>\t<span style="color: #008080;line-height: 26px;">${swap}</span>\t<span style="color: #008080;line-height: 26px;">${proc_name:0:100}</span>"</span> <br> <span style="font-weight: bold;line-height: 26px;">fi</span> <br> <span style="font-weight: bold;line-height: 26px;">fi</span><br><span style="font-weight: bold;line-height: 26px;">done</span> | sort -k2nr | head -10 | gawk -F<span style="color: #d14;line-height: 26px;">'\t'</span> <span style="color: #d14;line-height: 26px;">'{ #排序取前 10 <br> pid[NR]=$1; <br> size[NR]=$2; <br> name[NR]=$3; <br>} <br>END{ <br> for(id=1;id<=length(pid);id++) <br> { <br> if(size[id]<1024) <br> printf("%-10s\t%15sKB\t%s\n",pid[id],size[id],name[id]); <br> else if(size[id]<1048576) <br> printf("%-10s\t%15.2fMB\t%s\n",pid[id],size[id]/1024,name[id]);<br> else <br> printf("%-10s\t%15.2fGB\t%s\n",pid[id],size[id]/1048576,name[id]); <br> } <br>}<br></span></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">由于上面图中 2022.3.2 19:57:00 至 2022.3.2 19:58:00 发生了一次Full GC,我们重点关注下这一分钟内swap交换区的变化即可,我这里每10s做一次信息采集,可以看到在GC时点前后,swap确实没有变化</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100035955" data-ratio="0.475" data-type="png" data-w="720" style="display: block;margin-right: auto;margin-left: auto;height: auto !important;" src="/upload/0ee27d1d963cdac666cd7402e5dc294a.png"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">通过上述分析,回归本文核心问题上,现在看来我的处理方式过于激进了,其实也可以不用关闭swap,通过适当降低堆大小,也是能够解决问题的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这也侧面的说明,部署Java服务的Linux系统,在内存分配上并不是无脑大而全,需要综合考虑不同场景下JVM对Java永久代 、Java堆(新生代和老年代)、线程栈、Java NIO所使用内存的需求。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;border-bottom: 2px solid rgb(239, 112, 96);font-size: 1.3em;"><span style="display: none;"></span><span style="display: inline-block;background: rgb(239, 112, 96);color: rgb(255, 255, 255);padding: 3px 10px 1px;border-top-right-radius: 3px;border-top-left-radius: 3px;margin-right: 3px;">总结</span><span style="display: inline-block;vertical-align: bottom;border-bottom: 36px solid #efebe9;border-right: 20px solid transparent;"> </span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">综上,我们得出结论,swap和GC同一时候发生会导致GC时间非常长,JVM严重卡顿,极端的情况下会导致服务崩溃。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">主要原因是:JVM进行GC时,需要对对应堆分区的已用内存进行遍历,假如GC的时候,有堆的一部分内容被交换到swap中,遍历到这部分的时候就须要将其交换回内存;更极端情况同一时刻因为内存空间不足,就需要把内存中堆的另外一部分换到SWAP中去,于是在遍历堆分区的过程中,会把整个堆分区轮流往SWAP写一遍,导致GC时间超长。线上应该限制swap区的大小,如果swap占用比例较高应该进行排查和解决,适当的时候可以通过降低堆大小,或者添加物理内存。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">因此,部署Java服务的Linux系统,在内存分配上要慎重。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">以上内容希望可以起到抛转引玉的作用,如有理解不到位的地方烦请指出。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">好了,本文的技术部分就到这里啦。</p> </section>
作者:微信小助手
<p data-mpa-powered-by="yiban.io"><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-weight: bold;font-size: 17px;">代码重构</span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.8044444444444444" data-s="300,640" src="/upload/195ad5e38849f5d5862591adac996902.png" data-type="png" data-w="450" style=""></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(218, 104, 46);font-size: 15px;">【定义】</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">对软件代码做任何改动以增加可读性或者简化结构而</span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;font-size: 15px;letter-spacing: 0.034em;">不影响输出结果。</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(218, 104, 46);font-size: 15px;">【目的】</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">增加可读性、增加可维护性、可扩展性。</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(192, 0, 0);font-size: 15px;">【关键点】</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">1. 不影响输出;</span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;font-size: 15px;letter-spacing: 0.034em;">2. 不修正错误;3. 不增加新的功能性</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-weight: bold;font-size: 17px;">架构重构</span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.75" data-s="300,640" src="/upload/192c853030dd2c0cb988ef63f07ece5c.png" data-type="png" data-w="640" style=""></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(218, 104, 46);font-size: 15px;">【定义】</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">通过调整系统结构来修复系统质量问题而不</span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;font-size: 15px;letter-spacing: 0.034em;">影响整体系统能力。</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(218, 104, 46);font-size: 15px;">【目的】</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">修复质量问题(性能、可用性、可扩展……)。</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(221, 56, 6);font-size: 15px;">【关键点】</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">1. 修复质量问题,提升架构质量;</span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;font-size: 15px;letter-spacing: 0.034em;">2. 不影响整体系统功能;3. 架构本质没有发生变化。</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-weight: bold;font-size: 17px;">代码重构 vs 架构重构</span></p> <table> <tbody> <tr> <td width="172" valign="top" style="word-break: break-all;"><br></td> <td width="172" valign="top" style="word-break: break-all;"><span style="font-size: 15px;">代码重构<br></span></td> <td width="172" valign="top"><br></td> </tr> <tr> <td width="172" valign="top" style="word-break: break-all;"><p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">基本做法</span></p></td> <td width="172" valign="top" style="word-break: break-all;"><p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">调整代码</span></p><p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;"><br></span></p></td> <td width="172" valign="top" style="word-break: break-all;"><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;letter-spacing: 0.578px;font-size: 15px;">调整架构</span></td> </tr> <tr> <td width="172" valign="top" style="word-break: break-all;"><p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">目的</span></p></td> <td width="172" valign="top" style="word-break: break-all;"><p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">优化代码,增加代码的可读性、可维护性、可扩展性</span></p></td> <td width="172" valign="top" style="word-break: break-all;"><p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">修复架构质量问题</span></p></td> </tr> <tr> <td width="172" valign="top" style="word-break: break-all;"><p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">是否修复问题</span></p></td> <td width="172" valign="top" style="word-break: break-all;"><p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">否</span></p></td> <td width="172" valign="top" style="word-break: break-all;"><span style="font-size: 15px;">是<br></span></td> </tr> <tr> <td width="172" valign="top" style="word-break: break-all;"><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;letter-spacing: 0.578px;font-size: 15px;">是否改变系统能力</span></td> <td width="172" valign="top" style="word-break: break-all;"><span style="font-size: 15px;">否</span></td> <td width="172" valign="top" style="word-break: break-all;"><span style="font-size: 15px;">否<br></span></td> </tr> <tr> <td width="172" valign="top" style="word-break: break-all;"><span style="font-size: 15px;">手段<br></span></td> <td width="172" valign="top" style="word-break: break-all;"><p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">引入设计模式</span></p></td> <td width="172" valign="top" style="word-break: break-all;"><p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">引入缓存,分库分表</span></p></td> </tr> </tbody> </table> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-weight: bold;font-size: 17px;">架构重构手段</span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.4351851851851852" data-s="300,640" src="/upload/f5d67fe5482c28f8eccd7ef74ef9720c.png" data-type="png" data-w="1080" style=""></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-weight: bold;font-size: 17px;">技巧1 - 先局部优化后架构重构</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-weight: bold;font-size: 17px;">局部优化<br></span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(218, 104, 46);font-size: 15px;">【定义】</span></p> <p><span style="font-size: 15px;"><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">对部分业务或者功能进行优化,</span><span style="font-family: AlibabaPuHuiTiR;color: rgb(221, 56, 6);">不影响</span><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">系统架构。</span></span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(218, 104, 46);font-size: 15px;">【常见手段】</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">1. 数据库添加索引,优化索引;</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">2. 某个数据缓存更新策略采用后台更新;</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">3. 增加负载均衡服务数量;</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">4. 优化代码里面并发的逻辑;</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">5. 修改 InnoDB buffer pool 配置,分配更多内存;</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">6. 服务间的某个接口增加1个参数。</span></p> <p><strong><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">架构重构<br></span></strong></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(218, 104, 46);font-size: 15px;">【定义】</span></p> <p><span style="font-size: 15px;"><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">优化系统架构,整体提升质量,架构重构</span><span style="font-family: AlibabaPuHuiTiR;color: rgb(221, 56, 6);">会影响</span><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">架构的4R定义。</span></span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(218, 104, 46);font-size: 15px;">【常见手段】</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">1. 引入消息队列(增加 Role);</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">2. 去掉 ZooKeeper,改为内置 Raft 算法实现(删除 Role);</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">3. 将 Memcached 改为 Redis(改变 Role);</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">4. 按照稳定性拆分微服务(拆分 Role);</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">5. 将粒度太细的微服务合并(合并 Role);</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">6. 将服务间的通信方式由 HTTP 改为 gRPC(修改 Relation);</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">7. SDK 从读本地配置文件改为从管理系统读取配置(修改</span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;font-size: 15px;letter-spacing: 0.034em;">Rule)</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-weight: bold;font-size: 17px;">技巧2 - 有的放矢</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-weight: bold;font-size: 17px;">1.明确目标:</span></p> <p><span style="font-size: 15px;"><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">不要试图解决所有的问题,</span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;letter-spacing: 0.034em;">抓住关键问题。</span></span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(218, 104, 46);font-size: 15px;">【技巧】</span></p> <p><span style="font-size: 15px;"><span style="font-family: AlibabaPuHuiTiR;color: rgb(4, 50, 255);">问题分类</span><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">:问题收集列表可能有100条,</span></span><span style="font-size: 15px;letter-spacing: 0.034em;font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">不要全部想着通过架构重构解决,</span><span style="font-size: 15px;letter-spacing: 0.034em;font-family: AlibabaPuHuiTiR;color: rgb(192, 0, 0);">分门</span></p> <p><span style="font-size: 15px;"><span style="font-family: AlibabaPuHuiTiR;color: rgb(192, 0, 0);">别类</span><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">,找出需要架构重构解决的问题。</span></span></p> <p><strong><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 17px;">2.明确时间:<br></span></strong></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">要有明确的时间点和里程碑,</span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;font-size: 15px;letter-spacing: 0.034em;">不要说“慢慢优化”。需要有量化的指标来衡量,不能说“提升 xxx 质量。</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(218, 104, 46);font-size: 15px;">【技巧】</span></p> <p><span style="font-size: 15px;"><span style="font-family: AlibabaPuHuiTiR;color: rgb(4, 50, 255);">独立版本</span><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">:不要混在业务版本里面做</span></span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;font-size: 15px;letter-spacing: 0.034em;">架构重构,否则不好协调资源。</span></p> <p><strong><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;letter-spacing: 0.034em;font-size: 17px;">3.明确目标:<br></span></strong></p> <p><span style="font-size: 15px;"><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">需要有量化的指标来衡量,</span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;letter-spacing: 0.034em;">不能说“提升 xxx 质量”。</span></span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(218, 104, 46);font-size: 15px;">【技巧】</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">1. 先收集系统已有相关数据,适合项</span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;font-size: 15px;letter-spacing: 0.034em;">目投入、时间等;</span></p> <p><span style="font-size: 15px;"><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">2. </span><span style="font-family: AlibabaPuHuiTiR;color: rgb(4, 50, 255);">调查问卷</span><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">:适合效率、复杂度等。</span></span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-weight: bold;font-size: 17px;">技巧2 - 案例</span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.3148148148148148" data-s="300,640" src="/upload/975685b080d2777f190910a98e9ce7c4.png" data-type="png" data-w="1080" style=""></p> <p><br></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-weight: bold;font-size: 17px;">技巧3 - 合纵连横</span></p> <p><strong><span style="font-size: 15px;font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">1.合纵:</span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;letter-spacing: 0.034em;font-size: 15px;">说服业务方和老板。</span></strong></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(218, 104, 46);font-size: 15px;">1. 以数据说话</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">把“可扩展性”转换为“版本开发速度很慢”,</span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;font-size: 15px;letter-spacing: 0.034em;">然后给出对应的项目数据。</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(218, 104, 46);font-size: 15px;">2. 以案例说话</span></p> <p><span style="font-size: 15px;"><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">如果没有数据,就举极端案例,例如某个小功能,</span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;letter-spacing: 0.034em;">开发测试只要5天,但是等了1个月才上线。</span></span></p> <p><strong><span style="font-size: 15px;letter-spacing: 0.034em;font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">1.联横:</span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;letter-spacing: 0.034em;font-size: 15px;">说服其它团队</span></strong></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(218, 104, 46);font-size: 15px;">1. 换位思考</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">思考对其它团队的好处,才能让人配合。</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(218, 104, 46);font-size: 15px;">2. 合作双赢</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">汇报和总结的时候,把其它团队也带上。</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-weight: bold;font-size: 17px;">技巧3 - 案例</span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.32407407407407407" data-s="300,640" src="/upload/e5630099f16d682e0dcebb7d365ce40f.png" data-type="png" data-w="1080" style=""></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-weight: bold;font-size: 17px;">技巧4 - 运筹帷幄</span></p> <p><strong>1.问题分类:</strong></p> <p><span style="font-size: 15px;"><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">将问题分类,一段时间集中处理</span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;letter-spacing: 0.034em;">一类问题。</span></span></p> <p><span style="font-size: 15px;"><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">避免对照 Excel 表格,一条一条</span><span style="color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;letter-spacing: 0.034em;">的解决</span></span></p> <p><strong><span style="font-size: 15px;color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;letter-spacing: 0.034em;">2.问题排序</span></strong><span style="font-size: 15px;color: rgb(0, 0, 0);font-family: AlibabaPuHuiTiR;letter-spacing: 0.034em;"><br></span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">分类后排序,按照优先级顺序来落地。</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">避免见缝插针式的安排重构任务。</span></p> <p><strong><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">3.逐一攻破<br></span></strong></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">每一类问题里面先易后难。</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">把容易的问题解决掉,增强信心。</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-weight: bold;font-size: 17px;">技巧4 - 案例</span></p> <p style="text-align: center;"><img class="rich_pages wxw-img" data-galleryid="" data-ratio="0.49166666666666664" data-s="300,640" src="/upload/4d7803c5e8f2c5339839f966448de5c6.png" data-type="png" data-w="1080" style=""></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-weight: bold;font-size: 17px;">架构重构的一些典型问题</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">架构重构是否可以引入新技术?</span></p> <p><span style="font-size: 15px;"><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">可以,但尽量少,架构重构要求</span><span style="font-family: AlibabaPuHuiTiR;color: rgb(4, 50, 255);">快准</span><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">。</span></span></p> <hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"> <p><br></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">业务不给时间重构怎么办?</span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">会哭的孩子有奶吃。</span></p> <hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;"></span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">其它团队不配合怎么办?</span></p> <p><span style="font-size: 15px;"><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">学会利用</span><span style="font-family: AlibabaPuHuiTiR;color: rgb(4, 50, 255);">上级力量。</span></span></p> <hr style="border-style: solid;border-width: 1px 0 0;border-color: rgba(0,0,0,0.1);-webkit-transform-origin: 0 0;-webkit-transform: scale(1, 0.5);transform-origin: 0 0;transform: scale(1, 0.5);"> <p><span style="font-size: 15px;"><span style="font-family: AlibabaPuHuiTiR;color: rgb(4, 50, 255);"></span></span></p> <p><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);font-size: 15px;">业务进度很紧,人力不够怎么办?</span></p> <p><span style="font-size: 15px;"><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">收集需要重构的</span><span style="font-family: AlibabaPuHuiTiR;color: rgb(4, 50, 255);">证据</span><span style="font-family: AlibabaPuHuiTiR;color: rgb(0, 0, 0);">,技术汇报的时候有理有据。</span></span></p> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<section data-mpa-template="t" mpa-paragraph-type="ignored" style="margin-bottom: 0px;text-wrap: wrap;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);" data-mpa-powered-by="yiban.io"> <p style="text-align: left;"><span style="font-size: 16px;"><strong>目录</strong></span></p> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 介绍 </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> <section data-mpa-template="t" mpa-from-tpl="t"> <section data-mpa-category="模板" style="width: 100%;padding: 0 15px;" data-mid="" mpa-from-tpl="t"> <section style="width: 100%;padding: 15px 17px 20px;background: #ebf4ff;font-size: 14px;font-weight: 400;color: #6273aa;line-height: 20px;" data-mid="" mpa-from-tpl="t"> <p data-mid="" mpa-is-content="t" style="text-align: left;">文章来源:https://blog.csdn.net/m0_64360721/article/details/122960311</p> </section> <section style="width: 100%;display: flex;justify-content: flex-end;align-items: flex-start;padding-right: 5px;" data-mid="" mpa-from-tpl="t"> <section data-mid="" mpa-from-tpl="t" style="width: 23px;height: 27px;background: url("https://mmbiz.qpic.cn/mmbiz_png/dLHvdVqeWINyJQzMVmQzxIcFqDsaiaK6ATCCANPe11FbZKCApfz0TbDtfc5gfSQNgJpic86YejM6qcNU5gubeetQ/640") no-repeat;background-size: contain;background-position: center center;margin-top: -27px;z-index: 10;"> <br> </section> </section> <section style="width: 100%;display: flex;justify-content: flex-start;align-items: flex-start;" data-mid="" mpa-from-tpl="t"> <section style="width: 52.3%;height: 8px;background: #6273AA;margin-top: -6px;" data-mid="" mpa-from-tpl="t"> <br> </section> <section style="width: 10px;height: 8px;background: #6273AA;transform: skew(35deg);margin-left: -5px;margin-top: -6px;" data-mid="" mpa-from-tpl="t"> <br> </section> </section> <section style="width: 100%;display: flex;justify-content: flex-end;align-items: flex-start;" data-mid="" mpa-from-tpl="t"> <section style="width: 10px;height: 3px;background: #6273AA;transform: skew(35deg);margin-right: -5px;margin-top: -3px;" data-mid="" mpa-from-tpl="t"> <br> </section> <section style="width: 42.2%;height: 3px;background: #6273AA;margin-top: -3px;" data-mid="" mpa-from-tpl="t"> <br> </section> </section> </section> </section> <h2 data-tool="mdnice编辑器"><span style="display: none;"></span><br mpa-from-tpl="t"></h2> <p><br></p> <section data-mpa-template="t" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 25.6px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;color: rgb(68, 153, 231);" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;text-align: center;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto -38px;padding: 0px 15px;max-width: 100%;display: inline-block;background-color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;clear: both;min-height: 1em;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"><span style="font-family: Arial, Helvetica, sans-serif;"><strong mpa-from-tpl="t"><span style="border-color: rgb(68, 153, 231);color: rgb(255, 255, 255);font-size: 16px;" mpa-is-content="t">介绍</span></strong></span></p> </section> <section style="margin: -40px 25px 50px;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 3px 0px 0px;padding: 10px 0px;max-width: 100%;box-sizing: border-box;display: inline-block;width: 495px;color: rgb(68, 153, 231);float: left;border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 1em 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);clear: both;color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px 0px -3px;padding: 0px;max-width: 100%;float: right;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: 0px 0px -2px;padding: 0px;max-width: 100%;text-align: left;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: -20px 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;text-decoration: inherit;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-top: 1px solid rgb(68, 153, 231);width: 495px;float: left;border-right-color: rgb(68, 153, 231);border-bottom-color: rgb(68, 153, 231);border-left-color: rgb(68, 153, 231);color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <br> </section> </section> </section> </section> </section> </section> </blockquote> </section> </section> </blockquote> </section> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">下载功能应该是比较常见的功能了,虽然一个项目里面可能出现的不多,但是基本上每个项目都会有,而且有些下载功能其实还是比较繁杂的,倒不是难,而是麻烦。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">所以结合之前的下载需求,我写了一个库来简化下载功能的实现</p> <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;"> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">❝</p> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">传送门:https://github.com/Linyuzai/concept/wiki/Concept-Download</p> <p style="padding-top: 8px;padding-bottom: 8px;letter-spacing: 0.2em;word-spacing: 0.1em;line-height: 26px;font-size: 15px;">❞</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">如果我说现在只需要一个注解就能帮你下载任意的对象,是不是觉得非常的方便</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG1xSmLWhia6IibKjtW00qp2PJNo0qoyFEJa2wicj5SKvYw9vv9ic2BpNvSkccicwsH7ICu0Xz0m69eynXiaPq3bUOEKpt/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #9B9B9B;line-height: 26px;">@Download</span>(source = <span style="color: #D69D85;line-height: 26px;">"classpath:/download/README.txt"</span>)<br><span style="color: #9B9B9B;line-height: 26px;">@GetMapping</span>(<span style="color: #D69D85;line-height: 26px;">"/classpath"</span>)<br><span style="line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">public</span> <span style="color: #569CD6;line-height: 26px;">void</span> <span style="line-height: 26px;">classpath</span><span style="line-height: 26px;">()</span> </span>{<br><br>}<br><br><span style="color: #9B9B9B;line-height: 26px;">@Download</span><br><span style="color: #9B9B9B;line-height: 26px;">@GetMapping</span>(<span style="color: #D69D85;line-height: 26px;">"/file"</span>)<br><span style="line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">public</span> File <span style="line-height: 26px;">file</span><span style="line-height: 26px;">()</span> </span>{<br> <span style="color: #569CD6;line-height: 26px;">return</span> <span style="color: #569CD6;line-height: 26px;">new</span> File(<span style="color: #D69D85;line-height: 26px;">"/Users/Shared/README.txt"</span>);<br>}<br><br><span style="color: #9B9B9B;line-height: 26px;">@Download</span><br><span style="color: #9B9B9B;line-height: 26px;">@GetMapping</span>(<span style="color: #D69D85;line-height: 26px;">"/http"</span>)<br><span style="line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">public</span> String <span style="line-height: 26px;">http</span><span style="line-height: 26px;">()</span> </span>{<br> <span style="color: #569CD6;line-height: 26px;">return</span> <span style="color: #D69D85;line-height: 26px;">"http://127.0.0.1:8080/concept-download/image.jpg"</span>;<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">感觉差别不大?那就听听我遇到的一个下载需求</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">我们有一个平台是管理设备的,然后每个设备都会有一个二维码图片,用一个字段存储的 http 地址</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">现在需要导出所有设备二维码图片的压缩包,图片名称需要用设备名称加 .png 后缀,需求上来说并不难,但是着实有点麻烦</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 15px;"> 首先我需要将设备列表查出来 </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;"> 再生成一个压缩文件 </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: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">看着我实现了将近 200 行的代码,真是又臭又长,一个下载功能咋能那么麻烦呢,于是我就想有没有更简单的方式</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">我当时的需求很简单,我想着我只要提供需要下载的数据,比如一个文件路径,一个文件对象,一段字符串文本,一个http地址,或者混搭了前面所有类型的一个集合,甚至是我们自定义的某个类的实例,后面的事情我就不用管了</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">文件路径是一个文件还是一个目录?字符串文本需要先写入一个文本文件中?http资源如何下载到本地?多个文件怎么压缩?最后怎么写到响应中?我才不想花时间管这些</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">比如就像我现在这个需求,我只要返回设备列表就行了,其他的事情我都不用管</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG1xSmLWhia6IibKjtW00qp2PJNo0qoyFEJa2wicj5SKvYw9vv9ic2BpNvSkccicwsH7ICu0Xz0m69eynXiaPq3bUOEKpt/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #9B9B9B;line-height: 26px;">@Download</span>(filename = <span style="color: #D69D85;line-height: 26px;">"二维码.zip"</span>)<br><span style="color: #9B9B9B;line-height: 26px;">@GetMapping</span>(<span style="color: #D69D85;line-height: 26px;">"/download"</span>)<br><span style="line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">public</span> List<Device> <span style="line-height: 26px;">download</span><span style="line-height: 26px;">()</span> </span>{<br> <span style="color: #569CD6;line-height: 26px;">return</span> deviceService.all();<br>}<br><br><span style="color: #569CD6;line-height: 26px;">public</span> <span style="color: #B8D7A3;line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">class</span> <span style="color: #DCDCDC;line-height: 26px;">Device</span> </span>{<br><br> <span style="color: #57A64A;font-style: italic;line-height: 26px;">//设备名称</span><br> <span style="color: #569CD6;line-height: 26px;">private</span> String name;<br><br> <span style="color: #57A64A;font-style: italic;line-height: 26px;">//设备二维码</span><br> <span style="color: #57A64A;font-style: italic;line-height: 26px;">//注解表示该http地址是需要下载的数据</span><br> <span style="color: #9B9B9B;line-height: 26px;">@SourceObject</span><br> <span style="color: #569CD6;line-height: 26px;">private</span> String qrCodeUrl;<br><br> <span style="color: #57A64A;font-style: italic;line-height: 26px;">//注解表示文件名称</span><br> <span style="color: #9B9B9B;line-height: 26px;">@SourceName</span><br> <span style="line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">public</span> String <span style="line-height: 26px;">getQrCodeName</span><span style="line-height: 26px;">()</span> </span>{<br> <span style="color: #569CD6;line-height: 26px;">return</span> name + <span style="color: #D69D85;line-height: 26px;">".png"</span>;<br> }<br> <span style="color: #57A64A;font-style: italic;line-height: 26px;">//省略其他属性方法</span><br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">通过在 Device 的字段上标注某些注解(或是实现某个接口)来指定文件名称和文件地址</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">如果能这样实现,省时省心省力,又多了写 199 行代码的摸鱼时间难道不香么</p> <h2 data-tool="mdnice编辑器"><br></h2> <h2 data-tool="mdnice编辑器"><span style="display: none;"></span><br mpa-from-tpl="t"></h2> <section data-mpa-template="t" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);font-size: 16px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 25.6px;box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;color: rgb(68, 153, 231);" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <blockquote style="margin: 5px auto;padding: 0px;max-width: 100%;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto;padding: 0px;max-width: 100%;text-align: center;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px auto -38px;padding: 0px 15px;max-width: 100%;display: inline-block;background-color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <p style="margin-top: 5px;margin-bottom: 5px;max-width: 100%;clear: both;min-height: 1em;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;"><span style="font-family: Arial, Helvetica, sans-serif;"><strong mpa-from-tpl="t"><span style="border-color: rgb(68, 153, 231);color: rgb(255, 255, 255);font-size: 16px;" mpa-is-content="t">思路</span></strong></span></p> </section> <section style="margin: -40px 25px 50px;padding: 0px;max-width: 100%;border-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 3px 0px 0px;padding: 10px 0px;max-width: 100%;box-sizing: border-box;display: inline-block;width: 495px;color: rgb(68, 153, 231);float: left;border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 1em 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-width: 0px;border-style: none;border-color: rgb(68, 153, 231);clear: both;color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px 0px -3px;padding: 0px;max-width: 100%;float: right;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: 0px 0px -2px;padding: 0px;max-width: 100%;text-align: left;border-color: rgb(68, 153, 231);width: 6px;border-radius: 50%;background-color: rgb(68, 153, 231);box-sizing: border-box !important;word-wrap: break-word !important;overflow-wrap: break-word !important;height: 6px !important;" mpa-from-tpl="t"> <br> </section> <section style="margin: -20px 0px 0px;padding: 0px;max-width: 100%;box-sizing: border-box;text-decoration: inherit;color: rgb(68, 153, 231);border-color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <section style="margin: 0px;padding: 0px;max-width: 100%;box-sizing: border-box;border-top: 1px solid rgb(68, 153, 231);width: 495px;float: left;border-right-color: rgb(68, 153, 231);border-bottom-color: rgb(68, 153, 231);border-left-color: rgb(68, 153, 231);color: rgb(68, 153, 231);word-wrap: break-word !important;overflow-wrap: break-word !important;" mpa-from-tpl="t"> <br> </section> </section> </section> </section> </section> </section> </blockquote> </section> </section> </blockquote> </section> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">下面来讲讲这个库的主要设计思路,以及中间遇到的坑,大家有兴趣可以继续往下看</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">其实基于一开始的设想,我觉得功能并没有多复杂,于是就决定开肝</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">只是万万没想到实现起来比我想象的更复杂(这是后话了)</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;color: rgb(14, 136, 235);"><span style="display: none;"></span>基础<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 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;">Mono<InputStream</code>>这样的。。。奇怪组合?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">为什么会这样呢,很大的一个原因是由于需要兼容webmvc和webflux,导致我仅仅是将之前实现的InputStream方式重构成了响应式,所以就出现了这样的组合</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">这也是我遇到的最大的一个坑,我先前已经基本调通了基于Servlet的整个下载流程,然后就想着支持一下webflux</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">大家都知道webmvc中,我们可以通过RequestContextHolder来获得请求和响应对象,但是在webflux中就不行了,当然我们可以在方法参数中注入</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG1xSmLWhia6IibKjtW00qp2PJNo0qoyFEJa2wicj5SKvYw9vv9ic2BpNvSkccicwsH7ICu0Xz0m69eynXiaPq3bUOEKpt/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #9B9B9B;line-height: 26px;">@Download</span>(source = <span style="color: #D69D85;line-height: 26px;">"classpath:/download/README.txt"</span>)<br><span style="color: #9B9B9B;line-height: 26px;">@GetMapping</span>(<span style="color: #D69D85;line-height: 26px;">"/classpath"</span>)<br><span style="line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">public</span> <span style="color: #569CD6;line-height: 26px;">void</span> <span style="line-height: 26px;">classpath</span><span style="line-height: 26px;">(ServerHttpResponse response)</span> </span>{<br><br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">结合Spring自带的注入功能,我们就可以通过AOP拿到响应的入参了,但是总觉得这样写有点多余,强迫症表示不能忍</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;margin: 10px;line-height: 1.75;letter-spacing: 0.2em;font-size: 15px;word-spacing: 0.1em;">有什么办法既能把用不到的入参干掉,又能拿到响应对象呢,在网上找到了一种实现方式</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/hzVGicX27IG1xSmLWhia6IibKjtW00qp2PJNo0qoyFEJa2wicj5SKvYw9vv9ic2BpNvSkccicwsH7ICu0Xz0m69eynXiaPq3bUOEKpt/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;fo
作者:微信小助手
<section data-role="outer" label="edit by 135editor"> <p style="text-align:center;"><img class="rich_pages wxw-img" data-ratio="1" src="/upload/08df4a90871b04c5e2d71e0fbf281f40.png" data-w="400" data-width="141px" style="vertical-align: inherit;width: 141px;" width="141"></p> <section data-role="paragraph"> <blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="36" data-source-title=""> <section class="js_blockquote_digest"> <p>加微信 “AmsNeil” 领取所有系列Markdown/PDF文档和源码<span style="font-size: 18px;font-weight: bold;color: black;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;letter-spacing: 2px;text-align: left;"></span></p> </section> </blockquote> </section> <section data-tools="135编辑器" data-id="125616" data-color="#0070c0"> <section> <section data-width="80%"> <section> <section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;word-break: break-word;text-align: left;line-height: 1.25;letter-spacing: 2px;background-image: linear-gradient(90deg, rgba(50, 0, 0, 0.05) 3%, rgba(0, 0, 0, 0) 3%), linear-gradient(360deg, rgba(50, 0, 0, 0.05) 3%, rgba(0, 0, 0, 0) 3%);background-size: 20px 20px;background-position: center center;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">Kubernetes(通常简称为K8s)是一个用于自动部署、扩展和管理容器化应用程序的开源容器编排平台。它提供了一种便捷的方式来管理容器,使得在一个集群中运行、调度和扩展应用程序变得更加简单。</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-size: 18px;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(145, 109, 213);">为什么使用k8s而不是直接使用Docker?</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">尽管Docker提供了优秀的容器化解决方案,但它主要专注于构建、打包和运行容器。Kubernetes在这个基础上提供了更高级的编排和管理功能,特别适用于复杂的微服务架构和大规模的容器化应用程序。</p> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin-top: 10px;margin-bottom: 10px;word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「自动化和编排:」</strong> Kubernetes提供了自动化和编排容器的能力,使得在生产环境中运行大规模、多组件的应用程序变得容易。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin-top: 10px;margin-bottom: 10px;word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「高可用性:」</strong> Kubernetes的设计目标之一是确保应用程序的高可用性,即使在节点故障或其他问题时,也能保持服务的可用性。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin-top: 10px;margin-bottom: 10px;word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「水平扩展:」</strong> Kubernetes支持水平扩展,能够根据负载自动调整应用程序的规模,以应对流量的变化。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin-top: 10px;margin-bottom: 10px;word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「服务发现和负载均衡:」</strong> Kubernetes提供了内置的服务发现机制和负载均衡,使得在应用程序组件之间进行通信更加容易。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin-top: 10px;margin-bottom: 10px;word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「滚动更新和回滚:」</strong> Kubernetes支持滚动更新,使得应用程序的升级变得更加平滑,同时也支持回滚到之前的版本。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin-top: 10px;margin-bottom: 10px;word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「资源管理:」</strong> Kubernetes允许对资源进行灵活的管理和调度,确保Pods获得适当的资源分配。</p> </section></li> </ol> <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-size: 18px;display: inline-block;padding-left: 10px;border-left: 5px solid rgb(145, 109, 213);">K8s基本概念</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">以下是Kubernetes的一些基本概念和入门介绍:</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;">1. <strong style="color: rgb(145, 109, 213);">「容器化技术基础」</strong></span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">Kubernetes主要用于管理和编排容器化应用程序。容器是一种轻量级、可移植的软件打包方式,其中包含应用程序及其所有依赖关系。Docker是一个流行的容器化工具,但K8s也支持其他容器运行时。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;">2. <strong style="color: rgb(145, 109, 213);">「Kubernetes的核心概念」</strong></span><span style="display: none;"></span></h3> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-imgfileid="100011228" data-ratio="0.48518518518518516" src="/upload/6d91dfa10730aa4a79358f0f5b0ece41.png" data-type="png" data-w="1080" style="border-radius: 6px;display: block;margin: 20px auto;object-fit: contain;box-shadow: rgb(153, 153, 153) 2px 4px 7px;"> </figure> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>2.1 <strong style="color: rgb(145, 109, 213);">「Pods(Pod)」</strong><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">Pod是Kubernetes中最小的可部署单元,它包含一个或多个相关的容器。这些容器共享网络命名空间和存储卷,它们通常协同工作来构成一个应用程序。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>2.2 <strong style="color: rgb(145, 109, 213);">「Service(服务)」</strong><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">Service定义了一组Pod的逻辑集合,并提供了一个访问这些Pod的稳定入口点。Service可以通过集群内部或外部的网络访问这些Pod。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>2.3 <strong style="color: rgb(145, 109, 213);">「Deployment(部署)」</strong><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">Deployment用于定义应用程序的期望状态,并确保实际运行的Pod副本数量与期望状态一致。Deployment还支持滚动更新和回滚操作,以便更新应用程序。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>2.4 <strong style="color: rgb(145, 109, 213);">「ConfigMap和Secret」</strong><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">ConfigMap用于将配置数据从应用程序中分离出来,而Secret则用于安全地存储敏感信息,如密码、API密钥等。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>2.4 <strong style="color: rgb(145, 109, 213);">「Ingress」</strong><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">Kubernetes Ingress(K8s Ingress)是一种用于管理和公开Kubernetes集群中服务的API对象。它允许外部流量进入集群,并提供路由规则来决定如何将该流量路由到不同的服务.</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;">3. <strong style="color: rgb(145, 109, 213);">「Kubernetes的工作原理」</strong></span><span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">Kubernetes集群由一组物理或虚拟机器组成,这些机器被称为节点。集群有一个主节点(Master)和多个工作节点(Node)。</p> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3.1 <strong style="color: rgb(145, 109, 213);">「主节点(Master)」</strong><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">主节点负责管理集群的整体状态和控制工作节点的操作。它包括以下组件:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;list-style-type: circle;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <strong style="color: rgb(145, 109, 213);">「API Server:」</strong> 提供了K8s API的入口,用于与Kubernetes进行交互。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <strong style="color: rgb(145, 109, 213);">「Controller Manager:」</strong> 负责监控系统状态,确保实际状态符合期望状态。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <strong style="color: rgb(145, 109, 213);">「Scheduler:」</strong> 负责将Pod调度到工作节点上运行。 </section></li> </ul> <h4 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 18px;"><span style="display: none;"></span>3.2 <strong style="color: rgb(145, 109, 213);">「工作节点(Node)」</strong><span style="display: none;"></span></h4> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">工作节点是集群中的计算资源,用于运行容器。每个工作节点包括以下组件:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;list-style-type: circle;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <strong style="color: rgb(145, 109, 213);">「Kubelet:」</strong> 负责与主节点通信,确保在节点上运行所需的Pod。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <strong style="color: rgb(145, 109, 213);">「Container Runtime:」</strong> 用于启动和管理容器的软件,如Docker。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <strong style="color: rgb(145, 109, 213);">「Kube Proxy:」</strong> 负责在节点上实现Service的网络代理。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;text-align: center;"><span style="display: none;"></span><span style="border-bottom: 2px solid #d89cf6;">4. <strong style="color: rgb(145, 109, 213);">「Kubernetes的使用流程」</strong></span><span style="display: none;"></span></h3> <ol data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;font-size: 15px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin-top: 10px;margin-bottom: 10px;word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「定义应用程序:」</strong> 使用K8s的YAML文件定义应用程序的组件,包括Pods、Services、Deployments等。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin-top: 10px;margin-bottom: 10px;word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「部署应用程序:」</strong> 使用kubectl工具或Kubernetes API将定义的应用程序组件部署到集群中。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin-top: 10px;margin-bottom: 10px;word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「Kubernetes控制器处理:」</strong> 控制器(如Deployment)会接收定义并确保集群状态与定义状态一致。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin-top: 10px;margin-bottom: 10px;word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「应用程序运行:」</strong> K8s会在工作节点上创建和调度Pods,确保应用程序正常运行。</p> </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);font-size: 14px;"> <p style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;color: black;margin-top: 10px;margin-bottom: 10px;word-spacing: 2px;"><strong style="color: rgb(145, 109, 213);">「监控和维护:」</strong> 使用K8s的监控工具来监测集群状态,进行日志管理和故障排除。</p> </section></li> </ol> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;margin-top: 10px;margin-bottom: 10px;font-size: 14px;word-spacing: 2px;">Kubernetes为应用程序提供了弹性、可伸缩性和高可用性的运行环境,使得应用程序在多个环境中更容易部署和管理。学习和掌握Kubernetes需要逐步深入,通过实践和使用各种资源来加深理解。</p> </section> <section class="mp_profile_iframe_wrp"> <span style="display: none;line-height: 0px;"></span> <mp-common-profile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-weui-theme="light" data-id="MzU2MzYwMDI0Ng==" data-headimg="http://mmbiz.qpic.cn/sz_mmbiz_png/L3TFosuayYqHqhI3kVX5yJNicB3gQYEUr07zpQuiajmfCYwlhM8lnDYeC9qqtBLiab2WmtQP0cbFqlKM6sZXp06ew/0?wx_fmt=png" data-nickname="乐哥聊编程" data-alias="lglbc2022" data-signature="专注编程分享,聊程序人生" data-from="0" data-is_biz_ban="0"></mp-common-profile> <span style="display: none;line-height: 0px;"></span> </section> </section> </section> </section> </section> </section> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>