作者:微信小助手
<p style="margin-bottom: 8px;"><span style="font-size: 16px;">该数据仓库用例与规模有关。用户是中国联通,全球最大的电信服务提供商之一。使用 Apache Doris 在数十台机器上部署多个 PB 级集群,以支持 30 多个业务线每日添加的 150 亿条日志。如此庞大的日志分析系统是网络安全管理的一部分。出于实时监控、威胁追踪和警报的需求,用户需要一个能够自动收集、存储、分析和可视化日志和事件记录的日志分析系统。</span></p> <section style="text-align: left;margin-bottom: 8px;"> <span style="font-size: 16px;">从架构的角度来看,系统应该能够对各种格式的日志进行实时分析,当然还要具有可扩展性,以支持庞大且不断扩大的数据规模。本文关于用户的日志处理架构是什么样的,以及如何实现稳定的数据摄取、低成本存储和快速查询。</span> </section> <section style="margin-bottom: 8px;margin-top: 24px;text-align: left;"> <strong><span style="font-size: 18px;">系统架构</span></strong> </section> <p style="margin-bottom: 8px;text-align: left;"><span style="font-size: 16px;">这是用户的数据管道。日志被收集到数据仓库中,并经过多层处理。</span></p> <section style="text-align: left;margin-bottom: 0px;"> <img class="rich_pages wxw-img" data-backh="264" data-backw="554" data-galleryid="" data-ratio="0.47653429602888087" data-s="300,640" src="/upload/243f9d28d1a53dd18f8f14921b9cf355.png" data-type="png" data-w="554" style="width: 100%;height: auto;"> </section> <ul style="list-style-type: disc;" class="list-paddingleft-1"> <li style="font-size: 16px;"><p style="margin-bottom: 8px;text-align: left;"><span style="font-size: 16px;">ODS:来自所有来源的原始日志和警报都收集到 Apache Kafka 中。同时,它们的副本将存储在HDFS中以供数据验证或重放。</span></p></li> <li style="font-size: 16px;"><p style="margin-bottom: 8px;text-align: left;"><span style="font-size: 16px;">DWD:这是事实表所在的位置。Apache Flink 对数据进行清理、标准化、回填和去标识化,并将其写回 Kafka。这些事实表也将被放入 Apache Doris 中,以便 Doris 跟踪某个项目或用于仪表板和报告。由于日志不反对重复,因此事实表将按照Apache Doris 的Duplicate Key 模型进行排列。</span></p></li> <li style="font-size: 16px;"><p style="margin-bottom: 8px;text-align: left;"><span style="font-size: 16px;">DWS:该层聚合来自DWD的数据,为查询和分析奠定基础。</span></p></li> <li style="font-size: 16px;"><p style="margin-bottom: 8px;text-align: left;"><span style="font-size: 16px;">ADS:在这一层中,Apache Doris 使用其 Aggregate Key 模型自动聚合数据,并使用Unique Key 模型自动更新数架构 2.0 是从架构 1.0 发展而来的,由 ClickHouse 和 Apache Hive 支持。这种转变出于用户对实时数据处理和多表连接查询的需求。根据使用 ClickHouse 的经验,用户发现对并发和多表联接的支持不足,表现为仪表板频繁超时和分布式联接中的OOM 错误。</span></p></li> </ul> <p style="text-align: left;"><img class="rich_pages wxw-img" data-backh="263" data-backw="554" data-galleryid="" data-ratio="0.4747292418772563" data-s="300,640" src="/upload/8108824b31dca564e75cdf74c72a4025.png" data-type="png" data-w="554" style="width: 100%;height: auto;"></p> <p style="text-align: left;margin-bottom: 8px;">现在让我们看看用户使用架构2.0在数据摄取、存储和查询方面的实践。<br></p> <section style="margin-bottom: 8px;margin-top: 24px;text-align: left;"> <strong><span style="font-size: 18px;">真实案例练习</span></strong> </section> <p style="margin-bottom: 8px;text-align: left;"><strong><span style="font-size: 17px;">每天稳定摄取 150 亿条日志</span></strong></p> <section style="text-align: left;margin-bottom: 8px;"> <span style="font-size: 16px;">用户的业务每天会产生 150 亿条日志。快速稳定地摄取如此大的数据量是一个现实问题。对于 Apache Doris,推荐的方法是使用 Flink-Doris-Connector。它是由 Apache Doris 社区开发的,用于大规模数据写入。该组件需要简单的配置。实现了Stream Load,可以达到每秒200,000~300,000条日志的写入速度,而且不中断数据分析工作负载。</span> </section> <section style="text-align: left;margin-bottom: 8px;"> <span style="font-size: 16px;">得到的一个经验是,在使用Flink进行高频写入时,需要根据自己的情况找到合适的参数配置,避免数据版本积累。针对这种情况用户做了以下优化:</span> </section> <ul style="list-style-type: disc;" class="list-paddingleft-1"> <li> <section> <p style="margin-bottom: 8px;text-align: left;"><span style="font-size: 16px;">Flink Checkpoint:将检查点间隔从 15 秒增加到 60 秒,以减少写入频率和单位时间内 Doris 处理的事务数量。这样可以缓解数据写入压力,避免生成过多的数据版本。</span></p> </section></li> <li style="font-size: 16px;"><p style="margin-bottom: 8px;text-align: left;"><span style="font-size: 16px;">数据预聚合:对于ID相同但来自不同表的数据,Flink会根据主键ID进行预聚合并创建扁平表,以避免多源数据写入造成过多的资源消耗。</span></p></li> <li style="font-size: 16px;"><p style="margin-bottom: 8px;text-align: left;"><span style="font-size: 16px;">Doris Compaction:这里的技巧包括找到正确的Doris后端(BE)参数来分配适量的CPU资源进行数据压缩,设置适当数量的数据分区、桶和副本(过多的数据片会带来巨大的开销),并设置 </span><span style="font-size: 16px;background-color: rgb(214, 214, 214);">max_tablet_version_num</span><span style="font-size: 16px;"> 以避免版本累积。</span></p></li> </ul> <p style="margin-bottom: 8px;text-align: left;"><span style="font-size: 16px;">这些措施共同确保了数据日常摄取的稳定性。过程中用户见证了Doris后端的稳定性能和较低的压缩分数。此外,Flink 中的数据预处理与Doris 中的Unique Key 模型相结合,来保证更快的数据更新。</span></p> <section style="margin-bottom: 8px;text-align: left;margin-top: 24px;"> <strong><span style="font-size: 17px;">存储策略可降低成本 50%</span></strong> </section> <section style="text-align: left;margin-bottom: 8px;"> <span style="font-size: 16px;">日志的大小和生成率也给存储带来了压力。海量的日志数据中,只有一部分具有较高的信息价值,因此应差异化存储。用户采用三种存储策略来降低成本。</span> </section> <ul style="list-style-type: disc;" class="list-paddingleft-1"> <li style="font-size: 16px;"> <section style="text-align: left;margin-bottom: 8px;"> <span style="font-size: 16px;">ZSTD(ZStandard)压缩算法:对于大于1TB的表,在建表时指定压缩方式为“ZSTD”,将实现10:1的压缩比。</span> </section></li> <li style="font-size: 16px;"> <section style="text-align: left;margin-bottom: 8px;"> <span style="font-size: 16px;">冷热数据分层存储:这是Doris新特性支持的。用户设置 7 天的数据“冷却”期。这意味着过去7天的数据(即热点数据)将存储在SSD中。随着时间的推移,热数据“冷却”(超过 7 天),它会自动转移到成本较低的HDD。随着数据变得更加“冷”,它将被转移到对象存储,以大大降低存储成本。另外,在对象存储中,数据将仅存储一份而不是三份。这进一步降低了成本和冗余存储带来的管理费用。</span> </section></li> <li style="font-size: 16px;"> <section style="text-align: left;margin-bottom: 8px;"> <span style="font-size: 16px;">不同数据分区的差异化副本数:用户按时间范围对数据进行分区。原则是为较新的数据分区提供更多的副本,为旧的数据分区提供更少的副本。在他们的应用中,过去 3 个月的数据被频繁访问,因此他们为此分区有 2 个副本。3~6个月前的数据有两个副本,6个月前的数据有一个副本。</span> </section></li> </ul> <section style="text-align: left;margin-bottom: 8px;"> 通过这三种策略,用户的存储成本降低了 50%。 </section> <section style="margin-bottom: 8px;margin-top: 24px;text-align: left;"> <span style="font-size: 18px;"><strong>根据数据大小差异化查询策略</strong></span> </section> <p style="margin-bottom: 8px;text-align: left;"><span style="font-size: 16px;">有些日志必须立即追踪定位,例如异常事件或故障的日志。为了保证这些查询的实时响应,用户针对不同的数据大小有不同的查询策略:</span></p> <ul style="list-style-type: disc;" class="list-paddingleft-1"> <li style="font-size: 16px;"><p style="margin-bottom: 8px;text-align: left;"><span style="font-size: 16px;">小于100G:利用Doris的动态分区功能。小表将按日期分区,大表将按小时分区。这样可以避免数据倾斜。为了进一步确保分区内数据的平衡,使用snowflake ID 作为分桶字段。还设置了20天的起始偏移量,这意味着最近20天的数据将被保留。通过这种方式,找到了数据积压和分析需求之间的平衡点。</span></p></li> <li style="font-size: 16px;"><p style="margin-bottom: 8px;text-align: left;"><span style="font-size: 16px;">100G~1T:这些表有其物化视图,是存储在Doris中的预先计算的结果集。因此,对这些表的查询速度更快而且资源消耗更少。Doris中物化视图的DDL语法与PostgreSQL、Oracle中的相同。</span></p></li> <li style="font-size: 16px;"><p style="margin-bottom: 8px;text-align: left;"><span style="font-size: 16px;">超过100T:这些表被放入Apache Doris的Aggregate Key模型中并进行预聚合。这样就可以在1~2s内完成20亿条日志记录的查询。</span></p></li> </ul> <section style="margin-bottom: 8px;"> <span style="font-size: 16px;">这些策略缩短了查询的响应时间。例如,以前对特定数据项的查询需要几分钟,但现在可以在毫秒内完成。对于百亿条数据的大表,不同维度的查询都可以在几秒钟内完成。</span> </section> <section style="margin-bottom: 8px;margin-top: 24px;text-align: left;"> <strong><span style="font-size: 18px;">正在进行的计划</span></strong> </section> <p style="margin-bottom: 8px;text-align: left;"><span style="font-size: 16px;">用户正在 Apache Doris 中使用新添加的倒排索引进行测试。旨在加速字符串的全文搜索以及数字和日期时间的等价和范围查询。用户还对 Doris 中的自动分桶逻辑提供了宝贵的反馈:目前,Doris 根据前一个分区的数据大小来决定一个分区的分桶数量。问题在于,用户大部分新数据都是在白天输入,晚上则很少。因此,Doris 为夜间数据创建了太多的存储桶,但在白天创建的存储桶却太少,这与用户所需要的正好相反。用户希望增加一个新的自动分桶逻辑,参考前一天的数据大小和分布来决定分桶数量。我们正在致力于此优化。</span></p> <p style="margin-bottom: 8px;"><span style="font-size: 16px;">原文作者:ApacheDoris</span><br></p> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">不知道大家有没有遇到这种情况,接口业务逻辑写完后,用 postman 一调,发现接口响应时间好长,不得不对接口进行优化。但是此时接口的代码往往逻辑比较复杂,调用层次也比较多,很难定位到耗时较长的代码块</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">遇到这种情况大家都是如何定位耗时代码块的呢?</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">我看到很多人都是直接用<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">System.currentTimeMillis()</code>对代码进行埋点</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span> <span style="color: #a626a4;line-height: 26px;">static</span> <span style="color: #a626a4;line-height: 26px;">void</span> <span style="color: #4078f2;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> </span>{<br> Long startTime = System.currentTimeMillis();<br> exec();<br> Long endTime = System.currentTimeMillis();<br> log.info(<span style="color: #50a14f;line-height: 26px;">"exec 方法执行耗时:{}ms"</span>, endTime - startTime);<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">或者用<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">StopWatch</code>打印方法耗时</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span> <span style="color: #a626a4;line-height: 26px;">static</span> <span style="color: #a626a4;line-height: 26px;">void</span> <span style="color: #4078f2;line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> <span style="color: #a626a4;line-height: 26px;">throws</span> InterruptedException </span>{<br> StopWatch stopWatch = <span style="color: #a626a4;line-height: 26px;">new</span> StopWatch();<br> stopWatch.start(<span style="color: #50a14f;line-height: 26px;">"exec"</span>);<br> exec();<br> stopWatch.stop();<br> System.out.println(stopWatch.prettyPrint());<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这两种方法本质上是一样的,都是通过手动在代码块上进行埋点,打印出方法的耗时,该方法不仅费时费力,而且对代码有侵入,修复问题后删掉代码还是一个麻烦事</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">下面介绍如果通过<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Arthas</code>定位耗时代码块</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>Arthas 简介<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Arthas</code>是阿里开源的一款 Java 诊断工具,可以在无需重启 JVM 的情况下,实时查看应用 load、内存、gc、线程等状态信息,还能实时查看方法调用入参、出参、方法调用耗时等</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>Arthas 快速开始<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">直接下载<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Arthas</code>jar 包,然后用<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">java -jar</code>命令启动即可</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">$ curl -O https:<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//arthas.aliyun.com/arthas-boot.jar</span><br>$ java -jar arthas-boot.jar<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Arthas</code>启动的时候,会打印出当前运行的 java 进程</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">$ java -jar arthas-boot.jar<br>[INFO] JAVA_HOME: /Library/Java/JavaVirtualMachines/jdk1<span style="color: #986801;line-height: 26px;">.8</span><span style="color: #986801;line-height: 26px;">.0_351</span>.jdk/Contents/Home/jre<br>[INFO] arthas-boot version: <span style="color: #986801;line-height: 26px;">3.6</span><span style="color: #986801;line-height: 26px;">.9</span><br>[INFO] Found existing java process, please choose one and input the serial number of the process, eg : <span style="color: #986801;line-height: 26px;">1</span>. Then hit ENTER.<br>* [<span style="color: #986801;line-height: 26px;">1</span>]: <span style="color: #986801;line-height: 26px;">12512</span> com.huangxy.springstudy.SpringStudyApplication<br> [<span style="color: #986801;line-height: 26px;">2</span>]: <span style="color: #986801;line-height: 26px;">12511</span> org.jetbrains.jps.cmdline.Launcher<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">然后可以选择我们需要 attach 的 java 进程,这里我们选择 1,然后按回车。Arthas 会 attach 到目标进程上,并输出日志:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">[INFO] arthas home: /Users/huangxiaoyu/.arthas/lib/<span style="color: #986801;line-height: 26px;">3.6</span><span style="color: #986801;line-height: 26px;">.9</span>/arthas<br>[INFO] Try to attach process <span style="color: #986801;line-height: 26px;">12512</span><br>[INFO] Attach process <span style="color: #986801;line-height: 26px;">12512</span> success.<br>[INFO] arthas-client connect <span style="color: #986801;line-height: 26px;">127.0</span><span style="color: #986801;line-height: 26px;">.0</span><span style="color: #986801;line-height: 26px;">.1</span> <span style="color: #986801;line-height: 26px;">3658</span><br> ,---. ,------. ,--------.,--. ,--. ,---. ,---.<br> / O \ | .--. <span style="color: #50a14f;line-height: 26px;">''</span>--. .--<span style="color: #50a14f;line-height: 26px;">'| '</span>--<span style="color: #50a14f;line-height: 26px;">' | / O \ '</span> .-<span style="color: #50a14f;line-height: 26px;">'<br>| .-. || '</span>--<span style="color: #50a14f;line-height: 26px;">'.'</span> | | | .--. || .-. |`. `-.<br>| | | || |\ \ | | | | | || | | |.-<span style="color: #50a14f;line-height: 26px;">' |<br>`--'</span> `--<span style="color: #50a14f;line-height: 26px;">'`--'</span> <span style="color: #50a14f;line-height: 26px;">'--'</span> `--<span style="color: #50a14f;line-height: 26px;">' `--'</span> `--<span style="color: #50a14f;line-height: 26px;">'`--'</span> `--<span style="color: #50a14f;line-height: 26px;">'`-----'</span><br><br>wiki https:<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//arthas.aliyun.com/doc</span><br>tutorials https:<span style="color: #a0a1a7;font-style: italic;line-height: 26px;">//arthas.aliyun.com/doc/arthas-tutorials.html</span><br>version <span style="color: #986801;line-height: 26px;">3.6</span><span style="color: #986801;line-height: 26px;">.9</span><br>main_class com.huangxy.springstudy.SpringStudyApplication<br>pid <span style="color: #986801;line-height: 26px;">12512</span><br>time <span style="color: #986801;line-height: 26px;">2023</span>-<span style="color: #986801;line-height: 26px;">07</span>-<span style="color: #986801;line-height: 26px;">25</span> <span style="color: #986801;line-height: 26px;">09</span>:<span style="color: #986801;line-height: 26px;">14</span>:<span style="color: #986801;line-height: 26px;">22</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">到这里,Arthas 已经 attach 到我们的目标进程上了,我们尝试使用<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">dashboad</code>命令,查看进程的信息</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">$ dashboard<br>ID NAME GROUP PRIORITY STATE %CPU DELTA_TIME TIME INTERRUPT DAEMON<br><span style="color: #986801;line-height: 26px;">36</span> DestroyJavaVM main <span style="color: #986801;line-height: 26px;">5</span> RUNNABLE <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">1.748</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">false</span><br>-<span style="color: #986801;line-height: 26px;">1</span> C1 CompilerThread3 - -<span style="color: #986801;line-height: 26px;">1</span> - <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.761</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br>-<span style="color: #986801;line-height: 26px;">1</span> VM Periodic Task Thread - -<span style="color: #986801;line-height: 26px;">1</span> - <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.237</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br><span style="color: #986801;line-height: 26px;">24</span> http-nio-<span style="color: #986801;line-height: 26px;">8081</span>-exec-<span style="color: #986801;line-height: 26px;">1</span> main <span style="color: #986801;line-height: 26px;">5</span> WAITING <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.098</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br>-<span style="color: #986801;line-height: 26px;">1</span> VM Thread - -<span style="color: #986801;line-height: 26px;">1</span> - <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.071</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br><span style="color: #986801;line-height: 26px;">25</span> http-nio-<span style="color: #986801;line-height: 26px;">8081</span>-exec-<span style="color: #986801;line-height: 26px;">2</span> main <span style="color: #986801;line-height: 26px;">5</span> WAITING <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.055</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br><span style="color: #986801;line-height: 26px;">54</span> arthas-NettyHttpTelnetBootstra system <span style="color: #986801;line-height: 26px;">5</span> RUNNABLE <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.054</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br>-<span style="color: #986801;line-height: 26px;">1</span> GC task thread#<span style="color: #986801;line-height: 26px;">8</span> (ParallelGC) - -<span style="color: #986801;line-height: 26px;">1</span> - <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.043</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br>-<span style="color: #986801;line-height: 26px;">1</span> GC task thread#<span style="color: #986801;line-height: 26px;">1</span> (ParallelGC) - -<span style="color: #986801;line-height: 26px;">1</span> - <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.043</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br>-<span style="color: #986801;line-height: 26px;">1</span> GC task thread#<span style="color: #986801;line-height: 26px;">7</span> (ParallelGC) - -<span style="color: #986801;line-height: 26px;">1</span> - <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.042</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br>-<span style="color: #986801;line-height: 26px;">1</span> GC task thread#<span style="color: #986801;line-height: 26px;">6</span> (ParallelGC) - -<span style="color: #986801;line-height: 26px;">1</span> - <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.042</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br>-<span style="color: #986801;line-height: 26px;">1</span> GC task thread#<span style="color: #986801;line-height: 26px;">0</span> (ParallelGC) - -<span style="color: #986801;line-height: 26px;">1</span> - <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.042</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br>-<span style="color: #986801;line-height: 26px;">1</span> GC task thread#<span style="color: #986801;line-height: 26px;">9</span> (ParallelGC) - -<span style="color: #986801;line-height: 26px;">1</span> - <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.042</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br>-<span style="color: #986801;line-height: 26px;">1</span> GC task thread#<span style="color: #986801;line-height: 26px;">2</span> (ParallelGC) - -<span style="color: #986801;line-height: 26px;">1</span> - <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.042</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br>-<span style="color: #986801;line-height: 26px;">1</span> GC task thread#<span style="color: #986801;line-height: 26px;">3</span> (ParallelGC) - -<span style="color: #986801;line-height: 26px;">1</span> - <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.042</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br>-<span style="color: #986801;line-height: 26px;">1</span> GC task thread#<span style="color: #986801;line-height: 26px;">5</span> (ParallelGC) - -<span style="color: #986801;line-height: 26px;">1</span> - <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.042</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br>-<span style="color: #986801;line-height: 26px;">1</span> GC task thread#<span style="color: #986801;line-height: 26px;">4</span> (ParallelGC) - -<span style="color: #986801;line-height: 26px;">1</span> - <span style="color: #986801;line-height: 26px;">0.0</span> <span style="color: #986801;line-height: 26px;">0.000</span> <span style="color: #986801;line-height: 26px;">0</span>:<span style="color: #986801;line-height: 26px;">0.042</span> <span style="color: #a626a4;line-height: 26px;">false</span> <span style="color: #a626a4;line-height: 26px;">true</span><br>Memory used total max usage GC<br>heap <span style="color: #986801;line-height: 26px;">83</span>M <span style="color: #986801;line-height: 26px;">432</span>M <span style="color: #986801;line-height: 26px;">7282</span>M <span style="color: #986801;line-height: 26px;">1.14</span>% gc.ps_scavenge.count <span style="color: #986801;line-height: 26px;">4</span><br>ps_eden_space <span style="color: #986801;line-height: 26px;">72</span>M <span style="color: #986801;line-height: 26px;">212</span>M <span style="color: #986801;line-height: 26px;">2688</span>M <span style="color: #986801;line-height: 26px;">2.69</span>% gc.ps_scavenge.time(ms) <span style="color: #986801;line-height: 26px;">24</span><br>ps_survivor_space <span style="color: #986801;line-height: 26px;">0</span>K <span style="color: #986801;line-height: 26px;">21504</span>K <span style="color: #986801;line-height: 26px;">21504</span>K <span style="color: #986801;line-height: 26px;">0.00</span>% gc.ps_marksweep.count <span style="color: #986801;line-height: 26px;">2</span><br>ps_old_gen <span style="color: #986801;line-height: 26px;">10</span>M <span style="color: #986801;line-height: 26px;">199</span>M <span style="color: #986801;line-height: 26px;">5461</span>M <span style="color: #986801;line-height: 26px;">0.20</span>% gc.ps_marksweep.time(ms) <span style="color: #986801;line-height: 26px;">61</span><br>nonheap <span style="color: #986801;line-height: 26px;">53</span>M <span style="color: #986801;line-height: 26px;">56</span>M -<span style="color: #986801;line-height: 26px;">1</span> <span style="color: #986801;line-height: 26px;">94.71</span>%<br>code_cache <span style="color: #986801;line-height: 26px;">6</span>M <span style="color: #986801;line-height: 26px;">7</span>M <span style="color: #986801;line-height: 26px;">240</span>M <span style="color: #986801;line-height: 26px;">2.87</span>%<br>metaspace <span style="color: #986801;line-height: 26px;">40</span>M <span style="color: #986801;line-height: 26px;">43</span>M -<span style="color: #986801;line-height: 26px;">1</span> <span style="color: #986801;line-height: 26px;">94.45</span>%<br>compressed_class_space <span style="color: #986801;line-height: 26px;">5</span>M <span style="color: #986801;line-height: 26px;">5</span>M <span style="color: #986801;line-height: 26px;">1024</span>M <span style="color: #986801;line-height: 26px;">0.53</span>%<br>direct <span style="color: #986801;line-height: 26px;">16</span>K <span style="color: #986801;line-height: 26px;">16</span>K - <span style="color: #986801;line-height: 26px;">100.01</span>%<br>mapped <span style="color: #986801;line-height: 26px;">0</span>K <span style="color: #986801;line-height: 26px;">0</span>K - <span style="color: #986801;line-height: 26px;">0.00</span>%<br>Runtime<br>os.name Mac OS X<br>os.version <span style="color: #986801;line-height: 26px;">13.0</span><span style="color: #986801;line-height: 26px;">.1</span><br>java.version <span style="color: #986801;line-height: 26px;">1.8</span><span style="color: #986801;line-height: 26px;">.0_351</span><br>java.home /Library/Java/JavaVirtualMachines/jdk1<span style="color: #986801;line-height: 26px;">.8</span><span style="color: #986801;line-height: 26px;">.0_351</span>.jdk/Contents/<br> Home/jre<br>systemload.average <span style="color: #986801;line-height: 26px;">3.80</span><br>processors <span style="color: #986801;line-height: 26px;">12</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以看到<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">dashboad</code>命令会展示一个实时的数据面板,列出了我们平时比较关心的数据指标,如内存使用量,gc 状态等</p> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;border-left-color: rgba(0, 0, 0, 0.4);background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">更多命令的使用,可以参考官网的命令列表</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>使用 Trace 命令统计方法耗时<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">trace</code>命令能主动搜索<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">class-pattern</code>/<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">method-pattern</code>对应的方法调用路径,渲染和统计整个调用链路上的所有性能开销和追踪调用链路</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">比如下面接口</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;"><span style="color: #4078f2;line-height: 26px;">@RestController</span><br><span style="color: #a626a4;line-height: 26px;">public</span> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">class</span> <span style="color: #c18401;line-height: 26px;">HelloController</span> </span>{<br><br> <span style="color: #4078f2;line-height: 26px;">@GetMapping</span>(<span style="color: #50a14f;line-height: 26px;">"/test"</span>)<br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">public</span> String <span style="color: #4078f2;line-height: 26px;">test</span><span style="line-height: 26px;">()</span> <span style="color: #a626a4;line-height: 26px;">throws</span> InterruptedException </span>{<br> one();<br> two();<br> <span style="color: #a626a4;line-height: 26px;">return</span> <span style="color: #50a14f;line-height: 26px;">"hello"</span>;<br> }<br><br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">private</span> <span style="color: #a626a4;line-height: 26px;">void</span> <span style="color: #4078f2;line-height: 26px;">two</span><span style="line-height: 26px;">()</span> <span style="color: #a626a4;line-height: 26px;">throws</span> InterruptedException </span>{<br> Thread.sleep(<span style="color: #986801;line-height: 26px;">20</span>);<br> three();<br> }<br><br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">private</span> <span style="color: #a626a4;line-height: 26px;">void</span> <span style="color: #4078f2;line-height: 26px;">three</span><span style="line-height: 26px;">()</span> <span style="color: #a626a4;line-height: 26px;">throws</span> InterruptedException </span>{<br> Thread.sleep(<span style="color: #986801;line-height: 26px;">1000</span>);<br> }<br><br> <span style="line-height: 26px;"><span style="color: #a626a4;line-height: 26px;">private</span> <span style="color: #a626a4;line-height: 26px;">void</span> <span style="color: #4078f2;line-height: 26px;">one</span><span style="line-height: 26px;">()</span> <span style="color: #a626a4;line-height: 26px;">throws</span> InterruptedException </span>{<br> Thread.sleep(<span style="color: #986801;line-height: 26px;">100</span>);<br> }<br><br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">启动<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Arthas</code>进程,并 attach 到我们的 springboot 项目上,接着使用<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">trace</code>命令跟踪方法的调用情况</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">$ trace com.huangxy.springstudy.controller.HelloController test<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">trace</code>方法第一个参数是要 attach 的类的路径,第二个参数是方法名称,接着我们调用一遍接口,就能看到 hello 方法的调用堆栈及其耗时<img class="rich_pages wxw-img" data-ratio="0.1638888888888889" src="/upload/ead2fef7c384d0dbe2e49908e959e7b7.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;"></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">可以看到,这里耗时比较严重的是<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">tow()</code>方法,花了 1029ms,占了 90.73% 的比重</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">不过需要注意的是,trace 命令只会 trace 匹配到的函数里的子调用,并不会向下 trace 多层,如果需要 trace 多层,可以用正则匹配多个函数,如</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;"><code style="overflow-x: auto;padding: 16px;color: #383a42;background: #fafafa;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;border-radius: 0px;font-size: 12px;-webkit-overflow-scrolling: touch;">$ trace -E com.huangxy.springstudy.controller.HelloController test|two<br></code></pre> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.2222222222222222" src="/upload/3d56a20fb319255f9ad195c51926f0e4.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;"> <figcaption style="margin-top: 5px;text-align: center;color: #888;font-size: 14px;"> image.png </figcaption> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这下更清晰的定位到,导致耗时过长的方法是<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">three()</code>方法,定位到方法后,针对性的优化耗时代码块即可</p> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;border-left-color: rgba(0, 0, 0, 0.4);background: rgba(0, 0, 0, 0.05);color: rgb(106, 115, 125);padding: 10px 10px 10px 20px;margin-bottom: 20px;margin-top: 20px;"> <p style="font-size: 16px;padding-top: 8px;padding-bottom: 8px;color: black;line-height: 26px;">本文主要聊聊Kubernetes场景下收集微服务应用日志方案,相对来说更接地气,非常好落地。</p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">微服务应用的日志链路一般比较长,包含以下环节:日志收集 → 日志缓冲 → 日志过滤清洗 → 日志存储 → 日志展示。每个环节都有多种对应的组件去解决,这样的结果就是业内组合出了多种整体解决方案。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">以前我的微服务部署在IDC机房虚拟机时,采用的是ELK(Elasticsearch、Logstash、Kibana)方案,这也是通用的微服务应用的日志解决方案。几年前我们的应用部署整体切到Kubernetes后,我依旧采用了这套方案。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">下面介绍Kubernetes场景下基于ELK的日志解决方案。整体思路:Filebeat -> Kafka -> Logstash -> Elasticsearch -> Kibana。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>1、日志数据流转</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">日志数据流转见下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.43425925925925923" src="/upload/e329806538f23ed0a4c64c9b32412037.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>2、日志采集</h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>2.1、容器日志在哪儿<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">首先得有个概念:容器只是K8S集群Node上的一个进程。要在K8S集群机器上找到此Docker进程,然后进入到对应的文件夹里查看日志文件。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">一般情况下,容器的日志存放在宿主机上的这个目录下<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">/var/lib/docker/containers/</code>:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/rLpHsVF9HCUT8PxBH8unezaRoFBIkyhQRiaXSldmlicnzv31CoLY23KABkiaVcR0Qia8dqo7vQhgMiblG6I18SU5sukRWAxGJgNxv/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;"># 日志在宿主机的这个文件夹下</span><br><span style="color: #e6c07b;line-height: 26px;">cd</span> /var/lib/docker/containers<br><span style="color: #5c6370;font-style: italic;line-height: 26px;"># 用这个命令可以查找对应的日志文件</span><br>find /var/lib/docker/containers -name <span style="color: #98c379;line-height: 26px;">"*-json.log"</span><br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">进入到<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">/var/lib/docker/containers/</code>下,看到的是一堆毫无规律的文件夹。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.6194444444444445" src="/upload/8d07f62bc3615bfd05a660ad82f13319.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">看到这些毫无规律的文件夹名称,会一下子有点懵,但是仔细看看,其实这些码是对应的Docker容器的id。继续通过名称查看容器id。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/rLpHsVF9HCUT8PxBH8unezaRoFBIkyhQRiaXSldmlicnzv31CoLY23KABkiaVcR0Qia8dqo7vQhgMiblG6I18SU5sukRWAxGJgNxv/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #5c6370;font-style: italic;line-height: 26px;"># docker命令查看容器</span><br>docker ps -a<br></code></pre> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.3574074074074074" src="/upload/52ab1d98e2d8d477f6d8364d1a3e1c3c.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">找到了容器id之后,可以看到用容器id的前几位,可以完全匹配到,日志文件夹名称的前几位。<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">docker ps</code> 显示的容器id只是显示了整个id的前几位。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img data-ratio="0.10925925925925926" src="/upload/38db2b7bd0d48689a35ce4dcbee7e34c.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.21851851851851853" src="/upload/f66daab38429c5744577f9c0e4e939f1.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">进入到日志文件夹后,就可以看到具体的json日志文件了。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.1361111111111111" src="/upload/3d4d45a621074d75c61b076f56b29987.png" data-type="png" data-w="1080" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">至此已经知道日志文件存放的位置了。当然啦,要控制好日志级别,还要做好日志清理任务,否则大量的日志会导致磁盘空间不够。Pod销毁之后,日志文件也会被销毁的。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">文件找到了接下来,就看怎么采集日志了。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>2.2、日志采集工具<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">日志采集工具有多种,本文采用<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Filebeat</code>作为日志采集工具。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Filebeat是用于转发和汇总日志与文件的轻量级传送程序。作为服务器上的代理安装,Filebeat会监视你指定的日志文件或位置。然后收集日志事件,并将它们转发到Elasticsearch或Logstash或Kafka。官方文档显示的工作流程如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.7819148936170213" src="/upload/8dd64a7e49a53d98c3f83264c0bbbbaa.png" data-type="png" data-w="940" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Filebeat的主要优势有:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 轻量级并且易使用 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 免费开源 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 资源使用率低 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 良好的性能 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>2.3、日志如何采集<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">日志采集工具选型确定之后,接下来就是如何采集了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">K8S部署的场景下,想要收集每台Node下的容器日志,需要采用<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">Deamonset控制器</code>自动部署,这样每次新增节点时,会自动部署Filebeat的Pod。每台Node自动安装好Filebeat后,每台Node上的日志会被自动采集,然后输出到Kafka。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Filebeat大致的编排yaml如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/rLpHsVF9HCUT8PxBH8unezaRoFBIkyhQRiaXSldmlicnzv31CoLY23KABkiaVcR0Qia8dqo7vQhgMiblG6I18SU5sukRWAxGJgNxv/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;"><span style="color: #d19a66;line-height: 26px;">apiVersion:</span> <span style="color: #98c379;line-height: 26px;">v1</span><br><span style="color: #d19a66;line-height: 26px;">kind:</span> <span style="color: #98c379;line-height: 26px;">ConfigMap</span><br><span style="color: #d19a66;line-height: 26px;">metadata:</span><br> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">filebeat-config</span><br> <span style="color: #d19a66;line-height: 26px;">namespace:</span> <span style="color: #98c379;line-height: 26px;">ops-monit</span><br> <span style="color: #d19a66;line-height: 26px;">labels:</span><br> <span style="color: #d19a66;line-height: 26px;">k8s-app:</span> <span style="color: #98c379;line-height: 26px;">filebeat</span><br><span style="color: #d19a66;line-height: 26px;">data:</span><br> <span style="color: #d19a66;line-height: 26px;">filebeat.yml:</span> <span style="color: #98c379;line-height: 26px;">|-<br> filebeat.inputs:<br> - type: container #因为是采集的容器日志,所以这里要用container 不能用 log,否则拿不到容器日志<br> enable: true<br> stream: stdout #只取stdout日志<br> paths:<br> - /var/log/containers/*demo*.log #采集了demo环境的所有日志<br> processors:<br> - add_kubernetes_metadata: # 增加kubernetes的属性<br> in_cluster: true<br> host: ${NODE_NAME}<br> matchers:<br> - logs_path:<br> logs_path: "/var/log/containers/"<br> - drop_event:<br> when:<br> contains:<br> message: "INFO"<br> - drop_event:<br> when:<br> contains:<br> message: "DEBUG"<br> # 配置多行显示<br> multiline.type: pattern<br> multiline.pattern: '^[0-9]{4}-[0-9]{2}-[0-9]{2}'<br> multiline.negate: true<br> multiline.match: after<br> fields:<br> logtype: applog<br> output.kafka:<br> hosts: ['172.10.10.10:9092','172.10.10.11:9092','172.10.10.12:9092']<br> topic: 'topic-bizlog'<br> partition.round_robin:<br> reachable_only: false<br></span><span style="color: #61aeee;line-height: 26px;">---</span><br><span style="color: #d19a66;line-height: 26px;">apiVersion:</span> <span style="color: #98c379;line-height: 26px;">apps/v1</span><br><span style="color: #d19a66;line-height: 26px;">kind:</span> <span style="color: #98c379;line-height: 26px;">DaemonSet</span><br><span style="color: #d19a66;line-height: 26px;">metadata:</span><br> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">filebeat</span><br> <span style="color: #d19a66;line-height: 26px;">namespace:</span> <span style="color: #98c379;line-height: 26px;">ops-monit</span><br> <span style="color: #d19a66;line-height: 26px;">labels:</span><br> <span style="color: #d19a66;line-height: 26px;">k8s-app:</span> <span style="color: #98c379;line-height: 26px;">filebeat</span><br><span style="color: #d19a66;line-height: 26px;">spec:</span><br> <span style="color: #d19a66;line-height: 26px;">selector:</span><br> <span style="color: #d19a66;line-height: 26px;">matchLabels:</span><br> <span style="color: #d19a66;line-height: 26px;">k8s-app:</span> <span style="color: #98c379;line-height: 26px;">filebeat</span><br> <span style="color: #d19a66;line-height: 26px;">template:</span><br> <span style="color: #d19a66;line-height: 26px;">metadata:</span><br> <span style="color: #d19a66;line-height: 26px;">labels:</span><br> <span style="color: #d19a66;line-height: 26px;">k8s-app:</span> <span style="color: #98c379;line-height: 26px;">filebeat</span><br> <span style="color: #d19a66;line-height: 26px;">spec:</span><br> <span style="color: #d19a66;line-height: 26px;">serviceAccountName:</span> <span style="color: #98c379;line-height: 26px;">filebeat</span><br> <span style="color: #d19a66;line-height: 26px;">terminationGracePeriodSeconds:</span> <span style="color: #d19a66;line-height: 26px;">30</span><br> <span style="color: #d19a66;line-height: 26px;">dnsPolicy:</span> <span style="color: #98c379;line-height: 26px;">ClusterFirstWithHostNet</span><br> <span style="color: #d19a66;line-height: 26px;">containers:</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">filebeat</span><br> <span style="color: #d19a66;line-height: 26px;">image:</span> <span style="color: #98c379;line-height: 26px;">elastic/filebeat:7.12.1</span><br> <span style="color: #d19a66;line-height: 26px;">args:</span> <span style="color: #98c379;line-height: 26px;">[</span><br> <span style="color: #98c379;line-height: 26px;">"-c"</span><span style="color: #98c379;line-height: 26px;">,</span> <span style="color: #98c379;line-height: 26px;">"/etc/filebeat.yml"</span><span style="color: #98c379;line-height: 26px;">,</span><br> <span style="color: #98c379;line-height: 26px;">"-e"</span><span style="color: #98c379;line-height: 26px;">,</span><br> <span style="color: #98c379;line-height: 26px;">]</span><br> <span style="color: #d19a66;line-height: 26px;">env:</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">ELASTICSEARCH_HOST</span><br> <span style="color: #d19a66;line-height: 26px;">value:</span> <span style="color: #98c379;line-height: 26px;">"172.10.20.10"</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">ELASTICSEARCH_PORT</span><br> <span style="color: #d19a66;line-height: 26px;">value:</span> <span style="color: #98c379;line-height: 26px;">"9200"</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">ELASTICSEARCH_USERNAME</span><br> <span style="color: #d19a66;line-height: 26px;">value:</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">ELASTICSEARCH_PASSWORD</span><br> <span style="color: #d19a66;line-height: 26px;">value:</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">ELASTIC_CLOUD_ID</span><br> <span style="color: #d19a66;line-height: 26px;">value:</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">ELASTIC_CLOUD_AUTH</span><br> <span style="color: #d19a66;line-height: 26px;">value:</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">NODE_NAME</span><br> <span style="color: #d19a66;line-height: 26px;">valueFrom:</span><br> <span style="color: #d19a66;line-height: 26px;">fieldRef:</span><br> <span style="color: #d19a66;line-height: 26px;">fieldPath:</span> <span style="color: #98c379;line-height: 26px;">spec.nodeName</span><br> <span style="color: #d19a66;line-height: 26px;">securityContext:</span><br> <span style="color: #d19a66;line-height: 26px;">runAsUser:</span> <span style="color: #d19a66;line-height: 26px;">0</span><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;"># If using Red Hat OpenShift uncomment this:</span><br> <span style="color: #5c6370;font-style: italic;line-height: 26px;"># privileged: true</span><br> <span style="color: #d19a66;line-height: 26px;">resources:</span><br> <span style="color: #d19a66;line-height: 26px;">limits:</span><br> <span style="color: #d19a66;line-height: 26px;">cpu:</span> <span style="color: #98c379;line-height: 26px;">3000m</span><br> <span style="color: #d19a66;line-height: 26px;">memory:</span> <span style="color: #98c379;line-height: 26px;">2000Mi</span><br> <span style="color: #d19a66;line-height: 26px;">requests:</span><br> <span style="color: #d19a66;line-height: 26px;">cpu:</span> <span style="color: #98c379;line-height: 26px;">500m</span><br> <span style="color: #d19a66;line-height: 26px;">memory:</span> <span style="color: #98c379;line-height: 26px;">100Mi</span><br> <span style="color: #d19a66;line-height: 26px;">volumeMounts:</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">timezone</span><br> <span style="color: #d19a66;line-height: 26px;">mountPath:</span> <span style="color: #98c379;line-height: 26px;">/etc/localtime</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">config</span><br> <span style="color: #d19a66;line-height: 26px;">mountPath:</span> <span style="color: #98c379;line-height: 26px;">/etc/filebeat.yml</span><br> <span style="color: #d19a66;line-height: 26px;">readOnly:</span> <span style="color: #56b6c2;line-height: 26px;">true</span><br> <span style="color: #d19a66;line-height: 26px;">subPath:</span> <span style="color: #98c379;line-height: 26px;">filebeat.yml</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">data</span><br> <span style="color: #d19a66;line-height: 26px;">mountPath:</span> <span style="color: #98c379;line-height: 26px;">/usr/share/filebeat/data</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">varlibdockercontainers</span><br> <span style="color: #d19a66;line-height: 26px;">mountPath:</span> <span style="color: #98c379;line-height: 26px;">/var/lib/docker/containers</span><br> <span style="color: #d19a66;line-height: 26px;">readOnly:</span> <span style="color: #56b6c2;line-height: 26px;">true</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">varlog</span><br> <span style="color: #d19a66;line-height: 26px;">mountPath:</span> <span style="color: #98c379;line-height: 26px;">/var/log</span><br> <span style="color: #d19a66;line-height: 26px;">volumes:</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">timezone</span><br> <span style="color: #d19a66;line-height: 26px;">hostPath:</span><br> <span style="color: #d19a66;line-height: 26px;">path:</span> <span style="color: #98c379;line-height: 26px;">/usr/share/zoneinfo/Asia/Shanghai</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">config</span><br> <span style="color: #d19a66;line-height: 26px;">configMap:</span><br> <span style="color: #d19a66;line-height: 26px;">defaultMode:</span> <span style="color: #d19a66;line-height: 26px;">0640</span><br> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">filebeat-config</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">varlibdockercontainers</span><br> <span style="color: #d19a66;line-height: 26px;">hostPath:</span><br> <span style="color: #d19a66;line-height: 26px;">path:</span> <span style="color: #98c379;line-height: 26px;">/var/lib/docker/containers</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">varlog</span><br> <span style="color: #d19a66;line-height: 26px;">hostPath:</span><br> <span style="color: #d19a66;line-height: 26px;">path:</span> <span style="color: #98c379;line-height: 26px;">/var/log</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">data</span><br> <span style="color: #d19a66;line-height: 26px;">hostPath:</span><br> <span style="color: #d19a66;line-height: 26px;">path:</span> <span style="color: #98c379;line-height: 26px;">/var/lib/filebeat-data</span><br> <span style="color: #d19a66;line-height: 26px;">type:</span> <span style="color: #98c379;line-height: 26px;">DirectoryOrCreate</span><br><span style="color: #61aeee;line-height: 26px;">---</span><br><span style="color: #d19a66;line-height: 26px;">apiVersion:</span> <span style="color: #98c379;line-height: 26px;">rbac.authorization.k8s.io/v1</span><br><span style="color: #d19a66;line-height: 26px;">kind:</span> <span style="color: #98c379;line-height: 26px;">ClusterRoleBinding</span><br><span style="color: #d19a66;line-height: 26px;">metadata:</span><br> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">filebeat</span><br> <span style="color: #d19a66;line-height: 26px;">namespace:</span> <span style="color: #98c379;line-height: 26px;">ops-monit</span><br><span style="color: #d19a66;line-height: 26px;">subjects:</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">kind:</span> <span style="color: #98c379;line-height: 26px;">ServiceAccount</span><br> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">filebeat</span><br> <span style="color: #d19a66;line-height: 26px;">namespace:</span> <span style="color: #98c379;line-height: 26px;">ops-monit</span><br><span style="color: #d19a66;line-height: 26px;">roleRef:</span><br> <span style="color: #d19a66;line-height: 26px;">kind:</span> <span style="color: #98c379;line-height: 26px;">ClusterRole</span><br> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">filebeat</span><br> <span style="color: #d19a66;line-height: 26px;">apiGroup:</span> <span style="color: #98c379;line-height: 26px;">rbac.authorization.k8s.io</span><br><span style="color: #61aeee;line-height: 26px;">---</span><br><span style="color: #d19a66;line-height: 26px;">apiVersion:</span> <span style="color: #98c379;line-height: 26px;">rbac.authorization.k8s.io/v1</span><br><span style="color: #d19a66;line-height: 26px;">kind:</span> <span style="color: #98c379;line-height: 26px;">ClusterRole</span><br><span style="color: #d19a66;line-height: 26px;">metadata:</span><br> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">filebeat</span><br> <span style="color: #d19a66;line-height: 26px;">namespace:</span> <span style="color: #98c379;line-height: 26px;">ops-monit</span><br> <span style="color: #d19a66;line-height: 26px;">labels:</span><br> <span style="color: #d19a66;line-height: 26px;">k8s-app:</span> <span style="color: #98c379;line-height: 26px;">filebeat</span><br><span style="color: #d19a66;line-height: 26px;">rules:</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #d19a66;line-height: 26px;">apiGroups:</span> <span style="color: #98c379;line-height: 26px;">[""]</span> <span style="color: #5c6370;font-style: italic;line-height: 26px;"># "" indicates the core API group</span><br> <span style="color: #d19a66;line-height: 26px;">resources:</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #98c379;line-height: 26px;">namespaces</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #98c379;line-height: 26px;">pods</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #98c379;line-height: 26px;">nodes</span><br> <span style="color: #d19a66;line-height: 26px;">verbs:</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #98c379;line-height: 26px;">get</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #98c379;line-height: 26px;">watch</span><br> <span style="color: #61aeee;line-height: 26px;">-</span> <span style="color: #98c379;line-height: 26px;">list</span><br><span style="color: #61aeee;line-height: 26px;">---</span><br><span style="color: #d19a66;line-height: 26px;">apiVersion:</span> <span style="color: #98c379;line-height: 26px;">v1</span><br><span style="color: #d19a66;line-height: 26px;">kind:</span> <span style="color: #98c379;line-height: 26px;">ServiceAccount</span><br><span style="color: #d19a66;line-height: 26px;">metadata:</span><br> <span style="color: #d19a66;line-height: 26px;">name:</span> <span style="color: #98c379;line-height: 26px;">filebeat</span><br> <span style="color: #d19a66;line-height: 26px;">namespace:</span> <span style="color: #98c379;line-height: 26px;">ops-monit</span><br> <span style="color: #d19a66;line-height: 26px;">labels:</span><br> <span style="color: #d19a66;line-height: 26px;">k8s-app:</span> <span style="color: #98c379;line-height: 26px;">filebeat</span><br><span style="color: #61aeee;line-height: 26px;">---</span><br></code></pre> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>3、日志缓冲、过滤清洗、存储、展示</h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>3.1、缓冲<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Kafka是一个消息处理引擎,这里采用Kafka作为日志数据的缓冲工具。采用Kafka有2个用途:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 作为缓冲,防止日志量太大导致下游来不及消费,所以要加入消息缓冲这一层。这一层必不可少。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> Kafka消息可以被别的应用监听消费,过滤输出到一些告警信息到企微、钉钉、邮件等。 </section></li> </ul> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>3.2、过滤清洗和转发<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Logstash 是一个日志收集和处理引擎,它带有各种各样的插件,能够从各种来源摄取数据。并且可以对数据进行转换,然后转发到目的地。我这里采用Logstash作为日志摄取、过滤、清洗、转发的工具。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">这是一个大概的Logstash Conf文件,文件的内容分3块:<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">input</code> 、<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">filter</code> 、<code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">output</code>。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/rLpHsVF9HCUT8PxBH8unezaRoFBIkyhQRiaXSldmlicnzv31CoLY23KABkiaVcR0Qia8dqo7vQhgMiblG6I18SU5sukRWAxGJgNxv/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(40, 44, 52);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #abb2bf;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #282c34;border-radius: 5px;">input {<br> kafka {<br> bootstrap_servers=>"172.10.7.79:9092"<br> topics=>["topic-bizlogs"]<br> codec => "json"<br> }<br>}<br><br>filter{<br> mutate{<br> split => ["message", "|"]<br> add_field => { "log_time" => "%{[message][0]}"}<br> add_field => { "level" => "%{[message][1]}"}<br> add_field => { "class" => "%{[message][2]}"}<br> add_field => { "line" => "%{[message][3]}"}<br> add_field => { "thread" => "%{[message][4]}"}<br> add_field => { "log_message" => "%{[message][5]}"}<br><br> add_field => { "env" => "%{[kubernetes][namespace]}"}<br> add_field => { "podName" => "%{[kubernetes][pod][name]}"}<br> add_field => { "podId" => "%{[kubernetes][pod][uid]}"}<br> add_field => { "image" => "%{[container][image][name]}"}<br> add_field => { "imageId" => "%{[container][id]}"}<br> add_field => { "nodeId" => "%{[kubernetes][node][uid]}"}<br> add_field => { "nodeName" => "%{[kubernetes][node][name]}"}<br> add_field => { "nodeHostName" => "%{[kubernetes][node][hostname]}"}<br> add_field => { "logPath" => "%{[log][file][path]}"}<br> add_field => { "appName" => "%{[kubernetes][labels][app]}"}<br><br> remove_field => ["agent","fields","input","ecs","host","@version","kubernetes","stream","log","container"]<br> }<br>}<br><br>output{<br> elasticsearch{<br> hosts=>["172.11.4.82:9200"]<br> index => "%{appName}‐%{+YYYY.MM.dd}"<br><br> }<br>}<br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>3.3、存储和搜索<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">Elasticsearch是一个可扩展的搜索引擎,这里采用Elasticsearch作为日志存储搜索工具。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 20px;"><span style="display: none;"></span>3.4、展示<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">采用Kibana为日志构建可视化的UI。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 30px;margin-bottom: 15px;font-weight: bold;font-size: 22px;"><span style="display: none;"></span>4、总结</h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">本文主要介绍Kubernetes场景下比较接地气好落地的,基于ELK的日志解决方案。整体思路:Filebeat -> Kafka -> Logstash -> Elasticsearch -> Kibana。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;">本文没有介绍Kafka、Logstash、Elasticsearch、Kibana的安装,只提及了一些配置文件,安装过程读者自行查阅资料搭建。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><strong>本篇完结!感谢你的阅读,欢迎点赞 关注 收藏 私信!!!</strong></p> <section class="mp_profile_iframe_wrp"> <mp-common-profile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="MzI3OTA2MDQyOQ==" data-headimg="http://mmbiz.qpic.cn/sz_mmbiz_png/iaKiaGaGnVlcHDFk7YlZ6MLUftpPmuiaXDXcHh5EJWGjuByb7x8ZibwsAPKMhvUODRSOXGN4vOQ8VN2uou3etA8mAQ/0?wx_fmt=png" data-nickname="不焦躁的程序员" data-alias="yclxiaobjzcxy" data-signature="13年IT行业经验,做过架构创过业,一起交流学习。专注于软件开发、云原生、大数据领域。关注我职业发展不焦虑。" data-from="0" data-is_biz_ban="0"></mp-common-profile> </section> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;line-height: 26px;"><br></p> </section> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<p style="text-wrap: wrap;text-align: left;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;font-size: 15px;margin-right: 8px;margin-bottom: 1.5em;margin-left: 8px;letter-spacing: 0.1em;color: rgb(63, 63, 63);">本文通过自动化查询域名或公司的备案信息,来演示其中图片滑动验证码的破解方式,以此来思考验证码的安全性问题,思考如何设计出安全性更高的验证码。</p> <figure style="letter-spacing: normal;text-wrap: wrap;text-align: left;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;font-size: 15px;margin: 1.5em 8px;color: rgb(63, 63, 63);"> <img class="rich_pages wxw-img" data-ratio="0.4537037037037037" src="/upload/f25769ac63fe05b68d7073800883496c.png" data-type="other" data-w="1080" style="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;border-radius: 4px;display: block;margin: 0.1em auto 0.5em;" title="null"> </figure> <blockquote style="letter-spacing: normal;text-wrap: wrap;text-align: left;line-height: 1.75;font-family: -apple-system-font, BlinkMacSystemFont, "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "
作者:微信小助手
<blockquote style="margin-top: 0px;margin-bottom: 1.2em;padding: 15px 15px 15px 1rem;color: rgb(129, 145, 152);border-left-width: 6px;border-left-color: rgb(96, 125, 139);font-size: 14px;line-height: 22px;background: rgb(242, 247, 251);letter-spacing: normal;text-align: start;text-wrap: wrap;"> <p style="margin-bottom: 15px;white-space-collapse: preserve-breaks;line-height: 30px;color: rgb(74, 74, 74);">作者简介</p> <ul style="padding-left: 30px;list-style-position: initial;list-style-image: initial;margin-top: 6px !important;list-style-type: square !important;" class="list-paddingleft-1"> <li style="margin-top: 6px !important;"><p><span style="color: rgb(74, 74, 74);line-height: 22px;">伍菊红,来自货拉拉/技术中心/质量保障部,主要负责营销活动相关质量保障以及流量回放开发工作。</span></p></li> <li style="margin-top: 6px !important;"><p><span style="color: rgb(74, 74, 74);line-height: 22px;">史浩,来自货拉拉/技术中心/质量保障部,主要负责交易引擎相关质量保障以及流量回放开发工作。</span></p></li> </ul> </blockquote> <h2 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 24px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">一、背景与挑战</h2> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">货拉拉是一家正在快速发展的公司,在业务不断丰富的同时,对技术部门所带来的是快速迭代的奔跑和越来越复杂的业务链路,服务稳定性和人效均面临巨大挑战。初期都是通过补齐接口自动化这种传统模式保障,该模式虽然简单便捷,但存在成本高、覆盖场景有限、标准化难度高等问题。基于此,我们希望搭建一个流量回放平台,利用海量的流量自动构建丰富的测试场景保障测试范围和节省人力。</p> <h2 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 24px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">二、LLRepeater</h2> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">流量回放是一种通过复制线上/测试环境的实际流量(录制),然后在测试环境中进行模拟请求(回放)来验证代码逻辑正确性的方法。目前,市面上有许多开源产品都提供这种功能,其中包括阿里开源的工具jvm-sandbox-repeater,基于Go语言的GoReplay,以及TcpXCopy等。考虑到我们公司主要技术栈还是以java为主,并且我们注意到一些公司,如vivo、得物、酷家乐等,都在使用jvm-sandbox-repeater,综合考虑,我们决定选择jvm sandbox repeater作为我们的底层框架,来设计货拉拉的流量回放平台LLRepeater。</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">接下来将为大家展开介绍流量回放体系在货拉拉的平台设计、实现、挑战以及效果。</p> <h3 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 20px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">2.1 平台架构设计</h3> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">平台设计</strong> <strong style="color: rgb(0, 0, 0);">共有以下5大块:</strong></p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">插件管理</strong> -负责插件的安装、卸载、心跳、启动、冻结、配置推送等一系列与jvm sandbox agent相交互的事情;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">流量中心</strong> -打造流量库,提供流量查询、存储、分析、构造等一系列功能,为自动化、压测模型等赋能;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">录制服务</strong> -负责录制流量存储、打标、过滤等相关工作;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">回放服务</strong> -负责实时/手动/自动回放/回放速率/回放结果汇聚等工作;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">对比服务</strong> -负责降噪配置,结果比对,diffy分析等;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><img class="rich_pages wxw-img" data-ratio="0.4925925925925926" src="/upload/80ce350118a2fea258910e160a88f18a.jpg" data-type="jpeg" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <h3 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 20px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">2.2 核心功能实现</h3> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">核心功能共有以下3大块:</strong></p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">挂载</strong>-控制台下发挂载命令至被测服务,挂载命令会触发jvm sandbox repeater 挂载;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">录制</strong>-agent录制流量转发至控制台,控制台将流量转发至录制kafka,录制服务消费该消息流量存储至es;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">回放</strong>-发起回放,回放结果转发至控制台,控制台将流量转发至回放kafka,回放服务消费该消息,再调用对比服务进行比对降噪,处理结果存储至es&db;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><img class="rich_pages wxw-img" data-ratio="0.6111111111111112" src="/upload/9dd43102c2e5070234bf9d563466112f.jpg" data-type="jpeg" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <h3 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 20px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">2.3 平台挑战</h3> <h4 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 18px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">2.3.1 底层插件适配</h4> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">货拉拉的业务种类非常多,各个部门使用姿势也不尽相同,为适配现有业务,插件需要不断进行适配,目前已经适配插件如下:</p> <table width="659"> <thead> <tr> <th style="padding: 0.5rem 1rem;text-align: left;border-top-width: 1px;border-color: rgb(233, 235, 236);">组件类型</th> <th style="padding: 0.5rem 1rem;text-align: left;border-top-width: 1px;border-color: rgb(233, 235, 236);">描述</th> <th style="padding: 0.5rem 1rem;text-align: left;border-top-width: 1px;border-color: rgb(233, 235, 236);">录制</th> <th style="padding: 0.5rem 1rem;text-align: left;border-top-width: 1px;border-color: rgb(233, 235, 236);">回放</th> <th style="padding: 0.5rem 1rem;text-align: left;border-top-width: 1px;border-color: rgb(233, 235, 236);">入口流量</th> </tr> </thead> <tbody> <tr> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">http</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">http请求</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> </tr> <tr style="background-color: rgb(248, 248, 248);"> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">rpc</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">自研rpc请求</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> </tr> <tr> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">apollo</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">服务配置组件</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">❌</td> </tr> <tr style="background-color: rgb(248, 248, 248);"> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">feign</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">easyOpen组件</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">❌</td> </tr> <tr> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">ibatis</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">ibatis组件</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">❌</td> </tr> <tr style="background-color: rgb(248, 248, 248);"> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">mybatis</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">mybatis组件</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">❌</td> </tr> <tr> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">redis</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">redis组件</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">❌</td> </tr> <tr style="background-color: rgb(248, 248, 248);"> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">lala-redis</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">Lala redis组件</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">❌</td> </tr> <tr> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">guava-cache</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">guava缓存</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">❌</td> </tr> <tr style="background-color: rgb(248, 248, 248);"> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">en-cache</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">ehcache缓存</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">❌</td> </tr> <tr> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">caffeine-cache</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">caffeine缓存</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">❌</td> </tr> <tr style="background-color: rgb(248, 248, 248);"> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">kafka</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">kafka组件</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> <td style="padding: 0.5rem 1rem;border-color: rgb(233, 235, 236);">✅</td> </tr> </tbody> </table> <h4 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 18px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">2.3.2 频繁Full GC</h4> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">系统在初期推广频繁触发Full GC,服务超时等问题,经过分析主要有以下几点原因:</p> <ul style="padding-left: 30px;list-style-position: initial;list-style-image: initial;color: rgb(80, 97, 109);font-size: 15px;letter-spacing: normal;text-align: start;text-wrap: wrap;margin-top: 6px !important;list-style-type: square !important;" class="list-paddingleft-1"> <li style="margin-top: 6px !important;"><p><span style="color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;">部分子调用反复被调用,比较明显的是配置中心apollo以及guava cache这两个子调用,单条流量中相同请求多达10次以上,这样的流量一旦过多,会导致内存中大对象变多,容易触发FULL GC;</span></p></li> <li style="margin-top: 6px !important;"><p><span style="color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;">序列化对象偏大,存在部分非业务代码导致的序列化字节数特别大的请求,如服务发现等;</span></p></li> </ul> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">针对这些问题,进行了如下优化:</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">1)apollo以及guava 重复请求只录制一次;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><img class="rich_pages wxw-img" data-ratio="0.33425925925925926" src="/upload/9e1ba619a8ca96eb4f7b06e2b5ec9279.png" data-type="png" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">2)非业务代码导致的序列化字节超大的请求,skip掉;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><img class="rich_pages wxw-img" data-ratio="0.6268518518518519" src="/upload/f6f2594b16beb21f74f1eca844c22029.png" data-type="png" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">3)对录制过程进行监控/异常降级;</p> <h4 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 18px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">2.3.3 流量录制不均、筛选困难</h4> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">流量回放的主要优势在于能够收集线上的真实流量,然而在生产环境中收集流量时,会遇到两个问题。首先,由于服务的qps很高,全面收集流量可能影响业务服务的性能,也会造成资源浪费(存储一堆流量),其次许多流量都是重复的,这些重复流量对业务测试帮助不大,全面收集并没有太大的意义。因此,生产采集流量,全局采样率配置一般不会太高。但是这种模式可能导致大部分收集到的流量都来自于qps较高的接口,而请求量小的接口很难被收集到。为了解决这些问题,我们采用接口维度进行流量录制的配置,具体措施如下:</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">1)</strong> <strong style="color: rgb(0, 0, 0);">录制不均</strong> <strong style="color: rgb(0, 0, 0);">:</strong> 支持接口配置,接口优先级高于全局采样率,可以灵活调整各个接口的比例;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><img class="rich_pages wxw-img" data-ratio="0.9222222222222223" src="/upload/fb696f44ba31f5529193da6c33958fc5.png" data-type="png" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"><img class="rich_pages wxw-img" data-ratio="0.6509259259259259" src="/upload/cdcd0f4bf91b06ba9ba609e58ae7bcee.png" data-type="png" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">2)</strong> <strong style="color: rgb(0, 0, 0);">筛选</strong> <strong style="color: rgb(0, 0, 0);">困难:</strong> 可以从多个维度,针对单条流量进行打标,方便用户筛选出自己需要的流量;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><img class="rich_pages wxw-img" data-ratio="0.3435185185185185" src="/upload/dfc8e6098c21f3a09478fe0a69f8cafd.png" data-type="png" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"><img class="rich_pages wxw-img" data-ratio="0.45" src="/upload/f361e7b26c53f85bebf232ac92eea1ce.png" data-type="png" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <h4 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 18px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">2.3.4 回放排查成本高</h4> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">流量回放老大难的问题就是排查成本高,整个录制和回放都是非常复杂的过程,特别是碰到一些子调用高达上百条的流量,回放失败后,使用者无从下手。为了提升排查效率,我们也做了非常多的事情:</p> <ul style="padding-left: 30px;list-style-position: initial;list-style-image: initial;color: rgb(80, 97, 109);font-size: 15px;letter-spacing: normal;text-align: start;text-wrap: wrap;margin-top: 6px !important;list-style-type: square !important;" class="list-paddingleft-1"> <li style="margin-top: 6px !important;"><p><span style="color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;">与公司的监控链路打通,可以查看整个录制以及回放trace 链路;</span></p></li> <li style="margin-top: 6px !important;"><p><span style="color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;">agent优化,子调用排序,回放详情会打上对应的match标签,方便用户找到排查的入口;</span></p></li> <li style="margin-top: 6px !important;"><p><span style="color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;">批量详情支持按失败原因汇聚,减少重复排查;</span></p></li> <li style="margin-top: 6px !important;"><p><span style="color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;">常见失败排查策略推荐,领头羊培养等;</span></p></li> </ul> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><img class="rich_pages wxw-img" data-ratio="0.4925925925925926" src="/upload/c18f404ea7bf6ab63f1f6eeb3d7490c8.png" data-type="png" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"><img class="rich_pages wxw-img" data-ratio="0.43796296296296294" src="/upload/ffafad41b92da21787e4d14b5c0a14ae.png" data-type="png" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <h3 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 20px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">2.4 平台效果</h3> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">为了更方便用户使用,平台设计重点主要围绕"使用成本"、"有抓手"、"能力多样化"、"智能化"等多个角度展开,</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">接下来将从平台优势和特色效果来展开阐述:</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">1)平台</strong><strong style="color: rgb(0, 0, 0);">优势</strong></p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">接入成本低</strong> <strong style="color: rgb(0, 0, 0);">:</strong> 从接入、配置、录制、回放整个过程,新手大概30 min内完成;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">使用便捷高效:</strong> 流量支持多规则打标、智能降噪、回放结果汇聚等能力,降低排查成本;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">结果透明化:</strong> 与公司覆盖率打通,智能生成回放报告;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">个性化支持</strong> <strong style="color: rgb(0, 0, 0);">:</strong> 支持定时、实时、手动等多种回放姿势;</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><img class="rich_pages wxw-img" data-ratio="0.42962962962962964" src="/upload/6fa9aab79d559971989853bdd792d7d5.png" data-type="png" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"><img class="rich_pages wxw-img" data-ratio="1.5638888888888889" src="/upload/40152ea79591ac9cd3b1a34180712c5a.png" data-type="png" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><img class="rich_pages wxw-img" data-ratio="0.3416666666666667" src="/upload/c69c75cc9470594af6d13c0f24c821d3.png" data-type="png" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><img class="rich_pages wxw-img" data-ratio="0.29444444444444445" src="/upload/fc7f849e324cffec18e510d6bd4272a2.png" data-type="png" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><strong style="color: rgb(0, 0, 0);">2)平台特色</strong></p> <ul style="padding-left: 30px;list-style-position: initial;list-style-image: initial;color: rgb(80, 97, 109);font-size: 15px;letter-spacing: normal;text-align: start;text-wrap: wrap;margin-top: 6px !important;list-style-type: square !important;" class="list-paddingleft-1"> <li style="margin-top: 6px !important;"><p><span style="color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;"><span style="line-height: 22px;"><strong style="color: rgb(0, 0, 0);">自动回放</strong></span></span></p></li> </ul> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">自动回放是指针对只读接口,采用手动/定时触发的方式,使用实时录制的指定/随机流量进行非mock的降噪回放,汇总结果数据,进而实现“0”测试人力成本完整的查询接口测试。此方式误报率极低,不用担心代码链路变动用不了,也能更全面的覆盖线上场景。</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><img class="rich_pages wxw-img" data-ratio="0.9518518518518518" src="/upload/b34be5b673703989ee4dbc286bdb01d6.jpg" data-type="jpeg" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <ul style="padding-left: 30px;list-style-position: initial;list-style-image: initial;color: rgb(80, 97, 109);font-size: 15px;letter-spacing: normal;text-align: start;text-wrap: wrap;margin-top: 6px !important;list-style-type: square !important;" class="list-paddingleft-1"> <li style="margin-top: 6px !important;"><p><span style="color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;"><span style="line-height: 22px;"><strong style="color: rgb(0, 0, 0);">链路回放</strong></span></span></p></li> </ul> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">在多个大型核心系统架构升级背景下,基于现有单服务录制能力、货拉拉全局Trace能力、业务场景代码插桩能力,与研发团队共建了链路级流量回放能力,经过重构项目的应用,链路录制回放探索落地已取得初步胜利。</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><img class="rich_pages wxw-img" data-ratio="0.9101851851851852" src="/upload/10fe73ad3ac079d69f00c2c2f3307380.png" data-type="png" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <ul style="padding-left: 30px;list-style-position: initial;list-style-image: initial;color: rgb(80, 97, 109);font-size: 15px;letter-spacing: normal;text-align: start;text-wrap: wrap;margin-top: 6px !important;list-style-type: square !important;" class="list-paddingleft-1"> <li style="margin-top: 6px !important;"><p><span style="color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;"><span style="line-height: 22px;"><strong style="color: rgb(0, 0, 0);">接收外部流量输入并在平台内进行回放</strong></span></span></p></li> </ul> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">当前的流量录制与回放仅支持java系统,但对于服务语言(其他语言转java)重构的项目,此平台就无任何用武之地。为了能在此种项目中发挥效果,故将平台本身的录制模块进行灵活化改造,可以录制java服务流量,也可自定义流量输入。</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><img class="rich_pages wxw-img" data-ratio="0.7546296296296297" src="/upload/637665b0cfd64751b59f33bbc2bf7359.png" data-type="png" data-w="1080" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <h2 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 24px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">三、实践落地</h2> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">流量回放虽然具备自我录制和回放的完整能力,但因微服务的大流行,后端架构变的越来越复杂,市面上很多公司都没有有效的应用起来,原因主要有2个:</p> <ul style="padding-left: 30px;list-style-position: initial;list-style-image: initial;color: rgb(80, 97, 109);font-size: 15px;letter-spacing: normal;text-align: start;text-wrap: wrap;margin-top: 6px !important;list-style-type: square !important;" class="list-paddingleft-1"> <li style="margin-top: 6px !important;"><p><span style="color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;">使用此平台对测试人员要求极高,需要十分了解代码逻辑与链路交互;</span></p></li> <li style="margin-top: 6px !important;"><p><span style="color: rgb(74, 74, 74);line-height: 22px;font-size: 14px !important;">代码链路有一点变更,回放则会受到影响,导致失败率极高;</span></p></li> </ul> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">基于此历史经验,并结合货拉拉的目前现状特点(业务复杂、服务语言切换php转java重构、核心链路架构升级等),如何更好的应用此平台给测试人员减负和为系统增稳,主要从以简到难的应用思路去落地,逐步建立用户信心,最终达到用户依赖并信任平台的效果。</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">截止目前的应用数据:</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;"><img class="rich_pages wxw-img" data-ratio="0.48722986247544203" src="/upload/5c221b9f7c79830e449015b5ddeb29ff.png" data-type="png" data-w="1018" style="border-width: 2px;border-style: solid;border-color: rgb(238, 238, 238);border-radius: 6px;"></p> <h3 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 20px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">3.1 非Mock回放</h3> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">非mock回放的好处在于它不会受代码链路变更影响,但此种方式需确保录制与回放处于同一环境内、共用底层存储并不能变更数据,也就是指在同一环境内对读接口进行录制与回放。此种应用类型的失败只有一种,即返回值差异,降噪处理起来十分清晰与简易。目前平台共支持2种模式,java录制java回放、php录制java回放,可进行手动/自动回放。</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">累计回放次数5k次,流量数60w+,拦截问题<strong style="color: rgb(0, 0, 0);">200+</strong> <strong style="color: rgb(0, 0, 0);">。</strong></p> <h3 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 20px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">3.2 Mock回放</h3> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">mock回放的弊端是受代码链路变更影响和验证不到底层中间件部分,所以它比较适合技术架构比较稳定的业务线。基于此分析我们在具有此类业务线特性的团队进行推广应用,串入到项目流程的准入(提测)和准出(回归)环节使用。</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">累计回放次数1k次,流量数10w+,拦截问题<strong style="color: rgb(0, 0, 0);">10+</strong> <strong style="color: rgb(0, 0, 0);">。</strong></p> <h3 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 20px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">3.3 链路回放</h3> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">链路回放的接入成本较高,主要耗费在业务场景代码插桩上,但它很好的补充了单服务录制回放的短板,适合于大型链路升级与重构。</p> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">此能力目前应用于货拉拉的一个大型核心履约链路架构升级项目,拦截问题<strong style="color: rgb(0, 0, 0);">180+</strong> ,协助项目做到万无一失。</p> <h2 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 24px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">四、未来规划</h2> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">经过长期的迭代优化,我们已经在3种不同的应用(非mock回放、mock回放、链路回放)取得了阶段性的正向收益,这使我们能更好地应对业务快速迭代和系统架构升级的挑战。对于下一个阶段目标,主要从高效、流程管控、智能、拓展四个方面展开。</p> <h3 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 20px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">4.1 结合精准智能筛选流量回归</h3> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">公司已有的精准平台具有能提供每次提测分支受影响的方法以及该方法影响到的所有接口的能力。此能力可帮助LLRepeater进行精准回放无需人工介入,这样无论是对资源还是人力成本上都具有提效的效果。</p> <h3 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 20px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">4.2 CI/CD集成</h3> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">需要完善流程管控,未来将会与公司的准入准出流水线进行结合,避免受人的影响,导致执行不一的情况发生。</p> <h3 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 20px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">4.3 智能分析</h3> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">基于回放对比知识库的数据沉淀,利用智能化技术帮助使用人员分析解决问题,降低使用门槛,吸引更多的用户。</p> <h3 style="margin-top: 2rem;margin-bottom: 0.5rem;font-weight: 700;color: rgb(248, 95, 72);line-height: 1.35;font-size: 20px;letter-spacing: normal;text-align: start;text-wrap: wrap;font-family: Menlo, Monaco, "Source Code Pro", Consolas, Inconsolata, "Ubuntu Mono", "DejaVu Sans Mono", "Courier New", "Droid Sans Mono", "Hiragino Sans GB", 微软雅黑, monospace !important;">4.4 支持多语言的流量录制和回放,覆盖更多更广的业务领域</h3> <p style="margin-top: 15px;margin-bottom: 15px;font-size: 15px;white-space: pre-line;line-height: 30px;color: rgb(74, 74, 74);letter-spacing: normal;text-align: start;">Java是目前后端架构的主流语言,但是像go、php等语言也有很多,未来会在LLRepeater上兼容更多语言,做大做强。</p> <p style="display: none;"> <mp-style-type data-value="3"></mp-style-type></p>
作者:微信小助手
<h1 data-tool="mdnice编辑器" style="font-weight: bold;margin: 1em 0px;font-size: 1.4em;padding-bottom: 0.3em;border-bottom: 1px solid rgb(223, 226, 229);text-align: justify;line-height: 1.6 !important;"><span style="display: none;line-height: 1.6 !important;"></span><span style="line-height: 1.6 !important;">目录导读</span><span style="line-height: 1.6 !important;"></span></h1> <section style="padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-size: 16px;margin-top: -1em;color: rgb(51, 51, 51);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;margin-left: 0px;margin-right: 0px;"> <figure data-tool="mdnice编辑器" style="display: flex;flex-direction: column;justify-content: center;align-items: center;margin-top: 1em;margin-bottom: 1em;line-height: 1.6 !important;"> <img class="rich_pages wxw-img" data-ratio="0.46296296296296297" data-type="png" data-w="1080" style="display: block;width: auto;margin-right: auto;margin-left: auto;line-height: 1.6 !important;height: auto !important;" src="/upload/f845443e339251368fc020cad0a55fa0.png"> </figure> </section> <h1 data-tool="mdnice编辑器" style="font-weight: bold;margin: 1em 0px;font-size: 1.4em;padding-bottom: 0.3em;border-bottom: 1px solid rgb(223, 226, 229);text-align: justify;line-height: 1.6 !important;"><span style="display: none;line-height: 1.6 !important;"></span><span style="line-height: 1.6 !important;">HydraQL 简介</span><span style="line-height: 1.6 !important;"></span></h1> <section style="margin: 1em 0px;font-size: inherit;text-align: justify;line-height: 1.6 !important;"> HydraQL [ˈhaɪdrəQL],是基于 HBase 原生客户端 API 设计的一款 SQL 查询器,通过使用类 SQL 语法或更精简的 API,用户就可以轻松读写 HBase 表中的数据,而无需深入了解和编写复杂的方法调用。 </section> <section style="margin: 1em 0px;font-size: inherit;text-align: justify;line-height: 1.6 !important;"> 与 Phoenix 相比, <code style="padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(228, 105, 24);background-color: rgb(239, 239, 239);font-size: 0.875em;line-height: 1.6 !important;">HydraQL</code>中的 SQL 语法更轻量,无需引入额外的组件和配置即可使用,且对 HBase 无倾入性,但目前还不支持聚合查询、表关联、以及二级索引等高阶功能。 </section> <h1 data-tool="mdnice编辑器" style="font-weight: bold;margin: 1em 0px;font-size: 1.4em;padding-bottom: 0.3em;border-bottom: 1px solid rgb(223, 226, 229);text-align: justify;line-height: 1.6 !important;"><span style="display: none;line-height: 1.6 !important;"></span><span style="line-height: 1.6 !important;">HBase 简介和应用场景</span><span style="line-height: 1.6 !important;"></span></h1> <section style="margin: 1em 0px;font-size: inherit;text-align: justify;line-height: 1.6 !important;"> 在开始隆重介绍 HydraQL 之前,可以先简单认识下什么是 HBase,以及 HBase 的使用场景。 </section> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);margin-bottom: 20px;margin-top: 20px;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;border-left-width: 4px;border-left-color: rgb(221, 221, 221);padding-top: 0px;padding-right: 1em;padding-left: 1em;"> <section style="font-size: inherit;color: rgb(102, 102, 102);text-align: justify;margin-left: 0px;margin-right: 0px;line-height: 1.6 !important;"> HBase 是 Apache 的顶级项目之一,是一款开源的、分布式的、面向列的 NoSQL 数据库系统。它基于 Hadoop 的分布式文件系统(HDFS)构建,并且在 Hadoop 生态系统中充当高可靠、高性能和可伸缩性的实时数据存储和处理解决方案。 </section> </blockquote> <section style="margin: 1em 0px;font-size: inherit;text-align: justify;line-height: 1.6 !important;"> HBase 适用于需要大规模数据存储和实时访问的场景。其主要应用场景包括: </section> <ul data-tool="mdnice编辑器" style="padding-left: 25px;margin: 1em 0px;line-height: 1.6 !important;" class="list-paddingleft-1"> <li style="line-height: 1.6 !important;"> <section style="color: rgb(1, 1, 1);margin-top: 0.3em;margin-bottom: 0.3em;line-height: 1.6 !important;text-align: justify;"> 存储海量实时数据,如社交网络的消息、实时日志数据、在线游戏的玩家数据等。 </section></li> <li style="line-height: 1.6 !important;"> <section style="color: rgb(1, 1, 1);margin-top: 0.3em;margin-bottom: 0.3em;line-height: 1.6 !important;text-align: justify;"> 适用于需要高可靠性的应用,HBase 的设计使得数据可以以冗余的方式存储在分布式环境中,从而保证数据的持久性和可靠性。 </section></li> <li style="line-height: 1.6 !important;"> <section style="color: rgb(1, 1, 1);margin-top: 0.3em;margin-bottom: 0.3em;line-height: 1.6 !important;text-align: justify;"> 用于在线分析处理(OLAP)和实时查询分析(OLTP)的场景。唔,OLAP 还是不太适合 </section></li> <li style="line-height: 1.6 !important;"> <section style="color: rgb(1, 1, 1);margin-top: 0.3em;margin-bottom: 0.3em;line-height: 1.6 !important;text-align: justify;"> HBase 提供对大规模数据的低延迟随机读写操作,使得它成为处理实时分析和查询的理想选择。 </section></li> </ul> <section style="margin: 1em 0px;font-size: inherit;text-align: justify;line-height: 1.6 !important;"> HBase 具有以下架构特点: </section> <ul data-tool="mdnice编辑器" style="padding-left: 25px;margin: 1em 0px;line-height: 1.6 !important;" class="list-paddingleft-1"> <li style="line-height: 1.6 !important;"> <section style="color: rgb(1, 1, 1);margin-top: 0.3em;margin-bottom: 0.3em;line-height: 1.6 !important;text-align: justify;"> 分布式架构:HBase 以集群的方式部署,数据分布在多个节点上,从而实现数据的高可用性和负载均衡。 </section></li> <li style="line-height: 1.6 !important;"> <section style="color: rgb(1, 1, 1);margin-top: 0.3em;margin-bottom: 0.3em;line-height: 1.6 !important;text-align: justify;"> 列式存储:HBase 将数据存储在列族中,每个列族可以包含单独定义的列,并将数据按照列进行存储,从而提高查询效率。 </section></li> <li style="line-height: 1.6 !important;"> <section style="color: rgb(1, 1, 1);margin-top: 0.3em;margin-bottom: 0.3em;line-height: 1.6 !important;text-align: justify;"> 强一致性:HBase 通过强一致性保证数据的正确性,即在写入和读取操作过程中,始终保证数据的一致性。 </section></li> <li style="line-height: 1.6 !important;"> <section style="color: rgb(1, 1, 1);margin-top: 0.3em;margin-bottom: 0.3em;line-height: 1.6 !important;text-align: justify;"> 高可扩展性:HBase 支持水平扩展,即可以通过添加更多的节点来增加存储容量和处理能力。关于数据量规模,HBase 可以存储海量级别的数据。它可以通过添加更多的 RegionServer 节点来水平扩展,以存储和处理更大规模的数据。 </section></li> </ul> <section style="margin: 1em 0px;font-size: inherit;text-align: justify;line-height: 1.6 !important;"> HBase 被许多大型公司广泛应用,其中一些典型的大型公司包括: </section> <ul data-tool="mdnice编辑器" style="padding-left: 25px;margin: 1em 0px;line-height: 1.6 !important;" class="list-paddingleft-1"> <li style="line-height: 1.6 !important;"> <section style="color: rgb(1, 1, 1);margin-top: 0.3em;margin-bottom: 0.3em;line-height: 1.6 !important;"> <p style="margin-top: 1em;margin-bottom: 1em;font-size: inherit;color: rgb(51, 51, 51);line-height: 1.6 !important;text-align: justify;">Facebook:Facebook 使用 HBase 来存储和处理用户的消息、通知、实时新闻源等实时数据,提供实时的社交网络服务。</p> </section></li> <li style="line-height: 1.6 !important;"> <section style="color: rgb(1, 1, 1);margin-top: 0.3em;margin-bottom: 0.3em;line-height: 1.6 !important;"> <p style="margin-top: 1em;margin-bottom: 1em;font-size: inherit;color: rgb(51, 51, 51);line-height: 1.6 !important;text-align: justify;">Twitter:Twitter 使用 HBase 作为其实时分析和查询引擎的后端存储,用于存储和处理大规模的社交网络数据、实时推文和用户行为数据等。</p> </section></li> <li style="line-height: 1.6 !important;"> <section style="color: rgb(1, 1, 1);margin-top: 0.3em;margin-bottom: 0.3em;line-height: 1.6 !important;"> <p style="margin-top: 1em;margin-bottom: 1em;font-size: inherit;color: rgb(51, 51, 51);line-height: 1.6 !important;text-align: justify;">Airbnb:Airbnb 使用 HBase 来存储和处理其大规模的实时用户数据,包括订房信息、用户行为数据和实时推荐。</p> </section></li> <li style="line-height: 1.6 !important;"> <section style="color: rgb(1, 1, 1);margin-top: 0.3em;margin-bottom: 0.3em;line-height: 1.6 !important;"> <p style="margin-top: 1em;margin-bottom: 1em;font-size: inherit;color: rgb(51, 51, 51);line-height: 1.6 !important;text-align: justify;">Yahoo:Yahoo 使用 HBase 作为其广告平台的后端存储,用于存储和处理广告投放相关的海量数据。</p> </section></li> <li style="line-height: 1.6 !important;"> <section style="color: rgb(1, 1, 1);margin-top: 0.3em;margin-bottom: 0.3em;line-height: 1.6 !important;"> <p style="margin-top: 1em;margin-bottom: 1em;font-size: inherit;color: rgb(51, 51, 51);line-height: 1.6 !important;text-align: justify;">Spotify:Spotify 使用 HBase 来存储和处理音乐流媒体服务中的海量用户数据,包括播放历史、音乐推荐和用户互动数据等。</p> </section></li> </ul> <section style="margin: 1em 0px;font-size: inherit;text-align: justify;line-height: 1.6 !important;"> 这些大型公司选择使用 HBase 的原因主要是因为 HBase 提供了可靠性、可伸缩性和高性能的实时数据存储和查询能力,适用于处理大规模数据的场景。同时,HBase 具有强一致性和分布式架构的优势,能够应对企业级应用的高要求。 </section> <section style="margin: 1em 0px;font-size: inherit;text-align: justify;line-height: 1.6 !important;"> 以上内容摘抄自 ChatGPT。 </section> <h1 data-tool="mdnice编辑器" style="font-weight: bold;margin: 1em 0px;font-size: 1.4em;padding-bottom: 0.3em;border-bottom: 1px solid rgb(223, 226, 229);text-align: justify;line-height: 1.6 !important;"><span style="display: none;line-height: 1.6 !important;"></span><span style="line-height: 1.6 !important;">HydraQL 尝鲜示例</span><span style="line-height: 1.6 !important;"></span></h1> <section style="margin: 1em 0px;font-size: inherit;text-align: justify;line-height: 1.6 !important;"> 针对如下数据集: </section> <section style="margin-left: 0px;margin-right: 0px;"> <figure data-tool="mdnice编辑器" style="display: flex;flex-direction: column;justify-content: center;align-items: center;margin-top: 1em;margin-bottom: 1em;line-height: 1.6 !important;"> <img class="rich_pages wxw-img" data-ratio="0.8268518518518518" data-type="png" data-w="1080" style="display: block;width: auto;margin-right: auto;margin-left: auto;line-height: 1.6 !important;height: auto !important;" src="/upload/c3f2eb0a138af120fc46b5245200b1eb.png"> <figcaption style="margin-top: 5px;text-align: justify;color: rgb(136, 136, 136);font-size: 14px;line-height: 1.6 !important;"> 数据集合 </figcaption> </figure> </section> <section style="margin: 1em 0px;font-size: inherit;text-align: justify;line-height: 1.6 !important;"> 现有一查询场景: </section> <blockquote data-tool="mdnice编辑器" style="border-top: none;border-right: none;border-bottom: none;font-size: 0.9em;overflow: auto;color: rgb(106, 115, 125);margin-bottom: 20px;margin-top: 20px;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;border-left-width: 4px;border-left-color: rgb(221, 221, 221);padding-top: 0px;padding-right: 1em;padding-left: 1em;"> <section style="font-size: inherit;color: rgb(102, 102, 102);text-align: justify;margin-left: 0px;margin-right: 0px;line-height: 1.6 !important;"> 筛选 rowKey 范围在('a1000', 'g1005'],年龄>=18 岁,得有工作或者薪酬大于 1 万,有交通工具,而且交通工具不能是公交、自行车和地铁的人员信息。 </section> </blockquote> <section style="margin: 1em 0px;font-size: inherit;text-align: justify;line-height: 1.6 !important;"> 在没有 HydraQL 之前,我们需要这样做,才能过滤出来我们需要的结果 </section> <section style="margin-left: 0px;margin-right: 0px;"> <figure data-tool="mdnice编辑器" style="display: flex;flex-direction: column;justify-content: center;align-items: center;margin-top: 1em;margin-bottom: 1em;line-height: 1.6 !important;"> <img class="rich_pages wxw-img" data-ratio="1.4435185185185184" data-type="png" data-w="1080" style="display: block;width: auto;margin-right: auto;margin-left: auto;line-height: 1.6 !important;height: auto !important;" src="/upload/5c16c65706b2a1cfa5dca1f5a4b18c5.png"> <figcaption style="margin-top: 5px;text-align: justify;color: rgb(136, 136, 136);font-size: 14px;line-height: 1.6 !important;"> 原生Scan </figcaption> </figure> </section> <section style="margin: 1em 0px;font-size: inherit;text-align: justify;line-height: 1.6 !important;"> 上述代码的输出结果 </section> <section style="margin-left: 0px;margin-right: 0px;"> <figure data-tool="mdnice编辑器" style="display: flex;flex-direction: column;justify-content: center;align-items: center;margin-top: 1em;margin-bottom: 1em;line-height: 1.6 !important;"> <img class="rich_pages wxw-img" data-ratio="0.13333333333333333" data-type="png" data-w="1080" style="display: block;width: auto;margin-right: auto;margin-left: auto;line-height: 1.6 !important;height: auto !important;" src="/upload/aad0be7ebf751e5a1a1be754a375fa7b.png"> <figcaption style="margin-top: 5px;text-align: justify;color: rgb(136, 136, 136);font-size: 14px;line-height: 1.6 !i
作者:微信小助手
<section class="mp_profile_iframe_wrp" data-mpa-powered-by="yiban.io"> <mp-common-profile class="js_uneditable custom_select_card mp_profile_iframe" data-pluginname="mpprofile" data-id="Mzg4NjYyODc4OA==" data-headimg="http://mmbiz.qpic.cn/mmbiz_png/J4jTHmo8Xh6qM32ASOtVbXNoiaegrI26qLRw6r6FTI7dZw6TMT7vecvnjd1O8xSsM5MiajIuQZicxSC6KFK8TMpbg/0?wx_fmt=png" data-nickname="java突击队" data-alias="" data-signature="技术经验分享" data-from="0" data-is_biz_ban="0"></mp-common-profile> </section> <h1 cid="n0" mdtype="heading" style="break-after: avoid-page;break-inside: avoid;orphans: 4;font-size: 1.7em;margin-right: auto;margin-left: auto;font-weight: bold;line-height: 1.2;cursor: text;text-align: center;color: rgb(89, 0, 9);white-space: pre-wrap;font-family: Vollkorn, Palatino, Times;letter-spacing: normal;"><span md-inline="plain">1. 引言</span></h1> <h2 cid="n2" mdtype="heading" style="break-after: avoid-page;break-inside: avoid;orphans: 4;font-size: 1.5em;margin: 1em auto 1.4em;font-weight: bold;line-height: 1.4;cursor: text;border-bottom: 1px solid rgb(255, 127, 0);white-space: pre-wrap;color: rgb(0, 0, 0);font-family: Vollkorn, Palatino, Times;letter-spacing: normal;text-align: start;"><span md-inline="plain">1.1 上班通勤的日常</span></h2> <p cid="n3" mdtype="paragraph" style="line-height: 1.8rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;word-spacing: 0.05rem;color: rgb(0, 0, 0);font-family: Vollkorn, Palatino, Times;letter-spacing: normal;text-align: start;"><span md-inline="plain">“叮铃铃”,“叮铃铃”,早上七八点,你还在温暖的被窝里和闹钟“斗智斗勇”。</span></p> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="1.1126760563380282" data-s="300,640" src="/upload/2a5ea9ce2ab28fcbcd68dd581af8da59.jpg" data-type="jpeg" data-w="213" style=""></p> <p cid="n4" mdtype="paragraph" style="line-height: 1.8rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;word-spacing: 0.05rem;color: rgb(0, 0, 0);font-family: Vollkorn, Palatino, Times;letter-spacing: normal;text-align: start;"><span md-inline="plain">突然,你意识到已经快迟到了,于是像个闪电侠一样冲进卫生间,速洗漱,急穿衣,左手抄起手机,右手拿起面包,边穿衣边啃早餐。</span></p> <p cid="n5" mdtype="paragraph" style="line-height: 1.8rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;word-spacing: 0.05rem;color: rgb(0, 0, 0);font-family: Vollkorn, Palatino, Times;letter-spacing: normal;text-align: start;"><span md-inline="plain">这个时候,通勤的老难题又摆在了你面前:要不要吃完这口面包、刷牙和洗脸,还是先冲出门赶车?</span></p> <p cid="n6" mdtype="paragraph" style="line-height: 1.8rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;word-spacing: 0.05rem;color: rgb(0, 0, 0);font-family: Vollkorn, Palatino, Times;letter-spacing: normal;text-align: start;"><span md-inline="plain">好不容易做出了一个艰难的决定——放下面包,快步冲出门。你拿出手机,点开了熟悉的地铁乘车 App 或公交地铁乘车码小程序。</span></p> <p cid="n7" mdtype="paragraph" style="line-height: 1.8rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;word-spacing: 0.05rem;color: rgb(0, 0, 0);font-family: Vollkorn, Palatino, Times;letter-spacing: normal;text-align: start;"><span md-inline="strong"><strong style="padding: 0.1em;color: rgb(220, 53, 69);"><span md-inline="plain">然后,一张二维码在屏幕上亮了起来,这可是你每天通勤的“敲门砖”。</span></strong></span></p> <p style="text-align: center;margin-bottom: 24px;"><img class="rich_pages wxw-img js_insertlocalimg" data-ratio="0.5671140939597316" data-s="300,640" src="/upload/77d47137c743aa672286df295ba2af7f.jpg" data-type="jpeg" data-w="298" style=""></p> <p cid="n7" mdtype="paragraph" style="line-height: 1.8rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;word-spacing: 0.05rem;color: rgb(0, 0, 0);font-family: Vollkorn, Palatino, Times;letter-spacing: normal;text-align: start;"><span md-inline="strong"><strong style="padding: 0.1em;color: rgb(220, 53, 69);"><span md-inline="plain"></span></strong></span></p> <p cid="n8" mdtype="paragraph" style="line-height: 1.8rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;word-spacing: 0.05rem;color: rgb(0, 0, 0);font-family: Vollkorn, Palatino, Times;letter-spacing: normal;text-align: start;"><span md-inline="plain">你快步走到地铁站,将手机二维码扫描在闸机上,"嗖"的一声,闸机打开,你轻松通过,不再需要排队买票,不再被早高峰的拥挤闹心。</span></p> <p cid="n8" mdtype="paragraph" style="line-height: 1.8rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;word-spacing: 0.05rem;color: rgb(0, 0, 0);font-family: Vollkorn, Palatino, Times;letter-spacing: normal;text-align: start;"><span md-inline="plain">你走进地铁车厢,挤到了一个角落,拿出手机,开始计划一天的工作。</span></p> <p cid="n9" mdtype="paragraph" style="line-height: 1.8rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;word-spacing: 0.05rem;color: rgb(0, 0, 0);font-family: Vollkorn, Palatino, Times;letter-spacing: normal;text-align: start;"><br></p> <h2 cid="n10" mdtype="heading" style="break-after: avoid-page;break-inside: avoid;orphans: 4;font-size: 1.5em;margin: 1em auto 1.4em;font-weight: bold;line-height: 1.4;cursor: text;border-bottom: 1px solid rgb(255, 127, 0);white-space: pre-wrap;color: rgb(0, 0, 0);font-family: Vollkorn, Palatino, Times;letter-spacing: normal;text-align: start;"><span md-inline="plain">1.2 公交&地铁乘车系统</span></h2> <p cid="n11" mdtype="paragraph" style="line-height: 1.8rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;word-spacing: 0.05rem;color: rgb(0, 0, 0);font-family: Vollkorn, Palatino, Times;letter-spacing: normal;text-align: start;"><span md-inline="plain">正如上文所说,人们只需要一台手机,一个二维码就可以完成上班通勤的所有事项。</span></p> <p cid="n12" mdtype="paragraph" style="line-height: 1.8rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;word-spacing: 0.05rem;color: rgb(0, 0, 0);font-family: Vollkorn, Palatino, Times;letter-spacing: normal;text-align: start;"><span md-inline="plain">那这个便捷的公交或地铁乘车系统是如何设计的呢?它背后的技术和架构是怎样支撑着你我每天的通勤生活呢?</span></p> <p cid="n13" mdtype="paragraph" style="line-height: 1.8rem;orphans: 4;margin-top: 0.8em;margin-bottom: 0.8em;white-space: pre-wrap;word-spacing: 0.05rem;color: rgb(0, 0, 0);font-family: Vollkorn, Palatino, Times;letter-spacing: normal;text-align: start;"><span md-inline="plain">今天让我们一起揭开这个现代</span><span md-inline="strong"><strong style="padding: 0.1em;color: rgb(220, 53, 69);"><span md-inline="plain">都市打工人通勤小能手</span></strong></span><span md-inline="plain">的面纱,深入探讨</span><span md-inline="strong"><strong style="padding: 0.1em;
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;color: black;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;margin-bottom: 0px;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><code style="font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">本地加锁</code>的方式在分布式的场景下不适用,所以本文我们来探讨下如何引入<code style="font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">分布式锁</code>解决本地锁的问题。本篇所有代码和业务基于我的开源项目 PassJava。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">本篇主要内容如下:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.39223300970873787" src="/upload/efdd7855ea6e014a57352a5ad161eb88.png" data-type="png" data-w="1030" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> </figure> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;line-height: 1.5em;margin-top: 2.2em;margin-bottom: 35px;"><span style="display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);padding: 2px 13px;margin-right: 3px;height: 50%;">一、本地锁的问题</span></h2> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">首先我们来回顾下本地锁的问题:</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">目前题目微服务被拆分成了四个微服务。前端请求进来时,会被转发到不同的微服务。假如前端接收了 10 W 个请求,每个微服务接收 2.5 W 个请求,假如缓存失效了,每个微服务在访问数据库时加锁,通过锁(<code style="font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">synchronzied</code> 或 <code style="font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">lock</code>)来锁住自己的线程资源,从而防止<code style="font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">缓存击穿</code>。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">这是一种<code style="font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">本地加锁</code>的方式,在<code style="font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">分布式</code>情况下会带来数据不一致的问题:比如服务 A 获取数据后,更新缓存 key =100,服务 B 不受服务 A 的锁限制,并发去更新缓存 key = 99,最后的结果可能是 99 或 100,但这是一种未知的状态,<strong style="color: black;">与期望结果不一致</strong>。流程图如下所示:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.8601851851851852" src="/upload/b06aee7b8528e5afd1f904d9af9c1917.png" data-type="png" data-w="1080" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> </figure> <h2 data-tool="mdnice编辑器" style="font-weight: bold;font-size: 22px;line-height: 1.5em;margin-top: 2.2em;margin-bottom: 35px;"><span style="display: inline-block;background-image: linear-gradient(rgb(255, 255, 255) 60%, rgb(255, 177, 27) 40%);background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;color: rgb(81, 81, 81);padding: 2px 13px;margin-right: 3px;height: 50%;">二、什么是分布式锁</span></h2> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">基于上面本地锁的问题,我们需要一种支持<strong style="color: black;">分布式集群环境</strong>下的锁:查询 DB 时,只有一个线程能访问,其他线程都需要等待第一个线程释放锁资源后,才能继续执行。</p> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);"><strong style="color: black;">生活中的案例</strong>:可以把锁看成房门外的一把<code style="font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">锁</code>,所有并发线程比作<code style="font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">人</code>,他们都想进入房间,房间内只能有一个人进入。当有人进入后,将门反锁,其他人必须等待,直到进去的人出来。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.5092592592592593" src="/upload/3d7ce3c6c446e881904ed50a9720a93e.png" data-type="png" data-w="1080" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">我们来看下分布式锁的基本原理,如下图所示:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="1.1843220338983051" src="/upload/cf63b1f2de72b93bed4473eab33ede13.png" data-type="png" data-w="944" style="margin-right: auto;margin-left: auto;width: 100%;border-radius: 5px;display: block;margin-bottom: 15px;"> </figure> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">我们来分析下上图的分布式锁:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 1.前端将 10W 的高并发请求转发给四个题目微服务。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 2.每个微服务处理 2.5 W 个请求。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 3.每个处理请求的线程在执行业务之前,需要先抢占锁。可以理解为“占坑”。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 4.获取到锁的线程在执行完业务后,释放锁。可以理解为“释放坑位”。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 5.未获取到的线程需要等待锁释放。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 6.释放锁后,其他线程抢占锁。 </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;line-height: 26px;color: rgb(1, 1, 1);"> 7.重复执行步骤 4、5、6。 </section></li> </ul> <p data-tool="mdnice编辑器" style="margin-bottom: 20px;line-height: 1.8em;color: rgb(58, 58, 58);">大白话解释:所有请求的线程都去同一个地方<code style="font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;margin: 3px;">“占坑”</code>,如果有坑位,就执行业务逻辑,没有坑位,就需要其他线程释放“坑位”。这个坑位是所有线程可见的,可以把这个坑位放到 Redis 缓存或者数据库,这篇讲的就是如何用 Redis 做<code style="font-size: 14px;border-radius: 4px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(155, 110, 35);background-color: rgb(255, 245, 227);padding: 3px;m
作者:微信小助手
<section data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px;padding-right: 10px;padding-left: 10px;line-height: 1.6;letter-spacing: 0px;word-break: break-word;text-align: left;color: rgb(51, 51, 51);font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;margin-bottom: 24px;" data-mpa-powered-by="yiban.io"> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;margin-top: 16px;">我们在做消息队列的技术选型时,往往会结合业务场景进行考虑。今天来聊一聊消息队列可能会用到的 7 种消息场景。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;padding-top: 30px;padding-bottom: 30px;color: rgb(19, 92, 224);font-size: 20px;"><span style="display: none;"></span><span style="border-left: 4px solid;padding-left: 10px;">1 普通消息</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">消息队列最基础的功能就是生产者发送消息、Broker 保存消息,消费者来消费消息,以此实现系统解耦、削峰填谷的作用。</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.33947772657450076" src="/upload/9f724b7deaea6a839dc79a04b9e66d59.png" data-type="png" data-w="651" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">普通消息是消息队列必备的消息类型,也是系统使用场景最多的一种消息。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;padding-top: 30px;padding-bottom: 30px;color: rgb(19, 92, 224);font-size: 20px;"><span style="display: none;"></span><span style="border-left: 4px solid;padding-left: 10px;">2 顺序消息</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">顺序消息是指生产者发送消息的顺序和消费者消费消息的顺序是一致的。比如在一个电商场景,同一个用户提交订单、订单支付、订单出库,这三个消息消费者需要按照顺序来进行消费。如下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.16164817749603805" src="/upload/5fed68509772c292567be6f779bc4332.png" data-type="png" data-w="631" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">顺序消息的实现并不容易,原因如下:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;"> 生产者集群中,有多个生产者发送消息,网络延迟不一样,很难保证发送到 Broker 的消息落盘顺序是一致的; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;"> 如果 Broker 有多个分区或队列,生产者发送的消息会进入多个分区,也无法保证顺序消费; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;"> 如果有多个消费者来异步消费同一个分区,很难保证消费顺序跟生产者发送顺序一致。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">要保证消息有序,需要满足两个条件:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;"> 同一个生产者必须同步发送消息到同一个分区; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;"> 一个分区只能给同一个消费者消费。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">如下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.41851368970013036" src="/upload/47b7ee1bfa546cfcdcae6d625c8386d7.png" data-type="png" data-w="767" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">上面第二个条件是比较容易实现的,一个分区绑定一个消费者就可以,主要是第一个条件。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;margin-top: 16px;">在主流消息队列的实现中,Kafka 和 Pulsar 的实现方式类似,生产者给消息赋值一个 key,对 key 做 Hash 运算来指定消息发送到哪一个分区。比如上面电商的例子,对同一个用户的一笔订单,提交订单、订单支付、订单出库这三个消息赋值同一个 key,就可以把这三条消息发送到同一个分区。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;margin-top: 16px;">对于 RocketMQ,生产者在发送消息的时候,可以通过 MessageQueueSelector 指定把消息投递到那个 MessageQueue,如下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.17079530638852672" src="/upload/d66bf8ef9bfd1c7dc6b8edae928c3768.png" data-type="png" data-w="767" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">示例代码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/7N2JRaWooRA2IUibHI1SdC7oLTSHGZfskWPRJStpvb0icIn4QUFtC9JMwiatAHVpKvTYXSzY8LvColYRdH0rENCO5yUCicOic7hxt/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">public</span> <span style="color: #569CD6;line-height: 26px;">static</span> <span style="color: #569CD6;line-height: 26px;">void</span> <span style="line-height: 26px;">main</span><span style="line-height: 26px;">(String[] args)</span> <span style="color: #569CD6;line-height: 26px;">throws</span> UnsupportedEncodingException </span>{<br> <span style="color: #569CD6;line-height: 26px;">try</span> {<br> DefaultMQProducer producer = <span style="color: #569CD6;line-height: 26px;">new</span> DefaultMQProducer(<span style="color: #D69D85;line-height: 26px;">"please_rename_unique_group_name"</span>);<br> producer.start();<br><br> String[] tags = <span style="color: #569CD6;line-height: 26px;">new</span> String[] {<span style="color: #D69D85;line-height: 26px;">"TagA"</span>, <span style="color: #D69D85;line-height: 26px;">"TagB"</span>, <span style="color: #D69D85;line-height: 26px;">"TagC"</span>, <span style="color: #D69D85;line-height: 26px;">"TagD"</span>, <span style="color: #D69D85;line-height: 26px;">"TagE"</span>};<br> <span style="color: #569CD6;line-height: 26px;">for</span> (<span style="color: #569CD6;line-height: 26px;">int</span> i = <span style="color: #B8D7A3;line-height: 26px;">0</span>; i < <span style="color: #B8D7A3;line-height: 26px;">100</span>; i++) {<br> <span style="color: #569CD6;line-height: 26px;">int</span> orderId = i % <span style="color: #B8D7A3;line-height: 26px;">10</span>;<br> Message msg =<br> <span style="color: #569CD6;line-height: 26px;">new</span> Message(<span style="color: #D69D85;line-height: 26px;">"TopicTestjjj"</span>, tags[i % tags.length], <span style="color: #D69D85;line-height: 26px;">"KEY"</span> + i,<br> (<span style="color: #D69D85;line-height: 26px;">"Hello RocketMQ "</span> + i).getBytes(RemotingHelper.DEFAULT_CHARSET));<br> SendResult sendResult = producer.send(msg, <span style="color: #569CD6;line-height: 26px;">new</span> MessageQueueSelector() {<br> <span style="color: #9B9B9B;line-height: 26px;">@Override</span><br> <span style="line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">public</span> MessageQueue <span style="line-height: 26px;">select</span><span style="line-height: 26px;">(List<MessageQueue> mqs, Message msg, Object arg)</span> </span>{<br> Integer id = (Integer) arg;<br> <span style="color: #569CD6;line-height: 26px;">int</span> index = id % mqs.size();<br> <span style="color: #569CD6;line-height: 26px;">return</span> mqs.get(index);<br> }<br> }, orderId);<br><br> System.out.printf(<span style="color: #D69D85;line-height: 26px;">"%s%n"</span>, sendResult);<br> }<br><br> producer.shutdown();<br> } <span style="color: #569CD6;line-height: 26px;">catch</span> (MQClientException | RemotingException | MQBrokerException | InterruptedException e) {<br> e.printStackTrace();<br> }<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">RabbitMQ 的实现是 Exchange 根据设置好的 Route Key 将数据路由到不同的 Queue 中。示例代码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/7N2JRaWooRA2IUibHI1SdC7oLTSHGZfskWPRJStpvb0icIn4QUFtC9JMwiatAHVpKvTYXSzY8LvColYRdH0rENCO5yUCicOic7hxt/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #9B9B9B;line-height: 26px;">@Resource</span><br><span style="color: #569CD6;line-height: 26px;">private</span> AmqpTemplate rabbitTemplate;<br><br><span style="line-height: 26px;"><span style="color: #569CD6;line-height: 26px;">public</span> <span style="color: #569CD6;line-height: 26px;">void</span> <span style="line-height: 26px;">send1</span><span style="line-height: 26px;">(String message)</span> </span>{<br> rabbitTemplate.convertAndSend(<span style="color: #D69D85;line-height: 26px;">"testExchange"</span>, <span style="color: #D69D85;line-height: 26px;">"testRoutingKey"</span>, message);<br>}<br></code></pre> <h2 data-tool="mdnice编辑器" style="font-weight: bold;padding-top: 30px;padding-bottom: 30px;color: rgb(19, 92, 224);font-size: 20px;"><span style="display: none;"></span><span style="border-left: 4px solid;padding-left: 10px;">3 延时消息</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">或者也叫定时消息,是指消息发送后不会立即被消费,而是指定一个时间,到时间后再消费。经典的场景比如电商购物时,30 分钟未支付订单,让订单自动失效。</p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;padding-top: 30px;padding-bottom: 30px;color: rgb(19, 92, 224);"><span style="display: none;"></span>3.1 RocketMQ 实现<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">RocketMQ 定义了 18 个延时级别,每个延时级别对应一个延时时间。下面如果延迟级别是 3,则消息会延迟 10s 才会拉取。</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/7N2JRaWooRA2IUibHI1SdC7oLTSHGZfskWPRJStpvb0icIn4QUFtC9JMwiatAHVpKvTYXSzY8LvColYRdH0rENCO5yUCicOic7hxt/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;"><span style="color: #57A64A;font-style: italic;line-height: 26px;">//MessageStoreConfig类</span><br><span style="color: #569CD6;line-height: 26px;">private</span> String messageDelayLevel = <span style="color: #D69D85;line-height: 26px;">"1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h"</span>;<br></code></pre> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">RocketMQ 的延时消息如下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.31278890600924497" src="/upload/897bb0006be1bf54ca116a3bbbc85125.png" data-type="png" data-w="649" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">生产者把消费发送到 Broker 后,Broker 首先把消息保存到 SCHEDULE_TOPIC_XXXX 这个 Topic,然后调度任务会判断是否到期,如果到期,会把消息从 SCHEDULE_TOPIC_XXXX 取出投递到原始的 queue,这样消费者就可以消费到了。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;"><span style="color: rgb(0, 128, 255);"><strong><span style="color: rgb(0, 128, 255);letter-spacing: 0px;">RocketMQ 的延时消息只支持最大两个小时的延时,不过 RocketMQ5.0 基于时间轮算法实现了定时消息,解决了这个问题。</span></strong></span></p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;padding-top: 30px;padding-bottom: 30px;color: rgb(19, 92, 224);"><span style="display: none;"></span>3.2 Pulsar 实现<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">Pulsar 的实现如下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.31278890600924497" src="/upload/5286fc026079363ba868fe9b13cfa0b9.png" data-type="png" data-w="649" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">Pulsar 的延时消息首先会写入一个 Delayed Message Tracker 的数据结构中,Delayed Message Tracker 根据延时时间构建 delayed index 优先级队列。消费者拉取消息时,首先去 Delayed Message Tracker 检查是否有到期的消息。如果有则直接拉取进行消费。</p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;padding-top: 30px;padding-bottom: 30px;color: rgb(19, 92, 224);"><span style="display: none;"></span>3.3 RabbitMQ 实现<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">RabbitMQ 的实现方式有两种,一种是投递到普通队列都不消费,等消息过期后被投递到死信队列,消费者消费死信队列。如下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.17411402157164868" src="/upload/1ca2ca3f00b7e4e0463d0f8991a89ff0.png" data-type="png" data-w="649" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">第二种方式是生产者发送消息时,先发送到本地 Mnesia 数据库,消息到期后定时器再将消息投递到 broker。</p> <h3 data-tool="mdnice编辑器" style="font-weight: bold;padding-top: 30px;padding-bottom: 30px;color: rgb(19, 92, 224);"><span style="display: none;"></span>3.4 Kafka 实现<span style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">Kafka 本身并没有延时队列,不过可以通过生产者拦截器来实现消息延时发送,也可以定义延时 Topic,利用类似 RocketMQ 的方案来实现延时消息。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;padding-top: 30px;padding-bottom: 30px;color: rgb(19, 92, 224);font-size: 20px;"><span style="display: none;"></span><span style="border-left: 4px solid;padding-left: 10px;">4 事务消息</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">事务消息是指生产消息和消费消息满足事务的特性。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;margin-top: 16px;">RabbitMQ 和 Kafka 的事务消息都是只支持生产消息的事务特性,即一批消息要不全部发送成功,要不全部发送失败。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;margin-top: 16px;">RabbitMQ 通过 Channel 来开启事务消息,代码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/7N2JRaWooRA2IUibHI1SdC7oLTSHGZfskWPRJStpvb0icIn4QUFtC9JMwiatAHVpKvTYXSzY8LvColYRdH0rENCO5yUCicOic7hxt/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;">ConnectionFactory factory=<span style="color: #569CD6;line-height: 26px;">new</span> ConnectionFactory();<br>connection=factory.newConnection();<br>Channel channel=connection.createChannel();<br><span style="color: #57A64A;font-style: italic;line-height: 26px;">//开启事务</span><br>channel.txSelect();<br>channel.basicPublish(<span style="color: #D69D85;line-height: 26px;">"directTransactionExchange"</span>,<span style="color: #D69D85;line-height: 26px;">"transactionRoutingKey"</span>,<span style="color: #569CD6;line-height: 26px;">null</span>,message.getBytes(<span style="color: #D69D85;line-height: 26px;">"utf-8"</span>));<br><span style="color: #57A64A;font-style: italic;line-height: 26px;">//提交事务 或者 channel.txRollback()回滚事务</span><br>channel.txCommit();<br></code></pre> <p data-tool="mdnice编辑器" style="padding: 8px 10px;color: black;line-height: 2;font-size: 16px;letter-spacing: 0px;word-break: break-word;text-align: left;font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif;"><span style="color: rgb(0, 128, 255);"><strong><span style="color: rgb(0, 128, 255);letter-spacing: 0px;">Kafka 可以给多个生产者设置同一个事务 ID ,从而把多个 Topic 、多个 Partition 放在一个事务中,实现原子性写入。</span></strong></span></p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;margin-top: 16px;">Pulsar 的事务消息对于事务语义的定义是:允许事件流应用将消费、处理、生产消息整个过程定义为一个原子操作。可见,Pulsar 的事务消息可以覆盖消息流整个过程。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;margin-top: 16px;">RocketMQ 的事务消息是通过 half 消息来实现的。以电商购物场景来看,账户服务扣减账户金额后,发送消息给 Broker,库存服务来消费这条消息进行扣减库存。如下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="1.0736497545008183" src="/upload/d5401e51662b94fc3468d0076593b470.png" data-type="png" data-w="611" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">可见,RocketMQ 只能保证生产者发送消息和本地事务的原子性,并不能保证消费消息的原子性。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;padding-top: 30px;padding-bottom: 30px;color: rgb(19, 92, 224);font-size: 20px;"><span style="display: none;"></span><span style="border-left: 4px solid;padding-left: 10px;">5 轨迹消息</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">轨迹消息主要用于跟踪消息的生命周期,当消息丢失时可以很方便地找出原因。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;margin-top: 16px;">轨迹消息也跟普通消息一样,也需要存储和查询,也会占用消息队列的资源,所以选择轨迹消息要考虑下面几点:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;"> 消息生命周期的关键节点一定要记录; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;"> 不能影响正常消息的发送和消费性能; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;"> 不能影响 Broker 的消息存储性能; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;"> 要考虑消息查询维度和性能。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">RabbitMQ Broker 实现了轨迹消息的功能,打开 Trace 开关,就可以把轨迹消息发送到 amq.rabbitmq.trace 这个 exchange,但是要考虑轨迹消息会不会给 Broker 造成 压力进而导致消息积压。RabbitMQ 的生产者和消费者都没有实现轨迹消息,需要开发者自己来实现。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;margin-top: 16px;">RocketMQ 生产者、Broker 和消费者都实现了轨迹消息,不过默认是关闭的,需要手工开启。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;margin-top: 16px;">使用轨迹消息,需要考虑记录哪些节点、存储介质、性能、查询方式等问题。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;padding-top: 30px;padding-bottom: 30px;color: rgb(19, 92, 224);font-size: 20px;"><span style="display: none;"></span><span style="border-left: 4px solid;padding-left: 10px;">6 死信队列</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">在消息队列中,死信队列主要应对一些异常的情况,如下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.5633270321361059" src="/upload/f5080add0a8d3e29a3c6b3c64ae40748.png" data-type="png" data-w="529" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">RocketMQ 实现了消费端的死信队列,当消费者消费失败时,会进行重试,如果重试 16 次还是失败,则这条消息会被发送到死信队列。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;margin-top: 16px;">RabbitMQ 实现了生产者和 Broker 的死信队列,下面三种情况,消息会被发送到死信队列:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px;margin-bottom: 8px;padding-left: 25px;color: black;" class="list-paddingleft-1"> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;"> 生产者发送消息被拒绝,并且 requeue 参数设置为 false; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;"> Broker 消息过期了; </section></li> <li> <section style="margin-top: 5px;margin-bottom: 5px;color: rgb(1, 1, 1);line-height: 2;"> 队列达到最大长度。 </section></li> </ul> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">RabbitMQ 消息变成死信消息后,会被发送到死信交换机(Dead-Letter-Exchange)。</p> <h2 data-tool="mdnice编辑器" style="font-weight: bold;padding-top: 30px;padding-bottom: 30px;color: rgb(19, 92, 224);font-size: 20px;"><span style="display: none;"></span><span style="border-left: 4px solid;padding-left: 10px;">7 优先级消息</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">有一些业务场景下,我们需要优先处理一些消息,比如银行里面的金卡客户、银卡客户优先级高于普通客户,他们的业务需要优先处理。如下图:</p> <figure data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;display: flex;flex-direction: column;justify-content: center;align-items: center;"> <img class="rich_pages wxw-img" data-ratio="0.1828793774319066" src="/upload/1e03af290317d97a8164ff9a8c0733c1.png" data-type="png" data-w="771" style="display: block;margin-right: auto;margin-left: auto;"> </figure> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">主流消息队列中,RabbitMQ 是支持优先级队列的,代码如下:</p> <pre data-tool="mdnice编辑器" style="margin-top: 10px;margin-bottom: 10px;border-radius: 5px;box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block;background: url("https://mmbiz.qpic.cn/mmbiz_svg/7N2JRaWooRA2IUibHI1SdC7oLTSHGZfskWPRJStpvb0icIn4QUFtC9JMwiatAHVpKvTYXSzY8LvColYRdH0rENCO5yUCicOic7hxt/640?wx_fmt=svg") 10px 10px / 40px no-repeat rgb(30, 30, 30);height: 30px;width: 100%;margin-bottom: -7px;border-radius: 5px;"></span><code style="overflow-x: auto;padding: 16px;color: #DCDCDC;display: -webkit-box;font-family: Operator Mono, Consolas, Monaco, Menlo, monospace;font-size: 12px;-webkit-overflow-scrolling: touch;padding-top: 15px;background: #1E1E1E;border-radius: 5px;">ConnectionFactory factory=<span style="color: #569CD6;line-height: 26px;">new</span> ConnectionFactory();<br>connection=factory.newConnection();<br>Channel channel=connection.createChannel();<br>Map<String, Object> args = <span style="color: #569CD6;line-height: 26px;">new</span> HashMap<String, Object>();<br><span style="color: #57A64A;font-style: italic;line-height: 26px;">//设置优先级为 5</span><br>args.put(<span style="color: #D69D85;line-height: 26px;">"x-max-priority"</span>, <span style="color: #B8D7A3;line-height: 26px;">5</span>);<br>channel.queueDeclare(<span style="color: #D69D85;line-height: 26px;">"my-priority-queue"</span>, <span style="color: #569CD6;line-height: 26px;">true</span>, <span style="color: #569CD6;line-height: 26px;">false</span>, <span style="color: #569CD6;line-height: 26px;">false</span>, args);<br></code></pre> <h2 data-tool="mdnice编辑器" style="font-weight: bold;padding-top: 30px;padding-bottom: 30px;color: rgb(19, 92, 224);font-size: 20px;"><span style="display: none;"></span><span style="border-left: 4px solid;padding-left: 10px;">8 总结</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px;padding-bottom: 8px;color: black;line-height: 2;">消息队列技术选型,要考虑的因素很多,本文主要从业务场景来分析需要考虑的因素,同时技术上也需要考虑运维复杂度、业务规模、社区活跃度、学习成本等因素。希望本文对你使用消息队列有所帮助。</p> </section>
作者:微信小助手
<h3 style=" margin-bottom: 16px;box-sizing: border-box;font-weight: 700;-webkit-tap-highlight-color: rgba(0, 0, 0, 0); line-height: 1.43;font-size: 1.5em;font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif;text-align: left;white-space: normal; ">Java 调试技巧</h3> <h4 style=" margin-top: 1em;margin-bottom: 16px;box-sizing: border-box;font-weight: 700;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);font-size: 1.25em; line-height: 1.4;font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif;text-align: left;white-space: normal; ">1、IDEA 远程调试代码</h4> <p style="margin-bottom: 16px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif;text-align: left;white-space: normal;">在 idea 项目配置当中添加一个 Remote JVM debug,当然每个 idea 版本可能名称不一致,看准图标就行。<br style="box-sizing: border-box;"><img class="rich_pages wxw-img" data-ratio="0.47731397459165154" src="/upload/644887dfd81e4ded0a81ff57f2c78754.png" data-type="png" data-w="2204" style="box-sizing: border-box;display: inline-block;vertical-align: middle;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;"></p> <p style="margin-bottom: 16px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif;text-align: left;white-space: normal;">然后配置远程服务器的地址,复制 Command line argumengts for remote JVM 下面的命令行。<br style="box-sizing: border-box;"><img class="rich_pages wxw-img" data-ratio="0.452078032230704" src="/upload/fbc72f6f9db606dc99604c64d4eaa4d9.png" data-type="png" data-w="2358" style="box-sizing: border-box;display: inline-block;vertical-align: middle;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;"></p> <p style="margin-bottom: 16px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif;text-align: left;white-space: normal;">然后将项目打包,启动的时候添加上面复制的命令行。比如运行的命令是这样的:java -jar -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 test.jar</p> <p style="margin-bottom: 16px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif;text-align: left;white-space: normal;">启动了远程项目,就可以本地运行调试配置了。建议不要直接调试线上项目,复制一个项目副本去调试,不然会阻塞所有线程,实在要调试的话可以配合条件调试加线程级的阻塞来测试。</p> <p style="margin-bottom: 16px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif;text-align: left;white-space: normal;"><img class="rich_pages wxw-img" data-ratio="0.5364705882352941" src="/upload/1b30db5b9d6f95153dc85dc10a87c161.png" data-type="png" data-w="425" style="box-sizing: border-box;display: inline-block;vertical-align: middle;border-width: 0px;border-style: initial;border-color: initial;cursor: zoom-in;"></p> <h4 style=" margin-top: 1em;margin-bottom: 16px;box-sizing: border-box;font-weight: 700;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);font-size: 1.25em; line-height: 1.4;font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif;text-align: left;white-space: normal; ">2、jstack 调试</h4> <blockquote style="padding: 15px 20px;margin-top: 0px;margin-bottom: 16px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);color: rgb(102, 102, 102);border-left-width: 6px;border-left-color: rgb(220, 230, 240);font-size: 14px;background: rgb(242, 247, 251);font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif;text-align: left;white-space: normal;"> <p style="box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);">jstack 是 JVM 自带的 Java 堆栈跟踪工具,用于生成 Java 虚拟机当前时刻的线程快照。线程快照是当前 Java 虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。</p> </blockquote> <p style="margin-bottom: 16px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);font-family: "Microsoft YaHei", Helvetica, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Monaco, monospace, Tahoma, STXihei, 华文细黑, STHeiti, "Helvetica Neue", "Droid Sans", "wenquanyi micro hei", FreeSans, Arimo, Arial, SimSun, 宋体, Heiti, 黑体, sans-serif;text-align: left;white-space: normal;"><span style="box-sizing: border-box;font-weight: 700;">语法</span></p> <pre style="padding: 10px;margin-bottom: 16px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);white-space: pre-wrap;overflow-wrap: break-word;font-variant-numeric: normal;font-variant-east-asian: normal;font-stretch: normal;font-size: 14.45px;line-height: 1.6;font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace;overflow: auto;background: rgb(51, 51, 51);border-radius: 3px;border-width: 1px;border-style: solid;border-color: rgb(221, 221, 221);text-align: left;"> <ol class="list-paddingleft-1" style="padding-left: 2.5em;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);color: rgb(255, 255, 255);"> <li style="margin-top: 6px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);list-style: decimal;"><p><code style="box-sizing: border-box;color: rgb(255, 87, 34);background: 0px 0px;border-width: initial;border-style: none;border-color: initial;font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace;font-size: 14px;border-radius: 3px;display: inline;max-width: initial;overflow: initial;line-height: inherit;overflow-wrap: normal;"><span style="box-sizing: border-box;color: rgb(1, 170, 237);">Usage</span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">:</span></code></p></li> <li style="margin-top: 6px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);list-style: decimal;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"><p><code style="box-sizing: border-box;color: rgb(255, 87, 34);background: 0px 0px;border-width: initial;border-style: none;border-color: initial;font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace;font-size: 14px;border-radius: 3px;display: inline;max-width: initial;overflow: initial;line-height: inherit;overflow-wrap: normal;"><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> jstack </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">[-</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);">l</span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">]</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> </span><span style="box-sizing: border-box;color: rgb(0, 136, 0);"><pid></span></code></p></li> <li style="margin-top: 6px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);list-style: decimal;"><p><code style="box-sizing: border-box;color: rgb(255, 87, 34);background: 0px 0px;border-width: initial;border-style: none;border-color: initial;font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace;font-size: 14px;border-radius: 3px;display: inline;max-width: initial;overflow: initial;line-height: inherit;overflow-wrap: normal;"><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">连接正常运行的进程</span></code></p></li> <li style="margin-top: 6px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);list-style: decimal;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"><p><code style="box-sizing: border-box;color: rgb(255, 87, 34);background: 0px 0px;border-width: initial;border-style: none;border-color: initial;font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace;font-size: 14px;border-radius: 3px;display: inline;max-width: initial;overflow: initial;line-height: inherit;overflow-wrap: normal;"><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">(</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);">to connect to running process</span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">)</span></code></p></li> <li style="margin-top: 6px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);list-style: decimal;"><p><code style="box-sizing: border-box;color: rgb(255, 87, 34);background: 0px 0px;border-width: initial;border-style: none;border-color: initial;font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace;font-size: 14px;border-radius: 3px;display: inline;max-width: initial;overflow: initial;line-height: inherit;overflow-wrap: normal;"><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> jstack </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">-</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);">F </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">[-</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);">m</span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">]</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">[-</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);">l</span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">]</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> </span><span style="box-sizing: border-box;color: rgb(0, 136, 0);"><pid></span></code></p></li> <li style="margin-top: 6px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);list-style: decimal;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"><p><code style="box-sizing: border-box;color: rgb(255, 87, 34);background: 0px 0px;border-width: initial;border-style: none;border-color: initial;font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace;font-size: 14px;border-radius: 3px;display: inline;max-width: initial;overflow: initial;line-height: inherit;overflow-wrap: normal;"><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">连接挂起的进程</span></code></p></li> <li style="margin-top: 6px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);list-style: decimal;"><p><code style="box-sizing: border-box;color: rgb(255, 87, 34);background: 0px 0px;border-width: initial;border-style: none;border-color: initial;font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace;font-size: 14px;border-radius: 3px;display: inline;max-width: initial;overflow: initial;line-height: inherit;overflow-wrap: normal;"><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">(</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);">to connect to a hung process</span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">)</span></code></p></li> <li style="margin-top: 6px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);list-style: decimal;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"><p><code style="box-sizing: border-box;color: rgb(255, 87, 34);background: 0px 0px;border-width: initial;border-style: none;border-color: initial;font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace;font-size: 14px;border-radius: 3px;display: inline;max-width: initial;overflow: initial;line-height: inherit;overflow-wrap: normal;"><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> jstack </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">[-</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);">m</span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">]</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">[-</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);">l</span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">]</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> </span><span style="box-sizing: border-box;color: rgb(0, 136, 0);"><executable></span><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> </span><span style="box-sizing: border-box;color: rgb(0, 136, 0);"><core></span></code></p></li> <li style="margin-top: 6px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);list-style: decimal;"><p><code style="box-sizing: border-box;color: rgb(255, 87, 34);background: 0px 0px;border-width: initial;border-style: none;border-color: initial;font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace;font-size: 14px;border-radius: 3px;display: inline;max-width: initial;overflow: initial;line-height: inherit;overflow-wrap: normal;"><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">(</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);">to connect to a core file</span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">)</span></code></p></li> <li style="margin-top: 6px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);list-style: decimal;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"><p><code style="box-sizing: border-box;color: rgb(255, 87, 34);background: 0px 0px;border-width: initial;border-style: none;border-color: initial;font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace;font-size: 14px;border-radius: 3px;display: inline;max-width: initial;overflow: initial;line-height: inherit;overflow-wrap: normal;"><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> jstack </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">[-</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);">m</span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">]</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">[-</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);">l</span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">]</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">[</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);">server_id@</span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">]<</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);">remote server IP </span><span style="box-sizing: border-box;color: rgb(1, 170, 237);">or</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> hostname</span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">></span></code></p></li> <li style="margin-top: 6px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);list-style: decimal;"><p><code style="box-sizing: border-box;color: rgb(255, 87, 34);background: 0px 0px;border-width: initial;border-style: none;border-color: initial;font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace;font-size: 14px;border-radius: 3px;display: inline;max-width: initial;overflow: initial;line-height: inherit;overflow-wrap: normal;"><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">连接远程服务器</span></code></p></li> <li style="margin-top: 6px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);list-style: decimal;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;"><p><code style="box-sizing: border-box;color: rgb(255, 87, 34);background: 0px 0px;border-width: initial;border-style: none;border-color: initial;font-family: "YaHei Consolas Hybrid", Consolas, "Meiryo UI", "Malgun Gothic", "Segoe UI", "Trebuchet MS", Helvetica, monospace, monospace;font-size: 14px;border-radius: 3px;display: inline;max-width: initial;overflow: initial;line-height: inherit;overflow-wrap: normal;"><span style="box-sizing: border-box;color: rgb(255, 255, 255);"> </span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">(</span><span style="box-sizing: border-box;color: rgb(255, 255, 255);">to connect to a remote debug server</span><span style="box-sizing: border-box;color: rgb(255, 184, 0);">)</span></code></p></li> <li style="margin-top: 6px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);list-style: decimal;"><p><br></p></li> <li style="margin-top: 6px;box-sizing: border-box;-webkit-tap-highlight-color: rgba(0, 0, 0, 0);list-style: decimal;background-image: initial;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;backg