<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Kafka on 小盒子的技术分享</title><link>https://xiaobox.github.io/tags/kafka/</link><description>Recent content in Kafka on 小盒子的技术分享</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Sat, 22 Feb 2025 04:00:00 +0000</lastBuildDate><atom:link href="https://xiaobox.github.io/tags/kafka/index.xml" rel="self" type="application/rss+xml"/><item><title>云原生，你真的懂了吗？</title><link>https://xiaobox.github.io/p/2025-02-22-yun-yuan-sheng-ni-zhen-de-dong-le-ma/</link><pubDate>Sat, 22 Feb 2025 04:00:00 +0000</pubDate><guid>https://xiaobox.github.io/p/2025-02-22-yun-yuan-sheng-ni-zhen-de-dong-le-ma/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-02-22-yun-yuan-sheng-ni-zhen-de-dong-le-ma/cover.jpg" alt="Featured image of post 云原生，你真的懂了吗？" /&gt;&lt;h2 id="啥是云"&gt;&lt;a href="#%e5%95%a5%e6%98%af%e4%ba%91" class="header-anchor"&gt;&lt;/a&gt;啥是云？
&lt;/h2&gt;&lt;p&gt;说起云原生（cloud native），就不得不说明一下 “云” 是啥。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-02-22-yun-yuan-sheng-ni-zhen-de-dong-le-ma/001-79f74f23.png"&gt;&lt;/p&gt;
&lt;p&gt;简单理解，云就是 “云计算”，如果给它下个定义的话是这样的：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;云&amp;quot; 特指以云计算模型构建的现代化动态环境&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;为什么叫 &lt;strong&gt;云&lt;/strong&gt; 呢？它怎么不叫其他的什么呢？&lt;/p&gt;
&lt;p&gt;这个吧，就像你问马云为什么叫马云一样，那是因为给他起名的家长就是这么定的。对，云计算也是如此，计算机领域的专家就是这么定的。后来成了专业术语，大家都这么说。那你说叫 “云” 有没有道理呢？ 有道理。&lt;/p&gt;
&lt;p&gt;我们类比地看，如果你将 “资源” 看成水的话，那么在天空上自由自在、飘来飘去的云就是资源的载体，在你有需要的时候，“呼风唤雨🌧️” ，一朵带着雨水（资源）的积雨云就能为你带来一场甘霖（你需要的资源）。&lt;/p&gt;
&lt;p&gt;云在天上，不在地下，不像以前（过去的架构），你想吃水了得自己挖井，现在你可以 “呼风唤雨” 叫云给你水。而且很好管理和维护。所以你看，用 “云” 这个字还是有道理的。&lt;/p&gt;
&lt;h3 id="云-可以有多种形态"&gt;&lt;a href="#%e4%ba%91-%e5%8f%af%e4%bb%a5%e6%9c%89%e5%a4%9a%e7%a7%8d%e5%bd%a2%e6%80%81" class="header-anchor"&gt;&lt;/a&gt;“云” 可以有多种形态
&lt;/h3&gt;&lt;p&gt;云还有多种形态，一般来说有以下三种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;公有云（Public Cloud）： 由第三方云计算提供商（如 AWS、Azure、Google Cloud、阿里云、腾讯云等）拥有和运营，面向公众提供服务。&lt;/li&gt;
&lt;li&gt;私有云（Private Cloud）： 由企业或组织自己拥有和运营，仅供内部使用。私有云可以部署在企业自己的数据中心，也可以托管给第三方提供商。&lt;/li&gt;
&lt;li&gt;混合云（Hybrid Cloud）： 结合了公有云和私有云的优势，允许应用程序和数据在两者之间迁移和共享。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;还是用吃水比喻，公有云就像 “自来水”，打开水管就能喝。私有云就像自己找水源，自己挖井，自己舀水喝。混合云自然就是这两种的混合。&lt;/p&gt;
&lt;h3 id="资源有啥"&gt;&lt;a href="#%e8%b5%84%e6%ba%90%e6%9c%89%e5%95%a5" class="header-anchor"&gt;&lt;/a&gt;资源有啥？
&lt;/h3&gt;&lt;p&gt;说完了云，我们该说水了，云是提供资源的，那么具体有哪些资源呢？什么东西是云可以提供给我们的呢？你可能想到了：“嗨，不就是服务器嘛”。&lt;/p&gt;
&lt;p&gt;其实 “资源” 是一个&lt;strong&gt;多维度&lt;/strong&gt;的概念，远不止硬件设备。我们展开说说。&lt;/p&gt;
&lt;p&gt;首先是：基础资源，它包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;计算资源（CPU/GPU/FPGA）&lt;/li&gt;
&lt;li&gt;存储资源（磁盘 / SSD / 对象存储）&lt;/li&gt;
&lt;li&gt;网络资源（带宽 / IP / 负载均衡）&lt;/li&gt;
&lt;li&gt;内存资源（RAM）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然后是抽象服务，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;容器编排（Kubernetes（EKS/GKE/ACK）、Nomad）&lt;/li&gt;
&lt;li&gt;数据库服务（AWS RDS、阿里云 RDS）&lt;/li&gt;
&lt;li&gt;消息队列（Kafka 云托管、AWS SQS、RabbitMQ）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;接着是管理与安全，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;身份权限（AWS IAM、阿里云 RAM、Azure AD）&lt;/li&gt;
&lt;li&gt;监控告警（Prometheus 云托管、Datadog、阿里云 ARMS）&lt;/li&gt;
&lt;li&gt;日志分析（ELK Stack 云服务、Splunk）&lt;/li&gt;
&lt;li&gt;安全防御（阿里云 WAF）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后是高阶能力，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Serverless（AWS Lambda、阿里云 FC）&lt;/li&gt;
&lt;li&gt;服务网格（Istio、Linkerd）&lt;/li&gt;
&lt;li&gt;边缘计算（AWS Wavelength、阿里云 ENS）&lt;/li&gt;
&lt;li&gt;量子计算（AWS Braket、Azure Quantum）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我上面举的只是一些常见的例子，其实每一个分类下的资源条目是非常多的。所以你看，“资源” 可不止服务器那么简单，它是多维度的。现在几乎你能用的到的东西都上云了，都是资源。就算没有，经不住人家云厂商包装啊，只要你有需求，人家就有产品卖你，哈哈。&lt;/p&gt;
&lt;h2 id="云原生"&gt;&lt;a href="#%e4%ba%91%e5%8e%9f%e7%94%9f" class="header-anchor"&gt;&lt;/a&gt;云原生
&lt;/h2&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-02-22-yun-yuan-sheng-ni-zhen-de-dong-le-ma/002-7897a5f7.png"&gt;&lt;/p&gt;
&lt;p&gt;云其实还是比较好理解的，但是云原生（cloud native）就比较抽象了，在我刚接触这个概念的时候是一头雾水，无论别人给我讲，还是我给别人讲总是说不清楚，或者人家听不懂。&lt;/p&gt;
&lt;p&gt;我们还是先来说说定义吧，我找到 CNCF （https://github.com/cncf/toc/blob/main/DEFINITION.md）的一个定义，算比较权威了。&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中，构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式 API。&lt;/p&gt;
&lt;p&gt;这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段，云原生技术使工程师能够轻松地对系统作出频繁和可预测的重大变更。&lt;/p&gt;

 &lt;/blockquote&gt;

 &lt;blockquote&gt;
 &lt;p&gt;Cloud native practices empower organizations to develop, build, and deploy workloads in computing environments (public, private, hybrid cloud) to meet their organizational needs at scale in a programmatic and repeatable manner. It is characterized by loosely coupled systems that interoperate in a manner that is secure, resilient, manageable, sustainable, and observable.&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;说实话，如果你没有在这个领域干过，光看定义是不容易理解的。甚至就算在云原生环境下从事开发的工程师，如果不认真思考、理解，也不能把什么是“云原生” 讲的很明白。&lt;/p&gt;
