作者:微信小助手
<p style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;" data-mpa-powered-by="yiban.io"><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;font-size: 12px;color: rgb(120, 114, 119);user-select: text !important;">点击上方 "</span><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;color: rgb(0, 0, 0);font-size: 12px;user-select: text !important;"><strong style="color: rgb(62, 62, 62);font-size: 14px;user-select: text !important;"><span style="letter-spacing: 0.544px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;color: rgb(61, 170, 214);user-select: text !important;">zhisheng</span></strong></span><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;font-size: 12px;color: rgb(120, 114, 119);user-select: text !important;">"关注, <span style="letter-spacing: 0.544px;user-select: text !important;">星标或置顶一起成长</span></span><span style="font-size: 14px;letter-spacing: 0.544px;color: rgb(255, 41, 65);line-height: 22.4px;"></span></p> <p style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);font-size: 15px;background-color: rgb(255, 255, 255);text-align: center;"><a target="_blank" href="https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1337172142412169216&__biz=MzIxMTE0ODU5NQ==#wechat_redirect" textvalue="Flink 从入门到精通" tab="innerlink" data-linktype="2" style="color: rgb(120, 172, 254);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;letter-spacing: 0.544px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 13px;line-height: 1.75em;user-select: text !important;"><span style="letter-spacing: 0.544px;line-height: 1.75em;user-select: text !important;">Flink 从入门到精通</span></a><span style="letter-spacing: 0.544px;color: rgb(136, 136, 136);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 13px;line-height: 1.75em;user-select: text !important;"> 系列文章</span></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5594280607685433" data-s="300,640" src="/upload/23ecce49369cbcfcaaefe5a4504e4be.png" data-type="png" data-w="2238" style=""><br></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5607142857142857" data-s="300,640" src="/upload/4a3e021a5b4fa2399f12ca05ecc9093b.png" data-type="png" data-w="2240" style=""></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5625" data-s="300,640" src="/upload/cd9360c9efba97a85f9751df170a98ae.png" data-type="png" data-w="2240" style=""></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5611061552185549" data-s="300,640" src="/upload/4b5c943517efd5734384200369724044.png" data-type="png" data-w="2242" style=""></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5594280607685433" data-s="300,640" src="/upload/feb9fe4e0457eea57553469ec87611e4.png" data-type="png" data-w="2238" style=""></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5596085409252669" data-s="300,640" src="/upload/9bdb209c58b80fd36e034b08d507b63e.png" data-type="png" data-w="2248" style=""></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5613249776186213" data-s="300,640" src="/upload/f7d065c67f0bdf6cf562c1dc371b34ea.png" data-type="png" data-w="2234" style=""></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5596412556053811" data-s="300,640" src="/upload/331837661c77690c705e9b431ec86918.png" data-type="png" data-w="2230" style=""></p> <p style="text-align: center;"><br></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5579514824797843" data-s="300,640" src="/upload/876cbf7a719079ea4c49155ad258a71c.png" data-type="png" data-w="2226" style=""></p> <p style="text-align: center;"><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5693693693693693" data-s="300,640" src="/upload/29efa45842d4caa131c1f3a0bf02e5ee.png" data-type="png" data-w="2220" style=""></p> <p style="text-align: center;"><br></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5575539568345323" data-s="300,640" src="/upload/11f2735d622fd6f585696a37e791abc.png" data-type="png" data-w="2224" style=""></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5526785714285715" data-s="300,640" src="/upload/1d3469725c5228de417d38f0f2fc12bd.png" data-type="png" data-w="2240" style=""></p> <p><br></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.5614973262032086" data-s="300,640" src="/upload/a64b2beefbdc08e7c5690ade6091f02d.png" data-type="png" data-w="2244" style=""></p> <p><br></p> <p>扫描下面二维码回复 <span style="color: rgb(255, 76, 65);"><strong>华为云 </strong></span><span style="color: rgb(0, 0, 0);">即可获得该 PPT</span></p> <p><span style="color: rgb(0, 0, 0);"><br></span></p> <p style="text-align: center;"><span style="color: rgb(0, 0, 0);"><img src="/upload/53b4d8abfa4fb5c6873ceb3a9021dc69.jpg" data-type="jpeg" data-ratio="1" data-w="200"></span></p>
作者:微信小助手
<p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.624390243902439" data-s="300,640" src="/upload/6c6f5987af8566bd4a3523e3f5e0f375.jpg" data-type="jpeg" data-w="1025"></p> <section powered-by="xiumi.us" style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;line-height: 27.2px;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section donone="shifuMouseDownCard('shifu_c_008')" label="Copyright Reserved by PLAYHUDONG." style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;letter-spacing: 0.612px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section donone="shifuMouseDownCard('shifu_c_008')" label="Copyright Reserved by PLAYHUDONG." style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section donone="shifuMouseDownCard('shifu_c_008')" label="Copyright Reserved by PLAYHUDONG." style="margin-right: 0em;margin-left: 0em;padding: 0.5em 1em;max-width: 100%;border-style: none;background-color: rgb(245, 245, 245);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;overflow-wrap: break-word !important;">阿里妹导读:</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;overflow-wrap: break-word !important;">针对业务在不同场景下的差异,我们常常会习惯性地使用if-else来实现不同的业务逻辑,久而久之代码越来越难以维护。那么如何消除这些if-else?面对复杂业务应如何思考和分析?本文分享阿里高级技术专家张建飞</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;overflow-wrap: break-word !important;">(Frank)关于复杂</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;overflow-wrap: break-word !important;">业务<span style="color: rgb(136, 136, 136);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 0.612px;background-color: rgb(245, 245, 245);">治理</span>的方法论,介绍一种多维度分析问题的方法:矩阵分析法。</span></p> <p style="max-width: 100%;min-height: 1em;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="max-width: 100%;min-height: 1em;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;overflow-wrap: break-word !important;">文末福利:</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;overflow-wrap: break-word !important;">《微服务灰度实践及解决方案》在线直</span><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 15px;letter-spacing: 0.612px;box-sizing: border-box !important;overflow-wrap: break-word !important;">播。</span></p> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <blockquote style="margin-top: 0px;margin-bottom: 16px;padding-top: 0px;padding-right: 1em;padding-left: 1em;border-left-width: 0.25em;border-left-color: rgb(223, 226, 229);color: rgba(0, 0, 0, 0.5);max-width: 100%;box-sizing: border-box;letter-spacing: 0.544px;white-space: normal;font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";text-align: start;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;"> <section style="max-width: 100%;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="font-size: 15px;color: rgb(153, 153, 153);">You should not be a if-else coder, should be a complexity conquer. </span> </section> <section style="max-width: 100%;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="font-size: 15px;color: rgb(153, 153, 153);">——Frank</span> </section> </blockquote> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">这篇文章,是对之前我在<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&mid=2247491068&idx=1&sn=2e724face6f7e1df5e81c377c84862a6&chksm=e92920f3de5ea9e574cdc9b183e837aab9eb032694d44f44c61b4637d8e477e0c0de831f7f51&scene=21#wechat_redirect" textvalue="《一文教会你如何写复杂业务代码》" data-itemshowtype="11" tab="innerlink" data-linktype="2">《阿里高级技术专家方法论:如何写复杂业务代码?》</a></span> <span style="color: rgb(62, 62, 62);font-size: 15px;">说的“自上而下的结构化分解 + 自下而上的抽象建模”方法论的升级。</span> <span style="color: rgb(62, 62, 62);font-size: 15px;">因为在之前的方法论中,我们缺少一个多维度看问题的视角,这种维度思维的缺失,可能会导致miss掉一些重要的业务信息,从而使我们制定软件设计策略的时候,陷入困难。</span> </section> <p style="line-height: 1.75em;"><br></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">有了维度思维,我们便可以更加方面的去看清业务的全貌,更加全面的掌握业务信息,从而帮助我们更加体系化的去治理复杂性。</span></p> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(255, 106, 0);">从if-else说起</span></strong> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">我经常说,我们不要做一个if-else coder。这里的if-else,不是说我们在coding的时候不能使用if-else,而是说我们不应该简陋地用if-else去实现业务的分支流程,因为这样随意的代码堆砌很容易堆出一座座“屎山”。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">业务的差异性是if-else的根源。以零售通的商品业务为例。不同的处理场景,其业务逻辑实现是有差异性的。如下图所示,商品业务的差异性,主要体现在商品类型、销售方式和仓储方式的不同。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;text-align: center;"> <img data-ratio="0.5762942779291553" src="/upload/4d3b14dc98fdc95a1711c322fd2ffe54.png" data-type="png" data-w="1468"> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">这三个维度上的差异组合起来,有 </span> <span style="font-size: 15px;background-color: rgb(245, 245, 245);color: rgb(102, 102, 102);">2 * 3 * 2 = 12</span> <span style="font-size: 15px;color: rgb(62, 62, 62);"> 之多。这就是为什么在老代码中,到处可以看到 </span> <span style="font-size: 15px;background-color: rgb(245, 245, 245);color: rgb(102, 102, 102);">if(组合品) blabla</span> <span style="font-size: 15px;color: rgb(62, 62, 62);">,</span> <span style="font-size: 15px;background-color: rgb(245, 245, 245);color: rgb(102, 102, 102);">if(赠品) blabla</span> <span style="font-size: 15px;color: rgb(62, 62, 62);">,</span> <span style="font-size: 15px;background-color: rgb(245, 245, 245);color: rgb(102, 102, 102);">if(实仓) blabla</span> <span style="font-size: 15px;color: rgb(62, 62, 62);"> 之类的代码。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">那么,要如何消除这些讨厌的if-else呢?我们可以考虑以下两种方式:</span> </section> <section style="line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">多态扩展:利用面向对象的多态特性,实现代码的复用和扩展。</span></p></li> </ul> <section style="line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">代码分离:对不同的场景,使用不同的流程代码实现。这样很清晰,但是可维护性不好。</span></p></li> </ul> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">多态扩展</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">多态扩展可以有继承和组合两种方式。继承勿用多言,组合有点像策略模式,也就是把需要扩展的部分封装、抽象成需要被组合的对象,然后对其进行扩展,比如星环的能力扩展点就是这种方式。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">这里,我们举一个继承的例子,商品在上架的时候要检查商品的状态是否可售,普通商品(Item)检查自己就好了,而组合商品(CombineItem)需要检查每一个子商品。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">用过程式编码的方式,很容易就能写出如下的代码:</span> </section> <pre> </pre> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">checkSellable</span>(<span class="code-snippet__params">Item item</span>)</span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (item.isNormal()){</span></code><code><span class="code-snippet_outer"> item.isSellable(); </span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//省略异常处理</span></span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">else</span>{</span></code><code><span class="code-snippet_outer"> List<Item> childItems = getChildItems();</span></code><code><span class="code-snippet_outer"> childItems.forEach(childItem -> childItem.isSellable()); </span></code><code><span class="code-snippet_outer"> <span class="code-snippet__comment">//省略异常处理</span></span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">然而,这个实现不优雅,不满足OCP,也缺少业务语义显性化的表达。更好的做法是,我们可以把CombineItem和Item的关系通过模型显性化的表达出来。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;text-align: center;"> <img data-ratio="0.9710144927536232" src="/upload/3922731e690f907de40943aa25a17c2.png" data-type="png" data-w="552" style="width: 262px;height: 255px;"> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">这样一来,一方面模型正确的反应了实体关系,更清晰了。另一方面,我们可以利用多态来处理CombineItem和Item的差异,扩展性更好。重构后,代码会变成:</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">checkSellable</span>(<span class="code-snippet__params">Item item</span>)</span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">if</span> (!item.isSellable()){</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">throw</span> <span class="code-snippet__keyword">new</span> BizException(<span class="code-snippet__string">"商品的状态不可售,不能上架"</span>);</span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <section style="line-height: 1.75em;"> <br> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">代码分离</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">所谓的代码分离是指,对于不同的业务场景,我们用不同的编排代码将他们分开。以商品上架为例,我们可以这样写:</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">* 1. 普通商品上架</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">*/</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">itemOnSale</span>(<span class="code-snippet__params"></span>)</span>{</span></code><code><span class="code-snippet_outer"> checkItemStock();<span class="code-snippet__comment">//检查库存</span></span></code><code><span class="code-snippet_outer"> checkItemSellable();<span class="code-snippet__comment">//检查可售状态</span></span></code><code><span class="code-snippet_outer"> checkItemPurchaseLimit();<span class="code-snippet__comment">//检查限购</span></span></code><code><span class="code-snippet_outer"> checkItemFreight();<span class="code-snippet__comment">//检查运费</span></span></code><code><span class="code-snippet_outer"> checkItemCommission();<span class="code-snippet__comment">//检查佣金</span></span></code><code><span class="code-snippet_outer"> checkItemActivityConflict();<span class="code-snippet__comment">//检查活动冲突</span></span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> generateCspuGroupNo();<span class="code-snippet__comment">//生成单品组号</span></span></code><code><span class="code-snippet_outer"> publishItem();<span class="code-snippet__comment">//发布商品</span></span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">* 2. 组合商品上架</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">*/</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">combineItemOnSale</span>(<span class="code-snippet__params"></span>)</span>{</span></code><code><span class="code-snippet_outer"> checkCombineItemStock();<span class="code-snippet__comment">//检查库存</span></span></code><code><span class="code-snippet_outer"> checkCombineItemSellable();<span class="code-snippet__comment">//检查可售状态</span></span></code><code><span class="code-snippet_outer"> checkCombineItemPurchaseLimit();<span class="code-snippet__comment">//检查限购</span></span></code><code><span class="code-snippet_outer"> checkCombineItemFreight();<span class="code-snippet__comment">//检查运费</span></span></code><code><span class="code-snippet_outer"> checkCombineItemCommission();<span class="code-snippet__comment">//检查佣金</span></span></code><code><span class="code-snippet_outer"> checkCombineItemActivityConflict();<span class="code-snippet__comment">//检查活动冲突</span></span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"> generateCspuGroupNo();<span class="code-snippet__comment">//生成单品组号</span></span></code><code><span class="code-snippet_outer"> publishCombineItem();<span class="code-snippet__comment">//发布商品</span></span></code><code><span class="code-snippet_outer">}</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">* 3. 赠品上架</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">*/</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">public</span> <span class="code-snippet__keyword">void</span> <span class="code-snippet__title">giftItemOnSale</span>(<span class="code-snippet__params"></span>)</span>{</span></code><code><span class="code-snippet_outer"> checkGiftItemSellable();<span class="code-snippet__comment">//检查可售状态</span></span></code><code><span class="code-snippet_outer"> publishGiftItem();<span class="code-snippet__comment">//发布商品</span></span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">这种方式,当然也可以消除if-else,彼此独立,也还清晰。但复用性是个问题。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">多维分析</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">细心的你可能已经发现了,在上面的案例中,普通商品和组合商品的业务流程基本是一样的。如果采用两套编排代码,有点冗余,这种重复将不利于后期代码的维护,会出现散弹式修改(一个业务逻辑要修改多处)的问题。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">一个极端情况是,假如普通商品和组合商品,只有 </span> <span style="font-size: 15px;background-color: rgb(245, 245, 245);color: rgb(102, 102, 102);">checkSellable()</span> <span style="font-size: 15px;color: rgb(62, 62, 62);"> 不一样,其它都一样。那毫无疑问,我们使用有多态(继承关系)的CombineItem和Item来处理差异,会更加合适。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">而赠品上架的情况恰恰相反,它和其他商品的上架流程差异很大。反而不适合和他们合用一套流程代码,因为这样反而会增加他人的理解成本。还不如单独起一个流程来的清晰。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">那么,问题来了,我们什么时候要用多态来处理差异,什么时候要用代码分离来处理差异呢?</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">接下来,是我今天要给你着重介绍的多维度分析问题的方法论之一:矩阵分析法。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">我们可以弄一个矩阵,纵列代表业务场景,横列代表业务动作,里面的内容代表在这个业务场景下的业务动作的详细业务流程。对于我们的商品业务,我们可以得到如下的矩阵:</span> </section> <section style="line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.703111858704794" data-s="300,640" src="/upload/c68b18511f1e5525ef3eb7d849345bb6.png" data-type="png" data-w="1189" style=""></p> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">通过上面的矩阵分析,我们不难看出普通品和组合品可以复用同一套流程编排代码,而赠品和出清品的业务相对简单,更适合有一套独立的编排代码,这样的代码结构会更容易理解。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(255, 106, 0);">维度思维</span></strong> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">多维度的重要性</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">上面的案例不是我编造出来的,而是我在和张文(我同事)讨论应该用哪种方式去处理业务差异的真实故事。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">我记得在和大学讨论完,开车回去的路上,我一直在想这个问题,然后在第二个路口等红灯的时候,突然有一个灵感冒出来。我抑制不住兴奋,一边开车,一边发消息给张文说:“我想到了一个很NB的方法论,能解决在‘多态扩展’和‘代码分离’之间如何做选择的问题”。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">其实,我知道我兴奋的不仅仅是解决了这个问题。我兴奋的是,我第一次真正领悟到了多维度思考的重要性。从而有机会从一个“单维度”生物,升级成一个“多维度”思考者。妈妈再也不用担心我被“降维打击”了 :)</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">结构化思维有用、很有用、非常有用,只是它更多关注的是单向维度的事情。比如我要拆解业务流程,我要分解老板给我的工作安排,我要梳理测试用例,都是单向维度的。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">而复杂性,通常不仅仅是一个维度上的复杂,而是在多个维度上的交叉复杂性。当问题涉及的要素比较多,彼此关联关系很复杂的时候,两个维度肯定会比一个维度要来的清晰,这也是为什么说矩阵思维是比结构化思维更高层次的思维方式。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">实际上,我们从汉语的词汇上,也不难看出一个人的思维层级,是和他的思考维度正相关的。当我们说这个人很“轴”、“一根筋”的时候,实际上是在说他只有一维的线性思维。所以,观察事物的视角越多,维度越丰富,其思维层级也会越高。</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.42254663422546634" data-s="300,640" src="/upload/977496a80537b4ed603914698ae199f2.png" data-type="png" data-w="1233" style="width: 262px;height: 111px;"></p> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">无处不在的多维思考</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">有了这些感悟,我开始系统的整理关于多维度思考分析的资料,发现这种思考方式真是无处不在。发现的越多,我越是感慨,为什么如此重要的思维方式,我到现在才领悟到。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">波士顿矩阵</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">比如,在做产品分析的时候,有对产品发展前景进行分析的波士顿矩阵。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><img data-ratio="0.718381112984823" src="/upload/295f6179f7b63b3eba10422fa53f4265.png" data-type="png" data-w="593" style="width: 291px;height: 209px;"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">订单要素分析</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">当年,我在1688做交易下单业务的时候,有非常多的下单场景,每种场景下,买家享受的权益是不一样的(如下表所示)。我们当时也是使用了矩阵去表达这个复杂的关系,只是当时还没有想到要将其提升到方法论的高度。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.43156199677938806" data-s="300,640" src="/upload/593beca3b33afa2f67db9e37727da5f7.png" data-type="png" data-w="1242" style=""></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">数据交叉分析</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">在数据分析中,维度分析是非常重要的,特别是维度很多的时候,我们可以通过皮尔逊积矩相关系数,做交叉分析,从而弥补独立维度分析没法发现的一些问题。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><img src="/upload/216b618af17173ad226c9e4ecc375cbf.png" data-cropx1="0" data-cropx2="1080" data-cropy1="134.53287197231833" data-cropy2="741.7993079584775" data-ratio="0.562962962962963" src="https://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naIiaUUcIfut5VxcZuP5LUvOWqz4EXPO6xKicN7VBY1XfhriccZXibtNUAswL3KbgX4U5ibOJERtfQ87fwg/640?wx_fmt=jpeg" data-type="jpeg" data-w="1080" style="width: 578px;height: 325px;"></span> </section> <section style="line-height: 1.75em;text-align: center;"> <span style="color: rgb(153, 153, 153);font-size: 14px;">简单相关系数矩阵</span> <br> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">分析矩阵</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">最近我碰巧看到Alan Shalloway写的《设计模式解析:Design Patterns Explained》,这是一本非常经典的关于OOP的书,里面的第十六章就是专门讲“分析矩阵”的,作者创造这个方法论的初衷也是因为业务涉及的要素太多,信息量太大,他需要一种组织海量数据的新方式。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><img data-ratio="0.5381062355658198" src="/upload/61ada8542041503e62cef952c68db7da.png" data-type="png" data-w="866"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">我和Alan的路径不一样,但是都得出了同样的结论。由此可见,这种矩阵分析的方式的确是对复杂业务进行分析的一把利器,业务场景越多,交叉关系越是复杂,越需要这样的分析。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(62, 62, 62);">组织阵型</span></strong> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">生产关系决定生产力,对于一个管理者来说,如何有效的设置组织结构是决定团队是否能高效协作的关键。所以我们可以看到公司里面,每年都有比较大的关于组织结构和人员安排的调整。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">对于技术团队来说,我们习惯于按领域划分工作范围,这样做的好处是责任到人、职责清晰。然而,领域只是一个维度,我们工作通常都是以项目的形式的开展,而项目通常是贯穿多个领域的。所以,在做团队组织规划的时候,我们可以通过业务领域和业务项目两个维度去看。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">比如,在我负责的商品团队,我会按照如下的形式去做职责划分。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><img data-ratio="0.4026104417670683" src="/upload/ca17fb27fdaba50973780c8b34cbe5d3.png" data-type="png" data-w="1992"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(62, 62, 62);">时间维度</span></strong><span style="font-size: 15px;color: rgb(62, 62, 62);"></span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">除了工作,生活中也到处可见多维思考的重要性。</span></p> <p style="line-height: 1.75em;"><br></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">比如,我们说浪费可耻,应该把盘子舔的很干净,岂不知加上时间维度之后,你当前的舔盘,后面可能要耗费更多的资源和精力去减肥,反而会造成更大的浪费。</span></p> <p style="line-height: 1.75em;"><br></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">我们说代码写的丑陋,是因为要“快速”支撑业务,加上时间维度之后,这种临时的妥协,换来的是意想不到的bug,线上故障,以及无止尽的996。</span></p> <p style="line-height: 1.75em;"><br></p> <p style="line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(62, 62, 62);">RFM模型</span></strong><span style="font-size: 15px;color: rgb(62, 62, 62);"></span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span></p> <p style="line-height: 1.75em;"><span style="font-size: 15px;color: rgb(62, 62, 62);">简单的思考是“点”状的,比如舔盘、代码堆砌就是当下的“点”;好一点的思考是“线”状,加上时间线之后,不难看出“点”是有问题的;再全面一些的思考是“面”(二维);更体系化的思考是“体”(三维);比如,RFM模型就是一个很不错的三维模型。可惜的是,在表达上,我们人类只能在二维的空间里去模拟三维,否则四维可能会更加有用。</span></p> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><img data-ratio="0.6353754940711462" src="/upload/884a1db1013dc13eb361b16d6bc0d6ca.png" data-type="png" data-w="1012"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="color: rgb(255, 106, 0);"><strong><span style="color: rgb(255, 106, 0);font-size: 15px;">复杂业务治理总结</span></strong></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">在前言部分,我已经说过了,多维分析是对之前方法论的升级。加上以前的方法论,完整的方法论应该是“业务理解-->领域建模-->流程分解-->多维分析”。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">为了方便大家理解,下面我把这些方法论做一个简单的串联和解释。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">业务理解</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">理解业务是所有工作的起点。首先,我们要找到业务的核心要素,理解核心概念,梳理业务流程。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">比如,在零售通的商品域,我们要知道什么是商品(Item),什么是单品(CSPU),什么是组合品(CombineItem)。在下单域,我们要知道订单(order)的构成要素是商品、优惠、支付。在CRM领域,我们要理解客户、机会、联系人、Leads等等。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">这里,我想再次强调下语言的重要性,语言是我们思考的载体,就像维特根斯坦说的:“凡是能够说的事情,都能够说清楚”。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">你不应该放过任何一个模糊的业务概念,一定要透彻的理解它,并给与合理的命名(Ubiquitous Language)。唯有如此,我们才能更加清晰的理解业务,才能更好的开展后续的工作。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">领域建模</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">在软件设计中,模型是指实体,以及实体之间的联系,这里需要我们具备良好的抽象能力。能够透过庞杂的表象,找到事务的本质核心。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">再复杂的业务领域,其核心概念都不应该太复杂,抓住了核心,我们就抓住了主线,业务往往都是围绕着这些核心实体展开的。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">比如,商品域虽然很复杂,但其核心的领域模型,无外乎就如下图所示:</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><img data-ratio="1.0170212765957447" src="/upload/1c1728e1f8bc5b1daddbf0cd6e2404e5.png" data-type="png" data-w="940" style="width: 367px;height: 373px;"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">流程分解</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">关于流程分解,在<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzIzOTU0NTQ0MA==&mid=2247491068&idx=1&sn=2e724face6f7e1df5e81c377c84862a6&chksm=e92920f3de5ea9e574cdc9b183e837aab9eb032694d44f44c61b4637d8e477e0c0de831f7f51&scene=21#wechat_redirect" textvalue="《一文教会你如何写复杂业务代码》" data-itemshowtype="11" tab="innerlink" data-linktype="2">《阿里高级技术专家方法论:如何写复杂业务代码?》</a>里面已经有非常详细的阐述,这里就不赘述了。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">简单来说,流程分解就是对业务过程进行详细的分解,使用结构化的方法论(先演绎、后归纳),最后形成一个金字塔结构。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">比如,在商品领域,有创建商品、商品上架、上架审核、商品下架、下架审核、修改商品、删除商品等一些列动作(流程),每个动作的背后都有非常复杂的业务逻辑。我们需要对这些流程进行详细的梳理,然后按步骤进行分解。最后形成一个如下的金字塔结构:</span> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><br></span> </section> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><img src="/upload/d3a81b86be6c615c9085b721461ac458.png" data-cropx1="0" data-cropx2="956.5155709342561" data-cropy1="0" data-cropy2="463.8166089965398" data-ratio="0.48430962343096234" src="https://mmbiz.qpic.cn/mmbiz_jpg/Z6bicxIx5naIiaUUcIfut5VxcZuP5LUvOWSTtwYMmqy6VFPNtFkuDAFO9Sdiar1ugFrgaIWAIc9rCI6DaxEqfUSPA/640?wx_fmt=jpeg" data-type="jpeg" data-w="956" style="width: 563px;height: 273px;"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(255, 106, 0);">多维分析</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">关于多维分析,我以二维的矩阵分析为例,我想我前面应该已经说清楚了。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">业务的复杂性主要体现在流程的复杂性和多维度要素相互关联、依赖关系上,结构化思维可以帮我们梳理流程,而矩阵思维可以帮忙我们梳理、呈现多维度关联、依赖关系。二者结合,可以更加全面的展现复杂业务的全貌。从而让我们的治理可以有的放矢、有章可循。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">既然是方法论,在这里,我会尝试给出一个矩阵分析的框架。试想下,如果我们的业务很简单,只有一个业务场景,没有分支流程。我们的系统不会太复杂。之所以复杂,是因为各种业务场景互相叠加、依赖、影响。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">因此,我们在做矩阵分析的时候,纵轴可以选择使用业务场景,横轴是备选维度,可以是受场景影响的业务流程(如文章中的商品流程矩阵图),也可以是受场景影响的业务属性(如文章中的订单组成要素矩阵图),或者任何其它不同性质的“东西”。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;text-align: center;"> <img data-ratio="0.5625920471281296" src="/upload/5420fd14a62dbbf24159f9b55df29aaf.png" data-type="png" data-w="1358"> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">通过矩阵图,可以清晰的展现不同场景下,业务的差异性。基于此,我们可以定制满足差异性的最佳实现策略,可能是多态扩展,可能是分离的代码,也可能是其它。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">这就是矩阵分析的要义,其本质是一种多维度思考的方法论。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <strong><span style="font-size: 15px;color: rgb(255, 106, 0);">篇后寄语</span></strong> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">最后,我想说世界是熵增的(即万物都在缓慢的分崩离析),控制复杂度是我们这些从业者无法推卸的责任和使命。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">软件行业的发展才几十年,还是一门年轻的学科,软件工程就像一个刚学会走路的小孩,还很不成熟,有时还很幼稚。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">但毕竟还是有几十年的沉淀,还是有一些好的方法和实践可以参考,我的这些总结沉淀只是在前人的基础上,多走了一点点而已。但就是这一点点,也实属来自不易,其中冷暖,只有自己能体会。可以说,这一路走来,是一场对心力、脑力和体力的持续考验。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;text-align: center;"> <span style="font-size: 15px;color: rgb(62, 62, 62);"><img data-ratio="0.6523125996810207" src="/upload/db3312431b7bf00b9eaca60498224d95.png" data-type="png" data-w="1254"></span> </section> <section style="line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">心力是指不将就的匠心,不妥协的决心,不满足的好奇心、以及不放弃的恒心。</span></p></li> </ul> <section style="line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">脑力是指那些必要的思维能力、学习能力、思考能力、思辨能力。</span></p></li> </ul> <section style="line-height: 1.75em;"> <br> </section> <ul class="list-paddingleft-2" style="list-style-type: disc;"> <li><p><span style="font-size: 15px;color: rgb(62, 62, 62);">之所以说“业务理解-->领域建模-->流程分解-->多维分析”是体力,是因为实现它们就像是在做填空题,只要你愿意花时间,再复杂的业务都可以按部就班的清晰起来。</span></p></li> </ul> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">梳理清晰了,再配合COLA(https://start.aliyun.com/)的指导,我们就有可能写出清晰、易读的代码,就有可能从一个if-else coder升级为一个complexity conquer。</span> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="line-height: 1.75em;"> <span style="font-size: 15px;color: rgb(62, 62, 62);">而这不正是我们工程师孜孜不倦的追求吗?</span> </section> <section style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;color: rgb(62, 62, 62);box-sizing: border-box !important;overflow-wrap: break-word !important;"> </span> </section> <hr style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);border-style: solid;border-right-width: 0px;border-bottom-width: 0px;border-left-width: 0px;border-color: rgba(0, 0, 0, 0.1);transform-origin: 0px 0px;transform: scale(1, 0.5);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <strong style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(255, 104, 39);font-size: 14px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">在线直播</span></strong> </section> <section style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;color: rgb(255, 104, 39);font-size: 14px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(255, 104, 39);font-size: 14px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">微服务灰度实践及解决方案</span></span> <strong style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(255, 104, 39);font-size: 14px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(255, 104, 39);font-size: 14px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"></span></span></strong> </section> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;letter-spacing: 0.54px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;letter-spacing: 0.54px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(17, 31, 44);font-family: "Microsoft YaHei", "Segoe UI", system-ui, Roboto, "Droid Sans", "Helvetica Neue", sans-serif, Tahoma, "Segoe UI SymbolMyanmar Text", 微软雅黑;font-size: 14px;letter-spacing: 1.5px;white-space: pre-wrap;box-sizing: border-box !important;overflow-wrap: break-word !important;">企业在微服务化转型的过程中面临着一系列问题,如服务拆分、服务治理、devops等。单体应用在微服务改造后,会面临服务数量增多、调用链路变长等问题,用户需要进行灰度发布以控制风险。本次直播结合当前主流微服务框架,深入剖析阿里云在灰度发布侧的最佳实践和解决方案。</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;letter-spacing: 0.54px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;white-space: normal;background-color: rgb(255, 255, 255);text-align: left;letter-spacing: 0.54px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(17, 31, 44);font-family: "Microsoft YaHei", "Segoe UI", system-ui, Roboto, "Droid Sans", "Helvetica Neue", sans-serif, Tahoma, "Segoe UI SymbolMyanmar Text", 微软雅黑;white-space: pre-wrap;font-size: 14px;letter-spacing: 1.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;">点击“阅读原文”,去预约<span style="max-width: 100%;color: rgb(55, 61, 65);font-family: PingFangSC, "helvetica neue", "hiragino sans gb", arial, "microsoft yahei ui", "microsoft yahei", simsun, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;">观看</span></span><span style="max-width: 100%;color: rgb(17, 31, 44);font-family: "Microsoft YaHei", "Segoe UI", system-ui, Roboto, "Droid Sans", "Helvetica Neue", sans-serif, Tahoma, "Segoe UI SymbolMyanmar Text", 微软雅黑;white-space: pre-wrap;font-size: 14px;letter-spacing: 1.5px;box-sizing: border-box !important;overflow-wrap: break-word !important;">吧~</span></p> <section style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> <section style="max-width: 100%;white-space: normal;background-color: rgb(255, 255, 255);text-align: center;color: rgb(53, 53, 53);line-height: 1.75em;letter-spacing: 0.54px;font-family: "Helvetica Neue", "Hiragino Sans GB", "Microsoft YaHei", 黑体, Arial, sans-serif;font-size: 14px;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="1" data-type="jpeg" data-w="430" data-s="300,640" data-copyright="0" data-cropsely2="182" data-cropsely1="0" data-cropselx2="180" data-cropselx1="0" src="/upload/7de99e1a0d789cef8820d7628d4ad41b.jpg" style="background-color: rgb(238, 237, 235);border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);background-size: 22px;background-position: 50% 50%;background-repeat: no-repeat;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 182px !important;"> </section> <section style="margin-bottom: 0.1px;max-width: 100%;text-indent: 0em;background-color: rgb(255, 255, 255);white-space: pre-wrap;text-align: center;color: rgb(53, 53, 53);line-height: 1.75em;letter-spacing: 0.54px;font-family: monospace;font-size: 11.9px;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 宋体;color: rgb(136, 136, 136);box-sizing: border-box !important;overflow-wrap: break-word !important;">关注</span><span style="max-width: 100%;font-family: 宋体;color: rgb(255, 76, 65);box-sizing: border-box !important;overflow-wrap: break-word !important;">「阿里技术」</span></span></strong><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></strong></span> </section> <section style="margin-bottom: 0.1px;max-width: 100%;text-indent: 0em;background-color: rgb(255, 255, 255);white-space: pre-wrap;text-align: center;color: rgb(53, 53, 53);line-height: 1.75em;letter-spacing: 0.54px;font-family: monospace;font-size: 11.9px;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-size: 15px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: 宋体;color: rgb(136, 136, 136);box-sizing: border-box !important;overflow-wrap: break-word !important;">把握前沿技术脉搏</span></strong></span> </section> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <section style="max-width: 100%;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;text-align: left;width: 30px;color: rgb(62, 62, 62);letter-spacing: 0.54px;font-size: 15px;display: inline-block;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img class="__bg_gif" data-ratio="1" data-type="gif" data-w="400" src="/upload/d94385547ddd1e4f466f4de3618da7f9.png" style="display: inline-block;vertical-align: middle;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 400px !important;"> </section> <section data-brushtype="text" style="margin-left: 5px;max-width: 100%;text-align: left;color: rgb(62, 62, 62);letter-spacing: 0.54px;font-size: 12px;vertical-align: middle;display: inline-block;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span style="max-width: 100%;font-family: "Microsoft YaHei", "Segoe UI", system-ui, Roboto, "Droid Sans", "Helvetica Neue", sans-serif, Tahoma, "Segoe UI SymbolMyanmar Text", 微软雅黑;letter-spacing: 0.544px;white-space: pre-wrap;box-sizing: border-box !important;overflow-wrap: break-word !important;">戳我,去预约。</span> </section> </section>
作者:微信小助手
<p style="white-space: normal;text-align: center;"><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;">(给</span><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;max-width: 100%;line-height: 22.4px;color: rgb(0, 128, 255);">ImportNew</span><span style="font-size: 14px;letter-spacing: 0.5440000295639038px;max-width: 100%;color: rgb(255, 41, 65);line-height: 22.4px;">加星标,提高Java技能)</span></p> <blockquote style="white-space: normal;"> <p style="letter-spacing: 0.5440000295639038px;background-color: rgb(255, 255, 255);max-width: 100%;min-height: 1em;text-align: left;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">作者</span><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">:</span><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">Java旅途</span><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">/ 周明尧</span><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">(本文来自作者投稿)</span></p> </blockquote> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__1" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">今天给大家安利一款接口文档生成器——JApiDocs。</span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__1" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__2" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">Swagger 想必大家都用过吧,非常方便,功能也十分强大。如果非要说Swagger 有什么缺点,想必就是注解写起来比较麻烦。如果我说有一款不用写注解,就可以生成文档的工具,你心动了吗?他就是我们今天的主角——JApiDocs。</span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__2" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__3" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">下面我们一起来看看如何使用!</span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__3" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></span></p> <h2 data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" data-darkmode-bgimage-160098705222010="1" class="js_darkmode__bg__0 js_darkmode__4" data-style="font-weight: bold; color: black; font-size: 22px; text-align: center; background-image: url("https://mmbiz.qpic.cn/mmbiz_png/lgiaG5BicLkVd67fYzzWFpaMC0p9soETgiacMtnsX2GvXCA6qj3dTxqH5Vf4yicRTniaysTiaUXq9qLXGTO1liajTEMTQ/640?wx_fmt=png"); background-size: 50px; margin-top: 1em; margin-bottom: 10px; background-position: center center; background-repeat: no-repeat no-repeat;" style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;white-space: normal;max-width: 100%;min-height: 1em;color: rgb(64, 64, 64);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.008em;text-align: left;background-color: rgb(255, 255, 255);line-height: 1.74;outline-style: none;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="color: rgb(171, 25, 66);">1. 添加依赖</strong></h2> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><br></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="xml"><code><span class="code-snippet_outer"><span class="code-snippet__tag"><<span class="code-snippet__name">dependency</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">groupId</span>></span>io.github.yedaxia<span class="code-snippet__tag"></<span class="code-snippet__name">groupId</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">artifactId</span>></span>japidocs<span class="code-snippet__tag"></<span class="code-snippet__name">artifactId</span>></span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__tag"><<span class="code-snippet__name">version</span>></span>1.3<span class="code-snippet__tag"></<span class="code-snippet__name">version</span>></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__tag"></<span class="code-snippet__name">dependency</span>></span></span></code></pre> </section> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></span></p> <h2 data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" data-darkmode-bgimage-160098705222010="1" class="js_darkmode__bg__2 js_darkmode__7" data-style="font-weight: bold; color: black; font-size: 22px; text-align: center; background-image: url("https://mmbiz.qpic.cn/mmbiz_png/lgiaG5BicLkVd67fYzzWFpaMC0p9soETgiacMtnsX2GvXCA6qj3dTxqH5Vf4yicRTniaysTiaUXq9qLXGTO1liajTEMTQ/640?wx_fmt=png"); background-size: 50px; margin-top: 1em; margin-bottom: 10px; background-position: center center; background-repeat: no-repeat no-repeat;" style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;white-space: normal;max-width: 100%;min-height: 1em;color: rgb(64, 64, 64);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.008em;text-align: left;background-color: rgb(255, 255, 255);line-height: 1.74;outline-style: none;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="color: rgb(171, 25, 66);">2. 配置生成参数</strong></h2> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"></span><br></p> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">我们新建一个项目,然后随便写一个 main 方法,增加生成文档的配置,然后运行 main 方法。</span></p> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></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="javascript"><code><span class="code-snippet_outer">DocsConfig config = <span class="code-snippet__keyword">new</span> DocsConfig();</span></code><code><span class="code-snippet_outer">config.setProjectPath(<span class="code-snippet__string">"F:\\Java旅途\\japi-docs"</span>); <span class="code-snippet__comment">// 项目根目录</span></span></code><code><span class="code-snippet_outer">config.setProjectName(<span class="code-snippet__string">"japi-docs"</span>); <span class="code-snippet__comment">// 项目名称</span></span></code><code><span class="code-snippet_outer">config.setApiVersion(<span class="code-snippet__string">"V1.0"</span>); <span class="code-snippet__comment">// 声明该API的版本</span></span></code><code><span class="code-snippet_outer">config.setDocsPath(<span class="code-snippet__string">"F:\\test"</span>); <span class="code-snippet__comment">// 生成API 文档所在目录</span></span></code><code><span class="code-snippet_outer">config.setAutoGenerate(<span class="code-snippet__built_in">Boolean</span>.TRUE); <span class="code-snippet__comment">// 配置自动生成</span></span></code><code><span class="code-snippet_outer">Docs.buildHtmlDocs(config); <span class="code-snippet__comment">// 执行生成文档</span></span></code></pre> </section> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"></span><br></p> <h2 data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" data-darkmode-bgimage-160098705222010="1" class="js_darkmode__bg__4 js_darkmode__17" data-style="font-weight: bold; color: black; font-size: 22px; text-align: center; background-image: url("https://mmbiz.qpic.cn/mmbiz_png/lgiaG5BicLkVd67fYzzWFpaMC0p9soETgiacMtnsX2GvXCA6qj3dTxqH5Vf4yicRTniaysTiaUXq9qLXGTO1liajTEMTQ/640?wx_fmt=png"); background-size: 50px; margin-top: 1em; margin-bottom: 10px; background-position: center center; background-repeat: no-repeat no-repeat;" style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;white-space: normal;max-width: 100%;min-height: 1em;color: rgb(64, 64, 64);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.008em;text-align: left;background-color: rgb(255, 255, 255);line-height: 1.74;outline-style: none;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="color: rgb(171, 25, 66);">3. 编码规范</strong></h2> <p><span style="font-size: 15px;"><br></span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__18" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">由于 JApiDocs 是通过解析 Java 源码来实现的,因此如果要想实现想要的文档,还是需要遵循一定的规范。</span></p> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></span></p> <h3 data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(0,0,0)" data-style="margin-bottom: 15px; font-weight: bold; color: black; font-size: 20px; margin-top: 1.2em;" class="js_darkmode__19" style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;white-space: normal;max-width: 100%;min-height: 1em;color: rgb(64, 64, 64);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.008em;text-align: left;background-color: rgb(255, 255, 255);line-height: 1.74;outline-style: none;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="color: rgb(171, 25, 66);">3.1 类注释、方法注释和属性注释</strong></h3> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__21" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><br></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__21" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">如果想生成类的注释,可以直接在类上加注释,也可以通过加 @Description 来生成。</span></p> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><br></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="kotlin"><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * 用户接口类</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> */</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__meta">@RequestMapping(<span class="code-snippet__meta-string">"/api/user"</span>)</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__meta">@RestController</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">UserController</span> </span>{}</span></code><code><span class="code-snippet_outer"><br></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@author</span> Java旅途</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@Description</span> 用户接口类</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@Date</span> 2020-06-15 21:46</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> */</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__meta">@RequestMapping(<span class="code-snippet__meta-string">"/api/user"</span>)</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__meta">@RestController</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">UserController</span> </span>{}</span></code></pre> </section> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></span></p> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">如果我们想生成方法的注释,只能直接加注释,不能通过加 @Description 来生成。</span></p> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></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="java"><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * 查询用户</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@param</span> age 年龄</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@return</span> R<User></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">*/</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__meta">@GetMapping</span>(<span class="code-snippet__string">"/list"</span>)</span></code><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">public</span> R<User> <span class="code-snippet__title">list</span><span class="code-snippet__params">(@RequestParam <span class="code-snippet__keyword">int</span> age)</span></span>{</span></code><code><span class="code-snippet_outer"> User user = <span class="code-snippet__keyword">new</span> User(<span class="code-snippet__string">"Java旅途"</span>, <span class="code-snippet__number">18</span>);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> R.ok(user);</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"></span><br></p> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">JApiDocs 可以自动生成实体类。关于实体类属性的注释有三种方式,生成的效果都是一样的,像下面这样:</span></p> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></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="cs"><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * 用户名称</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> */</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">private</span> String name;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * 用户年龄</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> */</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">int</span> age;</span></code></pre> </section> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"></span><br></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="cs"><code><span class="code-snippet_outer"><span class="code-snippet__comment">// 用户名称</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">private</span> String name;</span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment">// 用户年龄</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">int</span> age;</span></code></pre> </section> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></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="cs"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">private</span> String name;<span class="code-snippet__comment">// 用户名称</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">int</span> age;<span class="code-snippet__comment">// 用户年龄</span></span></code></pre> </section> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"></span><br></p> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">除了支持常用的 model 外,还支持 iOS 的 model 生成效果,像下面这样:</span></p> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.65406162464986" data-s="300,640" src="/upload/bec64172c17304e9566919561e7a10cd.png" data-type="png" data-w="714" style=""></p> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"></span><br></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.438375350140056" data-s="300,640" src="/upload/f07bf68d35e9a30536579a1e2cdd45b6.png" data-type="png" data-w="714" style=""></p> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></span></p> <h3 data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(0,0,0)" data-style="margin-bottom: 15px; font-weight: bold; color: black; font-size: 20px; margin-top: 1.2em;" class="js_darkmode__45" style="padding-top: 8px;padding-bottom: 8px;font-size: 15px;white-space: normal;max-width: 100%;min-height: 1em;color: rgb(64, 64, 64);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.008em;text-align: left;background-color: rgb(255, 255, 255);line-height: 1.74;outline-style: none;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="color: rgb(171, 25, 66);">3.2 请求参数</strong></h3> <p><span style="font-size: 15px;"><br></span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__47" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">如果提交的表单是 application/x-www-form-urlencoded 类型的key/value格式,则通过@param注解来获取参数,在参数后面添加注释,示例如下:</span></p> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><br></p> <section class="code-snippet__fix code-snippet__js"> <ul class="code-snippet__line-index code-snippet__js"> </ul> <pre class="code-snippet__js" data-lang="java"><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@param</span> age 年龄</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> */</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__meta">@GetMapping</span>(<span class="code-snippet__string">"/list"</span>)</span></code><code><span class="code-snippet_outer"><span class="code-snippet__function"><span class="code-snippet__keyword">public</span> R<User> <span class="code-snippet__title">list</span><span class="code-snippet__params">(@RequestParam <span class="code-snippet__keyword">int</span> age)</span></span>{</span></code><code><span class="code-snippet_outer"> User user = <span class="code-snippet__keyword">new</span> User(<span class="code-snippet__string">"Java旅途"</span>, <span class="code-snippet__number">18</span>);</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> R.ok(user);</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"></span><br></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__53" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">生成的文档效果如下:</span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__53" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__54" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">请求参数</span></p> <section data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <table data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" width="657" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <thead data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <tr data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" data-darkmode-bgcolor-160098705222010="rgb(25, 25, 25)" data-darkmode-original-bgcolor-160098705222010="rgb(255,255,255)" data-style="border-width: 1px 0px 0px; border-top-style: solid; border-top-color: rgb(204, 204, 204); background-color: white;" class="js_darkmode__55" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <th data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" data-darkmode-bgcolor-160098705222010="rgb(40, 40, 40)" data-darkmode-original-bgcolor-160098705222010="rgb(240, 240, 240)" data-style="border-top-width: 1px; border-color: rgb(204, 204, 204); text-align: left; background-color: rgb(240, 240, 240); font-size: 14px; min-width: 85px;" class="js_darkmode__56" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">参数名</span></th> <th data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" data-darkmode-bgcolor-160098705222010="rgb(40, 40, 40)" data-darkmode-original-bgcolor-160098705222010="rgb(240, 240, 240)" data-style="border-top-width: 1px; border-color: rgb(204, 204, 204); text-align: left; background-color: rgb(240, 240, 240); font-size: 14px; min-width: 85px;" class="js_darkmode__57" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">类型</span></th> <th data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" data-darkmode-bgcolor-160098705222010="rgb(40, 40, 40)" data-darkmode-original-bgcolor-160098705222010="rgb(240, 240, 240)" data-style="border-top-width: 1px; border-color: rgb(204, 204, 204); text-align: left; background-color: rgb(240, 240, 240); font-size: 14px; min-width: 85px;" class="js_darkmode__58" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">必须</span></th> <th data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" data-darkmode-bgcolor-160098705222010="rgb(40, 40, 40)" data-darkmode-original-bgcolor-160098705222010="rgb(240, 240, 240)" data-style="border-top-width: 1px; border-color: rgb(204, 204, 204); text-align: left; background-color: rgb(240, 240, 240); font-size: 14px; min-width: 85px;" class="js_darkmode__59" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">描述</span></th> </tr> </thead> <tbody data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <tr data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" data-darkmode-bgcolor-160098705222010="rgb(25, 25, 25)" data-darkmode-original-bgcolor-160098705222010="rgb(255,255,255)" data-style="border-width: 1px 0px 0px; border-top-style: solid; border-top-color: rgb(204, 204, 204); background-color: white;" class="js_darkmode__60" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <td data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" data-darkmode-bgcolor-160098705222010="rgb(25, 25, 25)" data-darkmode-original-bgcolor-160098705222010="rgb(255,255,255)" data-style="border-color: rgb(204, 204, 204); font-size: 14px; min-width: 85px;" class="js_darkmode__61" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">age</span></td> <td data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" data-darkmode-bgcolor-160098705222010="rgb(25, 25, 25)" data-darkmode-original-bgcolor-160098705222010="rgb(255,255,255)" data-style="border-color: rgb(204, 204, 204); font-size: 14px; min-width: 85px;" class="js_darkmode__62" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">int</span></td> <td data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" data-darkmode-bgcolor-160098705222010="rgb(25, 25, 25)" data-darkmode-original-bgcolor-160098705222010="rgb(255,255,255)" data-style="border-color: rgb(204, 204, 204); font-size: 14px; min-width: 85px;" class="js_darkmode__63" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">否</span></td> <td data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" data-darkmode-bgcolor-160098705222010="rgb(25, 25, 25)" data-darkmode-original-bgcolor-160098705222010="rgb(255,255,255)" data-style="border-color: rgb(204, 204, 204); font-size: 14px; min-width: 85px;" class="js_darkmode__64" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">年龄</span></td> </tr> </tbody> </table> </section> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__65" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><br></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__65" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">如果提交的表单是 application/json 类型的 JSON 数据格式,像下面这样:</span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__65" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></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="kotlin"><code><span class="code-snippet_outer"><span class="code-snippet__comment">/**</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@param</span> user</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> * <span class="code-snippet__doctag">@return</span></span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__comment"> */</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__meta">@PostMapping(<span class="code-snippet__meta-string">"/add"</span>)</span></span></code><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> R<User> add(<span class="code-snippet__meta">@RequestBody</span> User user){</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">return</span> R.ok(user);</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__65" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"></span><br></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__71" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">生成的文档效果如下:</span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__71" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__72" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">请求参数</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="json"><code><span class="code-snippet_outer">{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">"name"</span>: <span class="code-snippet__string">"string //用户名称"</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">"age"</span>: <span class="code-snippet__string">"int //用户年龄"</span></span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__65" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><br></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__65" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><strong style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 0.008em;text-align: left;background-color: rgb(255, 255, 255);color: rgb(171, 25, 66);">3.3 响应结果</strong></p> <p><strong style="color: rgb(171, 25, 66);"><br></strong></p> <blockquote class="js_blockquote_wrap" data-type="2" data-url="" data-author-name="" data-content-utf8-length="165" data-source-title=""> <section class="js_blockquote_digest"> <p>我们知道,如果 Controller 声明了@RestController,SpringBoot 会把返回的对象直接序列成 JSON 数据格式返回给前端。JApiDocs 也利用了这一特性来解析接口返回的结果,但由于 JApiDocs 是静态解析源码的,因此你要明确指出返回对象的类型信息,JApiDocs 支持继承、泛型、循环嵌套等复杂的类解析。</p> </section> </blockquote> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__81" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">因此我们不需要再写注释,它会根据我们的返回结果进行解析,效果如下:</span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__81" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__82" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">返回结果:</span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__82" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></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="json"><code><span class="code-snippet_outer">{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">"code"</span>: <span class="code-snippet__string">"int"</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">"msg"</span>: <span class="code-snippet__string">"string"</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">"data"</span>: {</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">"name"</span>: <span class="code-snippet__string">"string //用户名称"</span>,</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__attr">"age"</span>: <span class="code-snippet__string">"int //用户年龄"</span></span></code><code><span class="code-snippet_outer"> }</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__82" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"></span><br></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__82" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">最终生成的接口文档像下面这样:</span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__65" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><br></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.44537037037037036" data-s="300,640" src="/upload/af6a2427cfd368fe9079538d60a5ef35.png" data-type="png" data-w="1080" style=""></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__65" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><strong style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 0.008em;text-align: left;background-color: rgb(255, 255, 255);color: rgb(171, 25, 66);"><br></strong></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__65" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><strong style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 0.008em;text-align: left;background-color: rgb(255, 255, 255);color: rgb(171, 25, 66);">4. 高级配置</strong><br></p> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><strong style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 0.008em;text-align: left;background-color: rgb(255, 255, 255);color: rgb(171, 25, 66);"><br></strong></p> <p style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><strong style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 0.008em;text-align: left;background-color: rgb(255, 255, 255);color: rgb(171, 25, 66);">4.1 @ApiDoc</strong><br></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__89" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><br></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__89" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">如果你不希望把所有的接口都导出,可以在配置中设置config.setAutoGenerate(Boolean.FALSE); 然后在想要生成的接口上添加 @ApiDoc。</span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__89" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__90" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">@ApiDoc 有以下三个属性:</span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__90" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></span></p> <ul data-tool="mdnice编辑器" class="js_darkmode__91 list-paddingleft-2" data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(0,0,0)" data-style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black;" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <li style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <section data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(1, 1, 1)" data-style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);" class="js_darkmode__92" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <span style="font-size: 15px;">result:可以直接声明返回的对象类型。如果你进行声明,将覆盖SpringBoot 的返回对象;</span> </section></li> <li style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <section data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(1, 1, 1)" data-style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);" class="js_darkmode__93" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <span style="font-size: 15px;">url:请求URL,扩展字段。用于支持非 SpringBoot 项目;</span> </section></li> <li style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <section data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(1, 1, 1)" data-style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);" class="js_darkmode__94" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <span style="font-size: 15px;">method:请求方法,扩展字段。用于支持非 SpringBoot 项目。</span> </section></li> </ul> <section data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(1, 1, 1)" data-style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);" class="js_darkmode__94" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <br> </section> <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="css"><code><span class="code-snippet_outer">@<span class="code-snippet__keyword">ApiDoc</span>(<span class="code-snippet__keyword">result</span> = User.class, url = <span class="code-snippet__string">"/api/user/view"</span>, method = <span class="code-snippet__string">"post"</span>)</span></code></pre> </section> <section data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(1, 1, 1)" data-style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);" class="js_darkmode__94" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <span style="font-size: 15px;"><br></span> </section> <section data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(1, 1, 1)" data-style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);" class="js_darkmode__94" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <strong style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 0.008em;text-align: left;background-color: rgb(255, 255, 255);color: rgb(171, 25, 66);">4.2 @Ignore</strong> <br> <span style="font-size: 15px;"></span> </section> <section data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(1, 1, 1)" data-style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; color: rgb(1, 1, 1);" class="js_darkmode__94" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"> <span style="font-size: 15px;"><br></span> </section> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__99" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">如果不想导出对象里面的某个字段,可以给这个字段加上 @Ignore 注解。这样 JApiDocs 导出文档的时候就会自动忽略掉了。</span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__99" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></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="java"><code><span class="code-snippet_outer"><span class="code-snippet__keyword">public</span> <span class="code-snippet__class"><span class="code-snippet__keyword">class</span> <span class="code-snippet__title">User</span> </span>{</span></code><code><span class="code-snippet_outer"> <span class="code-snippet__meta">@Ignore</span></span></code><code><span class="code-snippet_outer"> <span class="code-snippet__keyword">private</span> <span class="code-snippet__keyword">int</span> age;</span></code><code><span class="code-snippet_outer">}</span></code></pre> </section> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__99" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"></span><br></p> <h2 data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(163, 163, 163)" data-darkmode-original-color-160098705222010="rgb(63, 63, 63)" data-darkmode-bgimage-160098705222010="1" class="js_darkmode__bg__22 js_darkmode__103" data-style="font-weight: bold; color: black; font-size: 22px; text-align: center; background-image: url("https://mmbiz.qpic.cn/mmbiz_png/lgiaG5BicLkVd67fYzzWFpaMC0p9soETgiacMtnsX2GvXCA6qj3dTxqH5Vf4yicRTniaysTiaUXq9qLXGTO1liajTEMTQ/640?wx_fmt=png"); background-size: 50px; margin-top: 1em; margin-bottom: 10px; background-position: center center; background-repeat: no-repeat no-repeat;" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><strong style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;letter-spacing: 0.008em;text-align: left;background-color: rgb(255, 255, 255);color: rgb(171, 25, 66);">5. 总结</strong></h2> <p><span style="font-size: 15px;"><br></span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__104" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;">JApiDocs 就介绍到这里了,优势劣势大家很容易就看出来了。几乎不需要注释即可生成接口文档,仅有的几个注释我们也可以通过 IDE 来自动生成。但是 JApiDocs 不具备 Swagger 在线调试功能。如果有一天 JApiDocs 支持在线调试后,那时候肯定会有一大波追随者,毕竟写代码的都不愿意写多余的注解。</span></p> <p data-tool="mdnice编辑器" data-darkmode-color-160098705222010="rgb(156, 156, 156)" data-darkmode-original-color-160098705222010="rgb(74, 74, 74)" data-style="padding-bottom: 8px; padding-top: 1em; color: rgb(74, 74, 74); line-height: 1.75em;" class="js_darkmode__104" style="white-space: normal;font-variant-ligatures: normal;orphans: 2;widows: 2;"><span style="font-size: 15px;"><br></span></p> <section donone="shifuMouseDownCard('shifu_c_030')" label="Copyright Reserved by PLAYHUDONG." style="text-align: start;white-space: normal;margin-top: 1em;margin-bottom: 1em;caret-color: rgb(0, 0, 0);color: rgb(0, 0, 0);border: 0px;"> <section style="margin-left: 1em;line-height: 1.4;"> <span style="padding: 3px 8px;border-top-left-radius: 4px;border-top-right-radius: 4px;border-bottom-right-radius: 4px;border-bottom-left-radius: 4px;color: rgb(255, 255, 255);background-color: rgb(255, 105, 31);font-family: inherit;text-align: inherit;text-decoration: inherit;font-size: 16px;">推荐阅读</span> <span style="margin-left: 4px;padding: 3px 8px;border-top-left-radius: 1.2em;border-top-right-radius: 1.2em;border-bottom-right-radius: 1.2em;border-bottom-left-radius: 1.2em;color: rgb(255, 255, 255);line-height: 1.2;background-color: rgb(204, 204, 204);font-family: inherit;text-align: inherit;text-decoration: inherit;border-color: rgb(249, 110, 87);font-size: 12px;">点击标题可跳转</span> </section> <section style="margin-top: -11px;padding: 22px 16px 16px;border: 1px solid rgb(255, 105, 31);color: rgb(51, 51, 51);font-size: 1em;font-family: inherit;text-align: inherit;text-decoration: inherit;"> <p><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=2651480891&idx=1&sn=ebf08d8c626d6419f55c48cb386abf59&chksm=bd250f448a528652a1a6ea140ecb918d7a8981172873b9de6d61b155310a81a9ecf49e407948&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" style="font-family: inherit;text-align: inherit;font-size: 12px;" data-linktype="2">在 Java 中正确使用注释</a></p> <p><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=2651481061&idx=1&sn=f7bc023796841b92387e247d4c8c80b2&chksm=bd250f9a8a52868ce10079736949782940b6bf2f7e0fdc5c51cc5d683da01714295eb915efeb&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" style="caret-color: rgb(0, 0, 0);text-align: start;white-space: normal;font-size: 12px;" data-linktype="2">使用 Java 注解自动化处理对应关系实现注释代码化</a></p> <p><span style="caret-color: rgb(0, 0, 0);text-align: start;font-size: 12px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5NzMyMjAwMA==&mid=2651481061&idx=1&sn=f7bc023796841b92387e247d4c8c80b2&chksm=bd250f9a8a52868ce10079736949782940b6bf2f7e0fdc5c51cc5d683da01714295eb915efeb&scene=21#wechat_redirect" textvalue="Spring Boot 中使用 Swagger2 构建强大的 RESTful API 文档" data-itemshowtype="0" tab="innerlink" style="caret-color: rgb(0, 0, 0);text-align: start;white-space: normal;" data-linktype="2">Spring Boot 中使用 Swagger2 构建强大的 RESTful API 文档</a></span></p> </section> </section> <p style="white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;color: rgb(255, 169, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">看完本文有收获?请转发分享给更多人</span></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;color: rgb(255, 169, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">关注「ImportNew」,提升Java技能</strong></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img data-ratio="0.9166666666666666" data-s="300,640" data-type="jpeg" data-w="600" width="auto" src="/upload/899866149276fa5fddb73c61ae04be64.jpg" style="box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 600px !important;"></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: right;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="font-size: 14px;text-align: right;">好文章,我</span><span style="font-size: 14px;text-align: right;color: rgb(255, 41, 65);">在看</span><span style="font-size: 14px;text-align: right;">❤️</span></p>
作者:微信小助手
<p style="text-align: center;" data-mpa-powered-by="yiban.io"><img class="rich_pages" data-ratio="0.66796875" data-s="300,640" src="/upload/534fe711d9504dd1508d90513384b4d.jpg" data-type="jpeg" data-w="1280" style=""></p> <p style="text-align: center;"><span style="font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;letter-spacing: 0.544px;text-align: start;white-space: pre-line;widows: 1;background-color: rgb(255, 255, 255);font-size: 12px;color: rgb(136, 136, 136);">照片来源 pexels</span></p> <p style="margin-right: 8px;margin-bottom: 1.5em;margin-left: 8px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.75;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.1em;">在第一次建立HBase表的时候,我们可能需要往里面一次性导入大量的初始化数据。我们很自然地想到将数据一条条插入到HBase中,或者通过MR方式等。但是这些方式不是慢就是在导入的过程的占用Region资源导致效率低下,所以很不适合一次性导入大量数据。本文将针对这个问题介绍如何通过HBase的BulkLoad方法来快速将海量数据导入到HBase中。</p> <p style="margin: 1.5em 8px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.75;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.1em;">总的来说,使用 Bulk Load 方式由于利用了 HBase 的数据信息是按照特定格式存储在 HDFS 里的这一特性,直接在 HDFS 中生成持久化的 HFile 数据格式文件,然后完成巨量数据快速入库的操作,配合 MapReduce 完成这样的操作,不占用 Region 资源,不会产生巨量的写入 I/O,所以需要较少的 CPU 和网络资源。Bulk Load 的实现原理是通过一个 MapReduce Job 来实现的,通过 Job 直接生成一个 HBase 的内部 HFile 格式文件,用来形成一个特殊的 HBase 数据表,然后直接将数据文件加载到运行的集群中。与使用HBase API相比,使用Bulkload导入数据占用更少的CPU和网络资源。</p> <h3 style="margin-top: 2em;margin-right: 8px;margin-bottom: 0.75em;padding-left: 8px;font-weight: bold;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.2;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;border-left: 3px solid rgb(0, 152, 116);">实现原理</h3> <p style="margin: 1.5em 8px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.75;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.1em;">Bulkload过程主要包括三部分:</p> <p style="padding-left: 1em;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.75;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;list-style: circle;"><span style="margin: 0.2em 8px;line-height: 1.75;text-indent: -1em;display: block;"><span style="margin-right: 10px;">•</span>从数据源(通常是文本文件或其他的数据库)提取数据并上传到HDFS。抽取数据到HDFS和HBase并没有关系,所以大家可以选用自己擅长的方式进行,本文就不介绍了。</span><span style="margin: 0.2em 8px;line-height: 1.75;text-indent: -1em;display: block;"><span style="margin-right: 10px;">•</span>利用MapReduce作业处理事先准备的数据 。这一步需要一个MapReduce作业,并且大多数情况下还需要我们自己编写Map函数,而Reduce函数不需要我们考虑,由HBase提供。该作业需要使用rowkey(行键)作为输出Key;KeyValue、Put或者Delete作为输出Value。MapReduce作业需要使用HFileOutputFormat2来生成HBase数据文件。为了有效的导入数据,需要配置HFileOutputFormat2使得每一个输出文件都在一个合适的区域中。为了达到这个目的,MapReduce作业会使用Hadoop的TotalOrderPartitioner类根据表的key值将输出分割开来。HFileOutputFormat2的方法configureIncrementalLoad()会自动的完成上面的工作。</span><span style="margin: 0.2em 8px;line-height: 1.75;text-indent: -1em;display: block;"><span style="margin-right: 10px;">•</span>告诉RegionServers数据的位置并导入数据。这一步是最简单的,通常需要使用LoadIncrementalHFiles(更为人所熟知是completebulkload工具),将文件在HDFS上的位置传递给它,它就会利用RegionServer将数据导入到相应的区域。</span></p> <p style="margin: 1.5em 8px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.75;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.1em;">整个过程图如下:</p> <p style="margin: 1.5em 8px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.75;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.1em;"><img data-ratio="1" src="/upload/f192265a4744ee2949cf948430248221.png" data-type="png" data-w="430"></p> <p style="margin: 1.5em 8px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.75;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.1em;">上面我们已经介绍了HBase的BulkLoad方法的原理,我们需要写个Mapper和驱动程序,实现如下:</p> <h4 style="margin: 2em 8px 0.5em;font-weight: bold;white-space: normal;text-align: left;color: rgb(0, 152, 116);line-height: 1.75;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;">使用MapReduce生成HFile文件</h4> <section class="code-snippet__github" style="margin: 10px 8px;height: auto;display: flex;font-size: 12px;background-color: rgba(27, 31, 35, 0.05);color: rgb(0, 0, 0);font-family: "PingFang SC", system-ui, Roboto, "Helvetica Neue", sans-serif;text-align: start;white-space: normal;"> <pre data-lang="" style="padding: 1em;display: grid;counter-reset: line 0;overflow-x: auto;-webkit-box-flex: 1;flex: 1 1 0%;line-height: 20px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;"><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(167, 29, 93);">public</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">class</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">IteblogBulkLoadMapper</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">extends</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">Mapper</span><span style="color: rgb(51, 51, 51);"><</span><span style="color: rgb(0, 134, 179);">LongWritable</span><span style="color: rgb(51, 51, 51);">,</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">Text</span><span style="color: rgb(51, 51, 51);">,</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">ImmutableBytesWritable</span><span style="color: rgb(51, 51, 51);">,</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">Put</span><span style="color: rgb(51, 51, 51);">>{</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">protected</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">void</span><span style="color: rgb(51, 51, 51);"> map</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(0, 134, 179);">LongWritable</span><span style="color: rgb(51, 51, 51);"> key</span><span style="color: rgb(51, 51, 51);">,</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">Text</span><span style="color: rgb(51, 51, 51);"> value</span><span style="color: rgb(51, 51, 51);">,</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">Context</span><span style="color: rgb(51, 51, 51);"> context</span><span style="color: rgb(51, 51, 51);">)</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">throws</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">IOException</span><span style="color: rgb(51, 51, 51);">,</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">InterruptedException</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(51, 51, 51);">{</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">String</span><span style="color: rgb(51, 51, 51);"> line </span><span style="color: rgb(51, 51, 51);">=</span><span style="color: rgb(51, 51, 51);"> value</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">toString</span><span style="color: rgb(51, 51, 51);">();</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">String</span><span style="color: rgb(51, 51, 51);">[]</span><span style="color: rgb(51, 51, 51);"> items </span><span style="color: rgb(51, 51, 51);">=</span><span style="color: rgb(51, 51, 51);"> line</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">split</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(24, 54, 145);">"\t"</span><span style="color: rgb(51, 51, 51);">);</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">ImmutableBytesWritable</span><span style="color: rgb(51, 51, 51);"> rowKey </span><span style="color: rgb(51, 51, 51);">=</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">new</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">ImmutableBytesWritable</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(51, 51, 51);">items</span><span style="color: rgb(51, 51, 51);">[</span><span style="color: rgb(0, 134, 179);">0</span><span style="color: rgb(51, 51, 51);">].</span><span style="color: rgb(51, 51, 51);">getBytes</span><span style="color: rgb(51, 51, 51);">());</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">Put</span><span style="color: rgb(51, 51, 51);"> put </span><span style="color: rgb(51, 51, 51);">=</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">new</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">Put</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(0, 134, 179);">Bytes</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">toBytes</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(51, 51, 51);">items</span><span style="color: rgb(51, 51, 51);">[</span><span style="color: rgb(0, 134, 179);">0</span><span style="color: rgb(51, 51, 51);">]));</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(150, 152, 150);">//ROWKEY</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> put</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">addColumn</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(24, 54, 145);">"f1"</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">getBytes</span><span style="color: rgb(51, 51, 51);">(),</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(24, 54, 145);">"url"</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">getBytes</span><span style="color: rgb(51, 51, 51);">(),</span><span style="color: rgb(51, 51, 51);"> items</span><span style="color: rgb(51, 51, 51);">[</span><span style="color: rgb(0, 134, 179);">1</span><span style="color: rgb(51, 51, 51);">].</span><span style="color: rgb(51, 51, 51);">getBytes</span><span style="color: rgb(51, 51, 51);">());</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> put</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">addColumn</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(24, 54, 145);">"f1"</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">getBytes</span><span style="color: rgb(51, 51, 51);">(),</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(24, 54, 145);">"name"</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">getBytes</span><span style="color: rgb(51, 51, 51);">(),</span><span style="color: rgb(51, 51, 51);"> items</span><span style="color: rgb(51, 51, 51);">[</span><span style="color: rgb(0, 134, 179);">2</span><span style="color: rgb(51, 51, 51);">].</span><span style="color: rgb(51, 51, 51);">getBytes</span><span style="color: rgb(51, 51, 51);">());</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> context</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">write</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(51, 51, 51);">rowkey</span><span style="color: rgb(51, 51, 51);">,</span><span style="color: rgb(51, 51, 51);"> put</span><span style="color: rgb(51, 51, 51);">);</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(51, 51, 51);">}</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);">}</span></span></code></pre> </section> <h4 style="margin: 2em 8px 0.5em;font-weight: bold;white-space: normal;text-align: left;color: rgb(0, 152, 116);line-height: 1.75;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;">驱动程序</h4> <section class="code-snippet__github" style="margin: 10px 8px;height: auto;display: flex;font-size: 12px;background-color: rgba(27, 31, 35, 0.05);color: rgb(0, 0, 0);font-family: "PingFang SC", system-ui, Roboto, "Helvetica Neue", sans-serif;text-align: start;white-space: normal;"> <pre data-lang="" style="padding: 1em;display: grid;counter-reset: line 0;overflow-x: auto;-webkit-box-flex: 1;flex: 1 1 0%;line-height: 20px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;"><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(167, 29, 93);">public</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">class</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">IteblogBulkLoadDriver</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(51, 51, 51);">{</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">public</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">static</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">void</span><span style="color: rgb(51, 51, 51);"> main</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(0, 134, 179);">String</span><span style="color: rgb(51, 51, 51);">[]</span><span style="color: rgb(51, 51, 51);"> args</span><span style="color: rgb(51, 51, 51);">)</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">throws</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">IOException</span><span style="color: rgb(51, 51, 51);">,</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">ClassNotFoundException</span><span style="color: rgb(51, 51, 51);">,</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">InterruptedException</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(51, 51, 51);">{</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">final</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">String</span><span style="color: rgb(51, 51, 51);"> SRC_PATH</span><span style="color: rgb(51, 51, 51);">=</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(24, 54, 145);">"hdfs://iteblog:9000/user/iteblog/input"</span><span style="color: rgb(51, 51, 51);">;</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">final</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">String</span><span style="color: rgb(51, 51, 51);"> DESC_PATH</span><span style="color: rgb(51, 51, 51);">=</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(24, 54, 145);">"hdfs://iteblog:9000/user/iteblog/output"</span><span style="color: rgb(51, 51, 51);">;</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">Configuration</span><span style="color: rgb(51, 51, 51);"> conf </span><span style="color: rgb(51, 51, 51);">=</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">HBaseConfiguration</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">create</span><span style="color: rgb(51, 51, 51);">();</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">Job</span><span style="color: rgb(51, 51, 51);"> job</span><span style="color: rgb(51, 51, 51);">=</span><span style="color: rgb(0, 134, 179);">Job</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">getInstance</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(51, 51, 51);">conf</span><span style="color: rgb(51, 51, 51);">);</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> job</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">setJarByClass</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(0, 134, 179);">IteblogBulkLoadDriver</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(167, 29, 93);">class</span><span style="color: rgb(51, 51, 51);">);</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> job</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">setMapperClass</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(0, 134, 179);">IteblogBulkLoadMapper</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(167, 29, 93);">class</span><span style="color: rgb(51, 51, 51);">);</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> job</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">setMapOutputKeyClass</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(0, 134, 179);">ImmutableBytesWritable</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(167, 29, 93);">class</span><span style="color: rgb(51, 51, 51);">);</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> job</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">setMapOutputValueClass</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(0, 134, 179);">Put</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(167, 29, 93);">class</span><span style="color: rgb(51, 51, 51);">);</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> job</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">setOutputFormatClass</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(0, 134, 179);">HFileOutputFormat2</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(167, 29, 93);">class</span><span style="color: rgb(51, 51, 51);">);</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">HTable</span><span style="color: rgb(51, 51, 51);"> table </span><span style="color: rgb(51, 51, 51);">=</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">new</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">HTable</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(51, 51, 51);">conf</span><span style="color: rgb(51, 51, 51);">,</span><span style="color: rgb(24, 54, 145);">"blog_info"</span><span style="color: rgb(51, 51, 51);">);</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">HFileOutputFormat2</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">configureIncrementalLoad</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(51, 51, 51);">job</span><span style="color: rgb(51, 51, 51);">,</span><span style="color: rgb(51, 51, 51);">table</span><span style="color: rgb(51, 51, 51);">,</span><span style="color: rgb(51, 51, 51);">table</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">getRegionLocator</span><span style="color: rgb(51, 51, 51);">());</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">FileInputFormat</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">addInputPath</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(51, 51, 51);">job</span><span style="color: rgb(51, 51, 51);">,</span><span style="color: rgb(167, 29, 93);">new</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">Path</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(51, 51, 51);">SRC_PATH</span><span style="color: rgb(51, 51, 51);">));</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">FileOutputFormat</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">setOutputPath</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(51, 51, 51);">job</span><span style="color: rgb(51, 51, 51);">,</span><span style="color: rgb(167, 29, 93);">new</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">Path</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(51, 51, 51);">DESC_PATH</span><span style="color: rgb(51, 51, 51);">));</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">System</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(167, 29, 93);">exit</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(51, 51, 51);">job</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">waitForCompletion</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(167, 29, 93);">true</span><span style="color: rgb(51, 51, 51);">)?</span><span style="color: rgb(0, 134, 179);">0</span><span style="color: rgb(51, 51, 51);">:</span><span style="color: rgb(0, 134, 179);">1</span><span style="color: rgb(51, 51, 51);">);</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(51, 51, 51);">}</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);">}</span></span></code></pre> </section> <h4 style="margin: 2em 8px 0.5em;font-weight: bold;white-space: normal;text-align: left;color: rgb(0, 152, 116);line-height: 1.75;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;">通过BlukLoad方式加载HFile文件</h4> <section class="code-snippet__github" style="margin: 10px 8px;height: auto;display: flex;font-size: 12px;background-color: rgba(27, 31, 35, 0.05);color: rgb(0, 0, 0);font-family: "PingFang SC", system-ui, Roboto, "Helvetica Neue", sans-serif;text-align: start;white-space: normal;"> <pre data-lang="" style="padding: 1em;display: grid;counter-reset: line 0;overflow-x: auto;-webkit-box-flex: 1;flex: 1 1 0%;line-height: 20px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;"><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(167, 29, 93);">public</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">class</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">LoadIncrementalHFileToHBase</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(51, 51, 51);">{</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">public</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">static</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">void</span><span style="color: rgb(51, 51, 51);"> main</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(0, 134, 179);">String</span><span style="color: rgb(51, 51, 51);">[]</span><span style="color: rgb(51, 51, 51);"> args</span><span style="color: rgb(51, 51, 51);">)</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">throws</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">Exception</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(51, 51, 51);">{</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">Configuration</span><span style="color: rgb(51, 51, 51);"> configuration </span><span style="color: rgb(51, 51, 51);">=</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">HBaseConfiguration</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">create</span><span style="color: rgb(51, 51, 51);">();</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">HBaseConfiguration</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">addHbaseResources</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(51, 51, 51);">configuration</span><span style="color: rgb(51, 51, 51);">);</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">LoadIncrementalHFiles</span><span style="color: rgb(51, 51, 51);"> loder </span><span style="color: rgb(51, 51, 51);">=</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">new</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">LoadIncrementalHFiles</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(51, 51, 51);">configuration</span><span style="color: rgb(51, 51, 51);">);</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">HTable</span><span style="color: rgb(51, 51, 51);"> hTable </span><span style="color: rgb(51, 51, 51);">=</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(167, 29, 93);">new</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">HTable</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(51, 51, 51);">configuration</span><span style="color: rgb(51, 51, 51);">,</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(24, 54, 145);">"blog_info"</span><span style="color: rgb(51, 51, 51);">);</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> loder</span><span style="color: rgb(51, 51, 51);">.</span><span style="color: rgb(51, 51, 51);">doBulkLoad</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(167, 29, 93);">new</span><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(0, 134, 179);">Path</span><span style="color: rgb(51, 51, 51);">(</span><span style="color: rgb(24, 54, 145);">"hdfs://iteblog:9000/user/iteblog/output"</span><span style="color: rgb(51, 51, 51);">),</span><span style="color: rgb(51, 51, 51);"> hTable</span><span style="color: rgb(51, 51, 51);">);</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);"> </span><span style="color: rgb(51, 51, 51);">}</span></span></code><code style="padding-right: 8px;font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;display: flex;border-width: 0px !important;border-style: initial !important;border-color: initial !important;"><span class="code-snippet_outer"><span style="color: rgb(51, 51, 51);">}</span></span></code></pre> </section> <p style="margin: 1.5em 8px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.75;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;letter-spacing: 0.1em;">由于HBase的BulkLoad方式是绕过了Write to WAL,Write to MemStore及Flush to disk的过程,所以并不能通过WAL来进行一些复制数据的操作。后面我将会再介绍如何通过Spark来使用Hbase的BulkLoad方式来初始化数据。</p> <h3 style="margin-top: 2em;margin-right: 8px;margin-bottom: 0.75em;padding-left: 8px;font-weight: bold;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.2;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;border-left: 3px solid rgb(0, 152, 116);">BulkLoad的使用案例</h3> <p style="padding-left: 1em;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.75;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 16px;list-style: circle;"><span style="margin: 0.2em 8px;line-height: 1.75;text-indent: -1em;display: block;"><span style="margin-right: 10px;">•</span>首次将原始数据集载入 HBase- 您的初始数据集可能很大,绕过 HBase 写入路径可以显著加速此进程。</span><span style="margin: 0.2em 8px;line-height: 1.75;text-indent: -1em;display: block;"><span style="margin-right: 10px;">•</span>递增负载 - 要定期加载新数据,请使用 BulkLoad 并按照自己的理想时间间隔分批次导入数据。这可以缓解延迟问题,并且有助于您实现服务级别协议 (SLA)。但是,压缩触发器就是 RegionServer 上的 HFile 数目。因此,频繁导入大量 HFile 可能会导致更频繁地发生大型压缩,从而对性能产生负面影响。您可以通过以下方法缓解此问题:调整压缩设置,确保不触发压缩即可存在的最大 HFile 文件数很高,并依赖于其他因素,如 Memstore 的大小 触发压缩。</span><span style="margin: 0.2em 8px;line-height: 1.75;text-indent: -1em;display: block;"><span style="margin-right: 10px;">•</span>数据需要源于其他位置 - 如果当前系统捕获了您想在 HBase 中包含的数据,且因业务原因需要保持活动状态,您可从系统中将数据定期批量加载到 HBase 中,以便可以在不影响系统的前提下对其执行操作。</span></p> <p style="padding-left: 1em;font-size: 14px;white-space: normal;text-align: left;color: rgb(63, 63, 63);line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;list-style: circle;"><br></p> <p><br></p> <section style="white-space: normal;letter-spacing: 0px;font-size: 16px;color: rgb(62, 62, 62);background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);text-align: center;widows: 1;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;line-height: 1.6;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;"> <section powered-by="xiumi.us" style="transform: rotate(0deg);"> <section style="padding-right: 10px;padding-left: 10px;"> <section style="padding-right: 10px;padding-left: 10px;font-size: 15px;letter-spacing: 1px;"> <section powered-by="xiumi.us"> <section data-source="bj.96weixin.com" style="letter-spacing: 0.544px;font-size: 16px;color: rgb(63, 63, 63);"> <section style="text-align: inherit;border-width: 1px;border-style: solid;border-color: rgb(0, 187, 236);font-family: inherit;font-weight: inherit;text-decoration: inherit;background-color: rgb(239, 239, 239);"> <section style="margin-top: -1em;margin-right: 16px;margin-left: 16px;font-size: 1em;border-width: initial;border-style: none;border-color: initial;line-height: 1.4;"> <span style="padding: 3px 8px;display: inline-block;border-radius: 4px;color: rgb(255, 255, 255);font-family: inherit;font-weight: inherit;text-decoration: inherit;border-color: rgb(0, 187, 236);background-color: rgb(0, 187, 236);font-size: 14px;"> <section> 猜你喜欢 </section></span> </section> <section style="padding: 16px;line-height: 1.4;font-family: inherit;"> <p style="letter-spacing: 0.544px;white-space: pre-wrap;text-align: left;"><span style="font-size: 12px;letter-spacing: 0.544px;font-family: inherit;font-weight: inherit;text-align: inherit;text-decoration: inherit;">1、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA5MTc0NTMwNQ==&mid=2650723826&idx=1&sn=0c93fc528d925c22d3842774e829bcac&chksm=887dc884bf0a4192bd65b8c21c08dbd06d924f4ad935af784498aa638ccc1bdfc2d9c966290f&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">Spark SQL 分桶表在字节跳动的优化</a></span></p> <p style="letter-spacing: 0.544px;white-space: pre-wrap;text-align: left;"><span style="font-size: 12px;letter-spacing: 0.544px;font-family: inherit;font-weight: inherit;text-align: inherit;text-decoration: inherit;">2、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA5MTc0NTMwNQ==&mid=2650723792&idx=2&sn=4551a4bcd61f21862682e2d98b5e827c&chksm=887dc8a6bf0a41b0d44b6f45d8c85dcd1e083411ec32d192a84c228aaa1d662f363a4054edcb&scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">一文入魂!聊透分布式系统一致性!</a></span></p> <p style="letter-spacing: 0.544px;white-space: pre-wrap;text-align: left;"><span style="font-size: 12px;">3、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA5MTc0NTMwNQ==&mid=2650723773&idx=2&sn=c57d6f1f739456734cbc348ab8d54876&chksm=887dc8cbbf0a41dddb3818142ea82c12f88c9431a27d495d7a2b2213c22f04fe2a7a850f793c&scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">全面解析Kafka 核心要素及其常见部署</a></span></p> <p style="letter-spacing: 0.544px;white-space: pre-wrap;text-align: left;"><span style="font-size: 12px;">4、<a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA5MTc0NTMwNQ==&mid=2650723698&idx=2&sn=f81d98ba2488a9329a9402d02d991379&chksm=887dc804bf0a4112b73fe5ad5aca27a4ac7d4594e53084ca18468a847593ae4627eebdb8eea9&scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">JDK15正式发布,划时代的ZGC同时宣布转正</a></span></p> </section> </section> </section> </section> </section> </section> </section> </section> <p style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);text-align: center;widows: 1;"><img class="rich_pages" data-ratio="0.7071942446043166" data-s="300,640" data-type="jpeg" data-w="1390" src="/upload/9cf14aa6ee2a067d3da22c9381926a18.jpg" style="box-sizing: border-box !important;visibility: visible !important;width: 677px !important;"></p> <p style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;font-size: 16px;color: rgb(62, 62, 62);background-color: rgb(255, 255, 255);caret-color: rgb(51, 51, 51);text-align: center;widows: 1;"><span style="color: rgb(255, 76, 0);">过往记忆大数据微信群,请添加微信:fangzhen0219,备注【进群】</span></p>
作者:微信小助手
<section style="font-size: 15px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;" data-mpa-powered-by="yiban.io"> <p style="margin-bottom: 10px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);font-size: 15px;background-color: rgb(255, 255, 255);line-height: normal;text-align: center;"><span style="font-size: 14px;letter-spacing: 0.544px;word-spacing: 2px;color: rgb(136, 136, 136);">点击蓝色“</span><span style="font-size: 14px;letter-spacing: 0.544px;word-spacing: 2px;color: rgb(0, 128, 255);">架构文摘</span><span style="font-size: 14px;letter-spacing: 0.544px;word-spacing: 2px;color: rgb(136, 136, 136);">”关注我哟</span></p> <p style="margin-bottom: 10px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);font-size: 15px;background-color: rgb(255, 255, 255);text-size-adjust: auto;word-spacing: 2px;text-align: center;"><span style="font-size: 14px;color: rgb(136, 136, 136);">加个“</span><span style="color: rgb(0, 128, 255);font-size: 14px;">星标</span><span style="font-size: 14px;color: rgb(136, 136, 136);">”,每天上午 09:25,干货推送!</span></p> <p style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);font-size: 14px;background-color: rgb(255, 255, 255);text-align: center;"><img data-backh="36" data-backw="578" data-ratio="0.0625" data-s="300,640" data-type="jpeg" data-w="640" width="100%" src="/upload/8c292e55ba5a23cb6ebc11f2a2c4fece.jpg" style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;widows: 1;word-spacing: 2px;color: rgb(136, 136, 136);box-sizing: border-box !important;visibility: visible !important;width: 677px !important;"></p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;"><span style="font-size: 14px;color: rgb(136, 136, 136);"><em>来源:<em style="max-width: 100%;color: rgb(136, 136, 136);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;white-space: normal;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">http://kaito-kidd.com/</em></em></span></p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">从这篇文章开始,我们来介绍Redis高可用相关的机制。Redis要想实现高可用,主要有以下方面来保证:<br></p> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-2"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">数据持久化</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">主从复制</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">自动故障恢复</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">集群化</span></p></li> </ul> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">这篇文章我们先介绍Redis的高可用保障的基础:数据持久化。因为Redis的主从复制和自动故障恢复,都需要依赖Redis持久化相关的东西。同时,Redis的数据持久化也可以用来做数据备份,用来保障数据的安全性。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">Redis是一个内存数据库,它的数据都保存在内存中,如果实例宕机,那么数据则全部丢失。如何保证数据的完整性和安全性也是提高服务高可用的重要机制之一。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">Redis提供了完善的持久化机制,可以把内存中的数据持久化到磁盘上,方便我们进行备份数据和快速恢复数据。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">这篇文章我们就来分析Redis的数据持久化是如何实现的?我们经常听的RDB和AOF有什么区别?以及它们不同的使用场景。</p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">持久化方式</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">Redis提供的数据持久化方式主要有2种:</p> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-2"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">RDB:产生一个数据快照文件</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">AOF:实时追加命令的日志文件</span></p></li> </ul> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">它们分别对应了不同的使用场景,下面我们就来依次分析。</p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">RDB</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">RDB全称<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">Redis Database Backup file</code>(Redis数据备份文件),也被叫做Redis数据快照。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">我们可以通过执行save或bgsave命令让Redis在本地生成RDB快照文件,这个RDB文件包含了整个实例接近完整的数据内容。</p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.45623836126629425" data-s="300,640" src="/upload/dd29e36eeb8ff14c960e3e7868fbf52d.jpg" data-type="jpeg" data-w="1074" style=""></p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">它的优点如下:</p> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-2"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">RDB文件数据是被压缩写入的,因此RDB文件的体积要比整个实例内存要小</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">当实例宕机恢复时,加载RDB文件的速度很快,能够在很短时间内迅速恢复文件中的数据</span></p></li> </ul> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">它的缺点也很明显:</p> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-2"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">由于是某一时刻的数据快照,因此它的数据并不全</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">生成RDB文件的代价是比较大的,它会消耗大量的CPU和内存资源</span></p></li> </ul> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">因此RDB比较适用于以下场景:</p> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-2"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">主从全量同步数据</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">数据库备份</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">对于丢失数据不敏感的业务场景,实例宕机后快速恢复数据</span></p></li> </ul> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">Redis主从全量同步数据就是使用RDB文件进行的,我们会在后面的文章详细讲到。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">由此可以看出,RDB非常适合做数据备份,我们可以定时让Redis生成RDB文件,然后备份这个快照文件即可。</p> <h4 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">定时生成RDB</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">Redis也提供了定时触发生成RDB文件的配置项:</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;"># 最近15分钟内 至少产生1次写入</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">save</span> <span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">900</span> <span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">1</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;"># 最近5分钟内 至少产生10次写入</span><br>save <span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">300</span> <span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">10</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;"># 最近1分钟内 至少产生10000次写入</span><br>save <span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">60</span> <span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">10000</span><br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">如果达到以上任意条件,则Redis会自动生成新的RDB文件,降低RDB数据内容与实例数据的差异。</p> <h4 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">Copy On Write</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">在Redis上执行save和bgsave命令都可以生成RDB文件,但前者是在前台执行的,也就是说在生成RDB文件时,会阻塞整个实例,在RDB未生成之前,任何请求都是无法处理的,对于内存很大的实例,生成RDB文件非常耗时,显然这是我们不能接受的。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">所以通常我们会选择执行bgsave让Redis在后台生成RDB文件,这样Redis依旧可以处理客户端请求,不会阻塞整个实例。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">但不是说后台生成RDB就是没有代价的,Redis为了实现后台把内存数据的快照写入文件,采用了操作系统提供的Copy On Write技术,也就是我们熟知的fork系统调用。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;"><strong style="font-size: inherit;color: inherit;line-height: inherit;"><code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">fork</code>系统调用会产生一个子进程,它与父进程共享相同的内存地址空间,这样子进程在这一时刻就能拥有与父进程的相同的内存数据。</strong></p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">虽然子进程与父进程共享同一块内存地址空间,但在fork子进程时,操作系统需要拷贝父进程的内存页表给子进程,如果整个Redis实例内存占用很大,那么它的内存页表也会很大,在拷贝时就会比较耗时,同时这个过程会消耗大量的CPU资源。在完成拷贝之前父进程也处于阻塞状态,无法处理客户端请求。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">fork执行完之后,子进程就可以扫描自身所有的内存数据,然后把全部数据写入到RDB文件中。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">之后父进程依旧处理客户端的请求,当在处理写命令时,父进程会重新分配新的内存地址空间,从操作系统申请新的内存使用,不再与子进程共享,这个过程就是Copy On Write(写实复制)名字的由来。这样父子进程的内存就会逐渐分离,父进程申请新的内存空间并更改内存数据,子进程的内存数据不受影响。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">由此可以看出,在生成RDB文件时,不仅消耗CPU资源,还有需要占用最多一倍的内存空间。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">我们在Redis执行info命令,可以看到fork子进程的耗时,可以通过这个耗时来评估fork时间是否符合预期。同时我们应该保证Redis机器拥有足够的CPU和内存资源,并合理设置生成RDB的时机。</p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">AOF</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">AOF全称为<code style="font-size: inherit;line-height: inherit;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(233, 105, 0);background: rgb(248, 248, 248);">Append Only File</code>(追加日志文件)。它与RDB不同的是,AOF中记录的是每一个命令的详细信息,包括完整的命令类型、参数等。只要产生写命令,就会实时写入到AOF文件中。</p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.4689922480620155" data-s="300,640" src="/upload/e8b05b82113ce6dcc9ec6895b5f772ab.jpg" data-type="jpeg" data-w="1032" style=""></p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">我们可以通过配置文件开启AOF:</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;"># 开启AOF</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">appendonly</span> <span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">yes</span><br><br><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;"># AOF文件名</span><br>appendfilename <span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">"appendonly.aof"</span><br><br><span style="font-size: inherit;line-height: inherit;color: rgb(128, 128, 128);overflow-wrap: inherit !important;word-break: inherit !important;"># 文件刷盘方式</span><br>appendfsync everysec<br></code></pre> <h4 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">刷盘方式</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">开启AOF后,Redis会把每个写操作的命令记录到文件并持久化到磁盘中,为了保证数据文件的安全性,Redis还提供了文件刷盘的时机:</p> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-2"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><strong style="font-size: inherit;color: inherit;line-height: inherit;">appendfsync always</strong>:每次写入都刷盘,对性能影响最大,占用磁盘IO比较高,数据安全性最高</p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><strong style="font-size: inherit;color: inherit;line-height: inherit;">appendfsync everysec</strong>:1秒刷一次盘,对性能影响相对较小,节点宕机时最多丢失1秒的数据</p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><strong style="font-size: inherit;color: inherit;line-height: inherit;">appendfsync no</strong>:按照操作系统的机制刷盘,对性能影响最小,数据安全性低,节点宕机丢失数据取决于操作系统刷盘机制</p></li> </ul> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">以上可以看出AOF相对于RDB的优点是,AOF数据文件更新比较及时,比RDB保存更完整的数据,这样在数据恢复时能够恢复尽量完整的数据,降低丢失数据的风险。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">如果同时存在RDB文件和AOF文件,Redis会优先使用AOF文件进行数据恢复。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">但它的缺点也很易见:</p> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-2"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">随着时间增长,AOF文件会越来越大</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">AOF文件刷盘会增加磁盘IO的负担,可能影响Redis的性能(开启每秒刷盘时)</span></p></li> </ul> <h4 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">AOF重写</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">针对第一种情况,Redis提供了AOF瘦身的功能,可以设置在AOF文件很大时,自动触发AOF重写,Redis会扫描整个实例的数据,重新生成一个AOF文件达成瘦身的效果。但这个重写过程也需要消耗大量的CPU资源。</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;color: rgb(91, 218, 237);overflow-wrap: inherit !important;word-break: inherit !important;"># AOF文件距离上次文件增长超过多少百分比则触发重写</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">auto</span>-aof-rewrite-percentage <span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">100</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(91, 218, 237);overflow-wrap: inherit !important;word-break: inherit !important;"># AOF文件体积最小多大以上才触发重写</span><br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">auto</span>-aof-rewrite-min-size <span style="font-size: inherit;line-height: inherit;color: rgb(174, 135, 250);overflow-wrap: inherit !important;word-break: inherit !important;">64</span>mb<br></code></pre> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">由于AOF可以最大可能降低丢失数据的风险,所以它一般适用于对丢失数据很敏感的业务场景,例如涉及金钱交易的业务。</p> <h4 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.2em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">性能影响</span></h4> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">如果AOF的刷盘时机设置为每次写入都刷盘,那么会大大降低Redis的写入性能,因为每次写命令都需要写入文件并刷到磁盘中才会返回,当写入量很大时,会增加磁盘IO的负担。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">性能与数据安全不能兼得,虽然Redis提供了实时刷盘的机制,但是在真正场景中使用的不多。</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">通常我们会选择每秒刷盘这种方式,既能保证良好的写入性能,在实例宕机时最多丢失1秒的数据,做到性能和安全的平衡。</p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">总结</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">我们对RDB和AOF的总结如下表。</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-ratio="0.51640625" data-s="300,640" src="/upload/fdb3e162d5ffbd69b6e3b0bfa8c4834e.jpg" data-type="jpeg" data-w="1280" style=""></p> <figcaption style="line-height: inherit;margin-top: 10px;text-align: center;color: rgb(153, 153, 153);font-size: 0.7em;"> <br> </figcaption> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">我们需要针对不同的业务场景选择合适的持久化方式,也可以根据RDB和AOF的优点配合使用,保证Redis数据的安全性,又可以兼顾它的性能。</p> </section> <pre style="color: rgb(62, 62, 62);font-size: 16px;letter-spacing: 1px;text-align: start;widows: 1;word-spacing: 1px;caret-color: rgb(255, 0, 0);background-color: rgb(255, 255, 255);"> <section data-mpa-template="t" mpa-from-tpl="t" style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;caret-color: rgb(0, 0, 0);color: rgb(120, 114, 114);word-spacing: 2px;"> <section data-id="89429" mpa-from-tpl="t" style="border-width: 0px;border-style: none;border-color: initial;"> <section mpa-from-tpl="t" style="text-align: center;height: 50px;"> <section mpa-from-tpl="t" style="margin-right: auto;margin-left: auto;width: 48px;height: 48px;color: rgb(255, 255, 255);line-height: 48px;display: inline-block;background-image: url("https://mmbiz.qpic.cn/mmbiz_gif/kiaqiahsnxHd4Zt4378tqib1DnnfKYvZAI7sUNZCYmGN2HCMDFDYV5hLu6HrHIK5BynAAwgHGiafFFU7ibYez6mXL4w/640?wx_fmt=gif");background-repeat: no-repeat;background-size: 100%;background-position: 0px center;"> <p style="font-weight: bold;"><span style="font-size: 14px;">end</span></p> </section> <section mpa-from-tpl="t" style="margin-top: -26px;height: 2px;background-color: rgb(34, 33, 33);"> <br> </section> </section> </section> </section><p style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;"><br></p> <section mpa-from-tpl="t" style="padding-left: 5px;letter-spacing: 0.544px;white-space: normal;caret-color: rgb(0, 0, 0);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: medium;word-spacing: 2px;border-left: 5px solid rgb(51, 51, 51);line-height: 1.5em;"> <section powered-by="xiumi.us" mpa-from-tpl="t"> <section mpa-from-tpl="t"> <section mpa-from-tpl="t" style="font-size: 18px;"> <p><span style="font-size: 16px;">推荐阅读:</span></p> </section> </section> </section> </section> <ul class="list-paddingleft-2" mpa-from-tpl="t" style="letter-spacing: 0.544px;white-space: normal;caret-color: rgb(0, 0, 0);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: medium;word-spacing: 2px;"> <li style="font-size: 14px;"><p style="margin-top: 5px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&mid=2247492542&idx=2&sn=64270974b1169c71af925b90121360dc&chksm=9f448f76a8330660ab1f9befe539ff3575961646f87253177328c61bf0e66476070b365b6a6e&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">JAVA 线上故障排查指南!</a></p></li> <li style="font-size: 14px;"><p style="margin-top: 5px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&mid=2247492417&idx=2&sn=92833e66e40214fd5afc5a48fd7286a0&chksm=9f448f89a833069f095c986670cae3f2b96a52c95518e3bb97f22b1ff19dba50ee48f8d0c014&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">总结三种 MySQL 大表优化方案</a></p></li> <li style="font-size: 14px;"><p style="margin-top: 5px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&mid=2247492408&idx=1&sn=1bd7546b766d11e30648506222630ccd&chksm=9f448ff0a83306e66a6c80b275a6e5a6969239ea15aaef81172d305d9ff43daf18bb315c6abf&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">面试官:RocketMQ 消息会丢失吗?如何解决消息丢失!!</a></p></li> <li style="font-size: 14px;"><p style="margin-top: 5px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&mid=2247492361&idx=2&sn=8b0e9a5d08fffb620aaae38ed59ea8cc&chksm=9f448fc1a83306d703395e59e4c9e69b74e6f1e57c19f502faaa1b1e4101f12c9be904a79f54&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">100000 行级别数据的 Excel 导入优化之路</a></p></li> <li style="font-size: 14px;"><p style="margin-top: 5px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&mid=2247492339&idx=1&sn=a8e5726019b155a17a4634fa18d30588&chksm=9f448e3ba833072d5c08fc94dbea53cd4d78c36c3f7b366fdae2c847b36a2c54d4ba76306db3&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">用图讲解 ElasticSearch 搜索原理,你就明白了!</a><br></p></li> </ul><p style="margin-top: 5px;letter-spacing: 0.544px;white-space: normal;caret-color: rgb(0, 0, 0);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;word-spacing: 2px;"><br></p><p style="margin-top: 5px;letter-spacing: 0.544px;white-space: normal;caret-color: rgb(0, 0, 0);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;word-spacing: 2px;text-align: right;"><img class="rich_pages" data-ratio="0.5555555555555556" data-s="300,640" data-type="jpeg" data-w="900" src="/upload/9d786e52e671b1ce4beb338d1e0d1815.jpg" style="letter-spacing: 0.544px;text-align: center;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;visibility: visible !important;width: 677px !important;"><span style="letter-spacing: 0.544px;font-size: 14px;">如有收获,点个在看,诚挚感谢</span><img data-ratio="1" data-type="png" data-w="19" width="19px" src="/upload/5f7454d24a334e968c32b8ce9ae53c5.png" style="font-size: 16px;letter-spacing: 0.544px;display: inline-block;vertical-align: text-bottom;box-sizing: border-box !important;visibility: visible !important;width: 19px !important;"></p></pre> <p><br></p>
作者:微信小助手
<section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;"> <section style="margin-top: 10px;margin-bottom: 10px;box-sizing: border-box;"> <section style="padding: 10px 10px 0px;background-color: rgb(239, 239, 239);box-sizing: border-box;"> <span style="display: inline-block;width: 5%;line-height: 0.8;font-weight: bolder;font-size: 48px;box-sizing: border-box;" title=""> <section style="box-sizing: border-box;"> “ </section></span> <section style="display: inline-block;vertical-align: top;float: right;width: 90%;line-height: 1.5;font-size: 15px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><span style="letter-spacing: 1px;">问题要从一次 Kafka 的宕机开始说起。笔者所在的是一家金融科技公司,但公司内部并没有采用在金融支付领域更为流行的 RabbitMQ,而是采用了设计之初就为日志处理而生的 Kafka,所以我一直很好奇 Kafka 的高可用实现和保障。</span></p> </section> <section style="clear: both;box-sizing: border-box;"> <svg viewbox="0 0 1 1" style="float:left;line-height:0;width:0;vertical-align:top;"></svg> </section> </section> </section> </section> <section style="line-height: 1.75em;"> <br> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;"> <img class="rich_pages" data-ratio="0.6036217303822937" data-s="300,640" src="/upload/32cfa321dead4829ce6941b18a694b8f.png" data-type="png" data-w="994" style=""> </section> <section style="text-align: center;line-height: 1.75em;"> <span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;"><em>图片来自 Pexels</em></span> <br> </section> <section style="line-height: normal;"> <br> </section> <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin: 0.5em 0px;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-color: rgb(89, 89, 89);border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">Kafka 宕机引发的高可用问题</p> </section> </section> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">从 Kafka 部署后,系统内部使用的 Kafka 一直运行稳定,没有出现不可用的情况。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">但最近系统测试人员常反馈偶有 Kafka 消费者收不到消息的情况,登陆管理界面发现三个节点中有一个节点宕机挂掉了。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">但是按照高可用的理念,三个节点还有两个节点可用怎么就引起了整个集群的消费者都接收不到消息呢?<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">要解决这个问题,就要从 Kafka 的高可用实现开始讲起。<br></span></p> <section style="line-height: normal;"> <br> </section> <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin: 0.5em 0px;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-color: rgb(89, 89, 89);border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">Kafka 的多副本冗余设计</p> </section> </section> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">不管是传统的基于关系型数据库设计的系统,还是分布式的如 Zookeeper、Redis、Kafka、HDFS 等等,实现高可用的办法通常是采用冗余设计,通过冗余来解决节点宕机不可用问题。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">首先简单了解 Kafka 的几个概念:<br></span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;line-height: 1.75em;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">物理模型,如下图:</span></p> <section style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"> <img class="rich_pages" data-ratio="0.5458290422245108" data-s="300,640" src="/upload/b52fd36dfec4c4392f256007099251c3.png" data-type="png" data-w="971" style=""> </section> <section style="text-align: justify;line-height: 1.75em;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"> <span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">逻辑模型,如下图:<br></span> </section> <section style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"> <img class="rich_pages" data-ratio="0.5944609297725024" data-s="300,640" src="/upload/12690f25cdde1f8655eb6e36951b4a3d.png" data-type="png" data-w="1011" style=""> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Broker(节点):</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Kafka 服务节点,简单来说一个 Broker 就是一台 Kafka 服务器,一个物理节点。</span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Topic(主题):</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在 Kafka 中消息以主题为单位进行归类,每个主题都有一个 Topic Name,生产者根据 Topic Name 将消息发送到特定的 Topic,消费者则同样根据 Topic Name 从对应的 Topic 进行消费。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Partition(分区):</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Topic(主题)是消息归类的一个单位,但每一个主题还能再细分为一个或多个 Partition(分区),一个分区只能属于一个主题。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">主题和分区都是逻辑上的概念,举个例子,消息 1 和消息 2 都发送到主题 1,它们可能进入同一个分区也可能进入不同的分区(所以同一个主题下的不同分区包含的消息是不同的),之后便会发送到分区对应的 Broker 节点上。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Offset(偏移量):</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">分区可以看作是一个只进不出的队列(Kafka 只保证一个分区内的消息是有序的),消息会往这个队列的尾部追加,每个消息进入分区后都会有一个偏移量,标识该消息在该分区中的位置,消费者要消费该消息就是通过偏移量来识别。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">其实,根据上述的几个概念,是不是也多少猜到了 Kafka 的多副本冗余设计实现了?别急,咱继续往下看。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在 Kafka 0.8 版本以前,是没有多副本冗余机制的,一旦一个节点挂掉,那么这个节点上的所有 Partition 的数据就无法再被消费。这就等于发送到 Topic 的有一部分数据丢失了。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在 0.8 版本后引入副本记者则很好地解决宕机后数据丢失的问题。副本是以 Topic 中每个 Partition 的数据为单位,每个 Partition 的数据会同步到其他物理节点上,形成多个副本。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">每个 Partition 的副本都包括一个 Leader 副本和多个 Follower 副本,Leader 由所有的副本共同选举得出,其他副本则都为 Follower 副本。<br></span></p> <p style="line-height: normal;"><br></p> <section style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;margin-bottom: 5px;"> <span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">在生产者写或者消费者读的时候,都只会与 Leader 打交道,在写入数据后 Follower 就会来拉取数据进行数据同步。<br></span> </section> <p style="text-align: center;margin-left: 8px;margin-right: 8px;margin-bottom: 5px;"><img class="rich_pages" data-ratio="0.7897862232779097" data-s="300,640" src="/upload/9ebfb9b8a0d20001f0ab9bb066a1ce67.png" data-type="png" data-w="842" style=""></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">就这么简单?是的,基于上面这张多副本架构图就实现了 Kafka 的高可用。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">当某个 Broker 挂掉了,甭担心,这个 Broker 上的 Partition 在其他 Broker 节点上还有副本。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">你说如果挂掉的是 Leader 怎么办?</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">那就在 Follower 中在选举出一个 Leader 即可,生产者和消费者又可以和新的 Leader 愉快地玩耍了,这就是高可用。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">你可能还有疑问,那要多少个副本才算够用?</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Follower 和 Leader 之间没有完全同步怎么办?一个节点宕机后 Leader 的选举规则是什么?<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">直接抛结论:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">多少个副本才算够用?副本肯定越多越能保证 Kafka 的高可用,但越多的副本意味着网络、磁盘资源的消耗更多,性能会有所下降。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">通常来说副本数为 3 即可保证高可用,极端情况下将 replication-factor 参数调大即可。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">Follower 和 Leader 之间没有完全同步怎么办?</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Follower 和 Leader 之间并不是完全同步,但也不是完全异步,而是采用一种 ISR 机制(In-Sync Replica)。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">每个 Leader 会动态维护一个 ISR 列表,该列表里存储的是和 Leader 基本同步的 Follower。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如果有 Follower 由于网络、GC 等原因而没有向 Leader 发起拉取数据请求,此时 Follower 相对于 Leader 是不同步的,则会被踢出 ISR 列表。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">所以说,ISR 列表中的 Follower 都是跟得上 Leader 的副本。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">一个节点宕机后 Leader 的选举规则是什么?</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">分布式相关的选举规则有很多,像 Zookeeper 的 Zab、Raft、Viewstamped Replication、微软的 PacificA 等。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">而 Kafka 的 Leader 选举思路很简单,基于我们上述提到的 ISR 列表,当宕机后会从所有副本中顺序查找,如果查找到的副本在 ISR 列表中,则当选为 Leader。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">另外还要保证前任 Leader 已经是退位状态了,否则会出现脑裂情况(有两个Leader)。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">怎么保证?Kafka 通过设置了一个 Controller 来保证只有一个 Leader。<br></span></p> <section style="line-height: normal;"> <br> </section> <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin: 0.5em 0px;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-color: rgb(89, 89, 89);border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">Ack 参数决定了可靠程度</p> </section> </section> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">另外,这里补充一个面试考 Kafka 高可用必备知识点:request.required.asks 参数。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">Asks 这个参数是生产者客户端的重要配置,发送消息的时候就可设置这个参数。<br></span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">该参数有三个值可配置:</span></p> <ul style="list-style-type: disc;" class="list-paddingleft-2"> <li style="font-weight: bold;"><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">0<br></span></strong></p></li> <li style="font-weight: bold;"><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">1<br></span></strong></p></li> <li><p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">All</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p></li> </ul> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">第一种是设为 0,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">意思是生产者把消息发送出去之后,之后这消息是死是活咱就不管了,有那么点发后即忘的意思,说出去的话就不负责了。不负责自然这消息就有可能丢失,那就把可用性也丢失了。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">第二种是设为 1,意思是生产者把消息发送出去之后,这消息只要顺利传达给了 Leader,其他 Follower 有没有同步就无所谓了。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">存在一种情况,Leader 刚收到了消息,Follower 还没来得及同步 Broker 就宕机了,但生产者已经认为消息发送成功了,那么此时消息就丢失了。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">注意,设为 1 是 Kafka 的默认配置!!!可见 Kafka 的默认配置也不是那么高可用,而是对高可用和高吞吐量做了权衡折中。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">第三种是设为 All(或者 -1),</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">意思是生产者把消息发送出去之后,不仅 Leader 要接收到,ISR 列表中的 Follower 也要同步到,生产者才会任务消息发送成功。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">进一步思考,Asks=All 就不会出现丢失消息的情况吗?答案是否。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">当 ISR 列表只剩 Leader 的情况下,Asks=All 相当于 Asks=1,这种情况下如果节点宕机了,还能保证数据不丢失吗?<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">因此只有在 Asks=All 并且有 ISR 中有两个副本的情况下才能保证数据不丢失。<br></span></p> <p style="line-height: normal;"><br></p> <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;"> <section style="border-bottom: 1px solid black;margin: 0.5em 0px;line-height: 1.2;box-sizing: border-box;"> <section style="display: inline-block;border-color: rgb(89, 89, 89);border-bottom: 6px solid rgb(89, 89, 89);margin-bottom: -1px;font-size: 20px;color: rgb(89, 89, 89);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;">解决问题</p> </section> </section> </section> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">绕了一大圈,了解了 Kafka 的高可用机制,终于回到我们一开始的问题本身,Kafka 的一个节点宕机后为什么不可用?<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">我在开发测试环境配置的 Broker 节点数是 3,Topic 是副本数为 3,Partition 数为 6,Asks 参数为 1。</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">当三个节点中某个节点宕机后,集群首先会怎么做?没错,正如我们上面所说的,集群发现有 Partition 的 Leader 失效了,这个时候就要从 ISR 列表中重新选举 Leader。<br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">如果 ISR 列表为空是不是就不可用了?</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">并不会,而是从 Partition 存活的副本中选择一个作为 Leader,不过这就有潜在的数据丢失的隐患了。</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">所以,只要将 Topic 副本个数设置为和 Broker 个数一样,Kafka 的多副本冗余设计是可以保证高可用的,不会出现一宕机就不可用的情况(不过需要注意的是 Kafka 有一个保护策略,当一半以上的节点不可用时 Kafka 就会停止)。</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">那仔细一想,Kafka 上是不是有副本个数为 1 的 Topic?</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">问题出在了 __consumer_offset 上,__consumer_offset 是一个 Kafka 自动创建的 Topic,用来存储消费者消费的 Offset(偏移量)信息,默认 Partition 数为 50。</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">而就是这个 Topic,它的默认副本数为 1。如果所有的 Partition 都存在于同一台机器上,那就是很明显的单点故障了!</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">当将存储 __consumer_offset 的 Partition 的 Broker 给 Kill 后,会发现所有的消费者都停止消费了。</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;letter-spacing: 1px;color: rgb(71, 193, 168);">这个问题怎么解决?</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <p style="line-height: normal;"><br></p> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">第一点,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">需要将 __consumer_offset 删除,注意这个 Topic 时 Kafka 内置的 Topic,无法用命令删除,我是通过将 logs 删了来实现删除。</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">第二点,</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">需要通过设置 offsets.topic.replication.factor 为 3 来将 __consumer_offset 的副本数改为 3。</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">通过将 __consumer_offset 也做副本冗余后来解决某个节点宕机后消费者的消费问题。</span><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;"><br></span></p> <section style="line-height: normal;"> <br> </section> <p style="text-align: justify;margin-left: 8px;margin-right: 8px;line-height: 1.75em;"><strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">最后,给大家<span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">留个思考</span>:</span></strong><span style="font-size: 15px;color: rgb(89, 89, 89);letter-spacing: 1px;">为什么 __consumer_offset 的 Partition 会出现只存储在 1 个 Broker 上而不是分布在各个 Broker 上?</span></p> <section style="line-height: normal;"> <br> </section> <p style="white-space: normal;max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(89, 89, 89);letter-spacing: 1px;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;word-wrap: break-word !important;">作者:</span></em><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;word-wrap: break-word !important;">JanusWoo</span></em></span><span style="max-width: 100%;color: rgb(89, 89, 89);letter-spacing: 1px;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-size: 14px;box-sizing: border-box !important;word-wrap: break-word !important;"><br></span></em></span></p> <p style="white-space: normal;max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(89, 89, 89);letter-spacing: 1px;box-sizing: border-box !important;word-wrap: break-word !important;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;max-width: 100%;color: rgb(89, 89, 89);letter-spacing: 1px;"><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">编辑:陶家龙</span></em></span></em></span><br style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"></p> <p><em style="max-width: 100%;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;line-height: 1.75em;font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;box-sizing: border-box !important;word-wrap: break-word !important;">出处:https://juejin.im/post/6874957625998606344</span></em></p> <p style="text-align: center;"><img class="rich_pages" data-ratio="0.39375" src="/upload/eccf90ae5f48405df149baa3056d4bf3.png" data-type="gif" data-w="640" style=""></p> <section style="box-sizing: border-box;font-style: normal;font-weight: 400;text-align: justify;font-size: 16px;"> <section style="margin: 0.5em 0px;box-sizing: border-box;"> <section style="font-size: 15px;border-style: solid;border-width: 0px 0px 1px;color: rgb(89, 89, 89);border-bottom: 1px solid rgba(215, 215, 215, 0.96);box-sizing: border-box;"> <p style="margin: 0px;padding: 0px;box-sizing: border-box;"><span style="letter-spacing: 1px;"><strong>精彩文章推荐:</strong></span></p> </section> </section> </section> <p style="line-height: 2em;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&mid=2655836572&idx=1&sn=c765dc4eb1f68a05f487d5f82ae1e6e8&chksm=bd74944b8a031d5d7a62ba47d87d0bb9949a0ad66c8c4657cdad7385b73151935eb8b18e9d70&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">如何锁住数据库中几十亿小姐姐?</span></a><br><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&mid=2655836538&idx=1&sn=6a7ae50448b03a7b9ad31a80c1d191e4&chksm=bd7494ad8a031dbbafdbe54cfce75443ead6d886086c03687c582f114e1b982566d85247ba38&scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">Nginx,为什么依旧这么“香”?</span></a><br><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&mid=2655836483&idx=1&sn=464caca5495649abe57dce693b281c86&chksm=bd7494948a031d82a0bb9ae97f17345f26da93b29771aa39f191f74e22567838a35c195073cc&scene=21#wechat_redirect" data-itemshowtype="11" tab="innerlink" style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;" data-linktype="2"><span style="font-size: 14px;color: rgb(89, 89, 89);letter-spacing: 1px;">被“推荐系统”虐的日子,太惨了...</span></a><br></p>
作者:微信小助手
<p data-mpa-powered-by="yiban.io" style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(62, 71, 83);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br></p> <p data-mpa-powered-by="yiban.io" style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(62, 71, 83);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 16px;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(127, 127, 127);font-size: 14px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;">点击上方“</span><span style="max-width: 100%;font-size: 14px;line-height: 1.75em;color: rgb(0, 176, 240);box-sizing: border-box !important;overflow-wrap: break-word !important;">服务端思维</span><span style="max-width: 100%;color: rgb(127, 127, 127);font-size: 14px;line-height: 1.75em;box-sizing: border-box !important;overflow-wrap: break-word !important;">”,选择“</span></span><span style="max-width: 100%;color: rgb(136, 136, 136);font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">设为星标</span><span style="max-width: 100%;color: rgb(127, 127, 127);letter-spacing: 0.544px;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">”</span></span></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;color: rgb(62, 62, 62);font-size: 15px;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(127, 127, 127);font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">回复”</span><span style="max-width: 100%;letter-spacing: 0.544px;font-size: 14px;color: rgb(0, 122, 170);box-sizing: border-box !important;overflow-wrap: break-word !important;">669</span><span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(127, 127, 127);font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;">“获取独家整理的精选资料集</span></span></p> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;color: rgb(62, 62, 62);font-size: 15px;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 0.544px;color: rgb(127, 127, 127);font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">回复”</span><span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(0, 122, 170);box-sizing: border-box !important;overflow-wrap: break-word !important;">加群</span><span style="max-width: 100%;letter-spacing: 0.544px;box-sizing: border-box !important;overflow-wrap: break-word !important;">“加入全国服务端高端社群「后端圈」</span></span></p> <p style="text-align: center;"><img class="rich_pages js_insertlocalimg" data-backh="335" data-backw="500" data-ratio="0.668" data-s="300,640" src="/upload/411542c9cd09296b8182c8eab657a24d.jpg" data-type="jpeg" data-w="500" style="width: 100%;height: auto;"></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;border-width: 0px;border-style: initial;border-color: initial;">Cloud-Platform</span>是国内首个基于Spring Cloud微服务化开发平台,具有统一授权、认证后台管理系统,其中包含具备用户管理、资源权限管理、网关API 管理等多个模块,支持多业务系统并行开发,可以作为后端服务的开发脚手架。代码简洁,架构清晰,适合学习和直接项目中使用。核心技术采用Spring Boot 2.1.2以及Spring Cloud (Greenwich.RELEASE) 相关核心组件,采用Nacos注册和配置中心,集成流量卫兵Sentinel,前端采用vue-element-admin组件,Elastic Search自行集成。</p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-weight: 700;border-width: 0px;border-style: initial;border-color: initial;">码云开源地址:</span></p> <pre style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-family: Monaco;font-size: 16px;white-space: pre-wrap;margin-top: 1em;margin-bottom: 1em;padding: 15px;border-width: 1px;border-style: solid;border-color: rgb(232, 232, 232);line-height: 1.5;color: rgb(34, 34, 34);background: rgb(250, 250, 250);overflow-x: auto;border-radius: 3px;text-align: left;box-shadow: rgba(217, 217, 217, 0.498) 0px 0px 0px 1px inset;"><code style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-family: Consolas, Menlo, Courier, monospace;font-size: 1em;border-width: 0px;border-style: initial;border-color: initial;"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;color: rgb(17, 75, 166);">https</span>:<span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;color: rgb(153, 153, 153);">//gitee.com/geek_qi/cloud-platform</span></code></pre> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 1.5em;font-weight: 700;border-width: 0px;border-style: initial;border-color: initial;line-height: 1.33333;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);margin-top: 28px !important;">github开源地址:</h1> <pre style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-family: Monaco;font-size: 16px;white-space: pre-wrap;margin-top: 1em;margin-bottom: 1em;padding: 15px;border-width: 1px;border-style: solid;border-color: rgb(232, 232, 232);line-height: 1.5;color: rgb(34, 34, 34);background: rgb(250, 250, 250);overflow-x: auto;border-radius: 3px;text-align: left;box-shadow: rgba(217, 217, 217, 0.498) 0px 0px 0px 1px inset;"><code style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-family: Consolas, Menlo, Courier, monospace;font-size: 1em;border-width: 0px;border-style: initial;border-color: initial;"><span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;color: rgb(17, 75, 166);">https</span>:<span style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;color: rgb(153, 153, 153);">//github.com/wxiaoqi/Spring-Cloud-Platform</span></code></pre> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 1.5em;font-weight: 700;border-width: 0px;border-style: initial;border-color: initial;line-height: 1.33333;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);margin-top: 28px !important;">模块说明</h1> <p><img data-ratio="0.5666666666666667" src="/upload/da11390acc102167d6414d28c98ddefd.png" data-type="other" data-w="1080" style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin: 10px auto;display: block;"></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;"><br></p> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 1.5em;font-weight: 700;border-width: 0px;border-style: initial;border-color: initial;line-height: 1.33333;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);margin-top: 28px !important;">架构摘要</h1> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 1.5em;font-weight: 700;border-width: 0px;border-style: initial;border-color: initial;line-height: 1.33333;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);margin-top: 28px !important;">中台化前端</h1> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">集成d2admin中台化前端,优化前端架构和功能布局,支撑中台服务化的应用开发。</p> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 1.5em;font-weight: 700;border-width: 0px;border-style: initial;border-color: initial;line-height: 1.33333;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);margin-top: 28px !important;">JWT鉴权</h1> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">通过JWT的方式来进行用户认证和信息传递,保证服务之间用户无状态的传递。</p> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 1.5em;font-weight: 700;border-width: 0px;border-style: initial;border-color: initial;line-height: 1.33333;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);margin-top: 28px !important;">监控</h1> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">利用Spring Boot Admin 来监控各个独立Service的运行状态;利用Hystrix Dashboard来实时查看接口的运行状态和调用频率等。</p> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 1.5em;font-weight: 700;border-width: 0px;border-style: initial;border-color: initial;line-height: 1.33333;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);margin-top: 28px !important;">负载均衡</h1> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">将服务保留的rest进行代理和网关控制,除了平常经常使用的node.js、nginx外,Spring Cloud系列的zuul和ribbon,可以帮我们进行正常的网关管控和负载均衡。其中扩展和借鉴国外项目的扩展基于JWT的Zuul限流插件,方面进行限流。</p> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 1.5em;font-weight: 700;border-width: 0px;border-style: initial;border-color: initial;line-height: 1.33333;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);margin-top: 28px !important;">服务注册与调用</h1> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">基于Nacos来实现的服务注册与调用,在Spring Cloud中使用Feign, 我们可以做到使用HTTP请求远程服务时能与调用本地方法一样的编码体验,开发者完全感知不到这是远程方法,更感知不到这是个HTTP请求。</p> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 1.5em;font-weight: 700;border-width: 0px;border-style: initial;border-color: initial;line-height: 1.33333;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);margin-top: 28px !important;">熔断与流控</h1> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);">集成阿里Sentinel进行接口流量控制,通过熔断和降级处理避免服务之间的调用“雪崩”。</p> <hr style="-webkit-tap-highlight-color: transparent;box-sizing: content-box;height: 4px;overflow: visible;margin: 40px auto;width: 64px;background: rgb(237, 64, 64);outline: none;border-width: initial;border-style: none;border-color: initial;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;"> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 1.5em;font-weight: 700;border-width: 0px;border-style: initial;border-color: initial;line-height: 1.33333;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);margin-top: 28px !important;">功能截图</h1> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 1.5em;font-weight: 700;border-width: 0px;border-style: initial;border-color: initial;line-height: 1.33333;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);margin-top: 28px !important;">基本功能</h1> <h1 style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;font-size: 1.5em;font-weight: 700;border-width: 0px;border-style: initial;border-color: initial;line-height: 1.33333;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);margin-top: 28px !important;">功能截图</h1> <p><img data-ratio="0.5694444444444444" src="/upload/fdee2aec2f89ad55c25c19508e17dea8.png" data-type="other" data-w="1080" style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin: 10px auto;display: block;"></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;"><br></p> <p><img data-ratio="0.5703703703703704" src="/upload/fddda798e069670ae21fcaa826434fab.png" data-type="other" data-w="1080" style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin: 10px auto;display: block;"></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;"><br></p> <p><img data-ratio="0.5703703703703704" src="/upload/ef2368ecdc52074dc9119c67ad96b861.png" data-type="other" data-w="1080" style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin: 10px auto;display: block;"></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;"><br></p> <p><img data-ratio="0.5694444444444444" src="/upload/7eb37f4983f518456629880245fed0c0.png" data-type="other" data-w="1080" style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin: 10px auto;display: block;"></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;"><br></p> <p><img data-ratio="0.5694444444444444" src="/upload/3f36aa53d05cbd927a8605372af560d1.png" data-type="other" data-w="1080" style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin: 10px auto;display: block;"></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;"><br></p> <p><img data-ratio="0.5509259259259259" src="/upload/c1dbc883bcc7aedddad29a673bef26c8.png" data-type="other" data-w="1080" style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin: 10px auto;display: block;"></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;"><br></p> <p><img data-ratio="0.5509259259259259" src="/upload/c4b5402deb83bd49d1ad46c442b1de98.png" data-type="other" data-w="1080" style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin: 10px auto;display: block;"></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;"><br></p> <p><img data-ratio="0.5509259259259259" src="/upload/c42f39d9c1c14cd3a813b5334f1c00f7.png" data-type="other" data-w="1080" style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin: 10px auto;display: block;"></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;"><br></p> <p><img data-ratio="0.5694444444444444" src="/upload/acc5267f5a050bbb856e69d90f8063b4.png" data-type="other" data-w="1080" style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin: 10px auto;display: block;"></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;"><br></p> <p><img data-ratio="0.5472222222222223" src="/upload/ded6217610d065dbd4de581fd2c0b814.png" data-type="other" data-w="1080" style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin: 10px auto;display: block;"></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;"><br></p> <p><img data-ratio="0.5444444444444444" src="/upload/fc1acc7ff7b03e2eb9fb90746082915e.png" data-type="other" data-w="1080" style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin: 10px auto;display: block;"></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;"><br></p> <p><img data-ratio="0.5574074074074075" src="/upload/25efa2c9d91792815032a14d53dc218f.png" data-type="other" data-w="1080" style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin: 10px auto;display: block;"></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;"><br></p> <p><img data-ratio="0.5472222222222223" src="/upload/c18ad31c83000587a693eb935bbcbb34.png" data-type="other" data-w="1080" style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;border-width: 0px;border-style: initial;border-color: initial;margin: 10px auto;display: block;"></p> <p style="-webkit-tap-highlight-color: transparent;box-sizing: border-box;margin-top: 16px;margin-bottom: 16px;border-width: 0px;border-style: initial;border-color: initial;color: rgb(34, 34, 34);font-family: "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "WenQuanYi Micro Hei", "Helvetica Neue", Arial, sans-serif;font-size: 16px;text-align: start;white-space: normal;background-color: rgb(255, 255, 255);"><br></p> <section powered-by="xiumi.us" style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;background-color: rgb(255, 255, 255);text-align: center;color: rgb(62, 71, 83);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="margin-right: 16px;margin-left: 16px;max-width: 100%;min-height: 1em;letter-spacing: 1.5px;line-height: 1.5em;font-family: -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(77, 168, 238);box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 12px;letter-spacing: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;font-size: 17px;letter-spacing: 0.544px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 12px;box-sizing: border-box !important;overflow-wrap: break-word !important;">— 本文结束 —</span></strong></span></strong></span><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin-right: 16px;margin-left: 16px;max-width: 100%;min-height: 1em;letter-spacing: 1.5px;line-height: 1.5em;font-family: -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <section data-mpa-template="t" mpa-from-tpl="t" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-id="93709" mpa-from-tpl="t" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section mpa-from-tpl="t" style="padding: 5px;max-width: 100%;border-style: solid;border-width: 2px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section mpa-from-tpl="t" style="padding: 15px;max-width: 100%;border-style: dashed;border-width: 1px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section mpa-from-tpl="t" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <span data-role="width" data-width="80%" style="max-width: 100%;display: inline-block;width: 425.215px;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img border="0" class="__bg_gif" data-ratio="0.08658008658008658" data-type="gif" data-w="462" data-width="80%" height="" title="" width="80%" src="/upload/b0b0d65a8077fe5fc54ccd945913d458.png" style="box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 340.156px !important;"></span> </section> <p style="margin-top: 5px;margin-bottom: 5px;padding-right: 0em;padding-left: 0em;max-width: 100%;min-height: 1em;text-align: justify;letter-spacing: 1.5px;line-height: normal;color: rgb(136, 136, 136);font-size: 13px;box-sizing: border-box !important;overflow-wrap: break-word !important;">● <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA5NDg3MjAwMQ==&mid=2457103446&idx=1&sn=0d0c0cb83235675963be01cb7b8ddb7b&chksm=87c8c4f8b0bf4dee91ab4a8041363afc0839df2dbc219e2c0938ed2e53d13af4a966121314f4&scene=21#wechat_redirect" textvalue="漫谈设计模式在 Spring 框架中的良好实践" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">漫谈设计模式在 Spring 框架中的良好实践</a></p> <p style="margin-top: 5px;margin-bottom: 5px;padding-right: 0em;padding-left: 0em;max-width: 100%;min-height: 1em;text-align: justify;letter-spacing: 1.5px;line-height: normal;color: rgb(136, 136, 136);font-size: 13px;box-sizing: border-box !important;overflow-wrap: break-word !important;">● <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA5NDg3MjAwMQ==&mid=2457103280&idx=1&sn=f3bd921a2f88a9a3440c0ff1e03d1bd9&chksm=87c8c31eb0bf4a0820a572626141cfb1fc87ea1c7072a16f61992d67d21d9b61b556de2d6cd7&scene=21#wechat_redirect" textvalue="颠覆微服务认知:深入思考微服务的七个主流观点" data-itemshowtype="11" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">颠覆微服务认知:</a><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA5NDg3MjAwMQ==&mid=2457103280&idx=1&sn=f3bd921a2f88a9a3440c0ff1e03d1bd9&chksm=87c8c31eb0bf4a0820a572626141cfb1fc87ea1c7072a16f61992d67d21d9b61b556de2d6cd7&scene=21#wechat_redirect" textvalue="颠覆微服务认知:深入思考微服务的七个主流观点" data-itemshowtype="11" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">深入思考微服务的七个主流观点</a><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin-top: 5px;margin-bottom: 5px;padding-right: 0em;padding-left: 0em;max-width: 100%;min-height: 1em;text-align: justify;letter-spacing: 1.5px;line-height: normal;color: rgb(136, 136, 136);font-size: 13px;box-sizing: border-box !important;overflow-wrap: break-word !important;">● <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA5NDg3MjAwMQ==&mid=2457103129&idx=1&sn=3e0386d5f6f3b706e6bd72195648e34e&chksm=87c8c3b7b0bf4aa1530354a3b1507b33c5033db70e4c61328e9ed68118e24212a36d763671d8&scene=21#wechat_redirect" textvalue="人人都是 API 设计者" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">人人都是 API 设计者</a></p> <p style="margin-top: 5px;margin-bottom: 5px;padding-right: 0em;padding-left: 0em;max-width: 100%;min-height: 1em;text-align: justify;letter-spacing: 1.5px;line-height: normal;color: rgb(136, 136, 136);font-size: 13px;box-sizing: border-box !important;overflow-wrap: break-word !important;">● <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA5NDg3MjAwMQ==&mid=2457103538&idx=1&sn=9261bb2b742fd41168889738e0377a9c&chksm=87c8c41cb0bf4d0a5401fac49320faebfc4ac5ad7711d39758ecb0fd9df43354d19aa5aa57e3&scene=21#wechat_redirect" textvalue="一文讲透微服务下如何保证事务的一致性" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">一文讲透微服务下如何保证事务的一致性</a><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin-top: 5px;margin-bottom: 5px;padding-right: 0em;padding-left: 0em;max-width: 100%;min-height: 1em;text-align: justify;letter-spacing: 1.5px;line-height: normal;color: rgb(136, 136, 136);font-size: 13px;box-sizing: border-box !important;overflow-wrap: break-word !important;">● <a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA5NDg3MjAwMQ==&mid=2457103584&idx=1&sn=007226d602709eb3c840a0539dae678b&chksm=87c8c44eb0bf4d58e9aaba3221c0d9f61556f4a199691b428dd322231ab450023e748cfc620a&scene=21#wechat_redirect" textvalue="要黑盒测试微服务内部服务间调用,我该如何实现?" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">要黑盒测试微服务内部服务间调用,我该如何实现?</a><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> </section> </section> </section> </section> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br mpa-from-tpl="t" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> </section> </section> </section> </section> </section> </section> <section powered-by="xiumi.us" style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;background-color: rgb(255, 255, 255);text-align: center;color: rgb(62, 71, 83);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img data-ratio="0.3708738" data-type="png" data-w="515" src="/upload/328ca60e65e37255ffc9d00bfba58c3c.png" style="vertical-align: middle;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 515px !important;"></p> <p style="margin-right: 16px;margin-left: 16px;max-width: 100%;min-height: 1em;letter-spacing: 1.5px;line-height: 1.5em;font-family: -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;display: inline-block;width: 574px;vertical-align: top;border-style: solid;border-width: 1px;border-radius: 0px;border-color: rgb(225, 238, 226);background-color: rgba(191, 224, 216, 0.58);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="padding: 10px;max-width: 100%;display: inline-block;width: 572px;vertical-align: top;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section powered-by="xiumi.us" style="max-width: 100%;font-size: 15px;color: rgb(46, 101, 91);line-height: 1.8;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 12px;box-sizing: border-box !important;overflow-wrap: break-word !important;">关注我,回复 「加群」 加入各种主题讨论群。</span></p> </section> </section> </section> </section> </section> <section powered-by="xiumi.us" style="margin-top: 10px;max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;background-color: rgb(147, 195, 186);height: 2px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> </section> </section> </section> </section> </section> </section> </section> </section> </section> <section powered-by="xiumi.us" style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;background-color: rgb(255, 255, 255);text-align: center;color: rgb(62, 71, 83);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="margin-right: 16px;margin-left: 16px;max-width: 100%;min-height: 1em;letter-spacing: 1.5px;line-height: 1.5em;font-family: -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 12px;letter-spacing: 1px;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">对「服务端思维」有期待,请在文末点个<span style="max-width: 100%;color: rgb(198, 19, 25);box-sizing: border-box !important;overflow-wrap: break-word !important;">在看</span></span></strong></p> <p style="margin-right: 16px;margin-left: 16px;max-width: 100%;min-height: 1em;letter-spacing: 1.5px;line-height: 1.5em;font-family: -apple-system-font, BlinkMacSystemFont, Arial, sans-serif;box-sizing: border-box !important;overflow-wrap: break-word !important;"><strong style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;font-size: 12px;letter-spacing: 1px;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">喜欢这篇文章,欢迎<span style="max-width: 100%;color: rgb(198, 19, 25);box-sizing: border-box !important;overflow-wrap: break-word !important;">转发、分享</span>朋友圈</span></strong></p> </section> </section> </section> <p style="max-width: 100%;min-height: 1em;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(63, 63, 63);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 14px;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <section data-role="outer" label="Powered by 135editor.com" style="max-width: 100%;letter-spacing: 0.544px;white-space: normal;font-size: 16px;background-color: rgb(255, 255, 255);color: rgb(63, 63, 63);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-role="outer" label="Powered by 135editor.com" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-tools="135编辑器" data-id="94783" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;display: flex;justify-content: flex-end;align-items: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;width: 20px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="max-width: 100%;width: 20px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img data-ratio="1.037037037037037" data-type="png" data-w="27" data-width="100%" src="/upload/6087772642bee9a4b8104517c36c9aa7.png" style="display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 20px !important;"> </section> </section> <section style="max-width: 100%;display: inline-block;text-align: right;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-brushtype="text" style="margin-bottom: -15px;max-width: 100%;letter-spacing: 2px;transform: rotate(0deg);color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;"> 在看点这里 </section> </section> <section style="max-width: 100%;width: 22px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section style="margin-top: 15px;max-width: 100%;width: 22px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <img class="__bg_gif" data-ratio="1" data-type="gif" data-w="100" data-width="100%" src="/upload/8b34c0e8ddcf33f56770ae9f44c95ce1.png" style="display: block;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;width: 22px !important;"> </section> </section> </section> </section> </section> </section>
作者:微信小助手
<p style="letter-spacing: 0.544px;white-space: normal;font-size: 16px;background-color: rgb(255, 255, 255);color: rgb(0, 0, 0);font-family: PingFangSC-Light;text-align: center;" data-mpa-powered-by="yiban.io"><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;font-size: 12px;color: rgb(120, 114, 119);user-select: text !important;">点击上方 "</span><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;font-size: 12px;user-select: text !important;"><strong style="color: rgb(62, 62, 62);font-size: 14px;user-select: text !important;"><span style="letter-spacing: 0.544px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;color: rgb(61, 170, 214);user-select: text !important;">zhisheng</span></strong></span><span style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;font-size: 12px;color: rgb(120, 114, 119);user-select: text !important;">"关注, <span style="letter-spacing: 0.544px;user-select: text !important;">星标或置顶一起成长</span></span><br></p> <p style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;color: rgb(43, 43, 43);font-size: 16px;background-color: rgb(255, 255, 255);text-align: center;"><a target="_blank" href="https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&album_id=1337172142412169216&__biz=MzIxMTE0ODU5NQ==#wechat_redirect" textvalue="Flink 从入门到精通" tab="innerlink" data-linktype="2" style="color: rgb(120, 172, 254);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;letter-spacing: 0.544px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 13px;line-height: 1.75em;user-select: text !important;"><span style="letter-spacing: 0.544px;line-height: 1.75em;user-select: text !important;">Flink 从入门到精通</span></a><span style="letter-spacing: 0.544px;color: rgb(136, 136, 136);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 13px;line-height: 1.75em;user-select: text !important;"> 系列文章</span></p> <p style="white-space: normal;"><strong style="color: rgb(255, 104, 39);font-size: 20px;">前言</strong><br></p> <p style="white-space: normal;"><strong style="color: rgb(255, 104, 39);font-size: 20px;"><br></strong></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="background-color: rgb(255, 255, 255);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;">Flink和ClickHouse分别是实时计算和(近实时)OLAP领域的翘楚,也是近些年非常火爆的开源框架,很多大厂都在将两者结合使用来构建各种用途的实时平台,效果很好。</span><span style="background-color: rgb(255, 255, 255);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;">关于两者的优点就不再赘述,本文来简单介绍笔者团队在点击流实时数仓方面的一点实践经验。</span><br></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="background-color: rgb(255, 255, 255);font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;"><br></span></p> <h3><span style="color: rgb(255, 104, 39);font-size: 20px;"><strong>点击流及其维度建模</strong></span></h3> <p><span style="color: rgb(255, 104, 39);font-size: 20px;"><strong><br></strong></span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">所谓点击流(click stream),就是指用户访问网站、App等Web前端时在后端留下的轨迹数据,也是流量分析(traffic analysis)和用户行为分析(user behavior analysis)的基础。点击流数据一般以访问日志和埋点日志的形式存储,其特点是量大、维度丰富。以我们一个中等体量的普通电商平台为例,每天产生约200GB左右、数十亿条的原始日志,埋点事件100+个,涉及50+个维度。</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">按照Kimball的维度建模理论,点击流数仓遵循典型的星形模型,简图如下。</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"><br></span></p> <p><img data-ratio="0.6771561771561772" src="/upload/8567f74724e6d65cb94fe6e5554785ce.png" data-type="png" data-w="858"></p> <p><br></p> <h3><span style="color: rgb(255, 104, 39);font-size: 20px;"><strong>点击流数仓分层设计</strong></span></h3> <p><span style="color: rgb(255, 104, 39);font-size: 20px;"><strong><br></strong></span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">点击流实时数仓的分层设计仍然可以借鉴传统数仓的方案,以扁平为上策,尽量减少数据传输中途的延迟。简图如下。</span></p> <p><img data-ratio="0.8145161290322581" src="/upload/8e3e21543b8b119be7da376bcafce7a5.png" data-type="png" data-w="992"></p> <p><br></p> <ul class="list-paddingleft-2" style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"> <li style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">DIM层:维度层,MySQL镜像库,存储所有维度数据。</span></p></li> <li style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">ODS层:贴源层,原始数据由Flume直接进入Kafka的对应topic。</span></p></li> <li style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">DWD层:明细层,通过Flink将Kafka中数据进行必要的ETL与实时维度join操作,形成规范的明细数据,并写回Kafka以便下游与其他业务使用。再通过Flink将明细数据分别写入ClickHouse和Hive打成大宽表,前者作为查询与分析的核心,后者作为备份和数据质量保证(对数、补数等)。</span></p></li> <li style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">DWS层:服务层,部分指标通过Flink实时汇总至Redis,供大屏类业务使用。更多的指标则通过ClickHouse物化视图等机制周期性汇总,形成报表与页面热力图。特别地,部分明细数据也在此层开放,方便高级BI人员进行漏斗、留存、用户路径等灵活的ad-hoc查询,这些也是ClickHouse远超过其他OLAP引擎的强大之处。</span></p><p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"></span></p></li> </ul> <h3><span style="color: rgb(255, 104, 39);font-size: 20px;"><strong>要点与注意事项</strong></span></h3> <p><span style="color: rgb(255, 104, 39);font-size: 20px;"><strong><br></strong></span></p> <h4 style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><strong><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">Flink实时维度关联</span></strong><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"></span></h4> <p><strong><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"><br></span></strong></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">Flink框架的异步I/O机制为用户在流式作业中访问外部存储提供了很大的便利。针对我们的情况,有以下三点需要注意:</span></p> <ul class="list-paddingleft-2" style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"> <li style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">使用异步MySQL客户端,如Vert.x MySQL Client。</span></p></li> <li style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">AsyncFunction内添加内存缓存(如Guava Cache、Caffeine等),并设定合理的缓存驱逐机制,避免频繁请求MySQL库。</span></p></li> <li style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">实时维度关联仅适用于缓慢变化维度,如地理位置信息、商品及分类信息等。快速变化维度(如用户信息)则不太适合打进宽表,我们采用MySQL表引擎将快变维度表直接映射到ClickHouse中,而ClickHouse支持异构查询,也能够支撑规模较小的维表join场景。未来则考虑使用MaterializedMySQL引擎(当前仍未正式发布)将部分维度表通过binlog镜像到ClickHouse。</span></p></li> </ul> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"><br></span></p> <h4 style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><strong><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">Flink-ClickHouse Sink设计</span></strong><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"></span></h4> <p><strong><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"><br></span></strong></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">可以通过JDBC(flink-connector-jdbc)方式来直接写入ClickHouse,但灵活性欠佳。好在clickhouse-jdbc项目提供了适配ClickHouse集群的BalancedClickhouseDataSource组件,我们基于它设计了Flink-ClickHouse Sink,要点有三:</span></p> <ul class="list-paddingleft-2" style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"> <li style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">写入本地表,而非分布式表,老生常谈了。</span></p></li> <li style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">按数据批次大小以及批次间隔两个条件控制写入频率,在part merge压力和数据实时性两方面取得平衡。目前我们采用10000条的批次大小与15秒的间隔,只要满足其一则触发写入。</span></p></li> <li style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">BalancedClickhouseDataSource通过随机路由保证了各ClickHouse实例的负载均衡,但是只是通过周期性ping来探活,并屏蔽掉当前不能访问的实例,而没有故障转移——亦即一旦试图写入已经失败的节点,就会丢失数据。为此我们设计了重试机制,重试次数和间隔均可配置,如果当重试机会耗尽后仍然无法成功写入,就将该批次数据转存至配置好的路径下,并报警要求及时检查与回填。</span></p><p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"></span></p></li> </ul> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">当前我们仅实现了DataStream API风格的Flink-ClickHouse Sink,随着Flink作业SQL化的大潮,在未来还计划实现SQL风格的ClickHouse Sink,打磨健壮后会适时回馈给社区。另外,除了随机路由,我们也计划加入轮询和sharding key hash等更灵活的路由方式。</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"><br></span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">还有一点就是,ClickHouse并不支持事务,所以也不必费心考虑2PC Sink等保证exactly once语义的操作。如果Flink到ClickHouse的链路出现问题导致作业重启,作业会直接从最新的位点(即Kafka的latest offset)开始消费,丢失的数据再经由Hive进行回填即可。</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"><br></span></p> <h4 style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><strong><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">ClickHouse数据重平衡</span></strong><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"></span></h4> <p><strong><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"><br></span></strong></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">ClickHouse集群扩容之后,数据的重平衡(reshard)是一件麻烦事,因为不存在类似HDFS Balancer这种开箱即用的工具。一种比较简单粗暴的思路是修改ClickHouse配置文件中的shard weight,使新加入的shard多写入数据,直到所有节点近似平衡之后再调整回来。但是这会造成明显的热点问题,并且仅对直接写入分布式表才有效,并不可取。</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"><br></span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;">因此,我们采用了一种比较曲折的方法:将原表重命名,在所有节点上建立与原表schema相同的新表,将实时数据写入新表,同时用clickhouse-copier工具将历史数据整体迁移到新表上来,再删除原表。当然在迁移期间,被重平衡的表是无法提供服务的,仍然不那么优雅。如果大佬们有更好的方案,欢迎交流。</span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"><br></span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="font-size: 10px;"><span style="font-size: 10px;max-width: 100%;font-family: Optima-Regular, PingFangTC-light;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;overflow-wrap: break-word !important;">本文</span><span style="font-size: 10px;background-color: rgb(255, 255, 255);font-family: Optima-Regular, PingFangTC-light;letter-spacing: 2px;text-align: left;">链接:https://blog.csdn.net/nazeniwaresakini/article/details/108846835</span></span></p> <p style="max-width: 100%;min-height: 1em;font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif;letter-spacing: 0.5440000295639038px;white-space: normal;line-height: 2em;box-sizing: border-box !important;word-wrap: break-word !important;"><span style="max-width: 100%;font-family: Optima-Regular, PingFangTC-light;font-size: 15px;letter-spacing: 2px;text-align: left;background-color: rgb(255, 255, 255);box-sizing: border-box !important;word-wrap: break-word !important;"><br></span></p> <p><br></p> <pre style="letter-spacing: 0.544px;font-size: 16px;text-align: start;background-color: rgb(255, 255, 255);word-spacing: 2px;widows: 1;caret-color: rgb(255, 0, 0);color: rgb(89, 89, 89);user-select: text !important;"> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="margin-top: -10px;padding-right: 10px;padding-left: 10px;white-space: normal;line-height: 1.6;word-break: break-word;text-align: center;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 15px;letter-spacing: 0.05em;user-select: text !important;"> <img class="rich_pages __bg_gif" data-ratio="0.18524332810047095" data-type="gif" data-w="637" src="/upload/d2a38b8f8a4c599687e2292f14dfd57b.png" style="background-color: rgb(238, 237, 235);border-width: 1px;border-style: solid;border-color: rgb(238, 237, 235);background-size: 22px;background-position: center center;background-repeat: no-repeat;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;caret-color: rgb(51, 51, 51);color: rgb(62, 62, 62);box-sizing: border-box !important;user-select: text !important;visibility: visible !important;width: 220px !important;"> </section> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="margin-top: -10px;padding-right: 10px;padding-left: 10px;white-space: normal;line-height: 1.6;word-break: break-word;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;font-size: 15px;letter-spacing: 0.05em;user-select: text !important;"> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="margin-top: -10px;padding-right: 10px;padding-left: 10px;line-height: 1.6;word-break: break-word;text-align: center;letter-spacing: 0.05em;user-select: text !important;"> <section style="margin-top: 10px;margin-bottom: 10px;line-height: 26px;color: rgb(1, 1, 1);user-select: text !important;"> <br style="user-select: text !important;"> </section> </section> </section> <section data-mpa-template="t" mpa-paragraph-type="ignored" style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);font-size: 15px;user-select: text !important;"> <ul class="list-paddingleft-2" style="width: 577.422px;user-select: text !important;"> <li style="user-select: text !important;"><p style="margin-top: 5px;margin-bottom: 5px;line-height: normal;user-select: text !important;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzIxMTE0ODU5NQ==&mid=2650239332&idx=1&sn=bd47b1018a7b3e34506a3bacece6c088&chksm=8f5a1b38b82d922e25e6efbbe132d3c7d57e53ae204ecce2db73a8d4633b1c89d90a87b2656b&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;user-select: text !important;">基于 Apache Flink 的实时监控告警系统</a></p></li> <li style="user-select: text !important;"><p style="margin-top: 5px;margin-bottom: 5px;line-height: normal;user-select: text !important;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzIxMTE0ODU5NQ==&mid=2650239535&idx=1&sn=f70cc6fb3ba3559554e68c8735fef442&chksm=8f5a1873b82d916554a2a557a5cf911e9e7e55166677a01c9e915484ef357f98b35a79106963&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;user-select: text !important;">关于数据中台的深度思考与总结(干干货)</a></p></li> <li style="user-select: text !important;"><p style="margin-top: 5px;margin-bottom: 5px;line-height: normal;user-select: text !important;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzIxMTE0ODU5NQ==&mid=2650239084&idx=2&sn=11e5feffe499d9f7e97b2a7af9286e76&chksm=8f5a1a30b82d932696dcb11b547391a3651ccb063d6ebb727e921c9d35e8ff1911cfbf0d6ce0&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;user-select: text !important;">日志收集Agent,阴暗潮湿的地底世界</a><br style="user-select: text !important;"></p></li> <li style="user-select: text !important;"><p style="margin-top: 5px;margin-bottom: 5px;line-height: normal;user-select: text !important;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzIxMTE0ODU5NQ==&mid=2650238911&idx=1&sn=7b384c92896263171a925909dfcf66fb&chksm=8f5a05e3b82d8cf5e33d6034c420ee62474dbf3db18e3ca0f09fc28f2f9d50e98e801bae1995&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;user-select: text !important;">2020 继续踏踏实实的做好自己</a></p></li> </ul> </section></pre> <p style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);widows: 1;word-spacing: 2px;caret-color: rgb(255, 0, 0);font-size: 15px;color: rgb(62, 62, 62);text-align: center;user-select: text !important;"><img class="rich_pages" data-ratio="0.44" data-s="300,640" data-type="jpeg" data-w="500" src="/upload/95163402322e6a001b2f4d7e3281693.jpg" style="box-sizing: border-box !important;user-select: text !important;visibility: visible !important;width: 500px !important;"></p> <p style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);widows: 1;word-spacing: 2px;caret-color: rgb(255, 0, 0);font-size: 15px;color: rgb(62, 62, 62);text-align: center;user-select: text !important;"><br style="user-select: text !important;"></p> <p style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);widows: 1;word-spacing: 2px;caret-color: rgb(255, 0, 0);font-size: 15px;color: rgb(62, 62, 62);text-align: center;user-select: text !important;"><br style="user-select: text !important;"></p> <p style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);widows: 1;word-spacing: 2px;caret-color: rgb(255, 0, 0);font-size: 15px;color: rgb(62, 62, 62);text-align: center;user-select: text !important;"><img class="rich_pages" data-ratio="0.3310344827586207" data-s="300,640" data-type="png" data-w="1885" src="/upload/cd96652cff648c17bb36ef28b66ef3e3.png" style="box-sizing: border-box !important;user-select: text !important;visibility: visible !important;width: 677px !important;"></p> <pre style="letter-spacing: 0.544px;background-color: rgb(255, 255, 255);widows: 1;word-spacing: 2px;caret-color: rgb(255, 0, 0);font-size: 15px;color: rgb(62, 62, 62);text-align: center;line-height: inherit;user-select: text !important;"> <section class="js_darkmode__75" mpa-from-tpl="t" data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" data-style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif; white-space: normal; background-color: rgb(255, 255, 255); color: rgb(62, 62, 62); text-align: start; font-size: 14px; letter-spacing: 0.5px; word-spacing: 2px; user-select: text !important;" style="white-space: normal;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 14px;letter-spacing: 0.5px;user-select: text !important;"> <section data-mpa-template-id="1480331" data-mpa-color="null" data-mpa-category="收藏" mpa-from-tpl="t" data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="user-select: text !important;"> <section data-tools="135编辑器" data-id="89715" mpa-from-tpl="t" data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="font-size: 16px;border-width: 0px;border-style: none;border-color: initial;user-select: text !important;"> <section data-mpa-template-id="1252" data-mpa-color="#ffffff" data-mpa-category="divider" mpa-from-tpl="t" data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="font-size: 14px;user-select: text !important;"> <section mpa-from-tpl="t" data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="user-select: text !important;"> <p data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="letter-spacing: 0.544px;user-select: text !important;"><br style="user-select: text !important;"></p> <p data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="letter-spacing: 0.544px;text-align: left;user-select: text !important;"><span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(230, 230, 230)" data-style="letter-spacing: 0.544px; font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif; font-size: 12px; color: rgb(0, 0, 0); user-select: text !important;" class="js_darkmode__77" style="color: rgb(0, 0, 0);letter-spacing: 0.544px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 12px;user-select: text !important;">公众号</span><span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="letter-spacing: 0.544px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 12px;user-select: text !important;">(</span><strong data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="letter-spacing: 0.544px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;user-select: text !important;"><span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(224, 40, 91)" data-style="font-size: 12px; color: rgb(171, 25, 66); user-select: text !important;" class="js_darkmode__78" style="color: rgb(171, 25, 66);font-size: 12px;user-select: text !important;">zhisheng</span></strong><span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="letter-spacing: 0.544px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 12px;user-select: text !important;">)</span><span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(230, 230, 230)" data-style="letter-spacing: 0.544px; font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif; font-size: 12px; color: rgb(0, 0, 0); user-select: text !important;" class="js_darkmode__79" style="color: rgb(0, 0, 0);letter-spacing: 0.544px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 12px;user-select: text !important;">里回复</span><span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="letter-spacing: 0.544px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 12px;user-select: text !important;"> <span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="color: rgb(255, 41, 65);user-select: text !important;">面经、ClickHouse、<span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="letter-spacing: 0.544px;user-select: text !important;">ES、<span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="letter-spacing: 0.544px;user-select: text !important;">Flink、</span></span></span> <span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="color: rgb(255, 41, 65);letter-spacing: 0.544px;user-select: text !important;">Spring、<span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="letter-spacing: 0.544px;user-select: text !important;">Java、<span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="letter-spacing: 0.544px;user-select: text !important;">Kafka、<span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(168, 168, 168)" style="letter-spacing: 0.544px;user-select: text !important;">监控 </span></span></span></span></span><span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(230, 230, 230)" data-style="letter-spacing: 0.544px; font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif; color: rgb(0, 0, 0); font-size: 12px; user-select: text !important;" class="js_darkmode__80" style="color: rgb(0, 0, 0);letter-spacing: 0.544px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 12px;user-select: text !important;"><span data-darkmode-bgcolor="rgb(36, 36, 36)" data-darkmode-color="rgb(230, 230, 230)" style="letter-spacing: 0.544px;user-select: text !important;">等关键字</span>可以查看更多关键字对应的文章。</span><br style="user-select: text !important;"></p> </section> </section> </section> </section> </section></pre> <pre style="letter-spacing: 0.544px;font-size: 16px;background-color: rgb(255, 255, 255);color: rgb(89, 89, 89);text-align: start;widows: 1;word-spacing: 2px;caret-color: rgb(255, 0, 0);user-select: text !important;"> <section mpa-from-tpl="t" style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;user-select: text !important;"> <section data-mpa-template-id="1480331" data-mpa-color="null" data-mpa-category="收藏" mpa-from-tpl="t" style="user-select: text !important;"> <section data-tools="135编辑器" data-id="89715" mpa-from-tpl="t" style="border-width: 0px;border-style: none;border-color: initial;user-select: text !important;"> <section data-mpa-template-id="1252" data-mpa-color="#ffffff" data-mpa-category="divider" mpa-from-tpl="t" style="color: rgb(62, 62, 62);font-size: 14px;letter-spacing: 0.5px;user-select: text !important;"> <section mpa-from-tpl="t" style="user-select: text !important;"> <section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding: 10px;font-size: 16px;color: black;line-height: 1.6;letter-spacing: 0px;word-break: break-word;font-family: PingFangSC-Light;user-select: text !important;"> <section data-role="outer" label="Powered by 135editor.com" style="letter-spacing: 0.544px;user-select: text !important;"> <section data-role="outer" label="Powered by 135editor.com" style="user-select: text !important;"> <section data-tools="135编辑器" data-id="94250" style="user-select: text !important;"> <section data-tools="135编辑器" data-id="91842" style="border-color: currentcolor;border-style: none;border-width: 0px;user-select: text !important;"> <section style="text-align: right;width: auto;user-select: text !important;"> <section style="display: inline-block;clear: both;user-select: text !important;"> <section data-brushtype="text" style="padding: 18px 15px 20px 10px;color: rgb(86, 146, 214);background-image: url("https://mmbiz.qpic.cn/mmbiz_png/7QRTvkK2qC6hzicPF91rs9ItM18PtNACZj3MJMA9biczdQx5KOicGjX5c8Ty6j7NQ04wQJpM3bZSTp6DrLiaCicxJAw/640?wx_fmt=png");background-repeat: no-repeat;text-align: center;background-size: 100% 100%;letter-spacing: 1.5px;user-select: text !important;"> <section style="display: flex;justify-content: center;align-items: center;user-select: text !important;"> <section data-brushtype="text" style="font-size: 14px;color: rgb(51, 51, 51);user-select: text !important;"> <span style="letter-spacing: 0.544px;text-align: right;font-size: 16px;white-space: pre-line;caret-color: rgb(63, 63, 63);color: rgb(216, 79, 169);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-weight: bold;">点个赞+在看,少个 bug</span> <span style="letter-spacing: 0.544px;text-align: right;font-size: 16px;color: rgb(63, 63, 63);font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;"> </span> <span style="letter-spacing: 0.544px;text-align: right;font-size: 16px;white-space: pre-line;color: rgb(0, 179, 139);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-weight: bold;">👇</span> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section> </section></pre>
作者:微信小助手
<section style="font-size: 15px;color: rgb(62, 62, 62);line-height: 1.6;letter-spacing: 0px;font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;" data-mpa-powered-by="yiban.io"> <p style="margin-bottom: 10px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);font-size: 15px;background-color: rgb(255, 255, 255);line-height: normal;text-align: center;"><span style="font-size: 14px;letter-spacing: 0.544px;word-spacing: 2px;color: rgb(136, 136, 136);">点击蓝色“</span><span style="font-size: 14px;letter-spacing: 0.544px;word-spacing: 2px;color: rgb(0, 128, 255);">架构文摘</span><span style="font-size: 14px;letter-spacing: 0.544px;word-spacing: 2px;color: rgb(136, 136, 136);">”关注我哟</span></p> <p style="margin-bottom: 10px;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);font-size: 15px;background-color: rgb(255, 255, 255);text-size-adjust: auto;word-spacing: 2px;text-align: center;"><span style="font-size: 14px;color: rgb(136, 136, 136);">加个“</span><span style="color: rgb(0, 128, 255);font-size: 14px;">星标</span><span style="font-size: 14px;color: rgb(136, 136, 136);">”,每天上午 09:25,干货推送!</span></p> <p style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;color: rgb(62, 62, 62);font-size: 14px;background-color: rgb(255, 255, 255);text-align: center;"><img data-backh="36" data-backw="578" data-ratio="0.0625" data-s="300,640" data-type="jpeg" data-w="640" width="100%" src="/upload/8c292e55ba5a23cb6ebc11f2a2c4fece.jpg" style="font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;widows: 1;word-spacing: 2px;color: rgb(136, 136, 136);box-sizing: border-box !important;visibility: visible !important;width: 677px !important;"></p> <p style="font-size: inherit;color: inherit;line-height: inherit;"><span style="color: rgb(136, 136, 136);"><em><span style="color: rgb(136, 136, 136);font-size: 12px;">来源:https://juejin.im/post/6863283398727860238<br></span></em></span></p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">一、ClickHouse 是什么?</span></h3> <blockquote style="line-height: inherit;padding: 15px 15px 15px 1rem;font-size: 0.9em;color: rgb(129, 145, 152);border-left-width: 6px;border-left-color: rgb(220, 230, 240);background: rgb(242, 247, 251);overflow: auto;overflow-wrap: normal;word-break: normal;"> <p style="font-size: inherit;color: inherit;line-height: inherit;">ClickHouse:是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)</p> </blockquote> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">我们首先理清一些基础概念</p> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-2"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">OLTP:是传统的关系型数据库,主要操作增删改查,强调事务一致性,比如银行系统、电商系统</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">OLAP:是仓库型数据库,主要是读取数据,做复杂数据分析,侧重技术决策支持,提供直观简单的结果</span></p></li> </ul> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">接着我们用图示,来理解一下 <strong style="font-size: inherit;color: inherit;line-height: inherit;">列式数据库</strong> 和 <strong style="font-size: inherit;color: inherit;line-height: inherit;">行式数据库</strong> 区别</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">在传统的行式数据库系统中(MySQL、Postgres和MS SQL Server),数据按如下顺序存储:</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img data-ratio="0.322463768115942" src="/upload/12a58913dfc75f72c8e286d805441f42.png" data-type="png" data-w="1656" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <br>在列式数据库系统中(ClickHouse),数据按如下的顺序存储: <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img data-ratio="0.3804347826086957" src="/upload/fb0957aceb1d09b9768817003e1d83c9.png" data-type="png" data-w="1656" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">两者在存储方式上对比:</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img data-ratio="0.6840659340659341" src="/upload/44373bcebb1303210df67e7d719b23c2.png" data-type="png" data-w="1456" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">以上是ClickHouse基本介绍,更多可以查阅</p> <blockquote style="line-height: inherit;padding: 15px 15px 15px 1rem;font-size: 0.9em;color: rgb(129, 145, 152);border-left-width: 6px;border-left-color: rgb(220, 230, 240);background: rgb(242, 247, 251);overflow: auto;overflow-wrap: normal;word-break: normal;"> <p style="font-size: inherit;color: inherit;line-height: inherit;">官方手册: https://clickhouse.tech/docs/zh/</p> </blockquote> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">二、业务问题</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">业务端现有存储在Mysql中,5000万数据量的大表及两个辅表,单次联表查询开销在3min+,执行效率极低。经过索引优化、水平分表、逻辑优化,成效较低,因此决定借助ClickHouse来解决此问题</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">最终通过优化, <strong style="font-size: inherit;color: inherit;line-height: inherit;">查询时间降低至1s内,查询效率提升200倍!</strong></p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">希望通过本文,可以帮助大家快速掌握这一利器,并能在实践中少走弯路。</p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">三、ClickHouse实践</span></h3> <h5 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">1.Mac下的Clickhouse安装</span></h5> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">我是通过docker安装:</p> <blockquote style="line-height: inherit;padding: 15px 15px 15px 1rem;font-size: 0.9em;color: rgb(129, 145, 152);border-left-width: 6px;border-left-color: rgb(220, 230, 240);background: rgb(242, 247, 251);overflow: auto;overflow-wrap: normal;word-break: normal;"> <p style="font-size: inherit;color: inherit;line-height: inherit;">查看教程:https://blog.csdn.net/qq_24993831/article/details/103715194</p> </blockquote> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">也可以下载CK编译安装,相对麻烦一些。</p> <h5 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">2.数据迁移:从Mysql到ClickHouse</span></h5> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">ClickHouse支持Mysql大多数语法,迁移成本低,目前有 五种迁移 方案:</p> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-2"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">create table engin mysql,映射方案数据还是在Mysql</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">insert into select from,先建表,在导入</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">create table as select from,建表同时导入</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">csv离线导入</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">streamsets</span></p></li> </ul> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">选择第三种方案做数据迁移:</p> <pre style="font-size: inherit;color: inherit;line-height: inherit;"><code style="margin-right: 2px;margin-left: 2px;line-height: 18px;font-size: 14px;letter-spacing: 0px;font-family: Consolas, Inconsolata, Courier, monospace;border-radius: 0px;color: rgb(169, 183, 198);background: rgb(40, 43, 46);padding: 0.5em;overflow-wrap: normal !important;word-break: normal !important;overflow: auto !important;display: -webkit-box !important;"><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">CREATE</span> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">TABLE</span> [<span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">IF</span> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">NOT</span> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">EXISTS</span>] [db.]table_name <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">ENGINE</span> = Mergetree <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">AS</span> <span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">SELECT</span> *<br><span style="font-size: inherit;line-height: inherit;color: rgb(248, 35, 117);overflow-wrap: inherit !important;word-break: inherit !important;">FROM</span> mysql(<span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'host:port'</span>, <span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'db'</span>, <span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'database'</span>, <span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'user'</span>, <span style="font-size: inherit;line-height: inherit;color: rgb(238, 220, 112);overflow-wrap: inherit !important;word-break: inherit !important;">'password'</span>) <br></code></pre> <h5 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">3.性能测试对比</span></h5> <table> <thead style="font-size: inherit;color: inherit;line-height: inherit;"> <tr style="font-size: inherit;color: inherit;line-height: inherit;border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <th style="color: inherit;line-height: inherit;font-size: 1em;border-top-width: 1px;border-color: rgb(204, 204, 204);padding: 0.5em 1em;text-align: left;background-color: rgb(240, 240, 240);">类型</th> <th style="color: inherit;line-height: inherit;font-size: 1em;border-top-width: 1px;border-color: rgb(204, 204, 204);padding: 0.5em 1em;text-align: left;background-color: rgb(240, 240, 240);">数据量</th> <th style="color: inherit;line-height: inherit;font-size: 1em;border-top-width: 1px;border-color: rgb(204, 204, 204);padding: 0.5em 1em;text-align: left;background-color: rgb(240, 240, 240);" width="52">表大小</th> <th style="color: inherit;line-height: inherit;font-size: 1em;border-top-width: 1px;border-color: rgb(204, 204, 204);padding: 0.5em 1em;text-align: left;background-color: rgb(240, 240, 240);" width="17">查询速度</th> </tr> </thead> <tbody style="font-size: inherit;color: inherit;line-height: inherit;border-width: 0px;border-style: initial;border-color: initial;"> <tr style="font-size: inherit;color: inherit;line-height: inherit;border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="color: inherit;line-height: inherit;font-size: 1em;border-color: rgb(204, 204, 204);padding: 0.5em 1em;">Mysql</td> <td style="color: inherit;line-height: inherit;font-size: 1em;border-color: rgb(204, 204, 204);padding: 0.5em 1em;">5000万</td> <td style="color: inherit;line-height: inherit;font-size: 1em;border-color: rgb(204, 204, 204);padding: 0.5em 1em;" width="62">10G</td> <td style="color: inherit;line-height: inherit;font-size: 1em;border-color: rgb(204, 204, 204);padding: 0.5em 1em;word-break: break-all;" width="17">205s</td> </tr> <tr style="font-size: inherit;color: inherit;line-height: inherit;border-width: 1px 0px 0px;border-right-style: initial;border-bottom-style: initial;border-left-style: initial;border-right-color: initial;border-bottom-color: initial;border-left-color: initial;border-top-style: solid;border-top-color: rgb(204, 204, 204);background-color: white;"> <td style="color: inherit;line-height: inherit;font-size: 1em;border-color: rgb(204, 204, 204);padding: 0.5em 1em;word-break: break-all;">ClickHouse</td> <td style="color: inherit;line-height: inherit;font-size: 1em;border-color: rgb(204, 204, 204);padding: 0.5em 1em;word-break: break-all;">5000万</td> <td style="color: inherit;line-height: inherit;font-size: 1em;border-color: rgb(204, 204, 204);padding: 0.5em 1em;word-break: break-all;" width="72">600MB</td> <td style="color: inherit;line-height: inherit;font-size: 1em;border-color: rgb(204, 204, 204);padding: 0.5em 1em;" width="17">1s内</td> </tr> </tbody> </table> <h5 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">4.数据同步方案</span></h5> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;"><strong style="font-size: inherit;color: inherit;line-height: inherit;">临时表</strong></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img data-ratio="1.3266533066132264" src="/upload/a02d463f91bea1dbe1e0ce4c535fcb43.png" data-type="png" data-w="499" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">新建temp中间表,将Mysql数据全量同步到ClickHouse内temp表,再替换原ClickHouse中的表,适用数据量适度,增量和变量频繁的场景</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;"><strong style="font-size: inherit;color: inherit;line-height: inherit;">synch</strong></p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img data-ratio="0.8185053380782918" src="/upload/d9ee1aa551c8da77722ffc998587566d.png" data-type="png" data-w="1124" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">开源的同步软件推荐:</p> <blockquote style="line-height: inherit;padding: 15px 15px 15px 1rem;font-size: 0.9em;color: rgb(129, 145, 152);border-left-width: 6px;border-left-color: rgb(220, 230, 240);background: rgb(242, 247, 251);overflow: auto;overflow-wrap: normal;word-break: normal;"> <p style="font-size: inherit;color: inherit;line-height: inherit;">synch: https://github.com/long2ice/synch/blob/dev/README-zh.md</p> </blockquote> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">原理是通过Mysql的binlog日志,获取sql语句,再通过消息队列消费task</p> <h5 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">5.ClickHouse为什么快?</span></h5> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-2"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">只需要读取要计算的列数据,而非行式的整行数据读取,降低IO cost</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">同列同类型,有十倍压缩提升,进一步降低IO</span></p></li> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">clickhouse根据不同存储场景,做个性化搜索算法</span></p></li> </ul> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">四、遇到的坑</span></h3> <h5 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">1.ClickHouse与mysql数据类型差异性</span></h5> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">用Mysql的语句查询,发现报错:</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img data-ratio="0.05253623188405797" src="/upload/bcfc619549f618b176e3758c6d421516.png" data-type="png" data-w="1104" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;"><strong style="font-size: inherit;color: inherit;line-height: inherit;">解决方案</strong> :LEFT JOIN B b ON toUInt32(h.id) =<br>toUInt32(ec.post_id),中转一下,统一无符号类型关联</p> <h5 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1em;"><span style="font-size: inherit;color: inherit;line-height: inherit;">2.删除或更新是异步执行,只保证最终一致性</span></h5> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">查询CK手册发现,即便对数据一致性支持最好的Mergetree,也只是保证最终一致性:</p> <figure style="font-size: inherit;color: inherit;line-height: inherit;"> <img data-ratio="0.3111668757841907" src="/upload/6fed46dfe0ae1fb78079d79c267822c4.png" data-type="png" data-w="1594" style="font-size: inherit;color: inherit;line-height: inherit;display: block;margin-right: auto;margin-left: auto;" title=""> </figure> <br>如果对数据一致性要求较高,推荐大家做全量同步来解决 <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;"><br></p> <h3 style="color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;font-weight: bold;font-size: 1.3em;border-bottom: 2px solid rgb(0, 172, 193);"><span style="font-size: inherit;line-height: inherit;display: inline-block;font-weight: normal;background: rgb(0, 172, 193);color: rgb(255, 255, 255);padding-top: 3px;padding-right: 10px;padding-left: 10px;border-top-right-radius: 3px;border-top-left-radius: 4px;margin-right: 2px;">五、总结</span></h3> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">通过ClickHouse实践,完美的解决了Mysql查询瓶颈,20亿行以下数据量级查询,90%都可以在1s内给到结果,随着数据量增加,ClickHouse同样也支持集群,大家如果感兴趣,可以积极尝试</p> <p style="font-size: inherit;color: inherit;line-height: inherit;margin-top: 1.5em;margin-bottom: 1.5em;">参考资料:</p> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;" class="list-paddingleft-2"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p>ClickHouse官方手册</p></li> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;list-style-type: square;" class="list-paddingleft-2"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">https://clickhouse.tech/docs/zh/)</span></p></li> </ul> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p>ClickHouse在携程酒店应用</p></li> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;list-style-type: square;" class="list-paddingleft-2"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">https://cloud.tencent.com/developer/article/1462633</span></p></li> </ul> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p>ClickHouse引擎怎么选</p></li> <ul style="font-size: inherit;color: inherit;line-height: inherit;padding-left: 32px;list-style-type: square;" class="list-paddingleft-2"> <li style="font-size: inherit;color: inherit;line-height: inherit;margin-bottom: 0.5em;"><p><span style="font-size: inherit;color: inherit;line-height: inherit;">https://developer.aliyun.com/article/762461</span></p></li> </ul> </ul> </section> <p><br></p> <pre style="font-size: 16px;color: rgb(62, 62, 62);letter-spacing: 1px;text-align: start;widows: 1;word-spacing: 1px;caret-color: rgb(255, 0, 0);background-color: rgb(255, 255, 255);"> <section data-mpa-template="t" mpa-from-tpl="t" style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;caret-color: rgb(0, 0, 0);color: rgb(120, 114, 114);word-spacing: 2px;"> <section data-id="89429" mpa-from-tpl="t" style="border-width: 0px;border-style: none;border-color: initial;"> <section mpa-from-tpl="t" style="text-align: center;height: 50px;"> <section mpa-from-tpl="t" style="margin-right: auto;margin-left: auto;width: 48px;height: 48px;color: rgb(255, 255, 255);line-height: 48px;display: inline-block;background-image: url("https://mmbiz.qpic.cn/mmbiz_gif/kiaqiahsnxHd4Zt4378tqib1DnnfKYvZAI7sUNZCYmGN2HCMDFDYV5hLu6HrHIK5BynAAwgHGiafFFU7ibYez6mXL4w/640?wx_fmt=gif");background-repeat: no-repeat;background-size: 100%;background-position: 0px center;"> <p style="font-weight: bold;"><span style="font-size: 14px;">end</span></p> </section> <section mpa-from-tpl="t" style="margin-top: -26px;height: 2px;background-color: rgb(34, 33, 33);"> <br> </section> </section> </section> </section><p style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;"><br></p> <section mpa-from-tpl="t" style="padding-left: 5px;letter-spacing: 0.544px;white-space: normal;caret-color: rgb(0, 0, 0);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: medium;word-spacing: 2px;border-left: 5px solid rgb(51, 51, 51);line-height: 1.5em;"> <section powered-by="xiumi.us" mpa-from-tpl="t"> <section mpa-from-tpl="t"> <section mpa-from-tpl="t" style="font-size: 18px;"> <p><span style="font-size: 16px;">推荐阅读:</span></p> </section> </section> </section> </section> <ul class="list-paddingleft-2" mpa-from-tpl="t" style="letter-spacing: 0.544px;white-space: normal;caret-color: rgb(0, 0, 0);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: medium;word-spacing: 2px;"> <li style="font-size: 14px;"><p style="margin-top: 5px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&mid=2247492792&idx=1&sn=ba83f100298d6f94bcfa9d9665bf1fd1&chksm=9f448870a8330166fd5650716193cfa73b58deef8caee8c3b44cd85735bc17f25394b3cdf70e&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">原来 Elasticsearch 还可以这么理解!</a><br></p></li> <li style="font-size: 14px;"><p style="margin-top: 5px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&mid=2247492417&idx=2&sn=92833e66e40214fd5afc5a48fd7286a0&chksm=9f448f89a833069f095c986670cae3f2b96a52c95518e3bb97f22b1ff19dba50ee48f8d0c014&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">总结三种 MySQL 大表优化方案</a></p></li> <li style="font-size: 14px;"><p style="margin-top: 5px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&mid=2247492408&idx=1&sn=1bd7546b766d11e30648506222630ccd&chksm=9f448ff0a83306e66a6c80b275a6e5a6969239ea15aaef81172d305d9ff43daf18bb315c6abf&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">面试官:RocketMQ 消息会丢失吗?如何解决消息丢失!!</a></p></li> <li style="font-size: 14px;"><p style="margin-top: 5px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&mid=2247492361&idx=2&sn=8b0e9a5d08fffb620aaae38ed59ea8cc&chksm=9f448fc1a83306d703395e59e4c9e69b74e6f1e57c19f502faaa1b1e4101f12c9be904a79f54&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">100000 行级别数据的 Excel 导入优化之路</a></p></li> <li style="font-size: 14px;"><p style="margin-top: 5px;"><a target="_blank" href="http://mp.weixin.qq.com/s?__biz=MzA3ODIxNjYxNQ==&mid=2247492339&idx=1&sn=a8e5726019b155a17a4634fa18d30588&chksm=9f448e3ba833072d5c08fc94dbea53cd4d78c36c3f7b366fdae2c847b36a2c54d4ba76306db3&scene=21#wechat_redirect" data-itemshowtype="0" tab="innerlink" data-linktype="2" hasload="1" style="color: var(--weui-LINK);-webkit-tap-highlight-color: rgba(0, 0, 0, 0);cursor: pointer;">用图讲解 ElasticSearch 搜索原理,你就明白了!</a><br></p></li> </ul><p style="margin-top: 5px;letter-spacing: 0.544px;white-space: normal;caret-color: rgb(0, 0, 0);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;word-spacing: 2px;"><br></p><p style="margin-top: 5px;letter-spacing: 0.544px;white-space: normal;caret-color: rgb(0, 0, 0);font-family: "Helvetica Neue", Helvetica, "Hiragino Sans GB", "Microsoft YaHei", Arial, sans-serif;font-size: 15px;word-spacing: 2px;text-align: right;"><img class="rich_pages" data-ratio="0.5555555555555556" data-s="300,640" data-type="jpeg" data-w="900" src="/upload/9d786e52e671b1ce4beb338d1e0d1815.jpg" style="letter-spacing: 0.544px;text-align: center;font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;box-sizing: border-box !important;visibility: visible !important;width: 677px !important;"><span style="letter-spacing: 0.544px;font-size: 14px;">如有收获,点个在看,诚挚感谢</span><img data-ratio="1" data-type="png" data-w="19" width="19px" src="/upload/5f7454d24a334e968c32b8ce9ae53c5.png" style="font-size: 16px;letter-spacing: 0.544px;display: inline-block;vertical-align: text-bottom;box-sizing: border-box !important;visibility: visible !important;width: 19px !important;"></p></pre>
作者:微信小助手
<section style="display:none;" data-tools="新媒体管家" data-label="powered by xmt.cn" data-mpa-powered-by="yiban.io"> <br> </section> <p style="text-align: center;"><span style="font-size: 13px;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;">点击上方蓝色“</span><span style="font-size: 13px;font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;color: rgb(0, 128, 255);">程序猿DD</span><span style="font-size: 13px;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;">”,选择“设为星标”</span><strong style="max-width: 100%;letter-spacing: 0.544px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 16px;white-space: pre-line;background-color: rgb(255, 255, 255);text-align: right;box-sizing: border-box !important;overflow-wrap: break-word !important;"></strong></p> <p style="max-width: 100%;min-height: 1em;white-space: normal;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="font-size: 13px;max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;">回复“</span><span style="font-size: 13px;max-width: 100%;font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;color: rgb(0, 128, 255);overflow-wrap: break-word !important;box-sizing: border-box !important;">资源</span><span style="font-size: 13px;max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;">”获取独家整理的学习资料!</span><strong style="max-width: 100%;letter-spacing: 0.544px;color: rgb(74, 74, 74);font-family: Avenir, -apple-system-font, 微软雅黑, sans-serif;font-size: 16px;white-space: pre-line;background-color: rgb(255, 255, 255);text-align: right;overflow-wrap: break-word !important;box-sizing: border-box !important;"></strong></p> <p style="margin-top: 10px;margin-bottom: 10px;max-width: 100%;min-height: 1em;white-space: normal;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;color: rgb(136, 136, 136);font-family: Georgia, "Times New Roman", Times, "Songti SC", serif;font-size: 14px;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;"><img data-backh="34" data-backw="540" data-ratio="0.0625" data-s="300,640" data-type="jpeg" data-w="640" width="100%" src="/upload/8c292e55ba5a23cb6ebc11f2a2c4fece.jpg" style="font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;overflow-wrap: break-word !important;box-sizing: border-box !important;visibility: visible !important;width: 654px !important;"></span></p> <p style="max-width: 100%;min-height: 1em;white-space: normal;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);text-align: left;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;letter-spacing: 0.544px;color: rgb(178, 178, 178);font-family: Optima-Regular, PingFangTC-light;font-size: 13px;overflow-wrap: break-word !important;box-sizing: border-box !important;"><img src="/upload/5b74e33d8e8bc9247eb82b2b068b660c.jpg" data-type="jpeg" data-ratio="0.46296296296296297" data-w="1080"><br style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"></span></p> <section style="margin-bottom: 15px;max-width: 100%;white-space: normal;text-align: right;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;box-sizing: border-box !important;"> <span style="max-width: 100%;letter-spacing: 0.544px;font-family: Optima-Regular, PingFangTC-light;font-size: 13px;color: rgb(178, 178, 178);overflow-wrap: break-word !important;box-sizing: border-box !important;">来源 |<span style="letter-spacing: 0.544px;font-family: Optima-Regular, PingFangTC-light;font-size: 13px;color: rgb(178, 178, 178);max-width: 100%;white-space: pre-line;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <span style="max-width: 100%;color: rgb(178, 178, 178);font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;font-size: 12px;letter-spacing: 1px;text-align: left;background-color: rgb(255, 255, 255);overflow-wrap: break-word !important;box-sizing: border-box !important;">www.cnblogs.com/tanwei81/p/6814022.html</span></span></span> </section> <h1 style="font-weight: 700;font-size: 22px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(255, 140, 0);text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;"><span style="color: rgb(61, 167, 66);font-size: 20px;">一、注解 (annotations) 列表</span></h1> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@SpringBootApplication</strong>: </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 包含了 @ComponentScan、@Configuration 和 @EnableAutoConfiguration 注解。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 其中 @ComponentScan 让 spring Boot 扫描到 Configuration 类并把它加入到程序上下文。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Configuration</strong> 等同于 spring 的 XML 配置文件;使用 Java 代码可以检查类型安全。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> **@EnableAutoConfiguration ** 自动配置。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> **@ComponentScan ** 组件扫描,可自动发现和装配一些 Bean。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Component</strong> 可配合 CommandLineRunner 使用,在程序启动后执行一些基础任务。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@RestController</strong> 注解是 @Controller 和 @ResponseBody 的合集, 表示这是个控制器 bean, 并且是将函数的返回值直 接填入 HTTP 响应体中, 是 REST 风格的控制器。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Autowired</strong> 自动导入。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@PathVariable</strong> 获取参数。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@JsonBackReference</strong> 解决嵌套外链问题。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@RepositoryRestResourcepublic</strong> 配合 spring-boot-starter-data-rest 使用。 </section> <h1 style="font-weight: 700;font-size: 22px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(255, 140, 0);text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;"><span style="color: rgb(61, 167, 66);font-size: 20px;">二、注解 (annotations) 详解</span></h1> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@SpringBootApplication</strong>:申明让 spring boot 自动给程序进行必要的配置,这个配置等同于:@Configuration ,@EnableAutoConfiguration 和 @ComponentScan 三个配置。 </section> <pre style="padding: 0.5em;letter-spacing: 0.544px;font-family: Courier, "Courier New", monospace;background: rgb(45, 45, 45);border-width: 1px;border-style: solid;border-color: rgb(221, 221, 221);overflow-x: auto;color: rgb(204, 204, 204);font-size: 15px;text-align: start;"> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <code style="overflow-wrap: normal;font-family: Courier, "Courier New", monospace;display: inline;overflow: initial;line-height: inherit;border-width: 0px;border-style: initial;border-color: initial;font-size: 13.5px;"><span style="font-weight: 700;color: rgb(204, 153, 204);">package</span> com.example.myproject;<br><span style="font-weight: 700;color: rgb(204, 153, 204);">import</span> org.springframework.boot.SpringApplication;<br><span style="font-weight: 700;color: rgb(204, 153, 204);">import</span> org.springframework.boot.autoconfigure.SpringBootApplication;<br><br><span style="color: rgb(249, 145, 87);">@SpringBootApplication</span> <span style="color: rgb(153, 153, 153);">// same as @Configuration @EnableAutoConfiguration @ComponentScan</span><br><span style="font-weight: 700;color: rgb(204, 153, 204);">public</span> <span style="font-weight: 700;color: rgb(204, 153, 204);">class</span> <span style="color: rgb(102, 153, 204);font-weight: 700;">Application</span> {<br> <span style="font-weight: 700;color: rgb(204, 153, 204);">public</span> <span style="font-weight: 700;color: rgb(204, 153, 204);">static</span> <span style="font-weight: 700;color: rgb(204, 153, 204);">void</span> <span style="color: rgb(102, 153, 204);font-weight: 700;">main</span><span style="color: rgb(249, 145, 87);">(String[] args)</span> {<br> SpringApplication.run(Application.class, args);<br> }<br>}<br></code> </section></pre> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@ResponseBody</strong>:表示该方法的返回结果直接写入 HTTP response body 中,一般在异步获取数据时使用,用于构建 RESTful 的 api。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 在使用 @RequestMapping 后,返回值通常解析为跳转路径,加上 @responsebody 后返回结果不会被解析为跳转路径,而是直接写入 HTTP response body 中。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 比如异步获取 json 数据,加上 @responsebody 后,会直接返回 json 数据。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 该注解一般会配合 @RequestMapping 一起使用。示例代码: </section> <pre style="padding: 0.5em;letter-spacing: 0.544px;font-family: Courier, "Courier New", monospace;background: rgb(45, 45, 45);border-width: 1px;border-style: solid;border-color: rgb(221, 221, 221);overflow-x: auto;color: rgb(204, 204, 204);font-size: 15px;text-align: start;"> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <code style="overflow-wrap: normal;font-family: Courier, "Courier New", monospace;display: inline;overflow: initial;line-height: inherit;border-width: 0px;border-style: initial;border-color: initial;font-size: 13.5px;"><span style="color: rgb(249, 145, 87);">@RequestMapping(“/test”)</span><br><span style="color: rgb(249, 145, 87);">@ResponseBody</span><br><span style="font-weight: 700;color: rgb(204, 153, 204);">public</span> String <span style="color: rgb(102, 153, 204);font-weight: 700;">test</span><span style="color: rgb(249, 145, 87);">()</span>{<br> <span style="font-weight: 700;color: rgb(204, 153, 204);">return</span>”ok”;<br>}<br></code> </section></pre> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Controller</strong>:用于定义控制器类,在 spring 项目中由控制器负责将用户发来的 URL 请求转发到对应的服务接口(service 层) </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 一般这个注解在类中,通常方法需要配合注解 @RequestMapping。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 示例代码: </section> <pre style="padding: 0.5em;letter-spacing: 0.544px;font-family: Courier, "Courier New", monospace;background: rgb(45, 45, 45);border-width: 1px;border-style: solid;border-color: rgb(221, 221, 221);overflow-x: auto;color: rgb(204, 204, 204);font-size: 15px;text-align: start;"> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <code style="overflow-wrap: normal;font-family: Courier, "Courier New", monospace;display: inline;overflow: initial;line-height: inherit;border-width: 0px;border-style: initial;border-color: initial;font-size: 13.5px;"><span style="color: rgb(249, 145, 87);">@Controller</span><br><span style="color: rgb(249, 145, 87);">@RequestMapping(“/demoInfo”)</span><br>publicclass DemoController {<br> <span style="color: rgb(249, 145, 87);">@Autowired</span><br> <span style="font-weight: 700;color: rgb(204, 153, 204);">private</span> DemoInfoService demoInfoService;<br><br> <span style="color: rgb(249, 145, 87);">@RequestMapping("/hello")</span><br> <span style="font-weight: 700;color: rgb(204, 153, 204);">public</span> String <span style="color: rgb(102, 153, 204);font-weight: 700;">hello</span><span style="color: rgb(249, 145, 87);">(Map map)</span>{<br> System.out.println(<span style="color: rgb(153, 204, 153);">"DemoController.hello()"</span>);<br> map.put(<span style="color: rgb(153, 204, 153);">"hello"</span>,<span style="color: rgb(153, 204, 153);">"from TemplateController.helloHtml"</span>);<br> <span style="color: rgb(153, 153, 153);">//会使用hello.html或者hello.ftl模板进行渲染显示.</span><br> <span style="font-weight: 700;color: rgb(204, 153, 204);">return</span><span style="color: rgb(153, 204, 153);">"/hello"</span>;<br> }<br>}<br></code> </section></pre> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@RestController</strong>:用于标注控制层组件 (如 struts 中的 action),@ResponseBody 和 @Controller 的合集。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 示例代码: </section> <pre style="padding: 0.5em;letter-spacing: 0.544px;font-family: Courier, "Courier New", monospace;background: rgb(45, 45, 45);border-width: 1px;border-style: solid;border-color: rgb(221, 221, 221);overflow-x: auto;color: rgb(204, 204, 204);font-size: 15px;text-align: start;"> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <code style="overflow-wrap: normal;font-family: Courier, "Courier New", monospace;display: inline;overflow: initial;line-height: inherit;border-width: 0px;border-style: initial;border-color: initial;font-size: 13.5px;"><span style="font-weight: 700;color: rgb(204, 153, 204);">package</span> com.kfit.demo.web;<br><br><span style="font-weight: 700;color: rgb(204, 153, 204);">import</span> org.springframework.web.bind.annotation.RequestMapping;<br><span style="font-weight: 700;color: rgb(204, 153, 204);">import</span> org.springframework.web.bind.annotation.RestController;<br><br><span style="color: rgb(249, 145, 87);">@RestController</span><br><span style="color: rgb(249, 145, 87);">@RequestMapping(“/demoInfo2”)</span><br>publicclass DemoController2 {<br><br> <span style="color: rgb(249, 145, 87);">@RequestMapping("/test")</span><br> <span style="font-weight: 700;color: rgb(204, 153, 204);">public</span> String <span style="color: rgb(102, 153, 204);font-weight: 700;">test</span><span style="color: rgb(249, 145, 87);">()</span>{<br> <span style="font-weight: 700;color: rgb(204, 153, 204);">return</span><span style="color: rgb(153, 204, 153);">"ok"</span>;<br> }<br>}<br></code> </section></pre> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@RequestMapping</strong>:提供路由信息,负责 URL 到 Controller 中的具体函数的映射。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@EnableAutoConfiguration</strong>:Spring Boot 自动配置(auto-configuration):尝试根据你添加的 jar 依赖自动配置你的 Spring 应用。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 例如,如果你的 classpath 下存在 HSQLDB,并且你没有手动配置任何数据库连接 beans,那么我们将自动配置一个内存型(in-memory)数据库”。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 你可以将 @EnableAutoConfiguration 或者 @SpringBootApplication 注解添加到一个 @Configuration 类上来选择自动配置。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 如果发现应用了你不想要的特定自动配置类,你可以使用 @EnableAutoConfiguration 注解的排除属性来禁用它们。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@ComponentScan</strong>:表示将该类自动发现扫描组件。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 个人理解相当于,如果扫描到有 @Component、@Controller、@Service 等这些注解的类,并注册为 Bean,可以自动收集所有的 Spring 组件,包括 @Configuration 类。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 我们经常使用 @ComponentScan 注解搜索 beans,并结合 @Autowired 注解导入。可以自动收集所有的 Spring 组件,包括 @Configuration 类。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 如果没有配置的话,Spring Boot 会扫描启动类所在包下以及子包下的使用了 @Service,@Repository 等注解的类。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Configuration</strong>:相当于传统的 xml 配置文件,如果有些第三方库需要用到 xml 文件,建议仍然通过 @Configuration 类作为项目的配置主类——可以使用 @ImportResource 注解加载 xml 配置文件。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Import</strong>:用来导入其他配置类。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@ImportResource</strong>:用来加载 xml 配置文件。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Autowired</strong>:自动导入依赖的 bean </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Service</strong>:一般用于修饰 service 层的组件 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Repository</strong>:使用 @Repository 注解可以确保 DAO 或者 repositories 提供异常转译,这个注解修饰的 DAO 或者 repositories 类会被 ComponetScan 发现并配置,同时也不需要为它们提供 XML 配置项。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Bean</strong>:用 @Bean 标注方法等价于 XML 中配置的 bean。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Value</strong>:注入 Spring boot application.properties 配置的属性的值。示例代码: </section> <pre style="padding: 0.5em;letter-spacing: 0.544px;font-family: Courier, "Courier New", monospace;background: rgb(45, 45, 45);border-width: 1px;border-style: solid;border-color: rgb(221, 221, 221);overflow-x: auto;color: rgb(204, 204, 204);font-size: 15px;text-align: start;"> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <code style="overflow-wrap: normal;font-family: Courier, "Courier New", monospace;display: inline;overflow: initial;line-height: inherit;border-width: 0px;border-style: initial;border-color: initial;font-size: 13.5px;"><span style="color: rgb(249, 145, 87);">@Value(value = “#{message}”)</span><br><span style="font-weight: 700;color: rgb(204, 153, 204);">private</span> String message;<br></code> </section></pre> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Inject</strong>:等价于默认的 @Autowired,只是没有 required 属性; </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Component</strong>:泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Bean</strong>:相当于 XML 中的, 放在方法的上面,而不是类,意思是产生一个 bean, 并交给 spring 管理。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@AutoWired</strong>:自动导入依赖的 bean。byType 方式。把配置好的 Bean 拿来用,完成属性、方法的组装,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。当加上(required=false)时,就算找不到 bean 也不报错。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Qualifier</strong>:当有多个同一类型的 Bean 时,可以用 @Qualifier(“name”) 来指定。与 @Autowired 配合使用。@Qualifier 限定描述符除了能根据名字进行注入,但能进行更细粒度的控制如何选择候选者,具体使用方式如下: </section> <pre style="padding: 0.5em;letter-spacing: 0.544px;font-family: Courier, "Courier New", monospace;background: rgb(45, 45, 45);border-width: 1px;border-style: solid;border-color: rgb(221, 221, 221);overflow-x: auto;color: rgb(204, 204, 204);font-size: 15px;text-align: start;"> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <code style="overflow-wrap: normal;font-family: Courier, "Courier New", monospace;display: inline;overflow: initial;line-height: inherit;border-width: 0px;border-style: initial;border-color: initial;font-size: 13.5px;"><span style="color: rgb(249, 145, 87);">@Autowired</span><br><span style="color: rgb(249, 145, 87);">@Qualifier(value = “demoInfoService”)</span><br><span style="font-weight: 700;color: rgb(204, 153, 204);">private</span> DemoInfoService demoInfoService;<br></code> </section></pre> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Resource</strong>(name=”name”,type=”type”):没有括号内内容的话,默认 byName。与 @Autowired 干类似的事。 </section> <h1 style="font-weight: 700;font-size: 22px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(255, 140, 0);text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;"><span style="color: rgb(61, 167, 66);font-size: 20px;">三、JPA 注解</span></h1> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Entity</strong>:@Table(name=”“):表明这是一个实体类。一般用于 jpa 这两个注解一般一块使用,但是如果表名和实体类名相同的话,@Table 可以省略 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@MappedSuperClass</strong>: 用在确定是父类的 entity 上。父类的属性子类可以继承。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@NoRepositoryBean</strong>: 一般用作父类的 repository,有这个注解,spring 不会去实例化该 repository。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Column</strong>:如果字段名与列名相同,则可以省略。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Id</strong>:表示该属性为主键。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@GeneratedValue</strong>(strategy=GenerationType.SEQUENCE,generator= “repair_seq”):表示主键生成策略是 sequence(可以为 Auto、IDENTITY、native 等,Auto 表示可在多个数据库间切换),指定 sequence 的名字是 repair_seq。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@SequenceGeneretor</strong>(name = “repair_seq”, sequenceName = “seq_repair”, allocationSize = 1):name 为 sequence 的名称,以便使用,sequenceName 为数据库的 sequence 名称,两个名称可以一致。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@Transient</strong>:表示该属性并非一个到数据库表的字段的映射, ORM 框架将忽略该属性。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 如果一个属性并非数据库表的字段映射, 就务必将其标示为 @Transient, 否则, ORM 框架默认其注解为 @Basic。@Basic(fetch=FetchType.LAZY):标记可以指定实体属性的加载方式 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@JsonIgnore</strong>:作用是 json 序列化时将 Java bean 中的一些属性忽略掉, 序列化和反序列化都受影响。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@JoinColumn</strong>(name=”loginId”): 一对一:本表中指向另一个表的外键。一对多:另一个表指向本表的外键。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@OneToOne、@OneToMany、@ManyToOne</strong>:对应 hibernate 配置文件中的一对一,一对多,多对一。 </section> <h1 style="font-weight: 700;font-size: 22px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(255, 140, 0);text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;"><span style="color: rgb(61, 167, 66);font-size: 20px;">四、springMVC 相关注解</span></h1> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@RequestMapping</strong>:@RequestMapping(“/path”)表示该控制器处理所有 “/path” 的 UR L 请求。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> RequestMapping 是一个用来处理请求地址映射的注解,可用于类或方法上。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。该注解有六个属性: </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">params</strong>: 指定 request 中必须包含某些参数值是,才让该方法处理。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">headers</strong>: 指定 request 中必须包含某些指定的 header 值,才能让该方法处理请求。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">value</strong>: 指定请求的实际地址,指定的地址可以是 URI Template 模式 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">method</strong>: 指定请求的 method 类型, GET、POST、PUT、DELETE 等 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">consumes</strong>: 指定处理请求的提交内容类型(Content-Type),如 application/json,text/html; </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">produces</strong>: 指定返回的内容类型,仅当 request 请求头中的 (Accept) 类型中包含该指定类型才返回 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@RequestParam</strong>:用在方法的参数前面。 <br>@RequestParam <br>String a =request.getParameter(“a”)。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@PathVariable</strong>: 路径变量。如 </section> <pre style="padding: 0.5em;letter-spacing: 0.544px;font-family: Courier, "Courier New", monospace;background: rgb(45, 45, 45);border-width: 1px;border-style: solid;border-color: rgb(221, 221, 221);overflow-x: auto;color: rgb(204, 204, 204);font-size: 15px;text-align: start;"> <section style="margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <code style="overflow-wrap: normal;font-family: Courier, "Courier New", monospace;display: inline;overflow: initial;line-height: inherit;border-width: 0px;border-style: initial;border-color: initial;font-size: 13.5px;">RequestMapping(“user/get/mac/{macAddress}”)<br><span style="font-weight: 700;color: rgb(204, 153, 204);">public</span> String <span style="color: rgb(102, 153, 204);font-weight: 700;">getByMacAddress</span><span style="color: rgb(249, 145, 87);">(@PathVariable String macAddress)</span>{<br> <span style="color: rgb(153, 153, 153);">//do something;</span><br>}<br></code> </section></pre> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> 参数与大括号里的名字一样要相同。 </section> <h1 style="font-weight: 700;font-size: 22px;letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(255, 140, 0);text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;"><span style="color: rgb(61, 167, 66);font-size: 20px;">五、全局异常处理</span></h1> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@ControllerAdvice</strong>:包含 @Component。可以被扫描到。统一处理异常。 </section> <section style="letter-spacing: 0.544px;white-space: normal;background-color: rgb(255, 255, 255);color: rgb(80, 97, 109);font-family: Helvetica, Arial, sans-serif;font-size: 15px;text-align: start;margin-top: 15px;margin-bottom: 15px;line-height: 1.75em;"> <strong style="color: rgb(0, 0, 0);">@ExceptionHandler</strong>(Exception.class):用在方法上面表示遇到这个异常就执行以下方法。 </section> <section style="margin-bottom: 10px;max-width: 100%;white-space: normal;min-height: 1em;letter-spacing: 0.544px;font-family: -apple-system-font, system-ui, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;text-align: center;overflow-wrap: break-word !important;box-sizing: border-box !important;"> <span style="max-width: 100%;font-size: 15px;overflow-wrap: break-word !important;box-sizing: border-box !important;"><strong style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"><span style="max-width: 100%;overflow-wrap: break-word !important;box-sizing: border-box !important;"></span></strong></span> </section> <section data-mpa-template="t" mpa-from-tpl="t" style="max-width: 100%;caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section data-mpa-template="t" mpa-from-tpl="t" data-mid="" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section mpa-from-tpl="t" data-mid="" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section mpa-from-tpl="t" data-mid="" style="margin-right: auto;margin-left: auto;max-width: 100%;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section mpa-from-tpl="t" data-mid="" style="margin-top: 10px;max-width: 100%;display: inline-block;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p data-mid="" style="max-width: 100%;min-height: 1em;opacity: 0.2;box-sizing: border-box !important;overflow-wrap: break-word !important;">﹀</p> <p data-mid="" style="margin-top: -12.5px;max-width: 100%;min-height: 1em;opacity: 0.5;box-sizing: border-box !important;overflow-wrap: break-word !important;">﹀</p> <p data-mid="" style="margin-top: -12.5px;max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;">﹀</p> </section> </section> </section> </section> </section> <section data-mpa-template="t" mpa-from-tpl="t" style="max-width: 100%;caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section mpa-from-tpl="t" style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section mpa-from-tpl="t" style="margin-right: 10px;margin-left: 10px;max-width: 100%;display: flex;justify-content: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section mpa-from-tpl="t" style="padding: 5px 20px;max-width: 100%;border-width: 5px 1px 1px;border-style: solid;border-color: rgb(149, 149, 149);box-sizing: border-box !important;overflow-wrap: break-word !important;"> <p style="max-width: 100%;min-height: 1em;text-align: center;letter-spacing: 1.5px;font-size: 15px;color: rgb(40, 40, 40);box-sizing: border-box !important;overflow-wrap: break-word !important;">推荐加入<br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> </section> </section> </section> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><br style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;"></p> <p style="max-width: 100%;min-height: 1em;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-backh="498" data-backw="578" data-ratio="0.8617449664429531" data-s="300,640" data-type="png" data-w="745" src="/upload/83dd38656a6d560f2aabce3fb9781e0d.png" style="text-align: center;width: 664px;box-sizing: border-box !important;overflow-wrap: break-word !important;visibility: visible !important;"></p> </section> <section data-mpa-template="t" mpa-from-tpl="t" style="max-width: 100%;caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <section mpa-from-tpl="t" style="padding: 1px 5px;max-width: 100%;font-size: 14px;box-sizing: border-box !important;overflow-wrap: break-word !important;"> <h2 style="margin: 5px;padding-right: 10px;padding-left: 10px;font-weight: bold;max-width: 100%;border-left: 5px solid rgb(1, 1, 1);border-top-color: rgb(1, 1, 1);border-right-color: rgb(1, 1, 1);border-bottom-color: rgb(1, 1, 1);line-height: 32px;color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"><p style="max-width: 100%;min-height: 1em;border-color: rgb(1, 1, 1);box-sizing: border-box !important;overflow-wrap: break-word !important;"><span style="max-width: 100%;color: rgb(0, 0, 0);box-sizing: border-box !important;overflow-wrap: break-word !important;">最近热门内容回顾 <span style="max-width: 100%;box-sizing: border-box !important;overflow-wrap: break-word !important;">#技术人系列</span></span></p></h2> </section> </section> <p style="max-width: 100%;min-height: 1em;caret-color: rgb(51, 51, 51);font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;letter-spacing: 0.544px;white-space: normal;text-size-adjust: auto;text-align: center;box-sizing: border-box !important;overflow-wrap: break-word !important;"><img class="rich_pages" data-ratio="0.48688524590163934" data-s="300,640" data-type="png" data-w="610" src="/upload/e9ff2c01e1a9c246829d626ade92800c.png" style="box-sizing: border-box !important;overflow-wrap: break-word !important;width: 610px !important;visibility: visible !important;"><span style="font-family: mp-quote, -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei UI", "Microsoft YaHei", Arial, sans-serif;background-color: rgb(255, 255, 255);letter-spacing: 0.544px;"></span></p>