&lt;p&gt;原因是这个概念本来就比较抽象。所以我不用 CNCF 的定义，换一种说法来描述一下什么是 “云原生”&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;云原生是一种以云计算基础设施为基石，通过容器化封装、微服务拆分、声明式 API 和自动化运维，将应用的非功能需求（如弹性扩缩、故障自愈、安全策略）交由云平台管理的架构范式。其本质是通过技术手段让业务代码与底层资源解耦，使开发者只需关注业务逻辑，而由云平台自动处理部署、监控、容灾等复杂性。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;你看，我这样说是不是清晰一些了？ 更好理解一些了？还没有？接着往下看。&lt;/p&gt;
&lt;h3 id="本质"&gt;&lt;a href="#%e6%9c%ac%e8%b4%a8" class="header-anchor"&gt;&lt;/a&gt;本质
&lt;/h3&gt;&lt;p&gt;透过现象看本质，概念怎么说都行，重要的是要理解这个东西的本质。&lt;/p&gt;
&lt;p&gt;那我们就来看一看 “云原生” 的本质 ：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;云原生并非单纯的技术集合，而是一种 “以应用为中心” 的思维模式。它通过标准化技术栈（容器 / K8s / 微服务），将云计算从 “资源层” 提升到 “应用层”，让企业能像使用水电一样按需使用计算能力。它的目标是让技术复杂性对业务透明化。&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;说到这里，我们就不得不说一下为什么要使用或推崇“云原生”了。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;云原生的出现源于传统应用架构在云计算时代的局限性。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;传统架构有许多痛点，做的传统开发的同学一定都知道，比如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;部署效率低：传统应用依赖物理服务器或虚拟机，部署流程复杂（如手动配置环境、依赖冲突）。&lt;/li&gt;
&lt;li&gt;扩展性差：单体架构难以应对流量突增，扩容需要数小时甚至数天。&lt;/li&gt;
&lt;li&gt;运维成本高：故障恢复、监控、日志收集等运维工作需人工干预。&lt;/li&gt;
&lt;li&gt;环境不一致：开发、测试、生产环境差异导致 “在我机器上能跑” 的问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;采用 “云原生” 技术栈及应用架构可以有效的解决上面的所有问题。&lt;/p&gt;
&lt;h3 id="什么是不可替代的"&gt;&lt;a href="#%e4%bb%80%e4%b9%88%e6%98%af%e4%b8%8d%e5%8f%af%e6%9b%bf%e4%bb%a3%e7%9a%84" class="header-anchor"&gt;&lt;/a&gt;什么是不可替代的？
&lt;/h3&gt;&lt;p&gt;不得不说，Docker 和 Kubernetes 技术的出现给了 “云原生” 极大的助力。那如果没有 Docker 和 Kubernetes 呢？ 云原生这个概念还立得住吗？&lt;/p&gt;
&lt;p&gt;其实，云原生概念的出现（2010 年 Netflix 提出）比 Docker（2013）和 Kubernetes（2014）更早。核心思想在容器技术普及前就已萌芽。所以：&lt;strong&gt;云原生本质是一种架构哲学，而非特定技术捆绑&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;那么我们紧接着下一个问题就是：什么是云原生的核心内容，有什么是缺一不可的呢？或者说缺了什么就不能算是云原生了呢？&lt;/p&gt;
&lt;p&gt;总结来说，有四大支柱：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;弹性伸缩（Elasticity）&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;必须能力：根据负载自动扩缩资源&lt;/li&gt;
&lt;li&gt;替代方案：AWS Lambda（Serverless）、Nomad（非 K8s 编排器）&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;故障自愈（Resilience）&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;必须能力：服务熔断、重试、健康检查&lt;/li&gt;
&lt;li&gt;替代方案：Hystrix（微服务容错库）+ Consul（服务发现）&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="5"&gt;
&lt;li&gt;声明式管理（Declarative）&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;必须能力：通过 YAML/JSON 描述目标状态，而非手动操作&lt;/li&gt;
&lt;li&gt;替代方案：Terraform（基础设施即代码）+ Ansible（配置管理）&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="7"&gt;
&lt;li&gt;自动化交付（Automation）&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;必须能力：CI/CD 流水线、蓝绿部署&lt;/li&gt;
&lt;li&gt;替代方案：GitLab CI + Spinnaker（持续交付平台）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="云原生的-复杂性悖论"&gt;&lt;a href="#%e4%ba%91%e5%8e%9f%e7%94%9f%e7%9a%84-%e5%a4%8d%e6%9d%82%e6%80%a7%e6%82%96%e8%ae%ba" class="header-anchor"&gt;&lt;/a&gt;云原生的 “复杂性悖论”
&lt;/h3&gt;&lt;p&gt;云原生看起来真好呀，但事实是这样吗？对于软件开发，我们都知道一句著名的话：“没有银弹”，是的。云原生也不是哪儿哪儿都好，它也有它的问题。&lt;/p&gt;
&lt;p&gt;云原生存在一个看似矛盾的现象：&lt;strong&gt;它承诺降低业务复杂性，却引入了新的技术复杂性。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这种矛盾的核心在于技术栈的 “分层复杂性转移”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;传统架构的复杂性集中在应用层（如单体重构困难、环境配置混乱）&lt;/li&gt;
&lt;li&gt;云原生的复杂性下沉到基础设施层（如 K8s 集群运维、Istio 配置）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对企业而言，这相当于用 “可控的工程复杂度” 替代 “不可控的业务阻塞风险”。但关键在于，这种转移是否真正带来净收益。&lt;/p&gt;
&lt;p&gt;说白了，你要会“算账”，在成本一定的情况下，要有所取舍，到底要不要上“云原生”，不是技术本身决定的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;云原生有它的显性与隐性成本&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;技术债务：K8s 版本升级兼容性问题、Helm Chart 维护&lt;/li&gt;
&lt;li&gt;人力成本：需要 DevOps 工程师（平均薪资比开发高 30%+）&lt;/li&gt;
&lt;li&gt;认知负担：团队需掌握容器、服务网格、声明式 API 等新范式&lt;/li&gt;
&lt;li&gt;工具链成本 ：监控（Prometheus+AlertManager）、日志（EFK）、追踪（Jaeger）的集成和维护&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;有成本当然也有收益&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;部署效率：从手动部署 1 小时 → 全自动 CI/CD 5 分钟（效率提升 12 倍）&lt;/li&gt;
&lt;li&gt;资源利用率 ：虚拟机静态分配 → 容器动态调度（CPU 利用率从 15% 提升至 60%+）&lt;/li&gt;
&lt;li&gt;故障恢复速度：人工排查 1 小时 → 自动熔断 + 滚动更新（MTTR 从 60 分钟降至 5 分钟）&lt;/li&gt;
&lt;li&gt;业务敏捷性：新功能上线周期从 1 个月 → 1 周（迭代速度提升 4 倍）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，关键是要根据你的实际情况 “算账”，一般来说，当企业规模超过临界点（通常≥50 个微服务 / 日部署次数≥10 次），云原生的收益将显著超越成本。&lt;/p&gt;
&lt;h3 id="结论"&gt;&lt;a href="#%e7%bb%93%e8%ae%ba" class="header-anchor"&gt;&lt;/a&gt;结论
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-02-22-yun-yuan-sheng-ni-zhen-de-dong-le-ma/003-05d14457.png"&gt;&lt;/p&gt;
&lt;p&gt;所以说了半天云原生到底是什么？ 我不知道你明白了没有，我们上面林林总总写了那么多技术点，如果初次接触确实很头大。但这不重要。&lt;/p&gt;
&lt;p&gt;因为：&lt;strong&gt;云原生不是工具集，而是「工业化软件生产」的方法论升级&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;用制造业的思维来理解：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;传统软件交付 ≈ 手工作坊（每个陶器需手工塑形、烧制）&lt;/li&gt;
&lt;li&gt;云原生交付 ≈ 汽车生产线（标准化零件 + 自动化流水线 + 质量检测体系）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果你面试的时候，面试官让你谈谈对云原生的理解，我希望你能够把这篇文章的精华吸收了，从一个比较高的层次来谈，&lt;strong&gt;我不希望给你一个中规中矩的回答模板，虽然它是正确的&lt;/strong&gt;，比如以下这样：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;“云原生是云计算时代的一种架构范式，旨在通过标准化技术栈（如容器、K8s）和自动化运维体系，将非业务功能（如弹性扩缩、故障自愈）从应用代码中剥离，由云平台接管。其核心驱动力是解决传统单体应用部署慢、环境不一致、扩展难的问题。&lt;/p&gt;
&lt;p&gt;从技术分层看，云原生包含：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基础设施层：Docker 实现环境一致性，K8s 完成资源调度，比如我们通过 Deployment 的滚动更新实现零停机发布；&lt;/li&gt;
&lt;li&gt;应用架构层：微服务拆分业务能力，Istio 服务网格处理服务间通信的熔断、监控，例如在订单服务中配置超时自动重试；&lt;/li&gt;
&lt;li&gt;交付运维层：GitOps 工具链（如 Argo CD）确保声明式配置的版本可控，配合 Prometheus+Grafana 实现实时监控。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关键设计原则包括不可变基础设施（容器镜像一次构建多次运行）、声明式 API（通过 YAML 描述目标状态而非手动操作）。但引入云原生也带来挑战，比如团队需要掌握复杂的 K8s 生态，我们通过建设内部开发者平台（IDP）封装底层细节，让开发者只需关注业务代码。”&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;h2 id="云原生应用"&gt;&lt;a href="#%e4%ba%91%e5%8e%9f%e7%94%9f%e5%ba%94%e7%94%a8" class="header-anchor"&gt;&lt;/a&gt;云原生应用
&lt;/h2&gt;&lt;h3 id="什么样的应用是云原生的"&gt;&lt;a href="#%e4%bb%80%e4%b9%88%e6%a0%b7%e7%9a%84%e5%ba%94%e7%94%a8%e6%98%af%e4%ba%91%e5%8e%9f%e7%94%9f%e7%9a%84" class="header-anchor"&gt;&lt;/a&gt;什么样的应用是云原生的？
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2025-02-22-yun-yuan-sheng-ni-zhen-de-dong-le-ma/004-d345c5b7.png"&gt;&lt;/p&gt;
&lt;p&gt;一个应用是否云原生，而要看是否具备以下特征：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;容器化部署：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;应用打包为 Docker 镜像，在 Kubernetes 集群中运行。&lt;/li&gt;
&lt;li&gt;示例：电商大促时，通过 HPA（水平扩缩）自动增加订单处理服务的 Pod 数量。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="3"&gt;
&lt;li&gt;微服务架构：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;业务拆分为独立服务（如用户服务、支付服务），通过 API 通信。&lt;/li&gt;
&lt;li&gt;示例：视频网站将视频转码服务独立部署，利用 GPU 节点加速，不影响主站稳定性。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="5"&gt;
&lt;li&gt;DevOps 流水线：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;代码提交后自动触发 CI/CD，完成测试、镜像构建、灰度发布。&lt;/li&gt;
&lt;li&gt;示例：金融 App 通过蓝绿部署实现零停机更新，降低发布风险。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="7"&gt;
&lt;li&gt;依赖云原生中间件：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;使用云托管的数据库（如 AWS RDS）、消息队列（如 Kafka on K8s）、缓存（如 Redis Cluster）。&lt;/li&gt;
&lt;li&gt;示例：社交平台用云原生数据库 TiDB 处理海量关系数据，自动分片扩容。&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="9"&gt;
&lt;li&gt;跨云与混合云兼容：&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;应用设计不绑定特定云厂商，可在 AWS、Azure、私有云间迁移。&lt;/li&gt;
&lt;li&gt;示例：跨国企业采用 Anthos 实现跨公有云和本地数据中心的统一管理。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="最后"&gt;&lt;a href="#%e6%9c%80%e5%90%8e" class="header-anchor"&gt;&lt;/a&gt;最后
&lt;/h2&gt;&lt;p&gt;云原生不是终点，而是通往智能软件时代的必由之路。当我们将视角从工具本身移开，看到的是一场关于效率、可靠性与创新速度的认知革命。正如 Linux 之父 Linus Torvalds 所说：“技术终将老去，但优秀的架构思想永存。” 在这场变革中，比掌握某个工具更重要的，是建立持续进化的云原生思维体系。&lt;/p&gt;</description></item><item><title>自顶向下学习 RocketMQ（二）SpringCloud 整合 RocketMQ</title><link>https://xiaobox.github.io/p/2021-12-06-zi-ding-xiang-xia-xue-xi-rocketmq-er-springcloud-zheng-he-ro/</link><pubDate>Mon, 06 Dec 2021 10:49:07 +0000</pubDate><guid>https://xiaobox.github.io/p/2021-12-06-zi-ding-xiang-xia-xue-xi-rocketmq-er-springcloud-zheng-he-ro/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2021-12-06-zi-ding-xiang-xia-xue-xi-rocketmq-er-springcloud-zheng-he-ro/cover.jpg" alt="Featured image of post 自顶向下学习 RocketMQ（二）SpringCloud 整合 RocketMQ" /&gt;&lt;h2 id="why"&gt;&lt;a href="#why" class="header-anchor"&gt;&lt;/a&gt;why
&lt;/h2&gt;&lt;p&gt;上文中我们讨论了 RocketMQ 的安装问题，有些重要的问题忘了说，即：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为什么要用消息队列&lt;/li&gt;
&lt;li&gt;消息队列有什么用？&lt;/li&gt;
&lt;li&gt;用了消息队列有什么好处？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;来讨论为什么之前，先来看一下消息模型，即 “是什么？”，我们引用 RocketMQ 的消息模型：&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;“&lt;/p&gt;
&lt;p&gt;RocketMQ 主要由 Producer、Broker、Consumer 三部分组成，其中 Producer 负责生产消息，Consumer 负责消费消息，Broker 负责存储消息。Broker 在实际部署过程中对应一台服务器，每个 Broker 可以存储多个 Topic 的消息，每个 Topic 的消息也可以分片存储于不同的 Broker。Message Queue 用于存储消息的物理地址，每个 Topic 中的消息地址存储于多个 Message Queue 中。ConsumerGroup 由多个 Consumer 实例构成。&lt;/p&gt;
&lt;p&gt;”&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;可以看到，主要是有 Producer、Broker、Consumer 这三部分。利用这样的模型，一般来说我们可以做到几点应用：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;异步&lt;/li&gt;
&lt;li&gt;解耦&lt;/li&gt;
&lt;li&gt;削峰填谷&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="异步"&gt;&lt;a href="#%e5%bc%82%e6%ad%a5" class="header-anchor"&gt;&lt;/a&gt;异步
&lt;/h3&gt;&lt;p&gt;相对同步，异步理论上执行的速度更快，效率更高，主线程执行完自己的逻辑然后发一条消息给消息队列就结束了，另外一个异步线程去订阅然后消费这条消息。&lt;/p&gt;
&lt;h3 id="解耦"&gt;&lt;a href="#%e8%a7%a3%e8%80%a6" class="header-anchor"&gt;&lt;/a&gt;解耦
&lt;/h3&gt;&lt;p&gt;其实异步和解耦关系很密切，如果你把一个业务从同步的改成异步的了，实际上它从业务上就已经解耦了，至于形式上，无论你是用多个微服务进行拆分解耦，还是多个线程进行拆分解耦，都是解耦的。举个比较常见的例子，也是异步场景的，比如电商的用户下单购买后，增加消费积分场景：订单服务主业务逻辑结束后会给消息队列发一条增加消费积分的消息，下游营销服务会去订阅这条消息消费它，异步地执行增加积分的逻辑。&lt;/p&gt;
&lt;p&gt;当然解耦后，系统间调用关系从大的业务上是同步的还是异步的，完全是由业务自己决定的。&lt;/p&gt;
&lt;h3 id="削峰填谷"&gt;&lt;a href="#%e5%89%8a%e5%b3%b0%e5%a1%ab%e8%b0%b7" class="header-anchor"&gt;&lt;/a&gt;削峰填谷
&lt;/h3&gt;&lt;p&gt;说白了，就是根据系统的处理能力来处理信息。在我们没有用消息队列之前，系统接收多少请求就都要处理完响应回去，处理的能力是根据单机或集群的处理能力而定，当然这是有上限的，虽然可以扩展，但可扩展的粒度比较粗：scale out 或 scale up，要么增加机器，要么扩展单机性能。如果我只是有某一类请求有问题处理不过来，其他的没啥事儿，这种扩展粒度就不太合适了。&lt;/p&gt;
&lt;p&gt;利用消息队列，我们完全可以实现灵活的扩展，即将更细粒度的请求，解耦抽象为消息，发送到消息队列，让下游服务根据自身的能力去进消费。这里还涉及一个“流控”的问题，即像控制水流的流速一样，我们也要根据上下游系统及消息队列的处理能力来控制消息的流量，以 RocketMQ 为例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;生产者流控，因为 broker 处理能力达到瓶颈&lt;/li&gt;
&lt;li&gt;消费者流控，因为消费能力达到瓶颈。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所谓削峰填谷，讲究的是一个平衡，这个平衡是系统和消息队列处理能力与消息流量之间的平衡。峰值的时候控一控让它下来，低谷的时候填一填让它上来，仅此而已。&lt;/p&gt;
&lt;h2 id="spring-cloud-stream"&gt;&lt;a href="#spring-cloud-stream" class="header-anchor"&gt;&lt;/a&gt;Spring Cloud Stream
&lt;/h2&gt;&lt;p&gt;聊完 why, 我们回到本文的正题，既然是 SpringCloud 的整合，那我们先聊一下 SpringCloud 吧。&lt;/p&gt;
&lt;p&gt;Spring Cloud 体系内本身是有基于消息驱动的微服务框架的，即 Spring Cloud Stream。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2021-12-06-zi-ding-xiang-xia-xue-xi-rocketmq-er-springcloud-zheng-he-ro/001-4616aa6b.jpg"&gt;&lt;/p&gt;

 &lt;blockquote&gt;
 &lt;p&gt;“&lt;/p&gt;
&lt;p&gt;Spring Cloud Stream is a framework for building highly scalable event-driven microservices connected with shared messaging systems.&lt;/p&gt;
&lt;p&gt;The framework provides a flexible programming model built on already established and familiar Spring idioms and best practices, including support for persistent pub/sub semantics, consumer groups, and stateful partitions.&lt;/p&gt;
&lt;p&gt;”&lt;/p&gt;

 &lt;/blockquote&gt;
&lt;p&gt;Spring Cloud Stream 提供了消息中间件配置的统一抽象，推出了 publish-subscribe、consumer groups、partition 这些统一的概念，有效的简化了上层研发人员对 MQ 使用的复杂度，让开发人员更多的精力投入到核心业务的处理。&lt;/p&gt;
&lt;p&gt;Spring Cloud Stream 解决什么问题？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;无感知的使用消息中间件 Stream 解决了开发人员无感知的使用消息中间件的问题，因为 Stream 对消息中间件的进一步封装，可以做到代码层面对中间件的无感知。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;中间件和服务的高度解耦 Spring Cloud Stream 进行了配置隔离，只需要调整配置，开发中可以动态的切换中间件（如 rabbitmq 切换为 kafka)，使得微服务开发的高度解耦，服务可以关注更多自己的业务流程。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="应用模型"&gt;&lt;a href="#%e5%ba%94%e7%94%a8%e6%a8%a1%e5%9e%8b" class="header-anchor"&gt;&lt;/a&gt;应用模型
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2021-12-06-zi-ding-xiang-xia-xue-xi-rocketmq-er-springcloud-zheng-he-ro/002-3cb708a0.jpg"&gt;&lt;/p&gt;
&lt;p&gt;Spring Cloud Stream 由一个中立的中间件内核组成。Spring Cloud Stream 会注入输入和输出的 channels，应用程序通过这些 channels 与外界通信，而 channels 则是通过一个明确的中间件 Binder 与外部 brokers 连接。&lt;/p&gt;
&lt;p&gt;列举下 Binder 的实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RabbitMQ&lt;/li&gt;
&lt;li&gt;Apache Kafka&lt;/li&gt;
&lt;li&gt;Amazon Kinesis&lt;/li&gt;
&lt;li&gt;Google PubSub (partner maintained)&lt;/li&gt;
&lt;li&gt;Solace PubSub+ (partner maintained)&lt;/li&gt;
&lt;li&gt;Azure Event Hubs (partner maintained)&lt;/li&gt;
&lt;li&gt;Apache RocketMQ (partner maintained)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另外还有一个概念叫 Binding,Binding 在消息中间件与应用程序提供的 Provider 和 Consumer 之间提供了一个桥梁，实现了开发者只需使用应用程序的 Provider 或 Consumer 生产或消费数据即可，屏蔽了开发者与底层消息中间件的接触。Binding 包括 Input Binding 和 Output Binding。&lt;/p&gt;
&lt;p&gt;注意这里的 input 和 output 是站在生产者和消费者的角度，而不是 broker 的角度，如果你生产消息，那么对应使用的应该是 output, 如果你消费消息，那么对应使用的应该是 input。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2021-12-06-zi-ding-xiang-xia-xue-xi-rocketmq-er-springcloud-zheng-he-ro/003-f58cf852.jpg"&gt;&lt;/p&gt;
&lt;h2 id="接入-rocketmq"&gt;&lt;a href="#%e6%8e%a5%e5%85%a5-rocketmq" class="header-anchor"&gt;&lt;/a&gt;接入 RocketMQ
&lt;/h2&gt;&lt;h3 id="依赖"&gt;&lt;a href="#%e4%be%9d%e8%b5%96" class="header-anchor"&gt;&lt;/a&gt;依赖
&lt;/h3&gt;&lt;p&gt;使用 SpringCloud SpringBoot SpringCloud Alibaba 的组合，版本信息如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;spring.boot.version&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;2.3.2.RELEASE&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;spring.boot.version&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;spring.cloud.version&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Hoxton.SR9&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;spring.cloud.version&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;spring.cloud.alibaba.version&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;2.2.6.RELEASE&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;spring.cloud.alibaba.version&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;依赖包&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-html" data-lang="html"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;groupId&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;groupId&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;artifactId&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-web&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;artifactId&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;groupId&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;com.alibaba.cloud&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;groupId&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;artifactId&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;spring-cloud-starter-stream-rocketmq&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;artifactId&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;groupId&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;org.springframework.boot&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;groupId&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;artifactId&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;spring-boot-starter-actuator&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;artifactId&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="配置"&gt;&lt;a href="#%e9%85%8d%e7%bd%ae" class="header-anchor"&gt;&lt;/a&gt;配置
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-yaml" data-lang="yaml"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nt"&gt;spring&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;mvc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;throw-exception-if-no-handler-found&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 处理 404 问题&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;add-mappings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 关闭 404 资源映射&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;application&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;mq-example&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;cloud&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;bindings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 定义 name 为 input 的 binding&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;13&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;content-type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;application/json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;14&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;test-topic&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;15&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;test-group&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;16&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 定义 name 为 output 的 binding&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;17&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;18&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;content-type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;application/json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;19&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l"&gt;test-topic&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;20&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;rocketmq&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;21&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;binder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;22&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c"&gt;# 配置 rocketmq 的 nameserver 地址&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;23&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;name-server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;127.0.0.1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;9876&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="生产消费"&gt;&lt;a href="#%e7%94%9f%e4%ba%a7%e6%b6%88%e8%b4%b9" class="header-anchor"&gt;&lt;/a&gt;生产&amp;amp;消费
&lt;/h3&gt;&lt;p&gt;生产者 controller&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@GetMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;/produce&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;produceMsg&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MessageConst&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;PROPERTY_TAGS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;test&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MessageBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello RocketMQ!&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;MessageHeaders&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;发送了消息 &amp;#34;&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;消费者订阅&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="nd"&gt;@Service&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReceiveService&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 3&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 4&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cm"&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 5&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * 订阅消息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 6&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; * @param receiveMsg
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 7&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="cm"&gt; */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 8&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nd"&gt;@StreamListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;input&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt; 9&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;receiveInput1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;receiveMsg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;10&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34; 接受到消息 input receive: &amp;#34;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;receiveMsg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;11&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;12&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="测试"&gt;&lt;a href="#%e6%b5%8b%e8%af%95" class="header-anchor"&gt;&lt;/a&gt;测试
&lt;/h3&gt;&lt;p&gt;首先启动 RocketMQ(nameserver 和 broker) ，然后启动服务，调用 controller 接口 发送消息，查看接收到的消息内容。&lt;/p&gt;
&lt;p&gt;也可以通过 dashboard 查看消息的接收状态。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2021-12-06-zi-ding-xiang-xia-xue-xi-rocketmq-er-springcloud-zheng-he-ro/004-1d0e0832.jpg"&gt;&lt;/p&gt;
&lt;h2 id="参考"&gt;&lt;a href="#%e5%8f%82%e8%80%83" class="header-anchor"&gt;&lt;/a&gt;参考
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://spring.io/projects/spring-cloud-stream" target="_blank" rel="noopener"
 &gt;https://spring.io/projects/spring-cloud-stream&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/rocketmq-example/readme-zh.md" target="_blank" rel="noopener"
 &gt;https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/rocketmq-example/readme-zh.md&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://docs.spring.io/spring-cloud-stream/docs/3.1.5/reference/html/spring-cloud-stream.html#spring-cloud-stream-reference" target="_blank" rel="noopener"
 &gt;https://docs.spring.io/spring-cloud-stream/docs/3.1.5/reference/html/spring-cloud-stream.html#spring-cloud-stream-reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.cnblogs.com/binyue/p/12222198.html" target="_blank" rel="noopener"
 &gt;https://www.cnblogs.com/binyue/p/12222198.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>滴滴一面（高级java）面试题分享</title><link>https://xiaobox.github.io/p/2020-05-11-di-di-yi-mian-gao-ji-java-mian-shi-ti-fen-xiang/</link><pubDate>Mon, 11 May 2020 07:25:08 +0000</pubDate><guid>https://xiaobox.github.io/p/2020-05-11-di-di-yi-mian-gao-ji-java-mian-shi-ti-fen-xiang/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2020-05-11-di-di-yi-mian-gao-ji-java-mian-shi-ti-fen-xiang/cover.jpg" alt="Featured image of post 滴滴一面（高级java）面试题分享" /&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2020-05-11-di-di-yi-mian-gao-ji-java-mian-shi-ti-fen-xiang/001-4d881798.jpg"&gt;&lt;/p&gt;
&lt;h3 id="1-说下对-volatile关键字的理解"&gt;&lt;a href="#1-%e8%af%b4%e4%b8%8b%e5%af%b9-volatile%e5%85%b3%e9%94%ae%e5%ad%97%e7%9a%84%e7%90%86%e8%a7%a3" class="header-anchor"&gt;&lt;/a&gt;1 说下对 volatile关键字的理解
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;volatile可以禁止指令重排序优化&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;保证可见性、不保证原子性(也就是说多个线程并发修改某个变量时，依旧会产生多线程问题，但适合使用一个线程写，多个线程读的场合。)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;以下场景可以使用volatile&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;运算结果并不依赖变量的当前值，或者能够确保只有单一的线程修改变量的值&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;变量不需要与其他的状态变量共同参与不变约束&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;原理：volatile语义中的内存屏障volatile的内存屏障策略非常严格保守，非常悲观且毫无安全感的心态：在每个volatile写操作前插入StoreStore屏障，在写操作后插入StoreLoad屏障；在每个volatile读操作前插入LoadLoad屏障，在读操作后插入LoadStore屏障；由于内存屏障的作用，避免了volatile变量和其它指令重排序、线程之间实现了通信，使得volatile表现出了锁的特性。&lt;/p&gt;
&lt;h3 id="2-jvm调过优没有是怎么做的排查问题时一般会用哪些命令"&gt;&lt;a href="#2-jvm%e8%b0%83%e8%bf%87%e4%bc%98%e6%b2%a1%e6%9c%89%e6%98%af%e6%80%8e%e4%b9%88%e5%81%9a%e7%9a%84%e6%8e%92%e6%9f%a5%e9%97%ae%e9%a2%98%e6%97%b6%e4%b8%80%e8%88%ac%e4%bc%9a%e7%94%a8%e5%93%aa%e4%ba%9b%e5%91%bd%e4%bb%a4" class="header-anchor"&gt;&lt;/a&gt;2 jvm调过优没有，是怎么做的？排查问题时一般会用哪些命令？
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; jps(JVM Process Status):虚拟机进程状况工具 显示虚拟机进程 jps -l
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; jstat(JVM Statistics Monitoring Tool):监控虚拟机各种运行状态
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; jinfo(Configuration Info for Java):java配置信息工具
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; jmap(Memory Map for Java) 堆转储快照
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;pre&gt;&lt;code&gt; jstack(Stack Trace for Java) java堆栈跟踪工具
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="3-aqs-原理大概说一下"&gt;&lt;a href="#3-aqs-%e5%8e%9f%e7%90%86%e5%a4%a7%e6%a6%82%e8%af%b4%e4%b8%80%e4%b8%8b" class="header-anchor"&gt;&lt;/a&gt;3 AQS 原理大概说一下
&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;可参考 ： [彻底搞懂AQS](http://mp.weixin.qq.com/s?__biz=MzI3Njk5ODg4OQ==&amp;amp;mid=2247484343&amp;amp;idx=1&amp;amp;sn=0c0ac16161f09cadd00483addbf6e598&amp;amp;chksm=eb6dbc31dc1a35278931f76fce310d6ead4aba125fc2370aeb52a03b2dc4a78c0d4d95fae420&amp;amp;scene=21#wechat_redirect)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="4-redis-高可用实现方式"&gt;&lt;a href="#4-redis-%e9%ab%98%e5%8f%af%e7%94%a8%e5%ae%9e%e7%8e%b0%e6%96%b9%e5%bc%8f" class="header-anchor"&gt;&lt;/a&gt;4 Redis 高可用实现方式
&lt;/h3&gt;&lt;h3 id="redis-cluster-或哨兵机制"&gt;&lt;a href="#redis-cluster-%e6%88%96%e5%93%a8%e5%85%b5%e6%9c%ba%e5%88%b6" class="header-anchor"&gt;&lt;/a&gt;redis cluster 或哨兵机制
&lt;/h3&gt;&lt;h3 id="5-kafka-或-rocketmq-实现原理"&gt;&lt;a href="#5-kafka-%e6%88%96-rocketmq-%e5%ae%9e%e7%8e%b0%e5%8e%9f%e7%90%86" class="header-anchor"&gt;&lt;/a&gt;5 Kafka 或 RocketMq 实现原理
&lt;/h3&gt;&lt;h3 id="问的太广了自己知道什么有逻辑的表达一下吧"&gt;&lt;a href="#%e9%97%ae%e7%9a%84%e5%a4%aa%e5%b9%bf%e4%ba%86%e8%87%aa%e5%b7%b1%e7%9f%a5%e9%81%93%e4%bb%80%e4%b9%88%e6%9c%89%e9%80%bb%e8%be%91%e7%9a%84%e8%a1%a8%e8%be%be%e4%b8%80%e4%b8%8b%e5%90%a7" class="header-anchor"&gt;&lt;/a&gt;问的太广了，自己知道什么有逻辑的表达一下吧
&lt;/h3&gt;&lt;h3 id="6-spring-cloud-和-dubbo区别"&gt;&lt;a href="#6-spring-cloud-%e5%92%8c-dubbo%e5%8c%ba%e5%88%ab" class="header-anchor"&gt;&lt;/a&gt;6 spring cloud 和 dubbo区别
&lt;/h3&gt;&lt;pre&gt;&lt;code&gt; 主要是RPC和生态上的区别
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="7-spring-cloud-用过哪些组件-"&gt;&lt;a href="#7-spring-cloud-%e7%94%a8%e8%bf%87%e5%93%aa%e4%ba%9b%e7%bb%84%e4%bb%b6-" class="header-anchor"&gt;&lt;/a&gt;7 spring cloud 用过哪些组件 ？
&lt;/h3&gt;&lt;h3 id="可参考-spring及spring-cloud框架主要组件介绍"&gt;&lt;a href="#%e5%8f%af%e5%8f%82%e8%80%83-spring%e5%8f%8aspring-cloud%e6%a1%86%e6%9e%b6%e4%b8%bb%e8%a6%81%e7%bb%84%e4%bb%b6%e4%bb%8b%e7%bb%8d" class="header-anchor"&gt;&lt;/a&gt;可参考 ：&lt;a class="link" href="http://mp.weixin.qq.com/s?__biz=MzI3Njk5ODg4OQ==&amp;amp;mid=2247484358&amp;amp;idx=1&amp;amp;sn=f58ad629f83c3222d6eb7b2e4f739879&amp;amp;chksm=eb6dbc40dc1a355673bc17b44f22841ee415c8a592ff8a4e6f725b458325373b7fe5277ffc72&amp;amp;scene=21#wechat_redirect" target="_blank" rel="noopener"
 &gt;spring及spring cloud框架主要组件介绍&lt;/a&gt;
&lt;/h3&gt;&lt;h3 id="8-hystrix-熔断器有哪些模式"&gt;&lt;a href="#8-hystrix-%e7%86%94%e6%96%ad%e5%99%a8%e6%9c%89%e5%93%aa%e4%ba%9b%e6%a8%a1%e5%bc%8f" class="header-anchor"&gt;&lt;/a&gt;8 Hystrix 熔断器有哪些模式
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Image" data-title-escaped="image.png" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" title="image.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;closed：请求正常时，不使用熔断器；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;open：统计请求的失败比例，达到阀值时，打开熔断器，请求被降级处理；延时一段时候后（默认休眠时间是5S）会进入halfopen状态；默认失败比例阀值是50%，请求次数最少不低于20次；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;halfopen：在进入该状态后会放入部分请求；判断请求是否成功，不成功，进入open状态，重新计时，进入halfopen状态；成功，进入closed状态，&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="9-介绍下项目"&gt;&lt;a href="#9-%e4%bb%8b%e7%bb%8d%e4%b8%8b%e9%a1%b9%e7%9b%ae" class="header-anchor"&gt;&lt;/a&gt;9 介绍下项目
&lt;/h3&gt;&lt;h3 id=""&gt;&lt;a href="#" class="header-anchor"&gt;&lt;/a&gt;
&lt;/h3&gt;&lt;h3 id="10-有什么问题问我的"&gt;&lt;a href="#10-%e6%9c%89%e4%bb%80%e4%b9%88%e9%97%ae%e9%a2%98%e9%97%ae%e6%88%91%e7%9a%84" class="header-anchor"&gt;&lt;/a&gt;10 有什么问题问我的？
&lt;/h3&gt;</description></item><item><title>spring及spring cloud框架主要组件介绍</title><link>https://xiaobox.github.io/p/2020-04-23-spring-ji-spring-cloud-kuang-jia-zhu-yao-zu-jian-jie-shao/</link><pubDate>Thu, 23 Apr 2020 02:01:05 +0000</pubDate><guid>https://xiaobox.github.io/p/2020-04-23-spring-ji-spring-cloud-kuang-jia-zhu-yao-zu-jian-jie-shao/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2020-04-23-spring-ji-spring-cloud-kuang-jia-zhu-yao-zu-jian-jie-shao/cover.jpg" alt="Featured image of post spring及spring cloud框架主要组件介绍" /&gt;&lt;p&gt;&lt;strong&gt;spring 顶级项目&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring IO platform&lt;/strong&gt;:用于系统部署，是可集成的，构建现代化应用的版本平台，具体来说当你使用maven dependency引入spring jar包时它就在工作了。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Boot&lt;/strong&gt;:旨在简化创建产品级的 Spring 应用和服务，简化了配置文件，使用嵌入式web服务器，含有诸多开箱即用微服务功能，可以和spring cloud联合部署。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Framework&lt;/strong&gt;:即通常所说的spring 框架，是一个开源的Java/Java EE全功能栈应用程序框架，其它spring项目如spring boot也依赖于此框架。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Cloud&lt;/strong&gt;：微服务工具包，为开发者提供了在分布式系统的配置管理、服务发现、断路器、智能路由、微代理、控制总线等开发工具包。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring XD&lt;/strong&gt;：是一种运行时环境（服务器软件，非开发框架），组合spring技术，如spring batch、spring boot、spring data，采集大数据并处理。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Data&lt;/strong&gt;：是一个数据访问及操作的工具包，封装了很多种数据及数据库的访问相关技术，包括：jdbc、Redis、MongoDB、Neo4j等。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Batch&lt;/strong&gt;：批处理框架，或说是批量任务执行管理器，功能包括任务调度、日志记录/跟踪等。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Security&lt;/strong&gt;：是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Integration&lt;/strong&gt;：面向企业应用集成（EAI/ESB）的编程框架，支持的通信方式包括HTTP、FTP、TCP/UDP、JMS、RabbitMQ、Email等。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Social&lt;/strong&gt;：一组工具包，一组连接社交服务API，如Twitter、Facebook、LinkedIn、GitHub等，有几十个。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring AMQP&lt;/strong&gt;：消息队列操作的工具包，主要是封装了RabbitMQ的操作。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring HATEOAS&lt;/strong&gt;：是一个用于支持实现超文本驱动的 REST Web 服务的开发库。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Mobile&lt;/strong&gt;：是Spring MVC的扩展，用来简化手机上的Web应用开发。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring for Android&lt;/strong&gt;：是Spring框架的一个扩展，其主要目的在乎简化Android本地应用的开发，提供RestTemplate来访问Rest服务。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Web Flow&lt;/strong&gt;：目标是成为管理Web应用页面流程的最佳方案，将页面跳转流程单独管理，并可配置。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring LDAP&lt;/strong&gt;：是一个用于操作LDAP的Java工具包，基于Spring的JdbcTemplate模式，简化LDAP访问。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Session&lt;/strong&gt;：session管理的开发工具包，让你可以把session保存到redis等，进行集群化session管理。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Web Services&lt;/strong&gt;：是基于Spring的Web服务框架，提供SOAP服务开发，允许通过多种方式创建Web服务。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Shell&lt;/strong&gt;：提供交互式的Shell可让你使用简单的基于Spring的编程模型来开发命令，比如Spring Roo命令。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Roo&lt;/strong&gt;：是一种Spring开发的辅助工具，使用命令行操作来生成自动化项目，操作非常类似于Rails。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Scala&lt;/strong&gt;：为Scala语言编程提供的spring框架的封装（新的编程语言，Java平台的Scala于2003年底/2004年初发布）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring BlazeDS Integration&lt;/strong&gt;：一个开发RIA工具包，可以集成Adobe Flex、BlazeDS、Spring以及Java技术创建RIA。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Loaded&lt;/strong&gt;：用于实现java程序和web应用的热部署的开源工具。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring REST Shell&lt;/strong&gt;：可以调用Rest服务的命令行工具，敲命令行操作Rest服务。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;spring cloud子项目包括&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Cloud Config&lt;/strong&gt;：配置管理开发工具包，可以让你把配置放到远程服务器，目前支持本地存储、Git以及Subversion。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Cloud Bus&lt;/strong&gt;：事件、消息总线，用于在集群（例如，配置变化事件）中传播状态变化，可与Spring Cloud Config联合实现热部署。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Cloud Netflix&lt;/strong&gt;：针对多种Netflix组件提供的开发工具包，其中包括Eureka、Hystrix、Zuul、Archaius等。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Netflix Eureka&lt;/strong&gt;：云端负载均衡，一个基于 REST 的服务，用于定位服务，以实现云端的负载均衡和中间层服务器的故障转移。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Netflix Hystrix&lt;/strong&gt;：容错管理工具，旨在通过控制服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Netflix Zuul&lt;/strong&gt;：边缘服务工具，是提供动态路由，监控，弹性，安全等的边缘服务。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Netflix Archaius&lt;/strong&gt;：配置管理API，包含一系列配置管理API，提供动态类型化属性、线程安全配置操作、轮询框架、回调机制等功能。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Cloud for Cloud Foundry&lt;/strong&gt;：通过Oauth2协议绑定服务到CloudFoundry，CloudFoundry是VMware推出的开源PaaS云平台。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Cloud Sleuth&lt;/strong&gt;：日志收集工具包，封装了Dapper,Zipkin和HTrace操作。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;**Spring Cloud Data Flow：**大数据操作工具，通过命令行方式操作数据流。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Cloud Security&lt;/strong&gt;：安全工具包，为你的应用程序添加安全控制，主要是指OAuth2。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Cloud Consul&lt;/strong&gt;：封装了Consul操作，consul是一个服务发现与配置工具，与Docker容器可以无缝集成。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Cloud Zookeeper&lt;/strong&gt;：操作Zookeeper的工具包，用于使用zookeeper方式的服务注册和发现。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Cloud Stream&lt;/strong&gt;：数据流操作开发包，封装了与Redis,Rabbit、Kafka等发送接收消息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Spring Cloud CLI&lt;/strong&gt;：基于 Spring Boot CLI，可以让你以命令行方式快速建立云组件。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2020-04-23-spring-ji-spring-cloud-kuang-jia-zhu-yao-zu-jian-jie-shao/001-bf98d7fd.jpg"&gt;&lt;/p&gt;
&lt;p&gt;关注公众号 获取更多精彩内容&lt;/p&gt;</description></item><item><title>什么是零拷贝</title><link>https://xiaobox.github.io/p/2020-03-05-shen-me-shi-ling-kao-bei/</link><pubDate>Thu, 05 Mar 2020 10:58:37 +0000</pubDate><guid>https://xiaobox.github.io/p/2020-03-05-shen-me-shi-ling-kao-bei/</guid><description>&lt;img src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2020-03-05-shen-me-shi-ling-kao-bei/cover.jpg" alt="Featured image of post 什么是零拷贝" /&gt;&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2020-03-05-shen-me-shi-ling-kao-bei/001-e7aa8dc3.png"&gt;预计阅读时间6分钟&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2020-03-05-shen-me-shi-ling-kao-bei/002-375cd3dd.png"&gt;&lt;/p&gt;
&lt;p&gt;学习Netty时 看到Netty高性能的原因之一是使用零拷贝技术&lt;/p&gt;
&lt;p&gt;学习Kafka时 看到其高性能的原因之一也使用了零拷贝技术&lt;/p&gt;
&lt;p&gt;那么到底什么是零拷贝？本文简单做个描述。&lt;/p&gt;
&lt;h3 id="先解释几个概念"&gt;&lt;a href="#%e5%85%88%e8%a7%a3%e9%87%8a%e5%87%a0%e4%b8%aa%e6%a6%82%e5%bf%b5" class="header-anchor"&gt;&lt;/a&gt;先解释几个概念
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;用户态：只能受限地访问内存，不允许访问外围设备。占用 CPU 的能力被剥夺，CPU资源可以被其他程序获取。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;内核态：CPU可以访问内存中所有的数据，包括外围设备，例如硬盘、网卡，CPU也可以将自己从一个程序切换到另一个程序。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DMA (direct memory access):直接内存访问，是一种不经过CPU而直接从内存存取数据的数据交换模式。在DMA模式下，CPU只须向DMA控制器下达指令，让DMA控制器来处理数据的传送，数据传送完毕再把信息反馈给CPU，这样就很大程度上减轻了CPU资源占有率，可以大大节省系统资源&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="传统的数据拷贝方法"&gt;&lt;a href="#%e4%bc%a0%e7%bb%9f%e7%9a%84%e6%95%b0%e6%8d%ae%e6%8b%b7%e8%b4%9d%e6%96%b9%e6%b3%95" class="header-anchor"&gt;&lt;/a&gt;传统的数据拷贝方法
&lt;/h3&gt;&lt;pre&gt;&lt;code&gt; 下图为传统的数据拷贝方法：
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2020-03-05-shen-me-shi-ling-kao-bei/003-7d3200be.jpg"&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 上图分别对应传统 I/O 操作的数据读写流程，整个过程涉及 4 次 拷贝，
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;1 .数据从磁盘读取到内核的read buffer&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;2. 数据从内核缓冲区拷贝到用户缓冲区&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;3. 数据从用户缓冲区拷贝到内核的socket buffer&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;4. 数据从内核的socket buffer拷贝到网卡接口的缓冲区&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;并且在用户态和内核态中间进行了2次切换，无疑也加重了CPU负担。

在此过程中，我们没有对文件内容做任何修改，那么在内核空间和用户空间来回拷贝数据无疑就是一种浪费，而零拷贝主要就是为了解决这种低效性。
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="解决方案"&gt;&lt;a href="#%e8%a7%a3%e5%86%b3%e6%96%b9%e6%a1%88" class="header-anchor"&gt;&lt;/a&gt;解决方案
&lt;/h3&gt;&lt;pre&gt;&lt;code&gt; **一个很明显的着力点就是减少数据在内核空间和用户空间来回拷贝。**

 **Linux能够做到在数据传输的过程中，避免数据在操作系统内核态buffer和用户态buffer之间进行复制。****Linux中提供类似的系统调用函数主要有mmap()、sendfile()及splice()。下面介绍其中两种。**
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;**mmap
**&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; 我们减少拷贝次数的一种方法是调用mmap()来代替read调用：
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-makefile" data-lang="makefile"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;write(sockfd,&lt;/span&gt; &lt;span class="err"&gt;buf,&lt;/span&gt; &lt;span class="err"&gt;len);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt; 应用程序调用mmap()，磁盘上的数据会通过DMA被拷贝的内核缓冲区，接着操作系统会把这段内核缓冲区与应用程序共享，这样就不需要把内核缓冲区的内容往用户空间拷贝。应用程序再调用write(),操作系统直接将内核缓冲区的内容拷贝到socket缓冲区中，这一切都发生在内核态，最后，socket缓冲区再把数据发到网卡去。
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2020-03-05-shen-me-shi-ling-kao-bei/004-95800f3c.jpg"&gt;
使用mmap替代read很明显减少了一次拷贝，当拷贝数据量很大时，无疑提升了效率。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h5 id="sendfile"&gt;&lt;a href="#sendfile" class="header-anchor"&gt;&lt;/a&gt;sendfile
&lt;/h5&gt;&lt;h5 id="从21版内核开始linux引入了sendfile来简化操作"&gt;&lt;a href="#%e4%bb%8e21%e7%89%88%e5%86%85%e6%a0%b8%e5%bc%80%e5%a7%8blinux%e5%bc%95%e5%85%a5%e4%ba%86sendfile%e6%9d%a5%e7%ae%80%e5%8c%96%e6%93%8d%e4%bd%9c" class="header-anchor"&gt;&lt;/a&gt;从2.1版内核开始，Linux引入了sendfile来简化操作。
&lt;/h5&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;1&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#include&amp;lt;sys/sendfile.h&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="ln"&gt;2&lt;/span&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ssize_t&lt;/span&gt; &lt;span class="nf"&gt;sendfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;out_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;in_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;off_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;size_t&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;系统调用sendfile()在代表输入文件的描述符in\_fd和代表输出文件的描述符out\_fd之间传送文件内容（字节）。描述符out\_fd必须指向一个套接字，而in\_fd指向的文件必须是可以mmap的。这些局限限制了sendfile的使用，使sendfile只能将数据从文件传递到套接字上，反之则不行。
使用sendfile不仅减少了数据拷贝的次数，还减少了上下文切换，数据传送始终只发生在kernel space。
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2020-03-05-shen-me-shi-ling-kao-bei/005-5502487c.jpg"&gt;&lt;/p&gt;
&lt;h5 id=""&gt;&lt;a href="#" class="header-anchor"&gt;&lt;/a&gt;
&lt;/h5&gt;&lt;h3 id="方案对比"&gt;&lt;a href="#%e6%96%b9%e6%a1%88%e5%af%b9%e6%af%94" class="header-anchor"&gt;&lt;/a&gt;方案对比
&lt;/h3&gt;&lt;pre&gt;&lt;code&gt; 限于篇幅原因并没有把所有的零拷贝方式都介绍完整，以下是Linux中各方式的对比
&lt;/code&gt;&lt;/pre&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;拷贝方式&lt;/th&gt;
 &lt;th&gt;CPU拷贝&lt;/th&gt;
 &lt;th&gt;DMA拷贝&lt;/th&gt;
 &lt;th&gt;系统调用&lt;/th&gt;
 &lt;th&gt;上下文切换&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;传统方式（read + write）&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;read / write&lt;/td&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;内存映射（mmap + write）&lt;/td&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;mmap / write&lt;/td&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;sendfile&lt;/td&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;sendfile&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;sendfile + DMA gather copy&lt;/td&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;sendfile&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;splice&lt;/td&gt;
 &lt;td&gt;0&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;splice&lt;/td&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h5 id="kafka采用的是linux系统的函数sendfile允许操作系统将数据从page-cache直接发送到网络以此来避免数据复制"&gt;&lt;a href="#kafka%e9%87%87%e7%94%a8%e7%9a%84%e6%98%aflinux%e7%b3%bb%e7%bb%9f%e7%9a%84%e5%87%bd%e6%95%b0sendfile%e5%85%81%e8%ae%b8%e6%93%8d%e4%bd%9c%e7%b3%bb%e7%bb%9f%e5%b0%86%e6%95%b0%e6%8d%ae%e4%bb%8epage-cache%e7%9b%b4%e6%8e%a5%e5%8f%91%e9%80%81%e5%88%b0%e7%bd%91%e7%bb%9c%e4%bb%a5%e6%ad%a4%e6%9d%a5%e9%81%bf%e5%85%8d%e6%95%b0%e6%8d%ae%e5%a4%8d%e5%88%b6" class="header-anchor"&gt;&lt;/a&gt;&lt;strong&gt;Kafka&lt;/strong&gt;采用的是Linux系统的函数sendfile()，允许操作系统将数据从Page Cache直接发送到网络，以此来避免数据复制。
&lt;/h5&gt;&lt;pre&gt;&lt;code&gt; **Netty** 中的零拷贝和上面提到的操作系统层面上的零拷贝不太一样, 我们所说的 Netty 零拷贝完全是基于（Java 层面）用户态的，它的更多的是偏向于数据操作优化这样的概念，具体表现在以下几个方面：
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Netty 通过 DefaultFileRegion 类对 java.nio.channels.FileChannel 的 tranferTo() 方法进行包装，在文件传输时可以将文件缓冲区的数据直接发送到目的通道（Channel）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ByteBuf 可以通过 wrap 操作把字节数组、ByteBuf、ByteBuffer 包装成一个 ByteBuf 对象, 进而避免了拷贝操作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ByteBuf 支持 slice 操作, 因此可以将 ByteBuf 分解为多个共享同一个存储区域的 ByteBuf，避免了内存的拷贝&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Netty 提供了 CompositeByteBuf 类，它可以将多个 ByteBuf 合并为一个逻辑上的 ByteBuf，避免了各个 ByteBuf 之间的拷贝&lt;/p&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2020-03-05-shen-me-shi-ling-kao-bei/006-ce2ba975.png"&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;参考 :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://www.jianshu.com/p/fad3339e3448" target="_blank" rel="noopener"
 &gt;https://www.jianshu.com/p/fad3339e3448&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://segmentfault.com/a/1190000007560884" target="_blank" rel="noopener"
 &gt;https://segmentfault.com/a/1190000007560884&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://juejin.im/post/5d84bd1f6fb9a06b2d780df7" target="_blank" rel="noopener"
 &gt;https://juejin.im/post/5d84bd1f6fb9a06b2d780df7&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a class="link" href="https://www.infoq.cn/article/netty-high-performance/" target="_blank" rel="noopener"
 &gt;https://www.infoq.cn/article/netty-high-performance/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="Image" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://pub-f29bf2b53160470c9a85250116509a24.r2.dev/post/2020-03-05-shen-me-shi-ling-kao-bei/007-04ecede2.jpg"&gt;&lt;/p&gt;
&lt;p&gt;关注公众号 获取更多精彩内容&lt;/p&gt;</description></item></channel></rss>