<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>敖小剑的技术分享</title>
    <link>https://skyao.net/</link>
      <atom:link href="https://skyao.net/index.xml" rel="self" type="application/rss+xml" />
    <description>敖小剑的技术分享</description>
    <generator>Hugo Blox Builder (https://hugoblox.com)</generator><language>zh-Hans</language><lastBuildDate>Mon, 24 Oct 2022 00:00:00 +0000</lastBuildDate>
    <image>
      <url>https://skyao.net/media/icon_hudb624bbc033ea18e649787b654e68f81_24811_512x512_fill_lanczos_center_3.png</url>
      <title>敖小剑的技术分享</title>
      <link>https://skyao.net/</link>
    </image>
    
    <item>
      <title>编程语言及类库</title>
      <link>https://skyao.net/learning/language/</link>
      <pubDate>Wed, 08 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/learning/language/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;过去20多年中，我主要使用的编程语言有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Java&lt;/li&gt;
&lt;li&gt;Golang&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;短时间使用过的有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;VBScript/asp&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;PHP&lt;/li&gt;
&lt;li&gt;C#/.net&lt;/li&gt;
&lt;li&gt;C++/vc++&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Lua(简单写过一些内嵌脚本)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;尝试学习而没能学会的有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Erlang(已放弃)&lt;/li&gt;
&lt;li&gt;Rust (舍不得放弃，继续努力中)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;java&#34;&gt;Java&lt;/h2&gt;
&lt;h3 id=&#34;jdk学习笔记&#34;&gt;JDK学习笔记&lt;/h3&gt;
&lt;p&gt;JDK 版本信息和部分 JDK 相关的工具介绍。2023年左右，对 Dapr 的 java-sdk 进行了版本升级，因此更新了部分 JDK 相关的知识。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-jdk&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-jdk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-jdk&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-jdk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：维护&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;java-aot学习笔记&#34;&gt;Java AOT学习笔记&lt;/h3&gt;
&lt;p&gt;Java AOT / Ahead Of Time 编译技术。2022年左右，曾计划在 dapr 中配合 AOT 技术，用于解决 Java 应用启动时间过长导致不太适用于 FaaS 场景的问题。但后来发现，Java AOT 技术在实际应用中，并不如预期那么理想，因此暂时放弃了这个计划。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-java-aot&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-java-aot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-java-aot&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-java-aot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：维护&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;spring-cloud学习笔记&#34;&gt;Spring Cloud学习笔记&lt;/h3&gt;
&lt;p&gt;Spring Cloud 相关内容。2022年左右，曾计划在 dapr 中集成 Spring Cloud，当时主要是实现 dapr pub/sub 对接 spring cloud stream 的功能。后来发现，spring 社区对 service mesh / runtime 等基于 sidecar 的技术非常排斥，合作无法谈成，dapr spring cloud 项目也因此宣布失败。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-spring-cloud&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-spring-cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-spring-cloud&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-spring-cloud&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;mockito学习笔记&#34;&gt;Mockito学习笔记&lt;/h3&gt;
&lt;p&gt;Mockito 是 Java 中用于单元测试的模拟框架, 我之前写 Java 代码是重度使用 mocktio. 之前曾经想把以前积累的一些 mockito 的博客内容整理到这个笔记中,但后来因为时间原因没能完成,这个笔记暂时没啥内容,等待后续补充.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-mockito&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-mockito&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-mockito&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-mockito&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;其他归档和删除&#34;&gt;其他(归档和删除)&lt;/h3&gt;
&lt;p&gt;以下内容长期不更新，而且格式和主题都很老，内容归档不可访问，以后有机会再考虑重新整理。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;learning-java-unit-test&lt;/li&gt;
&lt;li&gt;learning-maven&lt;/li&gt;
&lt;li&gt;learning-guava&lt;/li&gt;
&lt;li&gt;learning-jenkins2&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以下内容因为太过久远，已经没有留存意义，已被删除，不可访问：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;learning-spring-boot&lt;/li&gt;
&lt;li&gt;leaning-java-performance-tuning&lt;/li&gt;
&lt;li&gt;learning-netty&lt;/li&gt;
&lt;li&gt;learning-cucumber&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;golang&#34;&gt;Golang&lt;/h2&gt;
&lt;h3 id=&#34;golang学习笔记&#34;&gt;Golang学习笔记&lt;/h3&gt;
&lt;p&gt;Golang 语言相关内容。2020年左右，开始学习并使用 Golang 语言，并记录了一些学习笔记。不过，最近一年代码写的少了，golang学习笔记也更新不频繁。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-golang&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-golang&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-golang&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-golang&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态: 维护中&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;rust&#34;&gt;Rust&lt;/h2&gt;
&lt;h3 id=&#34;rust学习笔记&#34;&gt;Rust学习笔记&lt;/h3&gt;
&lt;p&gt;Rust 语言相关内容。从2017年因为 linkerd 项目开始学习 Rust 语言，但一直没能深入掌握，主要是没机会在实际项目中大规模使用。最近几年，随着 Rust 语言的成熟，以及 Rust 语言在云原生领域的应用越来越多，因此决定继续学习 Rust 语言，后续希望可以用 Rust 语言实现一些想法。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-rust&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-rust&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-rust&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态: 维护&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;tokio学习笔记&#34;&gt;Tokio学习笔记&lt;/h3&gt;
&lt;p&gt;Tokio是用于Rust编程语言的一个异步运行时。2021年曾努力学习 tokio，但后来因为没怎么使用 rust，就荒废了。希望后面有机会能继续学习 tokio。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-tokio&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-tokio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-tokio&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-tokio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态: 休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;yarp学习笔记&#34;&gt;Yarp学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-yarp&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-yarp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-yarp&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-yarp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态: 休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;python&#34;&gt;Python&lt;/h2&gt;
&lt;h3 id=&#34;python学习笔记&#34;&gt;Python学习笔记&lt;/h3&gt;
&lt;p&gt;Python 语言相关内容。很早很早以前学过一点点python，主要用来写简单的运维脚本，后来没怎么用。最近几年，因为 AI 的原因，有越来越多的机会使用到 python 编写的各种软件/类库，因此考虑找时间再重新学习一下 python，以满足简单开发的需要。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-python&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-python&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态: 维护&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>操作系统</title>
      <link>https://skyao.net/learning/os/</link>
      <pubDate>Wed, 08 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/learning/os/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;我目前的操作系统选择如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;日常用机：我目前使用的主力机器操作系统是 windows 11 + linux mint 22 的双系统。macos 因为工作变动+驱动原因，已经不再使用。ubuntu desktop 被 linux mint 替代。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;服务器和虚拟化方面：我选择了 pve8 和 debian12 （即将升级为 pve9 + debian13）， 不再使用 exsi 和 ubuntu server。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;软路由：openwrt 是我喜欢的软路由操作系统。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;windows&#34;&gt;Windows&lt;/h2&gt;
&lt;h3 id=&#34;windows11学习笔记&#34;&gt;Windows11学习笔记&lt;/h3&gt;
&lt;p&gt;Windows 11 是目前在用的主力 windows 操作系统，我自己的主力机一般都是 windows + linux 双系统。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-windows11&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-windows11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-windows11&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-windows11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：活跃&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;windows-server学习笔记&#34;&gt;Windows Server学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-windows-server&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-windows-server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-windows-server&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-windows-server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：归档&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;linux&#34;&gt;Linux&lt;/h2&gt;
&lt;h3 id=&#34;linux-mint学习笔记&#34;&gt;Linux Mint学习笔记&lt;/h3&gt;
&lt;p&gt;Linux Mint 是我目前使用的主力 linux 桌面操作系统，替代了之前长期使用的 ubuntu desktop。主要的优点是界面相对 ubuntu 友好，日常使用流畅且稳定。而且在使用了 bigsur 主题之后界面的美观度也足够满足我的需要了。加上 linux mint 是基于 Debian Ubuntu 的发行版，因此和 debian 的兼容性很好，可以无缝切换。因此，我的主力机器一般是 linux mint + windows11 组成双系统。目前是 linux mint 22.1 Cinnamon 版本，基于 ubuntu 22.04 版本。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-linux-mint&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-linux-mint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-linux-mint&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-linux-mint&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：活跃&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;debian学习笔记&#34;&gt;Debian学习笔记&lt;/h3&gt;
&lt;p&gt;Debian 是我目前使用的主力 linxu 服务器操作系统，替代了之前长期使用的 ubuntu server。我是从 debian12 开始使用，目前准备升级到最新版本 debian13。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-debian&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-debian&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-debian&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-debian&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：活跃&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;pve学习笔记&#34;&gt;PVE学习笔记&lt;/h3&gt;
&lt;p&gt;PVE 是 Proxmox Virtual Environment 的缩写，是一款基于 Debian 的虚拟化平台。PVE 的好处是驱动支持比较全面， 尤其支持消费级硬件，因此我用 pve 替代了之前使用的 esxi 。目前使用的版本是 pve 8，准备升级 pve 9。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-pve&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-pve&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-pve&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-pve&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：活跃&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;openwrt学习笔记&#34;&gt;Openwrt学习笔记&lt;/h3&gt;
&lt;p&gt;openwrt 及其变种是我目前使用的软路由操作系统,包括基于 x86-64 系统的普通pc 和基于 arm64 的路由器刷 openwrt 固件。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-openwrt&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-openwrt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-openwrt&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-openwrt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：活跃&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;ubuntu-server学习笔记&#34;&gt;Ubuntu Server学习笔记&lt;/h3&gt;
&lt;p&gt;ubuntu server 是我使用时间非常长的 linux 服务器操作系统, 从 200x 年开始使用, 在 2023 年之后从 ubuntu server 22.04 开始切换到 debian 12,不过在某些场景下可能无法选择 debian,我也会继续使用 ubnuntu server. 这个笔记现在很少更新,但是会继续维护.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-ubuntu-server&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-ubuntu-server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-ubuntu-server&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-ubuntu-server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：维护(更新少,但内容可以访问)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;esxi学习笔记&#34;&gt;ESXi学习笔记&lt;/h3&gt;
&lt;p&gt;ESXi 是 VMware 公司的虚拟化软件，我有一段时间用 esxi 作为主力虚拟化平台，不过 esxi 硬件限制比较大，尤其我的机器主要是家用级配件，因此后来就换成了 pve。 esxi 就不再继续使用了。这个学习笔记也因此不再更新。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-esxi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-esxi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-esxi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-esxi&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠（不再更新，内容可以访问）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;macos&#34;&gt;Macos&lt;/h2&gt;
&lt;h3 id=&#34;macos学习笔记&#34;&gt;Macos学习笔记&lt;/h3&gt;
&lt;p&gt;有一段时间，公司配置的笔记本是 macbook，因此使用了 macos 。另外有段时间特别喜欢黑苹果，家里的主力机器一度是 windows + linux mint + macos （黑苹果）三系统。但现在所在的公司配置的是 windows 笔记本，黑苹果因为驱动原因（我用 nvidia 显卡）无法继续使用。因此我目前手上没有使用 macos 的设备了，这个 macos 学习笔记也因此不再更新。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-macos&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-macos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-macos&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-macos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠（不再更新，内容可以访问）&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>开发工具</title>
      <link>https://skyao.net/learning/develop/</link>
      <pubDate>Thu, 09 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/learning/develop/</guid>
      <description>&lt;h2 id=&#34;通用工具&#34;&gt;通用工具&lt;/h2&gt;
&lt;h3 id=&#34;git学习笔记&#34;&gt;Git学习笔记&lt;/h3&gt;
&lt;p&gt;Git 是目前主要使用的版本控制软件, 以前用过 CVS / SVN / IBM Rational ClearCase / Mercurial ,但基本都被 git 替代了. 这个笔记内容不多.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-git&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-git&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-git&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-git&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：维护&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;学习工具&#34;&gt;学习工具&lt;/h2&gt;
&lt;h3 id=&#34;hugo学习笔记&#34;&gt;Hugo学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-hugo&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-hugo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-hugo&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-hugo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：活跃&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;inoreader学习笔记&#34;&gt;Inoreader学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-inoreader&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-inoreader&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-inoreader&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-inoreader&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：归档&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;ide&#34;&gt;IDE&lt;/h2&gt;
&lt;h3 id=&#34;vs-code学习笔记&#34;&gt;VS Code学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-vscode&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-vscode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-vscode&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-vscode&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：维护&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;测试&#34;&gt;测试&lt;/h2&gt;
&lt;h3 id=&#34;fortio学习笔记&#34;&gt;Fortio学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-github-fortio&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-github-fortio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/fortio&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/fortio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：归档&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;cicd&#34;&gt;CI/CD&lt;/h2&gt;
&lt;h3 id=&#34;github-action学习笔记&#34;&gt;Github Action学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-github-action&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-github-action&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-github-action&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-github-action&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：归档&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;硬件&#34;&gt;硬件&lt;/h2&gt;
&lt;h3 id=&#34;电脑硬件学习笔记&#34;&gt;电脑硬件学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-computer-hardware&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-computer-hardware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-computer-hardware&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-computer-hardware&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：活跃&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>网络通讯</title>
      <link>https://skyao.net/learning/network/</link>
      <pubDate>Thu, 09 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/learning/network/</guid>
      <description>&lt;h2 id=&#34;网络协议&#34;&gt;网络协议&lt;/h2&gt;
&lt;h3 id=&#34;http2学习笔记&#34;&gt;Http2学习笔记&lt;/h3&gt;
&lt;p&gt;git 是目前主要使用的版本控制软件, 以前用过 CVS / SVN / IBM Rational ClearCase / Mercurial ,但基本都被 git 替代了. 这个笔记内容不多.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-http2&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-http2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-http2&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-http2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：归档(不再更新,内容不可见)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;dns学习笔记&#34;&gt;DNS学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-dns&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-dns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-dns&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-dns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：维护(很少更新,内容可见)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;grpc学习笔记&#34;&gt;gRPC学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-grpc&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-grpc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-grpc&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-grpc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;flatbuffers学习笔记&#34;&gt;FlatBuffers学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&amp;lt;https://skyao.net/learning-flatbuffers &amp;gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&amp;lt;https://github.com/skyao/learning-flatbuffers &amp;gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：归档&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;mtls学习笔记&#34;&gt;mTLS学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-mtls&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-mtls&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-mtls&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-mtls&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;网络服务器&#34;&gt;网络服务器&lt;/h2&gt;
&lt;h3 id=&#34;nginx学习笔记&#34;&gt;Nginx学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-nginx&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-nginx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-nginx&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-nginx&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：维护(很少更新,内容可见)&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>架构设计</title>
      <link>https://skyao.net/learning/architecture/</link>
      <pubDate>Thu, 09 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/learning/architecture/</guid>
      <description>&lt;h2 id=&#34;软件架构&#34;&gt;软件架构&lt;/h2&gt;
&lt;h3 id=&#34;serverless学习笔记&#34;&gt;Serverless学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-serverless&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-serverless&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-serverless&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-serverless&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：活跃&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;工作流&#34;&gt;工作流&lt;/h2&gt;
&lt;h3 id=&#34;工作流学习笔记&#34;&gt;工作流学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-workflow&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-workflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-workflow&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-workflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：活跃&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;temporal学习笔记&#34;&gt;Temporal学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-temporal&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-temporal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-temporal&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-temporal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;消息通讯&#34;&gt;消息通讯&lt;/h2&gt;
&lt;h3 id=&#34;kafka学习笔记&#34;&gt;Kafka学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-kafka&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-kafka&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-kafka&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-kafka&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：归档&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;actor模型&#34;&gt;Actor模型&lt;/h2&gt;
&lt;h3 id=&#34;actor编程模型学习笔记&#34;&gt;Actor编程模型学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-actor&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-actor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-actor&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-actor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：归档&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;编程模型&#34;&gt;编程模型&lt;/h2&gt;
&lt;h3 id=&#34;reactor学习笔记&#34;&gt;Reactor学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-reactor&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-reactor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-reactor&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-reactor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：归档&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>云原生</title>
      <link>https://skyao.net/learning/cloudnative/</link>
      <pubDate>Thu, 09 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/learning/cloudnative/</guid>
      <description>&lt;h2 id=&#34;容器技术&#34;&gt;容器技术&lt;/h2&gt;
&lt;h3 id=&#34;container-学习笔记&#34;&gt;container 学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-container&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-container&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：维护&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;docker-学习笔记&#34;&gt;docker 学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-docker&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-docker&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-docker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：维护&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;kubernetes-学习笔记&#34;&gt;kubernetes 学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-kubernetes&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-kubernetes&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-kubernetes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：活跃&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;微服务&#34;&gt;微服务&lt;/h2&gt;
&lt;h3 id=&#34;微服务学习笔记&#34;&gt;微服务学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-microservice&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-microservice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-microservice&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-microservice&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;consul学习笔记&#34;&gt;Consul学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-consul&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-consul&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-consul&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-consul&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;sentinel学习笔记&#34;&gt;Sentinel学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-sentinel&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-sentinel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-sentinel&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-sentinel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;servicemesh&#34;&gt;servicemesh&lt;/h2&gt;
&lt;h3 id=&#34;servicemesh学习笔记&#34;&gt;ServiceMesh学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-servicemesh&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-servicemesh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-servicemesh&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-servicemesh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;istio学习笔记&#34;&gt;Istio学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-istio&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-istio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-istio&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-istio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;envoy学习笔记&#34;&gt;Envoy学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-envoy&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-envoy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-envoy&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-envoy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;xds学习笔记&#34;&gt;xDS学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-xds&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-xds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-xds&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-xds&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;云原生&#34;&gt;云原生&lt;/h2&gt;
&lt;h3 id=&#34;cloudnative学习笔记&#34;&gt;CloudNative学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-cloudnative&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-cloudnative&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-cloudnative&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-cloudnative&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;应用运行时&#34;&gt;应用运行时&lt;/h2&gt;
&lt;h3 id=&#34;dapr学习笔记&#34;&gt;Dapr学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-dapr&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-dapr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-dapr&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-dapr&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;web-assembly&#34;&gt;Web Assembly&lt;/h2&gt;
&lt;h3 id=&#34;web-assembly学习笔记&#34;&gt;Web Assembly学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-webassembly&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-webassembly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-webassembly&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-webassembly&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>AI</title>
      <link>https://skyao.net/learning/ai/</link>
      <pubDate>Thu, 09 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/learning/ai/</guid>
      <description>&lt;h2 id=&#34;基础设施&#34;&gt;基础设施&lt;/h2&gt;
&lt;h3 id=&#34;ai基础设施学习笔记&#34;&gt;AI基础设施学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-ai-infra&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-ai-infra&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-ai-infra&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-ai-infra&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：活跃&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;agent&#34;&gt;Agent&lt;/h2&gt;
&lt;h3 id=&#34;ai-agent学习笔记&#34;&gt;AI Agent学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-ai-agent&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-ai-agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-ai-agent&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-ai-agent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：活跃&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;ai-编程&#34;&gt;AI 编程&lt;/h2&gt;
&lt;h3 id=&#34;ai辅助编程学习笔记&#34;&gt;AI辅助编程学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-ai-assisted-programming&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-ai-assisted-programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-ai-assisted-programming&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-ai-assisted-programming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：活跃&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;cursor学习笔记&#34;&gt;Cursor学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-cursor&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-cursor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-cursor&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-cursor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：活跃&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;github-copilot学习笔记&#34;&gt;Github Copilot学习笔记&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-github-copilot&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-github-copilot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-github-copilot&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-github-copilot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>存储</title>
      <link>https://skyao.net/learning/storage/</link>
      <pubDate>Thu, 09 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/learning/storage/</guid>
      <description>&lt;h2 id=&#34;数据架构&#34;&gt;数据架构&lt;/h2&gt;
&lt;h3 id=&#34;data-mesh学习笔记&#34;&gt;Data Mesh学习笔记&lt;/h3&gt;
&lt;p&gt;看到 Zhamak Dehghani 提出了 data mesh 的概念,就尝试去学习了一下,不过似乎技术社区对此的认可度并不高,我也没有太看懂. 就暂时没有继续研究.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-datamesh&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-datamesh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-datamesh&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-datamesh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>云平台</title>
      <link>https://skyao.net/learning/cloud/</link>
      <pubDate>Thu, 09 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/learning/cloud/</guid>
      <description>&lt;h2 id=&#34;亚马逊&#34;&gt;亚马逊&lt;/h2&gt;
&lt;h2 id=&#34;微软&#34;&gt;微软&lt;/h2&gt;
&lt;h3 id=&#34;微软durabletask框架学习笔记&#34;&gt;微软durabletask框架学习笔记&lt;/h3&gt;
&lt;p&gt;持久任务框架（Durable Task Framework）是一个轻量级、可嵌入的引擎，用于将持久、容错的业务逻辑（协调）编写成普通代码。Dapr 项目的 workflow 就是基于 durabletask 的理念和设计开发的. 之前我在微软开发 dapr workflow 时学习了一段时间 durabletask. 后来工作变动就没有继续,这个笔记的内容已经不再更新.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-durabletask&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-durabletask&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-durabletask&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-durabletask&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：休眠&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>分布式</title>
      <link>https://skyao.net/learning/distributed/</link>
      <pubDate>Thu, 09 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/learning/distributed/</guid>
      <description>&lt;h2 id=&#34;分布式状态&#34;&gt;分布式状态&lt;/h2&gt;
&lt;h3 id=&#34;cloudstate学习笔记&#34;&gt;CloudState学习笔记&lt;/h3&gt;
&lt;p&gt;CloudState 是一个专注于 Serverless 的分布式状态管理开源项目,之前研究 serverless 和 dpar 时调研了一下.但这几年看这个项目发展的也不是很好,2021年后停止开发.这个笔记也没有继续更新.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-cloudstate&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-cloudstate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-cloudstate&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-cloudstate&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：归档&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CloudState的核心价值在于,CloudState是一个开创性的项目，最早致力于解决无服务器架构中的状态管理难题。CloudState通过引入事件溯源（Event Sourcing）、CRDTs（无冲突复制数据类型） 等分布式系统模式，为构建有状态、高可用的无服务器服务提供了参考实现。其设计非常适合需要管理复杂状态的场景，如实时协作应用、物联网（IoT）平台和微服务架构.&lt;/p&gt;
&lt;p&gt;CloudState 的继任者有:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Eigr：作为CloudState精神上的继承者，Eigr同样是一个开源项目，它不仅吸收了CloudState的思想，还致力于提供更强大、灵活且易用的解决方案。这个项目可以后续关注.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Akka Serverless (Lightbend Fusion)：这是由原班团队打造的商业化产品，提供了成熟稳定的平台服务。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;分布式事务&#34;&gt;分布式事务&lt;/h2&gt;
&lt;h3 id=&#34;分布式事务学习笔记&#34;&gt;分布式事务学习笔记&lt;/h3&gt;
&lt;p&gt;2022年时,曾计划在 dapr 中实现分布式事务的功能, 抽取 api 并集成社区分布式事务的能力, 后来项目因故取消, 这个学习笔记也就没有再更新了. 后续希望能有机会继续研究分布式事务相关的技术.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-distributed-transaction&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-distributed-transaction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-distributed-transaction&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-distributed-transaction&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：归档&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>摄影</title>
      <link>https://skyao.net/learning/photograph/</link>
      <pubDate>Thu, 09 Oct 2025 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/learning/photograph/</guid>
      <description>&lt;h2 id=&#34;图片处理&#34;&gt;图片处理&lt;/h2&gt;
&lt;h3 id=&#34;photoshop学习笔记&#34;&gt;Photoshop学习笔记&lt;/h3&gt;
&lt;p&gt;学习使用 photoshop 处理摄影活动后拍摄的照片, 俗称 ps.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问地址：&lt;a href=&#34;https://skyao.net/learning-photoshop&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net/learning-photoshop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;仓库地址：&lt;a href=&#34;https://github.com/skyao/learning-photoshop&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/skyao/learning-photoshop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;格式：hugo格式 + docsy 主题&lt;/li&gt;
&lt;li&gt;状态：活跃&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>在 windows 上安装 detection2</title>
      <link>https://skyao.net/post/202503-install-detection2-on-windows/</link>
      <pubDate>Sat, 15 Mar 2025 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202503-install-detection2-on-windows/</guid>
      <description>&lt;p&gt;detection2 是 facebook 开源的深度学习目标检测库，但是官方不支持 windows 平台，本文介绍在 windows 上安装 detection2 的方式，尤其是容易出错的地方以及解决办法。&lt;/p&gt;
&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;在2024年的8月，我当时写了一个笔记，记录了在 windows 上安装 marker 的过程，期间需要进行 detection2 的安装。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://skyao.net/post/202408-marker-setup-on-windows/&#34;&gt;Marker学习笔记（2）: 搭建 windows 环境&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;当时顺利的安装上了 detection2，以及后面的 marker。比较奇怪的是，后来我重装系统之后，再次安装时，就发现安装不上去了。&lt;/p&gt;
&lt;h2 id=&#34;遇到的问题&#34;&gt;遇到的问题&lt;/h2&gt;
&lt;h3 id=&#34;安装过程和遇到的问题&#34;&gt;安装过程和遇到的问题&lt;/h3&gt;
&lt;p&gt;为了避免多个 python 版本之间的冲突，我采用了 pyenv 来管理 python 版本。安装过程如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 安装 visual c++ 生成工具 和 nvidia cuda 12.6 版本&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 安装 python 3.11.9&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pyenv install 3.11.9
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 设置为全局 python 版本&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pyenv global 3.11.9
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 更新 pip , setuptools 和 wheel 到最新版本&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -m pip install --upgrade pip setuptools wheel
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 安装 torch 和 torchvision&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在这里，可以验证 torch 和 cude 都安装成功：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;import torch; print(torch.__version__); print(torch.version.cuda)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2.6.0+cu126
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12.6
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是在继续安装 detection2 的时候:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip install -e detectron2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;发现一直报错 &lt;code&gt;ModuleNotFoundError: No module named &#39;torch&#39;&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Obtaining file:///D:/sky/work/code/marker/detectron2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Installing build dependencies ... &lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Checking &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; build backend supports build_editable ... &lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Getting requirements to build editable ... error
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  error: subprocess-exited-with-error
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  × Getting requirements to build editable did not run successfully.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  │ &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; code: &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  ╰─&amp;gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;23&lt;/span&gt; lines of output&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      Traceback &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;most recent call last&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        File &lt;span class=&#34;s2&#34;&gt;&amp;#34;C:\Users\sky\.pyenv\pyenv-win\versions\3.11.9\Lib\site-packages\pip\_vendor\pyproject_hooks\_in_process\_in_process.py&amp;#34;&lt;/span&gt;, line 389, in &amp;lt;module&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          main&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        File &lt;span class=&#34;s2&#34;&gt;&amp;#34;C:\Users\sky\.pyenv\pyenv-win\versions\3.11.9\Lib\site-packages\pip\_vendor\pyproject_hooks\_in_process\_in_process.py&amp;#34;&lt;/span&gt;, line 373, in main
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          json_out&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;return_val&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; hook&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;**hook_input&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;kwargs&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        File &lt;span class=&#34;s2&#34;&gt;&amp;#34;C:\Users\sky\.pyenv\pyenv-win\versions\3.11.9\Lib\site-packages\pip\_vendor\pyproject_hooks\_in_process\_in_process.py&amp;#34;&lt;/span&gt;, line 157, in get_requires_for_build_editable
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; hook&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;config_settings&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 ^^^^^^^^^^^^^^^^^^^^^
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        File &lt;span class=&#34;s2&#34;&gt;&amp;#34;D:\sky\AppData\Local\Temp\pip-build-env-9y_kz0i2\overlay\Lib\site-packages\setuptools\build_meta.py&amp;#34;&lt;/span&gt;, line 483, in get_requires_for_build_editable
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; self.get_requires_for_build_wheel&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;config_settings&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        File &lt;span class=&#34;s2&#34;&gt;&amp;#34;D:\sky\AppData\Local\Temp\pip-build-env-9y_kz0i2\overlay\Lib\site-packages\setuptools\build_meta.py&amp;#34;&lt;/span&gt;, line 334, in get_requires_for_build_wheel
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; self._get_build_requires&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;config_settings, &lt;span class=&#34;nv&#34;&gt;requirements&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=[])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        File &lt;span class=&#34;s2&#34;&gt;&amp;#34;D:\sky\AppData\Local\Temp\pip-build-env-9y_kz0i2\overlay\Lib\site-packages\setuptools\build_meta.py&amp;#34;&lt;/span&gt;, line 304, in _get_build_requires
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          self.run_setup&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        File &lt;span class=&#34;s2&#34;&gt;&amp;#34;D:\sky\AppData\Local\Temp\pip-build-env-9y_kz0i2\overlay\Lib\site-packages\setuptools\build_meta.py&amp;#34;&lt;/span&gt;, line 522, in run_setup
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          super&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt;.run_setup&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;setup_script&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;setup_script&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        File &lt;span class=&#34;s2&#34;&gt;&amp;#34;D:\sky\AppData\Local\Temp\pip-build-env-9y_kz0i2\overlay\Lib\site-packages\setuptools\build_meta.py&amp;#34;&lt;/span&gt;, line 320, in run_setup
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          exec&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;code, locals&lt;span class=&#34;o&#34;&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        File &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;lt;string&amp;gt;&amp;#34;&lt;/span&gt;, line 10, in &amp;lt;module&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      ModuleNotFoundError: No module named &lt;span class=&#34;s1&#34;&gt;&amp;#39;torch&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;end of output&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  note: This error originates from a subprocess, and is likely not a problem with pip.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;error: subprocess-exited-with-error
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;× Getting requirements to build editable did not run successfully.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;│ &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; code: &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;╰─&amp;gt; See above &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; output.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;note: This error originates from a subprocess, and is likely not a problem with pip.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但怎么检查也检查不出问题，torch 和 cude 都安装成功, python 和 pip 的路径也正确：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;import torch; print(torch.__version__); print(torch.version.cuda)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2.6.0+cu126
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12.6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ marker which pip
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/c/Users/sky/.pyenv/pyenv-win/shims/pip
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ marker which python
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/c/Users/sky/.pyenv/pyenv-win/shims/python
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ which pip3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/c/Users/sky/.pyenv/pyenv-win/shims/pip3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ which python3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/c/Users/sky/.pyenv/pyenv-win/shims/python3
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后就卡在这里，之后我换了 3.9/3.10/3.12 等各种 python 版本，cuda 12.4/12.6/12.8 等各种版本，都是同样的报错找不到 torch 模块。&lt;/p&gt;
&lt;p&gt;后来我尝试了清理环境，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在虚拟机下安装 windows 10 和 windows 11 以得到完全干净的环境&lt;/li&gt;
&lt;li&gt;重新安装 pyenv&lt;/li&gt;
&lt;li&gt;重新安装 python&lt;/li&gt;
&lt;li&gt;重新安装 vs 2022&lt;/li&gt;
&lt;li&gt;重新安装 cuda&lt;/li&gt;
&lt;li&gt;重新安装 torch&lt;/li&gt;
&lt;li&gt;重新安装 detection2，然后继续报错找不到 torch 模块&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;解决过程&#34;&gt;解决过程&lt;/h2&gt;
&lt;h3 id=&#34;python-多版本管理的问题&#34;&gt;python 多版本管理的问题&lt;/h3&gt;
&lt;p&gt;一筹莫展之间，google &lt;code&gt;ModuleNotFoundError: No module named &#39;torch&#39;&lt;/code&gt; 这个错误，发现 stackoverflow 上的这个帖子：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://stackoverflow.com/questions/54843067/no-module-named-torch&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://stackoverflow.com/questions/54843067/no-module-named-torch&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;帖子中提到了一个关键点，就是安装 torch 的 python 要和后面测试的 python 版本一致。如果安装 torch 的 python 版本和测试的 python 版本不一致，就会导致找不到 torch 模块。但明显我安装的 torch 的 python 版本和安装 detection2 的 python 版本是一致的：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ marker which pip
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/c/Users/sky/.pyenv/pyenv-win/shims/pip
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ marker which python
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/c/Users/sky/.pyenv/pyenv-win/shims/python
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ which pip3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/c/Users/sky/.pyenv/pyenv-win/shims/pip3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ which python3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/c/Users/sky/.pyenv/pyenv-win/shims/python3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ python -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;import torch; print(torch.__version__); print(torch.version.cuda)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2.6.0+cu126
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12.6
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ pip install -e detectron2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;......
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ModuleNotFoundError: No module named &lt;span class=&#34;s1&#34;&gt;&amp;#39;torch&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里明显前后矛盾，python 代码打印成功说明 torch 和 cuda 都安装成功，但是 pip 安装 detectron2 的时候却报错找不到 torch 模块。&lt;/p&gt;
&lt;p&gt;无奈之下我尝试了用 anaconda 替代 pyenv 来进行 python 版本的管理和隔离：创建名为 torch311 的 python 环境，并安装 python 3.11.11 版本。&lt;/p&gt;
&lt;h3 id=&#34;非常重要的参考贴&#34;&gt;非常重要的参考贴&lt;/h3&gt;
&lt;p&gt;另外发现了这个帖子，非常详细的阐述了在 windows 上安装 detection2 的整个过程，包括安装 python、torch、cuda、detection2 等，非常值得参考：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/VikParuchuri/marker/issues/12&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/VikParuchuri/marker/issues/12&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The most challenging aspect of installing Marker on Windows lies in the detectron2 package developed by Facebook Research. Facebook Research is not very Windows-friendly, and they basically do not support or provide installation guidance for Windows.&lt;/p&gt;
&lt;p&gt;在 windows 上安装 Marker 最困难的部分是 Facebook Research 开发的 detectron2 包。Facebook Research 对 Windows 不友好，他们基本上不支持或提供 Windows 的安装指导。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;安装-detectron2-前的准备工作&#34;&gt;安装 detectron2 前的准备工作&lt;/h3&gt;
&lt;p&gt;根据上面的参考贴，我尝试了新的安装方式和步骤，以下是安装 detectron2 前的准备工作：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;安装 visual studio 2022&lt;/p&gt;
&lt;p&gt;选择 “visual c++ 生成工具”, 点进去之后勾选第一项 “MSVC v143 - VS 2022 c++ x64/x86 生成工具” 和 “windows 10 SDK” / “windows 11 SDK” 即可。&lt;/p&gt;
&lt;p&gt;安装完成之后，检查 Microsoft Visual Studio 的安装路径下是否有如下的 cl.exe 文件&lt;/p&gt;
&lt;p&gt;D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.43.34808\bin\Hostx64\x64\cl.exe&lt;/p&gt;
&lt;p&gt;如果存在，则说明安装成功。&lt;/p&gt;
&lt;p&gt;（可选）设置环境变量：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Path，增加内容 &lt;code&gt;D:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.43.34808\bin\Hostx64\x64&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;VSINSTALLDIR = &lt;code&gt;D:\Program Files\Microsoft Visual Studio\2022\Community&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;备注：好像这两个环境变量不设置也行。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装 nvidia cuda 12.6 版本&lt;/p&gt;
&lt;p&gt;安装完成之后，检查 NVIDIA 的安装路径下是否有如下的 nvcc.exe 文件&lt;/p&gt;
&lt;p&gt;D:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.6\bin\nvcc.exe&lt;/p&gt;
&lt;p&gt;如果存在，则说明安装成功。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;安装 torch 和 torchvision&lt;/p&gt;
&lt;p&gt;然后继续安装 torch ：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;python -m pip install --upgrade pip setuptools wheel
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;成功安装：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;......
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Installing collected packages: mpmath, typing-extensions, sympy, pillow, numpy, networkx, MarkupSafe, fsspec, filelock, jinja2, torch, torchvision, torchaudio
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Successfully installed MarkupSafe-2.1.5 filelock-3.13.1 fsspec-2024.6.1 jinja2-3.1.4 mpmath-1.3.0 networkx-3.3 numpy-2.1.2 pillow-11.0.0 sympy-1.13.1 torch-2.6.0+cu126 torchaudio-2.6.0+cu126 torchvision-0.21.0+cu126 typing-extensions-4.12.2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;到这里 torch 就算是安装成功了，验证一下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;torch311&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; C:&lt;span class=&#34;se&#34;&gt;\U&lt;/span&gt;sers&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ky&amp;gt;python -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;import torch; print(torch.__version__)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2.6.0+cu126
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;torch311&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; C:&lt;span class=&#34;se&#34;&gt;\U&lt;/span&gt;sers&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ky&amp;gt;python -c &lt;span class=&#34;s2&#34;&gt;&amp;#34;import torch; print(torch.__version__); print(torch.version.cuda)&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2.6.0+cu126
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;12.6
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;安装-detectron2&#34;&gt;安装 detectron2&lt;/h3&gt;
&lt;p&gt;继续安装 detectron2 的时候，发现报错：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ pip install -e detectron2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;......
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    D:&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ky&lt;span class=&#34;se&#34;&gt;\w&lt;/span&gt;ork&lt;span class=&#34;se&#34;&gt;\c&lt;/span&gt;ode&lt;span class=&#34;se&#34;&gt;\m&lt;/span&gt;arker&lt;span class=&#34;se&#34;&gt;\d&lt;/span&gt;etectron2&lt;span class=&#34;se&#34;&gt;\d&lt;/span&gt;etectron2&lt;span class=&#34;se&#34;&gt;\l&lt;/span&gt;ayers&lt;span class=&#34;se&#34;&gt;\c&lt;/span&gt;src&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;ms_rotated&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;ms_rotated_cuda.cu&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;14&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: error: name must be a namespace name
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      using namespace detectron2&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                      ^
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    D:&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ky&lt;span class=&#34;se&#34;&gt;\w&lt;/span&gt;ork&lt;span class=&#34;se&#34;&gt;\c&lt;/span&gt;ode&lt;span class=&#34;se&#34;&gt;\m&lt;/span&gt;arker&lt;span class=&#34;se&#34;&gt;\d&lt;/span&gt;etectron2&lt;span class=&#34;se&#34;&gt;\d&lt;/span&gt;etectron2&lt;span class=&#34;se&#34;&gt;\l&lt;/span&gt;ayers&lt;span class=&#34;se&#34;&gt;\c&lt;/span&gt;src&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;ms_rotated&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;ms_rotated_cuda.cu&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;68&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: error: identifier &lt;span class=&#34;s2&#34;&gt;&amp;#34;single_box_iou_rotated&amp;#34;&lt;/span&gt; is undefined
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;single_box_iou_rotated&amp;lt;T&amp;gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;cur_box, block_boxes + i * 5&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                ^
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    D:&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ky&lt;span class=&#34;se&#34;&gt;\w&lt;/span&gt;ork&lt;span class=&#34;se&#34;&gt;\c&lt;/span&gt;ode&lt;span class=&#34;se&#34;&gt;\m&lt;/span&gt;arker&lt;span class=&#34;se&#34;&gt;\d&lt;/span&gt;etectron2&lt;span class=&#34;se&#34;&gt;\d&lt;/span&gt;etectron2&lt;span class=&#34;se&#34;&gt;\l&lt;/span&gt;ayers&lt;span class=&#34;se&#34;&gt;\c&lt;/span&gt;src&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;ms_rotated&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;ms_rotated_cuda.cu&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;68&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: error: &lt;span class=&#34;nb&#34;&gt;type&lt;/span&gt; name is not allowed
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;single_box_iou_rotated&amp;lt;T&amp;gt;&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;cur_box, block_boxes + i * 5&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; &amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                       ^
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; errors detected in the compilation of &lt;span class=&#34;s2&#34;&gt;&amp;#34;D:/sky/work/code/marker/detectron2/detectron2/layers/csrc/nms_rotated/nms_rotated_cuda.cu&amp;#34;&lt;/span&gt;.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    nms_rotated_cuda.cu
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    error: &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;D:\\Program Files\\nvidia-cuda-tookit-12.6\\bin\\nvcc&amp;#39;&lt;/span&gt; failed with &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; code &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;end of output&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;note: This error originates from a subprocess, and is likely not a problem with pip.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是编译问题，代码无法通过编译（这也是我现在非常疑惑的地方，去年8月那次我是怎么安装成功的？）。google 了一下，发现有人遇到了同样的问题：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/facebookresearch/detectron2/issues/1601&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/facebookresearch/detectron2/issues/1601&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这个 issue 后来被官方直接关闭了，解释是 detection2 根本不准备支持 windows 平台：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Unfortunately we &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; not provide support &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; windows.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;绝望了，准备放弃，没想到这个 issue 的评论中有人给出了一个解决方案：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/facebookresearch/detectron2/issues/1601#issuecomment-651560907&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/facebookresearch/detectron2/issues/1601#issuecomment-651560907&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;并给出了一个解决的办法：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;//NOTE: replace relative import
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;/*
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#ifdef WITH_CUDA&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#include &amp;#34;../box_iou_rotated/box_iou_rotated_utils.h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;// TODO avoid this when pytorch supports &lt;span class=&#34;s2&#34;&gt;&amp;#34;same directory&amp;#34;&lt;/span&gt; hipification
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#ifdef WITH_HIP&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#include &amp;#34;box_iou_rotated/box_iou_rotated_utils.h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;*/
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#include &amp;#34;box_iou_rotated/box_iou_rotated_utils.h&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我参考这个修改，顺利通过编译，detection2 终于完成在 windows 上的安装。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：这个issue在上面介绍 detection2 在 windows 上安装的参考贴中也有提到，但是当时没有在意，导致走了不少弯路。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;安装-marker-进行验证&#34;&gt;安装 marker 进行验证&lt;/h2&gt;
&lt;p&gt;继续安装 marker 进行验证，参考之前安装 marker 的笔记：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://skyao.net/post/202408-marker-setup-on-windows/&#34;&gt;Marker学习笔记（2）: 搭建 windows 环境&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;安装-tesseract-和-ghostscript&#34;&gt;安装 tesseract 和 Ghostscript&lt;/h3&gt;
&lt;p&gt;安装 tesseract 和 Ghostscript 的步骤和之前安装 marker 的笔记一样，这里不再赘述。&lt;/p&gt;
&lt;h3 id=&#34;安装-marker&#34;&gt;安装 marker&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip install marker-pdf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;输出为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Collecting marker-pdf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;......
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Installing collected packages: wcwidth, filetype, websockets, urllib3, typing-inspection, threadpoolctl, soupsieve, sniffio, scipy, safetensors, regex, rapidfuzz, python-dotenv, pypdfium2, pydantic-core, pyasn1, Pillow, opencv-python-headless, markdown2, joblib, jiter, idna, h11, ftfy, distro, charset-normalizer, certifi, cachetools, annotated-types, scikit-learn, rsa, requests, pydantic, pyasn1-modules, httpcore, beautifulsoup4, anyio, pydantic-settings, markdownify, huggingface-hub, httpx, google-auth, tokenizers, pdftext, google-genai, anthropic, transformers, surya-ocr, marker-pdf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Attempting uninstall: Pillow
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Found existing installation: pillow 11.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    Uninstalling pillow-11.0.0:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      Successfully uninstalled pillow-11.0.0
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Successfully installed Pillow-10.4.0 annotated-types-0.7.0 anthropic-0.46.0 anyio-4.8.0 beautifulsoup4-4.13.3 cachetools-5.5.2 certifi-2025.1.31 charset-normalizer-3.4.1 distro-1.9.0 filetype-1.2.0 ftfy-6.3.1 google-auth-2.38.0 google-genai-1.5.0 h11-0.14.0 httpcore-1.0.7 httpx-0.28.1 huggingface-hub-0.29.3 idna-3.10 jiter-0.9.0 joblib-1.4.2 markdown2-2.5.3 markdownify-0.13.1 marker-pdf-1.6.1 opencv-python-headless-4.11.0.86 pdftext-0.6.2 pyasn1-0.6.1 pyasn1-modules-0.4.1 pydantic-2.11.0b1 pydantic-core-2.31.1 pydantic-settings-2.8.1 pypdfium2-4.30.0 python-dotenv-1.0.1 rapidfuzz-3.12.2 regex-2024.11.6 requests-2.32.3 rsa-4.9 safetensors-0.5.3 scikit-learn-1.6.1 scipy-1.15.2 sniffio-1.3.1 soupsieve-2.6 surya-ocr-0.13.0 threadpoolctl-3.6.0 tokenizers-0.21.1 transformers-4.49.0 typing-inspection-0.4.0 urllib3-2.3.0 wcwidth-0.2.13 websockets-14.2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;验证-marker&#34;&gt;验证 marker&lt;/h3&gt;
&lt;p&gt;测试一下，转换一个 pdf 文件试试：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ marker_single D:&lt;span class=&#34;se&#34;&gt;\t&lt;/span&gt;emp&lt;span class=&#34;se&#34;&gt;\a&lt;/span&gt;dobe-photoshop-book-photographers-2nd.pdf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Downloading layout model...: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;......
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Running OCR Error Detection: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Detecting bboxes: 0it &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:00, ?it/s&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;......
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Detecting bboxes: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:01&amp;lt;00:00,  3.37it/s&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Recognizing Text: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:11&amp;lt;00:00,  1.84it/s&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Recognizing tables: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:03&amp;lt;00:00,  2.11it/s&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Saved markdown to D:&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ky&lt;span class=&#34;se&#34;&gt;\w&lt;/span&gt;ork&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;oft&lt;span class=&#34;se&#34;&gt;\a&lt;/span&gt;naconda&lt;span class=&#34;se&#34;&gt;\e&lt;/span&gt;nvs&lt;span class=&#34;se&#34;&gt;\t&lt;/span&gt;orch311&lt;span class=&#34;se&#34;&gt;\L&lt;/span&gt;ib&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ite-packages&lt;span class=&#34;se&#34;&gt;\c&lt;/span&gt;onversion_results&lt;span class=&#34;se&#34;&gt;\a&lt;/span&gt;dobe-photoshop-book-photographers-2nd
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Total time: 107.72942638397217
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;至此 detection2 和 marker 安装完成。&lt;/p&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;经过这么一番折腾，终于在 windows 上安装上了 detection2 和 marker。鸣谢上面提到的参考贴，以及 stackoverflow 上的帖子，以及 github 上的 issue 和评论。本着人人为我，我为人人的精神，我也将整个过程记录下来，希望对其他遇到类似问题的同学有所帮助。&lt;/p&gt;
&lt;p&gt;但依然有两个疑问我至今没能想明白：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;去年8月那次我是怎么安装成功的？毕竟从上面的过程上看，detection2 的安装过程中必须要修改源码才能编译通过，而需要修改源码这么关键的步骤，以我记录笔记的习惯，绝无可能疏漏。&lt;/li&gt;
&lt;li&gt;pyenv 和 anaconda 下同样的操作，为什么 pyenv 下安装 detection2 会报错找不到 torch 模块？&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>初试PDFMathTranslate</title>
      <link>https://skyao.net/post/202501-try-pdf2zh/</link>
      <pubDate>Wed, 08 Jan 2025 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202501-try-pdf2zh/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;备注：最后更新于 2025-03-15。这个项目进展很快，变化非常大。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;项目地址：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/Byaidu/PDFMathTranslate&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/Byaidu/PDFMathTranslate&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;windows-安装家用电脑&#34;&gt;windows 安装（家用电脑）&lt;/h2&gt;
&lt;p&gt;用自己家里的普通台式机，windows 11 ltsc 2024 版本。&lt;/p&gt;
&lt;h3 id=&#34;手动安装&#34;&gt;手动安装&lt;/h3&gt;
&lt;p&gt;安装：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip install pdf2zh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;启动 GUI 界面：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pdf2zh -i
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;或者直接命令行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pdf2zh ./applications-challenges-future-chatgpt.pdf -p 1-100
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一切顺利，除了需要做好全局科学上网的准备。&lt;/p&gt;
&lt;h3 id=&#34;下载二进制包&#34;&gt;下载二进制包&lt;/h3&gt;
&lt;p&gt;最新的版本为了方便使用，提供了打包好的二进制包，可以下载之后直接使用，非常省事。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/Byaidu/PDFMathTranslate/releases&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/Byaidu/PDFMathTranslate/releases&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;选择 pdf2zh-v1.9.6-with-assets-win64.zip ，下载之后解压，运行 pdf2zh.exe 即可。&lt;/p&gt;
&lt;h3 id=&#34;字体设置&#34;&gt;字体设置&lt;/h3&gt;
&lt;p&gt;如果需要设置字体，可以参考：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/Byaidu/PDFMathTranslate/issues/540&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/Byaidu/PDFMathTranslate/issues/540&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;翻译过程中，能看到有这样的日志：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;03/16/25 13:03:04&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; INFO     INFO:pdf2zh.high_level:use font:                                                               high_level.py:423
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                             C:/Users/sky/.cache/babeldoc/fonts/SourceHanSerifCN-Regular.ttf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以看到，默认使用的是 SourceHanSerifCN-Regular.ttf 字体，这是思源宋体。windows 系统默认没有安装这个字体，需要手动安装。&lt;/p&gt;
&lt;p&gt;可以自行安装思源黑体，也可以用 babeldoc 提供的字体，直接打开 &amp;ldquo;C:/Users/sky/.cache/babeldoc/fonts/&amp;rdquo; 目录，用字体查看器打开并安装以下字体：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SourceHanSerifCN-Regular.ttf&lt;/li&gt;
&lt;li&gt;SourceHanSerifCN-Bold.ttf&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但我其实不太喜欢宋体，尤其是在屏幕上，不管是电脑/手机/平板/电纸书，宋体的显示都不如黑体舒服，因此考虑要换成黑体。&lt;/p&gt;
&lt;p&gt;字体的设置在 high_level.py 文件中，对于用二进制文件安装的，路径如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pdf2zh\build\site-packages\pdf2zh\high_level.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pdf2zh\build\site-packages\babeldoc\high_level.py&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于用 pip 命令手工安装的，需要找到 pdf2zh 的安装路径，然后修改其中的 high_level.py 文件，如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;C:\Users\sky\.pyenv\pyenv-win\versions\3.11.9\Lib\site-packages\pdf2zh\high_level.py&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;修改其中的 download_remote_fonts 函数，将思源宋体替换为思源黑体。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;download_remote_fonts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lang&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;lang&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lang&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lower&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;LANG_NAME_MAP&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;la&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;GoNotoKurrent-Regular.ttf&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;la&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;noto_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;n&#34;&gt;la&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;sa&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;SourceHanSerif&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;region&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;-Regular.ttf&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;region&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;langs&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;s2&#34;&gt;&amp;#34;CN&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;zh-cn&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;zh-hans&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;zh&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;s2&#34;&gt;&amp;#34;TW&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;zh-tw&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;zh-hant&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;s2&#34;&gt;&amp;#34;JP&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ja&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;s2&#34;&gt;&amp;#34;KR&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ko&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;items&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;la&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;langs&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;font_name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;LANG_NAME_MAP&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lang&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;GoNotoKurrent-Regular.ttf&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;将 &lt;code&gt;SourceHanSerif{region}-Regular.ttf&amp;quot;&lt;/code&gt; 替换为 &lt;code&gt;SourceHanSans{region}-Regular.ttf&amp;quot;&lt;/code&gt; 即可。&lt;/p&gt;
&lt;h2 id=&#34;使用&#34;&gt;使用&lt;/h2&gt;
&lt;h3 id=&#34;gui-界面&#34;&gt;GUI 界面&lt;/h3&gt;
&lt;p&gt;通过执行 &lt;code&gt;pdf2zh -i&lt;/code&gt; 命令或者直接运行二进制包中的 pdf2zh.exe 可以打开基于 web 的 GUI 界面：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; pdf2zh -i
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;* Running on &lt;span class=&#34;nb&#34;&gt;local&lt;/span&gt; URL:  http://0.0.0.0:7860
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Error launching GUI using 0.0.0.0.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This may be caused by global mode of proxy software.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Rerunning server... use &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;close&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt; to stop &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; you need to change &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;launch&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt; parameters.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;---
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Error launching GUI using 127.0.0.1.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This may be caused by global mode of proxy software.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Rerunning server... use &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;close&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt; to stop &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; you need to change &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;launch&lt;span class=&#34;o&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt; parameters.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;----
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;* Running on public URL: https://0ed022102288ab69fb.gradio.live
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;This share link expires in &lt;span class=&#34;m&#34;&gt;72&lt;/span&gt; hours. For free permanent hosting and GPU upgrades, run &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;gradio deploy&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt; from the terminal in the working directory to deploy to Hugging Face Spaces &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;https://huggingface.co/spaces&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;命令行&#34;&gt;命令行&lt;/h3&gt;
&lt;p&gt;通过命令行也可以调用 pdf2zh 来进行 pdf 文件的翻译，如：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pdf2zh ./applications-challenges-future-chatgpt.pdf -p 1-100
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;顺利完成，此时在当前目录下，除了原英文版本的 pdf 文件外，还有出现两个新生成的 pdf 文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ ls *.pdf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;applications-challenges-future-chatgpt-dual.pdf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;applications-challenges-future-chatgpt-mono.pdf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;applications-challenges-future-chatgpt.pdf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;applications-challenges-future-chatgpt-mono.pdf： 中文翻译版本&lt;/li&gt;
&lt;li&gt;applications-challenges-future-chatgpt-dual.pdf：中英文对照版本，即一页中文，一页英文，方便对照。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;翻译的效果，只能说还行，借助于最新的人工智能翻译引擎，翻译后的内容可读性还算可以。如果要求不高，只是作为一个快速阅读通览全文的手段，不苛求细节，还是很不错的。至少我个人还是比较满意的。&lt;/p&gt;
&lt;p&gt;缺点自然也是有的，毕竟不能和专业人员手工翻译和多次校对，出版社精细排版的翻译成书相比。内容多少有些机翻的味道（其实已经很好了，和过去相比），排版方面也有各种瑕疵。但怎么说呢，瑕不掩瑜吧。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202501-try-pdf2zh/images/result_hu7c0d3daa3e40661338b84e4dcf566c65_496997_e59d3c35a02bdc8019e5a55a3eb9a839.webp 400w,
               /post/202501-try-pdf2zh/images/result_hu7c0d3daa3e40661338b84e4dcf566c65_496997_321e1af843934d730bcb42afc6c36ea7.webp 760w,
               /post/202501-try-pdf2zh/images/result_hu7c0d3daa3e40661338b84e4dcf566c65_496997_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202501-try-pdf2zh/images/result_hu7c0d3daa3e40661338b84e4dcf566c65_496997_e59d3c35a02bdc8019e5a55a3eb9a839.webp&#34;
               width=&#34;655&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;关键是这个翻译是真很方便，真的很快。尤其是网上经常有大量的英文技术书籍出版，这些书籍引入到国内翻译完成到出版上市，和英文原版相比最少要晚1-2年，在技术日新月异的今天，两年时间会造成技术书籍的时效性大减。&lt;/p&gt;
&lt;p&gt;另外，网上通常很快就会有这些新出版书籍的 pdf 格式文件可供下载，拿到这些英文原版 pdf 之后，通过 pdf2zh 工具进行快速翻译，可以立即得到一个不完美但是基本可读的中文翻译版本，还是很不错的。毕竟中文是母语，可以一目十行的快速浏览。&lt;/p&gt;
&lt;h3 id=&#34;可选参数&#34;&gt;可选参数&lt;/h3&gt;
&lt;p&gt;无论是 GUI 还是命令行， 都有不少参数可供选择。&lt;/p&gt;
&lt;p&gt;这是 pdf2zh 的命令行帮助的输出：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ pdf2zh --help
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;usage: pdf2zh &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;-h&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--version&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--debug&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--pages PAGES&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--vfont VFONT&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--vchar VCHAR&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--lang-in LANG_IN&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--lang-out LANG_OUT&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--service SERVICE&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--output OUTPUT&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--thread THREAD&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--interactive&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--share&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--flask&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--celery&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--authorized AUTHORIZED &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;AUTHORIZED ...&lt;span class=&#34;o&#34;&gt;]]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--prompt PROMPT&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--compatible&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--onnx ONNX&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--serverport SERVERPORT&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--dir&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--config CONFIG&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--babeldoc&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--skip-subset-fonts&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;--ignore-cache&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;files ...&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;A &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; line tool &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; extracting text and images from PDF and output it to plain text, html, xml or tags.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;positional arguments:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  files                 One or more paths to PDF files.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;options:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  -h, --help            show this &lt;span class=&#34;nb&#34;&gt;help&lt;/span&gt; message and &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --version, -v         show program&lt;span class=&#34;err&#34;&gt;&amp;#39;&lt;/span&gt;s version number and &lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --debug, -d           Use debug logging level.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Parser:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  Used during PDF parsing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --pages PAGES, -p PAGES
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        The list of page numbers to parse.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --vfont VFONT, -f VFONT
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        The regex to math font name of formula.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --vchar VCHAR, -c VCHAR
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        The regex to math character of formula.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --lang-in LANG_IN, -li LANG_IN
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        The code of &lt;span class=&#34;nb&#34;&gt;source&lt;/span&gt; language.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --lang-out LANG_OUT, -lo LANG_OUT
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        The code of target language.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --service SERVICE, -s SERVICE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        The service to use &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; translation.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --output OUTPUT, -o OUTPUT
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        Output directory &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; files.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --thread THREAD, -t THREAD
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        The number of threads to execute translation.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --interactive, -i     Interact with GUI.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --share               Enable Gradio Share
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --flask               flask
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --celery              celery
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --authorized AUTHORIZED &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;AUTHORIZED ...&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        user name and password.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --prompt PROMPT       user custom prompt.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --compatible, -cp     Convert the PDF file into PDF/A format to improve compatibility.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --onnx ONNX           custom onnx model path.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --serverport SERVERPORT
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                        custom WebUI port.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --dir                 translate directory.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --config CONFIG       config file.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --babeldoc            Use experimental backend babeldoc.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --skip-subset-fonts   Skip font subsetting. This option can improve compatibility but will increase the size of the output file.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  --ignore-cache        Ignore cache and force retranslation.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中最重要的是选择用于翻译的服务，可选项有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Google&lt;/li&gt;
&lt;li&gt;Bing&lt;/li&gt;
&lt;li&gt;DeepL&lt;/li&gt;
&lt;li&gt;DeepLX&lt;/li&gt;
&lt;li&gt;Ollama&lt;/li&gt;
&lt;li&gt;AzureOpenAI&lt;/li&gt;
&lt;li&gt;OpenAI&lt;/li&gt;
&lt;li&gt;Zhipu&lt;/li&gt;
&lt;li&gt;Silicom&lt;/li&gt;
&lt;li&gt;Gemini&lt;/li&gt;
&lt;li&gt;Azure&lt;/li&gt;
&lt;li&gt;Tencent&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意在命令行中需要用小写，如：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ pdf2zh ./applications-challenges-future-chatgpt.pdf -p 1-10 -s google
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 耗时4秒&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ pdf2zh ./applications-challenges-future-chatgpt.pdf -p 1-10 -s bing
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 耗时32秒&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对于 auth_key 等额外参数的，需要通过环境变量来传递，如 deepl:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ &lt;span class=&#34;nv&#34;&gt;DEEPL_SERVER_URL&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;https://api-free.deepl.com &lt;span class=&#34;nv&#34;&gt;DEEPL_AUTH_KEY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;84416fef-xxxx-xxxx-xxxx-xxxxxxxf3:fx pdf2zh ./applications-challenges-future-chatgpt.pdf -p 1-10 -s deepl
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 耗时16秒&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;具体有哪些环境变量要设置，没有看到文档，估计只能翻代码了。我是在 issue 中偶尔看到的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Byaidu/PDFMathTranslate/issues/175&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/Byaidu/PDFMathTranslate/issues/175&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;首先说优点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;能用：虽然多少有机翻的味道和排版不够理想，但起码是能入目的，从务实的角度看足以满足快速翻译/快速阅读的基本目标&lt;/li&gt;
&lt;li&gt;便捷：理论上一个命令就能完成全部翻译工作，对比我之前用 marker 将 pdf 转 markdown，再人工纠正排版，然后机翻+人工校对，速度快了几十倍。&lt;/li&gt;
&lt;/ul&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;翻译引擎的选择难题，免费的有限制，收费的很贵。唯一欣喜的是 bing 即免费又没限制，简直良心。&lt;/li&gt;
&lt;li&gt;最重要的：文档极其匮乏，遇到问题只能自己去 issue 中碰运气和 google。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s/cw1M0GVxfCE8095MyNWcdg?utm_source=pocket_shared&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;1.7K Star 科研党必备！PDFMathTranslate：精准翻译PDF，完美保留排版的开源神器。&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Marker学习笔记（3）: 拆分 markdown 文件</title>
      <link>https://skyao.net/post/202408-marker-split-markdown/</link>
      <pubDate>Mon, 26 Aug 2024 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202408-marker-split-markdown/</guid>
      <description>&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;Marker 生成的 markdown 文件是一个包含 pdf 所有内容的单个文件，当 pdf 文件内容比较多时，这个 markdown 文件的尺寸会比较大，影响阅读和后续处理（比如翻译）。&lt;/p&gt;
&lt;p&gt;如下图，原 pdf 文件有 680 多页，转换得到的 markdown 文件足足有 619K ：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ls -lh
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-rwxr-xr-x &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; sky sky 619K  8月 &lt;span class=&#34;m&#34;&gt;24&lt;/span&gt; 21:03 adobe-photoshop-book-photographers-2nd.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;-rwxr-xr-x &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; sky sky  46K  8月 &lt;span class=&#34;m&#34;&gt;23&lt;/span&gt; 10:25 adobe-photoshop-book-photographers-2nd_meta.json
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因此考虑将这个大 markdown 文件拆分为若一组小一点的 markdown 文件。很显然，按照章节进行拆分是比较合理的。&lt;/p&gt;
&lt;h2 id=&#34;bash脚本&#34;&gt;bash脚本&lt;/h2&gt;
&lt;p&gt;用 bash 脚本实现这个功能会很简单：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TODO: update keywords for different markdown files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;0&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;introduction&amp;#34;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# will be ignored for splitting and just used for naming&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;1&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# The Essentials Of Camera Raw&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;2&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Camera Raw–Beyond The Basics&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;3&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Masking Miracles&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;4&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Correcting Lens Problems&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;5&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Working With Layers&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;6&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Making Selections&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;7&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Black &amp;amp; White, Duotones &amp;amp; More&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;8&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Cropping &amp;amp; Resizing&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;9&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Retouching Portraits&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;10&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Removing Distracting Stuff&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;11&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Photoshop Effects&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;12&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Sharpening Techniques&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Preparing, reading keywords for chapters......&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;chapter_names&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;((&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$index&lt;/span&gt;&amp;lt;&lt;span class=&#34;si&#34;&gt;${#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_begin_keywords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[*]&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# build chapter name by keywords and index&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# remove &amp;#34;# &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_begin_keywords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]//# /&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# remove &amp;#34;&amp;amp; &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;//&amp;amp; /&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# remove &amp;#34;,&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;//,/&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# replace &amp;#34; &amp;#34; with &amp;#34;-&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;// /-&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# lowcase all&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,,&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# add &amp;#34;chapterxx&amp;#34; prefix&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[[&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$index&lt;/span&gt; -lt &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;chapter0&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;chapter&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;# add &amp;#34;.md&amp;#34; suffix&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;.md&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    chapter_names&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_name&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;chapter &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; begin keyword=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_begin_keywords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;chapter name=&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_names&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;index++&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# clean files before execution&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;clean chapter files if exists&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rm -f chapter*.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;rm -f todo.md todo-temp.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Begin to split file &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; by keywords......&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cp &lt;span class=&#34;nv&#34;&gt;$1&lt;/span&gt; todo.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;index&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;((&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$index&lt;/span&gt; &amp;lt; &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${#&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_begin_keywords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[*]&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt; - &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;)))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    cat todo.md &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep -B &lt;span class=&#34;m&#34;&gt;1000000000&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_begin_keywords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;+1]&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_names&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    cat todo.md &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep -A &lt;span class=&#34;m&#34;&gt;1000000000&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_begin_keywords&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;+1]&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt; todo-temp.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    rm -f todo.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    mv todo-temp.md todo.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Succeed to split out &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_names&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nb&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;index++&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;done&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# last chapter will be saved in todo.md, just rename it!&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mv todo.md &lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_names&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Succeed to split out &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;${&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;chapter_names&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$index&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Done!&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Please check the output files:&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ls -lh chapter*.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个脚本在使用前，需要为要拆分的 markdown 文件提供每个章节开始部位的关键字，比如之前生成的 adobe-photoshop-book-photographers-2nd.md 文件，每个章节都会以类似 &amp;ldquo;# The Essentials Of Camera Raw&amp;rdquo; 的方式开始，&lt;/p&gt;
&lt;p&gt;为了从 markdown 文件中找到每个章节开始的关键字， 可以用下面的命令先做一次筛选：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;cat ./adobe-photoshop-book-photographers-2nd.md &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep &lt;span class=&#34;s2&#34;&gt;&amp;#34;# &amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep -v &lt;span class=&#34;s2&#34;&gt;&amp;#34;## &amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后结合 pdf 的章节标题，就能很快找出来各个章节开始的关键字：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# TODO: update keywords for different markdown files&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;0&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;introduction&amp;#34;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;# will be ignored for splitting and just used for naming&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;1&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# The Essentials Of Camera Raw&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;2&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Camera Raw–Beyond The Basics&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;3&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Masking Miracles&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;4&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Correcting Lens Problems&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;5&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Working With Layers&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;6&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Making Selections&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;7&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Black &amp;amp; White, Duotones &amp;amp; More&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;8&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Cropping &amp;amp; Resizing&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;9&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Retouching Portraits&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;10&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Removing Distracting Stuff&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;11&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Photoshop Effects&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chapter_begin_keywords&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;12&lt;span class=&#34;o&#34;&gt;]=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;# Sharpening Techniques&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;......
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;附件： &lt;a href=&#34;./images/split.sh&#34;&gt;split.sh文件&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;手工调整&#34;&gt;手工调整&lt;/h2&gt;
&lt;p&gt;拆分过程并不会完美，比如在章节关键字之前，可能会有几张图片。这些图片的内容目前会被拆分到上一个章节中，需要手工进行调整。另外书籍末尾的 index 章节往往没有意义，通常会考虑删除。&lt;/p&gt;
&lt;p&gt;谨慎起见，手工调整的过程中，也可以对照 pdf 原文核对一下拆分是否准确。&lt;/p&gt;
&lt;h2 id=&#34;结论&#34;&gt;结论&lt;/h2&gt;
&lt;p&gt;虽然有 AI 的介入，但是有些还是需要人工介入，这也就意味着工作量，希望 AI 以后可以做的更加的智能。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Marker学习笔记（2）: 搭建 windows 环境</title>
      <link>https://skyao.net/post/202408-marker-setup-on-windows/</link>
      <pubDate>Sun, 25 Aug 2024 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202408-marker-setup-on-windows/</guid>
      <description>&lt;p&gt;硬件说明： 我所使用的电脑安装有 windows 11 版本，配置有 nvidia rtx 4080 显卡，可以提供 cuda 的支持。&lt;/p&gt;
&lt;p&gt;内容有参考这篇文档： &lt;a href=&#34;https://www.bilibili.com/read/cv29426242/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Marker：Windows 环境下折腾 PDF 转 Markdown&lt;/a&gt;。鸣谢原作者。&lt;/p&gt;
&lt;h2 id=&#34;克隆-marker-仓库&#34;&gt;克隆 marker 仓库&lt;/h2&gt;
&lt;p&gt;首先克隆 marker 的 github 代码仓库，后面使用时会用到：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p ~/work/code/marker
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ~/work/code/marker
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone git@github.com:VikParuchuri/marker.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; marker
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;安装-marker-及其依赖&#34;&gt;安装 marker 及其依赖&lt;/h2&gt;
&lt;h3 id=&#34;安装-python&#34;&gt;安装 python&lt;/h3&gt;
&lt;p&gt;要求 python 3.9+ ，我在linux 下用的是 3.10 版本，windows 下继续保持一致，下载地址：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.python.org/ftp/python/3.10.11/python-3.10.11-amd64.exe&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://www.python.org/ftp/python/3.10.11/python-3.10.11-amd64.exe&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;安装过程选自定义安装，然后记得勾选自动设置windows环境变量。安装完成后，在 cmd 中验证版本：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ pip --version
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip 23.0.1 from D:&lt;span class=&#34;se&#34;&gt;\w&lt;/span&gt;ork&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;oft&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;ython&lt;span class=&#34;se&#34;&gt;\l&lt;/span&gt;ib&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ite-packages&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;ip &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;python 3.10&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ python --version
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Python 3.10.11
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在 git bash 中验证（记得如果有打开 git bash 要关闭后重新打开才能载入新的环境变量）：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ python --version
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Python 3.10.11
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ pip --version
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip 23.0.1 from D:&lt;span class=&#34;se&#34;&gt;\w&lt;/span&gt;ork&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;oft&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;ython&lt;span class=&#34;se&#34;&gt;\l&lt;/span&gt;ib&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ite-packages&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;ip &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;python 3.10&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;特别提示-python-版本的选择&#34;&gt;特别提示： python 版本的选择&lt;/h3&gt;
&lt;p&gt;在 pytorch 官方文档中有这么一段提示：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://pytorch.org/get-started/locally/#windows-installation&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://pytorch.org/get-started/locally/#windows-installation&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Currently, PyTorch on Windows only supports Python 3.8-3.11&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我验证过，3.12版本的确会有问题，所以千万不要选 3.12 版本。&lt;/p&gt;
&lt;h3 id=&#34;安装-pytorch-和-torchvision&#34;&gt;安装 pytorch 和 torchvision&lt;/h3&gt;
&lt;p&gt;参考：&lt;a href=&#34;https://pytorch.org/get-started/locally/#windows-installation&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Start Locally | PyTorch&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我选择的是 stable(2.4.0) + windows + pip + python + CUDA 12.4，因此需要运行命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装顺利完成：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Installing collected packages: mpmath, typing-extensions, sympy, setuptools, pillow, numpy, networkx, MarkupSafe, fsspec, filelock, jinja2, torch, torchvision, torchaudio
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Successfully installed MarkupSafe-2.1.5 filelock-3.13.1 fsspec-2024.2.0 jinja2-3.1.3 mpmath-1.3.0 networkx-3.2.1 numpy-1.26.3 pillow-10.2.0 setuptools-70.0.0 sympy-1.12 torch-2.4.0+cu124 torchaudio-2.4.0+cu124 torchvision-0.19.0+cu124 typing-extensions-4.9.0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;安装-visual-c-生成工具&#34;&gt;安装 visual c++ 生成工具&lt;/h3&gt;
&lt;p&gt;从 &lt;a href=&#34;https://visualstudio.microsoft.com/visual-cpp-build-tools/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://visualstudio.microsoft.com/visual-cpp-build-tools/&lt;/a&gt; 下载到 &lt;code&gt;vs_BuildTools.exe&lt;/code&gt;，然后进行安装。安装内容选择 &amp;ldquo;visual c++ 生成工具&amp;rdquo;, 点进去之后勾选第一项 &amp;ldquo;MSVC v143 - VS 2022 c++ x64/x86 生成工具&amp;rdquo; 和第二项 &amp;ldquo;windows 11 SDK&amp;rdquo; 即可。&lt;/p&gt;
&lt;p&gt;为了不占用c盘空间，修改安装路径为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;virtual studio ide：从默认的 &lt;code&gt;C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools&lt;/code&gt; 修改为 &lt;code&gt;D:\work\soft\Microsoft Visual Studio\2022\BuildTools&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;下载缓存：从默认的&lt;code&gt;C:\ProgramData\Microsoft\VisualStudio\Packages&lt;/code&gt; 修改为 &lt;code&gt;D:\work\soft\Microsoft\VisualStudio\Packages&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;共享组件，工具和sdk：从默认的&lt;code&gt;C:\Program Files (x86)\Microsoft Visual Studio\Shared&lt;/code&gt; 修改为 &lt;code&gt;D:\work\soft\Microsoft Visual Studio\Shared&lt;/code&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;安装-detectron2&#34;&gt;安装 detectron2&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ~/work/code/marker
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone https://github.com/facebookresearch/detectron2.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip install -e detectron2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意，如果是 python 3.12 版本，会遇到报错：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ModuleNotFoundError: No module named &lt;span class=&#34;s1&#34;&gt;&amp;#39;torch&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个问题google一圈没有修复，最后通过退回 python 3.10 版本才得以解决。&lt;/p&gt;
&lt;p&gt;如果遇到缺少 fbgemm.dll 的报错：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      OSError: &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;WinError 126&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 找不到指定的模块。 Error loading &lt;span class=&#34;s2&#34;&gt;&amp;#34;D:\work\soft\python\lib\site-packages\torch\lib\fbgemm.dll&amp;#34;&lt;/span&gt; or one of its dependencies.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;end of output&lt;span class=&#34;o&#34;&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;p&gt;&lt;a href=&#34;https://www.dllme.com/dll/files/libomp140_x86_64/00637fe34a6043031c9ae4c6cf0a891d/download&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;libomp140.x86_64.dll : Free .DLL download. (dllme.com)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;将得到的 libomp140.x86_64_x86-64.zip 文件解压，将里面的 libomp140.x86_64.dll 文件复制到操作系统的 &lt;code&gt;Windows\system32&lt;/code&gt; 目录下即可。&lt;/p&gt;
&lt;p&gt;如果没有安装 visual c++ 生成工具，则会报错：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    D:&lt;span class=&#34;se&#34;&gt;\w&lt;/span&gt;ork&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;oft&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;ython&lt;span class=&#34;se&#34;&gt;\l&lt;/span&gt;ib&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ite-packages&lt;span class=&#34;se&#34;&gt;\t&lt;/span&gt;orch&lt;span class=&#34;se&#34;&gt;\u&lt;/span&gt;tils&lt;span class=&#34;se&#34;&gt;\c&lt;/span&gt;pp_extension.py:380: UserWarning: Error checking compiler version &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; cl: &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;WinError 2&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 系统找不到指定的文件。
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      warnings.warn&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;f&lt;span class=&#34;s1&#34;&gt;&amp;#39;Error checking compiler version for {compiler}: {error}&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    building &lt;span class=&#34;s1&#34;&gt;&amp;#39;detectron2._C&amp;#39;&lt;/span&gt; extension
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    error: Microsoft Visual C++ 14.0 or greater is required. Get it with &lt;span class=&#34;s2&#34;&gt;&amp;#34;Microsoft C++ Build Tools&amp;#34;&lt;/span&gt;: https://visualstudio.microsoft.com/visual-cpp-build-tools/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;按照上面的提示安装  visual c++ 生成工具即可。&lt;/p&gt;
&lt;h3 id=&#34;安装-tesseract&#34;&gt;安装 tesseract&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://digi.bib.uni-mannheim.de/tesseract/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://digi.bib.uni-mannheim.de/tesseract/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;找到最新版本 tesseract-ocr-w64-setup-5.4.0.20240606.exe：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://digi.bib.uni-mannheim.de/tesseract/tesseract-ocr-w64-setup-5.4.0.20240606.exe&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://digi.bib.uni-mannheim.de/tesseract/tesseract-ocr-w64-setup-5.4.0.20240606.exe&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;下载安装即可。&lt;/p&gt;
&lt;h3 id=&#34;安装-ghostscript&#34;&gt;安装 Ghostscript&lt;/h3&gt;
&lt;p&gt;安装文档：https://ghostscript.readthedocs.io/en/gs10.02.0/Install.html&lt;/p&gt;
&lt;p&gt;下载页面：https://ghostscript.com/releases/gsdnld.html&lt;/p&gt;
&lt;p&gt;下载得到 gs10031w64.exe，安装即可。&lt;/p&gt;
&lt;h3 id=&#34;安装-cuba&#34;&gt;安装 CUBA&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://developer.nvidia.com/cuda-downloads&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://developer.nvidia.com/cuda-downloads&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;安装文件有3个G！正常下载安装接口。&lt;/p&gt;
&lt;h3 id=&#34;安装-marker&#34;&gt;安装 marker&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip install marker-pdf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安装完成时的输出：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Installing collected packages: wcwidth, filetype, urllib3, threadpoolctl, scipy, safetensors, regex, rapidfuzz, python-dotenv, pypdfium2, pydantic-core, opencv-python, joblib, idna, ftfy, charset-normalizer, certifi, annotated-types, scikit-learn, requests, pydantic, pydantic-settings, huggingface-hub, tokenizers, pdftext, transformers, texify, surya-ocr, marker-pdf
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Successfully installed annotated-types-0.7.0 certifi-2024.7.4 charset-normalizer-3.3.2 filetype-1.2.0 ftfy-6.2.3 huggingface-hub-0.24.6 idna-3.8 joblib-1.4.2 marker-pdf-0.2.17 opencv-python-4.10.0.84 pdftext-0.3.10 pydantic-2.8.2 pydantic-core-2.20.1 pydantic-settings-2.4.0 pypdfium2-4.30.0 python-dotenv-1.0.1 rapidfuzz-3.9.6 regex-2024.7.24 requests-2.32.3 safetensors-0.4.4 scikit-learn-1.4.2 scipy-1.14.1 surya-ocr-0.5.0 texify-0.1.10 threadpoolctl-3.5.0 tokenizers-0.19.1 transformers-4.44.2 urllib3-2.2.2 wcwidth-0.2.13
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;使用-marker&#34;&gt;使用 marker&lt;/h2&gt;
&lt;p&gt;先尝试转换单个文件，我以从网络上下载的 &lt;code&gt;adobe-photoshop-book-photographers-2nd.pdf&lt;/code&gt; 这个680页的英文 pdf 为例。&lt;/p&gt;
&lt;p&gt;先设置临时环境变量，注意在 cmd 下要用 set 命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;set&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;IMAGE_DPI&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;192&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; %IMAGE_DPI%
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是在 bash/zsh 下要用 export 命令：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;IMAGE_DPI&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;192&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$IMAGE_DPI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;安全起见，打印一下 IMAGE_DPI 环境变量以检验是否设置成功。然后执行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;marker_single E:&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;tudy&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ky&lt;span class=&#34;se&#34;&gt;\e&lt;/span&gt;book&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;hotograph&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;hotoshop&lt;span class=&#34;se&#34;&gt;\2&lt;/span&gt;024-adobe-photoshop-book-photographers-2nd&lt;span class=&#34;se&#34;&gt;\a&lt;/span&gt;dobe-photoshop-book-photographers-2nd.pdf E:&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;tudy&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ky&lt;span class=&#34;se&#34;&gt;\e&lt;/span&gt;book&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;hotograph&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;hotoshop&lt;span class=&#34;se&#34;&gt;\2&lt;/span&gt;024-adobe-photoshop-book-photographers-2nd&lt;span class=&#34;se&#34;&gt;\m&lt;/span&gt;arkdown-windows --batch_multiplier &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; --max_pages &lt;span class=&#34;m&#34;&gt;10&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=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded detection model vikp/surya_det3 on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded detection model vikp/surya_layout3 on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded reading order model vikp/surya_order on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded recognition model vikp/surya_rec2 on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded texify model to cuda with torch.float16 dtype
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Detecting bboxes: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;██████████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 1/1 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:01&amp;lt;00:00,  1.07s/it&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Recognizing Text: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;██████████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 1/1 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:00&amp;lt;00:00,  2.81it/s&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Detecting bboxes: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;██████████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 1/1 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:00&amp;lt;00:00,  1.12it/s&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Finding reading order: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;█████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 1/1 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:00&amp;lt;00:00,  1.33it/s&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D:&lt;span class=&#34;se&#34;&gt;\w&lt;/span&gt;ork&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;oft&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;ython&lt;span class=&#34;se&#34;&gt;\l&lt;/span&gt;ib&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ite-packages&lt;span class=&#34;se&#34;&gt;\t&lt;/span&gt;hreadpoolctl.py:1214: RuntimeWarning:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Found Intel OpenMP &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;libiomp&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; and LLVM OpenMP &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;libomp&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; loaded at
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;the same time. Both libraries are known to be incompatible and this
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;can cause random crashes or deadlocks on Linux when loaded in the
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;same Python program.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Using threadpoolctl may cause crashes or deadlocks. For more
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;information and possible workarounds, please see
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    https://github.com/joblib/threadpoolctl/blob/master/multiple_openmp.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  warnings.warn&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;msg, RuntimeWarning&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Saved markdown to the E:&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;tudy&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ky&lt;span class=&#34;se&#34;&gt;\e&lt;/span&gt;book&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;hotograph&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;hotoshop&lt;span class=&#34;se&#34;&gt;\2&lt;/span&gt;024-adobe-photoshop-book-photographers-2nd&lt;span class=&#34;se&#34;&gt;\m&lt;/span&gt;arkdown-windows&lt;span class=&#34;se&#34;&gt;\a&lt;/span&gt;dobe-photoshop-book-photographers-2nd folder
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但在转换整个 pdf 文档（共680页）时，报错了：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;OSError: &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;WinError 1455&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; 页面文件太小，无法完成操作。 Error loading &lt;span class=&#34;s2&#34;&gt;&amp;#34;D:\work\soft\python\lib\site-packages\torch\lib\cublas64_12.dll&amp;#34;&lt;/span&gt; or one of its dependencies.
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是 windows 虚拟内存配置的太小了，尤其是我没有在 d 盘配置虚拟内存，因此修改系统配置，在 c 和 d 盘都配置固定大小为 16392 （16GB）的虚拟内存。重启电脑之后再试。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ marker_single E:&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;tudy&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ky&lt;span class=&#34;se&#34;&gt;\e&lt;/span&gt;book&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;hotograph&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;hotoshop&lt;span class=&#34;se&#34;&gt;\2&lt;/span&gt;024-adobe-photoshop-book-photographers-2nd&lt;span class=&#34;se&#34;&gt;\a&lt;/span&gt;dobe-photoshop-book-photographers-2nd.pdf E:&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;tudy&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ky&lt;span class=&#34;se&#34;&gt;\e&lt;/span&gt;book&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;hotograph&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;hotoshop&lt;span class=&#34;se&#34;&gt;\2&lt;/span&gt;024-adobe-photoshop-book-photographers-2nd&lt;span class=&#34;se&#34;&gt;\m&lt;/span&gt;arkdown-windows --batch_multiplier &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded detection model vikp/surya_det3 on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded detection model vikp/surya_layout3 on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded reading order model vikp/surya_order on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded recognition model vikp/surya_rec2 on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded texify model to cuda with torch.float16 dtype
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Detecting bboxes: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 25/25 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:26&amp;lt;00:00,  1.06s/it&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Recognizing Text: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 1/1 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:00&amp;lt;00:00,  1.01it/s&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Detecting bboxes: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 17/17 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:33&amp;lt;00:00,  1.97s/it&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Finding reading order: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 17/17 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:20&amp;lt;00:00,  1.20s/it&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;D:&lt;span class=&#34;se&#34;&gt;\w&lt;/span&gt;ork&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;oft&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;ython&lt;span class=&#34;se&#34;&gt;\l&lt;/span&gt;ib&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ite-packages&lt;span class=&#34;se&#34;&gt;\t&lt;/span&gt;hreadpoolctl.py:1214: RuntimeWarning:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Found Intel OpenMP &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;libiomp&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; and LLVM OpenMP &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;libomp&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; loaded at
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;the same time. Both libraries are known to be incompatible and this
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;can cause random crashes or deadlocks on Linux when loaded in the
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;same Python program.
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Using threadpoolctl may cause crashes or deadlocks. For more
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;information and possible workarounds, please see
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    https://github.com/joblib/threadpoolctl/blob/master/multiple_openmp.md
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  warnings.warn&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;msg, RuntimeWarning&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Saved markdown to the E:&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;tudy&lt;span class=&#34;se&#34;&gt;\s&lt;/span&gt;ky&lt;span class=&#34;se&#34;&gt;\e&lt;/span&gt;book&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;hotograph&lt;span class=&#34;se&#34;&gt;\p&lt;/span&gt;hotoshop&lt;span class=&#34;se&#34;&gt;\2&lt;/span&gt;024-adobe-photoshop-book-photographers-2nd&lt;span class=&#34;se&#34;&gt;\m&lt;/span&gt;arkdown-windows&lt;span class=&#34;se&#34;&gt;\a&lt;/span&gt;dobe-photoshop-book-photographers-2nd folder
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;有一个警告，暂时先不管。检查了一下生成的内容，和 linux 下一样，没什么问题。验证 windows 下 marker 是可以正常工作的。&lt;/p&gt;
&lt;p&gt;至于 marker 的其他使用方式，由于和 linux 下保持一致，本文就不赘述了。&lt;/p&gt;
&lt;h2 id=&#34;结论&#34;&gt;结论&lt;/h2&gt;
&lt;p&gt;windows 下安装 marker 要比 linux 下折腾的多，主要是有几个坑，尤其 python 版本的选择要特别注意。但折腾一次之后，后面再参照这个文档安装就会容易许多。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Marker学习笔记（1）: 用人工智能实现从 PDF 到 Markdown</title>
      <link>https://skyao.net/post/202408-marker-pdf-to-markdown/</link>
      <pubDate>Sat, 24 Aug 2024 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202408-marker-pdf-to-markdown/</guid>
      <description>&lt;h2 id=&#34;marker介绍&#34;&gt;Marker介绍&lt;/h2&gt;
&lt;p&gt;Marker 是一个快速、高精度地将 PDF 转换为 Markdown 的工具。&lt;/p&gt;
&lt;p&gt;这是摘录自 Marker 官方网站的介绍：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Marker is a PDF to Markdown converter that recognizes tables, OCRs equations, and re-OCRs bad pdf text. Marker has 8000+ stars on Github, benchmarks well against other similar tools, and is used by hundreds of organizations.&lt;/p&gt;
&lt;p&gt;Marker 是一款 PDF 到 Markdown 的转换器，它能识别表格、OCR 方程并重新 OCR 不良 PDF 文本。Marker 在 Github 上拥有 8000 多颗星，与其他同类工具相比具有很好的基准，并被数百家机构使用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Marker 的一些资料：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;项目代码仓库在： &lt;a href=&#34;https://github.com/VikParuchuri/marker&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/VikParuchuri/marker&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;官方网站： &lt;a href=&#34;https://www.datalab.to/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://www.datalab.to/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;本篇文档介绍 Marker 的安装和使用，内容参考官方文档： &lt;a href=&#34;https://github.com/VikParuchuri/marker/blob/master/README.md&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/VikParuchuri/marker/blob/master/README.md&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;硬件说明： 我所使用的电脑安装有 linux mint 21.3 版本，基于 ubuntu 22.04，因此 ubuntu / debian 系列操作系统上的操作应该都是类似的。配置有 nvidia rtx 4080 显卡，可以提供 cuda 的支持。&lt;/p&gt;
&lt;h2 id=&#34;克隆-marker-仓库&#34;&gt;克隆 marker 仓库&lt;/h2&gt;
&lt;p&gt;首先克隆 marker 的 github 代码仓库，后面使用时会用到：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;mkdir -p ~/work/code/marker
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ~/work/code/marker
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;git clone git@github.com:VikParuchuri/marker.git
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; marker
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;安装-marker-及其依赖&#34;&gt;安装 marker 及其依赖&lt;/h2&gt;
&lt;h3 id=&#34;安装-python&#34;&gt;安装 python&lt;/h3&gt;
&lt;p&gt;要求 python 3.9+ ，我机器上默认已经有了 Python 3.10.12：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ python3 --version
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Python 3.10.12
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是没有 pip：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ pip                 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;zsh: &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; not found: pip
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;继续安装:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt install python3-pip python3.10-venv
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;完成后检查 pip：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ pip --version                               
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip 22.0.2 from /usr/lib/python3/dist-packages/pip &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;python 3.10&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;安装-pytorch&#34;&gt;安装 PyTorch&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip3 install torch torchvision torchaudio
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;安装-marker&#34;&gt;安装 marker&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip install marker-pdf
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我机器上装有 nvidia rtx4080 显卡，安装中被识别到，安装过程中有下载 nvidia-cuda-runtime-cu12 / nvidia-cuda-cupti-cu12 / nvidia-curand-cu12 等 cuda 相关的包。&lt;/p&gt;
&lt;h2 id=&#34;marker-配置&#34;&gt;marker 配置&lt;/h2&gt;
&lt;p&gt;按照官方说明:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Inspect the settings in &lt;code&gt;marker/settings.py&lt;/code&gt;. You can override any settings with environment variables.&lt;/p&gt;
&lt;p&gt;检查&lt;code&gt;marker/settings.py&lt;/code&gt;中的设置。您可以使用环境变量覆盖任何设置。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Your torch device will be automatically detected, but you can override this. For example, &lt;code&gt;TORCH_DEVICE=cuda&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;你的 torch 设备会被自动检测到，但你可以忽略它。例如，&lt;code&gt;TORCH_DEVICE=cuda&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;By default, marker will use &lt;code&gt;surya&lt;/code&gt; for OCR. Surya is slower on CPU, but more accurate than tesseract. It also doesn&amp;rsquo;t require you to specify the languages in the document. If you want faster OCR, set &lt;code&gt;OCR_ENGINE&lt;/code&gt; to &lt;code&gt;ocrmypdf&lt;/code&gt;. This also requires external dependencies (see above). If you don&amp;rsquo;t want OCR at all, set &lt;code&gt;OCR_ENGINE&lt;/code&gt; to &lt;code&gt;None&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;默认情况下，marker 将使用&lt;code&gt;surya&lt;/code&gt;进行OCR。Surya在CPU上速度较慢，但比 tesseract 更准确。它也不要求您指定文档中的语言。如果你想要更快的OCR，请将&lt;code&gt;OCR_ENGINE&lt;/code&gt;设置为&lt;code&gt;ocrmypdf&lt;/code&gt;。这也需要外部依赖性（见上文）。如果您根本不需要OCR，请将&lt;code&gt;OCR_ENGINE&lt;/code&gt;设置为&lt;code&gt;None&lt;/code&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;IMAGE_DPI： 从 pdf 中提取图像时渲染的 DPI，默认96,有点低，会造成提取出来的图片清晰度明显低于 pdf 原图片的问题，尤其是图片上的细小文字会因此变得模糊而不可读。因此考虑设置的大一些，比如设置 DPI 为 192.&lt;/p&gt;
&lt;p&gt;实测，这是默认 96 DPI 时从 pdf 中提取的图片，文字已经模糊到难于识别：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;19_image_1-DPI-96&#34; srcset=&#34;
               /post/202408-marker-pdf-to-markdown/images/19_image_1-DPI-96_hu5168811d0d09343d40a51a530e209dd6_146813_8f34bb51d1eef9f194c2d4ba2e05cc96.webp 400w,
               /post/202408-marker-pdf-to-markdown/images/19_image_1-DPI-96_hu5168811d0d09343d40a51a530e209dd6_146813_be5b87573f5a79750fef00ea63dd5575.webp 760w,
               /post/202408-marker-pdf-to-markdown/images/19_image_1-DPI-96_hu5168811d0d09343d40a51a530e209dd6_146813_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202408-marker-pdf-to-markdown/images/19_image_1-DPI-96_hu5168811d0d09343d40a51a530e209dd6_146813_8f34bb51d1eef9f194c2d4ba2e05cc96.webp&#34;
               width=&#34;431&#34;
               height=&#34;483&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是修改为 192 DPI 的图片，和 96 DPI 相比清晰很多，尤其图片上的文字终于可以正常阅读了：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;19_image_1-DPI-192&#34; srcset=&#34;
               /post/202408-marker-pdf-to-markdown/images/19_image_1-DPI-192_hubf50038fa814f995c7769d0ada0903b3_431683_9a4efdf1b092ca2e6cb52bf49c306cad.webp 400w,
               /post/202408-marker-pdf-to-markdown/images/19_image_1-DPI-192_hubf50038fa814f995c7769d0ada0903b3_431683_bdd65ee3f3f0767095dbbbcef7c9d639.webp 760w,
               /post/202408-marker-pdf-to-markdown/images/19_image_1-DPI-192_hubf50038fa814f995c7769d0ada0903b3_431683_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202408-marker-pdf-to-markdown/images/19_image_1-DPI-192_hubf50038fa814f995c7769d0ada0903b3_431683_9a4efdf1b092ca2e6cb52bf49c306cad.webp&#34;
               width=&#34;678&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PAGINATE_OUTPUT： 分页输出标记符，默认false，尝试设置为 true，会在每一页结束时增加分页符 &lt;code&gt;----------------&lt;/code&gt; 。但因为 pdf 的内容未必每页都独立，有些跨越多页的内容就会被这些分页符分割，反而不美。因此最后我还是放弃了，改回false。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;特别提醒：要修改这些配置，不能直接修改 settings.py 文件，而是要用同名的环境变量覆盖他们。例如：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;IMAGE_DPI&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;192&lt;/span&gt; marker_single ......
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;使用-marker&#34;&gt;使用 marker&lt;/h2&gt;
&lt;h3 id=&#34;gui界面&#34;&gt;&lt;del&gt;GUI界面&lt;/del&gt;&lt;/h3&gt;
&lt;p&gt;marker 自带了一个基于 streamlit 的图形界面，可以交互式地尝试 marker 一些基本的选项。首先安装：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;pip install streamlit
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后执行&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;marker_gui
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;会自动打开浏览器，可以简单的设置少数参数，然后执行转换。但问题是我没有找到获取转换后的 markdown 文件的方式，不知道保存到哪里了。惭愧，放弃GUI，改用命令行吧。&lt;/p&gt;
&lt;h3 id=&#34;命令行&#34;&gt;命令行&lt;/h3&gt;
&lt;p&gt;先尝试转换单个文件，我以从网络上下载的 &lt;code&gt;adobe-photoshop-book-photographers-2nd.pdf&lt;/code&gt; 这个680页的英文 pdf 为例。参数 &lt;code&gt;--max_pages 10&lt;/code&gt; 限制只转换10页，适合用来做快速测试：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;IMAGE_DPI&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;192&lt;/span&gt; marker_single /media/sky/data/study/sky/ebook/photograph/photoshop/2024-adobe-photoshop-book-photographers-2nd/adobe-photoshop-book-photographers-2nd.pdf /media/sky/data/study/sky/ebook/photograph/photoshop/2024-adobe-photoshop-book-photographers-2nd/markdown --batch_multiplier &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; --max_pages &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;surya OCR 支持的语言可以在这里找到：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/VikParuchuri/surya/blob/master/surya/languages.py&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/VikParuchuri/surya/blob/master/surya/languages.py&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;当然，我们通常只需要 English 和 Chinese 两种。&lt;/p&gt;
&lt;p&gt;命令执行的输出如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ &lt;span class=&#34;nv&#34;&gt;IMAGE_DPI&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;192&lt;/span&gt; marker_single /media/sky/data/study/sky/ebook/photograph/photoshop/2024-adobe-photoshop-book-photographers-2nd/adobe-photoshop-book-photographers-2nd.pdf /media/sky/data/study/sky/ebook/photograph/photoshop/2024-adobe-photoshop-book-photographers-2nd/markdown --batch_multiplier &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; --max_pages &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded detection model vikp/surya_det3 on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded detection model vikp/surya_layout3 on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded reading order model vikp/surya_order on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded recognition model vikp/surya_rec2 on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded texify model to cuda with torch.float16 dtype
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Detecting bboxes: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;██████████████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 1/1 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:00&amp;lt;00:00,  1.61it/s&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Recognizing Text: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;██████████████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 1/1 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:03&amp;lt;00:00,  3.01s/it&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Detecting bboxes: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;██████████████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 1/1 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:00&amp;lt;00:00,  1.38it/s&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Finding reading order: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;█████████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 1/1 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:00&amp;lt;00:00,  2.07it/s&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Saved markdown to the /media/sky/data/study/sky/ebook/photograph/photoshop/2024-adobe-photoshop-book-photographers-2nd/markdown/adobe-photoshop-book-photographers-2nd folder
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在目标目录中，会生成以下文件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;adobe-photoshop-book-photographers-2nd.md&lt;/li&gt;
&lt;li&gt;adobe-photoshop-book-photographers-2nd_meta.json&lt;/li&gt;
&lt;li&gt;xxxx.png 图形文件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;继续尝试转换整个 pdf 文件，约680页：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;IMAGE_DPI&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;192&lt;/span&gt; marker_single /media/sky/data/study/sky/ebook/photograph/photoshop/2024-adobe-photoshop-book-photographers-2nd/adobe-photoshop-book-photographers-2nd.pdf /media/sky/data/study/sky/ebook/photograph/photoshop/2024-adobe-photoshop-book-photographers-2nd/markdown --batch_multiplier &lt;span class=&#34;m&#34;&gt;4&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=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ &lt;span class=&#34;nv&#34;&gt;IMAGE_DPI&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;192&lt;/span&gt; marker_single /media/sky/data/study/sky/ebook/photograph/photoshop/2024-adobe-photoshop-book-photographers-2nd/adobe-photoshop-book-photographers-2nd.pdf /media/sky/data/study/sky/ebook/photograph/photoshop/2024-adobe-photoshop-book-photographers-2nd/markdown --batch_multiplier &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded detection model vikp/surya_det3 on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded detection model vikp/surya_layout3 on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded reading order model vikp/surya_order on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded recognition model vikp/surya_rec2 on device cuda with dtype torch.float16
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Loaded texify model to cuda with torch.float16 dtype
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Detecting bboxes: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;█████████████████████████████████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 25/25 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:20&amp;lt;00:00,  1.23it/s&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Recognizing Text: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;██████████████████████████████████████████████████████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 1/1 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:00&amp;lt;00:00,  1.43it/s&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Detecting bboxes: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;████████████████████████████████████████████████████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 17/17 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:29&amp;lt;00:00,  1.75s/it&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Finding reading order: 100%&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;███████████████████████████████████████████████████████████████████████████████████████████████████████&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; 17/17 &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;00:16&amp;lt;00:00,  1.03it/s&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Saved markdown to the /media/sky/data/study/sky/ebook/photograph/photoshop/2024-adobe-photoshop-book-photographers-2nd/markdown/adobe-photoshop-book-photographers-2nd folder
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;转换后的内容整理&#34;&gt;转换后的内容整理&lt;/h3&gt;
&lt;p&gt;转换之后的 markdown 文件包含整个 pdf 文件的内容，非常巨大。而所有的图片都简单的堆放在一起，比较乱。&lt;/p&gt;
&lt;p&gt;可以稍微整理一下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;将图片放入 images 目录&lt;/p&gt;
&lt;p&gt;这样的好处是图片文件和 markdown 文件不至于混在一起不好查看。&lt;/p&gt;
&lt;p&gt;步骤：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新建 images 目录，将所有的 png 文件都移动进去&lt;/li&gt;
&lt;li&gt;用文本编辑器打开 markdown 文件，将所有的 &lt;code&gt;.png](&lt;/code&gt; 替换为 &lt;code&gt;.png](./images/&lt;/code&gt;，修复图片路径&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;清理 markdown 文件中不需要的内容&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;内容导航页面：转成 markdown 之后页数已经没有意义&lt;/li&gt;
&lt;li&gt;以及书籍最后的 index 部分：这部分倒是适合用 pdf 查看，因为可以导航到相关的页面&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;按照章节拆分 markdown 文件&lt;/p&gt;
&lt;p&gt;开始是手工编辑的，后来发现比较累，查找/复制/粘贴重复工作，后面就写了一个简单的 bash 脚本来帮我完成。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;结论&#34;&gt;结论&lt;/h2&gt;
&lt;p&gt;从我的实际使用上看，marker 转换后的 markdown 内容已经很不错了，和 pdf 相比还原度很高。虽然还有一些小的瑕疵需要手工修复，但整体效果是非常不错的，非常推荐使用。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译] 你想知道的关于 actor 模型但可能不敢问的所有信息</title>
      <link>https://skyao.net/post/202206-the-actor-model-everything-you-wanted-to-know/</link>
      <pubDate>Mon, 13 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202206-the-actor-model-everything-you-wanted-to-know/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;译者注：关于 actor 模型，有一个非常赞的视频（2012年），以及一篇和这个视频相关的文章（2016年），但我搜索了一下没有发现中文版本。因此在仔细学习的过程中顺手翻译了一下，希望可以对后面的同学稍有帮助。&lt;/p&gt;
&lt;p&gt;原视频地址： &lt;a href=&#34;https://www.youtube.com/watch?v=7erJ1DV_Tlo&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Hewitt, Meijer and Szyperski: The Actor Model (everything you wanted to know&amp;hellip;) - YouTube&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;原文请见： &lt;a href=&#34;https://alex-karaberov.medium.com/everything-you-always-wanted-to-know-about-the-actor-model-but-were-afraid-to-ask-b6eee8722953&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Everything you wanted to know about the Actor Model but might have been afraid to ask&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在这篇博客文章中，我想阐述 Actor 模型的基本方面。 希望这篇技术文章能帮助你理解 actor 模型背后的关键思想及其主要前提，正如 &lt;a href=&#34;https://en.wikipedia.org/wiki/Carl_Hewitt&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Carl E. Hewitt 教授&lt;/a&gt; 的 &lt;a href=&#34;https://arxiv.org/pdf/1008.1459.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;开创性论文&lt;/a&gt; 中所说的那样。 本文的另一个参考资料是 Hewitt 和 Baker 的一篇名为 &lt;a href=&#34;https://dspace.mit.edu/bitstream/handle/1721.1/41962/AI_WP_134A.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Laws for Communicating Parallel Processes &lt;/a&gt;的论文，其中介绍了 Actor 模型的数学框架和定律。&lt;/p&gt;
&lt;p&gt;&lt;em&gt;UPD：Carl E. Hewitt教授&lt;/em&gt; &lt;a href=&#34;https://news.ycombinator.com/item?id=21857763&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;em&gt;赞许这篇文章&lt;/em&gt;&lt;/a&gt; **&lt;/p&gt;
&lt;p&gt;我不想用有关特定实现的复杂细节的信息淹没您，例如 Erlang/Elixir 进程或 Akka Actor。 此外，尽管听起来可能有争议，但我不知道有任何主流工业技术或编程语言实现了 &lt;strong&gt;纯&lt;/strong&gt; Actor 模型而与原始模型没有细微的差异。 因此，这里的目标是提出抽象标准并描述 Actor 模型的 &lt;em&gt;概念规范&lt;/em&gt;。 请注意，尽管我努力做到尽可能严谨，但不要将本文视为任何形式的论文。&lt;/p&gt;
&lt;p&gt;现在，事不宜迟，让我们开始吧。&lt;/p&gt;
&lt;p&gt;Actor模型是一种计算的数学理论，基于 &lt;strong&gt;Actors&lt;/strong&gt; 的概念。 Actor是计算的基本单元，它体现为三件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;信息处理（计算）。&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;存储（状态）&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通信&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Actors 是模型中的基础而&lt;strong&gt;唯一&lt;/strong&gt;的对象，因此 &lt;em&gt;一切都是 actor&lt;/em&gt;。 系统不可能只有一个 actor，因为 actor 必须与其他 actor 进行&lt;strong&gt;通讯&lt;/strong&gt;。 Actors 的相互交互是&lt;em&gt;仅&lt;/em&gt;由一个 Actor 向另一个 Actor 发送 &lt;strong&gt;messenger&lt;/strong&gt; （message），它也是一个 &lt;em&gt;Actor&lt;/em&gt;。 Message 和 messenger 是可以完全互换的概念，我将同时使用它们。&lt;/p&gt;
&lt;p&gt;也许你已经注意到 Actor 模型和纯面向对象编程之间的相似之处，即一切都是对象，发送消息，局部可变状态。 但有一个重要的区别需要考虑 - actor 之间的边界是不可变的，也就是说，一个 actor 不能将可修改的引用传递给另一个 actor 或以某种方式修改另一个 actor 的状态。 Actor &lt;strong&gt;只能&lt;/strong&gt; 发送消息。 Actors 是独立的实体，其模型不将它们限制为进程或线程，它们具有跨进程、管道、机器进行通信的能力。 因此，仅概括一下——OOP 对行为和状态进行建模，而 Actor 模型对计算进行建模，并且是一种精确、完整、正式定义的理论，而不是 OOP。&lt;/p&gt;
&lt;p&gt;向其发送信使（messenger）的 actor 称为 &lt;strong&gt;target&lt;/strong&gt;。 因此，在这种计算模型中唯一的一种&lt;em&gt;事件&lt;/em&gt;是目标（target）接收到信使（messenger）。 &lt;strong&gt;事件&lt;/strong&gt; 是 actor 计算的持续历史中的离散步骤；它们是 actor 理论的基本交互。 每个事件 &lt;strong&gt;E&lt;/strong&gt; 都由 &lt;strong&gt;message(E)&lt;/strong&gt; 组成，被称为 &lt;strong&gt;target(E)&lt;/strong&gt; 的目标（接收者）接收。 术语基于论文 &lt;a href=&#34;https://dspace.mit.edu/bitstream/handle/1721.1/41962/AI_WP_134A.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Laws for Communicating Parallel Processes&lt;/a&gt; （Hewitt 和 Baker）。&lt;/p&gt;
&lt;p&gt;收到消息后，目标 actor 通过向其他 actor 发送消息来揭示 &lt;strong&gt;行为&lt;/strong&gt;。 Actor 可以由另一个 actor 创建，作为第二个 actor 行为的一部分。 事实上，几乎每个信使 actor（消息）都是在发送到目标 actor 之前新创建的。 对于每个 actor &lt;em&gt;X&lt;/em&gt;，我们将要求有一个独特的事件 &lt;em&gt;Birth(X)&lt;/em&gt; ，其中 &lt;em&gt;X&lt;/em&gt; 首先出现。 更准确地说， &lt;em&gt;Birth（X）&lt;/em&gt; 具有该性质，如果 &lt;em&gt;X&lt;/em&gt; 是另一个事件 &lt;strong&gt;E&lt;/strong&gt; 的参与者，则 &lt;em&gt;Birth（X）→&lt;/em&gt; &lt;strong&gt;E&lt;/strong&gt;，其中→是事件的二元关系， 这意味着事件的部分排序。 形式上，它将是 Actor 模型中的激活顺序和事件到达顺序的并集的 &lt;a href=&#34;https://en.wikipedia.org/wiki/Transitive_closure&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;传递闭包&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;每个 actor 都有 &lt;strong&gt;地址（address）&lt;/strong&gt;。 在各种实现中，地址可以是直接物理地址，例如 NIC 的 MAC 地址、内存地址或仅仅是进程标识符 （PID）。 多个 actor 可以有相同的地址，一个 actor 可以有多个地址。 这里有一个 &lt;em&gt;多对多&lt;/em&gt; 的关系。 地址 &lt;strong&gt;不是&lt;/strong&gt; actor 的唯一标识符。 Actor 没有身份，只有地址。 因此，当我们退后一步，看看我们的概念 Actor 模型时，我们只能看到并使用地址。 即使我们有一个地址，我们也无法判断我们是有一个 actor 还是有多个 actor ，因为这个地址可以是 actor 分组的代理。 我们对地址所能做的就是向它发送消息。 Address 代表 Actor 模型中的 &lt;em&gt;能力&lt;/em&gt;。 地址和 actor 的映射不是概念 actor 模型的一部分，尽管它是实现的一个特征。&lt;/p&gt;
&lt;p&gt;Actor 可以向自己发送消息（递归支持），他们将在以后的步骤中接收和处理这些消息。 此外，actor &lt;em&gt;可能&lt;/em&gt; 有一个邮箱（mailbox）。 &lt;strong&gt;邮箱（Mailbox）&lt;/strong&gt; 是 actor（请记住： &lt;em&gt;一切都是 actor&lt;/em&gt;），它表示消息的目的地。 Actor 不需要邮箱，因为如果 Actor 需要有邮箱，那么邮箱将是一个需要拥有自己的邮箱的 Actor，我们最终会得到无限递归。&lt;/p&gt;
&lt;p&gt;Actor模型中存在两个 &lt;strong&gt;局部性公理&lt;/strong&gt; ，包括 &lt;strong&gt;组织（Organisational）&lt;/strong&gt; 和 &lt;strong&gt;操作（Operational）&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;组织（Organisational）:&lt;/strong&gt; 响应收到的消息，Actor &lt;strong&gt;只能&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;产生有限数量的新 actor。&lt;/li&gt;
&lt;li&gt;&lt;em&gt;仅&lt;/em&gt;将消息发送到刚刚收到的消息中的地址或其本地存储中的地址。&lt;/li&gt;
&lt;li&gt;为下一条消息更新其本地存储（指定如何处理下一条消息）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;组织（Organisational）：&lt;/strong&gt; Actor 的本地存储包括的地址&lt;strong&gt;只能是&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在创建时提供的&lt;/li&gt;
&lt;li&gt;在消息中收到的&lt;/li&gt;
&lt;li&gt;适用于此处创建的 Actors（操作公理的第 1 段）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;从概念上讲，actor 按顺序处理来自其邮箱的传入消息，一次处理一个消息，但物理实现始终以某种方式优化或管道消息处理。 Actor 模型没有为消息传递和处理提供许多保证。 不同的物理实现可以自由地添加有趣的功能，例如消息模式匹配或 在 Erlang 中&lt;a href=&#34;http://ndpar.blogspot.com/2010/11/erlang-explained-selective-receive.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;选择性接收&lt;/a&gt; 排队消息中不匹配的消息，以便以后处理和管理超时。&lt;/p&gt;
&lt;p&gt;Actor 模型还支持 &lt;strong&gt;委派（delegation）&lt;/strong&gt;，因为 actor 可以在消息中发送其他 actor 的地址（在 Erlang 中，这些是 PID）。&lt;/p&gt;
&lt;p&gt;正如我之前已经提到的，Actor 可以向自己发送消息（递归），为了避免死锁，我们在 Actor 模型中有一个 &lt;strong&gt;future&lt;/strong&gt; 的概念。 Future 的想法是，你可以创建一个 actor ，在它仍然在计算时得到结果。 &lt;strong&gt;Future&lt;/strong&gt; 是一种特殊的消息类型，它表示（可能很长的）计算或事件（向目标发送消息的结果）的“未来（future）”值。 Actor 可以将 future 传递给其他 Actor，他们也可以将 future 发送给自己。 是的，这些与我们现在在 JavaScript 或 Scala 等主流编程语言中拥有的 &lt;strong&gt;future&lt;/strong&gt; 相同。 Future 的概念于 1977 年首次出现在 Actor 模型中（Carl Hewitt 和 Baker 的&lt;a href=&#34;https://dl.acm.org/citation.cfm?id=806932&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;“进程的增量垃圾收集”&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;消息传递没有顺序保证，并且可以丢弃消息（例如，如果在发送信使之前 Actor 被销毁），因此我们有 &lt;a href=&#34;https://en.wikipedia.org/wiki/Best-effort_delivery&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;尽最大努力的传递&lt;/a&gt;。 消息可以持久化（Actor 定义的第 2 段： &lt;em&gt;storage&lt;/em&gt;）并且可以重新发送。 消息&lt;strong&gt;最多&lt;/strong&gt;可以传递 一次（一次或零次）。 快速到达的消息可能会导致 actor 出现某种拒绝服务，从而使 actor 无法处理传入的消息流。 为了缓解这个问题，存在一个邮箱 actor 接收信使并持有这些信使，直到 actor 能够处理它们。 消息可能需要任意长的时间才能最终到达接收方的邮箱。 在 Actor 模型的物理实现中，邮箱中消息的入队和出队是原子操作，因此不可能出现争用情况。&lt;/p&gt;
&lt;p&gt;Actor 具有自己的状态或存储这一事实意味着额外的期望要求，特别是 actor 应具有固有的持久性，除非不再可访问。 因此，Actor 系统应该根据它拥有的记录来恢复 Actor。 我们可以将此属性称为“actor 的存储持久性”。 这里的持久性是一个程度问题。 最低是记录在 RAM 中。 接下来是持久性本地存储（本地数据库服务器等）。 之后是其他机器上的存储，可以表示为由分布式数据库支持的复制日志（日志）。 此属性的一个有趣的物理实现是 &lt;a href=&#34;https://doc.akka.io/docs/akka/2.4/scala/persistence.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Akka Persistence&lt;/a&gt;。 &lt;strong&gt;Akka persistence&lt;/strong&gt; 使有状态的 Actor 能够持久化其内部状态，以便在 Actor 启动、JVM 崩溃后重新启动、由 supervisor 重新启动或在集群中迁移时恢复。 Akka 持久性背后的关键概念是，只保留对 actor 内部状态的更改，但从不直接保留其当前状态（可选快照除外）。&lt;/p&gt;
&lt;p&gt;Actor 之间没有 channel 或任何其他类型的中介。 我们将消息 &lt;em&gt;直接&lt;/em&gt; 发送给 actor 。 当然，我们可以通过带有“put”和“get”信使的 actor 来实现通道，但这根本不是必需的。&lt;/p&gt;
&lt;p&gt;Actor 模型中的计算被认为是分布在空间中的，其中称为 Actor 的计算设备使用 Actor 的地址进行异步通信，并且整个计算不处于任何明确定义的状态。&lt;/p&gt;
&lt;p&gt;Actor 的本地状态是在收到消息时定义的，在其他时间可能是不确定的。 使用 Actor 模型，您将拥有一个基于配置的计算模型。 该模型的基础是接收到的消息，其本质上是动态的，而不是固定的。&lt;/p&gt;
&lt;p&gt;您可能已经注意到，Actor 模型在设计和定义上都是可扩展的。 这种固有的可扩展性意味着，在不久的将来（根据 Hewitt 的 &lt;a href=&#34;https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3428114&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2025年可重用可扩展智能系统 &lt;/a&gt;），我们可以在具有数百万个 Actor 内核的计算机盒子上观察到 Actor 模式的物理实现，平均10纳秒延迟消息在千万亿 Actor 之间传递。&lt;/p&gt;
&lt;p&gt;在 Actor 模型中还存在 &lt;strong&gt;仲裁者（Arbiter）&lt;/strong&gt; 的概念。 &lt;a href=&#34;https://en.wikipedia.org/wiki/Arbiter_%28electronics%29&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;仲裁者&lt;/a&gt; 为我们提供了 &lt;a href=&#34;https://en.wikipedia.org/wiki/Indeterminacy_in_concurrent_computation&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;不确定性&lt;/a&gt;。 根据 Hewitt 的论文 &lt;a href=&#34;https://papers.ssrn.com/sol3/papers.cfm?abstract_id=3459566&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Physical Indeterinacy in Digital Computation&lt;/a&gt; ，仲裁者实现了 actor 的不确定性。 通常，Actor 处理消息的顺序所观察到的细节会影响结果。 我们没有观察 Actor 计算仲裁过程的内部细节，而是等待结果。 仲裁者的不确定性会在 Actor 系统中产生不确定性。 这些仲裁者实际上类似于电子 &lt;a href=&#34;https://en.wikipedia.org/wiki/Arbiter_%28electronics%29&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;仲裁者&lt;/a&gt; 。 给定一个仲裁者，您可以同时将多个输入（例如 Input1，Input2）输入仲裁者，但 &lt;em&gt;只有&lt;/em&gt; 一个可能的结果（Output1或Exput2）将出现在另一端。 从概念上讲，仲裁者是某种具有逻辑门的电路，它可以基于 &lt;a href=&#34;https://en.wikipedia.org/wiki/NAND_logic&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;NAND逻辑&lt;/a&gt; （例如XNOR，NAND和NOT）。 这些门需要合适的阈值和其他参数。&lt;/p&gt;
&lt;p&gt;在仲裁者启动后，它可以在最终断言 Output1 或 Output2 之前，在不受限制的时间段内保持 &lt;a href=&#34;https://en.wikipedia.org/wiki/Metastability_in_electronics&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;元稳定&lt;/a&gt; 状态。 但是仲裁者尚未决定的概率随着时间的推移呈指数下降。 仲裁者的内部流程不是公开流程，而是“黑匣子”。 试图观察它们会影响它们的结果。 我们必须等待结果，而不是观察仲裁过程的内部。&lt;/p&gt;
&lt;p&gt;仲裁者是一个非常方便和实用的理论框架，引入它是为了能够推理或描述当我们有多个消息发送给同一个 actor 时发生的事情。 抽象地，仲裁者本身“决定”传入消息的顺序。 然而，真实可感知世界的一个标志是单个抽象概念的各种物理 &lt;a href=&#34;https://en.wikipedia.org/wiki/Instantiation_principle&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;实例化&lt;/a&gt; ，因此可能有很多仲裁者的实例或示例 - CPU时钟生成器，Linux内核计时器飞轮， &lt;a href=&#34;https://www.kernel.org/doc/html/latest/scheduler/sched-design-CFS.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;CFS&lt;/a&gt;，由垃圾回收引起的不可预测的暂停， 操作系统级暂停以解决主要页面故障，无数 &lt;a href=&#34;https://queue.acm.org/detail.cfm?id=2655736&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;网络故障&lt;/a&gt;，CPU交叉调用和TLB关闭等等。&lt;/p&gt;
&lt;p&gt;我们可以将 Erlang VM 视为一个具体的示例。 Erlang 消息传递的语义指出，每当两个进程分别向第三个进程发送一条消息，并且对单个发送事件没有排序约束时，我们永远不能依赖哪条消息将首先出现在接收方的邮箱中。 即使所有进程都在同一个 Erlang VM 中运行，它们也可能被任意延迟。 如果发送方位于不同的调度程序线程上，则可能会发生这种情况。 发送操作可以按一个顺序（挂钟时间）完成，但消息仍可能以交换顺序到达接收者的邮箱。 如果我们运行分布式 Erlang，甚至会发生更多的事情。 例如，Actor 通过拥塞网络向不同子网中的另一个 Actor 发送消息，该网络遭受 &lt;a href=&#34;https://www.usenix.org/system/files/login/articles/chen12-06.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;TCP&lt;/a&gt; 或 &lt;a href=&#34;https://www.usenix.org/legacy/events/nsdi05/tech/feamster/feamster.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;BGP 故障&lt;/a&gt;。 揭穿一个潜在的误解——在 Erlang 中，消息排序只在一个进程中得到保证。 也就是说，如果有一个实时进程，我们向它发送一条消息A，然后发送一条消息B，那么可以保证如果消息B到达，消息A已经到达它之前。&lt;/p&gt;
&lt;p&gt;为了总结上述内容，我们可以假设 Actor 模型中的不确定性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;由数字计算实现&lt;/li&gt;
&lt;li&gt;可能涉及与外部 Actor 的通信&lt;/li&gt;
&lt;li&gt;无限的不确定性：总是可以停止但需要无限的时间。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;实际上，Actor Model 是一个非常抽象的概念模型，因此任何基于上述局部性公理的实现都是合理的。&lt;/p&gt;
&lt;p&gt;为了建立一个类比，我们可以假设 actor 模型类似于 &lt;a href=&#34;https://ncatlab.org/nlab/show/category&amp;#43;theory&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;范畴论&lt;/a&gt; 计算。 范畴理论也是抽象的、最小的，并且专注于对象之间的相互作用，例如态射、函子、自然变换、 &lt;a href=&#34;https://ncatlab.org/nlab/show/transfor&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;变换&lt;/a&gt; ，而不描述对象本身的性质和内部结构。&lt;/p&gt;
&lt;p&gt;我不擅长总结，因此我将用 Robin Milner 的“交互元素：图灵奖讲座”中的一句话来结束：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;现在，纯粹的 lambda 演算只用两种东西构建：术语和变量。 我们可以为过程演算实现相同的经济性吗？ Carl Hewitt 凭借他的 actor 模型，很久以前就应对了这一挑战。他声明值、值操作符和过程都应该是同一种东西：Actor。 这个目标给我留下了深刻的印象，因为它暗示了表达的同质性和完整性 …&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>[译] Dapr 工作流提案</title>
      <link>https://skyao.net/post/202206-dapr-workflow-proposal/</link>
      <pubDate>Thu, 02 Jun 2022 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202206-dapr-workflow-proposal/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;译者注：Dapr 最近提出了一个新的提案，计划在 Dapr Runtime 中构建工作流引擎，社区反映非常积极。由于提案内容比较长，因此翻译过来以帮助阅读。原文和社区讨论请见： &lt;a href=&#34;https://github.com/dapr/dapr/issues/4576&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/dapr/dapr/issues/4576&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文档建议扩展 Dapr 运行时以包含新的工作流构建块。 此构建基与轻量级、可移植的工作流引擎相结合，将使开发人员能够将工作流表达为可以使用 Dapr 运行时执行、交互、监视和调试的代码块&lt;/p&gt;
&lt;h2 id=&#34;为什么使用它&#34;&gt;为什么使用它？&lt;/h2&gt;
&lt;p&gt;许多复杂的业务流程被很好地建模为 &lt;em&gt;工作流&lt;/em&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;li&gt;弹性&lt;/li&gt;
&lt;li&gt;故障处理机制&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;根据可用数据，很明显，工作流程非常受欢迎。在撰写本文时，在数以万计的 Azure 订阅中，托管工作流及其任务的每日执行次数为每天数十亿次。&lt;/p&gt;
&lt;h2 id=&#34;什么是工作流&#34;&gt;什么是工作流？&lt;/h2&gt;
&lt;p&gt;就本提案而言， &lt;em&gt;workflow&lt;/em&gt; 定义为应用程序逻辑，用于定义以下业务流程或数据流：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;具有特定的、预定义的确定性生命周期（例如，挂起 -&amp;gt; 正在运行 -&amp;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;/li&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;li&gt;可以创建新的子工作流，并可选择等待这些工作流完成，然后再进行&lt;/li&gt;
&lt;li&gt;可能依赖外部组件来执行其作业（即 HTTPS API 调用、发布/订阅消息队列等）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;为什么选择-dapr&#34;&gt;为什么选择 Dapr？&lt;/h2&gt;
&lt;p&gt;Dapr 已经包含许多为工作流的执行提供可靠性、可伸缩性和持久性所需的构建块。 在 Dapr 中构建这样的引擎，并提供必要的构建块，将有助于通过现有功能的可重用性和独立于底层的执行机制来提高开发人员的工作效率，从而提高可移植性。&lt;/p&gt;
&lt;p&gt;除了内置的执行引擎之外，Dapr 还可以为已经使用这些工具的用户提供一致的编程接口，以便与第三方工作流执行系统（即 AWS SWF、Apache Camel、Drools）进行交互。 从而提供了一个标准化的接口，用于处理外部工作流以及在 Dapr 内部运行的工作流。&lt;/p&gt;
&lt;h1 id=&#34;提案&#34;&gt;提案&lt;/h1&gt;
&lt;h2 id=&#34;变更的高级概述&#34;&gt;变更的高级概述&lt;/h2&gt;
&lt;p&gt;我们建议将以下特性/功能添加到 Dapr 运行时：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新的“workflow”构建块&lt;/li&gt;
&lt;li&gt;嵌入到 Dapr sidecar 中的可移植的轻量级工作流引擎，能够通过 Dapr 的构建块支持长时间运行、弹性和持久的工作流&lt;/li&gt;
&lt;li&gt;富有表现力、对开发人员友好的编程模型，用于将 &lt;em&gt;工作流构建为代码&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;支持容器化、声明式工作流（如 CNCF serverless 工作流规范）&lt;/li&gt;
&lt;li&gt;对 Dapr 仪表板的扩展，用于监视/管理工作流执行&lt;/li&gt;
&lt;li&gt;用于与工作流交互的 API&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;工作流构建块&#34;&gt;工作流构建块&lt;/h2&gt;
&lt;p&gt;如前所述，此提案包括添加新的工作流构建块。 与大多数其他 Dapr 构建块（状态存储、pubsub 等）一样，工作流构建基将包含两个主要内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可插拔的组件模型，用于集成各种工作流引擎&lt;/li&gt;
&lt;li&gt;一组 API，用于管理工作流（启动、调度、暂停、恢复、取消）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;与对 actor 的内置支持类似，我们还建议为工作流实现内置运行时（请参阅下一节中介绍的 DTFx-go 引擎）。 与 actor 不同，工作流运行时组件可以替换为替代实现。 如果开发人员想要使用其他工作流引擎，例如外部托管的工作流服务（如 Azure Logic Apps、AWS Step Functions 或 Temporal.io），则可以使用其他社区贡献的工作流组件来实现。&lt;/p&gt;
&lt;p&gt;对于供应商来说，此构建块的价值在于，其平台支持的工作流可以公开为支持 HTTP 和 Dapr SDK 的 API。 MTLS、分布式跟踪等不太明显但很有用处的功能也将可用。 各种抽象（如异步 HTTP 轮询）也可以通过 Dapr 提供支持，而无需工作流供应商自己实现它。&lt;/p&gt;
&lt;h2 id=&#34;dtfx-go-介绍&#34;&gt;DTFx-go 介绍&lt;/h2&gt;
&lt;p&gt;我们建议在 Dapr sidecar 中添加一个轻量级，可移植的嵌入式工作流引擎（DTFx-go），该引擎在其底层实现中利用现有的 Dapr 组件，包括 &lt;em&gt;actor&lt;/em&gt; 和 &lt;em&gt;状态存储&lt;/em&gt;。 由于是轻量级和可移植的，开发人员将能够以最小的开销执行在 DFTx-go 本地以及生产中运行的工作流；这通过将工作流与用户喜欢的现有 Dapr 开发模型相集成来增强开发者体验。&lt;/p&gt;
&lt;p&gt;新引擎将使用 Go 编写，并受到现有 Durable Task Framework (DTFx) 引擎的启发。 我们将这个新版本的框架称为DTFx-go，以区别于.NET实现（这不是本提案的一部分），它将作为一个开源项目存在，具有宽松的许可证，例如Apache 2.0，以便它作为CNCF项目的依赖项保持兼容。 请注意，确保此引擎保持轻量级非常重要，以避免显著增加 Dapr sidecar 的大小。&lt;/p&gt;
&lt;p&gt;重要的是，DTFx-go 不会暴露给应用层。 相反，Dapr sidecar 将通过 gRPC 流公开 DTFx-go 功能。 Dapr sidecar 不会执行任何特定于应用程序的工作流逻辑或加载任何声明性工作流文档。 相反，应用容器将负责托管实际的工作流逻辑。 Dapr sidecar 可以通过 gRPC 向连接的应用程序的工作流逻辑发送和接收工作流命令，代表工作流执行命令（服务调用、调用绑定等）。 其他问题（如激活、横向扩展和状态持久性）将由内部管理的 actor 处理。 关于所有这些的更多细节将在后续章节中讨论。&lt;/p&gt;
&lt;h3 id=&#34;执行调度和弹性&#34;&gt;执行、调度和弹性&lt;/h3&gt;
&lt;p&gt;在内部，Dapr 工作流实例将作为 &lt;strong&gt;actor&lt;/strong&gt;实现。 Actor 通过 gRPC 流与工作流 SDK 通信来驱动工作流执行。 通过使用 actor，我们已经解决了放置和可扩展性的问题。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;placement&#34; srcset=&#34;
               /post/202206-dapr-workflow-proposal/images/placement_hu4855adb841a87afa7e3d342e6fec36fd_47117_ee92742b04dfc3a9040c6a100a060545.webp 400w,
               /post/202206-dapr-workflow-proposal/images/placement_hu4855adb841a87afa7e3d342e6fec36fd_47117_491ee8bc25b4274f87eef3180ebf088c.webp 760w,
               /post/202206-dapr-workflow-proposal/images/placement_hu4855adb841a87afa7e3d342e6fec36fd_47117_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202206-dapr-workflow-proposal/images/placement_hu4855adb841a87afa7e3d342e6fec36fd_47117_ee92742b04dfc3a9040c6a100a060545.webp&#34;
               width=&#34;717&#34;
               height=&#34;364&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;单个工作流的执行将使用 &lt;strong&gt;actor reminder&lt;/strong&gt; 触发，因为它们既是 &lt;em&gt;persistent&lt;/em&gt; 又是 &lt;em&gt;durable&lt;/em&gt; （工作流的两个关键功能）。 如果容器或节点在工作流执行期间崩溃，则 actor 的 reminder 将确保它再次激活并从中断处恢复（使用状态存储来提供持久性，见下文）。&lt;/p&gt;
&lt;p&gt;为了防止工作流（无意中）阻塞，每个工作流将由两个单独的 actor 组成，一个充当调度（scheduler）/协调器（coordinator），另一个执行实际工作（调用API服务，执行计算等）。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;workflow-instance&#34; srcset=&#34;
               /post/202206-dapr-workflow-proposal/images/workflow-instance_hu294d50225f8f71667c9cca7205753ec1_155446_997271a13a01f57de593e90f1a67efc7.webp 400w,
               /post/202206-dapr-workflow-proposal/images/workflow-instance_hu294d50225f8f71667c9cca7205753ec1_155446_39aae381deabc43f44fb742aadc25370.webp 760w,
               /post/202206-dapr-workflow-proposal/images/workflow-instance_hu294d50225f8f71667c9cca7205753ec1_155446_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202206-dapr-workflow-proposal/images/workflow-instance_hu294d50225f8f71667c9cca7205753ec1_155446_997271a13a01f57de593e90f1a67efc7.webp&#34;
               width=&#34;760&#34;
               height=&#34;298&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;状态和持久性的存储&#34;&gt;状态和持久性的存储&lt;/h3&gt;
&lt;p&gt;为了使工作流执行在面对暂时性错误时可靠地完成，它必须是 &lt;em&gt;持久的&lt;/em&gt; - 这意味着它能够在取得进展时在检查点存储数据。 为了实现这一点，工作流执行将依赖于 Dapr 的状态存储来提供稳定的存储，以便在工作流被显式暂停或某个步骤提前终止（系统故障、资源不足等）时，可以从已知状态安全地恢复工作流。&lt;/p&gt;
&lt;h2 id=&#34;工作流即代码&#34;&gt;工作流即代码&lt;/h2&gt;
&lt;p&gt;术语&amp;quot;工作流即代码(workflow as code)&amp;ldquo;是指使用通用编程语言实现工作流逻辑。 “工作流即代码”用于越来越多的新式工作流框架，例如 Azure Durable Functions、Temporal.io 和Prefect (Orion)。 这种方法的优点是它对开发人员友好。 开发人员可以使用他们已经知道的编程语言（无需学习新的DSL或YAML模式），他们可以访问语言的标准库，可以构建自己的库和抽象，可以使用调试器和检查局部变量，甚至可以为他们的工作流编写单元测试，就像他们编写应用程序逻辑的任何其他部分一样。&lt;/p&gt;
&lt;p&gt;Dapr SDK 将与 Dapr sidecar 中的 DTFx-go gRPC 端点进行内部通信，以接收新的工作流事件并发送新的工作流命令，但这些协议详细信息将对开发人员隐藏。 由于工作流协议的复杂性，我们没有为此功能的运行时方面提供任何HTTP API。&lt;/p&gt;
&lt;h2 id=&#34;支持声明式工作流&#34;&gt;支持声明式工作流&lt;/h2&gt;
&lt;p&gt;我们预计工作流作为代码在开发人员中非常受欢迎，因为与声明式工作流建模语言相比，使用代码对于开发人员来说既非常自然，又更具表现力和灵活性。 尽管如此，仍然会有用户更喜欢或要求工作流是声明式的。 为了支持这一点，我们建议将声明式工作流的体验构建为“工作流即代码”基础之上的一个层。 以这种方式可以支持各种声明式工作流。 例如，此模型可用于支持 AWS Step Functions 工作流语法、Azure Logic Apps 工作流语法，甚至 Google Cloud Workflow 语法。 但是，出于此提案的目的，我们将重点介绍支持 CNCF serverless工作流规范的情况。 但请注意，建议的模型可用于支持任意数量的声明式多工作流架构。&lt;/p&gt;
&lt;h3 id=&#34;cncf-serverless工作流&#34;&gt;CNCF serverless工作流&lt;/h3&gt;
&lt;p&gt;Serverless工作流 （SLWF） 由基于开源标准的 DSL 和开发工具组成，用于在 JSON 或 YAML 中创作和验证工作流。 SLWF 被特别选择用于本提案，因为它代表了一种云原生和行业标准的工作流创作方式。 有一组已经存在的开源工具，用于生成和验证这些可以由社区采用的工作流。 它也是 Dapr 的理想选择，因为它位于 CNCF 的保护伞下（目前是一个 sandbox 项目）。 本提案将通过为 SLWF 项目提供轻量级，可移植的运行时（即Dapr sidecar）来支持它。&lt;/p&gt;
&lt;h3 id=&#34;托管-serverless-工作流&#34;&gt;托管 serverless 工作流&lt;/h3&gt;
&lt;p&gt;在本提案中，我们使用 Dapr SDK 来构建一个新的，可移植的 SLWF 运行时，该运行时将使用 Dapr sidecar。 最有可能的是，它被实现为可重用的容器镜像，并支持从 Dapr 状态存储加载工作流定义文件（需要确定确切的细节）。 请注意，Dapr sidecar 不会加载任何工作流定义。 相反，sidecar 只是驱动工作流的执行，将所有其他细节留给应用层。&lt;/p&gt;
&lt;h2 id=&#34;api&#34;&gt;API&lt;/h2&gt;
&lt;h3 id=&#34;启动工作流-api&#34;&gt;启动工作流 API&lt;/h3&gt;
&lt;h4 id=&#34;http--grpc&#34;&gt;HTTP / gRPC&lt;/h4&gt;
&lt;p&gt;开发人员可以通过向 Dapr sidecar 发出 HTTP（或 gRPC）API 调用来启动工作流实例：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;POST http://localhost:3500/v1.0/workflows/{workflowType}/{instanceId}/start&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;假定工作流具有由 {workflowType} 参数标识的类型。 还必须使用唯一的 {instanceId} 值创建每个工作流实例。 请求的有效负载是工作流的输入。 如果已存在具有此 ID 的工作流实例，则此调用将失败，并显示 HTTP 409 Conflict。&lt;/p&gt;
&lt;p&gt;为了支持 HTTP 客户端的异步 HTTP 轮询模式，此 API 将返回 HTTP 202 Accepted 响应，其 Location 标头包含可用于获取工作流状态的 URL（请参阅下面的进一步操作）。 工作流完成后，此端点将返回 HTTP 200 响应。 如果失败，端点可以返回 4XX 或 5XX 错误 HTTP 响应代码。 其中一些详细信息可能需要可配置，因为没有用于异步 API 处理的通用协议。&lt;/p&gt;
&lt;h4 id=&#34;input-bindings&#34;&gt;Input bindings&lt;/h4&gt;
&lt;p&gt;对于某些类型的自动化场景，直接从 Dapr input bindings 触发新的工作流实例可能很有用。 例如，使用 Twitter input binding 触发工作流以响应来自特定用户帐户的推文可能很有用。 另一个例子是启动一个新的工作流来响应 Kubernetes 事件，如 deployment 创建事件。&lt;/p&gt;
&lt;p&gt;工作流的实例 ID 和输入负载取决于 input binding 的配置。 例如，用户可能希望使用 Tweet 的唯一 ID 或 Kubernetes deployment 的名称作为 instance ID。&lt;/p&gt;
&lt;h4 id=&#34;pubsub&#34;&gt;Pub/Sub&lt;/h4&gt;
&lt;p&gt;工作流也可以直接从 pub/sub 事件启动，类似于 Actor pub/sub 的提案。 Pub/sub 主题的配置可用于标识用于初始化工作流的相应 instance ID 和输入工作负载。 在最简单的情况下，cloud event 消息的 source + ID 可用作工作流的 instance ID。&lt;/p&gt;
&lt;h3 id=&#34;终止工作流-api&#34;&gt;终止工作流 API&lt;/h3&gt;
&lt;h4 id=&#34;http--grpc-1&#34;&gt;HTTP / gRPC&lt;/h4&gt;
&lt;p&gt;工作流实例也可以使用显式 API 调用来终止：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;POST http://localhost:3500/v1.0/workflows/{workflowType}/{instanceId}/terminate&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;工作流终止主要是服务运维人员在需要取消特定业务流程时，或者工作流出现问题需要停止以减轻对其他服务的影响时执行的操作。&lt;/p&gt;
&lt;p&gt;如果 POST 请求中包含有效负载，则该有效负载将另存为工作流实例的输出。&lt;/p&gt;
&lt;h3 id=&#34;发起事件-api&#34;&gt;发起事件 API&lt;/h3&gt;
&lt;p&gt;当工作流可以等待外部事件并由外部事件驱动时，它们特别有用。 例如，工作流可以订阅 pubsub 主题中的事件，如电话验证示例中所示。 但是，此功能不应仅限于 pub/sub 事件。&lt;/p&gt;
&lt;h4 id=&#34;http--grpc-2&#34;&gt;HTTP / gRPC&lt;/h4&gt;
&lt;p&gt;应该存在用于将事件直接发布到工作流实例的 API：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;POST http://localhost:3500/v1.0/workflows/{workflowType}/{instanceId}/raiseEvent&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;“发起事件”API 的结果是 HTTP 202 Accepted，表示事件已收到但可能尚未处理。 工作流可以使用 waitForExternalEvent SDK 方法使用外部事件。&lt;/p&gt;
&lt;h3 id=&#34;获取工作流元数据-api&#34;&gt;获取工作流元数据 API&lt;/h3&gt;
&lt;h4 id=&#34;http--grpc-3&#34;&gt;HTTP / gRPC&lt;/h4&gt;
&lt;p&gt;用户可以使用显式 API 调用提取工作流实例的元数据：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GET http://localhost:3500/v1.0/workflows/{workflowType}/{instanceId}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;此调用的结果是工作流实例元数据，例如其开始时间、运行时状态、完成时间（如果已完成）以及自定义或特定于运行时的状态。 如果目标运行时支持，则还可以使用查询 API 提取工作流输入和输出。&lt;/p&gt;
&lt;h3 id=&#34;清除工作流元数据-api&#34;&gt;清除工作流元数据 API&lt;/h3&gt;
&lt;p&gt;用户可以使用以下 API 删除与工作流关联的所有状态：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;DELETE http://localhost:3500/v1.0/workflows/{workflowType}/{instanceId}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;使用嵌入式工作流组件时，这将删除工作流的底层 actor 存储的所有状态。&lt;/p&gt;
&lt;h1 id=&#34;脚注和示例&#34;&gt;脚注和示例&lt;/h1&gt;
&lt;h2 id=&#34;示例-1银行交易&#34;&gt;示例 1：银行交易&lt;/h2&gt;
&lt;p&gt;在此示例中，工作流实现为 JavaScript 生成器函数。 “bank1”和“bank2”参数是使用 Dapr 的微服务应用，每个应用都公开“ withdraw（提款）”和“ deposit（存款）”API。 工作流可用的 Dapr API 来自于上下文参数对象，并返回一个 &amp;ldquo;任务&amp;rdquo;，这实际上与 Promise 相同。 对任务调用 yield 会导致工作流持久检查其进度，并等待 Dapr 使用服务方法的输出进行响应。 任务的值就是服务调用的结果。 如果任何服务方法调用因错误而失败，则该错误将作为引发的 JavaScript 错误浮现出来，可以使用正常的 try/catch 语法捕获该错误。 此代码也可以使用 Node.js 调试器进行调试。&lt;/p&gt;
&lt;p&gt;请注意，有关如何编写代码的详细信息将因语言而异。 例如，C# SDK 将允许开发人员使用 async/await 而不是 yield。 无论语言细节如何，核心功能在所有语言中都是相同的。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;DaprWorkflowClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;DaprWorkflowContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;HttpMethod&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;dapr-client&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;daprHost&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;process&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;DAPR_HOST&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Dapr sidecar host 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;daprPort&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;process&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;DAPR_WF_PORT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;50001&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// Dapr sidecar port for workflow 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;workflowClient&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;DaprWorkflowClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;daprHost&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;daprPort&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Funds transfer workflow which receives a context object from Dapr and an input 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;workflowClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addWorkflow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;transfer-funds-workflow&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;DaprWorkflowContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;op&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;any&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// use built-in methods for generating psuedo-random data in a workflow-safe way 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;transactionId&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;createV5uuid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// try to withdraw funds from the source account. 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;success&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;yield&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;invoker&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;invoke&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;bank1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;withdraw&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;HttpMethod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;POST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;srcAccount&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;op&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;srcAccount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;amount&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;op&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;amount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;transactionId&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;success&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;success&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Insufficient funds&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;try&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// attempt to deposit into the dest account, which is part of a separate microservice app 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;k&#34;&gt;yield&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;invoker&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;invoke&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;bank2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;deposit&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;HttpMethod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;POST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nx&#34;&gt;destAccount&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;op&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;destAccount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nx&#34;&gt;amount&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;op&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;amount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nx&#34;&gt;transactionId&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;success&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;catch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// compensate for failures by returning the funds to the original account 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;k&#34;&gt;yield&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;invoker&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;invoke&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;bank1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;deposit&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;HttpMethod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;POST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nx&#34;&gt;destAccount&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;op&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;srcAccount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nx&#34;&gt;amount&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;op&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;amount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nx&#34;&gt;transactionId&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;failure&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Call start() to start processing workflow events 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;workflowClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;示例-2电话验证&#34;&gt;示例 2：电话验证&lt;/h2&gt;
&lt;p&gt;下面是另一个示例，演示开发人员如何构建短信电话验证工作流。 工作流接收某个用户的电话号码，创建一个验证码，将验证码传送到用户的 SMS 号码，并等待用户以正确的验证码进行响应。&lt;/p&gt;
&lt;p&gt;重要的一点是，端到端工作流可以表示为单个易于理解的函数。 状态（如验证码）可以简单地存储在本地变量中，而不是直接依靠 actor 来显式保存状态，从而大大降低了整体代码的复杂性，并使解决方案易于进行单元测试。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;DaprWorkflowClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;DaprWorkflowContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;HttpMethod&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;dapr-client&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;daprHost&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;process&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;DAPR_HOST&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;127.0.0.1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// Dapr sidecar host 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;daprPort&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;process&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;DAPR_WF_PORT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;50001&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// Dapr sidecar port for workflow 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;workflowClient&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;DaprWorkflowClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;daprHost&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;daprPort&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Phone number verification workflow which receives a context object from Dapr and an input 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;workflowClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;addWorkflow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;phone-verification&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;DaprWorkflowContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;phoneNumber&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Create a challenge code and send a notification to the user&amp;#39;s phone 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;challengeCode&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;yield&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;invoker&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;invoke&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;authService&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;createSmsChallenge&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;HttpMethod&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;POST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;phoneNumber&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Schedule a durable timer for some future date (e.g. 5 minutes or perhaps even 24 hours from now) 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;expirationTimer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;createTimer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;challengeCode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;expiration&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// The user gets three tries to respond with the right challenge code 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;authenticated&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// subscribe to the event representing the user challenge response 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;responseTask&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pubsub&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;subscribeOnce&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;my-pubsub-component&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sms-challenge-topic&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// block the workflow until either the timeout expires or we get a response event 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;winner&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;yield&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;whenAny&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;([&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;expirationTimer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;responseTask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]);&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;winner&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;expirationTimer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// timeout expired 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// we get a pubsub event with the user&amp;#39;s SMS challenge response 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;responseTask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;challengeNumber&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;===&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;challengeCode&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nx&#34;&gt;authenticated&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// challenge verified! 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;            &lt;span class=&#34;nx&#34;&gt;expirationTimer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;cancel&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 返回值可以作为工作流状态的一部分。 或者，我们可以发送通知。 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;authenticated&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 调用 listen() 开始处理工作流事件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;workflowClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;listen&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;示例-3用于监测患者生命体征的声明式工作流&#34;&gt;示例 3：用于监测患者生命体征的声明式工作流&lt;/h2&gt;
&lt;p&gt;下面是一个非常简单的 SLWF 工作流定义的例子，它监听三种不同的事件类型并根据收到的事件调用函数。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;id&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;monitorPatientVitalsWorkflow&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;version&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;1.0&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Monitor Patient Vitals Workflow&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;states&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Monitor Vitals&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;event&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;onEvents&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nt&#34;&gt;&amp;#34;eventRefs&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;s2&#34;&gt;&amp;#34;High Body Temp Event&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;s2&#34;&gt;&amp;#34;High Blood Pressure Event&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nt&#34;&gt;&amp;#34;actions&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[{&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;functionRef&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Invoke Dispatch Nurse Function&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}]&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nt&#34;&gt;&amp;#34;eventRefs&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;High Respiration Rate Event&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nt&#34;&gt;&amp;#34;actions&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[{&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;functionRef&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Invoke Dispatch Pulmonologist Function&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}]&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nt&#34;&gt;&amp;#34;end&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;functions&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;file://my/services/asyncapipatientservicedefs.json&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nt&#34;&gt;&amp;#34;events&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;file://my/events/patientcloudeventsdefs.yml&amp;#34;&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;此工作流中定义的函数将映射到 Dapr 服务调用。 同样，这些事件将映射到传入的 Dapr pub/sub 事件。 在幕后，运行时（使用前面提到的 Dapr SDK APIs 构建）处理与 Dapr sidecar 的通信，后者反过来管理状态的检查点和工作流的恢复语义。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Dapr 官方文档中文翻译 v1.5 版本正式发布</title>
      <link>https://skyao.net/post/202203-dapr-docs-v1.5-translation/</link>
      <pubDate>Sun, 20 Mar 2022 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202203-dapr-docs-v1.5-translation/</guid>
      <description>&lt;p&gt;经过 Dapr 中国社区十余位贡献者一个多月的努力，Dapr 官方文档中文翻译 v1.5 版本完成翻译和审校，正式发布并上线 Dapr 官网。&lt;/p&gt;
&lt;h3 id=&#34;访问方式&#34;&gt;访问方式&lt;/h3&gt;
&lt;p&gt;v1.5 版本的中文文档在3月19日已经正式发布并上线 Dapr 官网，请打开 Dapr 文档的官方网站：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.dapr.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://docs.dapr.io/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在右上角的下拉框中依次选择 &amp;ldquo;v1.5&amp;rdquo; 和 &amp;ldquo;简体中文&amp;rdquo;：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202203-dapr-docs-v1.5-translation/images/access-translation_hu5ef363f10ea0c7fca88408498918631f_88190_3f55e778eee57aa3adb3c6df11ea06ed.webp 400w,
               /post/202203-dapr-docs-v1.5-translation/images/access-translation_hu5ef363f10ea0c7fca88408498918631f_88190_0cd4a8819d8634401a39b5dc368ba654.webp 760w,
               /post/202203-dapr-docs-v1.5-translation/images/access-translation_hu5ef363f10ea0c7fca88408498918631f_88190_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202203-dapr-docs-v1.5-translation/images/access-translation_hu5ef363f10ea0c7fca88408498918631f_88190_3f55e778eee57aa3adb3c6df11ea06ed.webp&#34;
               width=&#34;760&#34;
               height=&#34;111&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;或直接进入网址：&lt;a href=&#34;https://v1-5.docs.dapr.io/zh-hans/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://v1-5.docs.dapr.io/zh-hans/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;page&#34; srcset=&#34;
               /post/202203-dapr-docs-v1.5-translation/images/page_hu436802fddf8d1c113b4e9009b4c4cde3_1481526_c46e0df76d90d20f114cfdb8f58d8ce6.webp 400w,
               /post/202203-dapr-docs-v1.5-translation/images/page_hu436802fddf8d1c113b4e9009b4c4cde3_1481526_ac60e35855d6ac0f9394cefd8f129551.webp 760w,
               /post/202203-dapr-docs-v1.5-translation/images/page_hu436802fddf8d1c113b4e9009b4c4cde3_1481526_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202203-dapr-docs-v1.5-translation/images/page_hu436802fddf8d1c113b4e9009b4c4cde3_1481526_c46e0df76d90d20f114cfdb8f58d8ce6.webp&#34;
               width=&#34;760&#34;
               height=&#34;336&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;发布内容&#34;&gt;发布内容&lt;/h3&gt;
&lt;p&gt;本次发布的翻译内容包含 Dapr 官方英文文档 v1.5 版本对应的几乎所有内容：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;content&#34; srcset=&#34;
               /post/202203-dapr-docs-v1.5-translation/images/content_hu204cc29a761f031c71330ae4260b2b1f_1037435_84a102fda2cbdc40e4a5db984909ea2d.webp 400w,
               /post/202203-dapr-docs-v1.5-translation/images/content_hu204cc29a761f031c71330ae4260b2b1f_1037435_3481b448e0e0d3f077d29942a1e61be9.webp 760w,
               /post/202203-dapr-docs-v1.5-translation/images/content_hu204cc29a761f031c71330ae4260b2b1f_1037435_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202203-dapr-docs-v1.5-translation/images/content_hu204cc29a761f031c71330ae4260b2b1f_1037435_84a102fda2cbdc40e4a5db984909ea2d.webp&#34;
               width=&#34;760&#34;
               height=&#34;441&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;例外的是图中所示的 &amp;ldquo;developing-applications&amp;rdquo; 和 &amp;ldquo;reference&amp;rdquo; 两个大章节。&lt;/p&gt;
&lt;p&gt;特别说明：在 Dapr 的官方文档中，有三个章节由于内容超级多，一直是 Dapr 中文文档翻译工作中最艰辛的部分，因工作量巨大被戏称为&amp;quot;三座大山&amp;quot;。在 v1.5 版本的翻译工作中，除了更新常规内容之外，重点完成了 &amp;ldquo;operations&amp;rdquo; 章节的翻译和审校。至此&amp;quot;三座大山&amp;quot;中的第一座被推翻，另外  &amp;ldquo;developing-applications&amp;rdquo; 章节翻译接近完成只待审校， &amp;ldquo;reference&amp;rdquo; 翻译过半，进度喜人。&lt;/p&gt;
&lt;p&gt;预期在 v1.6 版本中，中文翻译小组将完成 &amp;ldquo;developing-applications&amp;rdquo; 章节内容的审校。预期在 v1.7 或 v1.8 版本中完成  &amp;ldquo;operations&amp;rdquo; 章节的翻译和审校，彻底推翻&amp;quot;三座大山&amp;quot;，完成 Dapr 官方文档的完整翻译。&lt;/p&gt;
&lt;h3 id=&#34;特别鸣谢&#34;&gt;特别鸣谢&lt;/h3&gt;
&lt;p&gt;Dapr 中国社区在去年底重组了中文文档翻译小组，重启了 Dapr 翻译文档的翻译工作。&lt;/p&gt;
&lt;p&gt;以下是参与 Dapr 中文文档 v1.5 版本翻译和审校的贡献者名单：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;contributors&#34; srcset=&#34;
               /post/202203-dapr-docs-v1.5-translation/images/contributors_hue278351da0e94f54637abf9156bc459a_869619_0c5149574d4211e09e5a97fdda5842a7.webp 400w,
               /post/202203-dapr-docs-v1.5-translation/images/contributors_hue278351da0e94f54637abf9156bc459a_869619_5c427b11312ca41c1a884f199cf062bb.webp 760w,
               /post/202203-dapr-docs-v1.5-translation/images/contributors_hue278351da0e94f54637abf9156bc459a_869619_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202203-dapr-docs-v1.5-translation/images/contributors_hue278351da0e94f54637abf9156bc459a_869619_0c5149574d4211e09e5a97fdda5842a7.webp&#34;
               width=&#34;760&#34;
               height=&#34;261&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;谢谢各位小伙伴的辛苦努力和无私奉献！&lt;/p&gt;
&lt;h3 id=&#34;翻译进度说明&#34;&gt;翻译进度说明&lt;/h3&gt;
&lt;p&gt;借此机会，回答社区同学经常问到的两个和中文文档翻译进度有关的问题。&lt;/p&gt;
&lt;h4 id=&#34;为什么一直没有完成完整的中文文档翻译&#34;&gt;为什么一直没有完成完整的中文文档翻译？&lt;/h4&gt;
&lt;p&gt;Dapr 中文文档翻译工作中遇到的最大挑战，就是 Dapr 英文文档随着版本的推进，内容不断的更新，同时有大量新的文档加入。因此中文文档翻译的进度一直处于苦苦追赶的状态。期间由于英文文档新内容加入的速度快于中文文档翻译的速度，甚至出现了翻译完成度不升反降的局面，如下图中 v1.1 到 v1.4：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;process&#34; srcset=&#34;
               /post/202203-dapr-docs-v1.5-translation/images/process_hu6b1dbf3b4860ed9a16ecbc590bc0ab87_476518_dbcaa63b858b79162975eb184fa897e2.webp 400w,
               /post/202203-dapr-docs-v1.5-translation/images/process_hu6b1dbf3b4860ed9a16ecbc590bc0ab87_476518_41ad5f54a1b86e8c861c9c7e4afdebaa.webp 760w,
               /post/202203-dapr-docs-v1.5-translation/images/process_hu6b1dbf3b4860ed9a16ecbc590bc0ab87_476518_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202203-dapr-docs-v1.5-translation/images/process_hu6b1dbf3b4860ed9a16ecbc590bc0ab87_476518_dbcaa63b858b79162975eb184fa897e2.webp&#34;
               width=&#34;760&#34;
               height=&#34;184&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;本次发布的 v1.5 版本在小伙伴的努力下翻译量突发猛进，在完成 &amp;ldquo;operations&amp;rdquo; 章节之后成功将翻译完成度推高到 80% 。但由于 v1.6 英文文档的大量更新和新增，在 v1.6 中翻译完成度已经自动下降到70%。&lt;/p&gt;
&lt;h4 id=&#34;为什么翻译版本一直落后于-dapr-最新发布版本&#34;&gt;为什么翻译版本一直落后于 Dapr 最新发布版本？&lt;/h4&gt;
&lt;p&gt;中文文档翻译一般会比 Dapr 最新发布的版本低 2 个小版本，比如目前 Dapr 最新稳定版本是 v1.6，v1.7 发布了预览版本即将发布正式版本，而中文文档翻译才刚发布 v1.5 版本。这里面有三个主要原因：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;官方英文文档进度延后：Dapr 的官方英文文档的更新和新增工作，并不是在 Dapr 版本发布时同步完成，而是在 Dapr 版本发布之后陆陆续续的进行更新和补充，这个过程通常会持续到 Dapr 下一个小版本的发布。即官方英文文档本身就落后一个小版本。&lt;/li&gt;
&lt;li&gt;中文文档翻译进度延后：为了避免在翻译过程中，因为英文文档更新造成的干扰，避免出现重复或无效的翻译，通常会在英文文档比较稳定之后再全面开始这一个版本的中文翻译工作，考虑翻译和审校需要的时间，一般为1-2个月。因此中文文档也会延后一段时间，大体也是落后一个小版本。&lt;/li&gt;
&lt;li&gt;&amp;ldquo;三座大山&amp;quot;工作量惊人：前面提到的 Dapr 文档中  &amp;ldquo;operations&amp;rdquo; /  &amp;ldquo;developing-applications&amp;rdquo;  / &amp;ldquo;reference&amp;rdquo; 这三个章节内容量超大，对翻译进度有致命影响。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;总结：在&amp;quot;三座大山&amp;quot;被推翻之前，Dapr 中文文档依然会维持目前比 Dapr 发布版本低 2 个小版本的状态。预计未来在 v1.6/v1.7/v1.8 版本中能够陆续完成 &amp;ldquo;developing-applications&amp;rdquo;  / &amp;ldquo;reference&amp;rdquo; 这两个超大章节的翻译。在这个基础上，我们才有机会去同步跟进 Dapr 官方英文文档的进度。&lt;/p&gt;
&lt;h3 id=&#34;欢迎加入&#34;&gt;欢迎加入&lt;/h3&gt;
&lt;p&gt;当然，所有的一切都建立在 Dapr 中国社区中文文档翻译小组的努力基础上。为了更好更快的达成目标，让 Dapr 可以更好的在中国技术社区推广，让英文不是特别好的部分同学可以更方便的查阅文档，我们真诚的希望有更多的社区朋友加入到 Dapr 的文档翻译工作中来。&lt;/p&gt;
&lt;p&gt;Dapr v1.6 版本的翻译工作即将启动，新的征程，期待您的加入！&lt;/p&gt;
&lt;p&gt;加入方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;访问 &lt;a href=&#34;https://github.com/dapr-cn/docs&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/dapr-cn/docs&lt;/a&gt; 了解详情&lt;/li&gt;
&lt;li&gt;在 Dapr 各社区群中联系我们申请加入翻译小组&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>[译]服务端口：用事件驱动的serverless找到松散耦合的乌托邦</title>
      <link>https://skyao.net/post/202112-service-ports-finding-a-loosely-coupled-utopia-with-event-driven-serverless/</link>
      <pubDate>Thu, 20 Jan 2022 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202112-service-ports-finding-a-loosely-coupled-utopia-with-event-driven-serverless/</guid>
      <description>&lt;p&gt;原文出处：&lt;a href=&#34;https://medium.com/serverless-transformation/service-ports-finding-a-loosely-coupled-utopia-with-event-driven-serverless-6964aacd1487&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Service Ports: Finding a Loosely Coupled Utopia with Event-Driven Serverless&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;作者: &lt;strong&gt;&lt;a href=&#34;https://medium.com/@bene_37069&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Ben Ellerby&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;当我们使用领域驱动设计（Domain-Driven Design）构建事件驱动的serverless架构时，我们最终会得到一组按业务功能明确划分的服务，并通过事件通道（如Amazon EventBridge）进行异步通信。这些架构带来了许多优势：松散耦合、独立部署、可测试性和降低复杂度。然而，无论我们对领域的建模有多么优雅，总有一些交叉的基础设施依赖（如事件通道本身）是不能消除的。&lt;/p&gt;
&lt;p&gt;我们如何处理它们，决定了我们是得到一个松散耦合的乌托邦，还是一个半独立服务的无序纠缠。当你已经投入了90%的努力，不要让这成为最后的绊脚石。&lt;/p&gt;
&lt;p&gt;在这篇文章中，我们将看到明确定义的服务端口(Service Port)如何解决最后10%的基础设施依赖性，并带来松散耦合、独立部署/测试和提升开发速度。&lt;/p&gt;
&lt;h2 id=&#34;问题是如何产生的&#34;&gt;问题是如何产生的&lt;/h2&gt;
&lt;p&gt;我们之前讨论过Amazon EventBridge如何与强大的领域驱动设计相结合来创建这样的架构（见&lt;a href=&#34;https://medium.com/serverless-transformation/eventbridge-storming-how-to-build-state-of-the-art-event-driven-serverless-architectures-e07270d4dee&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;EventBridge Storming&lt;/a&gt;）。当我们以这种方式构建服务（或 &amp;ldquo;微服务&amp;rdquo;）的集合时，仍然存在一些跨领域的全局依赖性。这些依赖关系妨碍了独立开发服务，使集成测试变得困难，并会在我们的基础设施定义中产生复杂的代码。此外，当这种依赖关系没有被明确化时，服务的部署顺序在最好的情况下会成为一个谜，在最坏的情况下则会成为一系列的竞争条件。&lt;/p&gt;
&lt;p&gt;为了使这个问题更加具体化，让我们想象一下，我们进行了一个&lt;a href=&#34;https://medium.com/serverless-transformation/eventbridge-storming-how-to-build-state-of-the-art-event-driven-serverless-architectures-e07270d4dee&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;EventBridge Storming会话&lt;/a&gt;，通过将系统的所有业务事件收集到Bounded Contexts中来理解一个电子商务网站的示例问题域。从这个会话中，我们将了解业务领域，属于它的事件，以及它们如何被分组。&lt;/p&gt;
&lt;p&gt;从这样的会议中，我们可以推导出以下服务，将领域内的事件组合在一起，并通过松散耦合创建服务边界。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;1&#34; srcset=&#34;
               /post/202112-service-ports-finding-a-loosely-coupled-utopia-with-event-driven-serverless/images/1_huec85b290856ed052cb0d74168f369a70_180879_e11a269fd2aa819760a454b263012e11.webp 400w,
               /post/202112-service-ports-finding-a-loosely-coupled-utopia-with-event-driven-serverless/images/1_huec85b290856ed052cb0d74168f369a70_180879_bd49eba3712337d00f0a1a4797b52f1d.webp 760w,
               /post/202112-service-ports-finding-a-loosely-coupled-utopia-with-event-driven-serverless/images/1_huec85b290856ed052cb0d74168f369a70_180879_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202112-service-ports-finding-a-loosely-coupled-utopia-with-event-driven-serverless/images/1_huec85b290856ed052cb0d74168f369a70_180879_e11a269fd2aa819760a454b263012e11.webp&#34;
               width=&#34;760&#34;
               height=&#34;443&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;架构的高层视图将如下所示:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;2&#34; srcset=&#34;
               /post/202112-service-ports-finding-a-loosely-coupled-utopia-with-event-driven-serverless/images/2_hu4308910d9fab4de9b22e2467e2023d1a_502863_8798fcf552811d41b768baa2d63c3019.webp 400w,
               /post/202112-service-ports-finding-a-loosely-coupled-utopia-with-event-driven-serverless/images/2_hu4308910d9fab4de9b22e2467e2023d1a_502863_56890ca5e263606244ee191de832d604.webp 760w,
               /post/202112-service-ports-finding-a-loosely-coupled-utopia-with-event-driven-serverless/images/2_hu4308910d9fab4de9b22e2467e2023d1a_502863_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202112-service-ports-finding-a-loosely-coupled-utopia-with-event-driven-serverless/images/2_hu4308910d9fab4de9b22e2467e2023d1a_502863_8798fcf552811d41b768baa2d63c3019.webp&#34;
               width=&#34;760&#34;
               height=&#34;686&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;注意到两个典型的共享基础设施的依赖关系是EventBus本身，以及Cognito用户池。基础设施中对这些的引用很简单，就是一个ARN。但是，要求这些依赖关系被部署（与它们所属的堆栈中的其他一切一起）使得独立开发和测试变得复杂。此外，这些引用也可以作为代码文件隐藏在基础设施中。
这种跨领域的基础设施的依赖性需要有意为之，并为之设计，向开发者明示。如果没有，这将导致几个问题。&lt;/p&gt;
&lt;p&gt;&amp;ldquo;存在的来源问题&amp;rdquo;。我们可以在财务服务中保留这个依赖关系的定义，并在人力资源服务中引用它。当它是2个服务时，这很好，但如果10个服务都需要这个资源，那该怎么办。&lt;/p&gt;
&lt;p&gt;此外，我们还产生了一些连带问题。财务服务现在需要在人力资源服务之前部署。在生产中，这似乎是可控的，它将在第一时间发生；但在开发、分期和UAT中呢？此外，无服务器的一个惊人的好处是短暂的堆栈（见无服务器流程）&amp;ndash;这将如何实现？&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Dapr中国社区会议筹备事宜</title>
      <link>https://skyao.net/post/202112-dapr-china-community-meeting/</link>
      <pubDate>Thu, 23 Dec 2021 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202112-dapr-china-community-meeting/</guid>
      <description>&lt;p&gt;和微软的 Artur Souza 沟通了一次，关于Dapr社区会议的事情和大家同步一下。由于信息比较多，因此一些细节我先以文字的方式和大家同步好，方便后续讨论。&lt;/p&gt;
&lt;h2 id=&#34;参加现有dapr社区会议的建议&#34;&gt;参加现有Dapr社区会议的建议&lt;/h2&gt;
&lt;p&gt;Dapr社区会议的现有时间安排：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/dapr/community#community-meetings&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/dapr/community#community-meetings&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;del&gt;Tuesday November 16th 10:00am Pacific Time (PST)&lt;/del&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;del&gt;Tuesday November 30th 7:30pm Pacific Time (PST)&lt;/del&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;del&gt;Tuesday December 14th 10:00am Pacific Time (PST)&lt;/del&gt;&lt;/p&gt;
&lt;p&gt;换算到中国北京时间是2021年12月15号，凌晨两点，这个时间对中国区用户很不友好。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;december-14&#34; srcset=&#34;
               /post/202112-dapr-china-community-meeting/images/december-14_hu2c9cc191d0e9853cc7f54a376575af6f_67551_2aed0013e111018c5a13802d3f921d07.webp 400w,
               /post/202112-dapr-china-community-meeting/images/december-14_hu2c9cc191d0e9853cc7f54a376575af6f_67551_be89ae8a87ad68616372c3506f92dbba.webp 760w,
               /post/202112-dapr-china-community-meeting/images/december-14_hu2c9cc191d0e9853cc7f54a376575af6f_67551_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202112-dapr-china-community-meeting/images/december-14_hu2c9cc191d0e9853cc7f54a376575af6f_67551_2aed0013e111018c5a13802d3f921d07.webp&#34;
               width=&#34;760&#34;
               height=&#34;181&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tuesday January 11th 7:30pm Pacific Time (PST)&lt;/p&gt;
&lt;p&gt;换算到中国北京时间是2022年1月12号，上午11：30，这个时间比较适合中国区用户。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;january-11&#34; srcset=&#34;
               /post/202112-dapr-china-community-meeting/images/january-11_hua2b6ecad7dbb6a8195875562e8fb4079_66426_bbaf2dec433093dfd91b13e136a3fdd5.webp 400w,
               /post/202112-dapr-china-community-meeting/images/january-11_hua2b6ecad7dbb6a8195875562e8fb4079_66426_65ec1c319b6ab00ac5e2bf3032118650.webp 760w,
               /post/202112-dapr-china-community-meeting/images/january-11_hua2b6ecad7dbb6a8195875562e8fb4079_66426_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202112-dapr-china-community-meeting/images/january-11_hua2b6ecad7dbb6a8195875562e8fb4079_66426_bbaf2dec433093dfd91b13e136a3fdd5.webp&#34;
               width=&#34;760&#34;
               height=&#34;186&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tuesday February 8th 10:00am Pacific Time (PST)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tuesday February 22th 7:30pm Pacific Time (PST)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tuesday March 8th 10:00am Pacific Time (PST)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Tuesday March 22th 7:30pm Pacific Time (PST)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总结：Dapr社区会议是每两周一次，每月有一次的时间是PST 19：30，对应到北京时间上午11：30。&lt;/p&gt;
&lt;p&gt;建议：和dapr沟通的结果是，他们建议我们重点参加每月一次的 PST 19：30（北京时间上午11：30）的社区会议。当然有同学愿意参加PST 10：00（北京时间凌晨2点）的社区会议也没有问题，只是希望优先保证参加前者。&lt;/p&gt;
&lt;p&gt;另外, Artur Souza 给了一个建议，可以用中文来介绍，但我感觉执行起来不太容易，想听一下大家的意见：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;it would be great if we have representation from your Dapr community by presenting some topics in the call. They are usually in English. I would also suggest that having presentation in Chinese is OK but I would like to confirm from other maintainers here first.&lt;/p&gt;
&lt;p&gt;如果你们Dapr社区的代表能在电话会议上提出一些议题，那将是非常好的。他们通常是用英语。我也建议用中文来介绍，但我想先从其他维护者那里得到确认。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;举办新的dapr中国社区会议的建议&#34;&gt;举办新的Dapr中国社区会议的建议&lt;/h2&gt;
&lt;p&gt;上次dapr中文周会上，我总结了希望dapr中国社区会议可以做到的几个点（如有遗漏请大家帮忙补充）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;加强dapr中国社区内部的沟通和信息同步
&lt;ol&gt;
&lt;li&gt;推动目前正在做和准备做的几个事情：dapr中文文档翻译的维护和更新；dapr源码解读；dapr落地实践分享&lt;/li&gt;
&lt;li&gt;加强dapr中国区开发者之间的了解和互动，并希望发展出更多的贡献者（contributor、maintainer、core maintainer）&lt;/li&gt;
&lt;li&gt;扩大dapr在中国技术社区的影响力，布道、宣传、分享以找到更多的同路人&lt;/li&gt;
&lt;li&gt;分享dapr落地的业务场景，挖掘和整理需求，向dapr社区传递这些场景和需求信息&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;加强dapr社区和dapr中国社区彼此之间的双向沟通和信息同步
&lt;ol&gt;
&lt;li&gt;将dapr社区的信息带回来国内：包括短期的发布计划（release plan），长期的路线图（roadmap），一些重大的future/proposal或者改动&lt;/li&gt;
&lt;li&gt;将dapr中国社区的信息带给国外：包括我们的场景和需求，我们的落地实践，我们提出的issue和PR, 我们关注的大的proposal&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;目前我们已有一个dapr双周会，后面希望将这个会议组织的更好一些，然后成为dapr社区的一个正式会议（预计会冠以 Dapr China Community Meeting 的名字），并覆盖更多的dapr中国用户和开发者。&lt;/p&gt;
&lt;p&gt;关于Dapr中国社区会议的筹备，还有几个细节待讨论：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Dapr中国社区会议的时间：目前是双周会，而且刚好和dapr社区的会议周数是错开的，这样也适合我们Dapr中国社区会议的工作方式——把上一周dapr社区的信息同步到国内，然后将国内的信息在下一次的dapr社区会议上同步给国外。（下一次会议时间是本周六晚20：00-20：30）&lt;/li&gt;
&lt;li&gt;Dapr中国社区会议的工具：dapr官方是用zoom，但zoom在国内被墙（外加zoom限制中国IP接入），国内同学接入不便。目前我们已有的双周会使用的是腾讯会议。考虑到参会的基本都是国内同学，因此我建议不使用zoom而是采用我们国内方便接入的方式。关于这一点我也和 Artur Souza 同步过。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;dapr中国社区会议和国内各个dapr社区的关系&#34;&gt;Dapr中国社区会议和国内各个dapr社区的关系&lt;/h2&gt;
&lt;p&gt;目前我们国内的dapr社区，主要有几个：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;云原生社区Dapr SIG&lt;/li&gt;
&lt;li&gt;dapr 中文社区&lt;/li&gt;
&lt;li&gt;Dapr .Net&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：可能还存在其他零散的dapr群或者兴趣小组，如果有我没有列出来的请告知我，我去联系。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;由于大家的来源、关注点、技术背景、公司背景都不太相同，我觉得短时间内统一dapr社区不太现实，也看不到实际的意义。因此，我个人觉得 Dapr中国社区会议的定位是跨各个dapr社区、QQ群/微信群、兴趣小组建立一个dapr国内沟通和交流的渠道。现有的这些社区继续按照自己的方式运作。&lt;/p&gt;
&lt;h2 id=&#34;行动小组和后续推荐&#34;&gt;行动小组和后续推荐&lt;/h2&gt;
&lt;p&gt;Dapr社区会议只是加强沟通的一个方式，更重要的还是要务实的推动各个事情。因此我个人建议在社区内成立若干个行动小组，有明确的目标、牵头人、分工，然后每次的周会上各个行动小组可以做一下更新。&lt;/p&gt;
&lt;p&gt;我暂时想到的几个行动小组有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;dapr文档翻译&lt;/li&gt;
&lt;li&gt;dapr源码解读&lt;/li&gt;
&lt;li&gt;dapr落地实践分享&lt;/li&gt;
&lt;li&gt;dapr布道和宣传：组织或参加技术会议&lt;/li&gt;
&lt;li&gt;dapr动态跟进：release plan，roadmap，新的future，大的proposal等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;大家可以帮忙补充。具体方式我们一起讨论。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译]使用暗物质和暗能量设计架构</title>
      <link>https://skyao.net/post/202112-dark-matter-dark-energy/</link>
      <pubDate>Mon, 06 Dec 2021 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202112-dark-matter-dark-energy/</guid>
      <description>&lt;p&gt;原文出处：&lt;a href=&#34;http://chrisrichardson.net/post/microservices/2021/11/30/dark-matter-dark-energy.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Designing an architecture using dark matter and dark energy&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;作者: &lt;strong&gt;Chris Richardson&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;在设计应用程序的架构时，有许多决定是必须做出的。比如说。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;应用程序应该使用单体还是微服务架构？&lt;/li&gt;
&lt;li&gt;如果使用微服务架构，最好的服务边界是什么？&lt;/li&gt;
&lt;li&gt;如何设计跨多个服务的操作？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在与客户合作时，我经常被问到 &amp;ldquo;做X的最好方法是什么？&amp;quot;。几乎总是，我的回答是 &amp;ldquo;这取决于！&amp;quot;。具体来说，最佳解决方案取决于试图解决问题的具体环境。悲哀的是，&lt;strong&gt;没有银弹&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;相反，我建议使用基于暗物质和暗能量的标准来评估一个潜在的解决方案或比较多个候选解决方案。暗物质和暗能量是天体物理学家发明的神秘概念，以解释某些天文观测。暗能量是一种反重力，它迫使物质分离并加速了宇宙的膨胀。暗物质是一种看不见的物质，对恒星和星系有引力作用。正如我在 &lt;a href=&#34;https://chrisrichardson.net/post/microservices/2021/10/31/isaqb-keynote.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;iSAQB&lt;/a&gt; 和 &lt;a href=&#34;https://chrisrichardson.net/post/microservices/2021/04/15/mucon-2021-dark-energy-dark-matter.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Mucon&lt;/a&gt; 的演讲中所描述的，我把它们作为设计架构时必须解决的斥力和引力的隐喻。&lt;/p&gt;
&lt;p&gt;在谈论如何应用暗物质和暗能量的隐喻之前，我想先谈谈两个相互关联的概念：系统操作（System operation）和子域（subdomain）。&lt;/p&gt;
&lt;h3 id=&#34;关于系统操作和子域&#34;&gt;关于系统操作和子域&lt;/h3&gt;
&lt;p&gt;系统操作是对应用程序的功能需求（如故事）的提炼。每一个都是应用程序必须处理的请求的抽象表示。例如，FTGO应用程序实现了系统操作，如&lt;code&gt;createOrder()&lt;/code&gt;, &lt;code&gt;cancelOrder()&lt;/code&gt;, and &lt;code&gt;findOrderHistory()&lt;/code&gt;。系统操作还模拟了由时间流逝触发的动作。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;distilling-system-operations&#34; srcset=&#34;
               /post/202112-dark-matter-dark-energy/images/distilling-system-operations_hu496c7e3033e6ff93cc783a3aa047dc00_106092_5b5668ec34d28ebde2865c26fa0178be.webp 400w,
               /post/202112-dark-matter-dark-energy/images/distilling-system-operations_hu496c7e3033e6ff93cc783a3aa047dc00_106092_6f8531ac97f8decae3e0882d829af0c2.webp 760w,
               /post/202112-dark-matter-dark-energy/images/distilling-system-operations_hu496c7e3033e6ff93cc783a3aa047dc00_106092_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202112-dark-matter-dark-energy/images/distilling-system-operations_hu496c7e3033e6ff93cc783a3aa047dc00_106092_5b5668ec34d28ebde2865c26fa0178be.webp&#34;
               width=&#34;760&#34;
               height=&#34;403&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;系统操作所描述的应用程序的功能是由子域的集合来实现的。子域是一个可实现的，（通常）面向对象的业务能力模型。它由一个小团队拥有，负责其开发。例如，FTGO应用程序有许多子域，包括订单管理、送货管理、餐厅管理、厨房管理等。而且，由于它是一个Java应用程序，每个子域都是一个包含类的Java包的集合。&lt;/p&gt;
&lt;p&gt;每个系统操作都跨越了一个或多个子域。例如，&lt;code&gt;createOrder()&lt;/code&gt;系统操作跨越了许多域，包括订单管理、餐厅管理、厨房管理和会计。&lt;/p&gt;
&lt;p&gt;应用程序的子域构成了其架构的逻辑（也就是开发）视图。我们还需要考虑实现视图，它定义了这些子域如何被打包成组件，即可执行/可部署单元。&lt;/p&gt;
&lt;h3 id=&#34;什么是架构的实现视图&#34;&gt;什么是架构的实现视图&lt;/h3&gt;
&lt;p&gt;实现视图定义了应用程序的模块（module）和组件（component）。模块是一个经过编译和打包的子域。组件是一个可执行的或可部署的，由一个或多个模块组成。在Java应用程序中，模块是一个JAR文件，所以每个子域都会被打包成一个或多个JAR文件。Java组件是一个WAR文件或一个可执行的胖JAR文件，它包含JAR文件的集合。&lt;/p&gt;
&lt;p&gt;如果应用程序由一个单一的组件组成，那么它就是单体架构。或者，如果它由两个或更多的组件组成，那么它是微服务架构。&lt;/p&gt;
&lt;h3 id=&#34;定义应用程序的实现视图&#34;&gt;定义应用程序的实现视图&lt;/h3&gt;
&lt;p&gt;鉴于上述对子域和组件的定义，定义架构的（实现视图）的问题变成了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如何将应用程序的子域划分为一个或多个组件，也就是服务？&lt;/li&gt;
&lt;li&gt;鉴于这种划分，如何设计跨越服务的系统操作？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这就是暗能量和暗物质的比喻可以帮助的地方。&lt;/p&gt;
&lt;h3 id=&#34;关于暗能量和暗物质&#34;&gt;关于暗能量和暗物质&lt;/h3&gt;
&lt;p&gt;天体物理学家发明了暗能量的概念，以解释为什么以前放缓的宇宙膨胀在70亿年前开始加速。该理论认为，随着宇宙的膨胀，引力减弱，最终暗能量（一种反引力的排斥力）成为主导，加速了膨胀。暗能量是一个有用的比喻，可以解释鼓励子域划分为多个服务的排斥力。&lt;/p&gt;
&lt;p&gt;当天体物理学家观察遥远星系中恒星的轨道时，他们发现这些恒星的移动速度比根据可见物质的数量所预期的要快。为了解释这一差异，他们发明了暗物质的概念，这是一种不可见的物质形式，会产生引力。对于微服务架构中抵制分解为服务的吸引力，这是一个有用的比喻。这些作用于子域的吸引力是由跨越这些子域的系统操作产生的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;Dark_Energy_Dark_Matter_overview&#34; srcset=&#34;
               /post/202112-dark-matter-dark-energy/images/Dark_Energy_Dark_Matter_overview_hu474e66b43173483572744953cd5793b5_113242_0d03e8ac033741f863388377f979274a.webp 400w,
               /post/202112-dark-matter-dark-energy/images/Dark_Energy_Dark_Matter_overview_hu474e66b43173483572744953cd5793b5_113242_6f87e0bd161520999e743b3768514eec.webp 760w,
               /post/202112-dark-matter-dark-energy/images/Dark_Energy_Dark_Matter_overview_hu474e66b43173483572744953cd5793b5_113242_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202112-dark-matter-dark-energy/images/Dark_Energy_Dark_Matter_overview_hu474e66b43173483572744953cd5793b5_113242_0d03e8ac033741f863388377f979274a.webp&#34;
               width=&#34;760&#34;
               height=&#34;511&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们先来看看暗能量。&lt;/p&gt;
&lt;h3 id=&#34;利用暗能量&#34;&gt;利用暗能量&lt;/h3&gt;
&lt;p&gt;有几种力量作用于子域，鼓励将子域划分为多个服务:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;简单组件&amp;ndash;简单组件比复杂组件更容易理解和维护&lt;/li&gt;
&lt;li&gt;团队自主性&amp;ndash;团队需要能够独立开发、测试和部署他们的软件&lt;/li&gt;
&lt;li&gt;快速部署管道&amp;ndash;快速反馈和高部署频率是必不可少的，并由快速部署管道实现。&lt;/li&gt;
&lt;li&gt;支持多种技术栈&amp;ndash;子域有时是用各种语言编写的，开发人员需要不断地发展技术栈。&lt;/li&gt;
&lt;li&gt;成本有效的扩展&amp;ndash;按资源要求分离子域&lt;/li&gt;
&lt;li&gt;隔离受管制的软件&amp;ndash;某些领域的软件开发，如作为医疗设备的软件（SaMD），是受管制的，但分区使一些应用程序的子域避免受管制。&lt;/li&gt;
&lt;li&gt;隔离高可用性的组件&amp;ndash;关键业务组件应与不太关键的组件隔离，以最大限度地提高可用性。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些排斥性力量作用于子域，鼓励它们被打包成独立的服务。然而，它们并不是你必须考虑的唯一力量。你还必须考虑有引力的力量。&lt;/p&gt;
&lt;h3 id=&#34;利用暗物质&#34;&gt;利用暗物质&lt;/h3&gt;
&lt;p&gt;有以下抵制拆分的引力：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;简单相互作用&amp;ndash;组件之间简单的相互作用比复杂的相互作用更容易理解&lt;/li&gt;
&lt;li&gt;倾向于ACID而不是BASE&amp;ndash;将一个操作实现为ACID事务，而不是例如最终一致的sagas，这更容易。&lt;/li&gt;
&lt;li&gt;尽量减少运行时的耦合性&amp;ndash;为了最大限度地提高可用性和减少延时&lt;/li&gt;
&lt;li&gt;高效的服务间通信&amp;ndash;大量的网络往返和大量的数据传输会使效率过低&lt;/li&gt;
&lt;li&gt;尽量减少设计时的耦合&amp;ndash;减少同步改变服务的可能性，这将降低生产力&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;特定的系统操作所产生的吸引力的强度取决于两个因素:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;它所引用的子域是如何被划分为服务的&lt;/li&gt;
&lt;li&gt;用来实现该操作的模式&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;有时，可以通过重新设计操作来减少这些力量的强度。或者，可能需要重新划分子域。&lt;/p&gt;
&lt;h3 id=&#34;设计架构平衡暗物质和暗能量的力量&#34;&gt;设计架构=平衡暗物质和暗能量的力量&lt;/h3&gt;
&lt;p&gt;单体架构如此吸引人的原因之一是它满足了所有的吸引力。然而，可悲的是，它忽略了所有的排斥力，特别是当应用程序很大时。在另一端，细粒度的微服务架构满足了所有的排斥力，但可能忽略了吸引力。它可能是一个脆弱的分布式单体，由于过度的设计时和运行时耦合，它结合了两种架构风格的缺点。架构师的工作是设计一个架构，使组件内部的排斥力最小化，并使组件之间的吸引力最小化。未来的博文将对暗能量和暗物质力量进行更深入的探讨。&lt;/p&gt;
&lt;h3 id=&#34;要了解更多&#34;&gt;要了解更多&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;请看最近的一些演讲：&lt;a href=&#34;https://chrisrichardson.net/post/microservices/2021/10/31/isaqb-keynote.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;iSAQB主题演讲&amp;ndash;模块化单体和微服务：快速、可靠、频繁和可持续发展的架构模式&lt;/a&gt; 和 &lt;a href=&#34;https://chrisrichardson.net/post/microservices/2021/04/15/mucon-2021-dark-energy-dark-matter.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Mucon 2021&amp;ndash;暗能量、暗物质：设计微服务的不完美隐喻&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;我提供咨询和培训，帮助你有效地使用微服务架构。&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>[译]Linkerd和Istio基准测试：2021年重复</title>
      <link>https://skyao.net/post/202112-linkerd-vs-istio-benchmarks-2021/</link>
      <pubDate>Sun, 05 Dec 2021 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202112-linkerd-vs-istio-benchmarks-2021/</guid>
      <description>&lt;p&gt;原文出处：&lt;a href=&#34;https://linkerd.io/2021/11/29/linkerd-vs-istio-benchmarks-2021/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Benchmarking Linkerd and Istio: 2021 Redux&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;作者: &lt;strong&gt;William Morgan&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;今年早些时候，我们发布了 &lt;a href=&#34;https://linkerd.io/2021/05/27/linkerd-vs-istio-benchmarks/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Linkerd与Istio的基准测试&lt;/a&gt;，在简单的微服务应用上比较了两个服务网格在不同负载水平下的性能和资源消耗。通过使用开源的基准测试工具，我们发现Linkerd的速度明显快于Istio，同时消耗的数据平面内存和CPU少一个数量级。&lt;/p&gt;
&lt;p&gt;随着最近 &lt;a href=&#34;https://linkerd.io/2021/09/30/announcing-linkerd-2.11/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Linkerd 2.11中授权策略&lt;/a&gt; 的发布，我们想重新评估Linkerd的性能。毕竟，这是该项目一个重要的新功能，对性能有潜在影响。最新版本的Linkerd的性能如何？&lt;/p&gt;
&lt;p&gt;为了弄清楚，我们用两个项目的最新版本重新进行了基准测试。我们的结果显示，&lt;strong&gt;即使增加了策略，Linkerd仍然比Istio快得多，而消耗的系统资源只是一小部分&lt;/strong&gt;。在我们测试的最高负载水平下，Linkerd引入的额外尾延迟几乎比Istio少一个数量级。&lt;/p&gt;
&lt;p&gt;继续阅读，了解更多!&lt;/p&gt;
&lt;h2 id=&#34;背景介绍&#34;&gt;背景介绍&lt;/h2&gt;
&lt;p&gt;2019年，Kinvolk发布了 &lt;a href=&#34;https://linkerd.io/2019/05/18/linkerd-benchmarks/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Linkerd与Istio的公开基准数据&lt;/a&gt;。这项工作不仅表明Linkerd比Istio明显更快、更轻，而且还产生了一个 &lt;a href=&#34;https://github.com/kinvolk/service-mesh-benchmark&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;开源的服务网格基准测试工具&lt;/a&gt;，以便任何人都可以复制结果。这个工具模拟了&amp;quot;现实生活&amp;quot;场景：它通过一个简单的微服务应用发送了持续的流量，使用了gRPC和HTTP调用，并从内存和CPU消耗以及增加的延迟方面测量了使用服务网格的成本。最关键的是，延迟是从客户的角度测量的，产生面向用户的数字，而不是内部代理时间。&lt;/p&gt;
&lt;p&gt;今年早些时候，我们 &lt;a href=&#34;https://linkerd.io/2021/05/27/linkerd-vs-istio-benchmarks/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;重新审视了Linkerd 2.10和Istio 1.10.0的这些比较&lt;/a&gt;，显示Linkerd仍然比Istio快得多，而且在这样做的时候，消耗的数据平面内存和CPU少一个数量级。&lt;/p&gt;
&lt;p&gt;从那时起，这两个项目都发布了新的版本，最引人注目的是 &lt;a href=&#34;https://linkerd.io/2021/09/30/announcing-linkerd-2.11/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Linkerd 2.11引入了授权策略&lt;/a&gt;，这是该项目具有潜在性能影响的一个重要新功能。&lt;/p&gt;
&lt;h2 id=&#34;实验设置&#34;&gt;实验设置&lt;/h2&gt;
&lt;p&gt;在这些实验中，我们将相同的Kinvolk基准套件应用于两个项目的最新稳定版本。Linkerd 2.11.1（使用默认安装）和Istio 1.12.0（其 &amp;ldquo;最小&amp;quot;配置）。我们在Kubernetes v1.21.4集群上运行基准工具，使用基准工具使用的&lt;a href=&#34;https://kinvolk.io/lokomotive-kubernetes/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Lokomotive Kubernetes发行版&lt;/a&gt;，在 &lt;a href=&#34;https://www.equinix.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Equinix Metal&lt;/a&gt; 为CNCF项目慷慨提供的裸机硬件上运行。&lt;/p&gt;
&lt;p&gt;从我们以前的工作中，我们知道最重要的第一步是找到一个能提供一致延迟结果的环境。云环境可以在不同的时刻提供截然不同的性能特征，特别是在网络方面。然而，做好这一点对于像这样的比较实验至关重要：基线延迟的差异会降低结果的质量。&lt;/p&gt;
&lt;p&gt;我们的设置模仿了我们先前的实验：我们在Equinix Metal dfw2数据中心运行所有代码，这再次产生了我们发现的最低变异行为。我们的集群包括6个s3.xlarge.x86配置的工作节点（英特尔至强4214，24个物理核心@2.2GHz，192GB内存），基准应用程序在上面运行，加上一个相同配置的负载发生器节点，以及一个c2.medium.x86配置的K8s主节点。&lt;/p&gt;
&lt;p&gt;和以前一样，我们在20 RPS、200 RPS和2000 RPS下评估了这两个服务网格。在每个级别，我们对Linkerd、Istio和没有服务网格的基本情况进行了多次独立运行，每次持续负载10分钟。在两次运行之间，所有的基准和网格资源都被重新安装。对于20和200RPS的运行，我们运行了8次，并根据最大基线延迟丢弃了前3次。对于2,000 RPS的运行，由于最后期限的限制，我们运行了7次，并手动放弃了Istio和Linkerd各自的最大延迟的单一运行。(我们的原始数据可供查阅）。&lt;/p&gt;
&lt;p&gt;需要注意的是，Kinvolk框架以一种非常特殊的方式测量服务网格的行为，我们没有对这个框架进行任何修改。还要注意的是，这个基准所报告的数字是服务网格和工具及其环境的一个函数。换句话说，这些不是绝对分数，而是相对分数，只能与在相同环境和相同方式下测量的其他替代方案进行评估（附注1）。&lt;/p&gt;
&lt;h2 id=&#34;测试的服务网格功能&#34;&gt;测试的服务网格功能&lt;/h2&gt;
&lt;p&gt;虽然每个服务网提供了大量的功能，但在这些实验中，只有其中的一个子集是实际发挥作用的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;两个网格都启用了双向TLS，并在所有应用pod之间加密流量和验证身份。&lt;/li&gt;
&lt;li&gt;两个网格都在报告指标，包括L7指标，尽管这些指标在本实验中没有被使用。&lt;/li&gt;
&lt;li&gt;两个网格都默认在INFO级别上记录了各种信息。我们并没有配置日志记录。&lt;/li&gt;
&lt;li&gt;没有明确启用重试、超时、分布式跟踪、多集群通信或其他功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;实验结果&#34;&gt;实验结果&lt;/h2&gt;
&lt;p&gt;我们的实验结果显示在下面的图表中。这些图表中的每一点都是五次运行的平均值，误差条代表平均值的标准差。条形图本身代表Linkerd（蓝色）、Istio（橙色）和无服务网格的基线（黄色）。&lt;/p&gt;
&lt;h3 id=&#34;20rps时的延时&#34;&gt;20RPS时的延时&lt;/h3&gt;
&lt;p&gt;从相对平静的20RPS级别开始，我们已经看到了面向用户的延迟的巨大差异。Linkerd的中位延迟是14ms，比基线的6ms多8ms。相比之下，Istio的中位延迟是26ms，是Linkerd额外延迟的两倍多。在最大值上，Linkerd比基线的18ms延迟增加了39ms，而Istio的最大延迟增加了232ms，几乎是Linkerd额外延迟的六倍。&lt;/p&gt;
&lt;p&gt;看一下百分位数，我们看到Istio的延迟分布在p99时急剧上升到~240ms，而Linkerd在更高的百分位数时显示出更平缓的增长，达到57ms。&lt;/p&gt;
&lt;p&gt;获胜者：Linkerd（8ms对26ms的中位数；39ms对232ms的最大值）&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;latency-20rps&#34; srcset=&#34;
               /post/202112-linkerd-vs-istio-benchmarks-2021/images/latency-20rps_hu5a77cf620fb615e46ebbd4680fc42a5e_86669_aef5977c75ebae559d9c4136d7a4013f.webp 400w,
               /post/202112-linkerd-vs-istio-benchmarks-2021/images/latency-20rps_hu5a77cf620fb615e46ebbd4680fc42a5e_86669_cfe6a9e3fae269062f6fbe0d6428982a.webp 760w,
               /post/202112-linkerd-vs-istio-benchmarks-2021/images/latency-20rps_hu5a77cf620fb615e46ebbd4680fc42a5e_86669_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202112-linkerd-vs-istio-benchmarks-2021/images/latency-20rps_hu5a77cf620fb615e46ebbd4680fc42a5e_86669_aef5977c75ebae559d9c4136d7a4013f.webp&#34;
               width=&#34;760&#34;
               height=&#34;533&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;200rps下的延时&#34;&gt;200RPS下的延时&lt;/h3&gt;
&lt;p&gt;200RPS的数字讲述了一个非常相似的故事，中位延迟的数字几乎是相同的。Linkerd的中位延迟为14ms，比基线的中位延迟6ms高出8ms，而Istio的中位延迟为26ms，高出20ms。在最大值上，Istio的280ms延迟比基线的30ms高出250ms，而Linkerd的最大延迟119ms高出约90ms，不到Istio的额外延迟的一半。我们看到Istio的延迟在p99个时发生了同样的跳跃，面向用户的延迟几乎达到250ms，而Linkerd从p999开始逐渐增加。&lt;/p&gt;
&lt;p&gt;获胜者：Linkerd（8ms对26ms的中位数；90ms对250ms的最大值）&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;latency-200rps&#34; srcset=&#34;
               /post/202112-linkerd-vs-istio-benchmarks-2021/images/latency-200rps_hudbca733f0b51d982f997f8bfb25682e2_89263_6da5e791b70b53a6b2127f65a1a167b5.webp 400w,
               /post/202112-linkerd-vs-istio-benchmarks-2021/images/latency-200rps_hudbca733f0b51d982f997f8bfb25682e2_89263_f2f7ab5abceae867127a64e9f48ef443.webp 760w,
               /post/202112-linkerd-vs-istio-benchmarks-2021/images/latency-200rps_hudbca733f0b51d982f997f8bfb25682e2_89263_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202112-linkerd-vs-istio-benchmarks-2021/images/latency-200rps_hudbca733f0b51d982f997f8bfb25682e2_89263_6da5e791b70b53a6b2127f65a1a167b5.webp&#34;
               width=&#34;760&#34;
               height=&#34;533&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;2000rps时的延迟&#34;&gt;2000RPS时的延迟&lt;/h3&gt;
&lt;p&gt;最后，在2000RPS时，我们看到了网格之间最显著的差异：在中位数时，Linkerd在6ms的基线上引入了额外的6ms延迟，而Istio的额外延迟为17ms；在最大值时，Linkerd在84ms的基线上引入了额外的42ms，而Istio增加了8倍的额外延迟，约350ms。一般来说，在报告的每个百分点上，Istio比Linkerd多引入了130%到850%的额外延迟。&lt;/p&gt;
&lt;p&gt;获胜者:Linkerd（6ms对17ms的中位数；42ms对350ms的最大值）&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;latency-2000rps&#34; srcset=&#34;
               /post/202112-linkerd-vs-istio-benchmarks-2021/images/latency-2000rps_hu923aceb054a2d9429ce6975d52d56291_97193_f2e3a5fb5bbb8b4a0d7038a9fb771d89.webp 400w,
               /post/202112-linkerd-vs-istio-benchmarks-2021/images/latency-2000rps_hu923aceb054a2d9429ce6975d52d56291_97193_8054f53819ed5f60e6593fec5ec58f42.webp 760w,
               /post/202112-linkerd-vs-istio-benchmarks-2021/images/latency-2000rps_hu923aceb054a2d9429ce6975d52d56291_97193_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202112-linkerd-vs-istio-benchmarks-2021/images/latency-2000rps_hu923aceb054a2d9429ce6975d52d56291_97193_f2e3a5fb5bbb8b4a0d7038a9fb771d89.webp&#34;
               width=&#34;760&#34;
               height=&#34;536&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;资源消耗&#34;&gt;资源消耗&lt;/h3&gt;
&lt;p&gt;现在转向资源使用，每个服务网格的CPU和内存消耗显示在下面的图表中。这些数字在所有的吞吐量水平上是相当一致的，所以我们将重点关注最高负载的2000 RPS场景。&lt;/p&gt;
&lt;p&gt;从控制平面开始，我们看到Istio的控制平面使用量平均为597mb，比Linkerd的控制平面内存消耗量365mb高出约50%。Linkerd的CPU使用量要小一个数量级&amp;ndash;控制平面CPU时间为212ms，而Istio为5秒。&lt;/p&gt;
&lt;p&gt;然而，比控制平面更重要的是数据平面。毕竟，这是网格的一部分，必须随着应用程序的扩展而扩展。在这里，我们看到另一个戏剧性的差异：Linkerd代理所消耗的最大内存平均为26.3mb，而Istio的Envoy代理所消耗的最大内存为156.2mb&amp;ndash;6倍。同样，Linkerd的最大代理CPU时间记录为36ms，而Istio为67ms&amp;ndash;大约多出85%。&lt;/p&gt;
&lt;p&gt;获胜者：Linkerd（26mb对156mb内存；36ms对67ms CPU）&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;grid&#34; srcset=&#34;
               /post/202112-linkerd-vs-istio-benchmarks-2021/images/grid_hu1d108da7752c2194ff3ecd5253d28b67_662835_afb8f048b10585366268e49599c59931.webp 400w,
               /post/202112-linkerd-vs-istio-benchmarks-2021/images/grid_hu1d108da7752c2194ff3ecd5253d28b67_662835_f1729a736db795313c598246e48325b6.webp 760w,
               /post/202112-linkerd-vs-istio-benchmarks-2021/images/grid_hu1d108da7752c2194ff3ecd5253d28b67_662835_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202112-linkerd-vs-istio-benchmarks-2021/images/grid_hu1d108da7752c2194ff3ecd5253d28b67_662835_afb8f048b10585366268e49599c59931.webp&#34;
               width=&#34;760&#34;
               height=&#34;552&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;总结和讨论&#34;&gt;总结和讨论&lt;/h3&gt;
&lt;p&gt;在这些旨在模仿现实世界场景行为的基准测试中，我们再次看到最新版本的Linkerd极大地超越了最新版本的Istio，同时保持了明显较小的资源成本。在评估的最高吞吐量下，我们看到Linkerd在数据面消耗了1/6的内存和55%的CPU，同时提供了Istio的1/3的额外中位延迟和1/8的额外最大延迟。&lt;/p&gt;
&lt;p&gt;值得注意的是，Linkerd在200RPS时的最差延迟比2000RPS时更差。这可能是由于实验过程中的网络干扰造成的。在未来，我们可能要改变异常值检测的标准；现在，为了透明起见，我们要按原样报告这些结果。&lt;/p&gt;
&lt;p&gt;将这些结果与近6个月前的早期实验结果相比较，有几个亮点非常突出：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;自2.10.1以来，Linkerd的中位延迟实际上有所改善，即使增加了策略。Linkerd的额外中位延迟在每个评估的流量水平上都持续降低了3ms。(最大延迟在一些运行中增加，在其他运行中减少）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Istio的数据平面CPU使用率从2000RPS时的88ms下降了67ms；然而，Istio的最大延迟似乎变得非常糟糕，在20、200和2000 RPS时分别增加了44ms、59ms和97ms。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Linkerd的数据平面比2.10更重，报告的最大CPU使用率为36ms（以前为11ms），最大内存使用率为26mb（以前为18mb）。特别是内存占用，在Linkerd 2.11.0和2.11.1之间发生了很大的变化，可能是由于在代理中使用了jemalloc分配器。事实上，用2.11.0（早一个发布点）重复这些基准测试显示，数据平面的平均内存占用为17mb，相差9mb！ （附注2）一种假设是，选择jemalloc分配器是为了在非常高的连接数下减少内存消耗，并允许代理在尖锐的负载中更容易释放内存；这可能是在这些基准测试中衡量的最大内存消耗的情况下的一种折衷。我们正在继续调查这一变化。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;为什么linkerd会这么快这么轻&#34;&gt;为什么Linkerd会这么快、这么轻？&lt;/h2&gt;
&lt;p&gt;和以前一样，Linkerd和Istio在性能和资源成本上的巨大差异主要归结于一件事：&lt;a href=&#34;https://linkerd.io/2020/12/03/why-linkerd-doesnt-use-envoy/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Linkerd基于Rust的&amp;quot;微代理&amp;rdquo;，Linkerd2-proxy&lt;/a&gt;。这个微代理为Linkerd的整个数据平面提供动力，而这个基准在很大程度上反映了它的性能和资源消耗。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://linkerd.io/2020/07/23/under-the-hood-of-linkerds-state-of-the-art-rust-proxy-linkerd2-proxy/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;我们已经写了很多关于Linkerd2-proxy的文章&lt;/a&gt;，以及我们&lt;a href=&#34;https://www.infoq.com/articles/linkerd-v2-production-adoption/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;在2018年的黑暗时代采用Rust的动机&lt;/a&gt;。有趣的是，构建Linkerd2-proxy的主要原因不是为了性能，而是为了运维上的原因：运维像Istio这样基于Envoy的服务网格，往往需要你成为运维Envoy的专家，这是我们不愿意强加给Linkerd用户的挑战（附注3）。&lt;/p&gt;
&lt;p&gt;令人高兴的是，选择建立Linkerd2-proxy也带来了显著的性能和效率提升。通过解决仅作为&amp;quot;服务网格代理&amp;quot;这一非常具体的问题，我们可以在数据平面层面上非常高效。通过在Rust中构建Linkerd2-proxy，我们可以借助这个生态系统中令人难以置信的技术投资浪潮：像Tokio、Hyper和Tower这样的库是一些世界上最好的系统思维和设计的焦点。&lt;/p&gt;
&lt;p&gt;Linkerd2-proxy不仅仅是令人难以置信的快速、轻便和安全，它还代表了整个CNCF领域中最前沿的技术。&lt;/p&gt;
&lt;h2 id=&#34;如何重现这些结果&#34;&gt;如何重现这些结果&lt;/h2&gt;
&lt;p&gt;如果你想自己重现这些实验，请按照&lt;a href=&#34;https://github.com/linkerd/linkerd2/wiki/Linkerd-Benchmark-Setup&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;基准测试&lt;/a&gt;的说明进行。&lt;/p&gt;
&lt;p&gt;如果你尝试这样做，请看我们&lt;a href=&#34;https://linkerd.io/2021/11/29/linkerd-vs-istio-benchmarks-2021/?utm_source=pocket_mylist#experimental-setup&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;上面关于实验方法的评论&lt;/a&gt;。关键是你要找到一个能够提供一致结果的环境，特别是对于像最大延迟这样对网络流量、资源争夺等非常敏感的东西。另外，请记住，你产生的数字将是相对的，而不是绝对的测量。&lt;/p&gt;
&lt;p&gt;并让我们知道你的发现!&lt;/p&gt;
&lt;h2 id=&#34;鸣谢&#34;&gt;鸣谢&lt;/h2&gt;
&lt;p&gt;特别感谢Equinix的好心人提供了Kubernetes环境，使这一切成为可能；感谢CNCF，它使Linkerd项目能够运行这些实验；感谢Kinvolk，尤其是Thilo Fromm，提供了优秀的基准工具。&lt;/p&gt;
&lt;h2 id=&#34;linkerd为所有人服务&#34;&gt;Linkerd为所有人服务&lt;/h2&gt;
&lt;p&gt;Linkerd是云原生计算基金会的一个毕业项目。Linkerd致力于开放管理。如果您有功能需求、问题或意见，我们很希望您能加入我们快速增长的社区。 Linkerd托管在GitHub上，我们在Slack、Twitter和邮件列表上有一个繁荣的社区。来吧，加入我们！&lt;/p&gt;
&lt;h2 id=&#34;附注&#34;&gt;附注&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;例如，本报告中诸如&amp;quot;Linkerd在中位数上增加了Xms的延迟&amp;quot;的陈述，并不意味着Linkerd会给您的应用增加Xms的中位数延迟。它们也不意味着单个Linkerd代理会增加Xms的延迟（事实上，对于大多数类型的流量，单个Linkerd代理的中位延迟小于1毫秒）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;报告这些数字是非常诱人的! 但是，&amp;ldquo;最新版本&amp;quot;意味着最新版本，而在这种情况下，这意味着Linkerd 2.11.1。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;从技术角度来看，代理可能是服务网格中最有趣的部分，但从用户的角度来看，它是最不有趣的部分。我们的信念是，服务网格的代理应该是一个实现细节，我们努力确保&amp;ndash;除了博客文章&amp;ndash;大多数Linkerd用户只需了解很少的Linkerd2-proxy。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>Dapr学习手册</title>
      <link>https://skyao.net/publication/202111-learning-dapr/</link>
      <pubDate>Wed, 24 Nov 2021 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/publication/202111-learning-dapr/</guid>
      <description>&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;cover&#34; srcset=&#34;
               /publication/202111-learning-dapr/images/cover_hu0498f605e84be359c957e75337478aad_343651_83d3f054fe2d7cadf87579d2b42c9024.webp 400w,
               /publication/202111-learning-dapr/images/cover_hu0498f605e84be359c957e75337478aad_343651_ddf6a36e073b53a6a87275a5d015af5b.webp 760w,
               /publication/202111-learning-dapr/images/cover_hu0498f605e84be359c957e75337478aad_343651_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/publication/202111-learning-dapr/images/cover_hu0498f605e84be359c957e75337478aad_343651_83d3f054fe2d7cadf87579d2b42c9024.webp&#34;
               width=&#34;760&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;书籍内容&#34;&gt;书籍内容&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;了解云原生应用的新编程模型。&lt;/li&gt;
&lt;li&gt;编写高性能的分布式应用，而无需深入技术细节。&lt;/li&gt;
&lt;li&gt;使用Dapr轻松编写基于任何语言或框架的微服务。&lt;/li&gt;
&lt;li&gt;了解Dapr如何通过开放的API，以及可扩展、社区驱动的组件来提供的一致性和可移植性。&lt;/li&gt;
&lt;li&gt;探索Dapr如何处理状态、资源绑定、以及发布/订阅来实现可伸缩、可扩展、事件驱动的架构。&lt;/li&gt;
&lt;li&gt;将各种SaaS产品的能力集成进云应用，比如机器学习。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;作者简介&#34;&gt;作者简介&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Haishi Bai是一位经验丰富的开发人员和架构师，拥有30多年的编程经验。他作为Microsoft Azure CTO办公室的成员领导了一系列云创新项目。同时他还是一位热情的教育家，出版了八本云计算相关书籍。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Yaron Schneider是Microsoft Azure CTO团队的首席软件工程师。他是一位狂热的开源倡导者和贡献者，主要致力于云原生技术。Yaron是KEDA（CNCF项目）和Osiris的原创作者之一。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;译者介绍&#34;&gt;译者介绍&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;罗毅 Apache Dubbo PMC主席，Dapr Steering and Technical committee(STC)成员，从事分布式中间件领域多年。&lt;/li&gt;
&lt;li&gt;曹胜利 Apache Dubbo PMC，Dapr Steering and Technical committee(STC)成员，从事多年微服务相关的基础建设工作。&lt;/li&gt;
&lt;li&gt;敖小剑 Servicemesh布道师，Dapr Approver，云原生爱好者和实践者。&lt;/li&gt;
&lt;li&gt;李志信 Apache Dubbo PMC，Dapr贡献者，从事Go语言中间件研发和开源工作。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;编辑推荐&#34;&gt;编辑推荐&lt;/h2&gt;
&lt;p&gt;获取关于Dapr（与现有的以及未来的编程语言一同工作的分布式应用运行时）的权威指南。该指南由模型的创建者亲自撰写，向你展示了Dapr是如何统一了无状态、有状态，以及actor编程模型，而且能够随处运行，无论是在云上还是在边缘。&lt;/p&gt;
&lt;p&gt;来自微软Azure CTO团队的作者Haishi Bai和Yaron Schneider解释说，你不需要在用户代码中包含任何SDK或者库。相反，你自动的获得了灵活的绑定、状态管理、actor模式、发布/订阅、可靠消息，以及许多其他的功能。本书面向开发人员、架构师、CIO、学生，以及计算机爱好者等人群介绍了如何入门Dapr.&lt;/p&gt;
&lt;h2 id=&#34;书籍介绍&#34;&gt;书籍介绍&lt;/h2&gt;
&lt;p&gt;2018 年秋，一个阴沉的下午，Boris Scholl、Yaron Schneider 和我（海石）在微软位于雷德蒙德校园的一个小电话室，讨论云应用程序的开发。当时，我们正在构想一个与平台无关的应用程序模型，使开发人员能独立于特定平台设计出分布式应用程序的拓扑。这个想法终成为开放应用程序模型（ &lt;a href=&#34;https://oam.dev&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://oam.dev&lt;/a&gt; ），该模型将应用程序描述为在软件定义的网格上相互连通的服务集合。&lt;/p&gt;
&lt;p&gt;这个应用程序模型并不关心每个服务是怎么编写的。当时，我认为提出一个统一的编程模型太有野心了。因此，我们试图严格定义一个将服务视为黑盒的应用程序模型。然而，当我们进一步讨论该想法时，似乎遗漏了一些东西。突然，Yaron 跳到白板前开始涂画。通过他模糊的书写，一个绝妙的主意浮出水面，他称之为Reaktive（带有k 的Reactive，这反映了 Yaron 对 Kubernetes的深厚感情）。 Reaktive 的核心思想很简单——通过边车容器或进程将分布式系统构件带给用户的代码。我们将在“简介”部分解释这个优雅而强大的想法是如何将这一新颖的思想带入分布式系统的设计和实现中。现在，我们继续故事的讲述。&lt;/p&gt;
&lt;p&gt;几天后，Yaron 带着原型回来了，我们都认为这很厉害。 Reaktive 为用户的代码带来了状态管理、服务发现以及与可靠消息传递等功能，并且不会用任何 SDK 或库来污染用户代码。它可以与任何编程语言一起使用（为了证明这一点，Yaron 甚至在之后做了 COBOL 的示例），并且它非常轻量。&lt;/p&gt;
&lt;p&gt;在接下来的几周中，我们三个人花了很多时间头脑风暴，添加或删除我们认为有意义或没必要的功能，在微软更大的技术场景下考量它，以及思考如何发布它。Boris 邀请了微软和其他公司的架构师和开发人员来进一步验证我们的想法，并获得了早期反馈。总体而言，我们三个人的方向似乎没错，因此我们将它介绍给了 Azure 的首席技术官 Mark Russinovich，他立刻喜欢上了我们的想法。他认为这个编程模型有可能对框架设计和分布式应用程序的开发产生深远和普遍的影响——这远超我们之前的想法。&lt;/p&gt;
&lt;p&gt;后来，Mark 提议我们将 Reaktive 改名为 Actions，即 Actor 和 Functions 的组合。该名称反映了新产品的核心价值主张：一个非侵入式编程模型，并且将无状态服务、有状态服务、函数和 actor 统一在一起。我们都喜欢这个名字，所以保留了它。&lt;/p&gt;
&lt;p&gt;一年过去了，Actions 经过了数月的开发、大量的讨论以及来自很多早期尝试者的验证。终，它准备好以新的名字 Dapr（https://dapr.io）—— 分布式应用运行时的缩写，在佛罗里达州奥兰多市的 Microsoft Ignite 主讲台上被公布于众。这是微软有史以来成功的开源项目之一。在初的24 小时内，该项目收集了 1000 多个 GitHub star，并且在短短几天内增速就超越了一些受欢迎的开源项目（见图1）。Star 的热度持续了几个星期，团队成员终于厌倦并停止了每隔几个小时就去检查一下的行为。&lt;/p&gt;
&lt;p&gt;很快我们就疲于奔命，社区贡献从四面八方涌来：合作伙伴的、竞争对手的、知名企业的，以及一些小公司的，每个人都在努力使 Dapr 变得更有用。这确实是开源好的地方。&lt;/p&gt;
&lt;p&gt;巧合的是，O’Reilly 的 Kathleen Carr 通过 LinkedIn 联系上了我，询问我是否有出书的想法。 我提出了写《Actions in Action》这本书的想法。 这是一个大胆的提议：写一些仍在酝酿中的东西。Kathleen 依然很喜欢这个主意。几周后，我们签署了一份合同，将这本介绍 Actions （现在叫 Dapr）的书籍带给大家。&lt;/p&gt;
&lt;p&gt;你正在阅读本书的事实证明了冒险是值得的。无论 Dapr 未来发生什么，你都在这里，我们也很高兴你在这里。&lt;/p&gt;
&lt;p&gt;资源：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dapr 主页 (&lt;a href=&#34;https://dapr.io&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://dapr.io&lt;/a&gt;)。&lt;/li&gt;
&lt;li&gt;Dapr 运行时仓库 (&lt;a href=&#34;https://oreil.ly/SRqme&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://oreil.ly/SRqme&lt;/a&gt;)。&lt;/li&gt;
&lt;li&gt;Dapr 文档仓库 (&lt;a href=&#34;https://oreil.ly/MlQfS&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://oreil.ly/MlQfS&lt;/a&gt;)。&lt;/li&gt;
&lt;li&gt;Dapr 示例仓库 (&lt;a href=&#34;https://oreil.ly/7JBHH&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://oreil.ly/7JBHH&lt;/a&gt;)。&lt;/li&gt;
&lt;li&gt;Dapr 组件贡献仓库 (&lt;a href=&#34;https://oreil.ly/lVk5V&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://oreil.ly/lVk5V&lt;/a&gt;)。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /publication/202111-learning-dapr/images/info-1_hu24de8cf4662c041e2ab0e2a83219c6af_187211_76ee1d53647ba05b83ff321e720e5046.webp 400w,
               /publication/202111-learning-dapr/images/info-1_hu24de8cf4662c041e2ab0e2a83219c6af_187211_46030d2e60fc22b224d5aab93a6447af.webp 760w,
               /publication/202111-learning-dapr/images/info-1_hu24de8cf4662c041e2ab0e2a83219c6af_187211_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/publication/202111-learning-dapr/images/info-1_hu24de8cf4662c041e2ab0e2a83219c6af_187211_76ee1d53647ba05b83ff321e720e5046.webp&#34;
               width=&#34;474&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /publication/202111-learning-dapr/images/info-2_huff5707d37a274a8cb162a2866482176d_145835_2070ab4a9929696a685b37057c4a4538.webp 400w,
               /publication/202111-learning-dapr/images/info-2_huff5707d37a274a8cb162a2866482176d_145835_c4cf188bcec4c7c4bc9439fc3ebf808f.webp 760w,
               /publication/202111-learning-dapr/images/info-2_huff5707d37a274a8cb162a2866482176d_145835_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/publication/202111-learning-dapr/images/info-2_huff5707d37a274a8cb162a2866482176d_145835_2070ab4a9929696a685b37057c4a4538.webp&#34;
               width=&#34;659&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /publication/202111-learning-dapr/images/info-3_hu870a2edc56724ee7bf56890787dd1877_118547_729bdfac86b4a35c67f78b3b833907ac.webp 400w,
               /publication/202111-learning-dapr/images/info-3_hu870a2edc56724ee7bf56890787dd1877_118547_51c97d1dd733abc609915a7efed3b671.webp 760w,
               /publication/202111-learning-dapr/images/info-3_hu870a2edc56724ee7bf56890787dd1877_118547_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/publication/202111-learning-dapr/images/info-3_hu870a2edc56724ee7bf56890787dd1877_118547_729bdfac86b4a35c67f78b3b833907ac.webp&#34;
               width=&#34;679&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /publication/202111-learning-dapr/images/info-4_hud703fefc383fb66a2968aecaeacdac5a_164388_5bdf9ffbb4a29910bb495a398acd5f80.webp 400w,
               /publication/202111-learning-dapr/images/info-4_hud703fefc383fb66a2968aecaeacdac5a_164388_0e8cd53e1b29a4a6b7f9b7d2f250f337.webp 760w,
               /publication/202111-learning-dapr/images/info-4_hud703fefc383fb66a2968aecaeacdac5a_164388_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/publication/202111-learning-dapr/images/info-4_hud703fefc383fb66a2968aecaeacdac5a_164388_5bdf9ffbb4a29910bb495a398acd5f80.webp&#34;
               width=&#34;394&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /publication/202111-learning-dapr/images/info-5_hu4ff482cd199473ce0c2c4827dd28b59c_197152_2aac460b3acc5b8d1fc943c50334533a.webp 400w,
               /publication/202111-learning-dapr/images/info-5_hu4ff482cd199473ce0c2c4827dd28b59c_197152_b2e1e00288d751fa1653cb1c3339f2fb.webp 760w,
               /publication/202111-learning-dapr/images/info-5_hu4ff482cd199473ce0c2c4827dd28b59c_197152_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/publication/202111-learning-dapr/images/info-5_hu4ff482cd199473ce0c2c4827dd28b59c_197152_2aac460b3acc5b8d1fc943c50334533a.webp&#34;
               width=&#34;352&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;内容预览&#34;&gt;内容预览&lt;/h2&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;目录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;前言 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第0 章 简介 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.1 什么是 Dapr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.1.1 异构环境的编程模型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.1.2 更多的帮助，更少的倾向 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.1.3 不要重复造轮子！ &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.1.4 统一的编程模型 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.2 Dapr 的架构 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;语言支持 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.3 开始使用 Dapr &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.3.1 Dapr 独立模式下的 Hello world ！ &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.3.2 Dapr Kubernetes 模式下的 Hello world &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.4 使用 gRPC &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.4.1 从 gRPC 客户端调用应用程序 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.4.2 编写 gRPC 服务器 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.5 绑定 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.5.1 独立模式下的绑定 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.5.2 Kubernetes 模式下的绑定&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;0.6 小结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第1 章 服务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.1 在云出现之前&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.2 云的承诺与挑战&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.2.1 可用性&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.2.2 弹性&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.2.3 云原生应用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.2.4 基础设施是乏味的&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.3 服务调用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.3.1 名称解析&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.3.2 请求和应答&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.3.3 并发控制&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.3.4 服务调用练习&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.3.5 通用命名空间&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.4 发布/订阅&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.4.1 基于消息的集成的好处&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.4.2 用Dapr 进行发布/订阅&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.4.3 发布/ 订阅的工作方式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.5 Dapr 组件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.5.1 Dapr 配置&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.5.2 自定义管道&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.5.3 自定义管道练习&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.5.4 OAuth 2.0 授权&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.5.5 编写自定义中间件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.6 分布式追踪&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.6.1 追踪中间件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.6.2 使用Zipkin 追踪&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.6.3 使用Azure Monitor 跟踪&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.7 服务运维&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.7.1 服务部署与升级&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.7.2 OAM&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;1.8 小结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第2 章 状态&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.1 状态管理&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.1.1 无状态与有状态&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.1.2 为什么无状态服务在云端更受欢迎？&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.1.3 托管有状态服务的挑战&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.1.4 将有状态服务转换为无状态服务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.2 Dapr 状态管理&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.2.1 并发模型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.2.2 一致性模型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.2.3 批量操作和事务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.2.4 多状态存储&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.2.5 重试策略&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.3 Dapr State API&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.3.1 Key 方案&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.3.2 Get 请求&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.3.3 Set 请求&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.3.4 Delete 请求&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.3.5 事务性请求&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.4 使用Dapr State API&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.4.1 数据处理的考虑因素&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.4.2 数据查询和聚合&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.5 状态存储&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.5.1 Redis &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.5.2 Azure Cosmos DB &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.5.3 etcd &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.5.4 Apache Cassandra &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.5.5 Couchbase &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.6 自定义状态存储 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.6.1 实现 State API &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.6.2 更新组件注册表 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;2.7 小结 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第3 章 消息 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.1 事件驱动编程 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.1.1 消息与事件的对比 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.1.2 输入绑定和输出绑定 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.1.3 Pub/Sub &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.2 Pub/Sub with Dapr &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.2.1 实现 Powershell 脚本 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.2.2 使用Dapr CLI 测试发布/ 订阅 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.2.3 Dapr 发布/ 订阅行为 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.2.4 扩展 Dapr Pub/Sub &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.3 使用Dapr 进行输入和输出绑定 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.3.1 使用输入绑定 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.3.2 使用输出绑定 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.3.3 实现输入绑定 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.3.4 实现输出绑定 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.3.5 使用KEDA 自动缩放 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.4 消息传递模式 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.4.1 Saga 模式 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.4.2 基于内容的路由 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.4.3 路由清单 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.4.4 智能代理 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.4.5 MapReduce &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;3.5 小结 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第4 章 安全 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;4.1 保护分布式应用程序 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;4.1.1 访问控制 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;4.1.2 数据保护 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;4.1.3 安全通信 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;4.1.4 入侵与异常检测 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;4.2 Dapr 安全功能 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;4.2.1 密钥存储 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;4.2.2 实现密钥存储 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;4.2.3 Secret API &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;4.2.4 Mutual TLS (mTLS) &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;4.2.5 Dapr mTLS&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;4.3 小结 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第5 章 Actor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;5.1 Actor 模式 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;5.1.1 现代 Actor 框架&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;5.1.2 Actor 模型的误用 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;5.2 Dapr 与 Actor &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;5.2.1 调用一个 Dapr Actor &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;5.2.2 状态管理 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;5.2.3 计时器 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;5.2.4 Reminder &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;5.3 开始使用 Dapr Actors for C# &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;5.3.1 定义 Actor 接口 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;5.3.2 实现 Actor 接口 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;5.4 小结 . 173&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第6 章 应用模式 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;6.1 云原生应用 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;6.1.1 云上环境 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;6.1.2 基于 Dapr 的云原生应用 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;6.2 使用 Dapr 进行系统集成 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;6.2.1 使用分布式工作流构建有限状态机 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;6.2.2 同步 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;6.3 更大生态系统中的 Dapr &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;6.3.1 Yeoman Dapr 生成器 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;6.3.2 在 Visual Studio Code 中使用 Dapr &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;6.3.3 在 ASP.NET Core 中使用 Dapr &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;6.3.4 更大应用中的 Dapr &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;6.3.5 Dapr 和服务网格 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;6.4 边缘场景中的 Dapr&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;6.5 小结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第7 章 Dapr 的未来&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.1 能力交付&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.1.1 架构&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.1.2 应用场景&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.2 增强的 Actor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.2.1 聚合器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.2.2 查询接口&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.2.3 Actor 图 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.2.4 多版本 Actor &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.2.5 Actor 中间件 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.3 通用命名空间 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.3.1 架构 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.3.2 应用场景 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.4 边缘场景中的 Dapr &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.4.1 作为轻量级函数运行时的 Dapr &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.4.2 WebAssembly 中的 Dapr &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.4.3 作为脚本的 Dapr &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.5 Dapr 的其他改进 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.5.1 Dapr 组件投影 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.5.2 实践和经过验证的模式 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.5.3 Dapr 描述符 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.5.4 Dapr 对多方计算的促进 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;7.6 小结 &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
    </item>
    
    <item>
      <title>死生之地不可不察：论API标准化对Dapr的重要性</title>
      <link>https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/</link>
      <pubDate>Thu, 11 Nov 2021 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/</guid>
      <description>&lt;h2 id=&#34;快速回顾什么是dapr&#34;&gt;快速回顾：什么是Dapr？&lt;/h2&gt;
&lt;p&gt;Dapr 的全称是 &amp;ldquo;Distributed Application Runtime&amp;rdquo;，即 &amp;ldquo;分布式应用运行时&amp;rdquo;。Dapr 是一个开源项目，由微软发起，目前正在申请成为CNCF孵化器项目。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/dapr-logo_hu5806307ad54136ee489dfd9315402be8_12299_13194a281c432d1208823c5e5daff2db.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/dapr-logo_hu5806307ad54136ee489dfd9315402be8_12299_0c5e150fb19bed4e35e6b15af071b4f5.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/dapr-logo_hu5806307ad54136ee489dfd9315402be8_12299_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/dapr-logo_hu5806307ad54136ee489dfd9315402be8_12299_13194a281c432d1208823c5e5daff2db.webp&#34;
               width=&#34;272&#34;
               height=&#34;275&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;本文是 Dapr 的进阶内容分享和讨论，因此在本文中我假定读者对 &lt;strong&gt;Dapr&lt;/strong&gt; 已有初步的了解，如果之前没有接触过 Dapr，建议在阅读本文之前先阅读这篇 Dapr 的介绍文章：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dapr v1.0展望：从servicemesh到云原生&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在这里我们对 Dapr 进行一个快速而简单的介绍。首先来看ServiceMesh，和传统RPC框架相比，servicemesh的创新之处在于引入了 Sidecar 模式：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/sidecar-pattem_hu15d4860b6220d981fe979fc13bc6b5b1_77742_5c6ebd72a13797fcbdf951c1f8299700.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/sidecar-pattem_hu15d4860b6220d981fe979fc13bc6b5b1_77742_c7b05debca4daee9a8257e367e05c438.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/sidecar-pattem_hu15d4860b6220d981fe979fc13bc6b5b1_77742_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/sidecar-pattem_hu15d4860b6220d981fe979fc13bc6b5b1_77742_5c6ebd72a13797fcbdf951c1f8299700.webp&#34;
               width=&#34;760&#34;
               height=&#34;369&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而 Servicemesh 只解决了服务间通讯的需求，而现实中的分布式应用存在更多的需求，Multi-Runtime 理论将这些需求归结为四大类：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/four-requirements-of-distributed-app_hu34af877979b60d118c99d418652dcf15_433029_5c3e8533fbd776349f85e32fe68e2ca2.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/four-requirements-of-distributed-app_hu34af877979b60d118c99d418652dcf15_433029_766c442e60c535ebbb041e7c33a7423c.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/four-requirements-of-distributed-app_hu34af877979b60d118c99d418652dcf15_433029_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/four-requirements-of-distributed-app_hu34af877979b60d118c99d418652dcf15_433029_5c3e8533fbd776349f85e32fe68e2ca2.webp&#34;
               width=&#34;760&#34;
               height=&#34;359&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在 Servicemesh 初步成功，Sidecar 模式被云原生社区普遍接受之后，效仿 Servicemesh，将应用需要的其他分布式能力外移到各种 Runtime 变成为一个趋势。这些 Runtime 会逐渐整合，最后和应用 Runtime 共同组成微服务，形成所谓的 &amp;ldquo;Multi-Runtime&amp;rdquo; 架构，又称 Mecha：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/multi-runtime-theory-derivation_hu3ea55c8225538492d89ec2fe468c1e95_1705253_72c65566fc452e4acaf3395bb5284641.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/multi-runtime-theory-derivation_hu3ea55c8225538492d89ec2fe468c1e95_1705253_6828910a64fabd328d980f6b7f2654cc.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/multi-runtime-theory-derivation_hu3ea55c8225538492d89ec2fe468c1e95_1705253_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/multi-runtime-theory-derivation_hu3ea55c8225538492d89ec2fe468c1e95_1705253_72c65566fc452e4acaf3395bb5284641.webp&#34;
               width=&#34;760&#34;
               height=&#34;272&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Dapr 项目是目前业界第一个 Multi-Runtime  / Mecha 实践项目，下图来自 Dapr 官方，比较完善的概括了 Dapr 的能力和层次架构：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/dapr-overview-and-vision_hu612844ef2590eebecd233377b1953376_1040125_d166e463c51c3c837296f96c07216c77.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/dapr-overview-and-vision_hu612844ef2590eebecd233377b1953376_1040125_62bca57755d6192238c6ffa3cc6ea1e1.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/dapr-overview-and-vision_hu612844ef2590eebecd233377b1953376_1040125_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/dapr-overview-and-vision_hu612844ef2590eebecd233377b1953376_1040125_d166e463c51c3c837296f96c07216c77.webp&#34;
               width=&#34;760&#34;
               height=&#34;359&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Dapr 的愿景：any language, any framework, anywhere。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;划重点: 请特别注意这里的 &lt;strong&gt;anywhere&lt;/strong&gt; 一词，这是 Dapr 的核心价值之一，本文后面要对此详细展开。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;本质差异dapr-vs-servicemesh&#34;&gt;本质差异：Dapr vs ServiceMesh&lt;/h2&gt;
&lt;p&gt;在快速回顾完成 Dapr 之后，我们来正式展开本文的内容。首先需要回答这样一个问题：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dapr 和 ServiceMesh 有什么区别？&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&#34;核心都是sidecar模式&#34;&gt;核心都是Sidecar模式&lt;/h3&gt;
&lt;p&gt;这个问题也是大多数读者在了解 Dapr 之后最常问到的一个问题，原因是 Dapr 和 Servicemesh 在架构上实在太像了，都是以 Sidecar 模式为核心：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/sidecar-pattem_hu15d4860b6220d981fe979fc13bc6b5b1_77742_5c6ebd72a13797fcbdf951c1f8299700.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/sidecar-pattem_hu15d4860b6220d981fe979fc13bc6b5b1_77742_c7b05debca4daee9a8257e367e05c438.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/sidecar-pattem_hu15d4860b6220d981fe979fc13bc6b5b1_77742_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/sidecar-pattem_hu15d4860b6220d981fe979fc13bc6b5b1_77742_5c6ebd72a13797fcbdf951c1f8299700.webp&#34;
               width=&#34;760&#34;
               height=&#34;369&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Dapr 的基本思路也是和 Servicemesh 保持一致：通过引入 sidecar来实现 &lt;strong&gt;关注点分离&lt;/strong&gt; + &lt;strong&gt;独立维护&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/mesh-basic-prinsiple_hubb4421e974d3af75bf0caf46fdf2c17b_255317_7a3e7d38c1216c67e1d419061bccd14e.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/mesh-basic-prinsiple_hubb4421e974d3af75bf0caf46fdf2c17b_255317_8b75d9c548e4096acb6264159be8c424.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/mesh-basic-prinsiple_hubb4421e974d3af75bf0caf46fdf2c17b_255317_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/mesh-basic-prinsiple_hubb4421e974d3af75bf0caf46fdf2c17b_255317_7a3e7d38c1216c67e1d419061bccd14e.webp&#34;
               width=&#34;760&#34;
               height=&#34;250&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;dapr有更多的功能和使用场景&#34;&gt;Dapr有更多的功能和使用场景&lt;/h3&gt;
&lt;p&gt;Dapr 和 Servicemesh 最明显的不同之处是 &lt;strong&gt;Dapr 的场景比 Servicemesh 要复杂&lt;/strong&gt;: Servicemesh关注于服务间通讯，即下图中虚线部分；而 Dapr 除了服务间通讯之外，还适用于诸多其他的场景，如状态存储、消息的发布订阅、资源绑定、配置等。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/dapr-vs-servicemesh_hu18d0a66b1928ffb0b658727cc751def4_158683_494666d57fd6ffa6bb9443b3561eb331.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/dapr-vs-servicemesh_hu18d0a66b1928ffb0b658727cc751def4_158683_2a8f8774fd0c9e44ae326579b5785301.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/dapr-vs-servicemesh_hu18d0a66b1928ffb0b658727cc751def4_158683_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/dapr-vs-servicemesh_hu18d0a66b1928ffb0b658727cc751def4_158683_494666d57fd6ffa6bb9443b3561eb331.webp&#34;
               width=&#34;760&#34;
               height=&#34;344&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;下图是 Dapr 目前已有的构建块和他们提供的能力的简单描述（其中 Service Invocation 对应 Servicemesh 的服务间通讯能力）：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/dapr-8-building-blocks_huc57195030e34e0468882f925cc4bee9d_819120_00de7f76927c361091f6d7f3666c6914.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/dapr-8-building-blocks_huc57195030e34e0468882f925cc4bee9d_819120_e298d218b75600a7fb11ef0fad3fd641.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/dapr-8-building-blocks_huc57195030e34e0468882f925cc4bee9d_819120_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/dapr-8-building-blocks_huc57195030e34e0468882f925cc4bee9d_819120_00de7f76927c361091f6d7f3666c6914.webp&#34;
               width=&#34;760&#34;
               height=&#34;412&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;本质差异在于工作模式&#34;&gt;本质差异在于工作模式&lt;/h3&gt;
&lt;p&gt;功能的差异是很直白的，容易理解。但是，如果只是功能上的差异，那么问题来了：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如果 Servicemesh 也提供同样的能力，是不是就和 Dapr 一样了？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们来看 Envoy 的功能，Envoy 原生支持 HTTP1.1/REST 和 HTTP2 / gRPC 协议，社区增加了对 Dubbo、Thrift 等RPC协议的支持，而 Envoy 也在提供对 Kafka、Redis 等原生协议的支持，未来 Envoy 提供更多原生协议支持也是可以预期的。那是不是意味着随着功能的增加，以 Envoy、Istio 为代表的 Servicemesh 就和 Dapr 一样了呢？&lt;/p&gt;
&lt;p&gt;答案当然是否定的—— Dapr 和 Servicemesh 的本质差异在于其&lt;strong&gt;工作模式&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Servicemesh 的工作模式是&lt;strong&gt;原协议转发&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/servicemesh-work-model_hu942aaedff89646e73b3bc5ea51baf1eb_60092_5f5d71c6caad13503297936dd0481bd9.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/servicemesh-work-model_hu942aaedff89646e73b3bc5ea51baf1eb_60092_63f021d708fed6fd90e165e729c39d15.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/servicemesh-work-model_hu942aaedff89646e73b3bc5ea51baf1eb_60092_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/servicemesh-work-model_hu942aaedff89646e73b3bc5ea51baf1eb_60092_5f5d71c6caad13503297936dd0481bd9.webp&#34;
               width=&#34;760&#34;
               height=&#34;441&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Servicemesh 的 Sidecar 接收到是 app 发出的原生协议的请求，然后转发给另一端的 Sidecar 进而转发给目标 app；或者，对于 redis/kafka 等的支持是 Sidecar 将原协议转发给 redis/kafka 服务器。&lt;/p&gt;
&lt;p&gt;在这个过程中，Servicemesh 的 Sidecar 原则上不修改协议，只做&lt;strong&gt;转发&lt;/strong&gt;（&amp;ldquo;Forwarding&amp;rdquo;），Sidecar 扮演的是&lt;strong&gt;代理&lt;/strong&gt;（&amp;ldquo;Proxy&amp;rdquo;）的角色。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dapr 的工作模式是&lt;strong&gt;能力抽象&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/dapr-work-model_hu81956c8ff86b1a824261296ca1ae32c1_64677_4774efa22efbb3eca385ba604e125416.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/dapr-work-model_hu81956c8ff86b1a824261296ca1ae32c1_64677_5505a998dc6438a006749754ed038610.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/dapr-work-model_hu81956c8ff86b1a824261296ca1ae32c1_64677_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/dapr-work-model_hu81956c8ff86b1a824261296ca1ae32c1_64677_4774efa22efbb3eca385ba604e125416.webp&#34;
               width=&#34;760&#34;
               height=&#34;370&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Dapr Sidecar 接收到是 app 发出的遵从标准API的请求，这些标准API对能力进行了抽象；对于服务间通讯的场景，Sidecar 会将请求转发给另一端的 Sidecar；对于服务间通讯之外的能力的支持则需要将标准API转换为底层组件对应的原生协议。&lt;/p&gt;
&lt;p&gt;在这个过程中，Sidecar 原则上对应用只暴露抽象之后的分布式能力，屏蔽了底层具体的实现和通讯协议，不做&amp;quot;转发&amp;quot;而是提供&amp;quot;能力&amp;quot;，sidecar 扮演的是&lt;strong&gt;运行时&lt;/strong&gt;(&amp;ldquo;Runtime&amp;rdquo;) 的角色。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;设计目标不同dapr强调可移植性&#34;&gt;设计目标不同：Dapr强调可移植性&lt;/h3&gt;
&lt;p&gt;工作模式不同的背后，反应的是 Dapr 和 Servicemesh 在设计目标上的差异：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Servicemesh 的主要设计目标是 &lt;strong&gt;低侵入&lt;/strong&gt;，采用原协议转发的方式可以尽可能的降低对应用的侵入，为了达到无侵入的目标甚至采用了流量劫持的方式。&lt;/li&gt;
&lt;li&gt;Dapr 的主要设计目标是 &lt;strong&gt;可移植性&lt;/strong&gt;，即在跨云跨平台的前提下实现无厂商绑定，采用的方式是在将分布式能力抽象为标准API，并在各种开源项目和云平台上提供这套标准API的不同实现，从而达到在不同平台上运行的目标，这即 Dapr 愿景中的 &amp;ldquo;&lt;strong&gt;anywhere&lt;/strong&gt;&amp;rdquo;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总结一下 Dapr 和 Servicemesh 的差异以及适用场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Servicemesh 强调对应用无侵入，支持原协议转发和流量劫持，不仅仅适用于新应用，相比 Dapr 也更加适用于老应用。&lt;/li&gt;
&lt;li&gt;Dapr 提供 &amp;ldquo;标准API&amp;rdquo;、&amp;ldquo;语言SDK&amp;rdquo; 和 &amp;ldquo;Runtime&amp;rdquo;，需要应用进行适配（这意味着老应用需要进行改造），侵入性比较大。因此 Dapr 更适合新应用开发 （所谓 Green Field），对于现有的老应用（所谓 Brown Field）则需要付出较高的改造代价。但在付出这些代价之后，Dapr 就可以提供跨云跨平台的可移植性，这是 Dapr 的核心价值之一。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，在决策是否该采用 Dapr 时，可移植性是一个非常关键的考虑因素。&lt;/p&gt;
&lt;h2 id=&#34;死生之地api标准化的价值&#34;&gt;死生之地：API标准化的价值&lt;/h2&gt;
&lt;p&gt;在上一篇文章 &lt;a href=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dapr v1.0展望：从servicemesh到云原生&lt;/a&gt;  中，我曾经指出：Dapr 的本质是面向云原生应用的 &lt;strong&gt;分布式能力抽象层&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/nature-of-multi-runtime_hud23b41a33a32b215b19ef445300fe136_476076_c5690170b0fdfcc0f183e5a3eb72b780.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/nature-of-multi-runtime_hud23b41a33a32b215b19ef445300fe136_476076_68285c1e80602ecc6f5ab1d084793d30.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/nature-of-multi-runtime_hud23b41a33a32b215b19ef445300fe136_476076_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/nature-of-multi-runtime_hud23b41a33a32b215b19ef445300fe136_476076_c5690170b0fdfcc0f183e5a3eb72b780.webp&#34;
               width=&#34;760&#34;
               height=&#34;302&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而在上一节我们也刚刚认识到 &lt;strong&gt;可移植性&lt;/strong&gt; 是 Dapr 的重要目标和核心价值。Dapr 的愿景， &amp;ldquo;any language, any framework, &lt;strong&gt;anywhere&lt;/strong&gt;&amp;quot;，这里的 anywhere 包括：&lt;/p&gt;
&lt;ul&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;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;而 Dapr 可移植性的基石在于 &lt;strong&gt;标准 API&lt;/strong&gt; + &lt;strong&gt;可拔插可替换的组件&lt;/strong&gt;，下面这张来自 Dapr 官方网站的图片非常形象的展示了 Dapr 的这一特性：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/plugable-components_hu0c1e7e6be532a8ca124fcb9038b9bdef_837716_6b737faa99a2a48e5a69ee8e0faa0bd0.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/plugable-components_hu0c1e7e6be532a8ca124fcb9038b9bdef_837716_c7830a83d3d4108f3fe16f9cfe0b90f2.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/plugable-components_hu0c1e7e6be532a8ca124fcb9038b9bdef_837716_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/plugable-components_hu0c1e7e6be532a8ca124fcb9038b9bdef_837716_6b737faa99a2a48e5a69ee8e0faa0bd0.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;从架构设计的角度看，Dapr 的精髓在于：通过&lt;strong&gt;抽象/隔离/可替换&lt;/strong&gt;，&lt;strong&gt;解耦能力和实现&lt;/strong&gt;，从而实现可移植性。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/deep-into-dapr_hufbeaf90fcfe6a6b843b003123c6e38da_129954_273966515d306929ace6d60ef7b23f40.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/deep-into-dapr_hufbeaf90fcfe6a6b843b003123c6e38da_129954_facf81f69aa077910162de52034a8b64.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/deep-into-dapr_hufbeaf90fcfe6a6b843b003123c6e38da_129954_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/deep-into-dapr_hufbeaf90fcfe6a6b843b003123c6e38da_129954_273966515d306929ace6d60ef7b23f40.webp&#34;
               width=&#34;760&#34;
               height=&#34;301&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在传统的应用开发方式中，应用需要面向具体的实现编程，即当应用需要使用到某个能力时，就需要找到能提供该能力的底层组件，如上图中的 redis / consul / memcached / zookeeper 都可以提供分布式状态的存储能力。应用在选择具体组件之后，就需要针对该组件进行编程开发，典型如引入该组件的客户端SDK，然后基于这些SDK实现需要的分布式能力，如缓存、状态、锁、消息通讯等具体功能。&lt;/p&gt;
&lt;p&gt;而在 Dapr 中，Dapr 倡导 &amp;ldquo;&lt;strong&gt;面向能力编程&lt;/strong&gt;&amp;quot;，即：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Dapr API 提供了对分布式能力的&lt;strong&gt;抽象&lt;/strong&gt;，并提取为标准API&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dapr 的 Runtime &lt;strong&gt;隔离&lt;/strong&gt; 应用和底层组件的具体实现&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;而这些组件都是&lt;strong&gt;可替换&lt;/strong&gt;的，可以在运行时才进行绑定。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dapr 通过这样的方式，实现了能力和实现的解耦，并给出了一个美好的愿景：在有一个业界普遍认可并遵循的标准化API的基础上，用户可以自由选择编程语言开发云原生，这些云原生可以在不同的平台上运行，不被厂商和平台限制——终极目标是使得云原生应用真正具备跨云跨平台的可移植性。&lt;/p&gt;
&lt;p&gt;理想很美好，但现实依然残酷：和 Servicemesh 相比，Dapr 在落地时存在一个无可回避的问题——应用改造是有成本的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/servicemesh-vs-dapr_hu9b44204ba9cee2d3d922307f906859ff_58160_3794fa1bb654e66fe91b527b6b99d951.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/servicemesh-vs-dapr_hu9b44204ba9cee2d3d922307f906859ff_58160_f240321d166346d9c8a81d816b264063.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/servicemesh-vs-dapr_hu9b44204ba9cee2d3d922307f906859ff_58160_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/servicemesh-vs-dapr_hu9b44204ba9cee2d3d922307f906859ff_58160_3794fa1bb654e66fe91b527b6b99d951.webp&#34;
               width=&#34;760&#34;
               height=&#34;314&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;从落地的角度来看， Servicemesh 的低侵入性使得应用在迁移到 Servicemesh 时无需太大的改动，只需要像往常一样向 sidecar 发出原生协议的请求即可，甚至在流量劫持的帮助下可以做到应用完全无感知。从工作模式上说，基于原生协议转发的 Servicemesh 天然对旧有应用友好。而 Dapr 出于对可移植性目标的追求，需要为应用提供一个标准的分布式能力抽象层来屏蔽底层分布式能力的具体实现方式，应用需要基于这个抽象层进行开发，才能获得跨云跨平台无厂商绑定等可移植性方面的收益。因此，在 Dapr 落地过程中，新应用需要基于 Dapr API 全新开发，老应用则不可避免的需要进行改造以对接 Dapr API。&lt;/p&gt;
&lt;p&gt;API 标准化是 Dapr 成败的关键，为 Dapr 的发展建立起良性循环：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/loop_hue8b63ab091cc1d9e0e203537acbaafd2_72312_e7131f38720c8e4d17d8b2bfce4453a7.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/loop_hue8b63ab091cc1d9e0e203537acbaafd2_72312_8baf9e8cae7928d2279cea5cf0131b34.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/loop_hue8b63ab091cc1d9e0e203537acbaafd2_72312_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/loop_hue8b63ab091cc1d9e0e203537acbaafd2_72312_e7131f38720c8e4d17d8b2bfce4453a7.webp&#34;
               width=&#34;420&#34;
               height=&#34;427&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;API 标准化&lt;/p&gt;
&lt;p&gt;定义 Dapr API，对某一个分布式能力进行良好的抽象，覆盖日常使用的大部分场景，满足应用的常见需求。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;提供组件支持&lt;/p&gt;
&lt;p&gt;基于标准 Dapr API ，为开源产品和公有云商业产品提供支持组件，覆盖主流产品和厂商&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;具备可移植性&lt;/p&gt;
&lt;p&gt;基于标准 Dapr API 开发的应用，可以在主流开源产品和公有云商业产品之间自行选择适合的组件，不受平台和厂商的限制&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;API 得到更多认可&lt;/p&gt;
&lt;p&gt;可移植性为 Dapr 构建核心价值，Dapr API 得到更多的认可，逐渐成为业界的事实标准&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;更广泛的组件支持&lt;/p&gt;
&lt;p&gt;Dapr API 越接近业界标准，就会有越多的产品和厂商愿意提供支持 Dapr API 的组件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可移植性更强&lt;/p&gt;
&lt;p&gt;越来越多的组件支持，可以覆盖更多的开源产品和厂商，从而更接近 anywhere 的愿景&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;理想情况下，&amp;ldquo;标准化&amp;rdquo; / &amp;ldquo;组件支持&amp;rdquo; / &amp;ldquo;可移植性&amp;rdquo; 之间的相互促进和支撑将成为 Dapr 发展源源不断的动力。反之，如果 API 标准化出现问题，则组件的支持必然受影响，大大削弱可移植性，Dapr 存在的核心价值将受到强烈挑战。&lt;/p&gt;
&lt;h2 id=&#34;左右为难取舍之间何去何从&#34;&gt;左右为难：取舍之间何去何从&lt;/h2&gt;
&lt;p&gt;既然 API 标准化如此重要，那 Dapr 该如何去定义 API 并推动其标准化呢？我们以 Dapr State API 为例，介绍在 API 定义和标准化过程中常见的问题。&lt;/p&gt;
&lt;h3 id=&#34;state-api的基本定义&#34;&gt;State API的基本定义&lt;/h3&gt;
&lt;p&gt;State 形式上是 key-value 存储，即状态信息被序列化为 byte[] 然后以 value 的形式存储并关联到 key，当然实践中非 kv 存储也可以实现 State 的功能，比如 mysql 等关系型数据库。Dapr 的 State API 的定义非常简单明了，除了基于key的CRUD基本操作外，还有CRUD的批量操作，以及一个原子执行多个操作的事务操作：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;rpc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;GetState&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GetStateRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;returns&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GetStateResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;rpc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;GetBulkState&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GetBulkStateRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;returns&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GetBulkStateResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;rpc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;SaveState&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SaveStateRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;returns&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;google.protobuf.Empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;rpc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;DeleteState&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;DeleteStateRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;returns&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;google.protobuf.Empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;rpc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;DeleteBulkState&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;DeleteBulkStateRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;returns&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;google.protobuf.Empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;rpc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ExecuteStateTransaction&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ExecuteStateTransactionRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;returns&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;google.protobuf.Empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上述 API 定义貌似非常简单，毕竟kv基本操作的语义非常容易理解。但是，一旦各种高级特性陆续加入之后，API 就会逐渐复杂：数据一致性 / 并发保护 / 过期时间 / 批量操作等。&lt;/p&gt;
&lt;h3 id=&#34;state-api的高级特性&#34;&gt;State API的高级特性&lt;/h3&gt;
&lt;p&gt;以 GetState() 为例，我们展开 GetStateRequest 和 GetStateResponse 这两个消息的定义，了解一下数据一致性 / 并发保护这两个高级特性：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/getstate-api_hufb328c2f450c520ebcacf95445f29597_328007_30c8ee37397d4435c5a40c44f37883a7.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/getstate-api_hufb328c2f450c520ebcacf95445f29597_328007_32a6320f0421429704ebca8b87b4d7f5.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/getstate-api_hufb328c2f450c520ebcacf95445f29597_328007_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/getstate-api_hufb328c2f450c520ebcacf95445f29597_328007_30c8ee37397d4435c5a40c44f37883a7.webp&#34;
               width=&#34;760&#34;
               height=&#34;254&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们可以看到 GetStateRequest 中的字段 key 和 GetStateResponse 中以bytes[] 格式定义的字段 data，对应于 key-value 中的 key 和 value。 GetState() 的基本语义非常明显的呈现：请求中给出 key，在应答中返回对应的 value。除此之外，在 API 的设计中还有三个字段：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;请求中的consistency字段用于数据一致性&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/consistency-1_hu59c0994c0106bb2b403f8be20829d5c8_9512_b442963a228705e2630a615e57af004b.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/consistency-1_hu59c0994c0106bb2b403f8be20829d5c8_9512_a33e5a42b0f8afc3d83c366304d1c48b.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/consistency-1_hu59c0994c0106bb2b403f8be20829d5c8_9512_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/consistency-1_hu59c0994c0106bb2b403f8be20829d5c8_9512_b442963a228705e2630a615e57af004b.webp&#34;
               width=&#34;545&#34;
               height=&#34;522&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;当组件支持多副本时，consistency字段将用于指定对数据一致性的要求，其取值有两种：eventual:（最终一致性）和 strong:（强一致性）。除了getState()方法外，这个参数也适用于saveState()和 deleteState() 方法。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;应答中的 etag 字段用于并发，实现乐观锁&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/concurrency_huba7340ccee0d2dea81a7357995360b52_23649_079b4b2b5b7b9ddd73b5ac0a2f369118.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/concurrency_huba7340ccee0d2dea81a7357995360b52_23649_bf4a7601a15a2b56b1f3fbd6e9e81761.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/concurrency_huba7340ccee0d2dea81a7357995360b52_23649_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/concurrency_huba7340ccee0d2dea81a7357995360b52_23649_079b4b2b5b7b9ddd73b5ac0a2f369118.webp&#34;
               width=&#34;676&#34;
               height=&#34;564&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;乐观锁的工作原理如上图所示，假定有三个请求同时查询同一个key，三个应答中都会返回当前key的etag(值为&amp;quot;10&amp;rdquo;)。当这三个线程同时进行并发修改时，在saveState()的请求中需要设置之前获取到的etag，第一个save请求将被接受然后对应key的etag将修改为&amp;quot;11&amp;rdquo;，而后续的两个save请求会因为etag不匹配而被拒绝。&lt;/p&gt;
&lt;p&gt;etag 参数在 getState() 方法中返回，在 saveState() 方法中设置，每次对key进行写操作都要求必须修改etag。&lt;/p&gt;
&lt;p&gt;concurrency 参数在 saveState()方法中设置，有两个值可选：first_write（启用乐观锁) 和 last_write（无乐观锁，简单覆盖）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;请求和应答中都有的metadata&lt;/p&gt;
&lt;p&gt;类型定义为&lt;code&gt;map&amp;lt;string, string&amp;gt;&lt;/code&gt; ，可以方便的传递未在 API 中定义的参数，为 API 提供扩展性：即提供实现个性化功能（而不是通用功能）的扩展途径。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;对批量操作的处理&#34;&gt;对批量操作的处理&lt;/h3&gt;
&lt;p&gt;State API 提供的批量操作，用于一次性操作多个key，和应用多次调用单个操作的 API 相比，减少了多次往返的性能开销和延迟。考虑到组件原生对批量操作的支持程度，Dapr 中的批量操作的实现方式有两种:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/bulk-two-way-of-impl_hu3f22fb1f437a05a6c96092aeaa7bce7c_54267_abb4535a334aa6497cec2ad8b2e22105.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/bulk-two-way-of-impl_hu3f22fb1f437a05a6c96092aeaa7bce7c_54267_1c415f7fef3a6d6bcb7b86c897ae4b14.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/bulk-two-way-of-impl_hu3f22fb1f437a05a6c96092aeaa7bce7c_54267_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/bulk-two-way-of-impl_hu3f22fb1f437a05a6c96092aeaa7bce7c_54267_abb4535a334aa6497cec2ad8b2e22105.webp&#34;
               width=&#34;760&#34;
               height=&#34;296&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;原生支持批量操作：Dapr 组件将多个key一起打包提交给组件的后端实现，此时批量操作的实现由后端完成，Dapr 只是简单转发了多个key&lt;/li&gt;
&lt;li&gt;原生不支持批量操作：Dapr 组件将多次调用组件的后端实现，此时批量操作的实现由 Dapr 组件完成&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们展开细节看一下 Dapr 中 GetBulkState() 方法的代码实现，忽略细节代码和加密处理，只看主体逻辑：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;api&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;GetBulkState&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runtimev1pb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;GetBulkStateRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runtimev1pb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;GetBulkStateResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// try bulk get first
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;bulkGet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;responses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;store&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;BulkGet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;reqs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;// if store supports bulk get
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;bulkGet&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;bulkResp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// if store doesn&amp;#39;t support bulk get, fallback to call get() method one by one
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;limiter&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;concurrency&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;NewLimiter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;in&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Parallelism&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;reqs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nx&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;param&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;interface&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{})&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;param&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;GetRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;store&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nx&#34;&gt;item&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runtimev1pb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;BulkStateItem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				&lt;span class=&#34;o&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nx&#34;&gt;limiter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Execute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;reqs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;limiter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Wait&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Dapr 的 GetBulkState() 方法先尝试调用组件实现的 BulkGet()，如果组件支持批量操作则直接返回结果。而当组件不支持批量操作时，GetBulkState() 方法会做两个事情：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;兜底：Dapr 通过多次调用单个 getState() 方法来模拟实现批量操作，对于应用来说是没有感知的&lt;/li&gt;
&lt;li&gt;优化：如果只是简单的循环调用，当key比较多时延迟累加会比较大，因此 Dapr 做了一个并行查询的优化，容许启动多线程同时发起多个查询，然后将结果汇总起来后再一起返回。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Dapr 这样做的好处是：对于支持批量操作的组件可以充分发挥其功能，同时对于不支持批量操作的 组件由 Dapr 模拟出了批量操作的功能并提供了基本的性能优化。最终使得批量操作的API可以被所有组件都支持，从而让使用者在使用批量API时可以有统一的体验。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/timian_hu2c061791ce88b38ceb10609c3dcd8a65_61437_d374ae319fd856de36bf752bb0795ccd.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/timian_hu2c061791ce88b38ceb10609c3dcd8a65_61437_f6b98c6faaa9c3e77f7f3369ef72ee22.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/timian_hu2c061791ce88b38ceb10609c3dcd8a65_61437_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/timian_hu2c061791ce88b38ceb10609c3dcd8a65_61437_d374ae319fd856de36bf752bb0795ccd.webp&#34;
               width=&#34;508&#34;
               height=&#34;446&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;对事务操作的处理&#34;&gt;对事务操作的处理&lt;/h3&gt;
&lt;p&gt;相对于批量操作的简单处理方式，事务的支持在 Dapr 中就要麻烦的多，是目前 State API 在实现中最大的挑战，其根源在于：很多组件不支持事务！而且，事务性也无法像批量操作那边在 Dapr 侧进行简单补救。&lt;/p&gt;
&lt;p&gt;以下是实现了 Dapr State API 的组件对事务支持的情况，其中支持事务的组件有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cosmosdb&lt;/li&gt;
&lt;li&gt;Mongodb&lt;/li&gt;
&lt;li&gt;Mysql&lt;/li&gt;
&lt;li&gt;Postgresql&lt;/li&gt;
&lt;li&gt;Redis&lt;/li&gt;
&lt;li&gt;Rethinkdb&lt;/li&gt;
&lt;li&gt;Sqlserver&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不支持事务的组件有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Aerospike&lt;/li&gt;
&lt;li&gt;Aws/dynamodb&lt;/li&gt;
&lt;li&gt;Azure/blobstorage&lt;/li&gt;
&lt;li&gt;Azure/tablestorage&lt;/li&gt;
&lt;li&gt;Cassandra&lt;/li&gt;
&lt;li&gt;Cloudstate&lt;/li&gt;
&lt;li&gt;Couchbase&lt;/li&gt;
&lt;li&gt;Gcp/firestore&lt;/li&gt;
&lt;li&gt;Hashicorp/consul&lt;/li&gt;
&lt;li&gt;hazelcase&lt;/li&gt;
&lt;li&gt;memcached&lt;/li&gt;
&lt;li&gt;zookeeper&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，Dapr State API 的组件被是否支持事务分成了两大类。这些组件在开发时和运行时调用上需要就是否支持事务进行区分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;组件在初始化时需要指明是否支持事务&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/transactional-component-1_hu09cd7633a0fe262a802b084bdcefc180_42292_b909752002fe22d59a303018feda003b.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/transactional-component-1_hu09cd7633a0fe262a802b084bdcefc180_42292_8570f926eec8d83383edddc5f576cb2d.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/transactional-component-1_hu09cd7633a0fe262a802b084bdcefc180_42292_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/transactional-component-1_hu09cd7633a0fe262a802b084bdcefc180_42292_b909752002fe22d59a303018feda003b.webp&#34;
               width=&#34;760&#34;
               height=&#34;168&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dapr 在启动时进行过滤，支持事务的组件单独放在一个集合中&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/transactional-component-2_huc4ac4525a38a8394c23abca9c4bf7d04_51909_67a523c86885f5c2126bb7295a9c4d07.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/transactional-component-2_huc4ac4525a38a8394c23abca9c4bf7d04_51909_f5ee5d60ef074f1b18c923c45d8070e3.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/transactional-component-2_huc4ac4525a38a8394c23abca9c4bf7d04_51909_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/transactional-component-2_huc4ac4525a38a8394c23abca9c4bf7d04_51909_67a523c86885f5c2126bb7295a9c4d07.webp&#34;
               width=&#34;760&#34;
               height=&#34;160&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dapr 在收到事务请求时，会检查当前组件是否支持事务&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/transactional-component-3_hu1403763f3fe13eb45f2468f0252f210d_59270_b5fa8f948c02c07aad541a86525341ed.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/transactional-component-3_hu1403763f3fe13eb45f2468f0252f210d_59270_d0e2b76261fbfedb8c23b3f6179d35ca.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/transactional-component-3_hu1403763f3fe13eb45f2468f0252f210d_59270_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/transactional-component-3_hu1403763f3fe13eb45f2468f0252f210d_59270_b5fa8f948c02c07aad541a86525341ed.webp&#34;
               width=&#34;760&#34;
               height=&#34;124&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这直接导致了一个严重的后果：当用户使用 Dapr State API 时，就必须先明确自己是否会使用到事务操作，如果是，则只能选择支持事务的组件。&lt;/p&gt;
&lt;h3 id=&#34;残酷的现实高级特性的支持度&#34;&gt;残酷的现实：高级特性的支持度&lt;/h3&gt;
&lt;p&gt;在前面我们讲述API标准化的价值时，是基于一个基本假设：在能力抽象和API标准化之后，各种组件都可以提供对 Dapr API 的良好实现，从而使得基于这些标准API开发的应用在功能得到满足的同时也可以获得可移植性。&lt;/p&gt;
&lt;p&gt;这是一个非常美好的想法，但这个假设的成立是有前提条件的：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;API定义全部特性&lt;/strong&gt;：即API 提供的完整的能力，包括各种高级特性，从功能的角度满足用户对分布式能力的各种需求&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;所有组件都完美支持&lt;/strong&gt;：每个组件可以完整的实现API抽象和标准化的这些能力，不存在功能缺失，从而保证在任意一个平台上都可以以相同的体验获取同样的功能&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/advance-fetures-in-state-api_huab5cba9077040013e249f3f0525ecf62_135441_79ee6ab98dee750be031863ae1aa4f62.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/advance-fetures-in-state-api_huab5cba9077040013e249f3f0525ecf62_135441_f29d94c4924041ccd2215b009a743651.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/advance-fetures-in-state-api_huab5cba9077040013e249f3f0525ecf62_135441_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/advance-fetures-in-state-api_huab5cba9077040013e249f3f0525ecf62_135441_79ee6ab98dee750be031863ae1aa4f62.webp&#34;
               width=&#34;760&#34;
               height=&#34;375&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而现实是残酷的：&lt;strong&gt;特性越是高级，就越难于让所有组件都支持&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;以 Dapr State API 为例，如上图所示从做向右的各种特性，组件的支持程度越来越差：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基本操作：这些是基本的KV语义，CURD操作，而且是每次操作单个key。所有组件都支持，支持度=100%&lt;/li&gt;
&lt;li&gt;批量操作：在基本操作的基础上增加对多个key同时操作的支持，部分组件不能原生支持，但是 Dapr 可以在单个的基本操作上模拟出批量操作来进行弥补，因此也可以视为都支持，支持度~=100%&lt;/li&gt;
&lt;li&gt;过期时间：可选特性，设置过期时间可以让key在该时间之后自动被清理，有部分组件原生支持这个特性，但也有部分组件无法支持。这是一个可选特性，Dapr 的设计是通过在请求中提供名为 TtlInSeconds 的 metadata 来指定。&lt;/li&gt;
&lt;li&gt;并发支持：乐观锁机制，要求组件为每个key提供一个etag字段（或者称为version），每次修改时都要比对etag，修改后要更新etag。这个特性也是只有部分组件支持，需要在组件支持特性中明确指出是否支持。&lt;/li&gt;
&lt;li&gt;数据一致性：容许在请求中提供参数指定操作对数据一致性的要求，可以是强一致性或最终一致性，组件如果支持就可以依照这个参数的指示进行操作。这个特性同样只有部分组件支持&lt;/li&gt;
&lt;li&gt;事务：提供对多个写操作的原子性支持，只有部分组件支持（按照前面列出来的组件支持情况，大概是40%），需要在组件支持特性中明确指出是否支持。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但实际上，在 API 定义和标准化的过程中，我们不得不面对这样一个残酷的现实：&lt;strong&gt;API定义全部特性&lt;/strong&gt;  和 &lt;strong&gt;所有组件都完美支持&lt;/strong&gt; 无法同时满足！&lt;/p&gt;
&lt;p&gt;这导致在定义 Dapr API 时不得不面对这么一个痛苦的抉择：向左？还是向右？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/left-or-right_hu3135fa348e044c349fd69a4bebd28d8c_2960742_5520ac773002d6dfb98643f2c2b736ae.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/left-or-right_hu3135fa348e044c349fd69a4bebd28d8c_2960742_b06688a53a52249dc989c85e795fbb2e.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/left-or-right_hu3135fa348e044c349fd69a4bebd28d8c_2960742_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/left-or-right_hu3135fa348e044c349fd69a4bebd28d8c_2960742_5520ac773002d6dfb98643f2c2b736ae.webp&#34;
               width=&#34;760&#34;
               height=&#34;426&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;向左，只定义基本特性，最终得到的API倾向于功能最小集&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;优点：所有组件都支持，可移植性好&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;缺点：功能有限，很可能不满足需求&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;向右，定义各种高级特性，最终得到的API倾向于功能最大集&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;优点：功能齐全，很好的满足需求&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺点：组件只提供部分支持，可移植性差&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;api定义的核心挑战&#34;&gt;API定义的核心挑战&lt;/h3&gt;
&lt;p&gt;Dapr API定义的核心挑战在于：&lt;strong&gt;功能丰富性和组件支持度难于兼顾&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;如下图所示，当API定义的功能越丰富时，组件的支持度越差，越来越多的组件出现无法支持某个定义的高级特性，导致可移植性下降：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/api-challenge_huc70f213799dbb340de617b45d3095afe_21085_90986bbe8cef57e954895529e5269c48.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/api-challenge_huc70f213799dbb340de617b45d3095afe_21085_1d0b56a67fb83a30fa52d4b10b0f424d.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/api-challenge_huc70f213799dbb340de617b45d3095afe_21085_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/api-challenge_huc70f213799dbb340de617b45d3095afe_21085_90986bbe8cef57e954895529e5269c48.webp&#34;
               width=&#34;760&#34;
               height=&#34;474&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Dapr 现有的各种API，包括上面我们详细介绍的 State API，基本都经历过这样一个流程：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;每个Dapr构建块的 API 在初始创建时，通常会从基本功能开始，相对偏左侧&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;随着时间的推移，为了满足更多场景下的用户需求，会向右移动，在API中增加新功能&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;新增的功能可能会导致部分组件无法提供支持，损害可移植性&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此 Dapr API 在定义和后续演进时需要做权衡和取舍：&lt;/p&gt;
&lt;ul&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;h3 id=&#34;metadata的引入和实践&#34;&gt;Metadata的引入和实践&lt;/h3&gt;
&lt;p&gt;在 Dapr 现有的设计中，为了在标准API定义之外提供扩展功能，引入请求级别的 metadata 来进行自定义扩展：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/metadata-in-getstaterequest_hu7129a38bb21f1d85ce557d27e5051d01_46887_2b83c25071a3003ca9c36566dac041ef.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/metadata-in-getstaterequest_hu7129a38bb21f1d85ce557d27e5051d01_46887_c071a11cfd72c3aec813f28e19bcecf2.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/metadata-in-getstaterequest_hu7129a38bb21f1d85ce557d27e5051d01_46887_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/metadata-in-getstaterequest_hu7129a38bb21f1d85ce557d27e5051d01_46887_2b83c25071a3003ca9c36566dac041ef.webp&#34;
               width=&#34;760&#34;
               height=&#34;379&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;metadata 字段的类型定位为&lt;code&gt;map&amp;lt;string, string&amp;gt;&lt;/code&gt;，可以方便的携带任意的key-value，在不改变API定义的情况下，组件和使用者可以约定在请求级别的metadata中通过传递某些参数来使用更多的底层能力。&lt;/p&gt;
&lt;p&gt;下图是在阿里云在内部落地 Dapr 时，对 Dapr State API 的各种 metadata 自定义扩展：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/metadata-tair_hu9bcc4aa3d7891bef78748ebf65785be1_106321_f7ac1a75e758def58657eeac8a4a8f2f.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/metadata-tair_hu9bcc4aa3d7891bef78748ebf65785be1_106321_8c969da4e45874afb945e33a23b86189.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/metadata-tair_hu9bcc4aa3d7891bef78748ebf65785be1_106321_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/metadata-tair_hu9bcc4aa3d7891bef78748ebf65785be1_106321_f7ac1a75e758def58657eeac8a4a8f2f.webp&#34;
               width=&#34;476&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;注意：State API 中，expire 的功能在通过名为 &lt;code&gt;ttlInSeconds&lt;/code&gt; 的 metadata 来实现，而没有直接在 getStateRequest 中定义固定字段。&lt;/p&gt;
&lt;p&gt;metadata 的引入解决了API功能不足的问题，但是也造成了另外一个严重问题：&lt;strong&gt;破坏可移植性&lt;/strong&gt;。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;可移植性是Dapr的核心价值：因此定义Dapr API时应尽量满足可移植性的诉求&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;API设计时会偏功能最小集&lt;/p&gt;
&lt;p&gt;为了提供最大限度的可移植性，设计时往往会倾向于从功能最小集出发，如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/api-min-function-set_hu556fcd557c138008d6d0dd5bc0b6ecc3_43947_f9288e3fc2e40d8fea784f82bbb3d3a4.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/api-min-function-set_hu556fcd557c138008d6d0dd5bc0b6ecc3_43947_07b17f19b871b106e30f53b6976a3f66.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/api-min-function-set_hu556fcd557c138008d6d0dd5bc0b6ecc3_43947_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/api-min-function-set_hu556fcd557c138008d6d0dd5bc0b6ecc3_43947_f9288e3fc2e40d8fea784f82bbb3d3a4.webp&#34;
               width=&#34;358&#34;
               height=&#34;302&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;出现功能缺失&lt;/p&gt;
&lt;p&gt;功能最小集合意味着Dapr API只定义基本功能，自然会导致缺乏各种高级特性，落地时会遇到无法满足应用需求的情况&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;进行自定义扩展&lt;/p&gt;
&lt;p&gt;为了满足需求，使用请求级别的 metadata 进行自定义扩展，提供 Dapr API 没有定义的功能。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;优点：满足功能需求&lt;/p&gt;
&lt;p&gt;metadata 的使用扩展了功能，使得底层组件的能力得以释放&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;缺点：严重破坏可移植性&lt;/p&gt;
&lt;p&gt;自定义扩展越多，在迁移到其他组件时可能丢失的功能就越多，可移植性就越差。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/metadata-problem_hu79c1e8ba68a5600c40aa44befab7fa53_94697_8d864a3ff5713478df95366dfd2a55a8.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/metadata-problem_hu79c1e8ba68a5600c40aa44befab7fa53_94697_d12974b7921436b9a4c86efc0e457437.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/metadata-problem_hu79c1e8ba68a5600c40aa44befab7fa53_94697_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/metadata-problem_hu79c1e8ba68a5600c40aa44befab7fa53_94697_8d864a3ff5713478df95366dfd2a55a8.webp&#34;
               width=&#34;504&#34;
               height=&#34;511&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;从图上看，当从可移植性为出发点进行API设计时，由于功能缺失迫使引入 metadata 进行自定义扩展，在解决功能问题的同时，造成了可移植性的严重破坏。从而偏离了我们的初衷，也造成整个API设计和落地打磨的流程无法形成闭环，无法建立良性循环。&lt;/p&gt;
&lt;h3 id=&#34;dapr在阿里内部落地时遭遇的重大挑战&#34;&gt;Dapr在阿里内部落地时遭遇的重大挑战&lt;/h3&gt;
&lt;p&gt;阿里是 Dapr 最早期的用户之一，在阿里内部落地 Dapr 时遭遇了重大挑战：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;之前有的功能现在都要有！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是来自业务团队的普遍需求，其背景是落地时遇到的三个现状：&lt;/p&gt;
&lt;ol&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;li&gt;
&lt;p&gt;Dapr在内部落地时功能方面的GAP非常大&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;其结果就是迫使在落地时不得不引入 request 级别 metadata —— 这在短期内满足了功能需求，但从长期考虑损害了可移植性。&lt;/p&gt;
&lt;h3 id=&#34;反思左右为难何去何从&#34;&gt;反思：左右为难，何去何从？&lt;/h3&gt;
&lt;p&gt;回顾前面我们谈及的 Dapr API定义的核心挑战：&lt;strong&gt;功能丰富性和组件支持度难于兼顾&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/api-challenge_huc70f213799dbb340de617b45d3095afe_21085_90986bbe8cef57e954895529e5269c48.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/api-challenge_huc70f213799dbb340de617b45d3095afe_21085_1d0b56a67fb83a30fa52d4b10b0f424d.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/api-challenge_huc70f213799dbb340de617b45d3095afe_21085_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/api-challenge_huc70f213799dbb340de617b45d3095afe_21085_90986bbe8cef57e954895529e5269c48.webp&#34;
               width=&#34;760&#34;
               height=&#34;474&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;因此，在 Dapr API 定义和标准化过程中，在功能丰富性和组件支持度（可移植性）上如何取舍，就成为必须慎重考虑和严谨对待的关键问题。&lt;/p&gt;
&lt;h2 id=&#34;实践为先在落地中探索打磨&#34;&gt;实践为先：在落地中探索打磨&lt;/h2&gt;
&lt;p&gt;空想无益，实践为先，让我们以目前 state API 为例分析 Dapr 在 API 定义和标准化上的一些实践，让我们对此有更加深刻的理解。&lt;/p&gt;
&lt;h3 id=&#34;换角度看问题组件提供的能力不平齐&#34;&gt;换角度看问题：组件提供的能力不平齐&lt;/h3&gt;
&lt;p&gt;首先，让我们换一个角度看待这个问题，功能丰富性和组件支持度难于兼顾的核心在于&lt;strong&gt;组件提供的能力不是平齐的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/capabilities-not-eqauls_hue79ddb6c4f118ee7e9452682d6a75f22_98158_f40e888ee7d6ca9743347b2a58de2d3b.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/capabilities-not-eqauls_hue79ddb6c4f118ee7e9452682d6a75f22_98158_76d85235b4269d051f70650d5ee890a3.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/capabilities-not-eqauls_hue79ddb6c4f118ee7e9452682d6a75f22_98158_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/capabilities-not-eqauls_hue79ddb6c4f118ee7e9452682d6a75f22_98158_f40e888ee7d6ca9743347b2a58de2d3b.webp&#34;
               width=&#34;760&#34;
               height=&#34;372&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如上图所示，不同组件所能提供的能力是不同的，因此他们能够支持的API高级特性也有所不同：有些组件支持的特性多一些，有些组件支持的特性少一些。体现在上图的左侧，当我们把这些组件的能力都罗列出来时，得到的时一个高低不平的图形。&lt;/p&gt;
&lt;p&gt;最小功能集和最大功能集对应了这个图形中的最低处和最高处（简单起见我们假定最小功能集和最大功能集都刚好有组件可以直接对应），而 Dapr API 的设计关键就在于如何权衡功能丰富性和组件支持度，最终选择一个合适的功能集合。&lt;/p&gt;
&lt;h3 id=&#34;解决思路一dapr-runtime-弥补组件缺失能力&#34;&gt;解决思路一：Dapr Runtime 弥补组件缺失能力&lt;/h3&gt;
&lt;p&gt;还记得我们前面详细看过的 GetBulkState() 方法的实现代码吗？为了弥补部分组件无法支持批量操作的问题，Dapr 采用的方式是在 Dapr Runtime 中通过多次调用来模拟出批量操作的功能：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;api&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;GetBulkState&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runtimev1pb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;GetBulkStateRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runtimev1pb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;GetBulkStateResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// try bulk get first
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;bulkGet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;responses&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;store&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;BulkGet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;reqs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;// if store supports bulk get
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;bulkGet&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;bulkResp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// if store doesn&amp;#39;t support bulk get, fallback to call get() method one by one
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;limiter&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;concurrency&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;NewLimiter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;in&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Parallelism&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;reqs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nx&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;param&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;interface&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{})&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;param&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;GetRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;store&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nx&#34;&gt;item&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runtimev1pb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;BulkStateItem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;				&lt;span class=&#34;o&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nx&#34;&gt;limiter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Execute&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;fn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;reqs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;limiter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Wait&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;用让子弹飞的方式来解释这段代码的功能，就是这个画风：我给了他（组件）一把手枪(部署了Dapr Sidecar)，他要是体面（支持批量操作），你就让他体面（调用组件的批量方法）；他要是不体面（不支持批量操作），你就帮他体面（多次调用单个操作的方法来模拟批量操作）。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/timian_hu2c061791ce88b38ceb10609c3dcd8a65_61437_d374ae319fd856de36bf752bb0795ccd.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/timian_hu2c061791ce88b38ceb10609c3dcd8a65_61437_f6b98c6faaa9c3e77f7f3369ef72ee22.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/timian_hu2c061791ce88b38ceb10609c3dcd8a65_61437_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/timian_hu2c061791ce88b38ceb10609c3dcd8a65_61437_d374ae319fd856de36bf752bb0795ccd.webp&#34;
               width=&#34;508&#34;
               height=&#34;446&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;前面我们在介绍 Dapr 和 Servicemesh 的本质差异时强调过：Dapr 的工作模式是&lt;strong&gt;能力抽象&lt;/strong&gt;，Sidecar 原则上对应用只暴露抽象之后的分布式能力，屏蔽了底层具体的实现和通讯协议，不做&amp;quot;转发&amp;quot;而是提供&amp;quot;能力&amp;quot;，sidecar 扮演的是&lt;strong&gt;运行时&lt;/strong&gt;(&amp;ldquo;Runtime&amp;rdquo;) 的角色。&lt;/p&gt;
&lt;p&gt;所谓&amp;quot;组件能力缺失&amp;quot;，是指底层组件原生无法提供API定义的功能，如上面 State API 中定义的批量操作，现实中就是有不少 Dapr State 的组件原生不支持批量操作。而 Dapr 的工作模式使得 Dapr 有机会对组件缺失的能力进行弥补，请牢记：Dapr 的 Sidecar 是 Runtime， 而不是 Proxy。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/solution1-darp-work-model_hu93b048c94b7eb2cc82df73d7258a6d39_47305_217cf1cec5a1ecf12ff68ed7ae094a4d.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/solution1-darp-work-model_hu93b048c94b7eb2cc82df73d7258a6d39_47305_c778ed3f13fb347b697f479a6d636217.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/solution1-darp-work-model_hu93b048c94b7eb2cc82df73d7258a6d39_47305_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/solution1-darp-work-model_hu93b048c94b7eb2cc82df73d7258a6d39_47305_217cf1cec5a1ecf12ff68ed7ae094a4d.webp&#34;
               width=&#34;760&#34;
               height=&#34;368&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如上图右侧所示，Dapr Sidecar 对批量操作的实现进行了&amp;quot;干预&amp;quot;：当发现底层组件不支持批量操作时，Dapr Runtime 会改用多次调用组件的单个操作方法的方式来模拟批量操作，从而在功能上实现了 State API 定义中的批量操作。&lt;/p&gt;
&lt;p&gt;这是 Dapr 中解决功能缺失比较理想的方式，应优先采纳，当然这个代价是 Dapr 需要做更多的工作。但成效时非常明显的，如下图所示，在 Dapr 进行功能补齐之后，左侧组件功能不对齐的问题会得以缓解，相关的这些功能也就可以放心的纳入 Dapr API 的范围而无需担心组件支持度。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/capabilities-not-eqauls-after-dapr-fulfill_hue949d3d1d071158d5069adedb0a76ab6_102143_8a384b39acbc211ad3b33c9df1519f5e.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/capabilities-not-eqauls-after-dapr-fulfill_hue949d3d1d071158d5069adedb0a76ab6_102143_12f2fe4244f2eb085a826c658e6dfaee.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/capabilities-not-eqauls-after-dapr-fulfill_hue949d3d1d071158d5069adedb0a76ab6_102143_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/capabilities-not-eqauls-after-dapr-fulfill_hue949d3d1d071158d5069adedb0a76ab6_102143_8a384b39acbc211ad3b33c9df1519f5e.webp&#34;
               width=&#34;760&#34;
               height=&#34;372&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;解决思路二dapr-component-弥补组件缺失能力&#34;&gt;解决思路二：Dapr Component 弥补组件缺失能力&lt;/h3&gt;
&lt;p&gt;思路和前面是一致的，功能出现缺失时由 Dapr Sidecar 来进行补救。但差异在于进行补救的地方的不是 Dapr 的通用代码，而是 Dapr 中该组件对应的组件实现代码，因此这个补救只能在当前组件中生效，无法复用到其他组件。&lt;/p&gt;
&lt;p&gt;我们以并发支持为例，Dapr State API 通过 etag 的方式定义了乐观锁的功能，但是在使用 Redis 实现 State API 时就会遇到这样一个问题：Redis 原生是不支持 etag （或者叫做version）的。而且这个功能缺失还无法在 Dapr 中通过通用的方式（如前面通过多次调用单个操作的方式来模拟批量操作）来进行弥补。为了支持etag，Dapr 中的 redis state component 在代码实现中就采用了 hashmap 类型的 value，通过 data 和 version 两个 hashmap key 来实现 etag 的功能:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/redis-state-component-hashmap_hud9cc941754598a8129e6946fabf2aa46_25903_03b40a13fb0e3f71b88ea4195ee58592.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/redis-state-component-hashmap_hud9cc941754598a8129e6946fabf2aa46_25903_b15d3a0bf8226eb74dbb529786bb705d.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/redis-state-component-hashmap_hud9cc941754598a8129e6946fabf2aa46_25903_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/redis-state-component-hashmap_hud9cc941754598a8129e6946fabf2aa46_25903_03b40a13fb0e3f71b88ea4195ee58592.webp&#34;
               width=&#34;676&#34;
               height=&#34;635&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而为保证对 data 和 version 这两个 hashmap 值操作的原子性，引入了LUA脚本:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/redis-state-component-lua_hu693e84add5dad7cc052b7ac3c974992a_44679_9ec05dfafe59dc05ca74bf88b6636e20.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/redis-state-component-lua_hu693e84add5dad7cc052b7ac3c974992a_44679_015aec9d536da94bf90912fc52ced253.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/redis-state-component-lua_hu693e84add5dad7cc052b7ac3c974992a_44679_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/redis-state-component-lua_hu693e84add5dad7cc052b7ac3c974992a_44679_9ec05dfafe59dc05ca74bf88b6636e20.webp&#34;
               width=&#34;760&#34;
               height=&#34;208&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;类似的实现在 Dapr 各组件的代码中有不少，这种方式也可以很好的弥补功能缺失。&lt;/p&gt;
&lt;h3 id=&#34;解决思路三dapr无法弥补但可以模糊处理&#34;&gt;解决思路三：Dapr无法弥补，但可以模糊处理&lt;/h3&gt;
&lt;p&gt;State API 中的 saveState() 方法，请求中的 consistency 字段用于数据一致性，当组件支持多副本时，consistency字段将用于指定对数据一致性的要求，其取值有两种：eventual:（最终一致性）和 strong:（强一致性）。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/consistency-1_hu59c0994c0106bb2b403f8be20829d5c8_9512_b442963a228705e2630a615e57af004b.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/consistency-1_hu59c0994c0106bb2b403f8be20829d5c8_9512_a33e5a42b0f8afc3d83c366304d1c48b.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/consistency-1_hu59c0994c0106bb2b403f8be20829d5c8_9512_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/consistency-1_hu59c0994c0106bb2b403f8be20829d5c8_9512_b442963a228705e2630a615e57af004b.webp&#34;
               width=&#34;545&#34;
               height=&#34;522&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;下面是支持强一致性的 redis state 实现代码：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;StateStore&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;setValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SetRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Options&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Consistency&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Strong&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;replicas&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;client&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Do&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ctx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;WAIT&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;replicas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fmt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Errorf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;redis waiting for %v replicas to acknowledge write, err: %s&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;r&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;replicas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;如果组件不支持强一致性，或者当前组件并没有配置集群不存在多副本，则可以忽略 consistency 参数。即使请求中的 consistency字段明确要求强一致性，在不能实现或者无需实现时，可以简单忽略该参数而无需报错。&lt;/p&gt;
&lt;p&gt;类似的，超时的实现在 State API 中是通过名为 &lt;code&gt;ttlInSeconds&lt;/code&gt; 的 metadata 来实现。如果组件不支持超时，则可以简单的忽略该 metadata 。&lt;/p&gt;
&lt;h3 id=&#34;解决思路四无法弥补又不能模糊处理&#34;&gt;解决思路四：无法弥补又不能模糊处理&lt;/h3&gt;
&lt;p&gt;有些功能的缺失，是前面三种解决方式都无法解决的，例如前面提到的 State API 中的事务支持：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;刚需：从需求上说，这个功能必须有，比如 Dapr Secret Store 就严重依赖 State API 的事务方法&lt;/li&gt;
&lt;li&gt;硬伤：从实现上说，的确很多组件原生是不支持事务&lt;/li&gt;
&lt;li&gt;弥补：Dapr 目前无力弥补&lt;/li&gt;
&lt;li&gt;模糊：不能模糊处理，必须明确支持或者不支持，在有事务需求的场景下必须选择支持事务的组件不然无法保证多个操作的事务性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dapr State API 目前的做法是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;按照是否支持事务来区分 state components&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;这个解决方案的缺陷在于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;会对可移植性造成灾难性后果：如上面 State API，一旦要求支持事务，则只有约40%的组件可以支持&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;必须严格限制使用：只能为个别关键特性开特例，不能滥用，不然使用者选择组件时会非常痛苦&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;更大挑战比-state-api-复杂的多的-configuration-api&#34;&gt;更大挑战：比 State API 复杂的多的 Configuration API&lt;/h3&gt;
&lt;p&gt;虽然我们前面详细列出了在 State API 中为了实现各种高级特性而进行的各种解决方式，但 State API 其实本质上还是一个比较简单的API，高级特性也屈指可数。&lt;/p&gt;
&lt;p&gt;而 Dapr API 中还有其他比 State API 要复杂的多的API，如 Dapr 社区在今年开始深入讨论和尝试加入的 Configuration API。由于目前各种配置产品的差异性实在太大，甚至连最基本的配置模型都存在巨大差异，导致 Configuration API 在制定时遇到非常大的阻力。简而言之，和 State API 相比， Configuration API 要复杂10倍。&lt;/p&gt;
&lt;p&gt;对此感兴趣的同学请浏览：https://github.com/dapr/dapr/issues/2988&lt;/p&gt;
&lt;h2 id=&#34;路阻且长但行好事莫问前程&#34;&gt;路阻且长：但行好事莫问前程&lt;/h2&gt;
&lt;p&gt;虽然 Dapr 还很稚嫩，虽然多运行时(Mecha)的理论还在早期实践的过程中，但我坚信 Dapr 作为多运行时理论的第一个实践项目是符合云原生的大方向，Dapr 能为云原生应用带来巨大的价值。而从产品形态来说，目前 Dapr 是走在云原生社区的前面，作为 Dapr 的早期实践者、代码贡献者和 Dapr 项目的 Approver，我很骄傲的说：我们是云原生的开拓者，我们正在创造云原生新的历史。&lt;/p&gt;
&lt;p&gt;而 Dapr API 是 Dapr 成败的关键之一，从云原生发展的角度未来也需要这么一个通用的分布式能力的API标准，诚然目前的 Dapr API 需要在不断实践中补充和完善，而且这个过程注定会很艰难，就像前面这个迟迟未能顺产的 Configuration API。&lt;/p&gt;
&lt;p&gt;欢迎更多的公司和个人参与到 Dapr 项目，仅以下图，与君共勉：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202111-important-of-api-standardization-for-dapr/images/do-good-no-ask_hud6abad25849f85598713b3345cb3fd30_116980_5c3de83f46b488a7757af07c88b5c257.webp 400w,
               /talk/202111-important-of-api-standardization-for-dapr/images/do-good-no-ask_hud6abad25849f85598713b3345cb3fd30_116980_a36c8f8ca3ccbb2a2c2e0b04281315c3.webp 760w,
               /talk/202111-important-of-api-standardization-for-dapr/images/do-good-no-ask_hud6abad25849f85598713b3345cb3fd30_116980_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202111-important-of-api-standardization-for-dapr/images/do-good-no-ask_hud6abad25849f85598713b3345cb3fd30_116980_5c3de83f46b488a7757af07c88b5c257.webp&#34;
               width=&#34;760&#34;
               height=&#34;429&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;备注：Dapr 已经于2021年11月正式加入CNCF成为孵化器项目。&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;这篇文章的出处是今年5月22日我在云原生社区Meetup第四期广州站上的演讲，当时我正在主导 Configuration API 的设计和社区讨论。由于 Configuration API 中我试图引入了一系列的解决方案来处理本文中提到的 &amp;ldquo;功能丰富性和组件支持度（可移植性）&amp;rdquo; 之间的矛盾，因此我推迟了这次演讲的文字稿的发表，原想等  Configuration API 的设计方案定型之后，将在 Configuration API 中使用到的解决方案增加进本文。&lt;/p&gt;
&lt;p&gt;这些处理方式包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在API中引入分层能力模型：将 Configuration API 的能力划分为 level-0（必须支持） / level-1 / level-2 等&lt;/li&gt;
&lt;li&gt;建立组件的成熟度模型：根据每个组件对API的支持程度决定其成熟度&lt;/li&gt;
&lt;li&gt;key model 和 document model 的同时支持和平滑迁移：最大限度的避免API分裂&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但遗憾的是， Configuration API 的设计一拖再拖，始终未能确定下来，从5月底演讲迄今已等了五个月了依然未能定稿（目前讨论已经是v0.4了，而Dapr 1.5中的第一版实现的内容只是讨论范围中非常小的一个子集）。我只好先把之前演讲的已有内容发布出来， Configuration API 相关的细节内容我后续再补一个文章来进行深入介绍和探讨。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译]Dapr 加入 CNCF 孵化器</title>
      <link>https://skyao.net/post/202111-dapr-distributed-application-runtime-joins-cncf-incubator/</link>
      <pubDate>Thu, 04 Nov 2021 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202111-dapr-distributed-application-runtime-joins-cncf-incubator/</guid>
      <description>&lt;p&gt;CNCF &lt;a href=&#34;https://github.com/cncf/toc&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;技术监督委员会&lt;/a&gt;（TOC）已经投票决定接受 Dapr 作为 CNCF 的孵化项目。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://dapr.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dapr&lt;/a&gt; 是一套使开发者能够轻松编写分布式应用的 API。无论是在 Kubernetes 还是其他环境中，Dapr 都是以 Sidecar 进程运行在应用程序旁边，为开发者提供了一套形式为 pub/sub、状态管理、秘密管理、事件触发器和服务间调用的安全而可靠的原语。在 Dapr 的帮助下，开发人员可以专注于构建业务逻辑而不是基础设施。&lt;/p&gt;
&lt;p&gt;Dapr 维护者和指导委员会成员 Mark Fussell 说：“我听到开发者说 Dapr 如何缩短了他们在 Kubernetes 和其他托管平台上构建可扩展的分布式应用的时间，并解决了他们的业务需求，这对我产生了巨大的鼓舞。现在，随着 Dapr 成为 CNCF 的一部分，开发人员能够更容易地构建、使用和采纳云原生技术。”&lt;/p&gt;
&lt;p&gt;该项目于 2019 年在微软创建。随着时间的推移，许多社区成员加入该项目并做出贡献，扩展并帮助它在 2021 年 2 月达到了稳定的 1.0 版本。今天，Dapr 技术指导委员会管理该项目，其代表来自阿里巴巴、英特尔和微软。&lt;/p&gt;
&lt;p&gt;Dapr 维护者和指导委员会成员 Yaron Schneider 说：“我最自豪的是日益壮大的 Dapr 社区为项目贡献了新的 API 和构建块。我们在项目的 20 多个仓库中都有贡献，从我们的开发者工具和 SDK 到运行时本身。看到开发者来到这个项目并提出新的 API，帮助解决分布式系统的挑战，这是 Dapr 社区的重要成就。”&lt;/p&gt;
&lt;p&gt;Dapr 和多个 CNCF 项目集成。例如，使用 gRPC 进行内部 sidecar 通信，为 ACL 创建 SPIFFIE 身份，以 OpenTelemetry 格式发出遥测数据，使用 Prometheus 进行指标收集，利用 CloudEvents 作为 pub/sub 消息格式，并使用 Operator 在 Kubernetes 上原生运行。&lt;/p&gt;
&lt;p&gt;该项目被阿里云、Legentic、Tdcare、腾讯、Swoop Funding、Man Group、Zeiss &lt;a href=&#34;https://github.com/dapr/community/blob/master/ADOPTERS.md&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;等组织&lt;/a&gt;在生产中使用。采用者在所有主流云供应商以及企业内部环境上运行 Dapr。&lt;/p&gt;
&lt;p&gt;前阿里巴巴云的资深技术专家李响说：“在阿里云，我们相信 Dapr 将引领微服务开发的方向。通过采用 Dapr，我们的客户可以更快地建立可移植的、强大的分布式系统。”&lt;/p&gt;
&lt;p&gt;Ignition 集团的首席数字化转型官 Russell Stather 说：“使用 Dapr 可以在不改变其他任何东西的情况下轻易的引入新的基础设施。它改变了我们的业务。”&lt;/p&gt;
&lt;p&gt;蔡司的首席架构师 Kai Walter 说：“在我们的多云环境中，Dapr 给了我们需要的灵活性。它提供了一个抽象层，使开发人员能够专注于手头的业务案例。”&lt;/p&gt;
&lt;p&gt;主要组件：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dapr sidecar&lt;/strong&gt;：在应用程序旁边运行，包含面向开发者的 API。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CLI 和 SDK&lt;/strong&gt;：构成项目的开发者工具体验。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Components-contrib 仓库&lt;/strong&gt;：开发者可以扩展 Dapr，以集成和支持各种云服务和开源技术。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;显著的里程碑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;15100 个 GitHub Star&lt;/li&gt;
&lt;li&gt;1940 个 Pull Request&lt;/li&gt;
&lt;li&gt;3703 个问题&lt;/li&gt;
&lt;li&gt;1300 个贡献者&lt;/li&gt;
&lt;li&gt;14 次发布，目前稳定版 v1.4&lt;/li&gt;
&lt;li&gt;2600 万次 Docker 拉取&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CNCF 首席技术官 Chris Aniszczyk 说：“分布式应用和微服务构成了容器和云原生的基础，但编写可扩展和可靠的分布式应用是非常困难的。Dapr 与其他 CNCF 项目集成的很好，并提供最佳实践，开发人员可以使用任何语言或框架在上面构建。我们很高兴欢迎 Dapr 加入 CNCF 并努力培养他们的社区。”&lt;/p&gt;
&lt;p&gt;Dapr 项目的路线图包括增加新的配置 API，使开发者更容易管理其应用程序的配置，并在配置发生变化时得到通知；以及一个查询 API，使开发者更容易查询和过滤 Dapr 状态存储数据。此外，该项目正在寻求增加对基于 gRPC 和 WASM 的组件的支持，这将支持状态存储、pub/sub broker、binding 和其他 Dapr 组件的动态发现。最后，Dapr 社区还在讨论新的并发性 API，以解锁领导者选举等场景。&lt;/p&gt;
&lt;p&gt;作为由 CNCF 托管的项目，Dapr 是与其技术利益相一致的中立基金会的一部分，也是更大的 Linux 基金会的一部分，后者提供管理、营销支持和社区推广。Dapr 加入了孵化技术的行列：Argo, Buildpacks, Cilium, CloudEvents, CNI, Contour, Cortex, CRI-O, Crossplane, Dragonfly, emissary-ingress, Falco, Flagger, Flux, gRPC, KEDA, KubeEdge, Longhorn, NATS, Notary, OpenTelemetry, Operator Framework, SPIFFE, SPIRE, 和 Thanos。关于每个级别的成熟度要求，请访问 &lt;a href=&#34;https://github.com/cncf/toc/blob/master/process/graduation_criteria.adoc&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;CNCF 的毕业标准&lt;/a&gt;。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Dream Mesh</title>
      <link>https://skyao.net/project/dreammesh/</link>
      <pubDate>Mon, 09 Aug 2021 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/project/dreammesh/</guid>
      <description>&lt;p&gt;Dream Mesh = Servicemesh + Dapr based on Rust + Web Assembly&lt;/p&gt;
&lt;p&gt;构思中&amp;hellip;&amp;hellip;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>云原生分布式应用运行时 Dapr 在阿里的实践</title>
      <link>https://skyao.net/post/202103-how-alibaba-is-using-dapr/</link>
      <pubDate>Tue, 30 Mar 2021 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202103-how-alibaba-is-using-dapr/</guid>
      <description>&lt;h2 id=&#34;dapr-是什么&#34;&gt;Dapr 是什么？&lt;/h2&gt;
&lt;p&gt;Dapr是一个开源、可移植、事件驱动的云原生分布式应用运行时，它使开发人员能够轻松地构建运行在云平台和边缘的弹性而微服务化的无状态和有状态的应用程序，从而降低基于微服务架构构建现代云原生应用的准入门槛。&lt;/p&gt;
&lt;p&gt;Dapr 的名字来源于分布式应用运行时（ &lt;strong&gt;D&lt;/strong&gt;istributed &lt;strong&gt;Ap&lt;/strong&gt;plication &lt;strong&gt;R&lt;/strong&gt;untime）的缩写。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：关于Dapr 的介绍，请参考我刚发表的文章 &lt;a href=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/&#34;&gt;Dapr v1.0展望：从servicemesh到云原生&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;为什么我们选择dapr&#34;&gt;为什么我们选择Dapr？&lt;/h2&gt;
&lt;p&gt;在阿里巴巴，Java 使用非常广泛，不仅仅业务应用大量使用 Java，大量中间件和基础能力的服务器端也是使用 Java 开发。在过去十几年间，我们围绕 Java 建立了非常完备的生态体系，经历过各种严酷的考验。&lt;/p&gt;
&lt;p&gt;而随着业务形态的日渐丰富，&lt;strong&gt;多语言&lt;/strong&gt; 的需求在不断的增加，如 nodejs / golang / c / c++ / rust 等。特别是在微服务流行之后，根据实际情况而选择使用不同的编程语言开发微服务成为趋势。但效仿 Java ，为每一种编程语言都打造一套功能完备的生态体系在成本上是不现实的。因此，需要一个成本可控的方案来解决多语言问题，让微服务开发能真正的实现“语言自由”。&lt;/p&gt;
&lt;p&gt;随着云的采用，业务应用的形态也开始朝云原生方向发展，越来越多的业务应用（尤其是前台业务）开始拥抱 FaaS 和 Serverless  作为应用托管和资源调度的解决方案。而在 FaaS 和 Serverless 场景下，需要更轻量化的解决方案以满足快速启动和伸缩的需求 —— 传统类库模式下由于需要集成大量的SDK，业务应用变得非常的臃肿。而在 Function 形态下更加的不协调，以nodejs为例：几百行的 nodejs Function 代码依然需要依赖多达几十兆的node module。同时 FaaS 和 Serverless 也对多语言的支持提供了更高的要求。因此，在 FaaS 和 Serverless 这种新型形态下有必要提供有别于传统类库方式的、更轻量化的、支持多语言的解决方案。&lt;/p&gt;
&lt;p&gt;显然，Servicemesh 倡导的 Sidecar 模式是解决上述问题的绝佳方案。在过去几年间，随着 Servicemesh 的发展和采用， Sidecar 模式已经得到充分验证：Sidecar 模式非常符合云原生的理念，特别是在多语言支持和应用轻量化方面具备天然优势。&lt;/p&gt;
&lt;p&gt;我们非常认可 Bilgin Ibryam 在 &lt;a href=&#34;https://www.infoq.com/articles/multi-runtime-microservice-architecture/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;Multi-Runtime Microservices Architecture&amp;rdquo;&lt;/a&gt;  一文中提出的 Multiple Runtime / Mecha Runtime 的理念，尤其是他对分布式应用需求的分析，很符合我们的实际情况。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202103-how-alibaba-is-using-dapr/images/Multi-Runtime-Microservices-Architecture_hu3828c8b408219066fbc7297d21b025bb_65201_3879fd4ebcd91185c68673d91e21ddec.webp 400w,
               /post/202103-how-alibaba-is-using-dapr/images/Multi-Runtime-Microservices-Architecture_hu3828c8b408219066fbc7297d21b025bb_65201_deb93df2611cd016eb3eeec66b9b77cf.webp 760w,
               /post/202103-how-alibaba-is-using-dapr/images/Multi-Runtime-Microservices-Architecture_hu3828c8b408219066fbc7297d21b025bb_65201_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202103-how-alibaba-is-using-dapr/images/Multi-Runtime-Microservices-Architecture_hu3828c8b408219066fbc7297d21b025bb_65201_3879fd4ebcd91185c68673d91e21ddec.webp&#34;
               width=&#34;760&#34;
               height=&#34;409&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而 Dapr 是第一个实践 Multiple Runtime 理念的开源项目，我们从这个项目发布开始就密切关注它，因为 Dapr 可以很好的解决我们面临的问题：Sidecar 模式天然提供了对多语言的支持，各种客户端SDK被 Dapr Runtime 替代之后应用也得以轻量化。&lt;/p&gt;
&lt;p&gt;此外，从长期战略的角度考虑，我们在2020年提出了&amp;quot;三位一体&amp;quot;的理念，即将&amp;quot;自研技术&amp;quot;、&amp;ldquo;开源项目&amp;rdquo;、&amp;ldquo;商业产品&amp;quot;形成统一的技术体系，最大化技术的价值。而当前的实际情况是三者有完全不同的产品和技术方案，导致当我们需要将某个产品在阿里内部、公有云、客户私有云等不同的平台上进行迁移时，或者是跨多个平台部署时，就会遇到非常大的挑战。Dapr 面向能力编程的理念，强调可移植性和可扩展性的标准API，平台中立、无供应商锁定的设计，深深的吸引了我们。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;在阿里云，我们相信 Dapr 将引领微服务的发展。通过采用Dapr，我们的客户现在可以以更快的速度来构建可移植和健壮的分布式系统。&amp;rdquo; —— 阿里云资深技术专家 李响&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在2020年年中，我们开始基于 Dapr 项目进行了内部小规模的试点，在实际的落地过程中探索和验证 Dapr 的理念。我们也积极参与到 Dapr 开源项目的建设中，提交了大量的改进建议和代码。&lt;/p&gt;
&lt;p&gt;下面我们将以 Dapr 在阿里的实际落地场景来具体说明 Dapr 是如何帮助我们解决上述问题的。&lt;/p&gt;
&lt;h2 id=&#34;dapr在阿里的实践&#34;&gt;Dapr在阿里的实践&lt;/h2&gt;
&lt;h3 id=&#34;概况&#34;&gt;概况&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;目前 Dapr 在阿里巴巴内部还处于实验阶段&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;我们的首要工作是为内部的中间件开发 Dapr 组件，使业务应用程序可以与这些中间件和实现它们的 Java 语言/ Java Client SDK 解耦。然后通过小规模的业务应用落地，在各种场景下的对 Dapr 进行验证，在验证完成之后计划继续部署较大规模的业务应用。&lt;/p&gt;
&lt;p&gt;截止到2021年3月，Dapr 在阿里内部落地的场景主要集中在2个方面：多语言支持和云间迁移。&lt;/p&gt;
&lt;h3 id=&#34;多语言支持&#34;&gt;多语言支持&lt;/h3&gt;
&lt;h4 id=&#34;faas--serverless-场景&#34;&gt;Faas / Serverless 场景&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;背景：在阿里的电商系统中，存在大量活动和导购需求。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这些需求的特点是&amp;quot;短平快&amp;rdquo;：需要快速开发、快速迭代、生命周期相对比较短。因此这类需求非常适合通过采用 FaaS 的方式来落地。&lt;/p&gt;
&lt;p&gt;Faas 对多语言支持有强烈的诉求，肯定不会局限于 Java。而阿里内部大部分应用都是Java 体系，对多语言的支持比较弱，尤其是新兴语言（如Dart）或者小众语言（如Rust）。&lt;/p&gt;
&lt;p&gt;而从需求上说，采用 FaaS 的应用也同样需要和内部运行的服务以及各种中间件/基础设施进行通讯，因此 FaaS 平台迫切的需要解决多语言支持问题。&lt;/p&gt;
&lt;p&gt;通过 Dapr ，我们很好的解决了 FaaS 的多语言问题，从而使得客户通过 FaaS 实现了开发效率的大幅提升。&lt;/p&gt;
&lt;h4 id=&#34;多语言应用的接入&#34;&gt;多语言应用的接入&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;背景：阿里收购有大量的公司&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这些收购的公司有大量的应用，而这些应用中很多不是Java体系，在接入阿里的技术体系时，对多语言支持有明确的需求。&lt;/p&gt;
&lt;p&gt;另外，由于业务创新的需要，有些应用对 nodejs 和 golang 有强烈诉求，还有一些应用则需要使用到 Dart 和 C++。&lt;/p&gt;
&lt;p&gt;但目前这些语言的生态系统并没有像 Java 那么完善，尤其部分中间件和基础设施已经发展的非常成熟，进入维护状态，不太可能在现在重新开发所有语言的客户端：成本上代价很高，时间上也来不及。&lt;/p&gt;
&lt;p&gt;通过 Dapr ，我们可以为这些应用的提供多语言解决方案。&lt;/p&gt;
&lt;h4 id=&#34;复杂的java遗留系统&#34;&gt;复杂的Java遗留系统&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;背景：基于 Java ClassLoader 机制而设计的复杂系统&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;为了解决类冲突问题，隔绝不同的业务模块，阿里针对  Java 系统设计了基于 ClassLoader 机制的复杂系统，这些系统的设计往往非常复杂，应用也非常臃肿。&lt;/p&gt;
&lt;p&gt;此外，部分业务团队为了能和现有的中间件进行互通，自行维护了一套多语言的中间件SDK，而这些SDK本来应该由中间件团队维护并保持同步更新。这也带来了稳定性方面的隐患和风险。&lt;/p&gt;
&lt;p&gt;我们期望将这些遗留的系统迁移到 Dapr 中，统一实现中间件SDK的维护和更新。比较特殊的是这里存在一个需求：最好能让业务开发团队尽量不做代码层面的调整，以减少迁移时对业务应用的冲击。&lt;/p&gt;
&lt;p&gt;所以针对 Java 遗留系统，在迁往 Dapr 时，我们额外设计了一个Java适配层：将原来的 Java 调用适配到 Dapr 的客户端API上。&lt;/p&gt;
&lt;p&gt;以上三种多语言的落地实践场景，如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202103-how-alibaba-is-using-dapr/images/multiple-langurage_hu5d98ca782c8bcb789c89210a0f8e3e46_207793_55a8fcc2c11adb4f9da41c59cdd51370.webp 400w,
               /post/202103-how-alibaba-is-using-dapr/images/multiple-langurage_hu5d98ca782c8bcb789c89210a0f8e3e46_207793_641a52740dcaa9cb360db1320d36746f.webp 760w,
               /post/202103-how-alibaba-is-using-dapr/images/multiple-langurage_hu5d98ca782c8bcb789c89210a0f8e3e46_207793_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202103-how-alibaba-is-using-dapr/images/multiple-langurage_hu5d98ca782c8bcb789c89210a0f8e3e46_207793_55a8fcc2c11adb4f9da41c59cdd51370.webp&#34;
               width=&#34;760&#34;
               height=&#34;400&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;云间迁移&#34;&gt;云间迁移&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;背景：业务应用对外输出时有跨平台需求&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;阿里的部分业务，如钉钉文档，原本是提供给阿里内部和外部用户直接使用的，此时钉钉文档只需要部署在阿里内部的业务集群里，直接访问阿里内部的生态体系。&lt;/p&gt;
&lt;p&gt;但是随着 SaaS 业务的发展，以及部分信息安全敏感的用户对于数据安全的强烈诉求， 需要将钉钉文档部署到用户VPC下或者公有云下。&lt;/p&gt;
&lt;p&gt;为此，我们需要将钉钉文档的系统从阿里内部迁移到公有云上进行部署，而钉钉文档使用的底层技术需要从阿里内部的技术体系迁移到使用开源技术或阿里云的商业化产品上。&lt;/p&gt;
&lt;p&gt;借助 Dapr 的标准API和可扩展的组建模型，我们采取的策略是让用户不需要修改任何代码，直接通过 Dapr Runtime 屏蔽底层使用的中间件：部署在不同平台时，通过激活 Dapr 中的不同的 Component 来提供一致的能力。&lt;/p&gt;
&lt;p&gt;以消息通讯威力，当应用需要访问消息系统时：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在阿里内部：通过 Rocketmq.yaml 激活 Rocketmq 组件&lt;/li&gt;
&lt;li&gt;在公有云上：通过 Kafka.yaml 激活 kafka 组件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过 Dapr 的可移植性，上层的钉钉文档应用现在可以和底层的基础设施（如消息系统）解耦，从而实现在不同的云平台之间平滑迁移：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202103-how-alibaba-is-using-dapr/images/cloud-migration_hu5d98ca782c8bcb789c89210a0f8e3e46_276395_f10b03d0eac1b727617462b452a54a36.webp 400w,
               /post/202103-how-alibaba-is-using-dapr/images/cloud-migration_hu5d98ca782c8bcb789c89210a0f8e3e46_276395_19dc9a308c765ff9b0660cbb07006414.webp 760w,
               /post/202103-how-alibaba-is-using-dapr/images/cloud-migration_hu5d98ca782c8bcb789c89210a0f8e3e46_276395_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202103-how-alibaba-is-using-dapr/images/cloud-migration_hu5d98ca782c8bcb789c89210a0f8e3e46_276395_f10b03d0eac1b727617462b452a54a36.webp&#34;
               width=&#34;760&#34;
               height=&#34;382&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最终帮助我们的业务团队实现了他们的&lt;strong&gt;业务目标&lt;/strong&gt;：使 Dingtalk 在任何地方部署成为可能。&lt;/p&gt;
&lt;h2 id=&#34;阿里的dapr未来规划&#34;&gt;阿里的Dapr未来规划&lt;/h2&gt;
&lt;p&gt;未来我们将继续通过应用试点的方式对 Dapr 进行验证，包括：&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;同时我们将继续开发 Dapr 的组件，以集成更多的中间件和基础设施，包括内部产品和阿里云上支持的商业产品。其中对阿里云商业产品的集成代码，我们将在验证通过之后贡献给 Dapr 项目，从而为 Dapr 提供阿里云支持。这些项目预计将包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Apache Dubbo的RPC支持&lt;/li&gt;
&lt;li&gt;Apache RocketMQ的消息传递支持&lt;/li&gt;
&lt;li&gt;Nacos的动态配置支持&lt;/li&gt;
&lt;li&gt;阿里云RDS的MySQL支持&lt;/li&gt;
&lt;li&gt;阿里云缓存服务的Redis支持&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;作为 Multiple Runtime 架构的先驱者和 Dapr 项目的早期采用者，我们将继续和 Dapr 社区合作，在落地的过程中努力完善 Dapr 的功能、性能、稳定性等关键指标，和社区一起联手打造云原生时代的 &lt;strong&gt;D&lt;/strong&gt;istributed &lt;strong&gt;AP&lt;/strong&gt;plication &lt;strong&gt;R&lt;/strong&gt;untime！&lt;/p&gt;
&lt;h3 id=&#34;后记&#34;&gt;后记&lt;/h3&gt;
&lt;p&gt;关于这片文章的一点花絮，这是一篇应微软dapr团队请求撰写的文章，简单总结在过去一年间阿里巴巴在 Dapr 落地实践方面的各种实践，作为 Dapr 生产落地的参考。&lt;/p&gt;
&lt;p&gt;文章最早发布于 Dapr 官方博客，英文版本：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.dapr.io/posts/2021/03/19/how-alibaba-is-using-dapr/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;How Alibaba is using Dapr&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;发表的时间非常的巧合，3月19日，刚好是我生日。那天由于要参加20号在上海的云原生meetup，我在生日当晚乘坐动车从深圳去往上海，未能和家人一起度过，没有生日蛋糕和生日歌。&lt;/p&gt;
&lt;p&gt;后来这片文章被 InfoQ 转载：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.infoq.com/news/2021/03/alibaba-dapr/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Alibaba Cloud Uses Dapr to Support Its Business Growth&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于考虑到国内 Dapr 的现状，这篇 Dapr 实践文章押后了一周发布，在20号演讲的 Dapr 介绍文章，也就是 &lt;a href=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dapr v1.0展望：从servicemesh到云原生&lt;/a&gt; 一文发布之后，才对外发布这片 Dapr 的落地实践篇。&lt;/p&gt;
&lt;p&gt;但比较有意思的是国内 Dapr 社区的 &lt;strong&gt;Edison&lt;/strong&gt; 同学，非常积极的直接翻译并补充了部分内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://toutiao.io/posts/6eipm5d/preview&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;[译] 云原生：阿里巴巴的 Dapr 实践与探索&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这篇文章的可读性会比我的中文原文要好，毕竟原文是一篇比较官方的稿件，没有展开细节，而且行文也不是我平时的风格。上面的翻译加料版本其实写的挺好的。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Dapr v1.0展望：从servicemesh到云原生</title>
      <link>https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/</link>
      <pubDate>Sat, 20 Mar 2021 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-logo_hu6f17a442d95fb90b3fb1108d28c8bc84_14249_685767b0f21104983067fb42fc894395.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-logo_hu6f17a442d95fb90b3fb1108d28c8bc84_14249_69d04d0d7f02a54cb8caa1e7cf50ee40.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-logo_hu6f17a442d95fb90b3fb1108d28c8bc84_14249_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-logo_hu6f17a442d95fb90b3fb1108d28c8bc84_14249_685767b0f21104983067fb42fc894395.webp&#34;
               width=&#34;236&#34;
               height=&#34;236&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Dapr 是一个新兴的云原生开源项目，由微软发起，在今年2月份刚刚发布了 v1.0 正式版本。Dapr 是社区在云原生领域新的方向性的探索，项目前景非常看好。Dapr 在国外有很高的关注度，github已近12000颗星。但在国内 Dapr 知名度非常低，而且现有的少量  Dapr 资料也偏新闻资讯类和简单介绍类，缺乏对 Dapr 的深度解读。&lt;/p&gt;
&lt;p&gt;尤其是以下问题需要回答：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dapr 是什么？它能解决什么问题？为什么我们需要关注它？&lt;/li&gt;
&lt;li&gt;Dapr 可以做什么？它和 servicemesh 有什么关系？它和云原生又有什么关系？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 Dapr v1.0 发布之际，我希望可以通过这篇文章回答上面的问题，期望可以让读者对 Dapr 有一个准确的认知。为了帮助大家深刻理解 Dapr 背后的产品理念和设计思路，我将从 Servicemesh 开始展开，快速回顾 servicemesh 的定义和 Sidecar 模式的特点；然后详细介绍由 sidecar 模式推广而来的 Multi-Runtime 的微服务新架构，在大家对 Multi-Runtime 的本质有深刻理解的基础之上，才正式展开 Dapr 项目的介绍。&lt;/p&gt;
&lt;p&gt;希望可以通过这篇文章让读者掌握 Dapr 项目的发展脉搏，了解其核心价值和愿景，领悟 Dapr 项目背后的&amp;quot;道之所在&amp;quot; —— 云原生。&lt;/p&gt;
&lt;p&gt;基于这样的考虑，这篇文章内容将分成四个部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;**回顾篇：**快速回顾 Servicemesh和sidecar的原理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;演进篇&lt;/strong&gt;：介绍 sidecar 模式演进而来的 Multi-Runtime 的新架构&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;正文&lt;/strong&gt;：详细介绍基于 Multi-Runtime 架构的 Dapr&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;展望篇&lt;/strong&gt;：在云原生背景下结合 Dapr 项目探讨应用和中间件的未来形态&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;回顾servicemesh原理和方向&#34;&gt;回顾：Servicemesh原理和方向&lt;/h2&gt;
&lt;h3 id=&#34;servicemesh的定义&#34;&gt;Servicemesh的定义&lt;/h3&gt;
&lt;p&gt;首先，让我们先快速回顾一下“Servicemesh”的定义，这是 Dapr 故事的开始。&lt;/p&gt;
&lt;p&gt;以下内容摘录自我在2017年10月的QCon上海做的演讲 &lt;a href=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;Service Mesh：下一代微服务&amp;rdquo;&lt;/a&gt;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Service Mesh是一个基础设施层，用于处理服务间通讯。现代云原生应用有着复杂的服务拓扑，服务网格负责在这些拓扑中实现请求的可靠传递。&lt;/p&gt;
&lt;p&gt;在实践中，服务网格通常实现为一组轻量级网络代理，它们与应用程序部署在一起，而对应用程序透明。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh2_hud23b41a33a32b215b19ef445300fe136_153395_6e5894f9767965aa32cdbda4252b4994.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh2_hud23b41a33a32b215b19ef445300fe136_153395_e49609e7f78dcb6f87e1c4389f06dc4a.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh2_hud23b41a33a32b215b19ef445300fe136_153395_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh2_hud23b41a33a32b215b19ef445300fe136_153395_6e5894f9767965aa32cdbda4252b4994.webp&#34;
               width=&#34;760&#34;
               height=&#34;158&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在 Servicemesh 的定义中，简短的描述了 Servicemesh 的关键特征：1. 定位基础设施层 2. 功能是服务间通讯 3. 采用 sidecar 部署 4. 特别强调无侵入、对应用透明。&lt;/p&gt;
&lt;p&gt;熟悉 servicemesh 的同学，想必对下面这张图片不会陌生：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh_hu40afec4f37f823073a460da391f02237_94115_070153c0c1914c929bfa5e8d8f7a6b2a.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh_hu40afec4f37f823073a460da391f02237_94115_41b192927a418845a4595f5e55078dac.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh_hu40afec4f37f823073a460da391f02237_94115_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh_hu40afec4f37f823073a460da391f02237_94115_070153c0c1914c929bfa5e8d8f7a6b2a.webp&#34;
               width=&#34;413&#34;
               height=&#34;266&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;sidecar-模式&#34;&gt;sidecar 模式&lt;/h3&gt;
&lt;p&gt;和传统RPC框架相比，servicemesh的创新之处在于引入了 sidecar 模式：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/sidecar-pattem_hu15d4860b6220d981fe979fc13bc6b5b1_77742_5c6ebd72a13797fcbdf951c1f8299700.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/sidecar-pattem_hu15d4860b6220d981fe979fc13bc6b5b1_77742_c7b05debca4daee9a8257e367e05c438.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/sidecar-pattem_hu15d4860b6220d981fe979fc13bc6b5b1_77742_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/sidecar-pattem_hu15d4860b6220d981fe979fc13bc6b5b1_77742_5c6ebd72a13797fcbdf951c1f8299700.webp&#34;
               width=&#34;760&#34;
               height=&#34;369&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;引入 sidecar 之后，服务间通讯由 sidecar 接管，而 sidecar 由控制平面统一控制，从而实现了服务间通讯能力的下沉，使得应用得以大幅简化。&lt;/p&gt;
&lt;p&gt;我们再来快速回顾一下 Servicemesh 的基本思路：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/mesh-basic-prinsiple_hubb4421e974d3af75bf0caf46fdf2c17b_255317_7a3e7d38c1216c67e1d419061bccd14e.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/mesh-basic-prinsiple_hubb4421e974d3af75bf0caf46fdf2c17b_255317_8b75d9c548e4096acb6264159be8c424.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/mesh-basic-prinsiple_hubb4421e974d3af75bf0caf46fdf2c17b_255317_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/mesh-basic-prinsiple_hubb4421e974d3af75bf0caf46fdf2c17b_255317_7a3e7d38c1216c67e1d419061bccd14e.webp&#34;
               width=&#34;760&#34;
               height=&#34;250&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;引入 sidecar 之前： 业务逻辑和非业务逻辑混合在一个进程内，应用既有业务逻辑，也有各种非业务的功能（体现为各种客户端SDK）。&lt;/li&gt;
&lt;li&gt;引入 sidecar 之后：客户端SDK的功能剥离，业务进程专注于业务逻辑，而SDK中的大部分功能被拆解为独立进程，以Sidecar的模式运行。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过引入 sidecar 模式，Servicemesh 成功的实现了 **关注点分离 和 ** &lt;strong&gt;独立维护&lt;/strong&gt; 两大目标。&lt;/p&gt;
&lt;h3 id=&#34;servicemesh的发展趋势&#34;&gt;servicemesh的发展趋势&lt;/h3&gt;
&lt;p&gt;以 Istio 项目为例，我这里总结了最近一两年来 servicemesh 的发展趋势（注意这些内容不是本文的重点，请快速阅读，简单了解即可）：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh-trends_huf3e48973c497e7ae5c35305606cb8e6d_592108_541e8b96cc4d1bc64136bde790785b2e.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh-trends_huf3e48973c497e7ae5c35305606cb8e6d_592108_de05570a6304d0b8f1d2cb12fdbb452a.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh-trends_huf3e48973c497e7ae5c35305606cb8e6d_592108_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh-trends_huf3e48973c497e7ae5c35305606cb8e6d_592108_541e8b96cc4d1bc64136bde790785b2e.webp&#34;
               width=&#34;760&#34;
               height=&#34;331&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 id=&#34;协议支持&#34;&gt;协议支持&lt;/h4&gt;
&lt;p&gt;Istio 中通讯协议的支持主要在 HTTP 和 gRPC，各家厂商在提供更多协议支持，包括 Dubbo、Thrift、Redis。也有一些社区力量在做补充，如赵化冰同学的 &lt;a href=&#34;https://github.com/aeraki-framework/aeraki&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Aeraki&lt;/a&gt; 项目。&lt;/p&gt;
&lt;h4 id=&#34;虚拟机支持&#34;&gt;虚拟机支持&lt;/h4&gt;
&lt;p&gt;虚拟机的支持最近成为 Istio 的重要关注点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Istio 0.2：Mesh Expansion&lt;/li&gt;
&lt;li&gt;Istio 1.1：ServiceEntry&lt;/li&gt;
&lt;li&gt;Istio 1.6：WorkloadEntry&lt;/li&gt;
&lt;li&gt;Istio 1.8：WorkloadGroup 和智能DNS代理&lt;/li&gt;
&lt;li&gt;Istio 1.9：虚拟机集成&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;易用性&#34;&gt;易用性&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Istio 1.5：控制平面单体化，合并多个组件为istiod（这是Istio开源以来最大的架构调整之一）&lt;/li&gt;
&lt;li&gt;Istio 1.7：主推 Operator安装方式，增强istioctl工具，支持在sidecar启动之后再启动应用容器&lt;/li&gt;
&lt;li&gt;Istio 1.8：改善升级和安装,引入istioctl bug-report&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;可观测性&#34;&gt;可观测性&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Istio 1.8：正式移除Mixer，在Envoy基于wasm重新实现Mixer功能 （Istio最大的架构调整之一）&lt;/li&gt;
&lt;li&gt;Istio 1.9：远程获取和加载wasm模块&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;外部集成&#34;&gt;外部集成&lt;/h4&gt;
&lt;p&gt;和非 servicemesh 体系的相互访问，实现应用在两个体系之间的平滑迁移。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Istio曾计划通过MCP协议提供统一的解决方案&lt;/li&gt;
&lt;li&gt;Istio 1.7：MCP协议被废弃，改为 mcp over xds&lt;/li&gt;
&lt;li&gt;Istio 1.9：Kubernetes Service API支持(alpha)，对外暴露服务&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从上面列出的内容，可以看到 Istio 在最近一两年间还是在非常努力的完善自身，虽然过程有些曲折和往复（比如顽固不化的坚持Mixer到最后听从全社区的呼唤彻底废弃了Mixer，开始支持虚拟机后来实质性放弃再到最近重新重视，引入Galley再废弃Galley，引入MCP再变相放弃MCP），但整体上说 Istio 还是在朝 Product Ready 的大方向在努力。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：当然，社区对 Istio 的演进速度以及 Product Ready 的实际状态还是很不满意的，以至于出现了这个梗：Make Istio Product Ready (Again, and Again…)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;servicemesh-回顾总结&#34;&gt;servicemesh 回顾总结&lt;/h3&gt;
&lt;p&gt;我们前面快速回顾了 servicemesh 的定义、sidecar 模式的原理，以及粗略罗列了一下最近一两年间 servicemesh 的发展趋势，主要是为了告知大家这样一个信息：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;虽然 Servicemesh 蓬勃发展，但核心元素始终未变&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;从2016年 Linkerd 的 CEO William Morgon 给出 servicemesh 的定义，到2021年Istio都发布到了1.9版本，整整六年期间，servicemesh 有了很多的变化，但以下三个核心元素始终未变：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh-core-element_huc0456d80caa6c8780d992b5906f6f63d_138858_105975c18fc4bfc9aa89cd791abb0a46.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh-core-element_huc0456d80caa6c8780d992b5906f6f63d_138858_fb2673df42c607ff6fe59c83669902cd.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh-core-element_huc0456d80caa6c8780d992b5906f6f63d_138858_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/servicemesh-core-element_huc0456d80caa6c8780d992b5906f6f63d_138858_105975c18fc4bfc9aa89cd791abb0a46.webp&#34;
               width=&#34;591&#34;
               height=&#34;533&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;定位&lt;/strong&gt;：Servicemesh的定位始终是提供 &lt;strong&gt;服务间通讯&lt;/strong&gt; 的基础设施层，范围包括HTTP和RPC——支持HTTP1.1/REST，支持HTTP2/gRPC，支持TCP协议。也有一些小的尝试如对redis 、 kafka的支持。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;部署&lt;/strong&gt;：ServiceMesh 支持 Kubernetes 和虚拟机，但都是采用 &lt;strong&gt;Sidecar&lt;/strong&gt; &lt;strong&gt;模式&lt;/strong&gt;部署，没有采用其他方式如 Node 部署、中心化部署。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;原理&lt;/strong&gt;： Servicemesh的工作原理是 &lt;strong&gt;原协议转发&lt;/strong&gt;，原则上不改变协议内容（通常只是header有些小改动）。为了达到零侵入的目标，还引入了iptables等流量劫持技术。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;演进云原生分布式应用运行时&#34;&gt;演进：云原生分布式应用运行时&lt;/h2&gt;
&lt;p&gt;在快速完成 servicemesh 的回顾之后，我们开始本文第二部分的内容：当 sidecar 模式进一步推广，上述三个核心元素发生变化时，sidecar 模式将会如何演进？&lt;/p&gt;
&lt;h3 id=&#34;实践更多mesh形态&#34;&gt;实践：更多Mesh形态&lt;/h3&gt;
&lt;p&gt;我之前在蚂蚁金服的中间件团队做 servicemesh 相关的内容，可能很多朋友是从那个时候开始认识我。当时蚂蚁不仅仅做了 servicemesh，还将 servicemesh 的 sidecar 模式推广到其他的中间件领域，陆陆续续探索了更多的 mesh 形态：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/ant-more-mesh_hu56c375bdd66e5b8ec5c7446e085ec97c_227360_46f88cf24751f3a6720e4c46774f671c.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/ant-more-mesh_hu56c375bdd66e5b8ec5c7446e085ec97c_227360_f710c34f4a4846e76c6c5af2ef66bfe8.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/ant-more-mesh_hu56c375bdd66e5b8ec5c7446e085ec97c_227360_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/ant-more-mesh_hu56c375bdd66e5b8ec5c7446e085ec97c_227360_46f88cf24751f3a6720e4c46774f671c.webp&#34;
               width=&#34;760&#34;
               height=&#34;344&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这个图片摘录自我在2019年10月的上海QCon上做的主题演讲 &lt;a href=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;诗和远方：蚂蚁金服Service Mesh深度实践&amp;rdquo;&lt;/a&gt;，当时我们分享了包括消息Mesh，数据库Mesh等在内的多种mesh形态。&lt;/p&gt;
&lt;h3 id=&#34;理论升华multi-runtime-理念的提出&#34;&gt;理论升华：Multi-Runtime 理念的提出&lt;/h3&gt;
&lt;p&gt;最近有越来越多的项目开始引入 sidecar 模式， sidecar 模式也逐渐被大家认可和接受。就在2020年，&lt;strong&gt;Bilgin Ibryam&lt;/strong&gt; 提出了 &lt;strong&gt;Multi-Runtime&lt;/strong&gt; 的理念，对基于 sidecar 模式的各种产品形态进行了实践总结和理论升华。&lt;/p&gt;
&lt;p&gt;首先我们介绍一下 &lt;strong&gt;Bilgin Ibryam&lt;/strong&gt; 同学，他是  &amp;ldquo;Kubernetes Patterns&amp;rdquo; 一书的作者，Apache Camel 项目的 committer，目前工作于 redhat 。&lt;/p&gt;
&lt;p&gt;2020年初，Bilgin Ibryam 发表文章 &lt;a href=&#34;https://www.infoq.com/articles/multi-runtime-microservice-architecture/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;Multi-Runtime Microservices Architecture&amp;rdquo;&lt;/a&gt; ，正式提出了多运行时微服务架构（别名Mecha/机甲，非常帅气的名字）。在这篇文章中，Bilgin Ibryam 首先总结了分布式应用存在的四大类需求，作为 Multi-Runtime 的理论出发点：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/four-requirements-of-distributed-app_hu34af877979b60d118c99d418652dcf15_433029_5c3e8533fbd776349f85e32fe68e2ca2.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/four-requirements-of-distributed-app_hu34af877979b60d118c99d418652dcf15_433029_766c442e60c535ebbb041e7c33a7423c.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/four-requirements-of-distributed-app_hu34af877979b60d118c99d418652dcf15_433029_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/four-requirements-of-distributed-app_hu34af877979b60d118c99d418652dcf15_433029_5c3e8533fbd776349f85e32fe68e2ca2.webp&#34;
               width=&#34;760&#34;
               height=&#34;359&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这四大类需求中，生命周期管理类的需求主要是通过 PaaS 平台如 kubernetes 来满足，而 servicemesh 提供的主要是网络中的点对点通讯，对于其他通讯模式典型如 pub-sub 的消息通讯模式并没有覆盖到，此外状态类和绑定类的需求大多都和 servicemesh 关系不大。&lt;/p&gt;
&lt;p&gt;Multi-Runtime 的理论推导大体是这样的——基于上述四大类需求，如果效仿Servicemesh，从传统中间件模式开始，那么大体会有下面两个步骤：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/multi-runtime-theory-derivation_hu3ea55c8225538492d89ec2fe468c1e95_1705253_72c65566fc452e4acaf3395bb5284641.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/multi-runtime-theory-derivation_hu3ea55c8225538492d89ec2fe468c1e95_1705253_6828910a64fabd328d980f6b7f2654cc.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/multi-runtime-theory-derivation_hu3ea55c8225538492d89ec2fe468c1e95_1705253_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/multi-runtime-theory-derivation_hu3ea55c8225538492d89ec2fe468c1e95_1705253_72c65566fc452e4acaf3395bb5284641.webp&#34;
               width=&#34;760&#34;
               height=&#34;272&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;步骤一：将应用需要的分布式能力外移到各种runtime，此时会出现数量众多的各种 sidecar 或者 proxy，如上面中列出来的 istio、knative、cloudstate、camel、dapr等。&lt;/li&gt;
&lt;li&gt;步骤二：这些 runtime 会逐渐整合，只保留少量甚至只有一两个的 runtime。这种提供多种分布式能力的 runtime 也被称为 Mecha。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;步骤二完成后，每个微服务就会由至少一个 Mecha Runtime 和应用 Runtime 共同组成，也就是每个微服务都会有多个（至少两个）runtime，这也就是 Multi-Runtime / Mecha 名字的由来。&lt;/p&gt;
&lt;h3 id=&#34;multi-runtime和云原生分布式应用&#34;&gt;Multi-Runtime和云原生分布式应用&lt;/h3&gt;
&lt;p&gt;将Multi-Runtime / Mecha 的理念引入到云原生分布式应用的方式：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/multi-runtime-and-cloud-native-app_hue1d3be20b196b687907d25f858653883_103203_dc6504a79ce26bde62517f3f8147b882.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/multi-runtime-and-cloud-native-app_hue1d3be20b196b687907d25f858653883_103203_4823c372ece934cb5a4dd33a1ea73543.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/multi-runtime-and-cloud-native-app_hue1d3be20b196b687907d25f858653883_103203_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/multi-runtime-and-cloud-native-app_hue1d3be20b196b687907d25f858653883_103203_dc6504a79ce26bde62517f3f8147b882.webp&#34;
               width=&#34;472&#34;
               height=&#34;470&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;能力&lt;/strong&gt;：Mecha 是通用的，高度可配置的，可重用的组件，提供分布式原语作为现成的能力。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;部署&lt;/strong&gt;：Mecha 可以与单个Micrologic组件一起部署(Sidecar模式)，也可以部署为多个共享(如Node模式)。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;协议&lt;/strong&gt;：Mecha不对 Micrologic 运行时做任何假设。它与使用开放协议和格式（如HTTP/gRPC，JSON，Protobuf，CloudEvents）的多语言微服务甚至单体一起使用。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置&lt;/strong&gt;：Mecha以简单的文本格式（例如YAML，JSON）声明式地配置，指示要启用的功能以及如何将其绑定到Micrologic端点。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;整合&lt;/strong&gt;：与其依靠多个代理来实现不同的目的（例如网络代理，缓存代理，绑定代理），不如使用一个Mecha提供所有这些能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;multi-runtime的特点和差异&#34;&gt;Multi-Runtime的特点和差异&lt;/h3&gt;
&lt;p&gt;虽然同为 sidecar 模式，但是和 servicemesh 相比，Multi-Runtime 有自身的特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;提供能力的方式和范围&lt;/strong&gt;： Multi-Runtime提供的是分布式能力，体现为应用需要的各种分布式原语，并不局限于单纯的服务间点对点通讯的网络代理&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Runtime&lt;/strong&gt;部署的方式**： Multi-Runtime的部署模型，不局限于Sidecar模式，Node模式在某些场景下（如Edge/IoT，Serverless FaaS）可能会是更好的选择。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;和App的交互方式&lt;/strong&gt;： Multi-Runtime 和应用之间的交互是开放而有 API 标准的，Runtime 和 Micrologic 之间的“协议”体现在API上，而不是原生的TCP通讯协议。另外Multi-Runtime 不要求无侵入，还会提供各种语言的SDK以简化开发。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Multi-Runtime 和 servicemesh 的差异总结如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/difference-between-multi-runtime-and-servicemesh_huce123631e5f4755e17a396f2c12112ec_85116_03de4930e032d7a6786884ca0f2d98d7.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/difference-between-multi-runtime-and-servicemesh_huce123631e5f4755e17a396f2c12112ec_85116_05837c79b8251c2940b11f1d16e4938a.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/difference-between-multi-runtime-and-servicemesh_huce123631e5f4755e17a396f2c12112ec_85116_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/difference-between-multi-runtime-and-servicemesh_huce123631e5f4755e17a396f2c12112ec_85116_03de4930e032d7a6786884ca0f2d98d7.webp&#34;
               width=&#34;760&#34;
               height=&#34;426&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;multi-runtime-的本质&#34;&gt;Multi-Runtime 的本质&lt;/h3&gt;
&lt;p&gt;至此我介绍了 Multi-Runtime 架构的由来，相信读者对 Multi-Runtime 的特点以及和 servicemesh 的差异已经有所了解。为了加深大家的理解，我来进一步分享一下我个人对 Multi-Runtime 的感悟：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multi-Runtime的本质是面向云原生应用的 &lt;em&gt;分布式能力抽象层&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/nature-of-multi-runtime_hud23b41a33a32b215b19ef445300fe136_476076_c5690170b0fdfcc0f183e5a3eb72b780.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/nature-of-multi-runtime_hud23b41a33a32b215b19ef445300fe136_476076_68285c1e80602ecc6f5ab1d084793d30.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/nature-of-multi-runtime_hud23b41a33a32b215b19ef445300fe136_476076_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/nature-of-multi-runtime_hud23b41a33a32b215b19ef445300fe136_476076_c5690170b0fdfcc0f183e5a3eb72b780.webp&#34;
               width=&#34;760&#34;
               height=&#34;302&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;何为 &amp;ldquo;&lt;strong&gt;分布式能力抽象层&lt;/strong&gt;&amp;rdquo; ?&lt;/p&gt;
&lt;p&gt;如上图所示，左侧是分布式应用存在的四大类需求：生命周期、网络、状态、绑定。从需求上说 Multi-Runtime 要为分布式应用提供这四大类需求下所列出的各种具体的分布式能力。以 Sidecar 模式为应用提供这些能力容易理解，但关键在于 Multi-Runtime 提供这些能力的方式。和 servicemesh 采用原协议转发不同，Multi-Runtime 的方式是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将能力抽象为API：很多分布式能力没有类似 HTTP 这种业界通用的协议，因此 Multi-Runtime 的实现方式是将这些能力抽象为和通讯协议无关的API，只用于描述应用对分布式能力的需求和意图，尽量避免和某个实现绑定。&lt;/li&gt;
&lt;li&gt;为每种能力提供多种实现：Multi-Runtime 中的能力一般都提供有多种实现，包括开源产品和公有云商业产品。&lt;/li&gt;
&lt;li&gt;开发时：这里我们引入一个&amp;quot;面对能力编程&amp;quot;的概念，类似于编程语言中的&amp;quot;不要面对实现编程，要面向接口编程&amp;quot;。Multi-Runtime 中提倡面向&amp;quot;能力(Capability)&amp;ldquo;编程，即应用开发者面向的应该是已经抽象好的分布式能力原语，而不是底层提供这些能力的具体实现。&lt;/li&gt;
&lt;li&gt;运行时：通过配置在运行时选择具体实现，不影响抽象层API的定义，也不影响遵循&amp;quot;面对能力编程&amp;quot;原则而开发完成的应用。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：分布式能力的通用标准API，将会是Multi-Runtime成败的关键，Dapr的API在设计和实践中也遇到很大的挑战。关于这个话题，我稍后将单独写文章来阐述和分析。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;介绍分布式应用运行时dapr&#34;&gt;介绍：分布式应用运行时Dapr&lt;/h2&gt;
&lt;p&gt;在快速回顾 servicemesh 和详细介绍 multi-runtime 架构之后，我们已经为了解 Dapr 奠定了良好的基础。现在终于可以开始本文的正式内容，让我们一起来了解 Dapr 项目。&lt;/p&gt;
&lt;h3 id=&#34;什么是dapr&#34;&gt;什么是Dapr？&lt;/h3&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-logo_hu6f17a442d95fb90b3fb1108d28c8bc84_14249_685767b0f21104983067fb42fc894395.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-logo_hu6f17a442d95fb90b3fb1108d28c8bc84_14249_69d04d0d7f02a54cb8caa1e7cf50ee40.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-logo_hu6f17a442d95fb90b3fb1108d28c8bc84_14249_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-logo_hu6f17a442d95fb90b3fb1108d28c8bc84_14249_685767b0f21104983067fb42fc894395.webp&#34;
               width=&#34;236&#34;
               height=&#34;236&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Dapr 是一个开源项目，由微软发起，下面是来自 Dapr 官方网站的权威介绍：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dapr is a portable, event-driven runtime that makes it easy for any developer to build resilient, stateless and stateful applications that run on the cloud and edge and embraces the diversity of languages and developer frameworks.&lt;/p&gt;
&lt;p&gt;Dapr是一个可移植的、事件驱动的运行时，它使任何开发者都能轻松地构建运行在云和边缘的弹性、无状态和有状态的应用程序，并拥抱语言和开发者框架的多样性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;参考并对照 servicemesh 的定义，我们对上述 Dapr 定义的分析如下：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/what-is-dapr_hud23b41a33a32b215b19ef445300fe136_146592_47dcd25cf98eb8045b2c7c563996d3fd.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/what-is-dapr_hud23b41a33a32b215b19ef445300fe136_146592_12b98ace402d314689c3f636edde64f1.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/what-is-dapr_hud23b41a33a32b215b19ef445300fe136_146592_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/what-is-dapr_hud23b41a33a32b215b19ef445300fe136_146592_47dcd25cf98eb8045b2c7c563996d3fd.webp&#34;
               width=&#34;760&#34;
               height=&#34;175&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定位&lt;/strong&gt;：Dapr 将自身定义为运行时（runtime），而不是 servicmesh 中的 proxy。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;功能&lt;/strong&gt;：Dapr为应用提供各种分布式能力，以简化应用的开发。上面定义中提及的关键点有弹性、支持有状态和无状态、事件驱动。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;多语言&lt;/strong&gt;：对多语言的支持是 sidecar 模型的天然优势，Dapr 也不例外，考虑到 Dapr 为应用提交的分布式能力的数量，这可能比 servicemesh 只提供服务间通讯能力对应用的价值更高。而且由于 Dapr 语言 SDK 的存在，Dapr 可以非常方便的和各编程语言的主流开发框架集成，如 Java 下和 Spring 框架集成。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可移植性&lt;/strong&gt;：Dapr 适用的场景包括各种云（公有云，私有云，混合云）和边缘网络，Multi-Runtime 架构的几个关键特性如&amp;quot;面向能力编程&amp;rdquo;、标准API、可运行时配置实现等为 Dapr 带来了绝佳的跨云跨平台的可移植性。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们将在后面的介绍中详细展开 Dapr 的这些特性。在开始之前，这里有一个小小的花絮—— &amp;ldquo;Dapr&amp;rdquo; 项目名字的由来：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-name_hu5d98ca782c8bcb789c89210a0f8e3e46_99247_7d370f1ff3418d28fca3bcfc40e2d37e.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-name_hu5d98ca782c8bcb789c89210a0f8e3e46_99247_bcfad9e796445b22b9e365eb88c86f19.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-name_hu5d98ca782c8bcb789c89210a0f8e3e46_99247_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-name_hu5d98ca782c8bcb789c89210a0f8e3e46_99247_7d370f1ff3418d28fca3bcfc40e2d37e.webp&#34;
               width=&#34;760&#34;
               height=&#34;161&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;dapr-sidecar-的功能和架构&#34;&gt;Dapr Sidecar 的功能和架构&lt;/h3&gt;
&lt;p&gt;和 servicemesh 类似，Dapr 同样基于 Sidecar 模式，但提供的功能和使用场景要比 ServiceMesh 的复杂多，如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-sidecar_hub1f9bf3c3a053037972046798aff9731_389587_abdb9b8d5f3441248d146f0626110679.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-sidecar_hub1f9bf3c3a053037972046798aff9731_389587_0c7c727633b6f99c83aa7b513eabb452.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-sidecar_hub1f9bf3c3a053037972046798aff9731_389587_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-sidecar_hub1f9bf3c3a053037972046798aff9731_389587_abdb9b8d5f3441248d146f0626110679.webp&#34;
               width=&#34;760&#34;
               height=&#34;377&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Dapr 的 sidecar，除了可以和 servicemesh 一样支持服务间通讯（目前支持 HTTP1.1/REST协议和 gRPC 协议外，还可以支持到更多的功能，如 state（状态管理）、pub-sub（消息通讯），resource binding（资源绑定，包括输入和输出）。&lt;/p&gt;
&lt;p&gt;每个功能都有多种实现，在上图中我简单摘录了这几个能力的常见实现，可以看到实现中既有开源产品，也有公有云的商业产品。注意这只是目前 Dapr 实现中的一小部分，目前各种实现（在Dapr中被称为组件，我们下面会介绍）已经有超过70个，而且还在不断的增加中。&lt;/p&gt;
&lt;p&gt;在 Dapr 的架构中，有三个主要组成部分：API，Building Blocks 和Components，如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-architecture_hu3e61371684448afa8181641962a48e05_101877_f98ad1df0ba936f45f7b40d017bb5bf2.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-architecture_hu3e61371684448afa8181641962a48e05_101877_961eb2174894aae168ed01931f83b1e2.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-architecture_hu3e61371684448afa8181641962a48e05_101877_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-architecture_hu3e61371684448afa8181641962a48e05_101877_f98ad1df0ba936f45f7b40d017bb5bf2.webp&#34;
               width=&#34;709&#34;
               height=&#34;513&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dapr API：Dapr 提供两种API，HTTP1.1/REST 和 HTTP2/gRPC，两者在功能上是对等的。&lt;/li&gt;
&lt;li&gt;Dapr Building Blocks：翻译为构建块，这是 Dapr 对外提供能力的基本单元，每个构建块对外提供一种分布式能力。&lt;/li&gt;
&lt;li&gt;Dapr components：组件层，这是 Dapr 的能力实现层，每个组件都会实现特定构建块的能力。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了帮助大家理解 Dapr 的架构，我们回顾一下前面重点阐述的 Multi-Runtime 的本质：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/nature-of-multi-runtime_hud23b41a33a32b215b19ef445300fe136_476076_c5690170b0fdfcc0f183e5a3eb72b780.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/nature-of-multi-runtime_hud23b41a33a32b215b19ef445300fe136_476076_68285c1e80602ecc6f5ab1d084793d30.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/nature-of-multi-runtime_hud23b41a33a32b215b19ef445300fe136_476076_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/nature-of-multi-runtime_hud23b41a33a32b215b19ef445300fe136_476076_c5690170b0fdfcc0f183e5a3eb72b780.webp&#34;
               width=&#34;760&#34;
               height=&#34;302&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Multi-Runtime的本质是面向云原生应用的分布式能力抽象层&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;结合 Multi-Runtime 理念，我们再来理解 Dapr Runtime 的架构：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-architecture-and-multi-runtime-nature_hu97da40a29b063108d5632c6168658baa_255593_faac97d6339a0752a9151d7ab18f291f.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-architecture-and-multi-runtime-nature_hu97da40a29b063108d5632c6168658baa_255593_9615763fc9372d46f4bc6eda6037fa6c.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-architecture-and-multi-runtime-nature_hu97da40a29b063108d5632c6168658baa_255593_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-architecture-and-multi-runtime-nature_hu97da40a29b063108d5632c6168658baa_255593_faac97d6339a0752a9151d7ab18f291f.webp&#34;
               width=&#34;760&#34;
               height=&#34;329&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dapr Building Blocks 提供&amp;quot;&lt;strong&gt;能力&lt;/strong&gt;&amp;quot;&lt;/li&gt;
&lt;li&gt;Dapr API 提供对分布式能力的&amp;quot;&lt;strong&gt;抽象&lt;/strong&gt;&amp;quot;，对外暴露 Building Block 的能力&lt;/li&gt;
&lt;li&gt;Dapr Components 是 Building Block 能力的具体&amp;quot;实现&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;dapr-的愿景和现有能力&#34;&gt;Dapr 的愿景和现有能力&lt;/h3&gt;
&lt;p&gt;下图来自 Dapr 官方，比较完善的概括了 Dapr 的能力和层次架构：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-overview-and-vision_hu612844ef2590eebecd233377b1953376_1040125_d166e463c51c3c837296f96c07216c77.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-overview-and-vision_hu612844ef2590eebecd233377b1953376_1040125_62bca57755d6192238c6ffa3cc6ea1e1.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-overview-and-vision_hu612844ef2590eebecd233377b1953376_1040125_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-overview-and-vision_hu612844ef2590eebecd233377b1953376_1040125_d166e463c51c3c837296f96c07216c77.webp&#34;
               width=&#34;760&#34;
               height=&#34;359&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;居中蓝色的是 Dapr Runtime：这里列出了 Dapr 目前已经提供的构建块&lt;/li&gt;
&lt;li&gt;Dapr Runtime 对外通过远程调用提供能力，目前有 HTTP API 和 gRPC API&lt;/li&gt;
&lt;li&gt;由于 Sidecar 模式的天然优势，Dapr 支持各种编程语言，而且 Dapr 官方为主流语言（典型如 Java、golang、c++、nodejs、.net、python）提供了 SDK。这些 SDK 封装了通过 HTTP API 或者 gRPC API 和 Dapr Runtime 进行交互的能力。&lt;/li&gt;
&lt;li&gt;最下方是可以支持 Dapr 的云平台或者边缘网络，由于每个能力都可以由不同的组件来完成，因此理论上只要 Dapr 的支持做的足够完善，就可以实现在任何平台上，总是能找到基于开源产品或者基于云厂商商业化产品的可用组件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;结合以上几点，Dapr 提出了这样一个愿景：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Any language, any framework, anywhere&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;即：可以使用任意编程语言开发，可以和任意框架集成，可以部署在任意平台。&lt;/p&gt;
&lt;p&gt;下图是 Dapr 目前已有的构建块和他们提供的能力的简单描述：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-8-building-blocks_huc57195030e34e0468882f925cc4bee9d_819120_00de7f76927c361091f6d7f3666c6914.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-8-building-blocks_huc57195030e34e0468882f925cc4bee9d_819120_e298d218b75600a7fb11ef0fad3fd641.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-8-building-blocks_huc57195030e34e0468882f925cc4bee9d_819120_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-8-building-blocks_huc57195030e34e0468882f925cc4bee9d_819120_00de7f76927c361091f6d7f3666c6914.webp&#34;
               width=&#34;760&#34;
               height=&#34;412&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;dapr-的控制平面&#34;&gt;Dapr 的控制平面&lt;/h3&gt;
&lt;p&gt;和 servicemesh 的架构类似，Dapr 也有控制平面的概念：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-control-plane_hu32ec8c339282b281cdff3c71662e3695_1613641_34cb78732f33f2fd0644145a94809a43.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-control-plane_hu32ec8c339282b281cdff3c71662e3695_1613641_3c4593c0790e9af3ad18dd5969cb8265.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-control-plane_hu32ec8c339282b281cdff3c71662e3695_1613641_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-control-plane_hu32ec8c339282b281cdff3c71662e3695_1613641_34cb78732f33f2fd0644145a94809a43.webp&#34;
               width=&#34;760&#34;
               height=&#34;382&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Dapr 的控制平面组件有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dapr Actor Placement&lt;/li&gt;
&lt;li&gt;Dapr Sidecar Injector&lt;/li&gt;
&lt;li&gt;Dapr Sentry&lt;/li&gt;
&lt;li&gt;Dapr Operator&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;比较有意思的是：Istio 为了简化运维，已经将微服务架构的控制平面进行了合并，控制平面回归到传统的单体模式。而 Dapr 的控制平面目前还是微服务架构，不知道未来会不会效仿 Istio。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：出于控制篇幅的考虑，本文不对 Dapr 的构建块和控制平面进行详细展开，稍后预计会另有单独文章做详细介绍，对 Dapr 有兴趣的同学可以关注。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;dapr-的发展历程和阿里巴巴的参与&#34;&gt;Dapr 的发展历程和阿里巴巴的参与&lt;/h3&gt;
&lt;p&gt;Dapr 是一个非常新的开源项目，发展至今也才大约一年半的时间，不过社区关注度还不错（主要是国外），在github 上目前有接近 12000 颗星(类比：envoy 16000，istio 26000，linkerd 7000)。Dapr 项目的主要里程碑是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2019年10月：微软在 github 上开源了 Dapr，发布 0.1.0 版本&lt;/li&gt;
&lt;li&gt;2021年2月：Dapr v1.0 版本发布&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-history_huca9edd00c0ce76126584c8f3bd4e5d03_494535_37e4f4faa7423b814495c6b5bca49415.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-history_huca9edd00c0ce76126584c8f3bd4e5d03_494535_b33f42f6288feff7b5ada51f1f3cc419.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-history_huca9edd00c0ce76126584c8f3bd4e5d03_494535_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-history_huca9edd00c0ce76126584c8f3bd4e5d03_494535_37e4f4faa7423b814495c6b5bca49415.webp&#34;
               width=&#34;760&#34;
               height=&#34;542&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;阿里巴巴深度参与 Dapr 项目，不仅仅以终端用户的身份成为 Dapr 的早期采用者，也通过全面参与 Dapr 的开源开发和代码贡献成为目前 Dapr 项目中的主要贡献公司之一，仅次于微软：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;2020年中：阿里巴巴开始参与 Dapr 项目，在内部试用功能并进行代码开发&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;2020年底：阿里巴巴内部小规模试点 Dapr，目前已有十几个应用在使用 Dapr 。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：关于 Dapr 在阿里巴巴的实践，请参阅我们刚刚发表在 Dapr 官方博客上的文章 &lt;a href=&#34;https://blog.dapr.io/posts/2021/03/19/how-alibaba-is-using-dapr/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;How Alibaba is using Dapr&amp;rdquo;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;目前我们已经有两位 Dapr Committer 和一位 Dapr Maintainer，在2021年预计我们会在 Dapr 项目上有更多的投入，包括更多的开源代码贡献和落地实践，身体力行的推动 Dapr 项目的发展。欢迎更多的国内贡献者和国内公司一起加入到 Dapr 社区。&lt;/p&gt;
&lt;h3 id=&#34;dapr-快速体验&#34;&gt;Dapr 快速体验&lt;/h3&gt;
&lt;p&gt;在 Dapr 的官方文档中提供了 Dapr 安装和 quickstudy 的内容，可以帮助大家快速的安装和体验 Dapr 的能力和使用方式。&lt;/p&gt;
&lt;p&gt;为了更加快捷和方便的体验 Dapr，我们通过 &lt;strong&gt;阿里云知行动手实验室&lt;/strong&gt; 提供了一个超级简单的 Dapr 入门教程，只要大约十分钟就可以快速体验 Dapr 的开发、部署过程：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://start.aliyun.com/course?id=gImrX5Aj&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://start.aliyun.com/course?id=gImrX5Aj&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;有兴趣的同学可以实际体验一下。&lt;/p&gt;
&lt;h2 id=&#34;展望应用和中间件的未来形态&#34;&gt;展望：应用和中间件的未来形态&lt;/h2&gt;
&lt;p&gt;在本文的最后部分，我们展望一下应用和中间的未来形态。&lt;/p&gt;
&lt;h3 id=&#34;云原生的时代背景&#34;&gt;云原生的时代背景&lt;/h3&gt;
&lt;p&gt;首先要申明的是，我们阐述的所有这些内容，都是基于一个大的前提：云原生。&lt;/p&gt;
&lt;p&gt;下面这张图片，摘录自我在2019年10月QCon大会上的演讲 &lt;a href=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;诗和远方：蚂蚁金服Service Mesh深度实践&amp;rdquo;&lt;/a&gt; :&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/cloud-native-trades-2019_hu596cf91bb59ef8ef4319002ba5608797_89441_6baf91bdb53217cf986ad06fcb90185a.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/cloud-native-trades-2019_hu596cf91bb59ef8ef4319002ba5608797_89441_f81e35900543881f4f9121a9d3421832.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/cloud-native-trades-2019_hu596cf91bb59ef8ef4319002ba5608797_89441_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/cloud-native-trades-2019_hu596cf91bb59ef8ef4319002ba5608797_89441_6baf91bdb53217cf986ad06fcb90185a.webp&#34;
               width=&#34;760&#34;
               height=&#34;353&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;当时（2019年）我们刚完成了 kubernetes 和 servicemesh 的探索和大规模落地，并开始 serverless 的新探索，我在文中做了一个云原生落地总结和是否采纳 servciemesh 的建议，大体可以概括为（直接援引原文）：&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;有一点我们是非常明确的：&lt;strong&gt;Mesh化是云原生落地的关键步骤&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;如果云原生是你的诗和远方，那么&lt;strong&gt;ServiceMesh 就是必由之路&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;kubernetes / servicemesh / serverless&lt;/strong&gt; 是当下云原生落地实践的三驾马车，相辅相成，相得益彰。&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;两年之后的今天，回顾当时对云原生发展战略大方向的判断，感触良多。上面这张图片我稍加调整，增加了 Multi-Runtime/容器/多云/混合云的内容，修改如下图：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/cloud-native-background_hu07c095c300210deafcd30614819b253e_495427_e4c3cc37afec94190c3113ccb520fd4a.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/cloud-native-background_hu07c095c300210deafcd30614819b253e_495427_c86a60cd7242b43e8f236f1e2a86fc1f.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/cloud-native-background_hu07c095c300210deafcd30614819b253e_495427_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/cloud-native-background_hu07c095c300210deafcd30614819b253e_495427_e4c3cc37afec94190c3113ccb520fd4a.webp&#34;
               width=&#34;760&#34;
               height=&#34;333&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;和2019年相比，云原生的理念得到了更广泛的认可和采纳：多云、混合云成为未来云平台的主流方向；servicemesh有了更多的落地实践，有更多的公司使用 servicemesh；serverless 同样在过去两年间快速发展。&lt;/p&gt;
&lt;p&gt;云原生的历史大潮还在进行中，而在云原生背景下，应用和中间件将何去何从？&lt;/p&gt;
&lt;h3 id=&#34;应用的期望就是中间件的方向&#34;&gt;应用的期望就是中间件的方向&lt;/h3&gt;
&lt;p&gt;让我们畅想云原生背景下处于最理想状态的业务应用，就当是个甜美的梦吧：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;应用可以使用任意喜爱而适合的语言编写，可以快速开发和快速迭代。&lt;/li&gt;
&lt;li&gt;应用需要的能力都可以通过标准的API提供，无需关心底层具体实现。&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;我个人的对云原生应用未来形态的看法是：Serverless 会是云上应用的理想形态和主流发展方向；而多语言支持、跨云的可移植性和应用轻量化将会是云原生应用的三个核心诉求。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/direction-of-middleware_hu9f13d961e72e76d20dd7d24d650da139_543660_d06833484536d856911be3ee79e0b83b.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/direction-of-middleware_hu9f13d961e72e76d20dd7d24d650da139_543660_1dcf148ff66f4b83aa613c8f54496b50.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/direction-of-middleware_hu9f13d961e72e76d20dd7d24d650da139_543660_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/direction-of-middleware_hu9f13d961e72e76d20dd7d24d650da139_543660_d06833484536d856911be3ee79e0b83b.webp&#34;
               width=&#34;760&#34;
               height=&#34;365&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;应用对云原生的期望，就是中间件前进的方向！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;过去几年间，中间件在云原生的美好目标推动下摸索着前进，未来几年也必将还是如此。servicemesh 探索了 sidecar 模式，Dapr 将 sidecar 模式推广到更大的领域：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;完善的多语言支持和应用轻量化的需求推动中间件将更多的能力从应用中分离出来&lt;/li&gt;
&lt;li&gt;Sidecar 模式会推广到更大的领域，越来越多的中间件产品会 开始 Mesh 化，整合到 Runtime。&lt;/li&gt;
&lt;li&gt;对厂商锁定的天然厌恶和规避，会加剧对可移植性的追求，从而进一步促使为下沉到 Runtime 中的分布式能力提供标准而业界通用的 API。&lt;/li&gt;
&lt;li&gt;API 的标准化和社区认可，将成为 Runtime 普及的最大挑战，但同时也将推动各种中间件产品改进自身实现，实现中间件产品和社区标准API之间的磨合与完善。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在云原生需求推动下，多语言支持、跨云的可移植性和应用轻量化，预计将成为未来几年间中间件产品的突破点和重点发展方向，如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/cloud-native-flywheel_hu976fd141a5e14b32f4bfce5dbe989399_618714_bce5d8e0677aaecb9bbf8f91f17f5097.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/cloud-native-flywheel_hu976fd141a5e14b32f4bfce5dbe989399_618714_fe6b78c3015dbba3bb5744ff560a6a93.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/cloud-native-flywheel_hu976fd141a5e14b32f4bfce5dbe989399_618714_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/cloud-native-flywheel_hu976fd141a5e14b32f4bfce5dbe989399_618714_bce5d8e0677aaecb9bbf8f91f17f5097.webp&#34;
               width=&#34;760&#34;
               height=&#34;344&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在目前的云原生领域，Dapr 项目是一个非常引人注目的新生力量。Dapr 是探路者，开启 Multi-Runtime 理念的全新探索，而这必然是一个艰难的过程。 非常期待有更多的个人和公司，和我们一起加入 Dapr 社区，一起探索，共同成长！&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：关于 Dapr API 标准化的话题，以及 Dapr 在定义 API 和实现 API 遇到的挑战，在现场曾有一段热烈的讨论，我将稍后整理出单独的文章，结合 state api 的深度实践和新的 configuration api的设计过程，深入展开，敬请关注。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;尾声&#34;&gt;尾声&lt;/h2&gt;
&lt;p&gt;在这片文章的最后，让我们用这么一段话来总结全文：&lt;/p&gt;
&lt;p&gt;Dapr 在 Servicemesh 的基础上进一步扩展 Sidecar 模式的使用场景，一方面提供天然的多语言解决方案，满足云原生下应用对分布式能力的需求，帮助应用轻量化和serverless化，另一方面提供面向应用的分布式能力抽象层和标准API，为多云、混合云部署提供绝佳的可移植性，避免厂商锁定。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Dapr将引领云原生时代应用和中间件的未来。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-logo_hu6f17a442d95fb90b3fb1108d28c8bc84_14249_685767b0f21104983067fb42fc894395.webp 400w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-logo_hu6f17a442d95fb90b3fb1108d28c8bc84_14249_69d04d0d7f02a54cb8caa1e7cf50ee40.webp 760w,
               /talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-logo_hu6f17a442d95fb90b3fb1108d28c8bc84_14249_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202103-dapr-from-servicemesh-to-cloudnative/images/dapr-logo_hu6f17a442d95fb90b3fb1108d28c8bc84_14249_685767b0f21104983067fb42fc894395.webp&#34;
               width=&#34;236&#34;
               height=&#34;236&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;附录参考资料&#34;&gt;附录：参考资料&lt;/h2&gt;
&lt;p&gt;本文相关的参考资料如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://dapr.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dapr 官网&lt;/a&gt; 和 &lt;a href=&#34;https://docs.dapr.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dapr 官方文档&lt;/a&gt;：部分 Dapr 介绍内容和图片摘录自 dapr 官方网站&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.infoq.com/articles/multi-runtime-microservice-architecture/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Multi-Runtime Microservices Architecture&lt;/a&gt;: multi-runtime 介绍的内容和图片部分援引自 Bilgin Ibryam 的这篇文章&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>[译] Dapr可视化指南</title>
      <link>https://skyao.net/post/202103-a-visual-guide-to-dapr/</link>
      <pubDate>Thu, 04 Mar 2021 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202103-a-visual-guide-to-dapr/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;译者注：原文来自 Dapr 官方博客 &lt;a href=&#34;https://blog.dapr.io/posts/2021/03/02/a-visual-guide-to-dapr/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;A visual guide to Dapr&lt;/a&gt;，文章内容比较浅显易懂，适合简单阅读以对Dapr有个初步了解。最大的亮点是那张 Dapr 的概述大图，很好，很萌，作者 &lt;a href=&#34;https://sketchthedocs.dev/visual-azure/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Nitya Narasimhan&lt;/a&gt; 是个很会画图的大眼萌妹子。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;作为微软开发者关系部 Cloud Advocacy 团队的一员，我有一个独特的福利，那就是可以从那些在使用和开发方面拥有实际专业知识的人那里听到很多不同的技术和解决方案。因此，当我听到我的开源宣传团队的同事们在和 &amp;ldquo;云原生 &amp;ldquo;和 &amp;ldquo;微服务&amp;rdquo; 一起使用 Dapr 这个名字时，我很感兴趣。&lt;/p&gt;
&lt;p&gt;然后，我很高兴地发现 Dapr 代表 &amp;ldquo;Distributed Application Runtime/分布式应用运行时&amp;rdquo;，并在本月早些时候 &lt;a href=&#34;https://blog.dapr.io/posts/2021/02/17/announcing-dapr-v1.0/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;刚刚达到生产就绪的 v1.0 状态&lt;/a&gt;。我想知道关于它的一切。值得庆幸的是，Dapr有大量的文档来帮助我们入门。所以，当我想学习新的东西时，我做了我经常做的事情——我把学到的东西浓缩成一张大图，一张草图。现在，我想和你分享我的初步学习成果!&lt;/p&gt;
&lt;h2 id=&#34;大图&#34;&gt;大图&lt;/h2&gt;
&lt;p&gt;我之前曾说过。和 65% 的视觉学习者用户一样，我发现，在我深入了解细节之前，将关键信息记录在一张纸上可以有助于把握大局。不仅能让我更好地了解该技术的各个方面，而且还能将其与其他可能与上下文相关的想法或概念 &amp;ldquo;联系起来&amp;rdquo;。所以，让我先分享一下 sketchnote（见下图）。你可以在 &lt;a href=&#34;https://cloud-skills.dev/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;云技能:Sketchnotes网站&lt;/a&gt; 下载一个更高分辨率的版本，并查看 &lt;a href=&#34;https://sketchthedocs.dev/visual-azure/posts/visual-guide-to-sse/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Visual Azure 博客&lt;/a&gt;，以了解其他云计算技术的可视化指南。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202103-a-visual-guide-to-dapr/images/DAPR-1-Overview_hua1812142a75078b0a22a5d1a46458344_13500219_39549ec0974849587a79bf1ca97895d2.webp 400w,
               /post/202103-a-visual-guide-to-dapr/images/DAPR-1-Overview_hua1812142a75078b0a22a5d1a46458344_13500219_dc4c984280f4cc729f221001990182ed.webp 760w,
               /post/202103-a-visual-guide-to-dapr/images/DAPR-1-Overview_hua1812142a75078b0a22a5d1a46458344_13500219_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202103-a-visual-guide-to-dapr/images/DAPR-1-Overview_hua1812142a75078b0a22a5d1a46458344_13500219_39549ec0974849587a79bf1ca97895d2.webp&#34;
               width=&#34;760&#34;
               height=&#34;570&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;主要收获&#34;&gt;主要收获&lt;/h2&gt;
&lt;p&gt;上面的概述图片涵盖了很多领域，但以下是我总结的要点。&lt;/p&gt;
&lt;h3 id=&#34;什么是dapr&#34;&gt;什么是Dapr？&lt;/h3&gt;
&lt;p&gt;Dapr 是 Distributed Application Runtime 的缩写。它是一个可移植的、事件驱动的运行时，使应用开发者可以轻松构建弹性的无状态和有状态应用，而这些应用可以运行在云和边缘环境上。更重要的是，Dapr 支持多种编程语言和开发者框架，为我们提供了一个快速体验和使用的起点。你可以在 &lt;a href=&#34;https://docs.dapr.io/concepts/overview/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dapr 概述文档&lt;/a&gt; 中获得更多细节。&lt;/p&gt;
&lt;h3 id=&#34;为什么使用dapr&#34;&gt;为什么使用Dapr？&lt;/h3&gt;
&lt;p&gt;许多应用开发者都有传统的3层（客户端-服务器-数据库）架构的经验。然而，云原生系统依赖于松耦合的系统和微服务架构，旨在拥抱大规模、快速变更和弹性运维。现在，开发人员面临着一系列的全新挑战，如发现（和调用）微服务、管理密钥以及故障后恢复状态。&lt;/p&gt;
&lt;p&gt;Dapr 提炼了最佳实践，将微服务构建成独立、开放的&amp;rdquo;&lt;a href=&#34;https://docs.dapr.io/concepts/overview/?WT.mc_id=mobile-17439-ninarasi#microservice-building-blocks-for-cloud-and-edge&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;构建块&lt;/a&gt;&amp;quot;，然后暴露 API 以便于集成和清洗的分离关注点。开发者只需使用这些块中所需的子集，逐步构建，就能很快让他们的应用启动并运行。&lt;/p&gt;
&lt;h3 id=&#34;dapr如何工作&#34;&gt;Dapr如何工作？&lt;/h3&gt;
&lt;p&gt;Dapr 以 &lt;a href=&#34;https://docs.dapr.io/concepts/overview/?WT.mc_id=mobile-17439-ninarasi#sidecar-architecture&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;sidecar 架构&lt;/a&gt; 的形式暴露其 API 。实际上，Dapr 可以在自己的容器或进程中与主应用程序一起运行。您的应用程序不需要将 Dapr 集成到其核心中，而是可以通过 HTTP 或 gRPC 调用构建块 API。这清晰的分离了应用程序逻辑与微服务支持服务，更容易扩展您的解决方案 —— 从自托管（开发）到云托管（虚拟机或 Kubernetes）和边缘部署。&lt;/p&gt;
&lt;p&gt;虽然您可以简单地使用手动制作的 HTTP 或 gRPC 调用来访问这些 API，但您也有一套丰富的 &lt;a href=&#34;https://docs.dapr.io/developing-applications/sdks/?WT.mc_id=mobile-17439-ninarasi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;特定语言 SDK&lt;/a&gt;，为你提供语言优化的类型化 API，更容易集成和测试。目前支持的语言 SDK 包括 C++、Go、Java、JavaScript、Python、PHP、Rust 和 .NET! 请注意，Dapr 本身是语言无关的，它提供了一个默认的 RESTful HTTP API，如果你喜欢的语言 SDK 还不支持，你可以直接调用。&lt;/p&gt;
&lt;h3 id=&#34;还应该知道什么&#34;&gt;还应该知道什么？&lt;/h3&gt;
&lt;p&gt;只有三件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Dapr v1.0 已经做好了生产准备&lt;/strong&gt;!  Dapr有几个早期采用者，v1.0版本更加注重性能、安全、高可用性和一致性等方面。请 &lt;a href=&#34;https://blog.dapr.io/posts/2021/02/17/announcing-dapr-v1.0/#release-highlights?WT.mc_id=mobile-17439-ninarasi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;在此阅读该版本的亮点&lt;/a&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dapr 是开源的&lt;/strong&gt;，您可以在 &lt;a href=&#34;https://github.com/dapr&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Github&lt;/a&gt;上找到核心运行时代码、文档、快速开始等，并 &lt;a href=&#34;https://docs.dapr.io/contributing/?WT.mc_id=mobile-17439-ninarasi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;欢迎社区贡献&lt;/a&gt;。Dapr &lt;a href=&#34;https://aka.ms/dapr-discord&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Discord 服务器&lt;/a&gt; 和定期的 &lt;a href=&#34;https://github.com/dapr/community#community-meetings&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;社区会议&lt;/a&gt; 是与社区互动的好方法!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dapr 生态系统正在成长&lt;/strong&gt;! 有70多个 &lt;a href=&#34;https://docs.dapr.io/concepts/components-concept/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;组件&lt;/a&gt; 是由社区贡献的，所以 Dapr 可以帮助您的应用程序与广泛的技术集成，也使它在多云和混合云场景下有非常好的可移植性。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;入门最简单的方法是通过这个 &lt;a href=&#34;https://docs.dapr.io/getting-started/?WT.mc_id=mobile-17439-ninarasi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;入门教程&lt;/a&gt; 设置您的本地开发环境（自托管模式），并探索提供的quickstart，用代码学习核心概念！不要忘了关注@daprdev的Twitter，以获得更新的消息。不要忘记在 Twitter 上关注&lt;a href=&#34;https://twitter.com/daprdev&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;@daprdev&lt;/a&gt;，以获得更新和新闻的通知。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译] Dapr v1.0发布</title>
      <link>https://skyao.net/post/202102-announcing-dapr-v1.0/</link>
      <pubDate>Thu, 18 Feb 2021 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202102-announcing-dapr-v1.0/</guid>
      <description>&lt;p&gt;英文原文来自 Dapr 官方网站博客文章 &lt;a href=&#34;https://blog.dapr.io/posts/2021/02/17/announcing-dapr-v1.0/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Announcing Dapr v1.0
&lt;/a&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;strong&gt;分布式应用程序运行时现在已经生产就绪啦！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;今天，我们很高兴地发布分布式应用运行时（&lt;a href=&#34;https://dapr.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Distributed APplication Runtime / Dapr&lt;/a&gt;）的 &lt;a href=&#34;https://github.com/dapr/dapr/releases/tag/v1.0.0&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;v1.0版本&lt;/a&gt;，它已经达到了生产就绪所需的稳定性和企业准备。Dapr是一个开源、可移植、事件驱动的运行时，它使开发人员能够轻松地构建运行在云平台和边缘的弹性而微服务化的应用程序，无论是无状态还是有状态。Dapr 让开发人员能够专注于编写业务逻辑，而不是解决分布式系统的挑战，从而显著提高生产力并减少开发时间。Dapr 降低了基于微服务架构构建现代云原生应用的准入门槛，而通过此次发布的v1.0版本，Dapr 应用可以部署到生产场景中的自托管基础设施或 Kubernetes 集群。&lt;/p&gt;
&lt;p&gt;自 &lt;a href=&#34;https://cloudblogs.microsoft.com/opensource/2019/10/16/announcing-dapr-open-source-project-build-microservice-applications/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;2019年10月首次发布&lt;/a&gt; 以来，Dapr已有 &lt;a href=&#34;https://github.com/dapr/dapr/tags&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;14个版本&lt;/a&gt;，每个版本都建立在大量的社区和用户反馈基础上，以推动改进、稳定性和性能。这些版本立足于构建真实的应用，反映了当今开发者在开发云原生应用时的实际情况；无论是在云平台、边缘还是私有基础设施上，社区都在加紧贡献与Azure、AWS、阿里巴巴和 Google cloud 集成的 Dapr 组件。&lt;/p&gt;
&lt;h2 id=&#34;解决现实世界场景中的分布式应用挑战&#34;&gt;解决现实世界场景中的分布式应用挑战&lt;/h2&gt;
&lt;p&gt;从成立之初开始，Dapr 开源项目就面向那些正在构建新的现实世界绿色地带（greenfield）应用的开发者，以及那些在云原生架构中迁移和利用现有应用和组件的开发者。Dapr 方法的关键是满足开发者和企业的现状，帮助他们实现应用的现代化，并利用他们在云原生和微服务架构中的现有技能。在v1.0版本中，我们专注于将 Kubernetes 作为运行生产应用的主要托管环境，随着Dapr的进一步成熟，我们希望在无服务器（serverless）环境中看到 Dapr。在过去的一年半时间中，我们与早期采用者和合作伙伴紧密合作，因此 Dapr 现在已经成为多个基于 Kubernetes 的生产和预生产应用的核心。在这个用户驱动的过程中，Dapr 社区改进了Java、.NET和Python SDK的原生语言体验，用真实的工作负载测试了规模和性能，增加了安全特性，并证明了 Dapr 的 Actor 编程模型是工作流和物联网（IoT）场景的最佳选择。以下是一些早期采用者的故事，以凸显 Dapr 如今的使用情况。&lt;/p&gt;
&lt;h3 id=&#34;蔡司光学和光电子领域的国际技术领导者&#34;&gt;蔡司：光学和光电子领域的国际技术领导者&lt;/h3&gt;
&lt;p&gt;ZEISS 面临的挑战是维护和更新一个具有20年历史的带有硬编码业务规则的后端系统。原来的订单验证和路由解决方案是基于一个具有固定容量的单体架构，开发人员在不直接在系统中重新配置表格的情况下，无法轻松的更新、重新路由或跟踪订单。此外，业务部门无法直接控制其订单处理流程。由于存在大量的系统依赖，变更总是需要代价高昂而耗时的开发人员干预。为了解决这个问题，ZEISS 使用 Azure 和 Dapr 开发了一个新的应用程序，可以更快地完成客户订单，同时还加快了开发速度，并改善了公司的业务连续性。你可以在 &lt;a href=&#34;https://customers.microsoft.com/en-us/story/1336089737047375040-zeiss-accelerates-cloud-first-development-on-azure-and-streamlines-order-processing&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;这里&lt;/a&gt; 阅读更多关于他们的故事。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202102-announcing-dapr-v1.0/images/zeiss-diagram_huf094eedfd3008e5bc8e4ad7fe791dd83_182493_2505d747b29a8b1d1126a1d80be8b6d1.webp 400w,
               /post/202102-announcing-dapr-v1.0/images/zeiss-diagram_huf094eedfd3008e5bc8e4ad7fe791dd83_182493_49664d78d9806fac72c70b9a585dd01b.webp 760w,
               /post/202102-announcing-dapr-v1.0/images/zeiss-diagram_huf094eedfd3008e5bc8e4ad7fe791dd83_182493_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202102-announcing-dapr-v1.0/images/zeiss-diagram_huf094eedfd3008e5bc8e4ad7fe791dd83_182493_2505d747b29a8b1d1126a1d80be8b6d1.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;ignition-group一家位于南非的技术企业专注于客户承诺和销售支持工具&#34;&gt;Ignition Group：一家位于南非的技术企业，专注于客户承诺和销售支持工具&lt;/h3&gt;
&lt;p&gt;Ignition Group 打造的订单处理软件可以跟踪产品、管理订阅和处理来自各种来源的支付。订单处理涉及许多依赖，有一个采购跟踪机制，这个机制会调用客户订阅，触发会计和计费流程，并确定适当的支付渠道。Ignition Group 希望微服务能给其工作流逻辑带来好处——高可用性、弹性、可扩展性和性能。使用 Dapr 和 .NET Core，Ignition Group 构建了一个新的、可扩展性更好的、可维护的订单处理和支付系统，该系统目前已在生产中运行。Ignition Group 今天已经运行在生产中，你可以在 &lt;a href=&#34;https://customers.microsoft.com/en-us/story/1335733425802443016-ignition-group-speeds-development-and-payment-processing-using-dapr-and-azure&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;这里&lt;/a&gt; 阅读更多关于他们的故事。&lt;/p&gt;
&lt;h3 id=&#34;roadwork采集数据洞若观火&#34;&gt;Roadwork：采集数据洞若观火&lt;/h3&gt;
&lt;p&gt;Roadwork 是一家为自主系统提供端到端平台的初创公司，让用户产生可执行的洞察力并据此行动。目前，他们专注于数据提取技术，并以全面集成自主系统为路径。通过对 Dapr 与 &lt;a href=&#34;https://keda.sh/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;KEDA&lt;/a&gt; 的梳理，他们在 Kubernetes 上创建了一个生产服务，根据传入的客户负载请求，自动扩展应用和集群。Dapr 提供了使用 RabbitMQ 的 pub/sub 的抽象和集成，其能够轻松拥有 &lt;a href=&#34;https://docs.dapr.io/developing-applications/building-blocks/pubsub/pubsub-overview/#consumer-groups-and-competing-consumers-pattern&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;竞争消费者模式&lt;/a&gt;。今天，Roadwork的第一个产品 Scraper.ai 已经在生产中运行。在 &lt;a href=&#34;https://blog.dapr.io/posts/2021/02/09/running-dapr-in-production-at-roadwork/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;这里&lt;/a&gt; 了解更多信息。&lt;/p&gt;
&lt;h2 id=&#34;社区和生态系统&#34;&gt;社区和生态系统&lt;/h2&gt;
&lt;p&gt;是社区的努力让 Dapr 成长到 v1.0。自 Dapr 首次公布以来，开源社区团结在 Dapr 周围并不断成长，令人惊叹——从2019年10月的114个贡献者增长到今天的700个。在短短的16个月内，增长了6倍多!&lt;/p&gt;
&lt;p&gt;社区对项目的贡献涉及到 Dapr 的每一个仓库，范围包括提交问题、参与功能提案讨论、提供样本，当然也包括贡献代码。社区成员对项目贡献最大的部分包括 Dapr 运行时、文档、CLI 和 SDK。另外一个关键的贡献领域是创建了一个丰富的组件生态系统。可供开发人员使用的组件超过70个，使 Dapr 成为一个可以适用于广泛场景的解决方案，包括开源技术和云提供商的特定集成。当开发人员希望创建具有高可移植性的云平台无关的应用程序时，这些使得 Dapr 成为一个有吸引力的选择。&lt;/p&gt;
&lt;p&gt;贡献并不局限于个人，还包括阿里云、HashiCorp、微软等组织，以及上文提到的 ZEISS 和 Ignition Group 等早期采用者。Dapr 生态系统还包括合作伙伴的技术栈，这些技术栈为使用 Dapr 的开发者提供了附加值。例如，New Relic 提供了关于他们的监控工具如何与 Dapr 无缝工作的指导，这要归功于 Dapr 使用的标准跟踪协议，这些协议可以在不改变任何代码的情况下轻松地检测您的应用程序。&lt;/p&gt;
&lt;p&gt;培养一个开放和包容的社区是 Dapr 项目的首要目标。作为该承诺的一部分，我们分享了 &lt;a href=&#34;https://blog.dapr.io/posts/2020/09/30/transitioning-the-dapr-project-to-open-governance/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;向开放治理模式的过渡&lt;/a&gt;，这也是我们保持 Dapr 开放、供应商中立和包容性的方式。我们的愿景是继续这一旅程，并打算在不久的将来让 Dapr 加入一个开放软件基金会。同时，我们邀请您通过 &lt;a href=&#34;https://github.com/dapr&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;GitHub&lt;/a&gt;、Dapr &lt;a href=&#34;https://github.com/dapr/community#community-meetings&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;社区定期会议&lt;/a&gt; 和最近推出的 &lt;a href=&#34;https://aka.ms/dapr-discord&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Discord 服务器&lt;/a&gt;  与 Dapr  社区互动。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;在阿里云，我们相信 Dapr 将引领微服务的发展。通过采用Dapr，我们的客户现在可以以更快的速度来构建可移植和健壮的分布式系统。&amp;rdquo; —— 阿里云资深技术专家 李响&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;发布亮点&#34;&gt;发布亮点&lt;/h2&gt;
&lt;p&gt;在最近的几个月中，我们已经发布了三个 v1.0 版本的候选版本，专注于从社区获得反馈，并为v1.0版本做准备。在性能、安全、高可用性（HA）和一致性等方面更深入地关注于生产就绪。完整的发布说明可以在 &lt;a href=&#34;https://github.com/dapr/dapr/releases/tag/v1.0.0&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;这里&lt;/a&gt; 获得，以下是一些亮点：&lt;/p&gt;
&lt;h3 id=&#34;作为生产环境的kubernetes&#34;&gt;作为生产环境的Kubernetes&lt;/h3&gt;
&lt;p&gt;对于v1.0版本，Kubernetes 是首选的托管环境，它与 &lt;a href=&#34;https://docs.dapr.io/operations/hosting/kubernetes/kubernetes-overview/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dapr控制平面和 Dapr sidecar架构深度集成&lt;/a&gt;。例如，在运维上，通过Dapr CLI &amp;ldquo;init&amp;rdquo; 和 &amp;ldquo;upgrade&amp;rdquo; 命令简化了 Dapr 在 Kubernetes 上的安装和升级，这些命令可以拉取正确的 Dapr 运行时版本，并确保这些版本以受控的方式推出，包括迁移正在使用中的证书。您可以在 HA 模式下安装 Dapr 控制平面，确保多个实例同时运行，而且 Dapr sidecar 有一个健康端点，可以实现 Kubernetes 就绪（readiness）和活泼度（liveness）探针以确定其健康状态。在整个发布候选版本的过程中，我们与早期采用者密切合作，以确保他们能够以可运维的方式迁移到每个 Dapr 运行时版本，而不是构建新的集群。请参阅 &lt;a href=&#34;https://docs.dapr.io/operations/hosting/kubernetes/kubernetes-production/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;生产部署指南&lt;/a&gt; 以了解更多信息。&lt;/p&gt;
&lt;h3 id=&#34;性能一致性和支持&#34;&gt;性能、一致性和支持&lt;/h3&gt;
&lt;p&gt;在云原生应用中，性能是至关重要的，而 Dapr 对高性能非常重视。一个经常被提起的话题是，由 sidecar 模型为应用程序完成所有繁重工作所带来的影响，以及数据平面性能的权衡取舍。其中一个特别关注的领域是服务调用构建块，在这里，当通过两个 Dapr sidecar 在两个应用之间调用并收到响应时，&lt;a href=&#34;https://docs.dapr.io/operations/performance-and-scalability/perf-service-invocation/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dapr 在p90时增加了约1.2ms的端到端延迟，在p99时增加了约2ms&lt;/a&gt;。由此可见，Dapr具有极低的服务间延迟，并针对高吞吐量场景进行了优化。Dapr 有超过70个由社区开发的组件，为了确保对这些组件的使用信心，它们要经过一系列的一致性测试。组件首先从 alpha 状态开始，最终达到 GA 状态，并需要用户在生产中使用它们。对于v1.0版本，只有部分已经在生产中广泛使用的组件被批准为 GA，其他组件在满足标准后也将加入其中。与众多开源云原生技术一样，变更、修复和改进的引入速度很快，这意味着受支持版本存在滚动窗口。重要的是，Dapr v1.0版本宣称 API 层面是稳定的，如果未来需要修改，将通过 &lt;a href=&#34;https://docs.dapr.io/operations/support/support-versioning/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;版本机制&lt;/a&gt; 来保证 API 的完全向后兼容，如果需要破坏性的修改，则会提前几个版本注明。最后，从支持的角度来看，&lt;a href=&#34;https://docs.dapr.io/operations/support/support-release-policy/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;当前和之前的版本都将支持&lt;/a&gt; 在出现关键问题或安全问题时进行补丁更新。&lt;/p&gt;
&lt;h3 id=&#34;安全&#34;&gt;安全&lt;/h3&gt;
&lt;p&gt;安全一直是 Dapr 的核心主题，因为我们已经认识到基于微服务架构构建安全的现代分布式应用的复杂性，而 Dapr 已经通过了多项独立的&lt;a href=&#34;https://docs.dapr.io/concepts/security-concept/#security-audit&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;安全审计&lt;/a&gt;。为了抵御应用程序之间的中间人攻击，您需要进行加密，而 Dapr 通过其控制平面服务发出的x.509证书提供加密，这些证书会自动更新和滚动。为了提供对资源的访问控制，如状态存储、密钥、服务间调用，或发布/订阅特定主题的能力，您需要细粒度的访问控制策略（ACL）。当使用 &lt;a href=&#34;https://spiffe.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;spiffe&lt;/a&gt; 作为身份标准访问资源时，Dapr提供了广泛的ACL。当运行应用程序时，您可以将这些应用程序隔离在不同的命名空间中，以便进行运维部署和隔离。这些广泛的安全能力在下图中显示，这里有三个利用 Dapr 安全特性的微服务：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34;
           src=&#34;https://skyao.net/post/202102-announcing-dapr-v1.0/images/dapr-security.svg&#34;
           loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;编程语言和sdk&#34;&gt;编程语言和SDK&lt;/h3&gt;
&lt;p&gt;Dapr 以其编程语言、框架和工具拥抱所有的开发者社区。Dapr 被设计为可以通过 HTTP 和 gRPC 协议从任何编程语言中使用，这意味着您不需要在编译时包含任何依赖关系。当然，为了改善开发者的原生语言体验，&lt;a href=&#34;https://docs.dapr.io/developing-applications/sdks/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Java、.NET、Python和Go的SDK&lt;/a&gt; 也以v1.0 生产就绪的形式发布，这反映了它们在社区和组织中的成熟应用。这些SDK可以让您作为开发者，使用您最喜欢的开发环境，如 VS Code 或 IntelliJ。JavaScript/Node.js、C++、Rust 和 PHP 的 SDK目前处于预览阶段，随后将发布v1.0版本。PHP SDK包括对 Actor 的支持，这是社区为 Dapr 广泛且不断增长的编程语言列表做出贡献的一个极佳的例子。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202102-announcing-dapr-v1.0/images/dapr-sdks_hu536b30274f1ac6815de7b72c4a53cb48_168812_aada038176335f0fdc8f13a19f11650e.webp 400w,
               /post/202102-announcing-dapr-v1.0/images/dapr-sdks_hu536b30274f1ac6815de7b72c4a53cb48_168812_538ca13a539384e1e82fa63bce5a2b81.webp 760w,
               /post/202102-announcing-dapr-v1.0/images/dapr-sdks_hu536b30274f1ac6815de7b72c4a53cb48_168812_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202102-announcing-dapr-v1.0/images/dapr-sdks_hu536b30274f1ac6815de7b72c4a53cb48_168812_aada038176335f0fdc8f13a19f11650e.webp&#34;
               width=&#34;760&#34;
               height=&#34;341&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;展望未来&#34;&gt;展望未来&lt;/h2&gt;
&lt;p&gt;通过这个 v1.0 版本，我们为构建现代云原生应用所需的基本构建块奠定基础的旅程才刚刚起步。社区驱动意味着社区将在未来的版本中设定项目的优先级，其中许多优先级已经被投票通过。例如，增强现有构建块的亮点，包括在状态管理中使用 OData 查询和过滤多个值的能力。在 pub/sub 中，&lt;a href=&#34;https://github.com/dapr/dapr/issues/2582&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;支持 CloudEvents v1.0 过滤功能&lt;/a&gt;，以根据消息内容过滤出用户感兴趣的事件。在可观测性方面，提供一个API 用于 &lt;a href=&#34;https://github.com/dapr/dapr/issues/100&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;从应用中追踪事件&lt;/a&gt;，防止您不得不绑定到特定的监控类库，并使 actor 能够直接&lt;a href=&#34;https://github.com/dapr/dapr/issues/501&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;订阅 pub/sub&lt;/a&gt; 事件，从而开启了丰富的事件驱动场景。&lt;/p&gt;
&lt;p&gt;新的构建块提案包括用于读写应用程序配置数据的配置 API，例如来自 Azure Configuration Manager  或 GCP Configuration Management。领导者选举构建块，提供创建单例实例、同步或锁定语义能力。用于网络级服务调用的透明代理构建块，使您能够根据 URL 或 DNS 地址来路由消息，以及用于熔断器、隔离舱和超时等模式的更多弹性构建块。&lt;/p&gt;
&lt;p&gt;最后，在v1.0版本中，Dapr 集成了多个开发者框架，包括 ASP.NET Core、Java Spring Boot、Azure Functions 和 Logic Apps，而我们认为这还将继续，更多的开源框架如 Django、Nodejs 和 Kyma 都是潜在的例子。此外，考虑到 Dapr 的托管平台独立性，在虚拟机、边缘平台（如Azure Stack Hub或AWS Outpost）和其他分布式系统平台上提供对 Dapr 控制平面一流的支持，可以实现应用的可移植性。&lt;/p&gt;
&lt;h2 id=&#34;开始和贡献&#34;&gt;开始和贡献&lt;/h2&gt;
&lt;p&gt;我们希望您能试用 Dapr v1.0。您可以使用文档中的 &lt;a href=&#34;https://docs.dapr.io/getting-started/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;入门指南&lt;/a&gt; 进行学习，然后通过 &lt;a href=&#34;https://docs.dapr.io/getting-started/quickstarts/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;快速入门&lt;/a&gt; 来深入了解。如果你需要更多信息，&lt;a href=&#34;https://github.com/dapr/samples&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;样本库&lt;/a&gt; 是 Dapr 社区捐赠的不同的应用程序的展示。Dapr 文档 &lt;a href=&#34;https://docs.dapr.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;docs.dapr.io&lt;/a&gt; 是全面的指南，还有几本书，包括&lt;a href=&#34;https://learning.oreilly.com/library/view/learning-dapr/9781492072416/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;《 Learning Dapr》&lt;/a&gt;、&lt;a href=&#34;https://www.packtpub.com/product/practical-microservices-with-dapr-and-net/9781800568372&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;《使用Dapr和.NET实践微服务》&lt;/a&gt;以及最新发布的免费电子书&lt;a href=&#34;https://aka.ms/dapr-ebook&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;《Dapr for .NET开发者》&lt;/a&gt;。如果您有任何疑问，遇到问题或想与社区的其他成员交流，Dapr社区随时在 &lt;a href=&#34;https://aka.ms/dapr-discord&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Discord&lt;/a&gt; 上欢迎您的到来。&lt;/p&gt;
&lt;p&gt;对于 Dapr 来说，v1.0版本的发布只是一个开始，在这个过程中，我们感谢并鼓励您的持续帮助、反馈和贡献。无论是编写新的组件，提出建议，贡献新的构建块，还是增强您最喜欢的语言的SDK，我们都希望听到您的意见并与您一起参与。在这个微服务开发的时代，作为一名开发者，这是一个令人兴奋的时刻，Dapr 将释放您的生产力和创造力，轻松构建现代化的分布式应用。我们非常高兴的看到您继续使用这个项目，看到您使用它进行构建，并对 Dapr 的发展保持关注。&lt;/p&gt;
&lt;h2 id=&#34;译者注&#34;&gt;译者注&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;英文原文来自 Dapr 官方网站博客文章 &lt;a href=&#34;https://blog.dapr.io/posts/2021/02/17/announcing-dapr-v1.0/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Announcing Dapr v1.0&lt;/a&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;译者所在的阿里云云原生团队深度参与了 Dapr 1.0 的开发，同时也正在内部小规模的试点 Dapr ，稍后将分享阿里云在 Dapr 上的实践。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;文中提到的  &lt;a href=&#34;https://learning.oreilly.com/library/view/learning-dapr/9781492072416/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;《 Learning Dapr》&lt;/a&gt; 一书，我们团队正在翻译中，预计很快就将出版发行，欢迎关注。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/dapr-cn&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dapr中文社区&lt;/a&gt; 目前正在组织翻译 Dapr 的官方文档，预计不久将完成部分章节并在官方上线，同样欢迎关注，更欢迎一起参与。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>Dapr</title>
      <link>https://skyao.net/project/dapr/</link>
      <pubDate>Fri, 01 Jan 2021 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/project/dapr/</guid>
      <description></description>
    </item>
    
    <item>
      <title>[译] 深层系统的弹性</title>
      <link>https://skyao.net/post/202008-resilience-deep-systems/</link>
      <pubDate>Mon, 17 Aug 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202008-resilience-deep-systems/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://www.infoq.com/articles/resilience-deep-systems/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Resilience in Deep Systems&lt;/a&gt;，作者  Amir Souchami 。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;主要心得&#34;&gt;主要心得&lt;/h3&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;li&gt;通过将平衡的服务粒度、异步通信和正确的工具结合起来，提高系统的可观察性，从而最大限度地提高系统的弹性。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;当使用微服务架构来构建一个成功的产品，尤其是一个需要快速成长的产品时，你迟早会意识到你的系统变得有&amp;quot;深度&amp;quot;了。&lt;/p&gt;
&lt;p&gt;系统的深度可以认为是应用栈中微服务层的数量。&lt;/p&gt;
&lt;p&gt;当今最前沿的云技术，如Service Mesh、Container和Serverless计算，使团队能够轻松地在系统中添加许多微服务层。&lt;/p&gt;
&lt;p&gt;在这样的系统中，一个微服务其实并不能真正的独立&amp;ndash;它依赖于其他微服务，反之亦然。&lt;/p&gt;
&lt;p&gt;当微服务的通信越来越深时，会使公司快速诊断错误或性能瓶颈的能力变得复杂。&lt;/p&gt;
&lt;p&gt;因此，对于想要维持弹性、容错性和性能的研发团队来说，深层系统是一个严峻的挑战。&lt;/p&gt;
&lt;p&gt;如果没有正确的思维方式和正确的工具，产品和它的客户将受到危害。&lt;/p&gt;
&lt;p&gt;可以在不影响弹性的情况下，构建复杂的、带有深度链接微服务的系统。&lt;/p&gt;
&lt;p&gt;以下是有助于在深层系统中维持弹性的3种方式。&lt;/p&gt;
&lt;h3 id=&#34;1-服务粒度&#34;&gt;1. 服务粒度&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;不要跟风炒作；要与真实的业务能力相对应。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在使用微服务架构设计复杂的应用时，我们希望定义一组内聚的、松散耦合的服务。这方面最大的一个问题是，我们 &lt;strong&gt;如何将应用拆分成微服务&lt;/strong&gt;？&lt;/p&gt;
&lt;p&gt;因为微服务架构本质上遵循了 &amp;ldquo;做一件事，做好一件事&amp;rdquo; （&amp;ldquo;Do one thing and do it well&amp;rdquo;）的Unix哲学，可以简单地说，每个原子函数都应该是一个微服务（这是炒作）。虽然理论上听起来很完美，但如果简单遵循这种理念，就会产生大量的微服务。&lt;strong&gt;你是否能成功有效地维护这么多服务呢？&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我准备在 us-west-1 中提供 &amp;ldquo;整数/integer&amp;quot;服务。&lt;/p&gt;
&lt;p&gt;一个被炒作的开发者曾经如是说。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在现实中，我们发现，定义与真实业务能力相对应的微服务，会产生大量自成一体的业务功能碎片。这些碎片仍然可以非常凝聚，松散耦合，具备良好的扩展性，可测试，可构建，并可以归属于一个足够小的团队。所有这些都是微服务的支柱。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202008-resilience-deep-systems/images/pillars-of-microservices_hufa05c7b0696a90b59df07f6fddb395ae_164973_811913cf764771872a99b6b50608333e.webp 400w,
               /post/202008-resilience-deep-systems/images/pillars-of-microservices_hufa05c7b0696a90b59df07f6fddb395ae_164973_78ce5749731f65e39be375298f0aee1b.webp 760w,
               /post/202008-resilience-deep-systems/images/pillars-of-microservices_hufa05c7b0696a90b59df07f6fddb395ae_164973_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202008-resilience-deep-systems/images/pillars-of-microservices_hufa05c7b0696a90b59df07f6fddb395ae_164973_811913cf764771872a99b6b50608333e.webp&#34;
               width=&#34;760&#34;
               height=&#34;550&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;此外，通过创建共享库，即DRY（Don&amp;rsquo;t Repeat Yourself）来避免多个微服务中的代码重复是一种常见的做法。DRY是一个重要的概念。然而，有时候过于炒作。在现实中，我们发现，有时候共享类库会把我们的微服务相互耦合起来，降低了微服务之间隔离性和独立性的效果。同时也会拖慢团队进行改变的速度，因为他们并不总是能完全了解其他团队的使用模式。事实上，平衡微服务的粒度与平衡适量的共享类库是相辅相成的。在超粒度的微服务架构中，共享类库和代码重复都是一种负担。但当保持微服务粒度平衡时，代码重复的代价可以通过独立性的提高得到补偿。&lt;/p&gt;
&lt;h3 id=&#34;2-共享数据---安全和一致性&#34;&gt;2. 共享数据 - 安全和一致性&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;请注意：最糟糕的单体是分布式单体&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;微服务可以用各种同步和异步的方式进行通信。随着系统的发展，微服务之间的连接变得更加复杂。以容错的方式进行通信，并让在服务之间移动的数据保持一致性和新鲜成为一个巨大的挑战。&lt;/p&gt;
&lt;p&gt;有时，微服务必须以同步的方式进行通信。然而，在整个深层系统中使用同步通信，如REST，使得链中的各个组件之间的耦合非常紧密。它对网络的可靠性产生了更大的依赖。同时，链中的每一个微服务都需要完全可用，以避免数据不一致，或者更糟糕的是，如果微服务链中的一个环节出现故障，系统就会中断。在现实中，我们发现这样的深度系统表现得更像一个单体，或者更准确地说是一个分布式单体，这使得微服务的优势无法充分体现。&lt;/p&gt;
&lt;p&gt;使用异步的、事件驱动的架构，可以让微服务向其他微服务发布新鲜的数据更新。与同步通信不同，添加更多的数据订阅者是很容易的，而且不会导致发布者服务使用更多的流量。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202008-resilience-deep-systems/images/asynchronous-event-driven-architecture-microservices_hu94efa21489b31660b471b5638a0bb35e_15896_b57ce37a397eb5a1043ceee72e135b63.webp 400w,
               /post/202008-resilience-deep-systems/images/asynchronous-event-driven-architecture-microservices_hu94efa21489b31660b471b5638a0bb35e_15896_767d501b28b0da80c692ea0d003d2272.webp 760w,
               /post/202008-resilience-deep-systems/images/asynchronous-event-driven-architecture-microservices_hu94efa21489b31660b471b5638a0bb35e_15896_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202008-resilience-deep-systems/images/asynchronous-event-driven-architecture-microservices_hu94efa21489b31660b471b5638a0bb35e_15896_b57ce37a397eb5a1043ceee72e135b63.webp&#34;
               width=&#34;332&#34;
               height=&#34;253&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;异步系统是&amp;quot;最终一致&amp;quot;的。这意味着，如果微服务在消费数据更新时滞后，它的数据副本可能不是最新的。在读密集型、高吞吐量的服务中，使用同步通信需要复杂的缓存管理和清理机制、服务发现和重试技术。然而，通过使用 &amp;ldquo;推&amp;rdquo; 而不是 &amp;ldquo;拉&amp;rdquo;，系统可以几乎实时地处理数据更新，并处理掉所有的开销。&lt;/p&gt;
&lt;p&gt;事实上，事件驱动的架构具有挑战性，采用起来也并非易事。你将不得不在你的技术栈中引入新的工具&amp;ndash;事件总线/event bus（如Kafka）。并且要学会如何处理事件流，而不是只响应同步的REST请求。即使这很有挑战性，需要额外的努力才能采用，但许多公司还是转向了这样的架构，因为它有助于降低数据的不一致性问题，提高深度系统的弹性。&lt;/p&gt;
&lt;h3 id=&#34;分布式故事讲述&#34;&gt;分布式故事讲述&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;不要丢失事件流转的视角；提高可观察性。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;可观察性不仅仅是知道问题发生了，而是知道问题发生的原因。&lt;/p&gt;
&lt;p&gt;越来越多的微服务层以及它们的日志数据对研发团队和业务分析师来说都是一个挑战。排除问题有时需要跨多个代码库、团队和仪表盘进行推理。不幸的是，它通常会与 &amp;ldquo;on-call shifts from hell/地狱代班&amp;rdquo; 和团队之间的 &amp;ldquo;blaming games/指责游戏&amp;rdquo; 一起出现。&lt;/p&gt;
&lt;p&gt;假设你已经将各种微服务的日志和指标收集到一个集中的分析工具中，（比如ElasticSearch和/或数据湖），并假设你有一套定义明确的警报，当你试图弄清楚一个深层系统中的问题时，你可能还是会发现自己迷失并说 &amp;ldquo;我们没有足够的可见性，让我们创建一个仪表盘 &amp;quot; 或者 &amp;ldquo;天哪！我们有太多的仪表盘了&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;这时，请问自己：&lt;strong&gt;仪表盘或日志跟踪如何才能讲述一个故事？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这里有一些关于可视化 &amp;ldquo;what and why&amp;rdquo; 的想法：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Correlation ID/Trace ID&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;深层系统是由微服务链组成的，每个微服务都会记录有意义的操作数据。通过在一个工作流的开始分配一个关联ID，（无论是http请求还是触发的作业），然后通过日志消息传播它，这些日志消息是基于调用链的顺序请求和响应，你将获得通过所有通信渠道跟踪一个完整流程的机会。观察你的日志，无论是在特定的关联ID上，还是通过关联ID对数据进行分组，实际上都可以讲述一个很好的故事，这将帮助你从整个深层系统中快速找到并确定问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Distributed tracing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;分布式跟踪系统，如 Zipkin 和 Jaeger，使你能够在不同的系统和服务中跟踪调用栈。这也是通过自动创建唯一的 trace ID来实现的，然而，与普通的 &amp;ldquo;Correlation ID&amp;quot;不同，这些系统带有强大的UI工具，可以深入到你的系统中去，精确地指出问题。另外，与 &amp;ldquo;CorrelationID&amp;rdquo; 不同的是，traces通常只在你的一小部分流量上运行，所以虽然它非常详细，但你并没有一个完整的视图。此外，分布式追踪有时会丢失业务视角，因为对于非工程人员（如业务分析师、支持人员）来说，追踪结果可能很难理解。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202008-resilience-deep-systems/images/distributed-tracing-systems-zipkin_hu16f3b50d9c77fd5fbdf246a268f88bf0_157658_0b4f4ffc6c863acd801247797619a308.webp 400w,
               /post/202008-resilience-deep-systems/images/distributed-tracing-systems-zipkin_hu16f3b50d9c77fd5fbdf246a268f88bf0_157658_7fd54b7501c387f9f08595171a48716c.webp 760w,
               /post/202008-resilience-deep-systems/images/distributed-tracing-systems-zipkin_hu16f3b50d9c77fd5fbdf246a268f88bf0_157658_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202008-resilience-deep-systems/images/distributed-tracing-systems-zipkin_hu16f3b50d9c77fd5fbdf246a268f88bf0_157658_0b4f4ffc6c863acd801247797619a308.webp&#34;
               width=&#34;760&#34;
               height=&#34;267&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;监测工作流程自动化&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;你是否有这样的业务SLA：在这个SLA中，事件需要在一定的时间内处理，同时要经过微服务链？像Zeebe（用于微服务协调的工作流引擎）这样的工具将使您能够监控超时或其他工作流错误，并能够配置错误处理策略，如自动重试或升级到可以手动解决问题的团队。Zeebe可以100%记录您的业务事件，并提供公司端到端工作流状态的可视性，包括在途工作流的数量、平均工作流持续时间、工作流内的错误等。这样的工具通常更适合各种非工程人员的利益相关者。如果你曾经尝试过在深层系统中收集这些遥测数据，你就会知道这不是一件小事。&lt;/p&gt;
&lt;p&gt;这些可观察性技术的结合，可以让你更快地聚焦和定位问题。许多科技公司发现，它可以消除对团队造成的不必要的干扰，这些团队对于事故处理并不需要但可能已经牵涉其中。&lt;/p&gt;
&lt;h3 id=&#34;总而言之&#34;&gt;总而言之&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;正确的思维方式和正确的工具正在到来。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;弹性的第一个关键是要从平衡粒度开始。如果你选择以一种极度精细的方式来构建你的微服务，那么维护、数据一致性和整体可观察性简直会成为一场噩梦。抵制诱惑，不要全身心地投入到粒度和共享库中去。更倾向于定义回答真实业务能力的微服务，并检查你的共享代码是在加速你还是在阻碍你。&lt;/p&gt;
&lt;p&gt;微服务必须进行通信，共享数据，并保持其新鲜感。因此，弹性的第二个关键是尽可能将你的思维方式转向异步、事件驱动的架构。一开始会很难，也很耗时。REST等同步方法论比较容易实现，而事件驱动则是小菜一碟（译者注：less trivial，感觉语义不对，作者少写了一个 not？）。然而，越早越好。在你的流量增长，并导致你的微服务为了保持其数据副本的新鲜性和一致性而互相伤害之前就这样做。尽量避免发现自己在一个非常容易出错的环境中浪费了宝贵的资源。&lt;/p&gt;
&lt;p&gt;考虑到这一点，弹性的第三个关键是使用正确的工具来增加可观察性。这将使你在需要的时候，能够引入更多的业务能力（即微服务）和更多的业务能力之间的沟通渠道，而不至于丢失视角。请记住，你的产品和技术栈的增长正在扩大你需要监控和分析的遥测量。而能够轻松地推理问题意味着更健康的业务和更快乐的团队。&lt;/p&gt;
&lt;h3 id=&#34;关于作者&#34;&gt;关于作者&lt;/h3&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202008-resilience-deep-systems/images/Amir-Souchami_huc7f5d218f5a1d26e32e551be74b777fb_8158_5c9fb96135743903b37c677175447de9.webp 400w,
               /post/202008-resilience-deep-systems/images/Amir-Souchami_huc7f5d218f5a1d26e32e551be74b777fb_8158_cd4d48ce447c7d06871ef429ce3e2345.webp 760w,
               /post/202008-resilience-deep-systems/images/Amir-Souchami_huc7f5d218f5a1d26e32e551be74b777fb_8158_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202008-resilience-deep-systems/images/Amir-Souchami_huc7f5d218f5a1d26e32e551be74b777fb_8158_5c9fb96135743903b37c677175447de9.webp&#34;
               width=&#34;85&#34;
               height=&#34;100&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Amir Souchami 是 ironSource Aura 的首席架构师。他对技术有着极大的热情，他不断地学习最新的技术，以保持敏锐的洞察力，并创建具有积极商业投资回报率的高扩展性解决方案。Amir喜欢与团队和个人合作，共同设想并实现他们的目标。跟随他一起聊一聊。同理心、瑜伽、徒步旅行、创业公司、广告技术、机器学习、流处理、持续交付和微服务。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译] Serverless集成组件</title>
      <link>https://skyao.net/post/202007-serverless-integration-components/</link>
      <pubDate>Fri, 10 Jul 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202007-serverless-integration-components/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;http://wei-meilin.blogspot.com/2020/07/serverless-integration-components.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Serverless Integration Components&lt;/a&gt;，作者 &lt;a href=&#34;http://wei-meilin.blogspot.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;CHRISTINA&lt;/a&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：快速翻译（机翻+人工校对，没有精修），质量不高，一般阅读可以，不适合传播，谢绝转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Serverless不是一个可选项，而应该在所有的云原生环境中提供。当然，并不是所有的应用都应该采用serverless。但如果你仔细观察，应用的大部分模块都是无状态的，往往闲置，偶尔使用。有些应用则需要处理高度波动的负载。这些应用都是以Serverless方式运行的最佳候选。&lt;/p&gt;
&lt;p&gt;Serverless让开发人员专注于代码，而不用操心基础设施的搭建。为了提供这种环境，同时提供适当的监控和可靠的骨干网来处理大吞吐量的事件：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;这就是Serverless集成（基于Kubernetes）应有的形态&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;一切都是基于容器的。为什么要关心serverless的底层技术呢？难道这一切不应该都是透明的吗？如果你的目标是在混合云/多云上进行托管或构建，而这个混合云/多云是供应商不锁定的，这意味着参与其中的将不仅仅是开发人员。你最终会需要团队之间的合作，并与传统服务和微服务等各种应用一起工作。有了统一和标准化的技术，将使团队采用新型应用的学习曲线变得平坦，使维护变得不那么复杂。&lt;/p&gt;
&lt;p&gt;从开发到平台，所有的东西都应该无缝地协同工作，并且能够轻松地实现自动化和管理。&lt;/p&gt;
&lt;p&gt;![](images/Serverless Architecture.png)&lt;/p&gt;
&lt;p&gt;我们来分析一下所有的要素。&lt;/p&gt;
&lt;p&gt;Plantform/平台：提供完整的基础设施和平台管理的平台，具有自助服务能力，服务发现和应用容器政策和合规性。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202007-serverless-integration-components/images/Platform_hu5d831ae0e3c10251de7bd6afca76a159_16265_2473efb2cd057ef004f037e5114e4f12.webp 400w,
               /post/202007-serverless-integration-components/images/Platform_hu5d831ae0e3c10251de7bd6afca76a159_16265_b598fa04df96199e7452c4d53d2b0e41.webp 760w,
               /post/202007-serverless-integration-components/images/Platform_hu5d831ae0e3c10251de7bd6afca76a159_16265_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202007-serverless-integration-components/images/Platform_hu5d831ae0e3c10251de7bd6afca76a159_16265_2473efb2cd057ef004f037e5114e4f12.webp&#34;
               width=&#34;640&#34;
               height=&#34;238&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Serverless平台： 处理函数/应用的自动伸缩。对底层基础设施进行抽象。 搭建Deplayment的修订版本，便于回滚。并为发布者和消费者统一事件。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202007-serverless-integration-components/images/03-serverless_hue3f05c333900b8ff3132022578002e15_17236_1126be0a3b1490c72054f10e64efcd1c.webp 400w,
               /post/202007-serverless-integration-components/images/03-serverless_hue3f05c333900b8ff3132022578002e15_17236_86f09264287a6fa459fbcdc4f613f75d.webp 760w,
               /post/202007-serverless-integration-components/images/03-serverless_hue3f05c333900b8ff3132022578002e15_17236_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202007-serverless-integration-components/images/03-serverless_hue3f05c333900b8ff3132022578002e15_17236_1126be0a3b1490c72054f10e64efcd1c.webp&#34;
               width=&#34;640&#34;
               height=&#34;346&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Event Mesh：事件被发布到mesh，以及分布式的消费者。事件的基本结构是一致的，在不同的平台之间应该是可移植的。所有的事件都是灵活的，受控的，并可快速推送。 由可靠的stream network提供支持，有助于存储事件流，用于大数据处理/AI/ML数据集的追踪、审计或后期重播。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202007-serverless-integration-components/images/04-eventmesh_hu1f6140549e3753e93aca1041b469ba98_27864_a8a3a1488bb9224b12b33fa2765d11d7.webp 400w,
               /post/202007-serverless-integration-components/images/04-eventmesh_hu1f6140549e3753e93aca1041b469ba98_27864_3d51f8632296fc3471ef1847c0e2e31e.webp 760w,
               /post/202007-serverless-integration-components/images/04-eventmesh_hu1f6140549e3753e93aca1041b469ba98_27864_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202007-serverless-integration-components/images/04-eventmesh_hu1f6140549e3753e93aca1041b469ba98_27864_a8a3a1488bb9224b12b33fa2765d11d7.webp&#34;
               width=&#34;640&#34;
               height=&#34;362&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;集成函数:  serverless集成的典型特征包括：小、轻、无状态和事件驱动。这些特性使得应用具有弹性，以应对我们今天所面临的供应不足/过剩的问题。从运维层面来看，这些都是在被事件触发后停止并(spin up)起来的应用。为了更好的优化资源。而对于开发者来说，这是一个简单的模块化代码片段，他们写好后会自动运转起来。所以他们可以专注于代码而不是部署相关的问题。而集成函数是指通常处理事件中的路由、数据有效载荷的转换，以及其他组成和编排问题的应用。 也常用于连接外部服务，以及作为系统之间的桥梁。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202007-serverless-integration-components/images/05-functions_huafbfca6bc78744caadd33b1ac049a8ba_28405_fdaf6570fba51c5ef1a846db8da949dc.webp 400w,
               /post/202007-serverless-integration-components/images/05-functions_huafbfca6bc78744caadd33b1ac049a8ba_28405_7bd218063d1a2b1877d0844ca50dc0b4.webp 760w,
               /post/202007-serverless-integration-components/images/05-functions_huafbfca6bc78744caadd33b1ac049a8ba_28405_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202007-serverless-integration-components/images/05-functions_huafbfca6bc78744caadd33b1ac049a8ba_28405_fdaf6570fba51c5ef1a846db8da949dc.webp&#34;
               width=&#34;640&#34;
               height=&#34;358&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;微服务或长时间运行的应用：这些都是长时间运行的应用，有状态，比较重，总是被调用。它们中的一些会向mesh发送事件，以触发serverless函数的初始化和启动，或者仅仅是事件的另一个消费者。&lt;/p&gt;
&lt;p&gt;Service Registry：用于在API和事件驱动的架构中共享标准的事件模式和API设计，无论是无服务器函数还是常规应用的事件监听。 在运行时解耦数据结构和管理数据类型。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202007-serverless-integration-components/images/06-serviceregistry_hub6d55841d63bd11be69035e3ebffa305_18915_cc5683f80b61b7084cfeb265848d4aa3.webp 400w,
               /post/202007-serverless-integration-components/images/06-serviceregistry_hub6d55841d63bd11be69035e3ebffa305_18915_6b5bfc112ce37bf7ff1f745f4e50bcb6.webp 760w,
               /post/202007-serverless-integration-components/images/06-serviceregistry_hub6d55841d63bd11be69035e3ebffa305_18915_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202007-serverless-integration-components/images/06-serviceregistry_hub6d55841d63bd11be69035e3ebffa305_18915_cc5683f80b61b7084cfeb265848d4aa3.webp&#34;
               width=&#34;640&#34;
               height=&#34;331&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;API管理：网关安全和管理透出API端点。具备对消费者的访问控制和限制，管理控制台和访问端点的数据分析。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202007-serverless-integration-components/images/07-apigateway_hu4f8318cf2bf5a0d9488e90c9747f6f13_18227_d483a8b6626215f13aaf19d5e4381468.webp 400w,
               /post/202007-serverless-integration-components/images/07-apigateway_hu4f8318cf2bf5a0d9488e90c9747f6f13_18227_3ea1e9cb13f8461714611a6ec9e3afc1.webp 760w,
               /post/202007-serverless-integration-components/images/07-apigateway_hu4f8318cf2bf5a0d9488e90c9747f6f13_18227_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202007-serverless-integration-components/images/07-apigateway_hu4f8318cf2bf5a0d9488e90c9747f6f13_18227_d483a8b6626215f13aaf19d5e4381468.webp&#34;
               width=&#34;640&#34;
               height=&#34;264&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;重申，这是我对提供一个完整的serverless应用环境所需要的组件的两点看法。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>走出微服务误区：避免从单体到分布式单体</title>
      <link>https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/</link>
      <pubDate>Wed, 01 Jul 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/</guid>
      <description>&lt;h2 id=&#34;回顾从单体到微服务到function&#34;&gt;回顾：从单体到微服务到Function&lt;/h2&gt;
&lt;p&gt;在过去几年间，微服务架构成为业界主流，很多公司开始采用微服务，并迁移原有的单体应用迁移到微服务架构。从架构上，微服务和单体最大的变化在于微服务架构下应用的粒度被“拆小”：将所有业务逻辑都在一起的单体应用，按照领域模型拆分为多个内聚而自治的“更小”的应用。而Function则在拆分上更进一步，拆分粒度变成了“单个操作”，基于 Function 逐渐演进出现 FaaS 形态和 Serverless 架构。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/evolation_hu49b520efb2e95a6ee537b02ec5b1b836_146669_30cf2277cdb6634aec78d9ba6ca1a135.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/evolation_hu49b520efb2e95a6ee537b02ec5b1b836_146669_b7f7c53ac6efb76188e09b414c7e63df.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/evolation_hu49b520efb2e95a6ee537b02ec5b1b836_146669_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/evolation_hu49b520efb2e95a6ee537b02ec5b1b836_146669_30cf2277cdb6634aec78d9ba6ca1a135.webp&#34;
               width=&#34;760&#34;
               height=&#34;269&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在微服务和 serverless 的喧嚣中，也逐渐出现了很多质疑和反对的声音：越来越多的人发现，当他们兴冲冲的迁移单体应用到微服务和 serverless 架构之后，得到的收益并没有期望中的那么理想。最近，出现了对微服务的各种质疑、反思的声音，甚至放弃微服务回归单体。举例，我在 &lt;a href=&#34;https://www.infoq.cn/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Infoq中国网站&lt;/a&gt; 简单搜索关键字“微服务”，前三页中就出现了如下的内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.infoq.cn/article/zpi6lLdKaKB3MCLdPiAB&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;我们为什么停用微服务？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.infoq.cn/article/KSzctluch2ijbRbKYBgO&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;这些公司为什么放弃微服务？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzIzNjUxMzk2NQ==&amp;amp;mid=2247495266&amp;amp;idx=1&amp;amp;sn=d968d7cf2c67c8a56ab55bfa70ab671e&amp;amp;chksm=e8d411a0dfa398b67726e8d859c26ce86c968e90922e148bfcead2095109f47ab5f5bb366d2f&amp;amp;scene=27#wechat_redirect&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;什么？你的团队没有100人，那就不要用微服务了！&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.infoq.cn/article/Nd0RofAUp0WtlvlQArbu&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;致传统企业朋友：不够痛就别微服务，有坑&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzI4MTY5NTk4Ng==&amp;amp;mid=2247493913&amp;amp;idx=3&amp;amp;sn=157abdc9f5f78cf24925fb24c058e61c&amp;amp;chksm=eba7ea84dcd06392cb0b59437e032cdc60f10942b1fb1eefeb2a74e9fbe00df5d51fe363a442&amp;amp;scene=27#wechat_redirect&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;微服务带来的心理阴影&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzIzNjUxMzk2NQ==&amp;amp;mid=2247494671&amp;amp;idx=1&amp;amp;sn=5a61a5e99f706c9cf5416bd7ff2b140a&amp;amp;chksm=e8d413cddfa39adb5ec1ee71cf024b2bf2a6b4cf2a36ff1c58d81e96b015b79b465e0b7ddc77&amp;amp;scene=27#wechat_redirect&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;微服务到底该多大？如何设计微服务的粒度？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzIzNjUxMzk2NQ==&amp;amp;mid=2247493824&amp;amp;idx=2&amp;amp;sn=3e0b7c1019892d01d81b8c915f9bc9de&amp;amp;chksm=e8d41702dfa39e14eec73a424188fcdd069e12242968930efef3b60594ba925f91d1905dd0c6&amp;amp;scene=21#wechat_redirect&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Uber 团队放弃微服务改用宏服务，网友评论炸锅了&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzIzNjUxMzk2NQ==&amp;amp;mid=2247494317&amp;amp;idx=2&amp;amp;sn=440bb04225806538a146fa1b7e4e394b&amp;amp;chksm=e8d4156fdfa39c792772f9e130d1efe10b6f093ce589c80efccbfb3665141464133944326db0&amp;amp;scene=27#wechat_redirect&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;为什么 Segment 从微服务回归单体&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;无论是支持还是反对微服务的声音，大多都是着眼于组织架构（康威定律，对应用和代码的ownership）、微服务拆分（粒度大小，如何识别领域模型和业务边界）、分布式事务（跨多个微服务调用时维持一致性），工具（自动化构建、部署，可测试性，监控，分布式链路跟踪，CI/CD），数据库分离（避免多个微服务尤其是领域模型外的微服务共享数据库）等方面进行合理性分析和观点阐述，相信大家都对这些问题都有了解。&lt;/p&gt;
&lt;p&gt;而我今天的文章，将从另外一个角度来看待微服务（也包括Serverless）实践中存在的误区——辛辛苦苦从单体走到微服务，却最后沦为&lt;strong&gt;分布式单体&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;分布式单体&#34;&gt;分布式单体&lt;/h2&gt;
&lt;p&gt;“Distributed Monolith”，分布式单体，这真是一个悲伤的技术术语。而这偏偏是企业采用微服务后通常最容易踏进去的一个“陷阱”，事实上我看到的很多微服务落地最终都是以&amp;quot;分布式单体&amp;quot;收场，无法获得微服务的完整收益。&lt;/p&gt;
&lt;p&gt;问题源于微服务实施的方式 —— 按照业务逻辑拆解单体，划分为多个微服务，定义API接口，然后通过REST或者RPC进行远程调用，最终把这些微服务组合起来提供各种业务功能。简单说，就是在业务拆分的基础上，用进程间的&lt;strong&gt;远程调用&lt;/strong&gt;简单替代原来进程内的&lt;strong&gt;方法调用&lt;/strong&gt;。期间，对于原来使用的各种分布式能力，继续原用之前的方式，简单说：方式不变，只是粒度变小。&lt;/p&gt;
&lt;p&gt;从方法论说这样做无可厚非，这也是微服务采用过程中非常标准的做法。但问题在于，止步于此是不够的 —— 至少存在两个有待继续努力改进的地方。&lt;/p&gt;
&lt;h3 id=&#34;分布式单体起因之一通过共享库和网络客户端访问分布式能力&#34;&gt;分布式单体起因之一：通过共享库和网络客户端访问分布式能力&lt;/h3&gt;
&lt;p&gt;分布式能力的共享库和网络客户端是造成分布式单体问题的原因之一，关于这一点，来自 verizon 的 Mohamad Byan 在他的名为 &lt;a href=&#34;https://www.slideshare.net/DevOpsDaysDFW/avoid-the-distributed-monolith&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Avoid the Distributed Monolith!!&lt;/a&gt; 的演讲中有详细的阐述，我这里援引他的图片和观点：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/shared-library-1_hu05f2d69ba0319c258f11ab39e179ac17_492051_fda99ede9f9040acc02321984a954535.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/shared-library-1_hu05f2d69ba0319c258f11ab39e179ac17_492051_c839aa426174f808dfaf7d20b159e33f.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/shared-library-1_hu05f2d69ba0319c258f11ab39e179ac17_492051_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/shared-library-1_hu05f2d69ba0319c258f11ab39e179ac17_492051_fda99ede9f9040acc02321984a954535.webp&#34;
               width=&#34;760&#34;
               height=&#34;483&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;上图是微服务体系的逻辑架构，由两部分组成：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;内层架构（图上浅蓝色部分），是每个微服务的实现架构。&lt;/li&gt;
&lt;li&gt;外层架构(图上黄色部分)，是构建强大微服务架构所需要的各种能力。这里通常有大家熟悉的各种分布式能力。&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;特别提示：这里说的“网络客户端”是各种分布式能力的客户端，如服务注册发现/MQ中间件/redis等key-value存储/数据库/监控日志追踪系统/安全体系等，不是服务间通讯如RPC的客户端。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;而内层的微服务是通过 &lt;strong&gt;共享类库&lt;/strong&gt; 和 &lt;strong&gt;网络客户端&lt;/strong&gt; 来访问外层架构提供的分布式能力：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/shared-library-2_hu05f2d69ba0319c258f11ab39e179ac17_239954_180b8848fd4010add78a8d9f06ca1eca.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/shared-library-2_hu05f2d69ba0319c258f11ab39e179ac17_239954_85bf4216a79141cef8630bf471254da2.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/shared-library-2_hu05f2d69ba0319c258f11ab39e179ac17_239954_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/shared-library-2_hu05f2d69ba0319c258f11ab39e179ac17_239954_180b8848fd4010add78a8d9f06ca1eca.webp&#34;
               width=&#34;760&#34;
               height=&#34;296&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;分布式能力的 &lt;strong&gt;共享类库&lt;/strong&gt; 和 &lt;strong&gt;网络客户端&lt;/strong&gt; 会迫使内层微服务和外层架构的各种分布式能力之间产生强耦合，增加运维的复杂性（如升级困难造成版本碎片化），多语言受限于类库和网络客户端支持的语言，各种组件（如消息中间件）往往使用自定义数据格式和通讯协议 —— 所有这些迫使内层微服务不得不实质性受限于外层架构的技术选型。&lt;/p&gt;
&lt;p&gt;对于Function，这个问题就更加明显了：Function的粒度更小，更专注业务逻辑。某些简短的 Function 可能只有几百行代码，但是，为了让这几百行代码运转起来而需要引入的共享类库和网络客户端可能相比之下就规模惊人了。援引一张网上图片作为示意：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/too-many-sdk-dependencies_hu3072ce75a8b3ee084a3679d9a77b2257_34943_0cffdbe173abcf27a28963dc3a7fb6fb.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/too-many-sdk-dependencies_hu3072ce75a8b3ee084a3679d9a77b2257_34943_52e4457dcf9e8769fd7ae5244e1afee1.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/too-many-sdk-dependencies_hu3072ce75a8b3ee084a3679d9a77b2257_34943_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/too-many-sdk-dependencies_hu3072ce75a8b3ee084a3679d9a77b2257_34943_0cffdbe173abcf27a28963dc3a7fb6fb.webp&#34;
               width=&#34;465&#34;
               height=&#34;617&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;分布式单体起因之二简单用远程调用替代进程内方法调用&#34;&gt;分布式单体起因之二：简单用远程调用替代进程内方法调用&lt;/h3&gt;
&lt;p&gt;在微服务架构改造过程中，熟悉单体系统和架构的开发人员，习惯性的会将这些单体时代的知识和经验重用到新的微服务架构之中。其中最典型的做法就是：在遵循领域模型将现有单体应用按照业务边界拆分为多个微服务时，往往选择用REST或者RPC等远程调用方式&lt;strong&gt;简单替代&lt;/strong&gt;原有的进程内方法调用。&lt;/p&gt;
&lt;p&gt;当两个逻辑上的业务模块存在协作需求时：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/invoke_hu05f2d69ba0319c258f11ab39e179ac17_40335_90533caed6935e622e07736bf6e53dae.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/invoke_hu05f2d69ba0319c258f11ab39e179ac17_40335_0d26304f349bbef9b8bb74ab53a55735.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/invoke_hu05f2d69ba0319c258f11ab39e179ac17_40335_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/invoke_hu05f2d69ba0319c258f11ab39e179ac17_40335_90533caed6935e622e07736bf6e53dae.webp&#34;
               width=&#34;760&#34;
               height=&#34;194&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;从单体到微服务，直接方法调用被替换为远程调用（REST或者RPC），即使采用Servicemesh也只是在链路中多增加了sidecar节点，并未改变远程调用的性质：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/invoke2_hu05f2d69ba0319c258f11ab39e179ac17_207801_f553bdc494c9bbc3291e8186c044c13a.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/invoke2_hu05f2d69ba0319c258f11ab39e179ac17_207801_4bd4e5fb2846b98a42a779a0563178cc.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/invoke2_hu05f2d69ba0319c258f11ab39e179ac17_207801_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/invoke2_hu05f2d69ba0319c258f11ab39e179ac17_207801_f553bdc494c9bbc3291e8186c044c13a.webp&#34;
               width=&#34;760&#34;
               height=&#34;278&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这导致了前面所说的 “分布式单体”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在微服务之前：应用程序由多个耦合在一起的&lt;strong&gt;模块&lt;/strong&gt;组成，这些模块通过内存空间进行方法调用…..&lt;/li&gt;
&lt;li&gt;在微服务之后：应用程序由多个耦合在一起的&lt;strong&gt;微服务&lt;/strong&gt;组成，这些微服务通过网络进行远程调用…..&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;抛开调用方式的差异来看采用微服务前后的系统架构，会发现：两者几乎是完全一样的！！&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/same-architecture_hu05f2d69ba0319c258f11ab39e179ac17_416225_ea4713ae8d04abaa10cab91c256d3565.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/same-architecture_hu05f2d69ba0319c258f11ab39e179ac17_416225_bcbd16bee53670174553c253ea279e6c.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/same-architecture_hu05f2d69ba0319c258f11ab39e179ac17_416225_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/same-architecture_hu05f2d69ba0319c258f11ab39e179ac17_416225_ea4713ae8d04abaa10cab91c256d3565.webp&#34;
               width=&#34;760&#34;
               height=&#34;304&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而微服务版本在某些情况下可能表现的更糟糕：因为调用方式更脆弱，因为网络远比内存不可靠。而我们将网络当成 “胶水” 来使用，试图把分散的业务逻辑模块（已经拆分为微服务）按照单体时代的同样方式简单粘在一起，这当然比单体在同一个进程内直接方法调用更加的不可靠。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;关于这一点，在 &lt;a href=&#34;https://www.red-gate.com/simple-talk/blogs/the-eight-fallacies-of-distributed-computing/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;The Eight Fallacies of Distributed Computing/分布式计算的8个谬论&amp;rdquo;&lt;/a&gt; 一文中有详细阐述。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;类似的，在采用 Function 时，如果依然沿用上面的方式，以单体或微服务架构的思维方式和设计模式来创建FaaS/Serverless架构：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/invoke3_hu49b520efb2e95a6ee537b02ec5b1b836_185313_03e003ab121c031bf5595cbd959cd900.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/invoke3_hu49b520efb2e95a6ee537b02ec5b1b836_185313_8d0395b9f52a91823c833da6300d4f5e.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/invoke3_hu49b520efb2e95a6ee537b02ec5b1b836_185313_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/invoke3_hu49b520efb2e95a6ee537b02ec5b1b836_185313_03e003ab121c031bf5595cbd959cd900.webp&#34;
               width=&#34;760&#34;
               height=&#34;258&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;其本质不会发生变化 —— 不过是将微服务变成粒度更小的函数，导致系统中的远程调用数量大为增加：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/same-architecture2_hu05f2d69ba0319c258f11ab39e179ac17_441189_2a49ced4ede7aa2eed829a62ba133d98.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/same-architecture2_hu05f2d69ba0319c258f11ab39e179ac17_441189_162af116d2c807fde5275e5242ae3bba.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/same-architecture2_hu05f2d69ba0319c258f11ab39e179ac17_441189_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/same-architecture2_hu05f2d69ba0319c258f11ab39e179ac17_441189_2a49ced4ede7aa2eed829a62ba133d98.webp&#34;
               width=&#34;760&#34;
               height=&#34;309&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;系统内的耦合并没有发生变化，Serverless并不能改变微服务中存在的这个内部耦合问题：调用在哪里，则耦合就在哪里！只是把将组件的粒度从 “微服务“换成了 “Function/函数”。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;耦合的存在是源于系统不同组件之间的通讯模式，而不是实现通讯的技术。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果让两个组件通过“调用”（后面再展开讲何为&lt;strong&gt;调用&lt;/strong&gt;）进行远程通信，那么不管调用是如何实现的，这两个组件都是紧密耦合。因此，当系统从单体到微服务到serverless，如果止步于简单的用远程调用替代进程内方法调用，那么系统依然是高度耦合的，从这个角度来说：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;单体应用 ≈ 分布式单体 ≈ Serverless单体&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&#34;分布式单体起因小结&#34;&gt;分布式单体起因小结&lt;/h3&gt;
&lt;p&gt;上面我们列出了微服务和serverless实践中容易形成“分布式单体”的两个主要原因：&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;/p&gt;
&lt;h2 id=&#34;引入非侵入式方案物理隔离逻辑抽象&#34;&gt;引入非侵入式方案：物理隔离+逻辑抽象&lt;/h2&gt;
&lt;p&gt;前面谈到分布式单体产生的一个原因是“通过共享库和网络客户端访问分布式能力”，造成微服务和Lambda函数和分布式能力强耦合。以Servicemesh为典型代表的非侵入式方案是解决这一问题的有效手段，其他类似方案有 RSocket / Multiple Runtime Architecture，以及数据库和消息的Mesh化产品，其基本思路有两点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;委托&lt;/strong&gt;：通过Sidecar或者Runtime来进行对分布式能力的访问，避免应用和提供分布式能力的组件直接通讯造成强绑定 —— &lt;strong&gt;通过物理隔离进行解耦&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;抽象&lt;/strong&gt;：对内层微服务隐藏实现细节，只暴露网络协议和数据契约，将外围架构的各种分布式能力以API的方式暴露出来，而屏蔽提供这些能力的具体实现 —— &lt;strong&gt;通过逻辑抽象进行解耦&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;以Servicemesh的sidecar为例，在植入 sidecar 之后，业务应用需要直接对接的分布式能力就大为减少（物理隔离）：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/servicemesh-sidecar_hu05f2d69ba0319c258f11ab39e179ac17_193982_beb668cbe0b0a39c364946d3b9260215.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/servicemesh-sidecar_hu05f2d69ba0319c258f11ab39e179ac17_193982_81f37686f0c253c258a64ea50f26a5e5.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/servicemesh-sidecar_hu05f2d69ba0319c258f11ab39e179ac17_193982_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/servicemesh-sidecar_hu05f2d69ba0319c258f11ab39e179ac17_193982_beb668cbe0b0a39c364946d3b9260215.webp&#34;
               width=&#34;760&#34;
               height=&#34;372&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最近出现的 Multiple Runtime / Mecha 架构，以及遵循这一架构思想的微软开源产品 Dapr ，则将这个做法推进到服务间通讯之外更多的分布式能力。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/dapr-overview_hub0f40905bb31105b15316541e7839891_185368_a01f78cb9c24360d7c784225c9d31715.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/dapr-overview_hub0f40905bb31105b15316541e7839891_185368_a8a8599e07826a806949009b4dd8016f.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/dapr-overview_hub0f40905bb31105b15316541e7839891_185368_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/dapr-overview_hub0f40905bb31105b15316541e7839891_185368_a01f78cb9c24360d7c784225c9d31715.webp&#34;
               width=&#34;760&#34;
               height=&#34;358&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;此外在委托之外，还提供对分布式能力的抽象。比如在Dapr中，业务应用只需要使用Dapr提供的标准API，就可以使用这些分布式能力而无法关注提供这些能力的具体产品（逻辑抽象）：&lt;/p&gt;
&lt;p&gt;以pub-sub模型中的发消息为例，这是 Dapr 提供的 Java客户端 SDK API：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;interface&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;DaprClient&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Mono&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Void&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;publishEvent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;topic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Object&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Mono&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Void&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;publishEvent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;topic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Object&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Map&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可见在发送事件时，Dapr完全屏蔽了底层消息机制的具体实现，通过客户端SDK为应用提供发送消息的高层抽象，在Dapr Runtime中对接底层MQ实现——完全解耦应用和MQ：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/dapr-publish-event_hu05f2d69ba0319c258f11ab39e179ac17_131908_52526db53155c76861a903d60132a988.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/dapr-publish-event_hu05f2d69ba0319c258f11ab39e179ac17_131908_7ddaf9e0ebcde6dc104784bf8cff262d.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/dapr-publish-event_hu05f2d69ba0319c258f11ab39e179ac17_131908_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/dapr-publish-event_hu05f2d69ba0319c258f11ab39e179ac17_131908_52526db53155c76861a903d60132a988.webp&#34;
               width=&#34;760&#34;
               height=&#34;315&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;关于 Multiple Runtime / Mecha 架构的介绍不在这里深入展开，有兴趣的同学可以浏览我之前的博客文章 &lt;a href=&#34;https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;“Mecha：将Mesh进行到底”&lt;/a&gt; 。&lt;/p&gt;
&lt;p&gt;稍后我会有一篇深度文章针对上面这个话题，详细介绍在消息通讯领域和EDA架构下如何实现消息通讯和事件驱动的抽象和标准化，以避免业务应用和底层消息产品绑定和强耦合，敬请关注。&lt;/p&gt;
&lt;h2 id=&#34;引入event解除不必要的强耦合&#34;&gt;引入Event：解除不必要的强耦合&lt;/h2&gt;
&lt;p&gt;在解决了微服务/serverless系统和外部分布式能力之间紧耦合的问题之后，我们继续看微服务/Serverless系统内部紧耦合的问题。前面讨论到，从单体到微服务到Function/Serverless，如果只是简单的将直接方法调用替换为远程调用（REST或者RPC），那么两个通讯的模块之间会因为这个紧密耦合的调用而形成依赖，而且依赖关系会伴随调用链继续传递，导致形成一个树形的依赖关系网络，表现为系统间的高度耦合：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/dependency_hu05f2d69ba0319c258f11ab39e179ac17_443431_edaa71c993b934daffabb938636b9e53.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/dependency_hu05f2d69ba0319c258f11ab39e179ac17_443431_a14c36728e6c1259195158362c6fce69.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/dependency_hu05f2d69ba0319c258f11ab39e179ac17_443431_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/dependency_hu05f2d69ba0319c258f11ab39e179ac17_443431_edaa71c993b934daffabb938636b9e53.webp&#34;
               width=&#34;760&#34;
               height=&#34;279&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;要解决这个问题，基本思路在于审视两个组件之间通讯行为的&lt;strong&gt;业务语义&lt;/strong&gt;，然后据此决定两者之间究竟是应该采用Command/命令模式还是Event/事件模式。&lt;/p&gt;
&lt;h3 id=&#34;温故而知新event-和-command&#34;&gt;温故而知新：Event 和 Command&lt;/h3&gt;
&lt;p&gt;首先我们来温习一下 Event 和 Command 的概念和差别，借用一张图片，总结的非常到位：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/event-command_hu05f2d69ba0319c258f11ab39e179ac17_329148_d584326f5a73f8c2953edc0e3d60dadd.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/event-command_hu05f2d69ba0319c258f11ab39e179ac17_329148_c3c5534845894919d1aa7305203dea8f.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/event-command_hu05f2d69ba0319c258f11ab39e179ac17_329148_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/event-command_hu05f2d69ba0319c258f11ab39e179ac17_329148_d584326f5a73f8c2953edc0e3d60dadd.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 id=&#34;什么是-event&#34;&gt;什么是 Event？&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Event: “A significant change in state” — K. Mani Chandy&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Event 代表领域中&lt;strong&gt;已经发生&lt;/strong&gt;的事情：通常意味着有行为（Action）已经发生，有状态（Status）已经改变。&lt;/p&gt;
&lt;p&gt;因为是&lt;strong&gt;已经发生&lt;/strong&gt;的事情，因此：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Event可以被理解为是对已经发生的事实的客观陈述&lt;/li&gt;
&lt;li&gt;这意味着Event通常是不可变的：Event的信息（代表着客观事实）不能被篡改，Event的产生不能逆转&lt;/li&gt;
&lt;li&gt;命名：Event通常以动词的完成时态命名，如 UserRegistredEvent&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;产生Event的目标是为了接下来的Event传播：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将已经发生的Event通知给对此感兴趣的观察者&lt;/li&gt;
&lt;li&gt;收到Event的观察者将根据Event的内容进行判断和决策：可能会有接下来的动作（Action），有些动作可能需要和其他模块通讯而触发命令（Command），这些动作执行完毕可能会造成领域状态的改变从而继续触发新的事件（Event）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Event传播的方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Event有明确的“源/source”，即Event产生（或者说状态改变）的发生地&lt;/li&gt;
&lt;li&gt;但由于生产者并不知道（不愿意/不关心）会有哪些观察者对Event感兴趣，因此Event中并不包含“目的地/Destination”信息&lt;/li&gt;
&lt;li&gt;Event通常是通过 MessageQueue 机制，以 pub-sub 的方式传播&lt;/li&gt;
&lt;li&gt;Event通常不需要回复（ reply）或者应答（response）&lt;/li&gt;
&lt;li&gt;Event通常用 发布（publish）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;什么是command&#34;&gt;什么是Command？&lt;/h4&gt;
&lt;p&gt;Command 用于传递一个要求执行某个动作（Action）的请求。&lt;/p&gt;
&lt;p&gt;Command 代表&lt;strong&gt;将要发生&lt;/strong&gt;的事情：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通常意味着行为（Action）还未发生但即将发生（如果请求被接受和执行）。&lt;/li&gt;
&lt;li&gt;存在被拒绝的可能：不愿意执行（参数校验失败，权限不足），不能执行（接收者故障或者资源无法访问）&lt;/li&gt;
&lt;li&gt;命名：Command通常以动词的普通形态命名，如 UserRegisterCommand&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;产生Command的目标是为了接下来的Command执行：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;将Command发送给期望的执行者&lt;/li&gt;
&lt;li&gt;收到Command的执行者将根据Command的要求进行执行：在执行的过程中内部可能有多个动作（Action），有些动作可能需要和其他模块通讯而触发命令（Command），这些动作执行完毕可能会造成领域状态的改变从而继续触发新的事件（Event）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Command的传播方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Command有明确的源（Source），即Command的发起者&lt;/li&gt;
&lt;li&gt;Command也有非常明确的执行者（而且通常是一个），因此命名通常包含“目的地/Destination”信息&lt;/li&gt;
&lt;li&gt;Command通常是通过 HTTP / RPC 这样的点对点远程通讯机制，通常是同步&lt;/li&gt;
&lt;li&gt;Command通常需要应答（Response）：回应Command是否被执行（因为可能被拒绝），执行结果（因为可能执行失败）&lt;/li&gt;
&lt;li&gt;Command通常用 发送（Send）&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;command-和-event-总结&#34;&gt;Command 和 Event 总结&lt;/h4&gt;
&lt;p&gt;总结 —— Command 和 Event 的本质区别在于他们的意图：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Command 的意图是 &lt;strong&gt;告知希望发生的事情&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Event 的意图是 &lt;strong&gt;告知已经发生的事情&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;意图上的差异最终会在服务间依赖关系上有特别的体现：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/denpendency-direction_hu49b520efb2e95a6ee537b02ec5b1b836_98498_7f492565111a20c10dbdf48921100baa.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/denpendency-direction_hu49b520efb2e95a6ee537b02ec5b1b836_98498_0bfb8d4c602e647885f4354c5d92f3c4.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/denpendency-direction_hu49b520efb2e95a6ee537b02ec5b1b836_98498_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/denpendency-direction_hu49b520efb2e95a6ee537b02ec5b1b836_98498_7f492565111a20c10dbdf48921100baa.webp&#34;
               width=&#34;760&#34;
               height=&#34;271&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Command的发起者必须明确知晓Command的接收者并明确指示需要做什么（所谓的命令、指示、操纵、编排），尤其当发起者连续发出多个Command时，通常这些Command会有非常明确的顺序和逻辑关系，以组合为特定的业务逻辑。&lt;/p&gt;
&lt;p&gt;Command的依赖关系简单明确: 发起者 “&lt;strong&gt;显式依赖&lt;/strong&gt;” 接收者&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Event的发起者只需负责发布Event，而无需关注Event的接收者，包括接收者是谁（一个还是多个）以及会做什么（所谓的通知、驱动、协调）。即使Event实际有多个接收者，这些接受者之间往往没有明确的顺序关系，其处理过程中的业务逻辑也往往是彼此独立的。&lt;/p&gt;
&lt;p&gt;Event的依赖关系稍微复杂一些：发起者明确&lt;strong&gt;不依赖&lt;/strong&gt;接收者，接收者则存在对发起者 “&lt;strong&gt;隐式的反向依赖&lt;/strong&gt;” ——反向是指和Command的依赖关系相比方向调转，是接受者反过来依赖发起者；隐式则是指这种依赖只体现于 “接受者依赖Event，而Event是由发起者发布” 的间接关系中，接受者和发起者之间并不存在直接依赖关系。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;从业务视角出发关系模型决定通讯行为&#34;&gt;从业务视角出发：关系模型决定通讯行为&lt;/h3&gt;
&lt;p&gt;在温习完 Command 和 Event 之后，我们再来看我们前面的问题：为什么简单的将直接方法调用替换为远程调用（REST或者RPC）会出问题？主要原因是在这个替换过程中，所谓&lt;strong&gt;简单&lt;/strong&gt;是指不假思索直接选择远程调用，也就是选择全程Command方式：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/dependency-command_hu05f2d69ba0319c258f11ab39e179ac17_459222_f4daade3cc30bc58d6f5fa96d6e0481e.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/dependency-command_hu05f2d69ba0319c258f11ab39e179ac17_459222_85c22257d2b7622d7b34d86574b8be43.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/dependency-command_hu05f2d69ba0319c258f11ab39e179ac17_459222_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/dependency-command_hu05f2d69ba0319c258f11ab39e179ac17_459222_f4daade3cc30bc58d6f5fa96d6e0481e.webp&#34;
               width=&#34;760&#34;
               height=&#34;279&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
真实业务场景下各个组件（微服务或者Function）的业务逻辑关系，通常不会像上图这么夸张，不应该全是 Command （后面会谈到也不应该全是 Event） ，而应该是类似下图描述的两者结合，以微服务为例（Function类推）：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/busness-handling_hu49b520efb2e95a6ee537b02ec5b1b836_165012_b270c3fdf7136828f0c5abfe00e92d07.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/busness-handling_hu49b520efb2e95a6ee537b02ec5b1b836_165012_c2e7a384f06ac4a8e6805014d78451e2.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/busness-handling_hu49b520efb2e95a6ee537b02ec5b1b836_165012_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/busness-handling_hu49b520efb2e95a6ee537b02ec5b1b836_165012_b270c3fdf7136828f0c5abfe00e92d07.webp&#34;
               width=&#34;760&#34;
               height=&#34;288&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;业务输入：图上微服务A接收到业务请求的输入（可能是 Command 方式，也可能是 Event 方式）&lt;/li&gt;
&lt;li&gt;业务逻辑 “&lt;strong&gt;实现&lt;/strong&gt;” 的执行过程：
&lt;ul&gt;
&lt;li&gt;微服务A在执行Command（或者被Event触发）的过程中，会有很多动作（Action）&lt;/li&gt;
&lt;li&gt;有些是微服务A内部的动作，比如操作数据库，操作key-value存储，内存中的业务逻辑处理等&lt;/li&gt;
&lt;li&gt;有些是和外部微服务进行通讯，如执行查询或要求对方进行某些操作，这些通讯方式是以Command的形式，如图上和微服务B的通讯&lt;/li&gt;
&lt;li&gt;在这些内部和外部动作完成之后，执行过程完成&lt;/li&gt;
&lt;li&gt;如果是Command，则需要以应答的形式给回Command操作的结果&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;业务状态变更 &lt;strong&gt;触发&lt;/strong&gt; 的后续行为：
&lt;ul&gt;
&lt;li&gt;在上面的执行过程完成后，如果涉及到业务状态的变更，则需要为此发布事件&lt;/li&gt;
&lt;li&gt;事件通过 event bus 分发给对该事件感兴趣的其他微服务：注意这个过程是解耦的，微服务A不清楚也不关心哪些微服务对此事件感兴趣，事件也不需要应答。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;上面微服务A的业务逻辑执行处理过程中，需要以Command或者Event方式和其他微服务通讯，如图中的微服务B/C/D/E。而对于这些微服务B/C/D/E（视为微服务A的下游服务），他们在接受到业务请求后的处理流程和微服务A的处理流程是类似的。&lt;/p&gt;
&lt;p&gt;因此我们可以简单推导一下，当业务处理逻辑从微服务A延展到微服务A的下游服务（图中的微服务B/C/D/E）时的场景：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/busness-handling-deeper_hu05f2d69ba0319c258f11ab39e179ac17_297563_404a77991749f9053dbc2b8a98e4d1a4.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/busness-handling-deeper_hu05f2d69ba0319c258f11ab39e179ac17_297563_068b9d28188d4378d9fb2610b7dae871.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/busness-handling-deeper_hu05f2d69ba0319c258f11ab39e179ac17_297563_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/busness-handling-deeper_hu05f2d69ba0319c258f11ab39e179ac17_297563_404a77991749f9053dbc2b8a98e4d1a4.webp&#34;
               width=&#34;760&#34;
               height=&#34;322&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;将图中涉及的微服务A/B/C/D/E在处理业务逻辑的行为总结下来，通讯行为大体是一样的：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/busness-handling-cases_hu3759b242a349f1696964c87e34156d2e_137922_7a57ff944860aa9692da3f3088e4f938.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/busness-handling-cases_hu3759b242a349f1696964c87e34156d2e_137922_6f7e074340393d778bee2ddf7f55cfab.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/busness-handling-cases_hu3759b242a349f1696964c87e34156d2e_137922_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/busness-handling-cases_hu3759b242a349f1696964c87e34156d2e_137922_7a57ff944860aa9692da3f3088e4f938.webp&#34;
               width=&#34;760&#34;
               height=&#34;121&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;抽象起来，一个典型的微服务在业务处理流程中的通讯行为可以概括为以下四点：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/microservice-abstraction_huccfeabef392c3a2c5d6c2d270b150a9d_85897_2fc305c2e7723f71cf3ab0bc8ae11d94.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/microservice-abstraction_huccfeabef392c3a2c5d6c2d270b150a9d_85897_8a75785988c97fcab93293b14e92e593.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/microservice-abstraction_huccfeabef392c3a2c5d6c2d270b150a9d_85897_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/microservice-abstraction_huccfeabef392c3a2c5d6c2d270b150a9d_85897_2fc305c2e7723f71cf3ab0bc8ae11d94.webp&#34;
               width=&#34;760&#34;
               height=&#34;143&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;输入&lt;/strong&gt;：以一个Command请求或者一个Event通知为输入，这是业务处理流程的起点&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;内部Action&lt;/strong&gt;：微服务的内部逻辑，典型如数据库操作，访问redis等key-value存储（对应于Multiple Runtime/Mecha架构中的各种分布式能力）。可选，通常为0-N个&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;外部访问&lt;/strong&gt;：以Command形式访问外部的其他微服务。可选，通常为0-N个&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通告变更&lt;/strong&gt;：以Event形式对外发布事件，通告上述操作产生的业务状态的变更。可选，通常为0-1个&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在这个行为模式中，2和3是没有顺序的，而且可能交错执行，而4通常都是在流程的最后：只有当各种内部Action和外部Command都完成，业务逻辑实现结束，状态变更完成，“木已成舟”，才能以Event的方式对外发布：“操作已完成，状态已变更，望周知”。&lt;/p&gt;
&lt;p&gt;这里我们回顾一下前面的总结 —— Event 和 Command 的本质区别在于他们的意图：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Event 的意图是告知&lt;strong&gt;已经发生&lt;/strong&gt;的事情&lt;/li&gt;
&lt;li&gt;Command 的意图是告知&lt;strong&gt;希望发生&lt;/strong&gt;的事情&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从业务逻辑处理的角度来看，外部访问的Command和内部操作的Action是业务逻辑的 “&lt;strong&gt;实现&lt;/strong&gt;” 部分：这些操作组成了完整的业务逻辑——如果这些操作失败，则业务处理将会直接影响（失败或者部分失败）。而发布事件则是业务逻辑完成之后的后续 “&lt;strong&gt;通知&lt;/strong&gt;” 部分：当业务逻辑处理完毕，状态变更完成后，以事件的方式驱动后续的进一步处理。注意是&lt;strong&gt;驱动&lt;/strong&gt;，而不是直接操纵。&lt;/p&gt;
&lt;p&gt;从时间线的角度来看整个业务处理流程如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/microservice-timeline_hu49b520efb2e95a6ee537b02ec5b1b836_111797_35583864aef9d8f3853f46b8903fa78e.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/microservice-timeline_hu49b520efb2e95a6ee537b02ec5b1b836_111797_27fc8973374ce3f8a5527233491e14c6.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/microservice-timeline_hu49b520efb2e95a6ee537b02ec5b1b836_111797_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/microservice-timeline_hu49b520efb2e95a6ee537b02ec5b1b836_111797_35583864aef9d8f3853f46b8903fa78e.webp&#34;
               width=&#34;760&#34;
               height=&#34;269&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;全程command带来的问题不必要的强耦合&#34;&gt;全程Command带来的问题：不必要的强耦合&lt;/h3&gt;
&lt;p&gt;全程Command的微服务系统，存在的问题就是在上述最后阶段的“状态变更通知”环节，没有采用Event和pub-sub模型，而是继续使用Command逐个调用下游相关的其他微服务：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/all-commands_hub189c3baaaef25c1ac9b8cb1b874aa89_202731_092ec073293cea2d0293d2ce5026b328.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/all-commands_hub189c3baaaef25c1ac9b8cb1b874aa89_202731_35936610a295e3c66db0184214fc1459.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/all-commands_hub189c3baaaef25c1ac9b8cb1b874aa89_202731_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/all-commands_hub189c3baaaef25c1ac9b8cb1b874aa89_202731_092ec073293cea2d0293d2ce5026b328.webp&#34;
               width=&#34;760&#34;
               height=&#34;315&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Event可以解耦生产者和消费者，因此图中的微服务A和微服务C/D/E之间没有强烈的依赖关系，彼此无需锁定对方的存在。但是Command不同，在采用Command方式后微服务A和下游相关微服务C/D/E会形成强依赖，而且这种依赖关系会蔓延，最终导致形成一颗巨大而深层次的依赖树，而Function由于粒度更细，问题往往更严重：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/dependency-command_hu05f2d69ba0319c258f11ab39e179ac17_459222_f4daade3cc30bc58d6f5fa96d6e0481e.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/dependency-command_hu05f2d69ba0319c258f11ab39e179ac17_459222_85c22257d2b7622d7b34d86574b8be43.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/dependency-command_hu05f2d69ba0319c258f11ab39e179ac17_459222_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/dependency-command_hu05f2d69ba0319c258f11ab39e179ac17_459222_f4daade3cc30bc58d6f5fa96d6e0481e.webp&#34;
               width=&#34;760&#34;
               height=&#34;279&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而如果在“状态变更通知”环节引入Event，则可以解耦微服务和下游被通知的微服务，从而将依赖关系解除，避免无限制的蔓延。如下图所示，左边图形是使用Event代替Command来进行状态变更通知之后的依赖关系，考虑到Event对生产者和消费者的解耦作用，我们“斩断”绿色的Event箭头，这样就得到了右边这样一个被分解为多个小范围依赖树的系统依赖关系图：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/event-decouple-system_hued3ae7166e58f0b5791b5343b75cada8_380171_092224d316c81f240f39e6cb0d725999.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/event-decouple-system_hued3ae7166e58f0b5791b5343b75cada8_380171_ba0e53729a7da8b612bdb33e208f412a.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/event-decouple-system_hued3ae7166e58f0b5791b5343b75cada8_380171_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/event-decouple-system_hued3ae7166e58f0b5791b5343b75cada8_380171_092224d316c81f240f39e6cb0d725999.webp&#34;
               width=&#34;760&#34;
               height=&#34;326&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对Event和Command使用的建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在单体应用拆分为微服务时，不应该简单的将原有的方法调用替换为Command&lt;/li&gt;
&lt;li&gt;应该审视每个调用在业务逻辑上的语义：是业务逻辑执行的组成部分？还是执行完成之后的状态通知？&lt;/li&gt;
&lt;li&gt;然后据此决定采用Command还是Event&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;编排和协调&#34;&gt;编排和协调&lt;/h4&gt;
&lt;p&gt;在Command和Event的使用上，还有两个概念：编排和协调。&lt;/p&gt;
&lt;p&gt;这里强烈推荐一篇博客文章， &lt;a href=&#34;https://solace.com/blog/microservices-choreography-vs-orchestration/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Microservices Choreography vs Orchestration: The Benefits of Choreography&lt;/a&gt;，作者 &lt;a href=&#34;https://solace.com/blog/author/jonathan-schabowsky/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Jonathan Schabowsky&lt;/a&gt; ，Solace 的CTO。他在这边博客中总结了让微服务协同工作的两种模式，并做了一个生动的比喻：&lt;/p&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;编排（Orchestration）：需要主动控制所有的元素和交互，就像指挥家指挥乐团的乐手一样——对应Command。&lt;/li&gt;
&lt;li&gt;协调（Choreography）：需要建立一个模式，微服务会跟随音乐起舞，不需要监督和指令——对应Event。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;img&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/Orchestration-VS-Choreography_hu4fa49df069c328916d7531761e754a3e_88968_b12d19951a7530c1379e20c35743034b.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/Orchestration-VS-Choreography_hu4fa49df069c328916d7531761e754a3e_88968_9ff5a077bd899fafe22680c6865d1981.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/Orchestration-VS-Choreography_hu4fa49df069c328916d7531761e754a3e_88968_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/Orchestration-VS-Choreography_hu4fa49df069c328916d7531761e754a3e_88968_b12d19951a7530c1379e20c35743034b.webp&#34;
               width=&#34;760&#34;
               height=&#34;380&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;也曾看到很多持类似观点的文章，其中有一张图片印象深刻，我摘录过来：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;img&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/what-you-want-what-you-get_hu49b520efb2e95a6ee537b02ec5b1b836_330255_8f741ef0a50548d9e54c59d9ef0d01ea.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/what-you-want-what-you-get_hu49b520efb2e95a6ee537b02ec5b1b836_330255_1b262e785a169f3d3851b6b4ed70f06b.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/what-you-want-what-you-get_hu49b520efb2e95a6ee537b02ec5b1b836_330255_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/what-you-want-what-you-get_hu49b520efb2e95a6ee537b02ec5b1b836_330255_8f741ef0a50548d9e54c59d9ef0d01ea.webp&#34;
               width=&#34;760&#34;
               height=&#34;386&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;左边是&lt;strong&gt;期望&lt;/strong&gt;通过编排（Orchestration）方式得到的整齐划一的理想目标，右边是&lt;strong&gt;实际&lt;/strong&gt;得到的大型翻车现场。&lt;/p&gt;
&lt;h3 id=&#34;全程event带来的问题开发困难和业务边界不清晰&#34;&gt;全程Event带来的问题：开发困难和业务边界不清晰&lt;/h3&gt;
&lt;p&gt;在Command和Event的使用上，除了全程使用Command之外，还有一个极端是全程使用Event，这一点在Lambda（FaaS）中更常见一些：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/all-events_hu49b520efb2e95a6ee537b02ec5b1b836_227542_4a6597881e72fd224549a60128fa8ca0.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/all-events_hu49b520efb2e95a6ee537b02ec5b1b836_227542_58687fd400c5eab49bd4871682aa60c8.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/all-events_hu49b520efb2e95a6ee537b02ec5b1b836_227542_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/all-events_hu49b520efb2e95a6ee537b02ec5b1b836_227542_4a6597881e72fd224549a60128fa8ca0.webp&#34;
               width=&#34;760&#34;
               height=&#34;295&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这个方式首当其冲的问题就是在适用Command语义的地方采用了Event来替代，而由于Command和Event在使用语义上的差异，这个替代会显得别扭：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Command是一对一的，替代他的Event也不得不从 “1:N” 退化为 “1:1”，pub-sub模型不再存在&lt;/li&gt;
&lt;li&gt;Command是需要返回结果的，尤其是Query类的Command必须要有查询结果，使用Event替代之后，就不得不实现 “支持Response的Event”，典型如在消息机制中实现 Request-Reply 模型的。&lt;/li&gt;
&lt;li&gt;或者引入另外一个Event来反向通知结果，即用两个异步Event来替代一个同步的Command —— 这需要让发起者进行额外的订阅和处理，开发复杂性远远超过使用简单的Command。&lt;/li&gt;
&lt;li&gt;而且还引入了一个非常麻烦的状态问题：即服务间通讯的上下文中通常是有状态的，Reply Event必须准确的发送给Request Event的发起者的实例，而不能任意选择一个。这使得Reply Event不仅仅要1:1的绑定订阅者服务，还必须绑定这个服务的特定实例 —— 这样的Reply Event已经没法称为Event了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/two-events-as-one-command_hu49b520efb2e95a6ee537b02ec5b1b836_89637_8c69a43241d1d964e7f0b3bb993cca78.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/two-events-as-one-command_hu49b520efb2e95a6ee537b02ec5b1b836_89637_ce6ccef5f82c8823215db3c80b5a4901.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/two-events-as-one-command_hu49b520efb2e95a6ee537b02ec5b1b836_89637_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/two-events-as-one-command_hu49b520efb2e95a6ee537b02ec5b1b836_89637_8c69a43241d1d964e7f0b3bb993cca78.webp&#34;
               width=&#34;760&#34;
               height=&#34;181&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;绕开这个状态问题的常见方案是选择无状态的场景，如果处理Reply Event时无需考虑状态，那么Event Reply才能简单的发送给任意的实例。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于粒度较大的微服务系统，通常很难实现无状态，所以在微服务中全程采用Event通常会比较别扭的，事实上也很少有人这样做。而在粒度非常小的 Function/FaaS 系统中，全程采用Event方式比较常见。&lt;/p&gt;
&lt;p&gt;关于全程使用Event，我个人持保留态度，我倾向于即使是在FaaS中，也适当保留Command的用法：如果某个操作是“业务逻辑”执行中不可或缺的一部分，那么Command方式的紧耦合反而更能体现出这个“业务逻辑”的存在：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/command-event-in-faas_hu3759b242a349f1696964c87e34156d2e_481164_45ff23794cd08a77d5195194d5a390e4.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/command-event-in-faas_hu3759b242a349f1696964c87e34156d2e_481164_0267aef3ea500502c72a34d43871aa43.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/command-event-in-faas_hu3759b242a349f1696964c87e34156d2e_481164_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/command-event-in-faas_hu3759b242a349f1696964c87e34156d2e_481164_45ff23794cd08a77d5195194d5a390e4.webp&#34;
               width=&#34;760&#34;
               height=&#34;308&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如果完全采用Event方式，“彻底”解耦，则产生新的问题（且不论在编码方面额外带来的复杂度） —— 在海量细粒度的Event调用下，业务逻辑已经很难体现，领域模型（Domain Modeling）和 有界上下文（Bounded Context）则淹没在这些Event调用下，难于识别：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/all-command-in-faas_hu3759b242a349f1696964c87e34156d2e_408786_9d09c7f21a4a5d93ed834a3d1cdb72d8.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/all-command-in-faas_hu3759b242a349f1696964c87e34156d2e_408786_9965fd348e022a37b564ae6862a83958.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/all-command-in-faas_hu3759b242a349f1696964c87e34156d2e_408786_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/all-command-in-faas_hu3759b242a349f1696964c87e34156d2e_408786_9d09c7f21a4a5d93ed834a3d1cdb72d8.webp&#34;
               width=&#34;760&#34;
               height=&#34;303&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：这个问题被称为“Lambda Pinball”，这里不深入展开，后续计划会有一篇文章单独详细探讨“Lambda Pinball”的由来和解决的思路。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;command和event的选择实事求是不偏不倚&#34;&gt;Command和Event的选择：实事求是不偏不倚&lt;/h3&gt;
&lt;p&gt;总结一下Command和Event的选择，我个人的建议是不要一刀切：全程Command方式的缺点容易理解，但简单替换为全程Event也未必合适。&lt;/p&gt;
&lt;p&gt;我的个人观点是倾向于从实际“业务逻辑”处理的语义出发，判断：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果是业务逻辑的 “&lt;strong&gt;实现&lt;/strong&gt;” 部分：倾向于选择使用Command&lt;/li&gt;
&lt;li&gt;如果是业务逻辑完成之后的后续 “&lt;strong&gt;通知&lt;/strong&gt;” 部分：强烈建议选择使用Event&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202007-microservice-avoiding-distributed-monoliths/images/microservice-timeline_hu49b520efb2e95a6ee537b02ec5b1b836_111797_35583864aef9d8f3853f46b8903fa78e.webp 400w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/microservice-timeline_hu49b520efb2e95a6ee537b02ec5b1b836_111797_27fc8973374ce3f8a5527233491e14c6.webp 760w,
               /talk/202007-microservice-avoiding-distributed-monoliths/images/microservice-timeline_hu49b520efb2e95a6ee537b02ec5b1b836_111797_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202007-microservice-avoiding-distributed-monoliths/images/microservice-timeline_hu49b520efb2e95a6ee537b02ec5b1b836_111797_35583864aef9d8f3853f46b8903fa78e.webp&#34;
               width=&#34;760&#34;
               height=&#34;269&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;总结与反思&#34;&gt;总结与反思&lt;/h2&gt;
&lt;h3 id=&#34;警惕不要沦为分布式单体&#34;&gt;警惕：不要沦为分布式单体&lt;/h3&gt;
&lt;p&gt;上面我们列出了微服务和serverless实践中容易形成 “分布式单体” 的两个主要原因和对策：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;通过共享库和网络客户端访问分布式能力：引入非侵入方案解耦应用和各种分布式能力&lt;/li&gt;
&lt;li&gt;简单用远程调用替代进程内方法调用：区分Command和Event，引入Event来解除微服务间不必要的强耦合。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;前者在技术上目前还不太成熟，典型如Istio/Dapr项目都还有待加强，暂时在落地上阻力比较大。但后者已经是业界多年的成熟实践，甚至在微服务和Serverless兴起之前就广泛使用，因此建议可以立即着手改进。&lt;/p&gt;
&lt;p&gt;关于如何更方便的将Event和Event Driven Architecture引入到微服务和Serverless中，同时又不与提供Message Queue分布式能力的具体实现耦合，我将在稍后文章中详细展开，敬请期待。&lt;/p&gt;
&lt;h3 id=&#34;反思喧闹和谩骂之外的冷静思考&#34;&gt;反思：喧闹和谩骂之外的冷静思考&lt;/h3&gt;
&lt;p&gt;如果我们在微服务和Serverless实践中，始终停留在“用远程调用简单替代进程内方法调用”的程度，并固守单体时代的习惯引入各种SDK，那么 &lt;strong&gt;分布式单体&lt;/strong&gt; 问题就必然不可避免。我们的微服务转型、Serverless实践最后得到的往往是：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;把单体变成…… 更糟糕的分布式单体&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当然，微服务可能成为分布式单体，但这并不意味着微服务架构是个谎言，也不意味着比单体架构更差。Serverless 可能同样遭遇分布式单体（还有后续要深入探讨的 Lambda Pinball），但这也不意味着 serverless 不可取 —— 微服务和serverless都是&lt;strong&gt;解决特定问题的工具&lt;/strong&gt;，和所有的工具一样，在使用工具之前，我们需要先研究和了解它们，学习如何正确的使用它们：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;需要为微服务创建正确的架构，和单体架构必然会有很大的不同：一定不是“原封不动”的将方法调替换为远程调用，最好不要用共享类库和网络客户端的方式直接使用各种分布式能力&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Serverless 更是需要我们对架构进行彻底的反思&lt;/strong&gt;，需要改变思维方式，才能保证收益大于弊端&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;参考资料和推荐阅读&#34;&gt;参考资料和推荐阅读&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.slideshare.net/DevOpsDaysDFW/avoid-the-distributed-monolith&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Avoid the Distributed Monolith!!&lt;/a&gt;：来自 verizon 的 Mohamad Byan 在2018年9月的一个演讲，描述微服务实践中的分布式单体陷阱和解决的方式。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;“Mecha：将Mesh进行到底”&lt;/a&gt; ：我前段时间的文章，详细介绍 Multiple Runtime / Macha 架构，将更多的分布式能力进行Mesh化。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.red-gate.com/simple-talk/blogs/the-eight-fallacies-of-distributed-computing/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The Eight Fallacies of Distributed Computing&lt;/a&gt;: 分布式计算领域的经典文章，中文翻译请见 &lt;a href=&#34;http://www.xumenger.com/the-eight-fallacies-of-distributed-computing-20180817/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;分布式计算的八大谬论&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=jjYAZ0DPLNM&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Opportunities and Pitfalls of Event-driven Utopia&lt;/a&gt;: Bernd Rücker 在QCon上的一个演讲，讲述“事件驱动乌托邦的机遇与陷阱”，本文的部分图片来自这份PPT。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.infoq.com/presentations/microservices-ddd-bounded-contexts/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Practical DDD: Bounded Contexts + Events =&amp;gt; Microservices&lt;/a&gt;: Indu Alagarsamy的一个演讲，介绍领域驱动开发（DDD）和 Messaging 的交集。推荐使用消息技术在干净、定义良好的有界上下文之间进行通信，以去除时空耦合。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://medium.com/@ratrosy/building-event-driven-cloud-applications-and-services-ad0b5b970036&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Building Event-Driven Cloud Applications and Services&lt;/a&gt;: 讨论构建事件驱动的应用和服务的通用实践和技术，是一个序列教程。中文翻译看 &lt;a href=&#34;https://skyao.net/post/202004-building-event-driven-cloud-applications-and-services/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;构建事件驱动的云应用和服务&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://go.solace.com/wp-download-eventdrivenmicroservices.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The Architect’s Guide to Event-Driven Microservices&lt;/a&gt;: 来自Solace公司网站上的一份PDF格式的小册子,副标题为 “The Architect’s Guide to Building a Responsive, Elastic and Resilient Microservices Architecture / 架构师指南，用于建立响应式的，灵活而弹性的微服务架构。” 中文翻译见 &lt;a href=&#34;https://skyao.net/post/202004-event-driven-microservices/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;事件驱动微服务架构师指南&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.infoq.cn/article/Nd0RofAUp0WtlvlQArbu&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;致传统企业朋友：不够痛就别微服务，有坑&lt;/a&gt;：网易云刘超刘老师的超级好文章，极其实在而全面的讲述微服务落地需要考虑的方方面面以及各种问题，强烈推荐阅读。&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>[译] Operator和Sidecar: 软件交付的新模式</title>
      <link>https://skyao.net/post/202006-operators-and-sidecars-are-the-new-model-for-software-delivery/</link>
      <pubDate>Mon, 22 Jun 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202006-operators-and-sidecars-are-the-new-model-for-software-delivery/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://thenewstack.io/operators-and-sidecars-are-the-new-model-for-software-delivery/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Operators and Sidecars Are the New Model for Software Delivery&lt;/a&gt;，作者 &lt;a href=&#34;https://thenewstack.io/author/bilgin-ibryam/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Bilgin Ibryam&lt;/a&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：快速翻译（机翻+人工校对，没有精修），质量不高，一般阅读可以，不适合传播，谢绝转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202006-operators-and-sidecars-are-the-new-model-for-software-delivery/images/sidecar_huf365de61b789e791d17635dec9df6056_167009_af1fcdb6a436630d7ca550e6081ba7a5.webp 400w,
               /post/202006-operators-and-sidecars-are-the-new-model-for-software-delivery/images/sidecar_huf365de61b789e791d17635dec9df6056_167009_bc4a9d3e34abd166a394aa4f262ae7c2.webp 760w,
               /post/202006-operators-and-sidecars-are-the-new-model-for-software-delivery/images/sidecar_huf365de61b789e791d17635dec9df6056_167009_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202006-operators-and-sidecars-are-the-new-model-for-software-delivery/images/sidecar_huf365de61b789e791d17635dec9df6056_167009_af1fcdb6a436630d7ca550e6081ba7a5.webp&#34;
               width=&#34;760&#34;
               height=&#34;497&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;现在的开发者要开发弹性和可扩展的分布式系统。这些系统在面对安全问题时要容易修复，要容易进行低风险的增量升级。系统要从开源模式的软件重用和创新中获益。使用应用框架与嵌入式类库，在不同的语言实现全部这些是不可能的。&lt;/p&gt;
&lt;p&gt;最近我在博客上写了一篇关于  &lt;a href=&#34;https://www.infoq.com/articles/multi-runtime-microservice-architecture/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt; &amp;ldquo;多运行时微服务架构&amp;rdquo; &lt;/a&gt; 的文章，探讨了分布式系统的需求，如生命周期管理、高级网络、资源绑定、状态抽象，以及这些抽象在这些年是如何变化的。我还讲了 &lt;a href=&#34;https://www.youtube.com/watch?v=CZPEIJFJV9k&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;分布式系统在Kubernetes上的演进&amp;rdquo;&lt;/a&gt; ，涵盖了Kubernetes Operators和sidecar模型是如何作为主要的创新机制来提供相同的分布式系统原语。&lt;/p&gt;
&lt;p&gt;在这两次中，主要的收获是预测Kubernetes上的软件应用架构会向 operator 管理的 sidecar 模式发展。Sidecar和Oprator可能会成为主流软件分发和使用模式，在某些情况下甚至会取代我们惯用的软件类库和框架。&lt;/p&gt;
&lt;p&gt;sidecar模型支持用不同语言编写的应用程序组合，以提供组合而成的价值，运行的更快，没有运行时的耦合。让我们来看几个具体的sidecar和oprator的例子，然后我们将探讨这种新的软件组合模式对我们的影响。&lt;/p&gt;
&lt;h2 id=&#34;进程外智慧的崛起&#34;&gt;进程外智慧的崛起&lt;/h2&gt;
&lt;p&gt;在Kubernetes中，sidecar是核心设计模式之一，实现方式很轻松：将多个容器组织在一个Pod中。Pod结构保证了容器始终放在同一个节点上，并且可以通过网络、文件系统或其他IPC方法进行交互而实现合作。而 oprertor 支持自动化、Sidecar与平台的其他部分的管理和集成。Sidecar代表了一个语言无关、可扩展的数据平面，为自定义应用提供分布式原语。而Operator则代表他们的集中化管理和控制平面。&lt;/p&gt;
&lt;p&gt;让我们来看看sidecar模型的几种流行表现形式。&lt;/p&gt;
&lt;h3 id=&#34;envoy&#34;&gt;Envoy&lt;/h3&gt;
&lt;p&gt;Istio、Consul等服务网格正在使用Envoy等透明服务代理，为分布式系统提供增强的网络功能。Envoy可以提高安全性，可以实现高级流量管理，提高弹性，增加深度监控和追踪功能。不仅如此，它还能理解越来越多的第七层协议，如Redis、MongoDB、MySQL和最近增加的Kafka。它还增加了应答缓存功能，甚至支持WebAssembly，可以实现各种自定义插件。Envoy是一个很好的例子：透明服务代理如何为分布式系统增加高级网络功能，而不将代理纳入到分布式应用组件的运行时中。&lt;/p&gt;
&lt;h3 id=&#34;skupper&#34;&gt;Skupper&lt;/h3&gt;
&lt;p&gt;除了典型的服务网格外，还有一些项目，比如Skupper，通过外部代理来实现应用网络能力。Skupper通过7层虚拟网络解决多集群Kubernetes通信难题，并提供高级路由和连接能力。但它不是将Skupper嵌入到业务服务运行时，而是在每个Kubernetes命名空间中运行一个实例，作为一个共享的sidecar。&lt;/p&gt;
&lt;h3 id=&#34;cloudstate&#34;&gt;Cloudstate&lt;/h3&gt;
&lt;p&gt;Cloudstate是sidecar模型的另一个例子，但这次是为serverless开发模型提供有状态的抽象。它通过GRPC为EventSourcing、CQRS、Pub/Sub、Key/Value存储和其他用例提供有状态的原语。同样，它也是一个sidecar和operator的例子，但这次是为serverless编程模型提供有状态的抽象。&lt;/p&gt;
&lt;h3 id=&#34;dapr&#34;&gt;Dapr&lt;/h3&gt;
&lt;p&gt;Dapr是由微软发起的一个相对年轻的项目，它也是采用sidecar模型来提供以开发者为中心的分布式系统原语。Dapr提供了状态管理、服务调用和故障处理、资源绑定、pub/sub、分布式跟踪等抽象。尽管Dapr和Service Mesh提供的功能有一些重叠，但两者在本质上有很大不同。Envoy与Istio是从服务中注入并透明运行的，代表的是一种操作工具。而Dapr则必须通过HTTP或gRPC从应用运行时显式调用，它是一个针对开发者的显式sidecar。它可以理解为一个分布式原语的类库，但是是分布式的，并以sidecar的方式使用，这种模式对于使用分布式能力的开发者来说可能非常有吸引力。&lt;/p&gt;
&lt;h3 id=&#34;camel-k&#34;&gt;Camel K&lt;/h3&gt;
&lt;p&gt;Apache Camel 是一个成熟的集成类库，并在Kubernetes上重新发现了自己。它的子项目 Camel K 大量使用operator模型来改善开发者的体验，并与Kubernetes平台深度集成。虽然Camel K并不依赖sidecar，但通过其CLI和operator，它能够重用同一个应用容器，并在远程Kubernetes集群中执行任何本地代码修改，时间不到一秒。这是另一个通过operator模式针对开发者使用软件的例子。&lt;/p&gt;
&lt;h2 id=&#34;更多内容&#34;&gt;更多内容&lt;/h2&gt;
&lt;p&gt;而这些只是一些通过 sidecar 和 operator 探索各种方法的先锋项目。目前有更多的工作来减少基于容器的分布式架构引入的网络开销，比如数据平面开发工具包（DPDK），这是一个绕过Linux内核网络栈层面而直接访问网络硬件的用户空间应用。在Kubernetes项目中，还有创建具有更细化的生命周期保证的sidecar容器。还有一些新的基于GraalVM实现的Java项目，如Quarkus，可以减少资源消耗和应用启动时间，这使得更多的工作负载适用于sidecars。所有这些创新都使的sidecar模式更具吸引力，并得以诞生更多这样的项目。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202006-operators-and-sidecars-are-the-new-model-for-software-delivery/images/multiruntime_hu3bf15c5959fcffaa5c3cf5d9e3504f99_144986_a98f14c1d33e4a929d448176055d9be7.webp 400w,
               /post/202006-operators-and-sidecars-are-the-new-model-for-software-delivery/images/multiruntime_hu3bf15c5959fcffaa5c3cf5d9e3504f99_144986_cddddf364bbb5f2e7fcf23504af89901.webp 760w,
               /post/202006-operators-and-sidecars-are-the-new-model-for-software-delivery/images/multiruntime_hu3bf15c5959fcffaa5c3cf5d9e3504f99_144986_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202006-operators-and-sidecars-are-the-new-model-for-software-delivery/images/multiruntime_hu3bf15c5959fcffaa5c3cf5d9e3504f99_144986_a98f14c1d33e4a929d448176055d9be7.webp&#34;
               width=&#34;760&#34;
               height=&#34;429&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;图：提供分布式系统原语的 Sidecar&lt;/p&gt;
&lt;p&gt;我预期会看到更多围绕具体用例的项目出现，比如在Sidecar中出现长期运行流程的状态化编排，如 Business Process Model and Notation （BPMN）引擎。Sidecar中的作业调度器。无状态集成引擎，即sidecar中的企业集成模式的实现。Sidecar中的数据抽象和数据联合引擎。Sidecar中的 OAuth2/OpenID 代理。sidecars中用于serverless工作负载的可扩展的数据库连接池。作为sidecars的应用网络等等。但是，为什么软件厂商和开发者会改用这种模式呢？让我们来看看它提供的一些好处。&lt;/p&gt;
&lt;h2 id=&#34;带有控制平面的运行时而非类库&#34;&gt;带有控制平面的运行时而非类库&lt;/h2&gt;
&lt;p&gt;如果你是一个如今的软件供应商，可能你已经考虑过将你的软件以API或基于SaaS的解决方案的形式提供给潜在用户。这可能是最快的软件消费模式，而且不费力就能提供。根据软件的性质，你可能也会将你的软件作为类库或运行时框架来发布。是时候考虑是否把它也作为带有operator的容器来提供。这种分发软件的机制和由此产生的架构有一些非常独特的好处，这是类库机制无法提供的。&lt;/p&gt;
&lt;h3 id=&#34;支持多语言的使用者&#34;&gt;支持多语言的使用者&lt;/h3&gt;
&lt;p&gt;通过开放协议和标准提供可使用的类库，就可以为所有的编程语言开放它们。可在HTTP协议上作为sidecar和可使用的类库运行，使用JSON等文本格式，不需要任何特定的客户端运行库。即使在低延迟和高性能的交互时使用gRPC和Protobuf，生成这样的客户端仍然比在应用运行时包含第三方自定义类库并实现某些接口更容易。&lt;/p&gt;
&lt;h3 id=&#34;应用架构无感&#34;&gt;应用架构无感&lt;/h3&gt;
&lt;p&gt;显式sidecar架构（相对于透明架构）是一种软件能力使用方式，作为一个独立的运行时，藏在以开发者为中心的API后面。它是一个正交的功能，可以添加到任何应用程序中，无论是单体、微服务、基于函数、基于actor或任何介于两者之间的应用程序。它可以服务于动态性较差的环境中的单体，也可以服务于基于云的动态环境中的每个微服务。在Kubernetes上创建sidecars是非常简单的，在许多其他软件编排平台上也可以做到。&lt;/p&gt;
&lt;h3 id=&#34;对发布周期不匹配的容忍度&#34;&gt;对发布周期不匹配的容忍度&lt;/h3&gt;
&lt;p&gt;业务逻辑始终是定制的，并在内部开发。分布式系统原语是众所周知的商品特性，作为平台特性或运行时库直接使用。你可能会使用第三方开源项目或公司的状态抽象、消息客户端、网络弹性和监控类库等软件。而这些第三方实体有其发布周期、关键修复、CVE补丁，也会影响软件发布周期。当第三方类库作为一个独立的运行时（sidecar）来使用时，升级过程会比较简单，因为它是在一个API后面，不与应用运行时耦合。更容易管理团队和使用的第三方库供应商之间的发布周期的不匹配。&lt;/p&gt;
&lt;h3 id=&#34;控制平面包含心态&#34;&gt;控制平面包含心态&lt;/h3&gt;
&lt;p&gt;当特性作为类库被使用时，它就被包含在应用程序运行时中，了解它的工作原理，如何配置、监控、调整和升级成为你的责任。这是因为语言运行时（如JVM）和运行时框架（如Spring Boot或应用服务器）决定了如何包含、配置、监控和升级第三方类库。&lt;/p&gt;
&lt;p&gt;当软件能力作为一个独立的运行时（如sidecar或独立的容器）被使用时，它以Kubernetes operator的形式自带控制平面。&lt;/p&gt;
&lt;p&gt;这有很多好处，因为控制平面了解它所管理的软件（操作者），并附带所有必要的管理智能，否则将作为文档和最佳实践分发。更重要的是，operator还与Kubernetes深度集成，并提供了开箱即用的独特平台集成和操作管理智能。operator是由创建operator的开发人员创建的，他们了解容器化功能的内部结构，知道如何操作最合适。operator是容器中的可执行SRE，operator的数量和功能正在稳步增加，更多的operator和市场即将出现。&lt;/p&gt;
&lt;h2 id=&#34;未来的软件发行和使用&#34;&gt;未来的软件发行和使用&lt;/h2&gt;
&lt;h3 id=&#34;软件以带控制平面的sidecar方式发行&#34;&gt;软件以带控制平面的Sidecar方式发行&lt;/h3&gt;
&lt;p&gt;假设你是一个Java框架的软件提供商。你可能会把它作为一个包或Maven工件发布。也许更进一步，发布的是容器镜像。无论哪种情况，在今天的云原生世界中，这都不够好。用户仍然必须知道如何在不停机的情况下对运行中的应用程序进行补丁和升级。他们必须知道如何备份和恢复其状态。他们必须知道如何配置他们的监控和警报阈值。他们必须知道如何检测并从复杂的故障中恢复。他们必须知道如何根据当前的负载情况来调整应用程序。&lt;/p&gt;
&lt;p&gt;在所有这些类似场景中，答案是Kubernetes operators形式的智能控制平面。operator将应用程序的平台和领域知识封装在声明式配置的组件中，以管理工作负载。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sidecar 和 operator 将会成为一种主流的软件发布和使用模式，在某些情况下甚至会取代我们习惯的软件类库和框架。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;假设提供的是软件类库，并作为依赖被包含在使用者的应用程序中。也许它是上面描述的后端框架的客户端类库。例如，在Java中，你可能已经对它进行了认证，以便在JEE服务器上运行，提供了Spring Boot Starters、Builders、Factories和其他实现，这些实现都隐藏在一个干净的Java接口后面。你甚至可能已经把它也带回到了.Net。&lt;/p&gt;
&lt;p&gt;有了Kubernetes的 operator 和 sidecars，所有这些都对使用者隐藏。工厂类被operator取代，唯一的配置接口是自定义资源的YAML文件。然后，operator负责配置软件和平台，以便用户可以以显式的sidecar，或者透明代理的形式来使用它。在所有情况下，应用程序都可以通过远程API进行使用，并与平台功能完全集成，甚至和其他依赖的operators集成。让我们看看是如何实现的。&lt;/p&gt;
&lt;h3 id=&#34;通过远程api而不是侵入式类库来使用软件&#34;&gt;通过远程API而不是侵入式类库来使用软件&lt;/h3&gt;
&lt;p&gt;可以将 sidecar 理解为类似于OOP中的 &lt;strong&gt;组合优于继承&lt;/strong&gt;（composition over inheritance）原则，但是是在多语言的上下文中。Sidecar 是一种迥异的组织方式，通过将不同进程中的能力组合从而组织为应用责任，而不是将它们作为依赖包含到一个单一的应用运行时中。当作为一个类库使用软件时，需要实例化一个类，通过传递一些值对象来调用它的方法。当把它作为一个进程外能力使用时，需要访问一个本地进程。在这个模型中，方法被API取代，进程内方法调用被HTTP或gRPC调用取代，值对象被类似 CloudEvents 的东西取代。这是一个从应用服务器到Kubernetes（作为分布式运行时）的变化。从特定语言的接口到远程API的变化。从内存调用到HTTP，从值对象到CloudEvents等。&lt;/p&gt;
&lt;p&gt;这就需要软件提供商分发容器和控制器来操作。要创建能够在本地构建和调试多个运行时服务的IDE。用于快速将代码变更部署到Kubernetes并配置控制平面的CLI。编译器能够决定编译什么内容到自定义应用运行时，使用 sidecar 和 编排平台的哪些能力。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202006-operators-and-sidecars-are-the-new-model-for-software-delivery/images/softwareconsumers_huc5141c40b5830b8f9f057a5767db2cd1_186171_61f3fcad604215b2a2dc2e4d8ad3f7ff.webp 400w,
               /post/202006-operators-and-sidecars-are-the-new-model-for-software-delivery/images/softwareconsumers_huc5141c40b5830b8f9f057a5767db2cd1_186171_7d22279095daf18e993917c7f565445d.webp 760w,
               /post/202006-operators-and-sidecars-are-the-new-model-for-software-delivery/images/softwareconsumers_huc5141c40b5830b8f9f057a5767db2cd1_186171_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202006-operators-and-sidecars-are-the-new-model-for-software-delivery/images/softwareconsumers_huc5141c40b5830b8f9f057a5767db2cd1_186171_61f3fcad604215b2a2dc2e4d8ad3f7ff.webp&#34;
               width=&#34;760&#34;
               height=&#34;371&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;图：软件使用者和供应商生态系统&lt;/p&gt;
&lt;p&gt;从长远来看，这将导致标准化 API 的整合，这些 API 用于使用 sidecar 中的通用原语。我们将拥有多语言API，而不是特定语言的标准和API。例如，我们将拥有通过HTTP协议使用类似CloudEvents的多语言API，而不是Java数据库连接(JDBC)API、Java的缓存API(JCache)、Java持久性API(JPA)。以Sidecar为中心的API，用于消息传递、缓存、可靠的网络、cron作业和定时器调度、资源绑定（与其他API、协议的连接器）、幂等性、SAGA等。而所有这些能力都将以 operator 的形式包含在管理层中来交付，甚至用自助服务的用户界面来包装。Operator 在这里是关键赋能者，因为它们将使这个更加分布式化的架构在Kubernetes上易于管理和自操作。Operator 的管理接口由 CustomResourceDefinition 定义，代表了另一个面向公众的API，但仍然是应用特有的。&lt;/p&gt;
&lt;p&gt;这是以不同的方式分发和消费软件的心态打转变，由交付速度和可操作性驱动。这是从单运行时到多运行时应用架构的转变。这是一种类似于摩尔定律结束时硬件行业从单核到多核平台所必须经历的转变。这是一个通过构建所有拼图元素而慢慢发生的转变：我们已经统一采用并标准化了容器，我们已经有了通过Kubernetes进行编排的事实标准，可能很快就会有改进的Sidecar，operator的快速采用，CloudEvents作为广泛认同的标准，Quarkus等轻运行时，等等。有了基础，应用、生产力工具、实践、标准化的API和生态系统也会到来。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译] 公开接口与发布接口</title>
      <link>https://skyao.net/post/202006-public-vs-published-interfaces/</link>
      <pubDate>Mon, 15 Jun 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202006-public-vs-published-interfaces/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://martinfowler.com/ieeeSoftware/published.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Public versus Published Interfaces&lt;/a&gt;，作者 &lt;a href=&#34;https://martinfowler.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Martin Fowler&lt;/a&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：快速翻译（机翻+人工校对，没有精修），质量不高，一般阅读可以，不适合传播，谢绝转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;软件设计的发展趋势之一是将接口与实现分离。其原理是将模块分为公共（public）部分和私有（private）部分，这样就可以在不与其他模块协调的情况下改变私有部分。此外，还有更进一步的——公开（Public）接口和发布（Published）接口之间的区别。这种区别很重要，因为它影响到如何使用接口。&lt;/p&gt;
&lt;h2 id=&#34;公开与发布&#34;&gt;公开与发布&lt;/h2&gt;
&lt;p&gt;假设我正在用现代模块化语言编写应用程序——为了使事情更加具体，我们假设这个语言是Java。因此，我的应用程序由多个类（和接口）组成，每个类都有一个公开（Public）接口。这个类的公开接口定义了一组方法，系统中的任何其他类都可以调用这些方法。&lt;/p&gt;
&lt;p&gt;当我在增强一个公开（public）方法时，我意识到它的一个参数是多余的——我不需要在方法中使用它（可能是我可以通过其他途径获得这个值，或者我只是不需要它了）。此时，我可以把这个值从方法签名中删除，让这个方法更清晰，并有可能为其调用者节省工作。因为这个方法是公开的，系统中的任何类都可以调用它。我是否应该删除该参数？&lt;/p&gt;
&lt;p&gt;在这种情况下，我认为是应该的，因为有好处，而且不难。虽然这个方法可能在任何地方使用，但我可以用搜索工具轻松找到用户。如果我有一个适用于Java的新式重构工具（详见www.refactoring.com），我可以通过简单的菜单点击来完成——然后工具会自动更新所有的调用者。所以，改变一个公开（public）方法并不是什么大事。&lt;/p&gt;
&lt;p&gt;然而，如果我把这个软件作为一个组件放到网上，而其他我不认识的人开始在它的基础上构建应用程序，事态就会迅速改变。如果我现在删除这个参数，当我升级时，其他人的代码都会被破坏。现在我必须做一些更复杂的事情。我需要生成少一个参数的新方法，但保留旧方法——可能是重新编码旧方法来调用新方法。我把旧方法标记为废弃（deprecated），假设大家会把代码搬过来，我可以在下一两个版本中修改它。&lt;/p&gt;
&lt;p&gt;这两种情况是完全不同的，然而在Java语言中却没有任何东西可以表述其中的区别——在其他一些语言中这一点也存在差距。然而，公开（public）和发布（published）的区别比更常见的公开-私有的区别更重要。&lt;/p&gt;
&lt;p&gt;关键的区别在于能够找到并修改使用接口的代码。对于一个已发布（published）的接口，这是不可能的，所以你需要一个更复杂的接口更新过程。接口用户要么是调用者，要么是子类或实现接口的类。&lt;/p&gt;
&lt;h2 id=&#34;关于发布的建议&#34;&gt;关于发布的建议&lt;/h2&gt;
&lt;p&gt;认识到公开和发布之间的区别，这个区别会导致一系列重要的后果。&lt;/p&gt;
&lt;h3 id=&#34;不要将接口视为发布除非它真的是&#34;&gt;不要将接口视为发布，除非它真的是&lt;/h3&gt;
&lt;p&gt;如果你需要改变一个接口，并且可以找到并改变所有的用户，那么就不用费劲得去经历所有的转发和废弃的过程。做出改变并更新用户即可。&lt;/p&gt;
&lt;h3 id=&#34;不要在团队内部发布接口&#34;&gt;不要在团队内部发布接口&lt;/h3&gt;
&lt;p&gt;我曾经向某人建议修改一个公开（public）方法，他反对，因为它已经被发布（published）。真正的问题是，虽然团队里只有三个人，但每个开发人员都把自己的接口当作发布（published）给另外两个人。这是因为团队采用了一种强势的代码所有权形式，每个模块都被分配给一个程序员，只有这个程序员可以修改模块的代码。我很认可代码所有权——它鼓励人们监控他们的代码质量——但是像这种强势代码所有权模式会引起问题，因为它迫使你把人际接口当作发布（published）的。&lt;/p&gt;
&lt;p&gt;我鼓励一种较弱的所有权模式，即一个人负责模块，但其他人可以在必要时进行修改。这让其他开发者可以做一些事情，比如修改对变更了的的方法的调用。(你也可以使用集体代码所有权——任何人都可以修改任何东西，以避免内部发布。) 这种所有权通常需要一个支持并发写入器的配置管理系统（比如CVS），而不是使用悲观锁。&lt;/p&gt;
&lt;p&gt;在没有某种形式的内部发布（published）的情况下，能运行多大的团队是有限制的，但我还是倾向于更少的发布（published）。换句话说，先假设不需要发布接口，然后如果发现会导致问题，再进行调整。&lt;/p&gt;
&lt;h3 id=&#34;尽量减少和推迟发布&#34;&gt;尽量减少和推迟发布&lt;/h3&gt;
&lt;p&gt;因为发布将导致变化周期较慢，限制发布频率。这使得公开和发布之间的语义差别成为一个问题。建议最好的是声明一些模块为接口，然后劝告软件用户不要使用其他模块，即使他们可以看到它们。让这些接口尽可能的薄。在开发周期中尽可能晚一点发布，给自己留出时间完善接口。其中一项战略是在发布给大众之前，与组件的一个或两个用户紧密合作——这些用户足够友好可以接收剧烈的变化。&lt;/p&gt;
&lt;h3 id=&#34;尽量以做加法的方式来做变更&#34;&gt;尽量以做加法的方式来做变更&lt;/h3&gt;
&lt;p&gt;除了区分发布接口和公开接口外，我们还可以识别两种类型的接口变化。一般来说，变更可以改变一个接口的任何方面。但是，有一些更改只会造成对接口的添加，比如添加一个方法。添加不会破坏任何一个接口的客户端——现有的客户端使用老的方法是没有问题的。因此，当发生变更时，可以考虑是否可以将其构造为增加项。例如，如果需要从方法中删除一个参数，与其改变方法，不如尝试添加一个没有参数的新方法。这样一来，得到的是一个加法，而不是一般的改动，而客户端仍然是兼容的。&lt;/p&gt;
&lt;p&gt;如果外部有自己的接口实现，添加仍然会引起问题。如果发生这种情况，即使添加一个方法也会破坏替代实现。因此，一些组件技术，如COM，使用不可变的接口。对于不可变的接口，一旦发布了，就必须保证不能改变它。如果想改变这个接口，你必须创建第二个接口，然后组件可以随意支持这个接口。这不是理想的方案，但肯定有它的优点。&lt;/p&gt;
&lt;p&gt;我希望看到公开(public)和发布(published)的区别能更多地出现在语言和平台中。同样有趣的是，环境并不倾向于提供设施来演进接口。有些可以废弃即将被删除的方法：Eiffel将其作为语言的一部分，Java也是如此（但作为内建文档的一部分）。我还没有看到有人在方法中添加标记，警告实现者将要添加的东西，或者容许以一种临时的方式向接口添加东西。这是软件平台中普遍存在的问题。到目前为止，平台还没有充分理解软件应该是“软”的，因此需要设施来允许变更。近年来，我们已经在这个方向上有了长足的进步，有了组件打包系统，但这些只是开始。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>相爱相杀：Servicemesh和API Gateway关系深度探讨</title>
      <link>https://skyao.net/post/202004-servicemesh-and-api-gateway/</link>
      <pubDate>Thu, 30 Apr 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202004-servicemesh-and-api-gateway/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;关于Service Mesh和API Gateway之间的关系，这个问题过去两年间经常被问起，社区也有不少文章和资料给出解答。其中不乏 Christian Posta 这样的网红给出过深度介绍。我在这里做一个资料的整理和汇总，结合个人的理解给出一些看法。另外在本文最后，介绍蚂蚁金服在Service Mesh和API Gateway融合的这个最新领域的一些开创性的实践和探索，希望给大家一个更有体感的认知。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注1：为了节约篇幅，我们将直奔主题，假定读者对Servicemesh和API Gateway已有基本的了解。&lt;/p&gt;
&lt;p&gt;备注2:  这边文章更关注于梳理整个脉络，内容不会展开的特别细，尤其是其他文章已经详细阐述的部分。如果您在浏览本文之后，还想更深入的了解细节，请继续阅读文章最后的参考资料和推荐阅读。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;原本清晰的界限定位和职责&#34;&gt;原本清晰的界限：定位和职责&lt;/h2&gt;
&lt;p&gt;首先，Service Mesh和API Gateway在功能定位和承担的职责上有非常清晰的界限：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Service Mesh：微服务的网络通信基础设施，负责（系统内部的）服务间的通讯&lt;/li&gt;
&lt;li&gt;API Gateway： 负责将服务以API的形式暴露（给系统外部），以实现业务功能&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如上图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-servicemesh-and-api-gateway/images/relationship-without-bff_hub27c856e6c0599a35ff9a89fa6cf8999_108352_a90ba99ec56b012cd1b27bd7e7ce611a.webp 400w,
               /post/202004-servicemesh-and-api-gateway/images/relationship-without-bff_hub27c856e6c0599a35ff9a89fa6cf8999_108352_4b9957cf4cb352c963f5114860d450aa.webp 760w,
               /post/202004-servicemesh-and-api-gateway/images/relationship-without-bff_hub27c856e6c0599a35ff9a89fa6cf8999_108352_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-servicemesh-and-api-gateway/images/relationship-without-bff_hub27c856e6c0599a35ff9a89fa6cf8999_108352_a90ba99ec56b012cd1b27bd7e7ce611a.webp&#34;
               width=&#34;760&#34;
               height=&#34;284&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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;strong&gt;系统内部&lt;/strong&gt;，在采用servicemesh的情况下，由servicemesh提供服务间通讯的能力&lt;/li&gt;
&lt;li&gt;API Gateway用于将系统内部的这些服务暴露给 &lt;strong&gt;系统外部&lt;/strong&gt;，以API的形式接受外部请求。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从部署上说：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Servicemesh部署在系统内部：因为原子微服务和组合服务通常不会直接暴露给外部系统&lt;/li&gt;
&lt;li&gt;API Gateway部署在系统的边缘：一方面暴露在系统之外，对外提供API供外部系统访问；一方面部署在系统内部，以访问内部的各种服务。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在这里引入两个使用非常广泛的术语：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-servicemesh-and-api-gateway/images/directions_hua4205b154b414a6c9b162b19a0d449bd_54903_ad3b66ac526232502cc65f53461c6e60.webp 400w,
               /post/202004-servicemesh-and-api-gateway/images/directions_hua4205b154b414a6c9b162b19a0d449bd_54903_6aba9618d240faaaae7ec56aed5171af.webp 760w,
               /post/202004-servicemesh-and-api-gateway/images/directions_hua4205b154b414a6c9b162b19a0d449bd_54903_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-servicemesh-and-api-gateway/images/directions_hua4205b154b414a6c9b162b19a0d449bd_54903_ad3b66ac526232502cc65f53461c6e60.webp&#34;
               width=&#34;760&#34;
               height=&#34;326&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;东西向&lt;/strong&gt;通讯：指服务间的相互访问，其通讯流量在服务间流转，流量都位于系统内部&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;南北向&lt;/strong&gt;通讯：指服务对外部提供访问，通常是通过API Gateway提供的API对外部保罗，其通讯流量是从系统外部进入系统内部。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;解释一下“东西南北”的由来：如上图所示，通常在地图上习惯性的遵循“上北下南，左西右东”的原则。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;总结：Service Mesh和API Gateway在功能和职责上分工明确，界限清晰。但如果事情就这么结束，也就不会出现Service Mesh和API Gateway关系的讨论了，自然也不会有本文。&lt;/p&gt;
&lt;p&gt;问题的根源在哪里？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;强烈推荐阅读：附录中 Christian Posta 的文章 &amp;ldquo;Do I Need an API Gateway if I Use a Service Mesh?&amp;ldquo;对此有深度分析和讲解。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;哲学问题网关访问内部服务算东西向还是南北向&#34;&gt;哲学问题：网关访问内部服务，算东西向还是南北向？&lt;/h2&gt;
&lt;p&gt;如下图所示，图中黄色的线条表示的是API Gateway访问内部服务：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-servicemesh-and-api-gateway/images/relationship-without-bff_hub27c856e6c0599a35ff9a89fa6cf8999_108352_a90ba99ec56b012cd1b27bd7e7ce611a.webp 400w,
               /post/202004-servicemesh-and-api-gateway/images/relationship-without-bff_hub27c856e6c0599a35ff9a89fa6cf8999_108352_4b9957cf4cb352c963f5114860d450aa.webp 760w,
               /post/202004-servicemesh-and-api-gateway/images/relationship-without-bff_hub27c856e6c0599a35ff9a89fa6cf8999_108352_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-servicemesh-and-api-gateway/images/relationship-without-bff_hub27c856e6c0599a35ff9a89fa6cf8999_108352_a90ba99ec56b012cd1b27bd7e7ce611a.webp&#34;
               width=&#34;760&#34;
               height=&#34;284&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;问题来了，从流量走向看：这是外部流量进入系统后，开始访问对外暴露的服务，应该属于“南北向”通讯，典型如上图的画法。但从另外一个角度，如果我们将 API Gateway 逻辑上拆分为两个部分，先忽略对外暴露的部分，单独只看  API Gateway  访问内部服务的部分，这时可以视 API Gateway 为一个普通的客户端服务，它和内部服务的通讯更像是“东西向”通讯：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-servicemesh-and-api-gateway/images/api-gateway-access-service_huf0fe3ee17f350710b258c8e9b37cd31f_88997_692c265fe08ad89eb82e18bfba214e6c.webp 400w,
               /post/202004-servicemesh-and-api-gateway/images/api-gateway-access-service_huf0fe3ee17f350710b258c8e9b37cd31f_88997_5ceea65e25412701c5d15b7ae8beab86.webp 760w,
               /post/202004-servicemesh-and-api-gateway/images/api-gateway-access-service_huf0fe3ee17f350710b258c8e9b37cd31f_88997_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-servicemesh-and-api-gateway/images/api-gateway-access-service_huf0fe3ee17f350710b258c8e9b37cd31f_88997_692c265fe08ad89eb82e18bfba214e6c.webp&#34;
               width=&#34;760&#34;
               height=&#34;284&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;所以，API Gateway 作为一个客户端访问内部服务时，到底算南北向还是东西向，就成为一个哲学问题：完全取决于我们如何看待 API Gateway ，是作为一个整体，还是逻辑上分拆为对内对外两个部分。&lt;/p&gt;
&lt;p&gt;这个哲学问题并非无厘头，在 API Gateway 的各种产品中，关于如何实现 “API Gateway 作为一个客户端访问内部服务” ，就通常分成两个流派：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;泾渭分明：视 API Gateway 和内部服务为两个独立事物，API Gateway访问内部服务的通讯机制自行实现，独立于服务间通讯的机制&lt;/li&gt;
&lt;li&gt;兼容并济：视 API Gateway 为一个普通的内部服务的客户端，重用其内部服务间通讯的机制。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;而最终决策通常也和产品的定位有关：如果希望维持  API Gateway 的独立产品定位，希望可以在不同的服务间通讯方案下都可以使用，则通常选择前者，典型如kong；如果和服务间通讯方案有非常深的渊源，则通常选择后者，典型如springcloud生态下的zuul和springcloud gateway。&lt;/p&gt;
&lt;p&gt;但无论选择哪个流派，都改变不了一个事实，当 “API Gateway 作为一个客户端访问内部服务” 时，它的确和一个普通内部服务作为客户端去访问其他服务没有本质差异：服务发现，负载均衡，流量路由，熔断，限流，服务降级，故障注入，日志，监控，链路追踪，访问控制，加密，身份认证&amp;hellip;&amp;hellip; 当我们把网关访问内部服务的功能一一列出来时，发现几乎所有的这些功能都是和服务间调用重复。&lt;/p&gt;
&lt;p&gt;这也就造成了一个普遍现象：如果已有一个成熟的服务间通讯框架，再去考虑实现API Gateway，重用这些重复的能力就成为自然而然的选择。典型如前面提到的 springcloud 生态下的 zuul 以及后面开发的 springcloud gateway，就是以重用类库的方式实现了这些能力的重用。&lt;/p&gt;
&lt;p&gt;这里又是一个类似的哲学问题：当 “API Gateway 作为一个客户端访问内部服务” 时，它以重用类库的方式实现了代码级别的能力重用，相当于自行实现了一个和普通服务间通讯方案完全一样的客户端，那这个“客户端”发出来的流量算东西向还是南北向？&lt;/p&gt;
&lt;p&gt;答案不重要。&lt;/p&gt;
&lt;h2 id=&#34;sidecar真正的重合点&#34;&gt;Sidecar：真正的重合点&lt;/h2&gt;
&lt;p&gt;在进入servicemesh时代之后，Servicemesh和API gateway 的关系开始是这样：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;功能和职责清晰划分&lt;/li&gt;
&lt;li&gt;客户端访问服务的功能高度重叠&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;此时两者的关系很清晰，而且由于当时Servicemesh和API Gateway是不同的产品，两者的重合点只是在功能上。&lt;/p&gt;
&lt;p&gt;而随着时间的推移，当 Servicemesh 产品和 API Gateway 产品开始出现相互渗透时，两者的关系就开始变得暧昧。&lt;/p&gt;
&lt;p&gt;在Servicemesh出现之后，如何为基于Servicemesh的服务选择合适的API Gateway方案，就慢慢开始提上日程，而其中选择重用Servicemesh的能力也自然成为一个探索的方向，并逐步出现新式API Gateway产品，其想法很直接：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何融合东西向和南北向的通讯方案？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;其中的一个做法就是基于Servicemesh的Sidecar来实现API Gateway，从而在南北向通讯中引入Servicemesh这种东西向通讯的方案。这里我们不展开细节，我这里援引一个图片(鸣谢赵化冰同学)来解释这个方案的思路：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-servicemesh-and-api-gateway/images/api-gateway-with-service-mesh_hue5f03e6ac5dfd91191c9c2c237194c18_31788_866ec625f5e3b374693a6fb31a28fe4a.webp 400w,
               /post/202004-servicemesh-and-api-gateway/images/api-gateway-with-service-mesh_hue5f03e6ac5dfd91191c9c2c237194c18_31788_abfc50f7501c62af0762373428db879d.webp 760w,
               /post/202004-servicemesh-and-api-gateway/images/api-gateway-with-service-mesh_hue5f03e6ac5dfd91191c9c2c237194c18_31788_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-servicemesh-and-api-gateway/images/api-gateway-with-service-mesh_hue5f03e6ac5dfd91191c9c2c237194c18_31788_866ec625f5e3b374693a6fb31a28fe4a.webp&#34;
               width=&#34;760&#34;
               height=&#34;244&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这个时候servicemesh和API Gateway的关系就变得有意思了，因为servicemesh中sidecar的引入，所以前面的“哲学问题”又有了一个新的解法：API Gateway这次真的可以分拆为两个独立部署的物理实体，而不是逻辑上的两个部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;API Gateway本体：实现API Gateway除了访问内部服务之外的功能&lt;/li&gt;
&lt;li&gt;Sidecar：按照servicemesh的标准做法， 我们视API Gateway为一个部署于servicemesh中的普通服务，为这个服务1:1的部署sidecar&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-servicemesh-and-api-gateway/images/api-gateway-access-service-via-sidecar_huc56418c38975cec51ded52f628b5e565_113155_060393d7fc09565fdd3fe6c2951d4db9.webp 400w,
               /post/202004-servicemesh-and-api-gateway/images/api-gateway-access-service-via-sidecar_huc56418c38975cec51ded52f628b5e565_113155_d9d9a27d6ede2781845985f999adb8ad.webp 760w,
               /post/202004-servicemesh-and-api-gateway/images/api-gateway-access-service-via-sidecar_huc56418c38975cec51ded52f628b5e565_113155_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-servicemesh-and-api-gateway/images/api-gateway-access-service-via-sidecar_huc56418c38975cec51ded52f628b5e565_113155_060393d7fc09565fdd3fe6c2951d4db9.webp&#34;
               width=&#34;760&#34;
               height=&#34;284&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在这个方案中，原来用于servicemesh的sidecar，被用在了API Gateway中，替代了API Gateway中原有的客户端访问的各种功能。这个方案让API Gateway的实现简化了很多，也实现了东西向和南北向通讯能力的重用和融合，而 API Gateway可以更专注于 “API Management” 的核心功能。&lt;/p&gt;
&lt;p&gt;此时 servicemesh 和 API Gateway 的关系就从“泾渭分明”变成了“兼容并济”。&lt;/p&gt;
&lt;p&gt;而采用这个方案的公司，通常都是先有servicemesh产品，再基于servicemesh产品规划（或者重新规划）API Gateway方案，典型如蚂蚁金服的SOFA Gateway产品是基于MOSN，而社区开源产品Ambassador和Gloo都是基于Envoy。&lt;/p&gt;
&lt;p&gt;上述方案的优势在于API Gateway和Sidecar独立部署，职责明确，架构清晰。但是，和servicemesh使用sidecar被质疑多一跳会造成性能开销影响效率一样，API Gateway使用Sidecar也被同样的质疑：多了一跳&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;解决“多一跳”问题的方法简单而粗暴，基于sidecar，将API Gateway的功能加进来。这样API Gateway本体和Sidecar再次合二为一：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-servicemesh-and-api-gateway/images/api-gateway-based-on-sidecar_hu8317c108d3f682919948f23fbc5672f4_118375_274b470fc116c4dc2d2a78285d951440.webp 400w,
               /post/202004-servicemesh-and-api-gateway/images/api-gateway-based-on-sidecar_hu8317c108d3f682919948f23fbc5672f4_118375_b5e4f8438acc27fc1eeb00c3dae932e1.webp 760w,
               /post/202004-servicemesh-and-api-gateway/images/api-gateway-based-on-sidecar_hu8317c108d3f682919948f23fbc5672f4_118375_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-servicemesh-and-api-gateway/images/api-gateway-based-on-sidecar_hu8317c108d3f682919948f23fbc5672f4_118375_274b470fc116c4dc2d2a78285d951440.webp&#34;
               width=&#34;760&#34;
               height=&#34;284&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;至于走到这一步之后，Servicemesh和API Gateway是什么关系：这到底算是Servicemesh/sidecar融合了API Gateway，还是API Gateway融合了Servicemesh/Sidecar？这个问题就像斑马到底是白底黑纹还是黑底白纹一样，见仁见智。&lt;/p&gt;
&lt;h2 id=&#34;bff把融合进行到底&#34;&gt;BFF：把融合进行到底&lt;/h2&gt;
&lt;p&gt;BFF(Backend For Frontend)的引入会让Servicemesh和API Gateway走到一个更加亲密的地步。&lt;/p&gt;
&lt;p&gt;先来看看常规的BFF的玩法：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-servicemesh-and-api-gateway/images/relationship-with-bff_hu8eb4e2e0bfa2c646e35850acfa6b3966_122422_4d6cd0b12bc27f8cb47822c14faca802.webp 400w,
               /post/202004-servicemesh-and-api-gateway/images/relationship-with-bff_hu8eb4e2e0bfa2c646e35850acfa6b3966_122422_5c1a8baa8144f52a49725dcd86e0d613.webp 760w,
               /post/202004-servicemesh-and-api-gateway/images/relationship-with-bff_hu8eb4e2e0bfa2c646e35850acfa6b3966_122422_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-servicemesh-and-api-gateway/images/relationship-with-bff_hu8eb4e2e0bfa2c646e35850acfa6b3966_122422_4d6cd0b12bc27f8cb47822c14faca802.webp&#34;
               width=&#34;760&#34;
               height=&#34;338&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在这里，多增加了一个 BFF 层，介于API Gateway和内部服务（包括组合服务和原子微服务）之间。注意BFF的工作模式和组合服务很类似，都是组合多个服务。但差别在于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;组合服务还属于服务的范畴，只是实现机制上组合了多个服务，对外暴露的依然是一个完整和规范的服务&lt;/li&gt;
&lt;li&gt;BFF不同，BFF如名字所示，Backend For Frontend，完全是为了前端而存在，核心目标之一是简化前端的访问&lt;/li&gt;
&lt;li&gt;对我们今天的话题而言，最关键的一点：BFF完全收口了从外部进入的流量，而组合服务没有，API Gateway是可以直接访问原子微服务的&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;“BFF完全收口外部流量”，这一点在API Gateway和Sidecar融合之后，会变得很有想象空间，我们先看按照前面的融合方式，在有BFF的情况下，API Gateway和Sidecar融合后的情景：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-servicemesh-and-api-gateway/images/api-gateway-based-on-sidecar-with-bff_hu39aaf57ba28203eee1daf78e231d3f5e_130528_2b274d388a2338d05099b206d09c0564.webp 400w,
               /post/202004-servicemesh-and-api-gateway/images/api-gateway-based-on-sidecar-with-bff_hu39aaf57ba28203eee1daf78e231d3f5e_130528_d7347aed27d85eacb758af1b75ae7005.webp 760w,
               /post/202004-servicemesh-and-api-gateway/images/api-gateway-based-on-sidecar-with-bff_hu39aaf57ba28203eee1daf78e231d3f5e_130528_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-servicemesh-and-api-gateway/images/api-gateway-based-on-sidecar-with-bff_hu39aaf57ba28203eee1daf78e231d3f5e_130528_2b274d388a2338d05099b206d09c0564.webp&#34;
               width=&#34;760&#34;
               height=&#34;374&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;放大一点，单独看API Gateway和BFF：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-servicemesh-and-api-gateway/images/two-sidecar-in-bff_hu7baae209101f190d2d2f43489815e04f_22604_be2b55bec2c7158fbbfc4f3fd3bc5697.webp 400w,
               /post/202004-servicemesh-and-api-gateway/images/two-sidecar-in-bff_hu7baae209101f190d2d2f43489815e04f_22604_086bad83ed69a7d14a30abfad82448e1.webp 760w,
               /post/202004-servicemesh-and-api-gateway/images/two-sidecar-in-bff_hu7baae209101f190d2d2f43489815e04f_22604_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-servicemesh-and-api-gateway/images/two-sidecar-in-bff_hu7baae209101f190d2d2f43489815e04f_22604_be2b55bec2c7158fbbfc4f3fd3bc5697.webp&#34;
               width=&#34;552&#34;
               height=&#34;416&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;注意到，流量从被API Gateway接收，到进入BFF在这个流程中，这个请求路径中有两个sidecar：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;和BFF部署在一起的，是没有API Gateway功能的普通Sidecar&lt;/li&gt;
&lt;li&gt;API Gateway和Sidecar融合之后，这就是一个“有API Gateway功能的大Sidecar”（或者是“有Sidecar功能的特殊API Gateway”）：虽然扮演了API Gateway的角色，但本质上依然包含一个完整功能的sidecar，和BFF自带的Sidecar是等同的&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所以，问题来了：为什么要放两个sidecar在流程中，缩减到一个会怎么样？我们尝试将两个Sidecar合二为一，去掉BFF自带的Sidecar，直接把扮演API Gateway的sidecar给BFF用：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-servicemesh-and-api-gateway/images/one-sidecar-in-bff_hu6ccb64566e4e936a75bbc3febef96f67_14347_001547d745e6cc35b1ac2d584a656b68.webp 400w,
               /post/202004-servicemesh-and-api-gateway/images/one-sidecar-in-bff_hu6ccb64566e4e936a75bbc3febef96f67_14347_b018fe7b894e1b29396928653b10e444.webp 760w,
               /post/202004-servicemesh-and-api-gateway/images/one-sidecar-in-bff_hu6ccb64566e4e936a75bbc3febef96f67_14347_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-servicemesh-and-api-gateway/images/one-sidecar-in-bff_hu6ccb64566e4e936a75bbc3febef96f67_14347_001547d745e6cc35b1ac2d584a656b68.webp&#34;
               width=&#34;645&#34;
               height=&#34;287&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;此时的场景是这样：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;流量直接打到BFF上（BFF前面可能会挂其他的网络组件提供负载均衡等功能）&lt;/li&gt;
&lt;li&gt;BFF的sidecar接收流量，完成API Gateway的功能，然后将流量转给BFF&lt;/li&gt;
&lt;li&gt;BFF通过sidecar调用内部服务（和没有合并时一致）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-servicemesh-and-api-gateway/images/bff-api-gateway_hufa8ab7855af0a1dbc96110c1a7ce59ae_135500_7c54efe18271ed088eccc4ddbf12c23f.webp 400w,
               /post/202004-servicemesh-and-api-gateway/images/bff-api-gateway_hufa8ab7855af0a1dbc96110c1a7ce59ae_135500_bf216fe1163106e6a59e7a9555ed569b.webp 760w,
               /post/202004-servicemesh-and-api-gateway/images/bff-api-gateway_hufa8ab7855af0a1dbc96110c1a7ce59ae_135500_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-servicemesh-and-api-gateway/images/bff-api-gateway_hufa8ab7855af0a1dbc96110c1a7ce59ae_135500_7c54efe18271ed088eccc4ddbf12c23f.webp&#34;
               width=&#34;760&#34;
               height=&#34;389&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;注意这里有一个关键点，在前面时特意注明的：“&lt;strong&gt;BFF完全收口外部流量&lt;/strong&gt;”。这是前提条件，因为原有的API Gateway集群已经不再存在，如果BFF没能收口全部流量，则这些未能收口的流量会找不到API Gateway。当然，如果愿意稍微麻烦一点，在部署时清晰的划定需要暴露给外界的服务，直接在这些服务上部署带API Gateway功能的Sidecar，也是可行的，只是管理上会比BFF模式要复杂一些。&lt;/p&gt;
&lt;p&gt;另外，在部署上，按照上面的方案，我们会发现：API Gateway“消失”了 —— 不再有一个明确物理部署的API Gateway的集群，常规的中心化的网关在这个方案中被融合到每一个BFF的实例中，从而实现另外一个重要特性：去中心化。&lt;/p&gt;
&lt;p&gt;上述Servicemesh 和 API Gateway融合的方案，并未停留在纸面上。&lt;/p&gt;
&lt;p&gt;在蚂蚁金服内部，我们基于Servicemesh 和 API Gateway融合 + 去中心化的思路，进行过开创性的实践和探索。以支付宝移动网关为例，在过去十年间，网关经历了从单体到微服务，从中心化到去中心化，从共享的 gateway.jar 包到利用MOSN实现网关Mesh化/Sidecar化，最终演变成了这样一个方案：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-servicemesh-and-api-gateway/images/antfin-mesh-gateway_hued6ae6f94556d57599478cf3a6949453_1852032_fdd85a1e5c691101033a40eae7ace575.webp 400w,
               /post/202004-servicemesh-and-api-gateway/images/antfin-mesh-gateway_hued6ae6f94556d57599478cf3a6949453_1852032_ecc378a1cf60a156b7cf3c29f71d853d.webp 760w,
               /post/202004-servicemesh-and-api-gateway/images/antfin-mesh-gateway_hued6ae6f94556d57599478cf3a6949453_1852032_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-servicemesh-and-api-gateway/images/antfin-mesh-gateway_hued6ae6f94556d57599478cf3a6949453_1852032_fdd85a1e5c691101033a40eae7ace575.webp&#34;
               width=&#34;760&#34;
               height=&#34;379&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;强烈推荐阅读：附录中我的同事 贾岛 的文章 “蚂蚁金服 API Gateway Mesh 思考与实践” 对此有深入介绍和详细描述。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;本文总结了 Servicemesh 和 API Gateway 的关系，整体上说两者的定位和职责“泾渭分明”，但在具体实现上，开始出现融合的趋势：早期传统方式是类库级别的代码复用，最新趋势是API Gateway和Sidecar 合二为一。&lt;/p&gt;
&lt;p&gt;后者的发展才刚刚起步，包括在蚂蚁金服我们也是才开始探索这个方向，但是相信在未来一两年间，社区可能会有更多的类似产品形态出现。&lt;/p&gt;
&lt;p&gt;补充介绍一下文中多次提到的“MOSN”：&lt;/p&gt;
&lt;p&gt;MOSN 是 MOSN 是 Modular Open Smart Network 的简称， 是一款使用 Go 语言开发的网络代理软件，由蚂蚁金服开源并经过几十万容器的生产级验证。 MOSN 作为云原生的网络数据平面，旨在为服务提供多协议、模块化、智能化、安全的代理能力。 MOSN 可以与任何支持 xDS API 的 Service Mesh 集成，亦可以作为独立的四、七层负载均衡，API Gateway、云原生 Ingress 等使用。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GitHub：https://github.com/mosn/mosn&lt;/li&gt;
&lt;li&gt;官网：https://mosn.io&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;附录参考资料和推荐阅读&#34;&gt;附录：参考资料和推荐阅读&lt;/h2&gt;
&lt;p&gt;意犹未尽的同学，欢迎继续阅读以下内容。&lt;/p&gt;
&lt;p&gt;按文章发表的时间排序：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://konghq.com/blog/the-difference-between-api-gateways-and-service-mesh/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The Difference Between API Gateways and Service Mesh&lt;/a&gt;： 2020-02，指导架构师确定何时使用API网关以及何时使用服务网格，作者Marco Palladino，来自kong。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.christianposta.com/microservices/do-i-need-an-api-gateway-if-i-have-a-service-mesh/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Do I Need an API Gateway if I Use a Service Mesh?&lt;/a&gt;：2020-01，作者 Christian Posta，中文翻译版本请见马若飞同学的 &lt;a href=&#34;https://www.servicemesher.com/blog/do-i-need-an-api-gateway-if-i-have-a-service-mesh/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;使用了 Service Mesh 后我还需要 API 网关吗&lt;/a&gt;，对 Service Mesh 技术和 API 网关的对比，着重分析了两者的功能重合点和分歧点，为技术选型和落地提供了指导思路。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.infoq.cn/article/azCFGyTDGakZqaLEEDMN&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;蚂蚁金服 API Gateway Mesh 思考与实践&lt;/a&gt;: 2019-12，作者贾岛，介绍蚂蚁金服支付宝网关的发展和API Gateway Mesh的由来，强烈推荐阅读，这个文章非常清晰的介绍了蚂蚁金服在Servicemesh和API Gateway融合方面的实践。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.servicemesher.com/blog/api-gateways-are-going-through-an-identity-crisis/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;API Gateway的身份认同危机&lt;/a&gt;: 2019-05, 原文作者 Christian Posta，译者周雨青，讲述API Gateway的基本理念如API的定义，API Management的含义，API Gateway模式，以及服务网格和API Gateway的关系。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;../../talk/201810-ant-finance-service-mesh-practice/&#34;&gt;长路漫漫踏歌而行：蚂蚁金服Service Mesh实践探索&lt;/a&gt;: 2018-10，我在QCon的演讲，我分享了当时蚂蚁金服在服务间通讯范围的探索，提出将服务网格在东西向通讯中的能力重用到南北向通讯中，当时基于Sidecar的SOFA Gateway产品刚开始开发。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.getambassador.io/api-gateway-vs-service-mesh-104c01fa4784&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;API Gateway vs Service Mesh&lt;/a&gt;: 2018-09，作者Richard Li，Datawire的CEO ，在开发 Ambassador API Gateway。Ambassador 是基于 Envoy 的API Gateway开源产品，文章阐述了对服务网格和API Gateway的看法，差异，以及对两者集成的看法。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;../../post/201803-dreammesh-brainstorm-gateway/&#34;&gt;DreamMesh抛砖引玉(9)-API Gateway&lt;/a&gt;: 2018-03，这个文章也是我写的，2018年初我和servicemesh社区的一些朋友深入探讨之后，在DreamMesh系列博客文章中记录下了当时构想的方案，尤其对 API gateway和sidecar是分是合有详细讨论。当时想法还不够成熟，但大体方向已经有雏形了。鸣谢当时参与讨论的同学！&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://medium.com/microservices-in-practice/service-mesh-vs-api-gateway-a6d814b9bf56&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Service Mesh vs API Gateway&lt;/a&gt;: 2017-10，原文作者 &lt;a href=&#34;https://medium.com/@kasunindrasiri&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Kasun Indrasiri&lt;/a&gt;，以及 &lt;a href=&#34;https://zhaohuabing.com/2018/04/11/service-mesh-vs-api-gateway/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;赵化冰同学翻译的中文版本&lt;/a&gt;，文章不长，主要对比了服务网格和API Gateway的产品功能，提出了两者融合的方式——在API Gateway中通过服务网格来调用下游服务。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://blog.christianposta.com/microservices/application-network-functions-with-esbs-api-management-and-now-service-mesh/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Application Network Functions With ESBs, API Management, and Now.. Service Mesh?&lt;/a&gt;：2017-08，作者 Christian Posta，讲述服务网格与ESB，消息代理和API管理之类的事物的关系。内容非常好，强烈推荐阅读（我不得不吐糟一下：配图太辣眼睛）。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Mecha：将Mesh进行到底</title>
      <link>https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/</link>
      <pubDate>Sat, 25 Apr 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/</guid>
      <description>&lt;h2 id=&#34;mecha介绍&#34;&gt;Mecha介绍&lt;/h2&gt;
&lt;h3 id=&#34;什么是macha&#34;&gt;什么是Macha？&lt;/h3&gt;
&lt;p&gt;Mecha一词，相信爱好动漫的同学应该都不陌生。是的，就是大家熟悉的那个Mecha（机甲）：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202004-mecha-mesh-through-to-the-end/images/mecha_huda146d3825fc6d502e05b38609bff098_493667_10a320f686ee1f78b653ecc8740f0ac0.webp 400w,
               /talk/202004-mecha-mesh-through-to-the-end/images/mecha_huda146d3825fc6d502e05b38609bff098_493667_67f71d5b352ab91f44f0247be4dda64d.webp 760w,
               /talk/202004-mecha-mesh-through-to-the-end/images/mecha_huda146d3825fc6d502e05b38609bff098_493667_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/images/mecha_huda146d3825fc6d502e05b38609bff098_493667_10a320f686ee1f78b653ecc8740f0ac0.webp&#34;
               width=&#34;760&#34;
               height=&#34;381&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Mecha这个词之所以出现在这里，主要是因为 &lt;strong&gt;Bilgin Ibryam&lt;/strong&gt; 的这个博客文章 “&lt;strong&gt;&lt;a href=&#34;https://www.infoq.com/articles/multi-runtime-microservice-architecture/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Multi-Runtime Microservices Architecture&lt;/a&gt;&lt;/strong&gt;”，提出了微服务架构的一个新的设想：Multiple Runtime。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：这篇博客文章强烈推荐阅读，我甚至建议在阅读本文之前先阅读这篇文章，因为我今天的内容，可以视为对这个文章的深度解读和思考。为了方便，这里提供一份中文翻译版本 &lt;a href=&#34;https://skyao.net/post/202003-multi-runtime-microservice-architecture/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;多运行时微服务架构&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在这篇博客中，Bilgin Ibryam 首先分析并总结了分布式应用的四大需求:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202004-mecha-mesh-through-to-the-end/images/four-needs-of-app_hu3828c8b408219066fbc7297d21b025bb_65201_99ca95c76cf713ff68b71dec9a71bced.webp 400w,
               /talk/202004-mecha-mesh-through-to-the-end/images/four-needs-of-app_hu3828c8b408219066fbc7297d21b025bb_65201_44aec79d495406c31bf4dae74098c023.webp 760w,
               /talk/202004-mecha-mesh-through-to-the-end/images/four-needs-of-app_hu3828c8b408219066fbc7297d21b025bb_65201_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/images/four-needs-of-app_hu3828c8b408219066fbc7297d21b025bb_65201_99ca95c76cf713ff68b71dec9a71bced.webp&#34;
               width=&#34;760&#34;
               height=&#34;409&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;生命周期（Lifecycle）&lt;/li&gt;
&lt;li&gt;网络（Networking）&lt;/li&gt;
&lt;li&gt;状态（State）&lt;/li&gt;
&lt;li&gt;捆绑（Binding）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于每种需求存在的问题和局限性，导致传统解决方案如企业服务总线（ESB）及其变体（例如面向消息的中间件，更轻量级的集成框架等）不再适用。随着微服务架构的发展，以及容器和Kubernetes的普及和广泛使用，云原生思想开始影响这些需求的实现方式。未来的架构趋势是通过将所有传统的中间件功能移至其他运行时来全面发展，最后的目标是在服务中只需编写业务逻辑。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：详情请见原文，为了节约篇幅，这里只做简单概述，不完全引用原文内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下图是传统中间件平台和云原生平台的对比，传统中间件以各种SDK的方式提供能力，而云原生平台则通过各种外围Runtime（典型如大家熟悉的Servicemesh/Istio）：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202004-mecha-mesh-through-to-the-end/images/traditional-platform-and-cloudnative-platform_hu18bcab3fc2cc0513aa3cb38bca4a9a66_41954_ac405e1ea67a1f53614791a7900931ba.webp 400w,
               /talk/202004-mecha-mesh-through-to-the-end/images/traditional-platform-and-cloudnative-platform_hu18bcab3fc2cc0513aa3cb38bca4a9a66_41954_b0a7247ff4212a1a83541c12f81eb695.webp 760w,
               /talk/202004-mecha-mesh-through-to-the-end/images/traditional-platform-and-cloudnative-platform_hu18bcab3fc2cc0513aa3cb38bca4a9a66_41954_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/images/traditional-platform-and-cloudnative-platform_hu18bcab3fc2cc0513aa3cb38bca4a9a66_41954_ac405e1ea67a1f53614791a7900931ba.webp&#34;
               width=&#34;760&#34;
               height=&#34;253&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;因此作者引入了Multiple Runtime的概念：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202004-mecha-mesh-through-to-the-end/images/multi-runtime-microservices_huda146d3825fc6d502e05b38609bff098_210736_6d63b96504b12472c8e5698504bf5fb3.webp 400w,
               /talk/202004-mecha-mesh-through-to-the-end/images/multi-runtime-microservices_huda146d3825fc6d502e05b38609bff098_210736_115fc0a3a4af12223bc7d8c4467a3c86.webp 760w,
               /talk/202004-mecha-mesh-through-to-the-end/images/multi-runtime-microservices_huda146d3825fc6d502e05b38609bff098_210736_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/images/multi-runtime-microservices_huda146d3825fc6d502e05b38609bff098_210736_6d63b96504b12472c8e5698504bf5fb3.webp&#34;
               width=&#34;760&#34;
               height=&#34;311&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;作者提出：很可能在将来，我们最终将使用多个运行时来实现分布式系统。&lt;strong&gt;多个运行时，不是因为有多个微服务，而是因为每个微服务都将由多个运行时组成&lt;/strong&gt;，最有可能是两个运行时-自定义业务逻辑运行时和分布式原语运行时。&lt;/p&gt;
&lt;p&gt;对多运行时微服务架构和Mecha的说明：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;您还记得电影《阿凡达》和科学家们制作的用于去野外探索潘多拉的 Amplified Mobility Platform (AMP)“机车服”吗？这个多运行时架构类似于这些 Mecha-套装，为类人驾驶员赋予超能力。在电影中，您要穿上套装才能获得力量并获得破坏性武器。在这个软件架构中，您将拥有构成应用核心的业务逻辑（称为微逻辑/micrologic）和提供强大的开箱即用的分布式原语的sidecar mecha组件。Micrologic与mecha功能相结合，形成多运行时微服务，该服务将进程外功能用于其分布式系统需求。最棒的是，Avatar 2即将面世，以帮助推广这种架构。我们最终可以在所有软件会议上用令人赞叹的机甲图片代替老式的边车摩托车；-)。接下来，让我们看看该软件架构的详细信息。&lt;/p&gt;
&lt;p&gt;这是一个类似于客户端-服务器体系结构的双组件模型，其中每个组件都是独立的运行时。它与纯客户端-服务器架构的不同之处在于，这两个组件都位于同一主机上，彼此之间有可靠的网络连接。这两个组件的重要性相当，它们可以在任一方向上发起操作并充当客户端或服务器。其中的一个组件称为Micrologic，拥有非常少的业务逻辑，把几乎所有分布式系统问题都剥离出去了。另一个伴随的组件是Mecha，提供了我们在本文中一直讨论的所有分布式系统功能（生命周期除外，它是平台功能）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;作者在这里正式提出了Mecha的理念：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202004-mecha-mesh-through-to-the-end/images/multi-runtime-microservices-architecture_hu05f2d69ba0319c258f11ab39e179ac17_548510_1ceea0a086af2cbb35a8ce9f35eb2646.webp 400w,
               /talk/202004-mecha-mesh-through-to-the-end/images/multi-runtime-microservices-architecture_hu05f2d69ba0319c258f11ab39e179ac17_548510_c2e0146a21a32cb3042be76446d93f7f.webp 760w,
               /talk/202004-mecha-mesh-through-to-the-end/images/multi-runtime-microservices-architecture_hu05f2d69ba0319c258f11ab39e179ac17_548510_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/images/multi-runtime-microservices-architecture_hu05f2d69ba0319c258f11ab39e179ac17_548510_1ceea0a086af2cbb35a8ce9f35eb2646.webp&#34;
               width=&#34;760&#34;
               height=&#34;377&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;思路大体是：&lt;strong&gt;Smart Runtime， Dumb Pipes&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;我对Mecha的理解是：业务逻辑在编码开始阶段应该是“裸奔”的，专注于业务逻辑的实现，而尽量不涉及到底层实现逻辑；而在运行时，则应该装备“机甲”，全副武装，大杀四方。熟悉的味道是吧？标准而地道的云原生思想。&lt;/p&gt;
&lt;h3 id=&#34;mecha的本质&#34;&gt;Mecha的本质&lt;/h3&gt;
&lt;p&gt;作者在原文中探讨了Mecha运行时的特性：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Mecha是通用的，高度可配置的，可重用的组件，提供分布式原语作为现成的能力。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mecha 可以与单个Micrologic组件一起部署(Sidecar模式)，也可以部署为多个共享(注：我称之为Node模式)。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mecha不对Micrologic运行时做任何假设。它与使用开放协议和格式（例如HTTP/gRPC，JSON，Protobuf，CloudEvents）的多语言微服务甚至单体一起使用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mecha以简单的文本格式（例如YAML，JSON）声明式地配置，指示要启用的功能以及如何将其绑定到Micrologic端点。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;与其依靠多个代理来实现不同的目的（例如网络代理，缓存代理，绑定代理），不如使用一个Mecha提供所有这些能力。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;下面是我对上述特性的个人理解：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Mecha提供的是&lt;strong&gt;能力&lt;/strong&gt;，以分布式原语体现的各种能力，而不局限于单纯的网络代理。&lt;/li&gt;
&lt;li&gt;Mecha的部署模型，不局限于Sidecar模式，Node模式在某些场景下（如Edge/IoT，Serverless FaaS）可能会是更好的方式。至少，Mecha下有机会按需选择，而不是绑死在Sidecar模式上&lt;/li&gt;
&lt;li&gt;Mecha和Micrologic之间的交互是开放而有API标准的，Mecha和Micrologic之间的“协议”体现在API上，而不是TCP通讯协议。这提供了一个契机：一个统一Micrologic和Mecha之间通讯方式的契机。&lt;/li&gt;
&lt;li&gt;Mecha可以以声明式的方式进行配置和控制，这非常符合云原生的理念，同样也使得API更关注于能力本身，而不是能力如何配置。&lt;/li&gt;
&lt;li&gt;应用需要的能力如此之多（参见上面的图：分布式应用的四大需求），如果每个能力都对应一个代理（不管是Node还是Sidecar），数量会非常夸张，带来的运维压力会很可怕。因此，如Mecha这个名字暗示的，运行时应该是整套的形式提供能力，而不是分散。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果用一句话来总结，那么我认为Mecha的本质应该是：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;“面向应用的分布式能力抽象层”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如Servicemesh的本质是服务间通讯的抽象层一样，Mecha的本质是应用需要的各种分布式能力和原语，包括但不限于服务间通讯。&lt;/p&gt;
&lt;p&gt;从这个角度上说，Mecha覆盖的范围是Servicemesh的超集：毕竟Servicemesh只覆盖到应用的部分需求（服务间通讯，还只限于同步/一对一/request-response模式），还有更多的分布式能力和原语有待覆盖。&lt;/p&gt;
&lt;p&gt;换一句话说，Mecha的目标应该是：&lt;strong&gt;“将Mesh进行到底！”&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&#34;mecha的优势和未来&#34;&gt;Mecha的优势和未来&lt;/h3&gt;
&lt;p&gt;作者指出：Mecha的好处是业务逻辑和越来越多的分布式系统问题之间的松耦合。&lt;/p&gt;
&lt;p&gt;下图是业务逻辑和分布式系统问题在不同架构中的耦合：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202004-mecha-mesh-through-to-the-end/images/coupling-in-different-architectures_hu05f2d69ba0319c258f11ab39e179ac17_281537_d553972bb68188bb2ed39f0d84f92393.webp 400w,
               /talk/202004-mecha-mesh-through-to-the-end/images/coupling-in-different-architectures_hu05f2d69ba0319c258f11ab39e179ac17_281537_4c2cec39881c2e75675d0f7db7fa5a0c.webp 760w,
               /talk/202004-mecha-mesh-through-to-the-end/images/coupling-in-different-architectures_hu05f2d69ba0319c258f11ab39e179ac17_281537_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/images/coupling-in-different-architectures_hu05f2d69ba0319c258f11ab39e179ac17_281537_d553972bb68188bb2ed39f0d84f92393.webp&#34;
               width=&#34;760&#34;
               height=&#34;304&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;其实思路和Servicemesh是一脉相承的，只是覆盖的分布式能力更广泛一些。&lt;/p&gt;
&lt;p&gt;有一个问题：Mecha会不会成为微服务架构的演进的下一个形态？我个人的答案：是，随着云原生的推进，分布式能力（以传统中间件为典型代表）下沉是大势所趋，Mesh化的范围必然会继续扩大，也就离Mecha的形态越来越近了。这也就是本文标题的立意所在，Mecha会是微服务乃至云原生的下一站。&lt;/p&gt;
&lt;h2 id=&#34;微软dapr&#34;&gt;微软Dapr&lt;/h2&gt;
&lt;p&gt;在介绍完 Mecha/Multiple Runtime 的理念之后，我们来看看目前微软新推出来的Dapr项目 —— 这应该是业界第一个Multiple Runtime的开源实践项目。&lt;/p&gt;
&lt;p&gt;项目地址：https://github.com/dapr/dapr。&lt;/p&gt;
&lt;h3 id=&#34;dapr介绍&#34;&gt;Dapr介绍&lt;/h3&gt;
&lt;p&gt;Dapr 是 Distributed Application Runtime （分布式应用运行时）的缩写，官方介绍说Dapr是“一种可移植的，事件驱动的运行时，用于构建跨云和边缘的分布式应用”。&lt;/p&gt;
&lt;p&gt;Dapr的详细介绍是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Dapr是一种可移植的，serverless的，事件驱动的运行时，它使开发人员可以轻松构建弹性，无状态和有状态微服务，这些服务运行在云和边缘上，并包含多种语言和开发框架。&lt;/p&gt;
&lt;p&gt;Dapr 整理了构建微服务应用为开放，独立的构建块的最佳实践，使您能够使用自己选择的语言和框架来构建可移植的应用程序。 每个构建块都是独立的，您可以在应用中使用其中的一个或多个。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dapr的功能和定位，下面这一张图就可以概括了：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202004-mecha-mesh-through-to-the-end/images/dapr-overview_hub0f40905bb31105b15316541e7839891_185368_a01f78cb9c24360d7c784225c9d31715.webp 400w,
               /talk/202004-mecha-mesh-through-to-the-end/images/dapr-overview_hub0f40905bb31105b15316541e7839891_185368_a8a8599e07826a806949009b4dd8016f.webp 760w,
               /talk/202004-mecha-mesh-through-to-the-end/images/dapr-overview_hub0f40905bb31105b15316541e7839891_185368_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/images/dapr-overview_hub0f40905bb31105b15316541e7839891_185368_a01f78cb9c24360d7c784225c9d31715.webp&#34;
               width=&#34;760&#34;
               height=&#34;358&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;最底下基础设施是各种云平台（主流公有云都支持）或者边缘环境&lt;/li&gt;
&lt;li&gt;其上是dapr提供的分布式能力，dapr称之为“building block”。&lt;/li&gt;
&lt;li&gt;这些building block的能力，以统一的API（支持HTTP和gRPC）对外提供服务&lt;/li&gt;
&lt;li&gt;应用可以用各种语言编写，然后通过dapr提供的API使用这些能力，dapr也提供客户端类库来简化对API的调用，实现了多语言的支持。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Dapr提供的具体分布式能力（building block）如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202004-mecha-mesh-through-to-the-end/images/dapr-building-block_hu792db24d2ffb61797e62677c4dcc3d6f_249632_97a5a37167df929b26920ac1afdacaa8.webp 400w,
               /talk/202004-mecha-mesh-through-to-the-end/images/dapr-building-block_hu792db24d2ffb61797e62677c4dcc3d6f_249632_9bde2e0a1a332fe5d8115b634d8d4c4c.webp 760w,
               /talk/202004-mecha-mesh-through-to-the-end/images/dapr-building-block_hu792db24d2ffb61797e62677c4dcc3d6f_249632_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/images/dapr-building-block_hu792db24d2ffb61797e62677c4dcc3d6f_249632_97a5a37167df929b26920ac1afdacaa8.webp&#34;
               width=&#34;760&#34;
               height=&#34;309&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;每个building block提供的具体能力请参加 Dapr 的官方文档：https://github.com/dapr/docs/tree/master/concepts。&lt;/p&gt;
&lt;h3 id=&#34;dapr的api例子&#34;&gt;Dapr的API例子&lt;/h3&gt;
&lt;p&gt;我们来看一下应用调用Darp API的例子，体验一下使用Dapr的方式。&lt;/p&gt;
&lt;p&gt;以 Service Invocation / 服务调用为例：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202004-mecha-mesh-through-to-the-end/images/service-invocation_hubb81548a6f7fe9e85b55171d8e544990_45511_0130fa3a851fcd43e8e2b3580cc76f55.webp 400w,
               /talk/202004-mecha-mesh-through-to-the-end/images/service-invocation_hubb81548a6f7fe9e85b55171d8e544990_45511_c374c6ec94e06c7aec4367b3dca2abfa.webp 760w,
               /talk/202004-mecha-mesh-through-to-the-end/images/service-invocation_hubb81548a6f7fe9e85b55171d8e544990_45511_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/images/service-invocation_hubb81548a6f7fe9e85b55171d8e544990_45511_0130fa3a851fcd43e8e2b3580cc76f55.webp&#34;
               width=&#34;760&#34;
               height=&#34;266&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;部署和调用方式与 Servicemesh/Istio 极为相似，但是，差别在于：Dapr是以提供API的方式提供API背后的能力，而不是提供提供协议代理的方式。&lt;/p&gt;
&lt;p&gt;上图中1，是ServiceA发起请求来调用一个远程服务。其HTTP request 如下所示：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-http&#34; data-lang=&#34;http&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;POST/GET/PUT/DELETE http://localhost:&amp;lt;daprPort&amp;gt;/v1.0/invoke/&amp;lt;appId&amp;gt;/method/&amp;lt;method-name&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;ul&gt;
&lt;li&gt;参数 daprPort 是Dapr Runtime启动的监听端口，用来接受应用的 outbound 请求&lt;/li&gt;
&lt;li&gt;参数 appId 是远程应用在darp中的关联id，每个注册到dapr的应用都有一个唯一的appId&lt;/li&gt;
&lt;li&gt;参数 method-name 是要调用的远程应用的方法名或者URL&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;负载可以存放在HTTP body中随请求发送，如 json。&lt;/p&gt;
&lt;p&gt;注意，虽然都是提供相同的功能，这里体现了Dapr（或者说背后的Mecha）和Servicemesh在方式上的差异：暴露API还是代理通讯协议。&lt;/p&gt;
&lt;p&gt;我们看一个更明显的例子，dapr提供的 “publish/subscriptions” 能力，让应用可以方便的发布消息，或者订阅主题并接收消息。下图是应用发布消息，请求直接发给dapr即可：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202004-mecha-mesh-through-to-the-end/images/publish_hu05f2d69ba0319c258f11ab39e179ac17_87094_f1c1478309321d19694dde68e987f329.webp 400w,
               /talk/202004-mecha-mesh-through-to-the-end/images/publish_hu05f2d69ba0319c258f11ab39e179ac17_87094_67f031e30ffa27b87ad37269927aba35.webp 760w,
               /talk/202004-mecha-mesh-through-to-the-end/images/publish_hu05f2d69ba0319c258f11ab39e179ac17_87094_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/images/publish_hu05f2d69ba0319c258f11ab39e179ac17_87094_f1c1478309321d19694dde68e987f329.webp&#34;
               width=&#34;760&#34;
               height=&#34;651&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;例子中，参数 topic 指定了消息要发往的主题（例子中是  deathStarStatus）。后续dapr会完成将消息入queue，然后推送到订阅了该topic的应用。接收消息的方式也类似，不过这次是darp主动发起：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202004-mecha-mesh-through-to-the-end/images/subscribe_hu05f2d69ba0319c258f11ab39e179ac17_92409_7df1d426a419293373f68c57b4f5e6ca.webp 400w,
               /talk/202004-mecha-mesh-through-to-the-end/images/subscribe_hu05f2d69ba0319c258f11ab39e179ac17_92409_935cb675e79636414d880740604eccb9.webp 760w,
               /talk/202004-mecha-mesh-through-to-the-end/images/subscribe_hu05f2d69ba0319c258f11ab39e179ac17_92409_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/images/subscribe_hu05f2d69ba0319c258f11ab39e179ac17_92409_7df1d426a419293373f68c57b4f5e6ca.webp&#34;
               width=&#34;760&#34;
               height=&#34;738&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;dapr首先会请求应用，咨询应用需要订阅那些主题（topic），如例子中应用返回的的TopicA / TopicB&lt;/li&gt;
&lt;li&gt;dapr实现主题订阅，在接收到消息之后，再把消息发送给应用，通过URL参数的不同来区分不同的主题&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;注意在这个调用期间，无论是收发消息，应用完全不用理会底层pub/sub的实现机制（比如是kafka，还是rocketmq，还是其他公有云提供的消息机制），也完全不用引入该实现机制的客户端SDK，只是简单的使用darp定义的API即可，从而实现了和底层的解耦，以及“厂商不绑定”。&lt;/p&gt;
&lt;p&gt;为了进一步简化调用的过程（毕竟发一个最简单的HTTP GET请求也要应用实现HTTP协议的调用/连接池管理等），dapr提供了各个语言的SDK，如 java / go / python / dotnet / js / cpp / rust 。另外同时提供HTTP客户端和gRPC客户端。&lt;/p&gt;
&lt;p&gt;我们以 Java 为例，java的 client API 接口定义如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;interface&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;DaprClient&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Mono&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Void&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;publishEvent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;topic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Object&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Mono&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Void&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;invokeService&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Verb&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;verb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;appId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;method&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Object&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;......&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&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;p&gt;&lt;a href=&#34;https://github.com/dapr/java-sdk/blob/master/sdk/src/main/java/io/dapr/client/DaprClient.java&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/dapr/java-sdk/blob/master/sdk/src/main/java/io/dapr/client/DaprClient.java&lt;/a&gt;&lt;/p&gt;
&lt;h2 id=&#34;分析和总结&#34;&gt;分析和总结&lt;/h2&gt;
&lt;p&gt;前面介绍了Multiple Runtime / Mecha 的架构思想，以及参考实现之一的微软Dapr项目。&lt;/p&gt;
&lt;p&gt;由于 Multiple Runtime / Mecha 这个思想非常的新，刚刚提出不久，而微软 Dapr 项目也是一个新出来的项目，不管是理论思想还是实践都处于非常早期的状态，也还没有形成完善的方法论。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;特别申明&lt;/strong&gt;：以下内容更多是我个人当下的理解和感悟，仅代表个人意见，肯定有很多不成熟甚至谬误的地方，欢迎指正和探讨。&lt;/p&gt;
&lt;h3 id=&#34;mecha和dapr的启示&#34;&gt;Mecha和Dapr的启示&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Mesh 模式应该推向更大的领域&lt;/p&gt;
&lt;p&gt;随着云原生的深入，应用需要的分布式能力应该全面下沉，而不仅仅局限于Servicemesh提供的服务间通讯能力；应用形态会朝纯业务逻辑这个目标更进一步，应用更加的云原生化。&lt;/p&gt;
&lt;p&gt;这是大势所趋，也是Mecha架构出现和发展的原动力。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Mecha强调是“提供能力”，而不是通讯代理&lt;/p&gt;
&lt;p&gt;Mecha的使用方式和Servicemesh有非常大的差异：Mecha强调的是提供分布式能力给应用使用，这些能力最终以封装完善的API的方式呈现。API体现的是应用对能力的“需求”和“意愿”，不涉及到如何实现，实现是Mecha的职责，采用什么样的实现也是由Mecha来控制。&lt;/p&gt;
&lt;p&gt;在Servicemesh下，不存在这个需求：Servicemesh提供的是服务间通讯能力，这个能力是由sidecar来提供，没有其他的更底层的实现，不存在隔离和替换的可能。受服务通讯协议和报文schema的限制，Servicemesh只能做请求的“转发”，能力聚焦在“如何转发”上，没有其他需要隔离和替代的能力。&lt;/p&gt;
&lt;p&gt;当Mecha把能力扩展到Servicemesh之外时，很多能力是由外部系统提供：比如 pub-sub 能力可以由不同的Message Queue实现；状态管理能力可以连接不同的Key-Value实现。此时能力的隔离性和可替代性就成为关键需求：解耦应用和能力实现，容许Mecha替换底层实现（进而实现供应商不锁定等）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不强求“零侵入”&lt;/p&gt;
&lt;p&gt;在Servicemesh中，“零侵入”是一个非常强调的特性，为此不惜引入 iptables 等流量劫持方案。“零侵入”在某些特殊场景下会发挥巨大的优势，如旧有应用不做改造的前提下接入servicemesh。好处自然不言而喻，但零侵入也有自身的限制：客户端必须能发出符合服务器端要求的网络通讯请求，这个过程外部无法插手。&lt;/p&gt;
&lt;p&gt;对于服务间通讯，这个不是大问题。但是对于其他能力，由于有和实现解耦的需求，再通过客户端自行发起原生协议的请求就不合适了。因此，Mecha中更倾向于采用低侵入的轻量级SDK方案，同样也可以实现跨语言和跨平台，只是需要付出实现各种语言SDK的代价。由于这个SDK足够轻量，因此代价还不算很高。&lt;/p&gt;
&lt;p&gt;而这些少量的工作量，少量的侵入，可以换取轻量级SDK能提供的各种便利和配合（简单理解：开后门），可以实现能力的抽象和API的封装。权衡利弊，Mecha下更倾向于轻量级SDK方案。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不限定 Sidecar 部署&lt;/p&gt;
&lt;p&gt;Sidecar部署模式，存在资源占用、维护成本增加等缺点，在某些情况下可能并不合适：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;边缘网络，IoT场景：资源非常有限，不适合启动太多Sidecar&lt;/li&gt;
&lt;li&gt;FaaS场景：应用自身足够轻量，甚至比Sidecar还要轻量&lt;/li&gt;
&lt;li&gt;Serverless场景：Scale to Zero时，对冷启动速度有严格要求，Sidecar的启动和初始化可能拖累应用启动速度&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mecha下，部署模式不限定于 Sidecar ，在合适时容许选择 Node 模式，甚至 Node 模式和 Sidecar 模式混合使用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;API和配置是关键&lt;/p&gt;
&lt;p&gt;API是分布式能力的抽象，需要要对（开发上层业务应用的）客户友好，简单好用，稳定不变。这些API 也需要标准化，被社区广泛接受和采纳，才能实现厂商不锁定和自由迁移，提升客户价值。&lt;/p&gt;
&lt;p&gt;另外，API还需要配合配置使用，在把能力抽象为API时，是不提供能力的细节控制的。这些控制将在运行时由Mecha根据配置实现，可以理解为：“API + 配置 = 完整的能力”。&lt;/p&gt;
&lt;p&gt;API和配置的制订以及标准化，预计将会是Mecha成败的关键。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;mecha的精髓&#34;&gt;Mecha的精髓&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;Program to an &lt;strong&gt;interface&lt;/strong&gt;, not an implementation.&lt;/p&gt;
&lt;p&gt;Design Patterns: Elements of Reusable Object-Oriented Software (GOF, 1994)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Mecha的精髓，要从上面这句名言开始：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在Mecha下，为了实现&lt;strong&gt;解耦&lt;/strong&gt;和&lt;strong&gt;可替换&lt;/strong&gt;， Runtime &lt;strong&gt;隔离&lt;/strong&gt;了底层实现，因此演变为：&amp;ldquo;Program to an &lt;strong&gt;Runtime&lt;/strong&gt;, not an implementation.&amp;rdquo;&amp;quot;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;考虑到 Runtime 不管是部署为Sidecar模式，还是部署为 Node 模式，都是Localhost，因此有： “Program to an &lt;strong&gt;Localhost&lt;/strong&gt;, not an implementation.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;为了简化开发，Mecha还是会提供轻量级SDK，提供API作为能力的&lt;strong&gt;抽象&lt;/strong&gt;：“Program to an &lt;strong&gt;API&lt;/strong&gt;, not an implementation.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;考虑到 API 通常是以 interface 的形式提供，因此绕了一圈，Mecha最后还是回到原点：“Program to an &lt;strong&gt;interface&lt;/strong&gt;, not an implementation.”&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;个人理解，Mecha的精髓就在于这几个关键点：隔离/抽象/解耦/可替换。如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202004-mecha-mesh-through-to-the-end/images/mecha-core_hu3b8e8d0b9f984bf252a3398b084f4528_48558_c6f04cee4e69782584d9bb0701789d97.webp 400w,
               /talk/202004-mecha-mesh-through-to-the-end/images/mecha-core_hu3b8e8d0b9f984bf252a3398b084f4528_48558_2be55736de85d4c9fdaf4c225df3c7d7.webp 760w,
               /talk/202004-mecha-mesh-through-to-the-end/images/mecha-core_hu3b8e8d0b9f984bf252a3398b084f4528_48558_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/images/mecha-core_hu3b8e8d0b9f984bf252a3398b084f4528_48558_c6f04cee4e69782584d9bb0701789d97.webp&#34;
               width=&#34;677&#34;
               height=&#34;679&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在Mecha下，MicroLogic（也就是业务逻辑的代码实现）不容许直接使用底层实现提供的分布式能力&lt;/li&gt;
&lt;li&gt;Mecha Runtime将为Micro Logic提供分布式能力，同时隔离应用和底层实现&lt;/li&gt;
&lt;li&gt;为了方便使用，提供轻量级SDK，其中的API层实现了分布式能力的抽象，应用只需面向API编程&lt;/li&gt;
&lt;li&gt;轻量级SDK和Mecah Runtime配合，完成对底层实现的解耦和可替换。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;mecha的实现原则&#34;&gt;Mecha的实现原则&lt;/h3&gt;
&lt;p&gt;在Mecha的实现上，我理解的原则是这样：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Runtime 是主力，要做厚&lt;/li&gt;
&lt;li&gt;轻量级SDK 主要是给 Runtime 打配合，要做薄&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/202004-mecha-mesh-through-to-the-end/images/mecha-implementation_huf4410f65aa2156ce431f56d2d65f6101_79027_4d7db7c78cc9ed9a2fe0c32c5550833b.webp 400w,
               /talk/202004-mecha-mesh-through-to-the-end/images/mecha-implementation_huf4410f65aa2156ce431f56d2d65f6101_79027_efdf6cb25abc88e3367ffeb88cb3a540.webp 760w,
               /talk/202004-mecha-mesh-through-to-the-end/images/mecha-implementation_huf4410f65aa2156ce431f56d2d65f6101_79027_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/202004-mecha-mesh-through-to-the-end/images/mecha-implementation_huf4410f65aa2156ce431f56d2d65f6101_79027_4d7db7c78cc9ed9a2fe0c32c5550833b.webp&#34;
               width=&#34;760&#34;
               height=&#34;223&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;具体的职责划分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;轻量级SDK：实现多语言接入，低侵入（但不追求零侵入）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;API 接口：由轻量级SDK中提供统一，目标社区化+标准化，给开发者提供一致的编程体验，同时提供可移植性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;应用：轻量级SDK/Runtime配合，提供各种分布式能力，应用无感，只需简单使用API，不耦合底层实现&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在Mecha架构中，Runtime 自然是整个架构的核心，扮演类似Servicemesh中数据平面的角色&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;所有分布式能力使用的过程（包括访问内部生态体系和访问外部系统）都被 Runtime 接管和屏蔽实现&lt;/li&gt;
&lt;li&gt;通过CRD/控制平面实现声明式配置和管理（类似Servicemesh）&lt;/li&gt;
&lt;li&gt;部署方式上 Runtime 可以部署为Sidecar模式，或者Node模式，取决于具体需求，不强制&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：Mecha有非常多的能力，实现上也有非常多的细节，这里先做一个High Level的概述。细节后面会有一系列文章一一覆盖，欢迎多交流讨论。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;mecha总结&#34;&gt;Mecha总结&lt;/h2&gt;
&lt;p&gt;大概是在3月初，当时我第一次阅读 “Multi-Runtime Microservices Architecture” 这篇文章，有一种豁然开朗的感觉，尤其是有很多之前在反复考虑和权衡但是下不了结论的问题，在这个文章中得到了清晰的解答。可谓受益匪浅。&lt;/p&gt;
&lt;p&gt;在Servicemesh探索和实践的这三年中，遇到很多问题，有很多之前没有想到过的问题浮现。比如，以前一直觉得Servicemesh中引入Sidecar带来的最大麻烦会是性能，但实际上，从目前的实践看，Sidecar引入后带来的维护代价才是更令人头疼的事情，相比之下Sidecar引入带来的性能损失显得无伤大雅。&lt;/p&gt;
&lt;p&gt;总结一下我个人对 Mecha 架构的核心理解，主要是两点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Mecha是云原生化和Mesh化的必然趋势：云原生在继续发展，应用需要的分布式能力需要继续下沉，越来越多的能力会以sidecar的形式出现，这是大势所趋。但不可能出现一个应用部署十几个sidecar的局面，这会是运维地狱。因此，必然需要出现新的形态来解决Sidecar过多的问题，合并为一个或者多个Sidecar就会成为必然。&lt;/li&gt;
&lt;li&gt;Mecha是Servicemesh模式的自然进化版本：Servicemesh落地实践三年了，效果一直并不理想，到了该反思反省的时候了；而且Mecha的范围也远不止服务间通讯，新的需求下应该有新的思考和突破。Servicemesh现有的固定模式，在Mecha下可以尝试打破以探索新的方式：不必拘泥于Sidecar，试试Node模式；不必拘泥于通讯协议转发，试试Runtime提供能力解耦底层实现；不必拘泥于零侵入，试试在应用中保留一个足够轻的轻量级SDK。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;正如曾有说法，说“微服务是SOA实践中正确的部分（the Good Part）”，我希望在 Mecha 的探索和实践中，能够从Servicemesh的实践中吸取成功的经验和失败的教训，希望 Mecha 也能成为Servicemesh的Good Part。希望在云原生的演进路线中，Mecha 可以继微服务和Servicemesh之后，成为云原生落地实践的下一站。&lt;/p&gt;
&lt;p&gt;回到现实，目前 Mecha 和 Multi-Runtime 还是一个非常新的想法，Dapr 项目也才刚刚起步，Mecha 要探索的道路还很漫长，一切都还需要摸索着前进。&lt;/p&gt;
&lt;h2 id=&#34;附录参考资料&#34;&gt;附录：参考资料&lt;/h2&gt;
&lt;p&gt;在文章的最后，特别鸣谢 “Multi-Runtime Microservices Architecture”一文的作者 “&lt;strong&gt;Bilgin Ibryam&lt;/strong&gt;”，我非常认可这篇文章中的思想和理念，分析归纳的非常到位，提炼和升华的能力令人佩服。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;作者介绍：&lt;/p&gt;
&lt;p&gt;![](images/Bilgin Ibryam.png)&lt;/p&gt;
&lt;p&gt;Red Hat的首席架构师，Apache Software Foundation 的 committer 和成员。开源的布道师，博客作者，偶尔演讲，著有书籍 Kubernetes Patterns 和 Camel Design Patterns 。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本文参考了 Bilgin Ibryam 出品的如下内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.infoq.com/articles/multi-runtime-microservice-architecture/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Multi-Runtime Microservices Architecture&lt;/a&gt;，作者 &lt;a href=&#34;http://ofbizian.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Bilgin Ibryam&lt;/a&gt;，Mecha的思想来自这篇文章，强烈推荐阅读。也可以直接看我翻译的版本 &lt;a href=&#34;https://skyao.net/post/202003-multi-runtime-microservice-architecture/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;多运行时微服务架构&lt;/a&gt;。如前所述，建议在阅读本文之前先阅读这篇博客文章。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://qconlondon.com/london2020/presentation/evolution-distributed-systems-kubernetes&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The Evolution of Distributed Systems on Kubernetes&lt;/a&gt; : 作者 Bilgin Ibryam, 2020年3月在 QCon London的演讲，依然强烈推荐。内容非常精彩，对 Kubernetes 上分布式系统演进做了很好的总结和展望，当然也依然在布道多运行时微服务架构的理念。本文的很多图片 &lt;a href=&#34;https://qconlondon.com/system/files/presentation-slides/bilgin_-_evolution_of_distributed_systems_on_kubernetes.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;援引自这份PPT&lt;/a&gt;。&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>[译] 反应式事件驱动系统及推荐实践</title>
      <link>https://skyao.net/post/202004-reactive-event-driven-systems-and-recommended-practices/</link>
      <pubDate>Wed, 08 Apr 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202004-reactive-event-driven-systems-and-recommended-practices/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://medium.com/google-cloud/reactive-event-driven-systems-and-recommended-practices-785a1ab7e509&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Reactive Event-Driven Systems and Recommended Practices&lt;/a&gt;，作者 &lt;a href=&#34;https://medium.com/@ratrosy&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Ratros Y.&lt;/a&gt;，文章发表于2019年9月。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;本文讨论如何构建反应式事件驱动系统及其推荐实践，这是 &lt;a href=&#34;../202004-building-event-driven-cloud-applications-and-services/&#34;&gt;《构建事件驱动的云应用和服务》&lt;/a&gt; 系列教程的第三篇。&lt;/p&gt;
&lt;h2 id=&#34;介绍&#34;&gt;介绍&lt;/h2&gt;
&lt;p&gt;正如开篇讨论的那样，在一个反应式事件驱动的系统中，发布者发出事件来调用（触发）订阅者的操作；这种模式中的事件实际上与内部函数调用、HTTP请求或RPC调用没有什么区别，从技术上讲，你可以将这种模式改造任何工作流，包括单体和基于HTTP RESTful/RPC的微服务系统。常见的用例包括支付处理、预订/保留，以及任何长期运行的操作（如视频转码）。&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;/ul&gt;
&lt;p&gt;但缺点是追踪事件流程变得越来越难。另外，在没有执行路径的情况下，无法保证发布者收到回复，要想得到反馈，可能还得自己去做查询。&lt;/p&gt;
&lt;p&gt;在本教程中，您将使用 Stripe 和 Google Cloud Functions 构建一个简单的支付处理工作流，客户通过 Stripe 使用信用卡支付，您的服务完成订单并发送确认邮件。请注意，这个工作流和许多使用反应式模式构建的工作流一样，都是事务性的；更确切地说，这个工作流中的所有步骤要么全部成功，要么全部失败，而且是在每一种情况下，包括错误、崩溃和平台不可用（如Google Cloud Functions脱机）。&lt;/p&gt;
&lt;p&gt;该演示项目使用 Cloud Pub/Sub 来进行消息队列/流。Cloud Pub/Sub 是一个托管的解决方案，发布者和用户通过 Cloud Pub/Sub 主题（topic）处理消息（事件）。&lt;/p&gt;
&lt;h2 id=&#34;架构概述&#34;&gt;架构概述&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-reactive-event-driven-systems-and-recommended-practices/images/architectural-overview_hufe8c1de579b477ed8fa92694cf044dba_151475_6e2b98b8480ba05a2f36eb7503c37727.webp 400w,
               /post/202004-reactive-event-driven-systems-and-recommended-practices/images/architectural-overview_hufe8c1de579b477ed8fa92694cf044dba_151475_d25c2ce56007411029d05ce498b33d74.webp 760w,
               /post/202004-reactive-event-driven-systems-and-recommended-practices/images/architectural-overview_hufe8c1de579b477ed8fa92694cf044dba_151475_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-reactive-event-driven-systems-and-recommended-practices/images/architectural-overview_hufe8c1de579b477ed8fa92694cf044dba_151475_6e2b98b8480ba05a2f36eb7503c37727.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;工作流程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;客户通过APP进行消费。&lt;/li&gt;
&lt;li&gt;Stripe 向客户的信用卡收费，并发送一个 webhook 事件给 Cloud Function &lt;code&gt;fulfillment&lt;/code&gt;（如果收费成功）或 &lt;code&gt;cancellation&lt;/code&gt;（如果收费失败）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fulfillment&lt;/code&gt; 履行完成订单，并向 Cloud Pub/Sub 发布 &lt;code&gt;orderProcessed&lt;/code&gt; 事件。&lt;code&gt;cancellation&lt;/code&gt; 拒绝订单，也向 Cloud Pub/Sub 发布 &lt;code&gt;orderProcessed&lt;/code&gt; 事件。如果 &lt;code&gt;fulfillment&lt;/code&gt; 或 &lt;code&gt;cancellation&lt;/code&gt; 无法处理订单，Stripe 发送的 webhook 事件将保存在 DLQs 中，以便进一步检查。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;email&lt;/code&gt; 接收到 &lt;code&gt;orderProcessed&lt;/code&gt; 事件，并发送确认邮件。如果 &lt;code&gt;email&lt;/code&gt; 无法发送邮件，那么 &lt;code&gt;orderProcessed&lt;/code&gt;  事件将被保存在DLQ中，以便进一步检查。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;stats&lt;/code&gt; 也会接收到这个事件，并将订单的ID写到 BigQuery 中以备参考。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;搭建&#34;&gt;搭建&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;译者注：实操细节请参考英文原文。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你喜欢在本地运行，请按照下面的步骤进行操作。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;设置好你的Python开发环境。安装Python 3.&lt;/li&gt;
&lt;li&gt;安装 Google Cloud SDK。&lt;/li&gt;
&lt;li&gt;按照 gcp_tutorial.md 继续进行。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;了解代码&#34;&gt;了解代码&lt;/h3&gt;
&lt;h3 id=&#34;事件&#34;&gt;事件&lt;/h3&gt;
&lt;p&gt;这个工作流所涉及的事件在 events.yaml 中定义。该演示项目使用 CloudEvents Generator准备的事件库来写入和读取事件。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;至少有一次交付，和正好是一次交付&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;At least once delivery, and exactly once delivery&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在单体系统中，内部函数调用始终是同步的；如果进行一次函数调用，它将被调用一次，而且是精确的一次。不幸的是，在反应式事件驱动系统中，情况并非如此：大多数消息队列/流式解决方案，如 Cloud Pub/Sub 和 Apache Kafka（0.11之前），都只能保证至少一次交付，也就是说，所有的事件最终都会被交付，尽管订阅者可能会看到少量的事件两次或更多次。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;p&gt;即使你的消息队列/流解决方案承诺了精确的一次性交付，你也应该非常谨慎。这些承诺通常有一个前提条件：对于Kafka来说，精确的一次性处理是一个端到端的保证，你的应用程序必须设计成不违反该属性；另一方面，Google Cloud Tasks则偏向于在必要时保证执行，而不是精确的一次性执行，这意味着它对99.999%的任务承诺精确的一次性交付，但不是全部。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果你的订阅者不是幂等的话，至少一次交货会在你期待偏少的时候引起问题。以本教程的演示项目为例，一个订单不应该被执行两次。因此，强烈建议你通过事务将传入的事件（或者至少是它们的ID）通过数据库持久化，并使用这些记录拒绝任何重复的事件。此外，您应该为您的事件设置一个TTL(time to live)值(例如10分钟)，这样您就不需要永远持久化所有的事件；任何不在数据库中但陈旧的事件也应该被拒绝。&lt;/p&gt;
&lt;p&gt;这个演示使用Cloud Firestore，一个托管的NoSQL数据库解决方案来保存事件。它首先检查事件的过期日期，然后使用事务以确保该事件之前从未被处理过。通过云函数开始时的事务把关，即使在执行过程中，例如部署时崩溃，每个事件也只会被处理一次。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fulfill&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;res&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Rejects stale events.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;utils&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;checkForExpiredEvents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;POSIX&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;paymentIntent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;created&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;EVENT_MAX_AGE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Checks if the event is duplicated.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;utils&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;guaranteeExactlyOnceDelivery&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;firestoreClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;EVENT_COLLECTION&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;paymentIntent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;JSON&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;stringify&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;paymentIntent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Checks if an event has expired.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;exports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;checkForExpiredEvents&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;eventTimestamp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;maxAge&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;age&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;RFC3339&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;age&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;Date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;Date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;parse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;eventTimestamp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;POSIX&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;age&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;Date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;eventTimestamp&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;Error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;INVALID_TIMESTAMP&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;age&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;maxAge&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;Error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;EXPIRED_EVENT&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Checks if an event is duplicated.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;exports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;guaranteeExactlyOnceDelivery&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;firestoreClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;collection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;eventId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ref&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;firestoreClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;collection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;collection&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;doc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;eventId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;firestoreClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;runTransaction&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;t&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;doc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ref&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;doc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;exists&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;set&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ref&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;context&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;throw&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;Error&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;DUPLICATE_EVENT&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&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;h3 id=&#34;可观测性&#34;&gt;可观测性&lt;/h3&gt;
&lt;p&gt;正如前面所解释的，反应式事件驱动系统最突出的一个缺点是，你不能像在单体系统中的try-catch块（或其等价物）那样观察系统中的事件（命令）流。比如说，如果事件流突然停止（可能是由于代码中的bug），你将无法在事件流的上游（事件流的开始）或下游（事件流的结束）捕捉到它；为了排除故障，你必须逐一检查每一个发布者和订阅者。&lt;/p&gt;
&lt;p&gt;幸运的是，有一些工具可以提供帮助。&lt;strong&gt;分布式日志&lt;/strong&gt;、&lt;strong&gt;集中式监控&lt;/strong&gt;和&lt;strong&gt;分布式跟踪&lt;/strong&gt;是反应式事件驱动系统（以及几乎所有分布式系统）中可观察性的三大支柱。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;分布式日志&lt;/strong&gt; 有助于将所有逻辑上连接的组件的日志关联起来（例如在同一事件流中）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;集中式监控&lt;/strong&gt; 有助于收集来自所有逻辑上连接的组件的指标。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分布式跟踪&lt;/strong&gt; 有助于跟踪每个步骤在流中所花费的时间，从而衡量其性能。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面的两个例子，分别展示了如何使用 Stackdriver Logging、Stackdriver Monitoring 和OpenCensus 进行分布式日志和跟踪，前者使用订单的ID来分组日志，后者使用唯一的ID来分组同一跟踪下的span。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Logging&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;@google-cloud/logging&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;logging&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Logging&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// const logName = &amp;#39;customLog&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// const resourceType = &amp;#39;cloud_function&amp;#39;;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// const labels = {
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//    &amp;#39;source&amp;#39;: &amp;#39;fulfillment&amp;#39;,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//    &amp;#39;orderId&amp;#39;: &amp;#39;myOrderId&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// };
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;distributedLog&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;logName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;resourceType&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;customLabels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;logging&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;logName&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;metadata&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;labels&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;customLabels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;resource&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;resourceType&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;entry&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;write&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;entry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以在 Stackdriver 日志查看器中用过滤器 label.orderId=myOrderId 查询，以跟踪处理该特定订单时产生的所有日志。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;tracing&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;@opencensus/nodejs&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;StackdriverTraceExporter&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;@opencensus/exporter-stackdriver&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;exporter&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;StackdriverTraceExporter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;projectId&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;YOUR-GCP-PROJECT&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;tracer&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;tracing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;registerExporter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;exporter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;start&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;samplingRate&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tracer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;A&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;traceId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;tracer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;startRootSpan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;A&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;rootSpan&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;doSomeWorkInA&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;traceId&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;rootSpan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;traceId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;rootSpan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Pass traceId to another function
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;B&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;kd&#34;&gt;let&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;traceId&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;The trace ID passed from A&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;tracer&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;startRootSpan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;B&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;traceId&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;traceId&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;rootSpan&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;doSomeWorkInB&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;rootSpan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Keep passing the traceId if needed
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当在 Stackdriver Trace Viewer 中查看跟踪时，即使两个span在两个不同的实例中运行，也会被关联到同一个跟踪。您可以用诸如 orderId 来注释跟踪，以备参考。&lt;/p&gt;
&lt;h3 id=&#34;dlqs-让它崩溃&#34;&gt;DLQs (✨让它崩溃！)&lt;/h3&gt;
&lt;p&gt;一般来说，在单体或基于HTTP RESTful/RPC的微服务系统中，开发人员必须一丝不苟地检查每一个可能的输入，并尽力从异常中恢复。这部分原因是由于函数调用（或HTTP请求/RPC调用）从核心上说同步的；如果一个异常没有被捕获（和恢复），那么调用本身就会永远消失&amp;ndash;没有简单的恢复方法。&lt;/p&gt;
&lt;p&gt;而反应式事件驱动系统中的事件则是不可变的，可以很容易恢复，这要归功于作为中介的消息队列/流解决方案。尽管你可能觉得奇怪，但建议在反应式事件驱动系统中采取 &amp;ldquo;让它崩溃 &amp;ldquo;的不良态度，专注于订阅者中的幸福路径，简单地拒绝任何你无法处理的事件到DLQ（死信队列）中。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;重要&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;显然，这种态度并不适用于对业务逻辑至关重要的异常，这些异常仍然需要尽快捕获并处理。比如说在这个演示项目中，当一个订单因为bug而无法执行时，你仍然需要在代码中尽快修复它。或者，你可以拒绝所有的死事件到DLQ，并设置专门的worker来处理特定类型的错误。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;死信队列（Dead letter queues），顾名思义，就是死信事件的消息队列。它允许开发人员&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;检查潜在的问题和BUG&lt;/li&gt;
&lt;li&gt;检测和分析问题的模式&lt;/li&gt;
&lt;li&gt;配置专职工作人员处理错误&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;DLQ的好处在于它能准确地捕捉到事件生产者发送的事件，让你有机会获得第二次机会来轻松地修正问题。例如，如果由于某种原因，传递给 fulfillment 的订单ID暂时损坏，而你很快就找到了修复它们的方法，你可以从DLQ中找回所有被拒绝的事件，并要求 fulfillment 再次处理它们。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注&lt;/p&gt;
&lt;p&gt;Cloud Pub/Sub，与一些消息队列/流的选项不同，它没有内置DLQ支持。因此，我们在这里设置了一个单独的主题作为DQL；在你的生产系统中，你可能会有拒绝事件的选项，而不需要在代码中进行额外的设置。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// A wrapper for rejecting dead-lettered events.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;exports&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;functions&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;https&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;onRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kr&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;res&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;try&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fulfill&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;res&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;catch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;console&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;log&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Stripe webhook events are delivered via HTTP. Here it is wrapped in
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// a Cloud Event and rejected to DLQ via Cloud Pub/Sub.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;kr&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;stripeWebhookEventRejected&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;utils&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;createStripeWebhookEventRejectedEvent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SOURCE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;headers&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;err&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kr&#34;&gt;await&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;utils&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;publishEvent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pubSubClient&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;DLQ&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;stripeWebhookEventRejected&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;res&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;400&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;Promise&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;resolve&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;async&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;function&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;fulfill&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;req&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;res&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;流程控制&#34;&gt;流程控制&lt;/h3&gt;
&lt;p&gt;你可以在任何时候暂停，然后重新启动一部分事件流。您的消息队列/流解决方案应该能够在这段时间内（在Cloud Pub/Sub的情况下是7天）暂停事件，这样就可以在离开的地方恢复。要在演示项目中做到这一点，请在Cloud Console中删除与您希望暂停的云功能相关联的订阅。您可以在以后准备好后再重新创建一个。&lt;/p&gt;
&lt;p&gt;默认情况下，Cloud Pub/Sub 会根据您的 Cloud 函数的事件消费速率自动控制流速。Cloud Functions 会自动伸缩；如果您想限制 Cloud Function 实例的最大数量，从而调节流量速度，请调整 Cloud Functions 的可伸缩性设置。其他消息队列/流解决方案和计算平台可能也有类似的设置。&lt;/p&gt;
&lt;h3 id=&#34;构建测试部署&#34;&gt;构建、测试、部署&lt;/h3&gt;
&lt;p&gt;Cloud Pub/Sub 和其他一些消息队列/流解决方案具有快照功能，允许您重放事件序列。当您在为您的反应式事件驱动系统的更新代码时，这将是非常有用的：只需要求 Cloud Pub/Sub 将相同的事件序列在另一个时间段传递给新代码，您就可以有一个可以用于比较的基础。&lt;/p&gt;
&lt;p&gt;另外，正如本系列教程的开篇所介绍的那样，在反应式事件驱动系统中，只要有消息队列/流解决方案的存在，你就可以随时添加/删除订阅者。这就实现了镜像模式，在这里你可以设置一个新版本的订阅者与旧版本的订阅者并排工作，以尝试一下新的功能。例如，这个演示项目增加了一个统计云函数，可以与email 并排工作，将订单状态保存到BigQuery。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译] 事件驱动微服务架构</title>
      <link>https://skyao.net/post/202004-event-driven-microservice-architecture/</link>
      <pubDate>Wed, 08 Apr 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202004-event-driven-microservice-architecture/</guid>
      <description>&lt;p&gt;英文原文来自: &lt;a href=&#34;https://medium.com/trendyol-tech/event-driven-microservice-architecture-91f80ceaa21e&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Event-Driven Microservice Architecture&lt;/a&gt; ，作者 &lt;a href=&#34;https://medium.com/@bahadirtasdemir&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Bahadir Tasdemir&lt;/a&gt;，文章发表时间为 2019年11月。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-event-driven-microservice-architecture/images/event-driven-microservice-architecture_hud4e68d0d0d51121c943f5b1bacc61187_11643_f6664816c6e751d3b3aa7ca6308d0e8a.webp 400w,
               /post/202004-event-driven-microservice-architecture/images/event-driven-microservice-architecture_hud4e68d0d0d51121c943f5b1bacc61187_11643_3d0ccdb2a760fca74ea25ce7c68b5363.webp 760w,
               /post/202004-event-driven-microservice-architecture/images/event-driven-microservice-architecture_hud4e68d0d0d51121c943f5b1bacc61187_11643_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-event-driven-microservice-architecture/images/event-driven-microservice-architecture_hud4e68d0d0d51121c943f5b1bacc61187_11643_f6664816c6e751d3b3aa7ca6308d0e8a.webp&#34;
               width=&#34;359&#34;
               height=&#34;297&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;首先，在事件驱动的微服务架构中，服务之间通过事件消息进行通信。当业务事件发生时，生产者用消息发布事件。同时，其他服务通过事件监听器来消费它们。&lt;/p&gt;
&lt;p&gt;因此，事件驱动系统的主要优点是异步行为和松耦合结构。例如，在需要的时候，App不是在需要请求数据，而是在需要之前通过事件来消费它们。因此，APP的整体性能提高了。另一方面，保持松散的耦合是微服务环境的关键点之一。&lt;/p&gt;
&lt;h2 id=&#34;作为一种解决方案的事件驱动架构&#34;&gt;作为一种解决方案的事件驱动架构&lt;/h2&gt;
&lt;p&gt;除了可以用事件驱动的架构来构建系统之外，还可以把它作为一种解决方案来应用到已经构建的高耦合环境中。让我们来讨论一下如何应用事件驱动方法作为解决方案。&lt;/p&gt;
&lt;h3 id=&#34;基本的rest驱动方式&#34;&gt;基本的REST驱动方式&lt;/h3&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-event-driven-microservice-architecture/images/rest-api-call_hu45492cc45869bcafbb2a0a5a4900953d_2272_310220a67a429fb6a2208a128295d30d.webp 400w,
               /post/202004-event-driven-microservice-architecture/images/rest-api-call_hu45492cc45869bcafbb2a0a5a4900953d_2272_dc45179d2d3880c9ab43ee036bf005c2.webp 760w,
               /post/202004-event-driven-microservice-architecture/images/rest-api-call_hu45492cc45869bcafbb2a0a5a4900953d_2272_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-event-driven-microservice-architecture/images/rest-api-call_hu45492cc45869bcafbb2a0a5a4900953d_2272_310220a67a429fb6a2208a128295d30d.webp&#34;
               width=&#34;381&#34;
               height=&#34;61&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;虽然应用可以正常工作，但存在缺点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;模块1等待响应&lt;/li&gt;
&lt;li&gt;模块2可以down机&lt;/li&gt;
&lt;li&gt;网络延迟降低性能&lt;/li&gt;
&lt;li&gt;如果数据很大，就会分页。这意味着更多的REST调用&lt;/li&gt;
&lt;li&gt;模块2可能在重载的情况下进行，导致反应很晚。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;当系统因为同步连接而变得效率低下时，可以应用事件驱动的解决方案。&lt;/p&gt;
&lt;h3 id=&#34;真实场景我们的团队是如何应用的&#34;&gt;真实场景：我们的团队是如何应用的&lt;/h3&gt;
&lt;p&gt;在 Trendyol/Marketplace 团队中，我们有一个报告应用（GIB API）。它将所有的销售报告传输给政府。所以，这个应用必须从另一个API中获取所有的销售数据。刚开始的时候，交易量很低。因此，我们用REST的方式快速构建了这个API。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-event-driven-microservice-architecture/images/Report-Generation-Timing-Diagram_huc99ff01808124f0b929541d8bbf39691_20986_130dbf2769f2d0c3bf21aa733b62a38f.webp 400w,
               /post/202004-event-driven-microservice-architecture/images/Report-Generation-Timing-Diagram_huc99ff01808124f0b929541d8bbf39691_20986_7fa74c74e838813910b5cc1c33b9f72d.webp 760w,
               /post/202004-event-driven-microservice-architecture/images/Report-Generation-Timing-Diagram_huc99ff01808124f0b929541d8bbf39691_20986_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-event-driven-microservice-architecture/images/Report-Generation-Timing-Diagram_huc99ff01808124f0b929541d8bbf39691_20986_130dbf2769f2d0c3bf21aa733b62a38f.webp&#34;
               width=&#34;760&#34;
               height=&#34;174&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

报告生成时序图&lt;/p&gt;
&lt;p&gt;虽然一开始数据量不多，但突然间就增加了起来。因为 Trendyol 是一家快速发展的公司，所以我们经常会遇到这样的问题。另一方面，解决的方法很简单，就是转化成事件消息。&lt;/p&gt;
&lt;h2 id=&#34;解决方案1转换为事件消息&#34;&gt;解决方案1：转换为事件消息&lt;/h2&gt;
&lt;p&gt;当我们意识到报表生成效率不高时，我们采用了事件驱动的解决方案。&lt;/p&gt;
&lt;p&gt;最重要的是，我们的方案很简单：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;当创建了一个交易项目时，发布一个事件&lt;/li&gt;
&lt;li&gt;接收到事件时，获取相关数据&lt;/li&gt;
&lt;li&gt;转换为一段报告字符串&lt;/li&gt;
&lt;li&gt;在 RDBMS (PostgreSQL) 中持久化&lt;/li&gt;
&lt;li&gt;生成报告时查询数据&lt;/li&gt;
&lt;li&gt;将字符串数据合并并以文件形式保存到磁盘上&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;![](images/Gathering-DATA via-Async-Event-Messaging.png)&lt;/p&gt;
&lt;p&gt;因此，所需的事务项被持久化到报表API中。一旦开始创建报表，它就会从RDBMS中查询并聚合报表数据。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-event-driven-microservice-architecture/images/Generate-Transaction-Report_huf3d6731a881d178b2e120384e506421a_14538_0684d9dbcdc1b2ce0a7c9e7a72e7c17c.webp 400w,
               /post/202004-event-driven-microservice-architecture/images/Generate-Transaction-Report_huf3d6731a881d178b2e120384e506421a_14538_00737b37a23f07af8c87ef9600f74c40.webp 760w,
               /post/202004-event-driven-microservice-architecture/images/Generate-Transaction-Report_huf3d6731a881d178b2e120384e506421a_14538_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-event-driven-microservice-architecture/images/Generate-Transaction-Report_huf3d6731a881d178b2e120384e506421a_14538_0684d9dbcdc1b2ce0a7c9e7a72e7c17c.webp&#34;
               width=&#34;401&#34;
               height=&#34;278&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;成功来之不易&#34;&gt;成功来之不易&lt;/h3&gt;
&lt;p&gt;当我们将同步过程转换为异步架构时，事务API面临着另一个性能问题。因为报表（GIB）API在每次创建交易项目时都会请求详细的数据，所以交易API的负载很重。原因是，Trendyol中的每一个交易记录都是为每一个交易项目创建的。所以，大量的交易项目详情请求让API感到非常的吃力。&lt;/p&gt;
&lt;h2 id=&#34;解决方案2富事件&#34;&gt;解决方案2：富事件&lt;/h2&gt;
&lt;p&gt;解释一下，富事件意味着消息除了实体标识符之外还包含详情。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-event-driven-microservice-architecture/images/Fat-Event-Message-Sample_huca9c3bdbd48cbe522c332da96edb3c70_5007_54350fedee17598b090d776f65602dec.webp 400w,
               /post/202004-event-driven-microservice-architecture/images/Fat-Event-Message-Sample_huca9c3bdbd48cbe522c332da96edb3c70_5007_695a331e19530aa8559a44269907a37c.webp 760w,
               /post/202004-event-driven-microservice-architecture/images/Fat-Event-Message-Sample_huca9c3bdbd48cbe522c332da96edb3c70_5007_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-event-driven-microservice-architecture/images/Fat-Event-Message-Sample_huca9c3bdbd48cbe522c332da96edb3c70_5007_54350fedee17598b090d776f65602dec.webp&#34;
               width=&#34;304&#34;
               height=&#34;120&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在将消息转换为富事件后，我们不需要任何额外的REST调用。因此，我们的架构成为了一个完整的异步事件驱动系统。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-event-driven-microservice-architecture/images/Complete-Even-Driven-Architecture_hu1e85420ed7e277b49ce34597d83e1f19_10949_57022a04bec7f6037040d6872badc5ad.webp 400w,
               /post/202004-event-driven-microservice-architecture/images/Complete-Even-Driven-Architecture_hu1e85420ed7e277b49ce34597d83e1f19_10949_d9bdab8f139571181af36ce2b9591a77.webp 760w,
               /post/202004-event-driven-microservice-architecture/images/Complete-Even-Driven-Architecture_hu1e85420ed7e277b49ce34597d83e1f19_10949_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-event-driven-microservice-architecture/images/Complete-Even-Driven-Architecture_hu1e85420ed7e277b49ce34597d83e1f19_10949_57022a04bec7f6037040d6872badc5ad.webp&#34;
               width=&#34;630&#34;
               height=&#34;276&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;解决方案3outbox模式&#34;&gt;解决方案3：outbox模式&lt;/h2&gt;
&lt;p&gt;当我们在谈论销售交易的时候，已经可以看出这些数据是多么的重要。因为它们关系到金融业务。因此，计算的正确率必须是100%。&lt;/p&gt;
&lt;p&gt;为了能够获得这种准确性，我们必须确保我们的系统不会丢失任何事件消息。基于此，我们应用了outbox模式。&lt;/p&gt;
&lt;p&gt;什么是outbox模式？很简单，当你的API发布事件消息时，它不会直接发送事件消息。相反，这些消息会被持久化地保存在DB表中。有一个作业会按照预定义的时间间隔发送累积消息。&lt;/p&gt;
&lt;p&gt;解释图中的内容：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;业务模块发布事件&lt;/li&gt;
&lt;li&gt;事件服务将消息持久化到RDBMS中&lt;/li&gt;
&lt;li&gt;调度器服务触发作业 &amp;ldquo;发送事件消息&amp;rdquo;&lt;/li&gt;
&lt;li&gt;事件服务查询累计事件消息&lt;/li&gt;
&lt;li&gt;事件服务通过 RabbitMQ 发布消息&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;下面我们就来列举一下outbox模式的利弊吧。&lt;/p&gt;
&lt;h3 id=&#34;优点&#34;&gt;优点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;事件消息首先在RDBMS中持久化。事务的ACID属性保证了事件消息的持久性。&lt;/li&gt;
&lt;li&gt;当事件丢失时，可以从DB中检查该消息。&lt;/li&gt;
&lt;li&gt;丢失的事件可以有效地从RDBMS中恢复。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;缺点&#34;&gt;缺点&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;增加了复杂性。&lt;/li&gt;
&lt;li&gt;发布事件有延迟。&lt;/li&gt;
&lt;li&gt;要发布一个基本事件，至少需要两种技术：存储系统和消息队列协议。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;事件驱动微服务架构的好处&#34;&gt;事件驱动微服务架构的好处&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;松散耦合结构&lt;/li&gt;
&lt;li&gt;微服务的完全隔离&lt;/li&gt;
&lt;li&gt;无同步REST调用&lt;/li&gt;
&lt;li&gt;异步事件驱动的功能&lt;/li&gt;
&lt;li&gt;性能增益&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;上述好处中最重要的好处是第一个。因为我们要通过微服务架构来分离组件，所以所有的单元必须足够的分离（松散耦合）。否则，微服务架构就无法发挥作用，你的系统会变成一个分布式单体。&lt;/p&gt;
&lt;h3 id=&#34;坏处&#34;&gt;坏处&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;单点故障&lt;/strong&gt;：如果您的RabbitMQ在生产过程中遇到任何问题，整个系统也会出现故障。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-event-driven-microservice-architecture/images/single-point-of-failure_huc81f4454626c1eee4dc530b7a0730299_18566_b5723734eaadb96f13c44565ba7796ff.webp 400w,
               /post/202004-event-driven-microservice-architecture/images/single-point-of-failure_huc81f4454626c1eee4dc530b7a0730299_18566_c5190d9047baf132bbc4162dde2dd1d8.webp 760w,
               /post/202004-event-driven-microservice-architecture/images/single-point-of-failure_huc81f4454626c1eee4dc530b7a0730299_18566_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-event-driven-microservice-architecture/images/single-point-of-failure_huc81f4454626c1eee4dc530b7a0730299_18566_b5723734eaadb96f13c44565ba7796ff.webp&#34;
               width=&#34;630&#34;
               height=&#34;318&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;要克服故障:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;将RabbitMQ构建为集群&lt;/li&gt;
&lt;li&gt;建立队列的耐用性&lt;/li&gt;
&lt;li&gt;持久化发布的信息&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这样就可以快速恢复任何故障。在任何错误发生的时候，集群中的其他实例将接管工作并重新创建持久队列。同时，持久消息也会从磁盘上恢复。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;重复的事件消息&lt;/strong&gt;：事件发布者API可能会遇到问题，重新发送相同的消息。要解决系统中的任何重复问题，任何消费端点都必须是幂等的：总是考虑先检查API之前是否获得了该事件。&lt;/p&gt;
&lt;p&gt;在微服务架构环境下，我们必须保持低耦合。为了能够保持低耦合，我们必须关注模块之间的连接。做到这一点的一种方法是使用事件驱动的方法。&lt;/p&gt;
&lt;p&gt;同时，直接REST调用是昂贵的。目标API可能会不在服务中。此外，源API必须等待直到收到响应。&lt;/p&gt;
&lt;p&gt;为了创建事件驱动的微服务结构，我们可以简单地创建一个具有持久化消息的RabbitMQ集群。所有需要的事件都可以通过 &lt;code&gt;service-in-responsibility&lt;/code&gt; 发布。同时，当事件消息发出后，其他所有的服务都可以绑定其消费者，并对其进行处理。&lt;/p&gt;
&lt;p&gt;在构建事件驱动的系统时，我们可以考虑富事件。当事件发生时，富事件提供了所有需要的数据。因此，API不需要任何额外的外部调用。&lt;/p&gt;
&lt;p&gt;另一方面，由于系统故障或网络瘫痪，可能会出现丢失事件。为了确保所有的事件都能成功地发布和消费，可以应用 outbox 模式。简单地说，就是将事件存储在存储系统中，而不是直接发布事件。之后，配置好的作业会在确定的时间间隔内发送事件。丢失的消息可以通过存储系统轻松恢复。&lt;/p&gt;
&lt;h2 id=&#34;结论&#34;&gt;结论&lt;/h2&gt;
&lt;p&gt;总结一下，微服务架构是一个相当新的架构，我们这些开发人员每天都在更好的学习它。当我们一不小心，我们的系统就会变成一个分布式单体，这是最糟糕的情况。因为你不能获得任何好处，因为你必须要处理好复杂性的问题。最重要的是，使用事件驱动架构保持松耦合是最重要的事情之一。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译] 使用CloudEvents和CloudEvents生成器</title>
      <link>https://skyao.net/post/202004-using-cloud-events-and-cloud-events-generator/</link>
      <pubDate>Tue, 07 Apr 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202004-using-cloud-events-and-cloud-events-generator/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://medium.com/google-cloud/using-cloud-events-and-cloud-events-generator-4b71b8a90277&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Using CloudEvents and CloudEvents Generator&lt;/a&gt;，作者 &lt;a href=&#34;https://medium.com/@ratrosy&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Ratros Y.&lt;/a&gt;，文章发表于2019年9月。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;本文档讨论了CloudEvents和CloudEvents Generator的使用方法，帮助更好地理解本教程系列其他教程中使用的演示项目，这是 &lt;a href=&#34;../202004-building-event-driven-cloud-applications-and-services/&#34;&gt;《构建事件驱动的云应用和服务》&lt;/a&gt;系列教程的第二篇。&lt;/p&gt;
&lt;h2 id=&#34;cloudevents&#34;&gt;CloudEvents&lt;/h2&gt;
&lt;p&gt;CloudEvents是由云原生计算基金会的serverless工作组组织的一个倡议，其目标是规范事件发布者如何描述他们的事件。目前这个倡议还在努力中，规范还没有稳定下来；许多云服务提供商和开源项目已经宣布了采用这个规范的计划，包括Knative Eventing和Azure。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;备注&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;您可以在这里阅读 &lt;a href=&#34;https://github.com/cloudevents/spec/blob/v0.3/spec.md&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;最新版本的规范（0.3）&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;CloudEvent 由许多属性组成，例如事件的 ID 和事件的类型。CloudEvent Specification 定义了 CloudEvent 可能具有的必要和可选属性集合，如下所示：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attribute Name&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;&lt;code&gt;id&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Required. The ID of the event. A CloudEvent is uniquely identified with its &lt;code&gt;source&lt;/code&gt; and &lt;code&gt;id&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;source&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String (URI-reference)&lt;/td&gt;
&lt;td&gt;Required. The source of the event.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;specversion&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Required. The version of CloudEvents Specification the Cloud Event uses.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;type&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Required. The type of the event.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;datacontentencoding&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String (RFC 2045 Section 6.1)&lt;/td&gt;
&lt;td&gt;Optional. The encoding of &lt;code&gt;data&lt;/code&gt; (if the field stores binary data).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;datacontenttype&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String (RFC 2046)&lt;/td&gt;
&lt;td&gt;Optional. The content type of &lt;code&gt;data&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;schemaurl&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String (URI-reference)&lt;/td&gt;
&lt;td&gt;Optional. The schema of data.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;subject&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;Optional. The subject of the event.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;String (Timestamp)&lt;/td&gt;
&lt;td&gt;Optional. The timestamp when the event happens.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;data&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;Optional. The payload of the event.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;此外，CloudEvents 允许开发人员通过扩展来添加自己的属性集。&lt;a href=&#34;https://github.com/cloudevents/spec/blob/master/documented-extensions.md&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;文档化的扩展列表可在这里获得&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;CloudEvents 绑定有助于在应用、服务和设备之间传输事件。例如，您可以将事件绑定到 JSON 格式，或者将其映射到 HTTP 请求。&lt;/p&gt;
&lt;h2 id=&#34;cloudevents-生成器&#34;&gt;CloudEvents 生成器&lt;/h2&gt;
&lt;p&gt;Normally, to build a CloudEvent, you will have to use an in-memory structure of your preferred programming language directly, or uses CloudEvents SDK (also a work in progress):&lt;/p&gt;
&lt;p&gt;通常情况下，要构建一个CloudEvent，需要直接使用自己喜欢的编程语言的内存结构，或者使用CloudEvents SDK（也在进行中）:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;datetime&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;json&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;uuid&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;id&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;uuid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;uuid4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;source&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;my-event-source&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;my-event-type&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;specversion&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;0.3&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;time&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;utcnow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isoformat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;T&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;Z&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;data&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;Hello World!&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;event_json_str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;json&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;dumps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Alternatively&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Cloud&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Events&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;SDK&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;cloudevents&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;sdk&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;v03&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;v03&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;SetEventID&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;my-event-id&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;SetSource&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;my-event-source&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;SetEventType&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;my-event-type&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;SetEventTime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;datetime&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;utcnow&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;isoformat&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;T&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;Z&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;SetData&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;Hello World!&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在本系列教程中，为了简单起见，我们使用一个实验性的项目CloudEvents Generator来发布和接收事件。该工具以JSON或YAML格式的事件模式作为输入，并准备一个自己的事件schema，你可以用它来发布和接收事件。schema输入和事件库也可以帮助团队在事件驱动的系统中更好地协作。例如，要用CloudEvents Generator发送上述片段中的事件，首先指定 schema 如下:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;events&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;err&#34;&gt;#&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Define&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;an&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;basic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;nx&#34;&gt;basic&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;err&#34;&gt;#&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Set&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;an&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;attribute&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;id&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;which&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;auto&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;poulated&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;UUIDv4&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;UUIDv4&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;auto&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;err&#34;&gt;#&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Set&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;an&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;attribute&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;source&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;source&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;source&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;err&#34;&gt;#&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Set&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;an&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;attribute&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;my&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;err&#34;&gt;#&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Set&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;an&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;attribute&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;specversion&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;value&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;specversion&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;0.3&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;err&#34;&gt;#&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Set&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;an&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;attribute&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;which&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;auto&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;populated&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;RFC3339&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;timestamp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;time&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;format&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;RFC3339&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;auto&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;err&#34;&gt;#&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Set&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;up&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;an&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;attribute&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pass the schema to CloudEvents Generator, and ask it to prepare a Python package. You can then use this package to create the same event:&lt;/p&gt;
&lt;p&gt;将模式传给CloudEvents Generator，并要求它准备Python包。然后你可以使用这个包来创建同样的事件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;from&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;mypackage&lt;/span&gt; &lt;span class=&#34;kr&#34;&gt;import&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Basic&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Attributes&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;id&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;time&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;will&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;be&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;auto&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;populated&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;#&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;If&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;specified&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;attributes&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;source&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;specversion&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;use&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;their&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;respective&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;values&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Basic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;data&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;Hello World!&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;event_json_str&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;event&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;to_JSON&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;要查看CloudEvents Generator的运行情况，请点击下面的按钮在Cloud Shell中试用。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;译者注：实操环节请在原文中操作。&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>[译] 构建事件驱动的云应用和服务</title>
      <link>https://skyao.net/post/202004-building-event-driven-cloud-applications-and-services/</link>
      <pubDate>Mon, 06 Apr 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202004-building-event-driven-cloud-applications-and-services/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://medium.com/google-cloud/building-event-driven-cloud-applications-and-services-ad0b5b970036&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Building Event-Driven Cloud Applications and Services&lt;/a&gt;，作者 &lt;a href=&#34;https://medium.com/@ratrosy&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Ratros Y.&lt;/a&gt;，文章发表于2019年9月。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;本文讨论了构建事件驱动的应用和服务的通用实践和技术。它是 &lt;a href=&#34;https://medium.com/@ratrosy/building-event-driven-cloud-applications-and-services-ad0b5b970036&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;《构建事件驱动的云应用和服务》&lt;/a&gt; 系列教程的开篇。&lt;/p&gt;
&lt;h2 id=&#34;追求建立可重用和可增长的系统&#34;&gt;追求建立可重用和可增长的系统&lt;/h2&gt;
&lt;p&gt;每个开发者在编写代码时都会考虑到一些显式和隐式假设。我们最常见的一个假设是，计算设备总是按顺序执行我们的代码。每一行代码都命令执行其逻辑上的下一个，它可以是本身（递归）、同一包中的另一个函数，也可以是互联网上的一个远程过程（RPC/RESTful API调用）。执行路径本身本质上是一个水晶化的契约：在编译和部署之后，它不能被修改。&lt;/p&gt;
&lt;p&gt;相对而言，在小范围内，顺序执行假设有助于写出简单、直接、易懂的代码。然而，随着代码库越来越大，增加了数百甚至上千种功能，执行路径本身就不可避免地会变成一个迷宫。伟大的设计模式、软件工程原则和最佳实践可能会暂时解决这个挑战，但危险仍然潜伏着；随着技术债务的积累，它将会进行反击。&lt;/p&gt;
&lt;p&gt;基于HTTP RESTful/RPC的微服务架构解决了这一担忧，它迫使开发人员针对远程服务的接口进行编程，而不是本地实现，其核心是可重用的面向对象设计的第一个原则的自然延伸。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Program to an interface, not an implementation.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Design Patterns: Elements of Reusable Object-Oriented Software (1994)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;然而，缺点是引入了服务之间的依赖关系，这是一个可以管理的副作用，开发人员可以也不得不忍受的副作用。执行路径依然存在；相反，这种模式有助于大大减少一个人或团队管理的代码量，并将一些责任以一种高度规范的方式卸载给其他服务。这带来了一系列新的挑战，这些挑战是基于 HTTP RESTful/gRPC 的微服务架构的从业者所独有的；我们在这里不讨论这些挑战，因为它们显然不在本系列教程的范围之内。&lt;/p&gt;
&lt;p&gt;另一方面，事件驱动架构试图通过一劳永逸地摆脱执行路径来解决这个问题。在事件驱动的app中，逻辑块的代码在完成时发出事件，这是一个带有上下文数据的消息块，而不是协调另一个块代码的执行。事实上，事件的发布者几乎不关心下一步会发生什么；下面的操作由消息机制来决定，通常是消息队列/流的解决方案。消息机制将事件（几乎）同时从发布者传递给0个或更多的订阅者，在这里，事件被单独处理。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The key in making great and growable systems is much more to design how its modules communicate rather than what their internal properties and behaviors should be.&lt;/p&gt;
&lt;p&gt;构建伟大的、可增长的系统的关键在于设计其模块如何通信，而不是设计其内部的属性和行为应该是什么。&lt;/p&gt;
&lt;p&gt;Alan Kay&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;与基于 HTTP RESTful/RPC 的微服务架构不同，事件驱动的系统在各部分之间没有依赖关系，也没有编程接口。诚然，发布者和订阅者仍然必须在一定程度上尊重事件的预设模式；然而，契约是相当灵活的：正如前面所解释的那样，发布者几乎不知道订阅者是否使用发布的事件，也不知道订阅者是如何使用发布的事件。没有了执行路径，应用程序和服务的可扩展性就会成倍增长：你可以随时添加或删除代码块，以订阅者的形式；同一事件流的订阅者在默认情况下同时工作，不会以任何方式相互干扰。&lt;/p&gt;
&lt;p&gt;而这并不是事件驱动架构的唯一好处。通过作为中间人的消息队列，你的应用和服务被赋予了前所未有的可扩展性：像Google Cloud Pub/Sub和Apache Kafka这样的解决方案，如果配置得当，可以在短时间内预留并在之后分发海量的数据，延迟可以忽略不计。许多消息队列也能够自适应；它们与订阅者同步工作，并尽最大努力不让订阅者不堪重负。在当今世界上，越来越多的企业都是以实时数据为基础运行的，这种质量是非常重要的：随着数十亿设备的相互通信，应用和服务必须变得超级弹性。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注意&lt;/p&gt;
&lt;p&gt;诚然，单体和基于  HTTP RESTful/RPC 的微服务系统在合适的平台（如 Kubernetes/Google Kubernetes Engine）下也可以扩展。然而，在执行路径的作用下，每个函数调用、RPC调用和/或HTTP请求都意味着（立即）执行另一个（可能是远程的）代码块；调用和请求本身也会占用资源，而且不能批量化。一般来说，基于 HTTP RESTful/RPC 的微服务应该只在必要的时候才会互相通信；健谈式服务是这个架构中一个臭名昭著的反模式。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;本系列教程将详细讨论事件驱动架构的优点，当然也有其缺点，以及开发人员用来构建自己的事件驱动系统的常用模式和实践。&lt;/p&gt;
&lt;h2 id=&#34;什么是事件驱动&#34;&gt;什么是事件驱动？&lt;/h2&gt;
&lt;h3 id=&#34;事件&#34;&gt;事件&lt;/h3&gt;
&lt;p&gt;事件无非就是一份数据。更具体地说，它是一个不可变的小段数据，记录了系统在特定时间内的特定行为；常见的例子包括你的恒温器检测到房间的温度变化，或者顾客在购物车中添加了一个新的商品。通过读取系统的事件流（序列），可以轻松地重建系统的运行历史。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-building-event-driven-cloud-applications-and-services/images/event_hub1f86e51723fad9ea07328d20f38a4d6_124731_f584969672f2872dece28bcc4bc65876.webp 400w,
               /post/202004-building-event-driven-cloud-applications-and-services/images/event_hub1f86e51723fad9ea07328d20f38a4d6_124731_05edf09642d7192cc71795dba5daffbc.webp 760w,
               /post/202004-building-event-driven-cloud-applications-and-services/images/event_hub1f86e51723fad9ea07328d20f38a4d6_124731_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-building-event-driven-cloud-applications-and-services/images/event_hub1f86e51723fad9ea07328d20f38a4d6_124731_f584969672f2872dece28bcc4bc65876.webp&#34;
               width=&#34;760&#34;
               height=&#34;346&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;一般来说，事件的格式是由开发者自己决定的。云原生计算基金会现在正在创建一个描述事件的标准化规范，即CloudEvents，现在很多云服务提供商都计划支持这种格式。本系列教程自始至终都使用了0.3版本的CloudEvents规范；强烈建议您在事件驱动的应用和服务中也使用此规范。&lt;/p&gt;
&lt;p&gt;另外，为了简单起见，本系列教程尽可能使用实验项目 CloudEvents Generator 来生成和消费事件。请注意，你也可以使用你喜欢的编程语言的内存内结构自己构建标准的CloudEvents。&lt;/p&gt;
&lt;h3 id=&#34;事件驱动&#34;&gt;事件驱动&lt;/h3&gt;
&lt;p&gt;事件驱动是一个松散定义的术语，它的用法因开发者而异。可以说，任何使用事件发布者/订阅者范式（有时也称为通知范式）的系统都可以被认为是事件驱动的系统。根据事件集成到系统中的程度，事件驱动系统大致可以分为两类：反应式（reactive）和流处理（stream processing ）式。&lt;/p&gt;
&lt;h3 id=&#34;反应式事件驱动系统&#34;&gt;反应式事件驱动系统&lt;/h3&gt;
&lt;p&gt;在一个反应式事件驱动的系统中，事件本质上是不带同步性的函数调用（或HTTP RESTful/RPC调用）。发布者发出一个事件，实际上是在发布者无感知的情况下触发了订阅者的动作。例如，航班预订服务可能会在客户预订航班时，设置其API后台发出 &lt;code&gt;orderCreated&lt;/code&gt; 事件；消息队列将该事件传递给订阅者服务，后者处理该事件，联系航空公司预订机票，并向客户的信用卡收费。&lt;/p&gt;
&lt;p&gt;有人可能会认为这是一种表面上采用事件的方式（被动式的函数调用）；但是，反应式的事件驱动系统仍然可以享受到架构的诸多好处：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;由于订阅者服务承担了订票和支付处理的责任，API后台可以更快地响应，在 orderCreated 事件发出后，立即告诉客户系统正在处理订单，随后通知客户处理结果。&lt;/li&gt;
&lt;li&gt;团队现在可以分别在API后台、票务预订功能和支付处理功能上进行工作，没有耦合的烦恼。&lt;/li&gt;
&lt;li&gt;系统现在对节假日期间的流量波峰有了更多的准备。当订阅者服务不堪重负时，消息队列会自动扣留 OrderCreated 事件；有些解决方案甚至可以通过适当的配置自动重试暂时失败的预订和支付。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;流处理事件驱动应用&#34;&gt;流处理事件驱动应用&lt;/h3&gt;
&lt;p&gt;具有流处理功能的事件驱动系统以更密集的、面向数据的方式使用事件。在这种模式下，事件的订阅者通常是流处理器，它从事件流中提取状态，并将状态传递给相关方。这类系统通常由数据流解决方案支持，如Apache Flink、Apache Spark和Cloud Dataflow等。如果有帮助的话，可以设想利用物联网设备监控区域内的温度方差的系统：每隔一秒钟，该区域周围的恒温器就会通过消息队列以事件的形式向服务报告他们的读数，每个事件包括一个特定时间的温度数据点；服务在设定的时间窗口中（例如每15秒一次）收集所有的事件，并使用流处理器计算出数据的统计方差（状态）；然后服务将状态传递给另一个系统（例如控制面板），以便进一步检查。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-building-event-driven-cloud-applications-and-services/images/stream-processing_hu7d201df7abf74cd1c5b453b250389a20_102712_f2c5b4ccccbd1072eeb588f2e9235c95.webp 400w,
               /post/202004-building-event-driven-cloud-applications-and-services/images/stream-processing_hu7d201df7abf74cd1c5b453b250389a20_102712_9fa6f9154904c7655090e258546dd14b.webp 760w,
               /post/202004-building-event-driven-cloud-applications-and-services/images/stream-processing_hu7d201df7abf74cd1c5b453b250389a20_102712_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-building-event-driven-cloud-applications-and-services/images/stream-processing_hu7d201df7abf74cd1c5b453b250389a20_102712_f2c5b4ccccbd1072eeb588f2e9235c95.webp&#34;
               width=&#34;760&#34;
               height=&#34;284&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;事件驱动的流处理系统是近年来行业内普遍采用的。社交网络使用它来计算喜好、页面浏览量、收听量等，而云服务提供商则将其用于欺诈/滥用检测。这种模式也是许多实时数据分析应用和数据转换管道的基础。&lt;/p&gt;
&lt;h3 id=&#34;event-sourcing和cqrs&#34;&gt;Event Sourcing和CQRS&lt;/h3&gt;
&lt;p&gt;事件源是事件驱动系统中常见的另一个名词。这个名词可能会让人有点混淆，它实际上是一种数据持久化模式，而不是事件驱动系统的设计模式。你可能会认为它是关系型（SQL）数据库和NoSQL数据库的替代品。这个模式的设计理念或许可以用一个例子来解释。&lt;/p&gt;
&lt;p&gt;设想一下，你正在为世界著名的电视节目《So You Think You Can Code》构建一个电子投票系统。投票系统从本质上来说是一个写密集型的系统：计数只在最后才是重要的，但人们一直在提交他们的投票。因此，如果你使用关系型（SQL）数据库作为数据库的后台，很容易让人应接不暇，因为每一次投票都需要更新一个表，锁住一行，然后再释放。然而，使用Event Sourcing，接受投票只需要在事件日志中做一次插入，因为每个投票（事件）都是不可更改的，所以不需要锁定。当你需要最后的计数时，只需简单地读取记录的事件序列，然后把投票数加起来就可以了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-building-event-driven-cloud-applications-and-services/images/event-sourcing_hu2baada46ccf1b12e66ebfe174cf0827e_90557_a7558498996e024be54d981cc3d99b62.webp 400w,
               /post/202004-building-event-driven-cloud-applications-and-services/images/event-sourcing_hu2baada46ccf1b12e66ebfe174cf0827e_90557_944d0b78c5a27f7ce046ac8b6fbf8703.webp 760w,
               /post/202004-building-event-driven-cloud-applications-and-services/images/event-sourcing_hu2baada46ccf1b12e66ebfe174cf0827e_90557_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-building-event-driven-cloud-applications-and-services/images/event-sourcing_hu2baada46ccf1b12e66ebfe174cf0827e_90557_a7558498996e024be54d981cc3d99b62.webp&#34;
               width=&#34;760&#34;
               height=&#34;692&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Event Sourcing 的特性使其成为事件驱动系统中数据持久化的天然选择。然而，Event Sourcing并不是唯一的选择，许多反应式事件驱动系统，例如，仍然使用关系型（SQL）/NOSQL数据库作为存储。&lt;/p&gt;
&lt;p&gt;当人们谈论Event Sourcing时，你可能也会听到CQRS（Command Query Responsibility Segregation）这个词。简单的说，在Event Sourcing系统中，CQRS有助于在事件序列上创建一个物化的视图，这样你就可以像使用普通的DBMS一样查询数据，省去了每次需要状态时自己扫描事件和计算数字的麻烦。这种设计并不排斥Event Sourcing，它的核心只是说明，可以使用不同的模型来更新信息，而不是你用来读取信息的模型。&lt;/p&gt;
&lt;p&gt;本系列教程不会讨论太多的事件源或CQRS，因为它们不是事件驱动系统的一个组成部分。如果你有兴趣，可以参考Martin Fowler撰写的这些博文（Event Sourcing，CQRS）。&lt;/p&gt;
&lt;h3 id=&#34;事件驱动系统和serverless计算&#34;&gt;事件驱动系统和serverless计算&lt;/h3&gt;
&lt;p&gt;事件驱动架构是serverless计算平台的天然盟友，尤其是FaaS(Function as a Service)架构。这种架构和解决方案有很多共同的特点：都是以解耦系统和可扩展性为设计理念。许多serverless计算平台也采用了按使用收费的定价模式，这与发布者/用户模式非常吻合。其中一些平台，如Cloud Functions，甚至内置了与消息队列解决方案的集成（本例中，Cloud Pub/Sub）。&lt;/p&gt;
&lt;p&gt;本教程在演示中使用了一些serverless计算解决方案。不过，在你的生产型APP和服务中，在选择serverless作为运行用户的平台之前，需要谨慎一些：除了技术上的限制（冷启动时间、运行时间限制、延迟等）之外，构建、测试、部署和管理serverless代码本身就是一个挑战。&lt;/p&gt;
&lt;p&gt;作为一个侧面说明，许多serverless计算解决方案是无状态的，这使得在其上运行分组操作（或一般的流处理）相当困难。你可以添加一个数据持久化层来解决这个问题，但它可能会变得相当昂贵，而且难以构建/维护。从经验上说，在反应式事件驱动系统中使用它们比在流处理系统中使用它们更好，也更容易。&lt;/p&gt;
&lt;h3 id=&#34;要不要走事件驱动&#34;&gt;要不要走事件驱动？&lt;/h3&gt;
&lt;p&gt;到目前为止，我们已经说了很多关于事件驱动系统的好话。可悲的是，就像计算机科学领域的许多想法和概念一样，事件驱动架构提供的每一个好处都是有代价的。事件流（流）是出了名的难以跟踪；如果没有作为地图的执行路径，开发人员可能要花大力气才能在无穷无尽的事件流中找到一个bug，或者是性能瓶颈。有许多工具和实践可以帮助缓解这个问题（我们将在本系列教程的后面讨论），尽管它们都不是最终的解决方案；这只是我们为隔离发布者和用户而不得不付出的代价。&lt;/p&gt;
&lt;p&gt;事件驱动系统的另一个潜在痛点是消息队列/流解决方案。开发者通常会认为中间商会按照他们的承诺来执行，在99.99%-99.99999%的情况下，这是事实；然而，打盹的情况还是会发生。消息队列可能会意外地停止工作，突然间发送大量重复的消息，或者在没有警告的情况下引入无法解释的、不可重现的延迟。要有心理准备。&lt;/p&gt;
&lt;p&gt;即使有一些完全拥抱事件驱动架构的原型，很多团队也会将事件驱动系统作为这种服务的一部分，专门用于特定的工作流程，而这种工作流程对事件的效果最好。例如，你可以在你的服务网格中引入一个事件驱动的微服务，专门用于数据分析，同时保持其他一切都基于HTTP RESTful/RPC。&lt;/p&gt;
&lt;p&gt;总而言之：三思而后行。事件驱动的架构听起来很花哨，但没有人会责怪你使用单体系统，如果它的效果一样好的话。架构本身可以成为一些问题的神奇解决方案，但它的局限性在特定的场景中同样会让人防不胜防。请根据具体情况，采用事件驱动的系统。&lt;/p&gt;
&lt;h2 id=&#34;后续内容&#34;&gt;后续内容&lt;/h2&gt;
&lt;p&gt;本系列教程包括以下内容。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;使用 CloudEvents 和 CloudEvents Generator&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;../202004-reactive-event-driven-systems-and-recommended-practices/&#34;&gt;反应式事件驱动系统及推荐实践&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;带流处理的事件驱动系统介绍&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>[译] 事件驱动微服务架构师指南</title>
      <link>https://skyao.net/post/202004-event-driven-microservices/</link>
      <pubDate>Thu, 02 Apr 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202004-event-driven-microservices/</guid>
      <description>&lt;p&gt;英文原文来自Solace公司网站上的一份PDF格式的小册子: &lt;a href=&#34;https://go.solace.com/wp-download-eventdrivenmicroservices.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The Architect’s Guide to Event-Driven Microservices&lt;/a&gt; ，副标题为 &amp;ldquo;The Architect’s Guide to Building a Responsive, Elastic and Resilient Microservices Architecture / 架构师指南，用于建立响应式的，灵活而弹性的微服务架构。&amp;rdquo;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;If we are to exponentially increase agility through microservices, we need to replace our static, stove-piped, monolithic thinking.&lt;/p&gt;
&lt;p&gt;如果我们要通过微服务来指数级地提高敏捷性，我们需要取代静态的、炉火纯青的、单体化的思维。&lt;/p&gt;
&lt;p&gt;By JONATHAN SCHABOWSKY&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;简介&#34;&gt;简介&lt;/h2&gt;
&lt;p&gt;许多组织迁移到微服务架构，原因只有一个：敏捷性。在有大量竞争者，而上市时间就是一切的世界里，能够快速创建和修改组件的能力是至关重要的。但开发组件的速度只是其中的一块拼图而已。&lt;/p&gt;
&lt;p&gt;如何快速地将它们与你的系统的其他部分集成？你接受创新的技术新事物有多彻底？为了使您的微服务计划能够成功，您的组织必须认识到敏捷取决于全面的利用诸如CI/ CD，自动化基础设施，DevOps和敏捷开发。一般的微服务架构师结合这些融入精益求精的发展理念。一个优秀的微服务架构师不会止步于此，还包括欣赏和探讨如何克服不可否认的问题 - 高度分布式系统中的可预见的陷阱 。&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;/ul&gt;
&lt;p&gt;如果我们不尊重分布式系统的现实，我们将重复过去的失败，就像2000年代的SOA炒作一样。幸运的是，有一种真正强大的方法可以弥补这些现实：事件驱动（也叫反应式/reactive）架构。&lt;/p&gt;
&lt;p&gt;Jonathan Schabowsky，Solace CTO办公室的高级架构师，将解释把事件驱动架构和微服务结合在一起的巨大好处，首先应用的分解虽然在很多方面都有好处，但会让事情变得更复杂一些。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Application leaders engaged in digital transformation initiatives must add ‘event thinking’ to their technical, organizational and cultural strategies.&lt;/p&gt;
&lt;p&gt;参与数字化转型计划的应用领导者必须在其技术、组织和文化战略中加入 &amp;ldquo;事件思维&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;YEFIM NATIS
GARTNER&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;服务分解悖论&#34;&gt;服务分解悖论&lt;/h2&gt;
&lt;p&gt;微服务的理论很简单：通过将单体的应用分解成小的、特定用途的微服务，实现更好的敏捷性、可扩展性和可重用性。&lt;/p&gt;
&lt;p&gt;现实世界中的微服务实现一如既往地比这复杂。在很大程度上是因为分布式计算的谬误&amp;ndash;程序员和架构师在进入分布式应用的世界时，都会做出一系列错误的假设。这个列表是由 Sun Microsystems 公司的 L. Peter Deutsch 和其他人在1994年写的，但它在今天仍然适用。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The network is reliable / 网络是可靠的&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Latency is zero / 延迟为零&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Bandwidth is infnite / 带宽无限&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The network is secure / 网络是安全的&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Topology doesn’t change / 拓扑结构不会改变&lt;/li&gt;
&lt;li&gt;There is one administrator / 有一个管理员&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transport cost is zero / 传输成本为零&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The network is homogeneous / 网络是同质化的&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;虽然所有这些谬误都是相关的，但粗体字的谬误对于微服务世界来说特别重要。把每个微服务做得越小，服务数量越大，分布式计算的谬误就越影响稳定性和用户体验/系统性能。这使得建立架构和实现变得至关重要：既能最大限度地减少延迟，又能处理网络和服务中断的现实。&lt;/p&gt;
&lt;p&gt;大部分与微服务相关的工具工具都涉及到CI/CD、自动化基础设施、DevOps和敏捷软件开发。Pivotal Cloud Foundry就是一个很好的例子，它为开发人员提供了一种使用现代云原生技术创建、测试、部署和更新微服务的简便方法。&lt;/p&gt;
&lt;p&gt;挑战在于，微服务需要连接/数据才能发挥其作用并提供业务价值，而数据采集/通信在很大程度上被忽略了，以至于工具化严重滞后。例如，API管理/网关产品只支持同步、请求/回复的交换模式，这加剧了分布式计算的挑战。而且它们不具备与遗留系统集成或获取数据的能力。&lt;/p&gt;
&lt;p&gt;同时，事件/消息工具也一直停留在过时的、非agile的世界里，与微服务的许多指导原则如 DevOps 和 selfservice 不兼容。但是，事件/消息才是最能处理分布式计算的特异性，也是释放微服务架构潜力的关键。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Eventing/messaging tools have been stuck in the antiquated, non-agile world. Many are incompatible with the guiding principles of microservices, such as DevOps.”&lt;/p&gt;
&lt;p&gt;&amp;ldquo;事件/消息工具一直停留在陈旧的、非agile的世界里。许多工具都与微服务的指导原则不相容，比如DevOps。&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;随着服务的规模越来越小，目的越来越单一，复用的可能性也就越来越大，但这是以服务的协作能力为前提的。&lt;/p&gt;
&lt;p&gt;在SOA时代，会创建大量的单体服务，直接实现用例的所有方面，如一组使用BPEL引擎或ESB编排的服务。它们不能重复使用，难以扩大规模，因为 ESB / BPEL 编排将太多的逻辑移进入网络，导致 &amp;ldquo;哑巴端点和智能管道（dumb endpoints and smart pipes）&amp;quot;，昂贵、复杂，几乎不可能排除故障。&lt;/p&gt;
&lt;p&gt;今天，我们认识到，要走的路是小型、单一用途的微服务，和用&amp;quot;智能终端哑巴管道（smart endpoints, dumb pipes） &amp;ldquo;的方式来进行连接和通信。但是， 有个问题一直困扰着我们。&lt;/p&gt;
&lt;p&gt;在增加商业价值的情况下，我们如何才能实现服务协作，而不回归到那些失败的单体或编排技术？&lt;/p&gt;
&lt;h2 id=&#34;集成的难题&#34;&gt;集成的难题&lt;/h2&gt;
&lt;p&gt;因为所有的微服务都需要数据来处理，而既然12要素应用是无状态的，那么数据需要从哪里来。为 greenfield 的系统获取数据是很容易，但微服务几乎总是作为数字化转型、现代化或需要以更快的速度构建新功能的副作用而出现。因此，你几乎总是在处理一个由遗留系统组成的生态系统；有些系统将被现代化，有些系统将在可预见的未来保持原样。&lt;/p&gt;
&lt;p&gt;现有的商业生态体系是 负担，是大多数 企业在进行 开始他们的微服务之旅。大多数 现有系统在房地内运行，而 微服务活在私人和公共 云。数据传输的能力。往往是一个不稳定和不可预知的世界，在这个世界上，我们的工作是不稳定的。广域网(WAN)是棘手的，也是很难的。耗费时间。那么，我们需要考虑到 的出现和专业化 物联网、移动设备和大数据造成的。这些系统的数量和种类 导致了很大的前期风险，对 微服务举措。&lt;/p&gt;
&lt;p&gt;大多数企业开始微服务之旅时，现有业务生态系统是必须应对的不可避免的负担。现有的大多数系统都位于本地，而微服务则位于私有云和公共云中。 在通常不稳定且不可预测的广域网（WAN）世界中数据传输是非常棘手且耗时。 然后，我们需要考虑物联网，移动设备和大数据的出现和专业化。 这些系统的数量和多样性给微服务计划带来很大的前期风险。&lt;/p&gt;
&lt;p&gt;当你把它加起来的时候，到处都是阻抗不匹配。1. 传统系统的更新速度很慢，但微服务需要快速、敏捷；2.传统系统使用旧的通信介质，但微服务使用现代开放的协议和API；3.传统系统几乎都在本地，充其量是使用虚拟化，但微服务依赖云和IaaS抽象；4. 物联网系统使用高度专业化的协议，但大多数微服务API和框架并不原生支持；5、移动设备可能使用REST，但也需要异步通信，但大多数API网关只支持同步RESTful交互。组织如何解决所有这些不匹配的问题？&lt;/p&gt;
&lt;h2 id=&#34;舞动的微服务&#34;&gt;舞动的微服务&lt;/h2&gt;
&lt;p&gt;正如我前面所描述的，服务越小，它对终端用户的价值越小&amp;ndash;价值来自于编排（Orchestration）。历史上，编排是由BPEL引擎或ESB等中心组件来处理的，或者现在的API网关。&lt;/p&gt;
&lt;p&gt;我将用一个音乐类比来解释这种方法的问题。&lt;/p&gt;
&lt;p&gt;大多数作曲家通过试验和错误创造音乐（就像软件开发者一样）。他们的输出是什么？乐谱包含了每一种乐器都会演奏的音乐。对于这个比喻，每个演奏者就像一个微服务。如果作曲家是为一个重金属乐队创作，那么只有几件乐器（吉他、贝斯手、鼓手、声乐手），不需要指挥。&lt;/p&gt;
&lt;p&gt;但一个交响乐团由一百名左右的演奏者组成，演奏各种乐器。在这种情况下，他们绝对需要一个指挥家，以确保每个演奏者在正确的时刻开始演奏，保持节拍，必要时加快或减慢速度，演奏的声音或大或小。&lt;/p&gt;
&lt;p&gt;不幸的是，如果指挥家不能与演奏者沟通，甚至只是一个部分或一个演奏者的沟通，那么事情就会很快就会分崩离析，演出就会受到影响，甚至被破坏。&lt;/p&gt;
&lt;p&gt;舞蹈就不同了。舞蹈编导听了一首歌，然后根据音乐中的事件创造出一个套路。舞者可能会做完全不同的动作或舞步，但只要是根据这些声音提示（或事件）一起协调（choreograph）的，那么这个舞步就是成功的。即使有人踏错了舞步或失去了节拍，表演也可以继续进行，因为每个舞者都是在听着为他们的特定事件而协调（choreograph）的音乐，而不是由编排者告诉他们该做什么。&lt;/p&gt;
&lt;p&gt;回到微服务，给定的微服务会在代码中执行一系列的步骤，这就是微编排的例子。微服务的输入或输出是数据事件，这个数据事件具有领域意义。关键在于，由于微服务只是产生事件，所以它并不知道这个事件是否会被处理或何时处理。其他服务会对一个事件或一组事件进行注册并做出相应的反应。就像一个舞者在执行套路的舞步一样。具有讽刺意味的是，微服务执行和舞蹈动作之间的共同驱动因素是事件（数据事件或音频事件）。&lt;/p&gt;
&lt;h3 id=&#34;事件的哥白尼转变&#34;&gt;事件的哥白尼转变&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;FROM DATA-CENTRIC TO EVENT-CENTRIC IT PRIORITY – A COPERNICAN SHIFT&lt;/p&gt;
&lt;p&gt;从以数据为中心到以事件为中心的IT优先级&amp;mdash;-哥白尼的转变&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-event-driven-microservices/images/copernican_huda146d3825fc6d502e05b38609bff098_72841_61956f53ee2887b9b42a8d76690576e7.webp 400w,
               /post/202004-event-driven-microservices/images/copernican_huda146d3825fc6d502e05b38609bff098_72841_e9f2fdbded3574b739a5fcdefa41f605.webp 760w,
               /post/202004-event-driven-microservices/images/copernican_huda146d3825fc6d502e05b38609bff098_72841_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-event-driven-microservices/images/copernican_huda146d3825fc6d502e05b38609bff098_72841_61956f53ee2887b9b42a8d76690576e7.webp&#34;
               width=&#34;670&#34;
               height=&#34;297&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Similar to the mistakes that astronomers made before Copernicus, many architects and technologists are obsessed with the idea that data is the center of the computing universe.”&lt;/p&gt;
&lt;p&gt;&amp;ldquo;与哥白尼之前的天文学家所犯的错误类似，很多架构师和技术专家都迷恋于数据是计算宇宙的中心的想法。&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;哥白尼是文艺复兴时期的数学家和天文学家，他提出了一个宇宙模型，将太阳而不是地球置于宇宙中心。改变了当时的游戏规则。&lt;/p&gt;
&lt;p&gt;与哥白尼之前的天文学家所犯的错误类似，许多架构师和技术专家都执着于认为数据是计算机宇宙的中心。这种传统的观点是基于这样的信念：数据是工作。一旦数据被保存下来，就会通过命令式的请求/响应交互来查看、更新和删除。&lt;/p&gt;
&lt;p&gt;这种对数据的极端关注的原因很简单：所有与数据库的交互都是通过命令式的交互来完成的! 这种观点的问题在于，企业最终以数据库为核心做了一堆微服务，导致很多烟囱式的应用飞地，无法快速、灵活地共享数据。换句话说，花钱创造了一种不同类型的单体应用，这种单体应用注定会同样遭遇缺乏敏捷性的命运。&lt;/p&gt;
&lt;p&gt;那么什么应该是微服务宇宙的中心？很简单：事件。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-event-driven-microservices/images/microservices_huda146d3825fc6d502e05b38609bff098_40188_e61f68d86c65b1b105ad7f5342565d14.webp 400w,
               /post/202004-event-driven-microservices/images/microservices_huda146d3825fc6d502e05b38609bff098_40188_9e7352cd02cf9069ddfeb07c9acb9ef8.webp 760w,
               /post/202004-event-driven-microservices/images/microservices_huda146d3825fc6d502e05b38609bff098_40188_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-event-driven-microservices/images/microservices_huda146d3825fc6d502e05b38609bff098_40188_e61f68d86c65b1b105ad7f5342565d14.webp&#34;
               width=&#34;657&#34;
               height=&#34;374&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如果我们要通过微服务成倍地提高敏捷性 ，我们需要将我们静态的，根深蒂固的单体思维替代为渴望在正确的时间将正确的事件带到正确的服务。考虑到你自己的身体。我们根据我们的触觉，视觉，味觉，听觉和气味不断地反应和行动。该事件的中继信息储存在我们的记忆中，在我们的大脑中重播，并在必要时采取某种行动，对这些信息产生作用，从而为我们的宇宙做出反应。&lt;/p&gt;
&lt;p&gt;以事件驱动的方式思考，将组织变成了计算机宇宙中的感知元素。由Web/移动应用、IoT传感器或遗留的记录系统感知到的新事件被转发到事件/消息平台，然后分发到微服务平台。就像我们的感觉系统是如何将事件传到中枢神经系统进行解读一样。在微服务的世界里，我们需要一个中枢神经系统，它可以：&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;不采用事件驱动的思维，将以增加成本和降低生产力的方式阻止数字化转型和微服务计划的成功。那么，有哪些模式和方法可以让你和你的组织以事件为中心，并获得成功？&lt;/p&gt;
&lt;h2 id=&#34;实现现代中枢神经系统提供的灵活性&#34;&gt;实现现代中枢神经系统提供的灵活性&lt;/h2&gt;
&lt;p&gt;正如Gartner公司在2017年8月发布的题为《数字化业务中的业务事件、业务时刻和事件思维》的报告中所说，&amp;ldquo;参与数字化转型举措的应用领导者必须在技术、组织和文化战略中加入&amp;rsquo;事件思维&amp;rsquo;。&amp;rdquo;&lt;/p&gt;
&lt;p&gt;这是一个大胆的说法，我非常同意。本文的目的，毕竟是为了布置出你必须采取的可操作步骤，以实现事件驱动微服务的敏捷性。&lt;/p&gt;
&lt;h2 id=&#34;事件驱动的思维和服务执行的编排&#34;&gt;事件驱动的思维和服务执行的编排&lt;/h2&gt;
&lt;p&gt;采纳事件驱动思维的第一步是改变对设计和架构解决方案的思维方式。初识的倾向是将服务之间的所有交互视为请求/回复服务调用序列的一系列。事实上，如果你或你的团队使用 &amp;ldquo;调用/invoking&amp;rdquo;、&amp;ldquo;请求/requesting&amp;quot;或 &amp;ldquo;调用/calling&amp;quot;等术语，那么这肯定表明你仍然在用命令式的思维模式来思考。&lt;/p&gt;
&lt;p&gt;相反，不妨试试这些。&amp;ldquo;我的服务应该处理哪些事件？&amp;ldquo;和 &amp;ldquo;我的服务应该发送哪些事件？&amp;rdquo;&lt;/p&gt;
&lt;p&gt;一旦你采用了事件驱动的思维，你就需要实现从编排（orchestration）到协调（choreography）的转变。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-event-driven-microservices/images/orchestration-and-choreography_huda146d3825fc6d502e05b38609bff098_15377_9cadf3090b9589b048ad6db76b6ae39b.webp 400w,
               /post/202004-event-driven-microservices/images/orchestration-and-choreography_huda146d3825fc6d502e05b38609bff098_15377_cb5d0104607b34f8409c917076ede049.webp 760w,
               /post/202004-event-driven-microservices/images/orchestration-and-choreography_huda146d3825fc6d502e05b38609bff098_15377_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-event-driven-microservices/images/orchestration-and-choreography_huda146d3825fc6d502e05b38609bff098_15377_9cadf3090b9589b048ad6db76b6ae39b.webp&#34;
               width=&#34;322&#34;
               height=&#34;169&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;架构师通常会从 &amp;ldquo;服务A调用服务B，而服务B调用服务C &amp;ldquo;的角度来思考，然后通过调用链（a-&amp;gt;b-&amp;gt;c）或通过创建一个编排器服务来实现该模型，例如 x-&amp;gt;a，然后 x-&amp;gt;b，然后 x-&amp;gt;c。&lt;/p&gt;
&lt;p&gt;当分布式计算的现实出现时，这两种方法都会造成混乱，特别是当你开始扩展时。&lt;/p&gt;
&lt;p&gt;另一种选择是遵循协调（choreography）的哲学。回到舞蹈的比喻，服务应该像舞者对音乐提示做出反应一样，对环境的变化做出反应。这样做的好处是巨大的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;更加敏捷&lt;/strong&gt;。敏捷开发团队更加独立，受其他服务的变化影响明显变小。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;服务更小/更简单&lt;/strong&gt;。每个服务不需要对下游服务或网络故障进行复杂的错误处理。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;服务耦合性较小&lt;/strong&gt;。不知道其他服务的存在。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;实现细粒度的伸缩性&lt;/strong&gt;。每项服务都可以根据需求独立地伸缩。这样既保证了良好的用户体验，又减少了计算资源的浪费。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;易于添加新服务&lt;/strong&gt;。由于耦合较少，一个新的服务可以上线、消费事件和实现新的功能，而不需要改变任何其他服务。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这一连串的好处并不是白送的，世界上没有免费的午餐。&lt;/p&gt;
&lt;p&gt;那么，状态的一致性就成为了需要关注的领域，因为一个被暂时宕机的服务意味着事件状态的变化可能无法立即处理。从根本上说，我们如何处理这种负面效应？&lt;/p&gt;
&lt;h2 id=&#34;拥抱最终一致性&#34;&gt;拥抱最终一致性&lt;/h2&gt;
&lt;p&gt;最终的一致性是指一致性会在未来达成的想法，它意味着接受事情可能会在一段时间内不同步。这是一种模式和概念，让架构师们可以将昂贵的XA事务从mix中去除。事件/消息平台的工作是确保这些领域变更事件在被服务适当处理并承认之前永远不会丢失。&lt;/p&gt;
&lt;p&gt;有些人认为最终一致性的唯一好处是性能，但真正的好处是微服务的解耦，因为单个服务仅仅是对它们感兴趣的事件采取行动。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The road to microservices is paved with good intentions. But more than a few teams are jumping on the bandwagon without analyzing their needs frst.&lt;/p&gt;
&lt;p&gt;微服务的前景时美好的。但是，非常多的团队在没有先分析需求的情况下就跳到了微服务这条路上。&lt;/p&gt;
&lt;p&gt;NATHANIEL T. SCHUTTA&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;数据库--cqrs&#34;&gt;数据库 + CQRS&lt;/h2&gt;
&lt;p&gt;关于使用事件的思考过程，通常会引出一个有趣的问题。如果数据不再是我的宇宙的中心，那么我现在要把这些事件持久化到哪里去？&lt;/p&gt;
&lt;p&gt;数据库将我们的思维带回命令式（Create、Read、Update、Delete）的交互。数据库的困境是极其有趣的，使用一种叫做命令查询责任隔离（Command Query Responsibility Segregation/CQRS）的模式可以提供很大的好处。关键是，CQRS不是一个架构；它是一个简单的模式，可以帮助实现事件驱动架构，因为我们的宇宙中心的事件必须在某个地方持久化。&lt;/p&gt;
&lt;p&gt;最终，对于大多数情况下，这个地方将是一个数据库。&lt;/p&gt;
&lt;p&gt;那么，CQRS到底是什么？&lt;/p&gt;
&lt;p&gt;让我们以一个琐碎的银行业务用例为例，来探讨一下CQRS的作用。传统上，我们会有一个 Account 服务来处理所有的账户交互。它的API将被定义为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;AccountService&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;nx&#34;&gt;Public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;createAccount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;nx&#34;&gt;Public&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Account&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;getAccount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;nx&#34;&gt;Public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;debitAccount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;amount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;nx&#34;&gt;Public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;creditAccount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;amount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;nx&#34;&gt;Public&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;AccountList&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;nx&#34;&gt;getInactiveAccounts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;nx&#34;&gt;Public&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;AccountList&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;   &lt;span class=&#34;nx&#34;&gt;getOverdrawnAccounts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;CQRS模式简单地将这个单一的服务分成两个不同的独立的可扩展服务:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;AccountChangeService&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;createAccount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;acctMetadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;debitAccount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;amount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Public&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;creditAccount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;amount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&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=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;AccountReaderService&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Public&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Account&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;getAccount&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Public&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;AccountList&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;getInactiveAccounts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Public&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;AccountList&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;getOverdrawnAccounts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&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;p&gt;那么，为什么我们要把事件驱动的架构和简单的CQRS模式结合起来，有什么好处呢？&lt;/p&gt;
&lt;p&gt;考虑一下：通常情况下，使用数据库中，你会从数据设计和数据模型开始。该设计中的决策会影响到所有的上游服务和处理流程，因为它必须在数据模型的约束下工作。这种思维将数据直接放在架构的中心位置，而不是事件。&lt;/p&gt;
&lt;p&gt;如果把命令操作，如创建、更新和删除等命令操作从查询中分离出来，那么基本上就可以把改变领域状态的事件和不改变域状态的查询分离出来。正是这些事件让你的思维回到了事件是架构的重点，也是最自然的领域建模方式。&lt;/p&gt;
&lt;p&gt;巨大的优势在于，你可以很容易地将这些领域变化事件推送到新的微服务中（轻易地增加新的功能和特性），或者进入大数据的世界（在这里可以进行分析并进行新的发现）。&lt;/p&gt;
&lt;p&gt;对于我们银行的例子来说，新功能的例子是为一张新的银行信用卡实施一个营销活动。使用EDA和CQRS可以很容易地消费账户创建事件，并根据acctMetadata（如开户余额、地址、工作等）向新客户营销银行信用卡。&lt;/p&gt;
&lt;p&gt;使用CQRS确实牺牲了一致性，但提高了性能和可用性，正如前面提到的，拥抱最终的一致性为大多数用例减轻了这种担忧。&lt;/p&gt;
&lt;h2 id=&#34;集成事件驱动架构&#34;&gt;集成事件驱动架构&lt;/h2&gt;
&lt;p&gt;企业中充斥着大量的事件和数据存储，其中包含着改变游戏规则的潜力。不要让事件驱动的微服务架构之外的世界把你拉回命令式的交互，或者更糟糕的是（瑟瑟发抖）批处理，这一点真的很重要。这个理念对于已经是事件驱动的系统和设备来说是直截了当的，但对于以数据库为中心的系统来说就不是这样了。&lt;/p&gt;
&lt;p&gt;帮助微服务与以数据为中心的传统系统共存的一种方法是在底层数据库上实现变更数据捕获（change data  capture/CDC）。这种技术在Oracle数据库中的一个例子是利用CDC工具Golden Gate。当事件发生时，它们被写入数据库。通过捕获这些变化并将其作为事件处理，可以在微服务平台中利用它们。这消除了对现有系统的任何影响，也消除了对昂贵代码的修改需求。这里的大部分工作是将CDC事件转化为领域数据结构。&lt;/p&gt;
&lt;p&gt;整合现代系统和设备就更容易了。例如，IoT设备本来就是事件驱动的，社交媒体平台是支持流的，甚至许多JEE应用都利用了消息驱动的Bean（MDB），这些都很容易被利用。关键是要避免让集成将你带回到非事件驱动的世界。&lt;/p&gt;
&lt;h2 id=&#34;利用事件&#34;&gt;利用事件&lt;/h2&gt;
&lt;p&gt;现在你了解了EDA可以为后端微服务处理架构带来的力量，你应该考虑将这种力量带到用户体验中去。&lt;/p&gt;
&lt;p&gt;让我们面对现实吧，虽然AJAX提供的用户体验看起来是异步的，但实际上它只是在轮询Web资源。如果轮询时间间隔太长，用户体验就会下降，而且会因为尝试刷新而给系统带来不必要的负荷。&lt;/p&gt;
&lt;p&gt;反之，如果轮询间隔太短，那么真正发生刷新的概率就会很低，再次浪费资源。随着越来越多的用户使用这种网络应用，他们将急剧增加访问这些更新服务的流量（大多数不会返回任何新的结果），并使企业付出更多的成本。&lt;/p&gt;
&lt;p&gt;一个更好的方法是使用异步协议，如MQTT或WebSocket。Web应用程序打开一个连接，订阅用户想要的数据，然后等待事件流向浏览器。用户体验会更好，因为事件是实时到达的，而且它可以为您的业务节省资金，因为带宽和计算资源不会浪费在无意义的请求上。&lt;/p&gt;
&lt;h2 id=&#34;作为dr基石的事件&#34;&gt;作为DR基石的事件&lt;/h2&gt;
&lt;p&gt;让我们来看看航空业在应对IT灾难时的最佳例子。&lt;/p&gt;
&lt;p&gt;在过去的几年里，成千上万的乘客误机，不是因为恐怖主义、地缘政治或疾病爆发，而是因为IT故障的层层叠叠影响。在很多情况下，系统设计不当。在另一些情况下，他们的灾难恢复系统构思不周，或者花了太多时间来做他们的事情。&lt;/p&gt;
&lt;p&gt;这直接关系到事件驱动微服务。事件可以很容易地复制到其他活动或灾难恢复站点，因此系统始终处于同步状态，随时准备采取行动。从历史上看，这是在数据存储层面完成的，每个数据库类型都使用自己的复制机制。&lt;/p&gt;
&lt;p&gt;这很复杂，因为它涉及到许多组件和不同的策略。这也非常昂贵，因为在许多情况下，同一事件被存储在多个地点。围绕事件而不是数据来设计系统的一个很大的边际效应就是让业务能够在可能发生灾难性的情况下继续执行，就像什么都没发生过一样。&lt;/p&gt;
&lt;h2 id=&#34;使用与供应商无关的标准api或协议来处理事件&#34;&gt;使用与供应商无关的标准API或协议来处理事件&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;“The existing business ecosystem is the unavoidable burden that most businesses must deal with when they start their microservices journey.”&lt;/p&gt;
&lt;p&gt;&amp;ldquo;现有的业务生态体系是大多数企业在开始微服务之旅时必须要面对的不可避免的负担。&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;利用云提供商的事件/消息产品如AWS的SQS/SNS、谷歌云Pub/Sub、Azure Service Bus等，或者专有事件传输解决方案如Apache Kafka、IBM MQ和TIBCO EMS，似乎很有吸引力。但这种方法存在着多种问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;锁定。当由于技术或业务原因想离开这个解决方案时，问题就会出现。这需要大量的投资来撤销这个错误，因为几乎所有的服务和业务都是如此。集成受影响。&lt;/li&gt;
&lt;li&gt;缺少API。微服务的一个主要优点是它不规定使用什么编程语言，专有的API通常只支持一小部分语言，因此限制了灵活性和选择。&lt;/li&gt;
&lt;li&gt;抑制创新。微服务的另一个好处是随着行业和产品的发展而使用新技术和新工艺的能力。由于转换成本太高，被锁定在一个供应商的专有API中，可能意味着你被锁定在创新之外。听起来和单体应用的问题差不多!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当选择事件/消息平台的实现时，重要的是确保它支持标准API，如Spring、JMS、NMS、Paho和Qpid，如MQTT和AMQP v1.0。&lt;/p&gt;
&lt;p&gt;THE BARRIERS BETWEEN YOU AND EVENT-DRIVEN MICROSERVICES&lt;/p&gt;
&lt;h2 id=&#34;跨越你和事件驱动微服务之间的障碍&#34;&gt;跨越你和事件驱动微服务之间的障碍&lt;/h2&gt;
&lt;p&gt;只要架构师和开发人员拥抱成功所需的心态，EDA就有巨大的潜力。挑战在于缺乏在微服务背景下实现EDA的工具。&lt;/p&gt;
&lt;p&gt;工具化不是现代的、执行力强的、开放的或稳定的。它也不能在业务需求所决定的配置中部署，例如在本地和/或各种公共云中部署。它们不提供跨广域网络的联邦、同步或恢复。最后，API管理/网关解决方案根本就不适合于事件驱动的微服务。有7个原因：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;缺少现代化&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;消息本身已经存在了很长时间。15年前，还没有敏捷开发&amp;ndash;瀑布流统治了整个时代，消息基础设施由专门的团队管理。今天，DevOps的概念及其相关的敏捷性意味着开发人员不能等待消息基础设施的安装、配置和数据变得可用。一切都必须自动化、DevOps友好和自服务。这意味着，虽然消息是正确的工具，但这些工具已经不能满足今天的敏捷需要和需求。这一点被微服务架构承诺的速度、规模和敏捷性放大了。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;高且不可预测的延迟&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;随着单体应用被分解成离散的服务，有一个点：延迟会增加，性能会降低，影响用户体验和满足SLA的能力。事件/消息平台需要尽可能的低延迟，这直接影响到最终实施的成功与否。当这种情况发生时，初始的反应是反其道而行之，构建更大的、更单一的、可重用性更低的敏捷服务，以减少网络跳转，从而减少延迟。这一步完全取消了微服务的众多好处，但在许多情况下，企业由于专有的API和线路的原因被锁定，因此走的是阻力最小的道路。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;专有协议和API&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;几年前，没有任何标准的线路或协议，所以IBM、TIBCO和其他企业消息公司都实施了自己的协议。今天，他们这样做是因为他们（是的！）担心开放的标准会增加竞争，并使他们的客户很容易放弃他们的产品，因为竞争者提供创新和差异化的产品。大多数厂商最多只实现了单一标准的线路或开放的API，从而限制了可以实现微服务的语言，并排除了更大的事件生态系统，例如IoT设备的事件。这降低了微服务提供的整体价值和敏捷性，并导致了旨在统一数据移动的集成片。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;稳定性差&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;没有任何服务能实现100%的可用性，没有任何系统会在任何时候都能完美运行。服务内的Bug、网络中断和有害信息都是如何拖慢服务或给微服务生态系统带来负担的真实例子。当这些异常事件发生时，作为架构师，我们期望我们的基础服务，如消息等，能经受住风暴的考验，缓冲请求，确保数据不丢失。事实证明，在这些场景发生之前，许多消息系统都能很好地工作。换句话说，当情况变得艰难时，它们会让我们失望。具有讽刺意味的是，这正是我们最需要它们的时候。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可部署性风险&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;云提供商都有消息/事件平台，而这些平台无法部署到竞争对手的云上，也无法部署到许多企业维护核心业务功能的场所。传统的消息系统不能轻易地部署到云环境中，有的根本无法部署到云环境中，因为它们使用的是多播系统。鉴于当今云战略不断发展的气候，部署性是一个重要的考虑因素。当决定转向混合和/或多云架构时，迁移的痛苦可能是巨大的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;广域网的弱点&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;混合云和多云架构的使用极为普遍，无论从经济性还是业务连续性来说，都是非常普遍的。所有这些策略都要求事件以可靠、安全和性能良好的方式在广域网上传播。由于传统的消息产品最初是在数据中心环境中使用的，因此它们对抖动和往返时间慢等常见的广域网属性响应较差。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;API管理/网关 - 错的工具&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;API管理/网关领域正在蓬勃发展。这个组件是必要的，因为在许多情况下，B2B和Web应用需要使用REST/HTTP等Web友好的API进行集成。这些交互，其中代表领域变化事件的交互必须快速转化为事件，以便于下游处理。API管理和网关根本没有尝试在微服务之间启用事件驱动的交互，也没有启用多种异步协议将事件流转到Web应用中。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;结论&#34;&gt;结论&lt;/h2&gt;
&lt;p&gt;虽然事件驱动的微服务起初看起来很困难，但它们是大多数微服务和IT战略的未来。选择合适的事件/消息平台是实现微服务的巨大优势的道路上最关键的步骤之一。&lt;/p&gt;
&lt;p&gt;架构师和开发人员需要一个经过工程设计的平台，这个平台能在当今这个快速发展的现代世界中茁壮成长。作为现代事件化平台设计，Solace可以在每一个云和PaaS中部署，并且可以轻松跨越广域网。它支持DevOps自动化，并为开发者提供了几乎完整的自助服务体验。Solace是唯一一个稳定且性能优异的解决方案，能够满足微服务架构师的独特需求。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;译者注：最后一段广告味道太重了&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>[译] 微服务协调与编排：协调的好处</title>
      <link>https://skyao.net/post/202004-microservices-choreography-vs-orchestration/</link>
      <pubDate>Wed, 01 Apr 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202004-microservices-choreography-vs-orchestration/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://solace.com/blog/microservices-choreography-vs-orchestration/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Microservices Choreography vs Orchestration: The Benefits of Choreography&lt;/a&gt;，作者 &lt;a href=&#34;https://solace.com/blog/author/jonathan-schabowsky/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt; Jonathan Schabowsky&lt;/a&gt; 。&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;翻译说明：在中文中 Orchestration 通常都翻译为“编排”，这个术语通常为开发人员所熟知，如服务编排，容器编排（k8s）。而 Choreography 的翻译是“编舞/舞蹈编排”，在舞蹈之外的语义中通常也翻译为“编排”。本文为了明确的和 Orchestration 区分开，刻意将 Choreography 翻译为“协调”。并在全文中显示标注协调（Choreography）和编排（Orchestration）以避免误解。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;微服务架构（一种软件设计范式，将应用程序和业务用例分解成一组可组合的服务）为企业组织带来许多技术上的好处。首先，它们小巧、轻便且易于实现。其次，它们实现了可重用性，降低了开发或更改应用程序的成本，确保了资源的有效利用，并使应用程序易于按需扩展。在高层次上，有两种方法可以让微服务朝着一个共同的目标协同工作：协调（Choreography）和编排（Orchestration）。&lt;/p&gt;
&lt;p&gt;编排（Orchestration）需要主动控制所有的元素和交互，就像指挥家指挥乐团的乐手一样，而协调（Choreography）则需要建立一个模式或例程，微服务会跟随音乐起舞，不需要监督和指令。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-microservices-choreography-vs-orchestration/images/Orchestration-VS-Choreography_hu4fa49df069c328916d7531761e754a3e_88968_b12d19951a7530c1379e20c35743034b.webp 400w,
               /post/202004-microservices-choreography-vs-orchestration/images/Orchestration-VS-Choreography_hu4fa49df069c328916d7531761e754a3e_88968_9ff5a077bd899fafe22680c6865d1981.webp 760w,
               /post/202004-microservices-choreography-vs-orchestration/images/Orchestration-VS-Choreography_hu4fa49df069c328916d7531761e754a3e_88968_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-microservices-choreography-vs-orchestration/images/Orchestration-VS-Choreography_hu4fa49df069c328916d7531761e754a3e_88968_b12d19951a7530c1379e20c35743034b.webp&#34;
               width=&#34;760&#34;
               height=&#34;380&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;微服务的采用正在迅速增长，这是由 Dimensional Research 代表 LightStep 进行的 &lt;a href=&#34;https://siliconangle.com/2018/05/02/new-study-shows-rapid-growth-microservices-adoption-among-enterprises/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;一项最新研究&lt;/a&gt; 证明的。该研究发现，几乎所有接受调查的部署过微服务的高级研发利益相关者都希望微服务成为其默认的应用架构。&lt;/p&gt;
&lt;p&gt;研究还指出，微服务的实现还有很多许多挑战 – 很多与微服务如何相互交互来实现业务成果有关。在微服务编舞与编排之间进行选择，将影响到服务在后台无缝运行的方式，以及您是成功构建出微服务架构，还是分布式单体。&lt;/p&gt;
&lt;h2 id=&#34;编排如何杀死微服务并创建分布式单体&#34;&gt;编排如何杀死微服务并创建分布式单体&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-microservices-choreography-vs-orchestration/images/Orchestration-300x300_hua212ade3a28c696241b166ecc06daaac_20879_28bc095ebd709303564776bfce1fb659.webp 400w,
               /post/202004-microservices-choreography-vs-orchestration/images/Orchestration-300x300_hua212ade3a28c696241b166ecc06daaac_20879_fc64f389670b28cd807f5683abd16976.webp 760w,
               /post/202004-microservices-choreography-vs-orchestration/images/Orchestration-300x300_hua212ade3a28c696241b166ecc06daaac_20879_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-microservices-choreography-vs-orchestration/images/Orchestration-300x300_hua212ade3a28c696241b166ecc06daaac_20879_28bc095ebd709303564776bfce1fb659.webp&#34;
               width=&#34;300&#34;
               height=&#34;300&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在乐团中，每个音乐家都在等待指挥家的指令。他们每个人都是演奏乐器的专家，无论是小提琴，低音鼓还是单簧管，他们都久经训练，并拥有活页乐谱 - 但他们还是会在没有指挥的情况下集体迷失。&lt;/p&gt;
&lt;p&gt;在编排（Orchestration）中，服务控制器处理微服务之间的所有通信，并指导每个服务执行预期的功能。在我们的交响乐示例中，功能是“演奏音乐”。&lt;/p&gt;
&lt;h3 id=&#34;微服务编排的缺点&#34;&gt;微服务编排的缺点&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=fvXkN5cFMFY&amp;amp;t=32s&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;编排的一个缺点&lt;/a&gt; 是控制器需要与每个服务直接通信并等待每个服务的响应。现在，这些交互是在网络上发生的，调用会花费更长的时间，并且会受到下游网络和服务可用性的影响。&lt;/p&gt;
&lt;p&gt;在较小的环境中，这可能会工作很好，但是当有数百甚至数千个微服务时，事情就会分崩离析。您基本上已经创建了一个分布式的单体应用程序，它比过去的应用程序更慢，更脆弱！就像指挥家会失去有效管理大型乐团的能力一样，因为每个音乐家都在等待个别的关注，因此要求服务控制来管理这么多微服务是不可行的。&lt;/p&gt;
&lt;h4 id=&#34;紧耦合&#34;&gt;紧耦合&lt;/h4&gt;
&lt;p&gt;当编排（Orchestration）微服务时，你会发现它们彼此高度依赖 - 当它们是同步的，每个服务都必须明确地接收和响应请求，才能使整个服务正常工作，任何一点故障都可能使整个服务停止运行。&lt;/p&gt;
&lt;p&gt;当我们在企业环境中谈论微服务时，有时会有成千上万的微服务应用于单一业务功能。在这种规模下，一对一的交互根本跟不上业务需求。&lt;/p&gt;
&lt;h4 id=&#34;对restful-api的依赖&#34;&gt;对RESTful API的依赖&lt;/h4&gt;
&lt;p&gt;编排（Orchestration）方法也依赖于RESTful API&amp;mdash;通常是以紧密耦合的服务形式创建的，所以使用它们实际上会增加你的架构中的耦合度。此外，构建新功能的成本很高，对API的影响也很大。&lt;/p&gt;
&lt;p&gt;那么，如果RESTful API和编排（Orchestration）架构不能扩展，那么部署和管理微服务的解决方案是什么样子的呢？答案将带我们走出编排的坑，走上人生巅峰&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;使用事件流的协调服务的好处&#34;&gt;使用事件流的协调服务的好处&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202004-microservices-choreography-vs-orchestration/images/Choreography-300x300_hud5e932a4f90e309d649eba1dfa701fb0_22195_913a89f7eb1b6a19e01062de7c6d5129.webp 400w,
               /post/202004-microservices-choreography-vs-orchestration/images/Choreography-300x300_hud5e932a4f90e309d649eba1dfa701fb0_22195_b2cdbbc39f08469311fcb863fab525c5.webp 760w,
               /post/202004-microservices-choreography-vs-orchestration/images/Choreography-300x300_hud5e932a4f90e309d649eba1dfa701fb0_22195_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202004-microservices-choreography-vs-orchestration/images/Choreography-300x300_hud5e932a4f90e309d649eba1dfa701fb0_22195_913a89f7eb1b6a19e01062de7c6d5129.webp&#34;
               width=&#34;300&#34;
               height=&#34;300&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如果说指挥交响乐是服务编排（Orchestration）的一个很好的比喻，那么舞蹈队就很适合协调（Choreography）。在一个舞蹈团队中，每个人都知道自己应该做什么，并且能够（并被要求）在每一个节拍打响时迈出正确的步伐。&lt;/p&gt;
&lt;p&gt;要协调（Choreography）微服务，你需要一种信息交换的方式：在微服务之间每当有事情发生时，就需要在微服务之间交换消息&amp;ndash;你需要 &lt;a href=&#34;https://solace.com/what-is-an-event-broker/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;事件代理&lt;/a&gt;。当给定的微服务发送消息的那一刻，它们就完成了。其他的事情都是以异步的方式发生，不需要等待响应，也不用担心下一步会发生什么。每个服务都在观察它的环境，任何其他订阅了那个消息通道的服务都会从那里知道要做什么。&lt;/p&gt;
&lt;p&gt;在我们的类比中，舞者(微服务)听着音乐(事件代理)，并做出必要的动作，因为他们都在遵循同样的协调（Choreography）。&lt;/p&gt;
&lt;h3 id=&#34;服务松耦合实现敏捷和容错&#34;&gt;服务松耦合，实现敏捷和容错&lt;/h3&gt;
&lt;p&gt;在协调（Choreography）好的微服务架构中，添加和删除服务要简单得多。你需要做的就是将微服务连接（或将其断开）到事件代理中的适当通道（channel）。通过服务松耦合，微服务的添加和删除不会破坏现有的逻辑，从而减少了开发造成的问题。&lt;/p&gt;
&lt;p&gt;协调（Choreography）微服务的事实意味着，如果一个应用出现故障，不依赖它的业务服务可以在问题得到纠正的同时继续进行。同时也不需要每个服务在网络故障时都有复杂的、内置的错误处理，因为这是事件代理的责任。&lt;/p&gt;
&lt;p&gt;使用 RESTful API，错误会导致级联问题。这可能会导致原本可以执行的任务因为单一的通信问题而被阻断，从而导致资源闲置。此外，任何中断都会导致客户失望，并有可能导致业务损失。&lt;/p&gt;
&lt;h3 id=&#34;更快更敏捷的开发&#34;&gt;更快更敏捷的开发&lt;/h3&gt;
&lt;p&gt;在这个快节奏的环境中，产品上市的时间至关重要，开发和修改应用程序的速度会对业务产生严重影响。开发团队敏捷性的一个常见障碍是容易受到其他服务变化的影响。协调（Choreography）好的、事件驱动的微服务允许开发团队更独立地运作，专注于关键服务。一旦这些服务被创建出来后，它们就可以很容易在团队之间共享。这种对已开发组件的重用，可以大大节省人力和时间。&lt;/p&gt;
&lt;h3 id=&#34;更加一致而高效的应用&#34;&gt;更加一致而高效的应用&lt;/h3&gt;
&lt;p&gt;当创建具有特定功能的微服务时，你可以创建一个更模块化的代码库。每个微服务处理一个特定的业务功能，作为一个单元，它们一起执行业务流程。&lt;/p&gt;
&lt;p&gt;重用这些微服务作为众多业务流程的一部分，这样的能力可以使你的系统保持一致，并使创建或修改服务更容易，因为你可以利用已经被证明可以执行特定功能的代码。&lt;/p&gt;
&lt;h2 id=&#34;让微服务起舞&#34;&gt;让微服务起舞&lt;/h2&gt;
&lt;p&gt;只使用 RESTful API 方式的时代已经过去了&amp;ndash; 对于能够更快、更可靠地提供业务服务，并且能够轻松扩展的架构来说，更好的方法是协调（Choreography）微服务之间的交互。随着事件驱动的架构和微服务席卷了软件开发领域，服务之间的交互方式将为公司节省时间和金钱，同时改善客户体验。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译] 多运行时微服务架构</title>
      <link>https://skyao.net/post/202003-multi-runtime-microservice-architecture/</link>
      <pubDate>Wed, 04 Mar 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202003-multi-runtime-microservice-architecture/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://www.infoq.com/articles/multi-runtime-microservice-architecture/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Multi-Runtime Microservices Architecture&lt;/a&gt;，作者 &lt;a href=&#34;http://ofbizian.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Bilgin Ibryam&lt;/a&gt;，由 &lt;a href=&#34;https://www.infoq.com/profile/Daniel-Bryant/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Daniel Bryant&lt;/a&gt; 复审。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;重点&#34;&gt;重点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;创建分布式系统并非易事。围绕“微服务”架构和“ 12要素应用程序”设计有很多最佳实践。提供了与交付生命周期，网络，状态管理以及绑定外部依赖有关的准则。&lt;/li&gt;
&lt;li&gt;然后，始终一致地实施这些原则，尤其是以可扩展和可维护的方式，是非常具有挑战性的。&lt;/li&gt;
&lt;li&gt;参照这些原理，传统的以技术为中心的方法包括企业服务总线（Enterprise Service Bus/ESB）和面向消息的中间件（Message-Oriented Middleware/MOM）。虽然这些解决方案提供了良好的功能集，但主要的挑战是单体架构以及业务逻辑和平台之间的紧密技术耦合。&lt;/li&gt;
&lt;li&gt;随着云，容器和容器编排器（Kubernetes）的流行，参照这些原理的新解决方案应运而生。例如，用于交付的Knative，用于网络的服务网格以及用于绑定和集成的Camel-K。&lt;/li&gt;
&lt;li&gt;使用这种方法，业务逻辑（称为“微逻辑/micrologic”）构成了应用程序的核心，然后创建sidecar“ mecha”组件，提供强大的开箱即用的分布式原语。&lt;/li&gt;
&lt;li&gt;微逻辑（micrologic）组件和机制（mecha）组件的解耦可以改善运维，例如打补丁和升级，并有助于维持业务逻辑内聚单元的长期可维护性。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;创建良好的分布式应用程序并非易事：此类系统通常遵循12要素应用和微服务原则。它们必须是无状态的，可伸缩的，可配置的，独立发布的，容器化的，可自动化的，并且有时是事件驱动的和serverless的。创建后，它们应该易于升级，并且长期可维护的。在当今的技术中，要在这些相互竞争的要求之间找到良好的平衡仍然是一项艰巨的努力。&lt;/p&gt;
&lt;p&gt;在本文中，我将探讨分布式平台如何发展以实现这种平衡，更重要的是，在分布式系统的发展中还需要哪些东西，以简化可维护的分布式体系架构的创建。如果您想看到我实时谈论这个话题，请加入我三月的 &lt;a href=&#34;https://qconlondon.com/london2020/presentation/kubernetes-and-cloud-architectures-1&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;QCon&lt;/a&gt; 伦敦。&lt;/p&gt;
&lt;h2 id=&#34;分布式应用的需求&#34;&gt;分布式应用的需求&lt;/h2&gt;
&lt;p&gt;在此讨论中，我将把现代分布式应用的需求分为四种类型（生命周期，网络，状态，绑定）并简要分析它们在最近几年中的发展情况。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202003-multi-runtime-microservice-architecture/images/four-needs-of-app_hu3828c8b408219066fbc7297d21b025bb_65201_99ca95c76cf713ff68b71dec9a71bced.webp 400w,
               /post/202003-multi-runtime-microservice-architecture/images/four-needs-of-app_hu3828c8b408219066fbc7297d21b025bb_65201_44aec79d495406c31bf4dae74098c023.webp 760w,
               /post/202003-multi-runtime-microservice-architecture/images/four-needs-of-app_hu3828c8b408219066fbc7297d21b025bb_65201_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202003-multi-runtime-microservice-architecture/images/four-needs-of-app_hu3828c8b408219066fbc7297d21b025bb_65201_99ca95c76cf713ff68b71dec9a71bced.webp&#34;
               width=&#34;760&#34;
               height=&#34;409&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;（图：分布式应用程序需求）&lt;/p&gt;
&lt;h3 id=&#34;生命周期lifecycle&#34;&gt;生命周期（Lifecycle）&lt;/h3&gt;
&lt;p&gt;让我们从基础开始。当我们编写功能时，编程语言会指定生态系统中的可用库，打包格式和运行时。例如，Java使用.jar格式，用作生态系统的所有Maven依赖项，还有JVM用作运行时。如今，随着发布周期的缩短，生命周期中更重要的是自动化能力：能够部署，从错误中恢复以及扩展服务。这组功能广泛地代表了我们的应用生命周期需求。&lt;/p&gt;
&lt;h3 id=&#34;网络networking&#34;&gt;网络（Networking）&lt;/h3&gt;
&lt;p&gt;从某种意义上讲，今天几乎每个应用都是分布式应用，因此需要网络。但是现代分布式系统需要从更广泛的角度掌握网络。从服务发现和错误恢复开始，到启用现代软件发布技术，以及各种跟踪和遥测。为了我们的目的，我们甚至将不同的消息交换模式，点对点和发布/订阅方法，以及智能路由机制包括在此类别中。&lt;/p&gt;
&lt;h3 id=&#34;状态state&#34;&gt;状态（State）&lt;/h3&gt;
&lt;p&gt;当我们谈论状态时，通常是关于服务状态以及为什么最好是无状态的。但是管理我们服务的平台本身是需要状态的。这是执行可靠的服务编排和工作流，分布式单例，临时调度（cron作业），幂等，有状态错误恢复，缓存等所需的。这里列出的所有功能都依赖于底层的状态。尽管实际的状态管理不在本文讨论范围之内，但依赖状态的分布式原语及其抽象却令人关注。&lt;/p&gt;
&lt;h3 id=&#34;捆绑binding&#34;&gt;捆绑（Binding）&lt;/h3&gt;
&lt;p&gt;分布式系统的组件不仅必须彼此对话，而且还必须与现代或旧式外部系统集成。这就要求连接器能够转换各种协议，支持不同的消息交换模式，例如轮询，事件驱动，请求/答复，转换消息格式，甚至能够执行自定义错误恢复过程和安全机制。&lt;/p&gt;
&lt;p&gt;在不涉及一次性使用案例的情况下，以上内容代表了创建良好的分布式系统所需的通用原语的良好集合。今天，许多平台都提供了这样的功能，但是我们在本文中探寻的是过去十年中我们使用这些功能的方式是如何变化的，以及在下一个十年中它将如何变化。为了进行比较，让我们看一下过去的十年，看看基于Java的中间件如何满足这些需求。&lt;/p&gt;
&lt;h2 id=&#34;传统中间件限制&#34;&gt;传统中间件限制&lt;/h2&gt;
&lt;p&gt;在满足上述需求的上一代传统解决方案，众所周知的是企业服务总线（ESB）及其变体（例如面向消息的中间件，更轻量级的集成框架等）。ESB是一种中间件，可以使用面向服务的架构（即经典SOA）在异构环境之间实现互操作性。&lt;/p&gt;
&lt;p&gt;虽然ESB将为您提供良好的功能集，但ESB的主要挑战是单体架构以及业务逻辑和平台之间紧密的技术耦合，从而导致了技术和组织的中心化。开发并部署服务到这样的系统中时，与分布式系统框架紧密耦合，从而限制了服务的发展。这通常只会在软件生命周期的后期才变得明显。&lt;/p&gt;
&lt;p&gt;以下是每种需求的问题和局限性，这些导致ESB在现在不再有用。&lt;/p&gt;
&lt;h3 id=&#34;生命周期lifecycle-1&#34;&gt;生命周期（Lifecycle）&lt;/h3&gt;
&lt;p&gt;在传统的中间件中，通常只有一个受支持的语言运行时（例如Java），它规定了软件的打包方式，可用的库，需要修补的频率等。业务服务必须使用这些库。使其与以相同语言编写的平台紧密结合。实际上，这导致服务和平台升级被关联起来，从而阻止了独立和常规的服务和平台发布。&lt;/p&gt;
&lt;h3 id=&#34;网络networking-1&#34;&gt;网络（Networking）&lt;/h3&gt;
&lt;p&gt;尽管传统中间件也具有围绕与其他内部和外部服务交互的高级功能集，但它有一些主要缺点。网络功能集中于一种主要语言及其相关技术。对于Java语言，即JMS，JDBC，JTA等。更重要的是，网络问题和语义也深深地刻在业务服务中。有一些具有抽象的库来处理网络问题（例如曾经很受欢迎的Hystrix项目），但是该库的抽象也“泄漏”到了服务的编程模型，交换模式和错误处理语义以及库本身中。虽然可以方便地在一个位置编写和读取与网络方面混合的整个业务逻辑，但是这将两个问题紧密地耦合到实现中，最终形成了共同的演进路径。&lt;/p&gt;
&lt;h3 id=&#34;状态state-1&#34;&gt;状态（State）&lt;/h3&gt;
&lt;p&gt;为了进行可靠的服务编排，业务流程管理以及实现模式（例如Saga模式和其他运行缓慢的流程），平台需要在幕后持久化状态。同样，临时动作（例如触发计时器和cron作业）建立在状态之上，并且需要在分布式环境中对数据库进行集群和恢复。这里的主要约束是以下事实：与状态交互的库和接口没有完全抽象出来，也没有与服务运行时解耦。通常，这些库必须配置有数据库详细信息，并且它们存在于服务中，从而将语义和依赖关系泄漏到应用域中。&lt;/p&gt;
&lt;h3 id=&#34;绑定binding&#34;&gt;绑定（Binding）&lt;/h3&gt;
&lt;p&gt;使用集成中间件的主要驱动力之一是能够使用不同的协议，数据格式和消息交换模式连接到其他各种系统。但是，这些连接器必须与应用程序一起使用，这意味着必须将依赖关系与业务逻辑一起更新和修补。这意味着必须在服务中来回转换数据类型和数据格式。这意味着必须根据消息交换模式来构造代码并设计流程。即使是抽象的端点也会影响传统中间件中的服务实现，有很多这方面的例子。&lt;/p&gt;
&lt;h2 id=&#34;云原生趋势&#34;&gt;云原生趋势&lt;/h2&gt;
&lt;p&gt;传统的中间件功能强大。它具有所有必要的技术功能，但缺乏现代数字业务需求所要求的快速更改和扩展的能力。这就是微服务架构及其设计现代分布式应用的指导原则所要解决的问题。&lt;/p&gt;
&lt;p&gt;微服务背后的思想及其技术要求促进了容器和Kubernetes的普及和广泛使用。这开始了一种新的创新方式，这种方式将影响我们今后几年处理分布式应用程序的方式。让我们看看Kubernetes和相关技术如何影响每种需求。&lt;/p&gt;
&lt;h3 id=&#34;生命周期lifecycle-2&#34;&gt;生命周期（Lifecycle）&lt;/h3&gt;
&lt;p&gt;容器和Kubernetes将打包，分发和部署应用的方式发展为与语言无关的格式。关于&lt;a href=&#34;http://k8spatterns.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Kubernetes模式&lt;/a&gt;和&lt;a href=&#34;https://www.infoq.com/articles/kubernetes-effect&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Kubernetes影响&lt;/a&gt;开发人员的文章有很多，在这里我将简短介绍。但是请注意，对于Kubernetes，要管理的最小原语是容器，它专注于在容器级别和流程模型上交付分布式原语。这意味着它在管理应用的生命周期，健康检查，恢复，部署和扩展方面做得很出色，但是在容器内的分布式应用的其他方面却没有做得很好，例如灵活的网络，状态管理和绑定。&lt;/p&gt;
&lt;p&gt;您可能会指出，Kubernetes具有有状态工作负载，服务发现，cron作业和其他功能。的确如此，但是所有这些原语都是在容器级别的，并且在容器内部，开发人员仍然必须使用特定于语言的库来访问我们在本文开头列出的更详细的功能。这就是推动诸如Envoy，Linkerd，Consul，Knative，Dapr，Camel-K等项目的原因。&lt;/p&gt;
&lt;h3 id=&#34;网络networking-2&#34;&gt;网络（Networking）&lt;/h3&gt;
&lt;p&gt;事实证明，Kubernetes提供的围绕服务发现的基本网络功能是一个很好的基础，但对于现代应用来说还不够。随着微服务数量的增加和部署速度的加快，在不改动服务的情况下，对更高级的发布策略，管理安全性，指标，跟踪，从错误中恢复，模拟错误等等方面的需求变得越来越具有吸引力，并产生了一种新的软件类别，称为服务网格。&lt;/p&gt;
&lt;p&gt;这里更令人兴奋的是，趋势是将与网络相关的问题从包含业务逻辑的服务中移出，放到单独的运行时（无论是sidecar还是节点级代理）。如今，服务网格可以执行高级路由，帮助测试，处理某些方面的安全性，甚至可以使用特定于应用的协议（例如，Envoy支持Kafka，MongoDB，Redis，MySQL等）。尽管服务网格作为一种解决方案可能尚未得到广泛采用，但它触及了分布式系统中的真正痛点，我相信它将找到其形状和存在形式。&lt;/p&gt;
&lt;p&gt;除了典型的服务网格外，还有其他项目，例如&lt;a href=&#34;https://skupper.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Skupper&lt;/a&gt;，这些项目证实了将网络功能放入外部运行时代理的趋势。Skupper通过7层虚拟网络解决了多集群通信难题，并提供了高级的路由和连接能力。但是，它没有将Skupper嵌入到业务服务运行时中，而是在每个Kubernetes命名空间中运行一个实例，该实例充当共享的Sidecar。&lt;/p&gt;
&lt;p&gt;综上所述，容器和Kubernetes在应用生命周期管理方面迈出了重要的一步。服务网格和相关技术遇到了真正的痛点，并为将更多职责从应用程序移到代理中奠定了基础。让我们看看下一步。&lt;/p&gt;
&lt;h3 id=&#34;状态state-2&#34;&gt;状态（State）&lt;/h3&gt;
&lt;p&gt;我们在前面列出了依赖状态的主要集成原语。管理状态非常困难，应将其委派给专门的存储软件和托管服务。这不是今天的主题，而是在语言无关的抽象中使用状态来帮助集成的用例。今天，许多努力试图在语言无关的抽象后面提供有状态的原语。有状态的工作流管理是基于云的服务中的强制性功能，例如AWS Step Functions，Azure Durable Functions等示例。在基于容器的部署中，&lt;a href=&#34;https://github.com/cloudstateio/cloudstate&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;CloudState&lt;/a&gt;和&lt;a href=&#34;https://dapr.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dapr&lt;/a&gt;都依赖于sidecar模型来提供对分布式应用的状态抽象的更好的解耦。&lt;/p&gt;
&lt;p&gt;我也期待将上面列出的所有有状态功能抽象到一个单独的运行时中。这意味着工作流管理，单例，幂等，事务管理，cron作业触发器和有状态错误处理都可靠地发生在Sidecar（或主机级代理）中，而不是存在于服务中。业务逻辑不需要在应用中包含此类依赖关系和语义，并且可以从绑定环境中声明性地请求此类行为。例如，Sidecar可以充当cron作业触发器，幂等消费者和工作流管理器，而自定义业务逻辑可以作为回调调用或作为某些阶段插入到工作流，错误处理，临时调用或唯一幂等需求中。&lt;/p&gt;
&lt;p&gt;另一个有状态用例是缓存。无论是通过服务网格层执行请求缓存，还是使用Infinispan，Redis，Hazelcast等之类的数据缓存，都有一些将缓存功能推到应用运行时之外的&lt;a href=&#34;https://dzone.com/articles/where-is-my-cache-architectural-patterns-for-cachi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;示例&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id=&#34;绑定binding-1&#34;&gt;绑定（Binding）&lt;/h3&gt;
&lt;p&gt;尽管我们的主题是将所有分布式需求与应用运行时解耦，但这种趋势也伴随着绑定。连接器，协议转换，消息转换，错误处理和安全中介都可以移出服务运行时。我们还没有到那里，但是在诸如&lt;a href=&#34;https://cloud.google.com/knative/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Knative&lt;/a&gt;和Dapr之类的项目中已经在朝这个方向进行尝试。将所有这些职责移出应用运行时将导致更小，更专注于业务逻辑的代码。这样的代码将在运行时中运行，运行时独立于分布式系统需求，而分布式系统需求可以作为预先打包好的功能使用。&lt;/p&gt;
&lt;p&gt;Apache &lt;a href=&#34;https://camel.apache.org/camel-k/latest/index.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Camel-K&lt;/a&gt;项目采用了另一种有趣的方法。该项目没有使用代理运行时来伴随主应用，而是依靠智能的Kubernetes Operator，用Operator来构建具有Kubernetes和Knative的附加平台功能的应用运行时。在这里，单个代理是Operator，负责包含应用所需的分布式系统原语。不同之处在于，某些分布式原语已添加到应用运行时中，而某些在平台中启用（也可能包括Sidecar）。&lt;/p&gt;
&lt;h2 id=&#34;未来架构趋势&#34;&gt;未来架构趋势&lt;/h2&gt;
&lt;p&gt;概括地说，我们可以得出结论，通过将功能部件转移到平台级别，分布式应用的商品化达到了新的高度。除了生命周期之外，现在我们还可以观察到网络，状态抽象，声明性事件和端点绑定（现成可用），还有随后的 EIP（译者注：EIP应该是Enterprise Integration Patterns/企业集成模式）。有趣的是，商品化使用进程外模型（sidecar）进行功能扩展，而不是使用运行时库或纯平台功能（例如新的Kubernetes功能）。&lt;/p&gt;
&lt;p&gt;现在，我们正在通过将所有传统的中间件功能（如ESB）移至其他运行时来全面发展，不久之后，我们在服务中要做的就只是编写业务逻辑。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202003-multi-runtime-microservice-architecture/images/traditional-platform-and-cloudnative-platform_hu18bcab3fc2cc0513aa3cb38bca4a9a66_41954_ac405e1ea67a1f53614791a7900931ba.webp 400w,
               /post/202003-multi-runtime-microservice-architecture/images/traditional-platform-and-cloudnative-platform_hu18bcab3fc2cc0513aa3cb38bca4a9a66_41954_b0a7247ff4212a1a83541c12f81eb695.webp 760w,
               /post/202003-multi-runtime-microservice-architecture/images/traditional-platform-and-cloudnative-platform_hu18bcab3fc2cc0513aa3cb38bca4a9a66_41954_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202003-multi-runtime-microservice-architecture/images/traditional-platform-and-cloudnative-platform_hu18bcab3fc2cc0513aa3cb38bca4a9a66_41954_ac405e1ea67a1f53614791a7900931ba.webp&#34;
               width=&#34;760&#34;
               height=&#34;253&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;（图：传统中间件平台和云原生平台概述）&lt;/p&gt;
&lt;p&gt;与传统的ESB时代相比，这个架构更好的解耦了业务逻辑和平台，但是还没有完全分离。许多分布式原语，如经典的企业集成模式（enterprise integration patterns/EIP）：拆分器，聚合器，过滤器，基于内容的路由器；流处理模式：映射，过滤，折叠，联接，合并，滑动窗口；仍然必须包含在业务逻辑的运行时中，还有许多其他的东西依赖于多个不同且重叠的平台附加组件。&lt;/p&gt;
&lt;p&gt;如果我们把不同领域进行创新的各种云原生项目进行叠加，那么最终将得到下图：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202003-multi-runtime-microservice-architecture/images/multi-runtime-microservices_hua1f4a255ba112f15edcdbd9d3d9253ad_67212_be487e7c712b9c6d801d9bdd971d2d3c.webp 400w,
               /post/202003-multi-runtime-microservice-architecture/images/multi-runtime-microservices_hua1f4a255ba112f15edcdbd9d3d9253ad_67212_cb550f38462519bd510c7ee0efe4f861.webp 760w,
               /post/202003-multi-runtime-microservice-architecture/images/multi-runtime-microservices_hua1f4a255ba112f15edcdbd9d3d9253ad_67212_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202003-multi-runtime-microservice-architecture/images/multi-runtime-microservices_hua1f4a255ba112f15edcdbd9d3d9253ad_67212_be487e7c712b9c6d801d9bdd971d2d3c.webp&#34;
               width=&#34;760&#34;
               height=&#34;235&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;（图：多运行时微服务）&lt;/p&gt;
&lt;p&gt;上图仅用于说明，它有目的地选择了代表性的项目并将其映射到分布式原语的分类。实际上，您不会同时使用所有这些项目，因为其中一些项目是重叠的，且工作负载模型不兼容。如何解释这个图？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kubernetes和容器在多语言应用的生命周期管理中取得了巨大飞跃，并为未来的创新奠定基础。&lt;/li&gt;
&lt;li&gt;服务网格技术通过高级网络功能在Kubernetes上进行了改进，并开始涉足应用方面。&lt;/li&gt;
&lt;li&gt;尽管Knative通过快速扩展主要专注于serverless工作负载，但它也满足了服务编排和事件驱动的绑定需求。&lt;/li&gt;
&lt;li&gt;Dapr以Kubernetes，Knative和Service Mesh的思想为基础，并深入应用运行时以解决有状态的工作负载，绑定和集成需求，充当现代化分布式中间件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;该图可帮助您直观地看到，很可能在将来，我们最终将使用多个运行时来实现分布式系统。多个运行时，不是因为有多个微服务，而是因为每个微服务都将由多个运行时组成，最有可能是两个运行时-自定义业务逻辑运行时和分布式原语运行时。&lt;/p&gt;
&lt;h2 id=&#34;引入多运行时微服务&#34;&gt;引入多运行时微服务&lt;/h2&gt;
&lt;p&gt;这是正在形成的多运行时微服务架构的简要说明。&lt;/p&gt;
&lt;p&gt;您还记得电影《阿凡达》和科学家们制作的用于去野外探索潘多拉的 Amplified Mobility Platform (AMP)“机车服”吗？这个多运行时架构类似于这些 &lt;a href=&#34;https://en.wikipedia.org/wiki/Mecha&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Mecha&lt;/a&gt;-套装，为类人驾驶员赋予超能力。在电影中，您要穿上套装才能获得力量并获得破坏性武器。在这个软件架构中，您将拥有构成应用核心的业务逻辑（称为微逻辑/micrologic）和提供强大的开箱即用的分布式原语的sidecar mecha组件。Micrologic与mecha功能相结合，形成多运行时微服务，该服务将进程外功能用于其分布式系统需求。最棒的是，Avatar 2即将面世，以帮助推广这种架构。我们最终可以在所有软件会议上用令人赞叹的机甲图片代替老式的边车摩托车；-)。接下来，让我们看看该软件架构的详细信息。&lt;/p&gt;
&lt;p&gt;这是一个类似于客户端-服务器体系结构的双组件模型，其中每个组件都是独立的运行时。它与纯客户端-服务器架构的不同之处在于，这两个组件都位于同一主机上，彼此之间有可靠的网络连接。这两个组件的重要性相当，它们可以在任一方向上发起操作并充当客户端或服务器。其中的一个组件称为Micrologic，拥有非常少的业务逻辑，把几乎所有分布式系统问题都剥离出去了。另一个伴随的组件是Mecha，提供了我们在本文中一直讨论的所有分布式系统功能（生命周期除外，它是平台功能）。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202003-multi-runtime-microservice-architecture/images/multi-runtime-microservices-architecture_huf1af746a9380c447db35c511e78522a9_71845_7f0ed7a79a48632654f467b5b9506fc9.webp 400w,
               /post/202003-multi-runtime-microservice-architecture/images/multi-runtime-microservices-architecture_huf1af746a9380c447db35c511e78522a9_71845_b0b8d242203ca033f4eb4276bab12c29.webp 760w,
               /post/202003-multi-runtime-microservice-architecture/images/multi-runtime-microservices-architecture_huf1af746a9380c447db35c511e78522a9_71845_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202003-multi-runtime-microservice-architecture/images/multi-runtime-microservices-architecture_huf1af746a9380c447db35c511e78522a9_71845_7f0ed7a79a48632654f467b5b9506fc9.webp&#34;
               width=&#34;760&#34;
               height=&#34;328&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;（图：多运行时（进程外）微服务架构）&lt;/p&gt;
&lt;p&gt;Micrologic 和 Mecha 可以是一对一部署（称为sidecar模型），也可以是多个Micrologic运行时共享一个Mecha。第一种模型最适用于Kubernetes等环境，而后者适用于边缘部署。&lt;/p&gt;
&lt;h3 id=&#34;micrologic运行时特征&#34;&gt;Micrologic运行时特征&lt;/h3&gt;
&lt;p&gt;让我们简要地探讨Micrologic运行时的一些特征：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Micrologic组件本身不是微服务。它包含微服务将具有的业务逻辑，但是该逻辑只能与Mecha组件结合使用。另一方面，微服务是自包含的，不会把整体功能的一部分或者一部分处理流程扩展到其他运行时中。Micrologic和Mecha的组合形成微服务。&lt;/li&gt;
&lt;li&gt;这也不是 function 或 serverless 架构。Serverless中最著名的是其托管的快速扩展和收缩到零的功能。在serverless架构中，function 实现单个操作，作为可伸缩性的单位。在这方面，function 不同于实现多种操作的Micrologic，但实现方式不是端到端的。最重要的是，操作的实现分布在Mecha和Micrologic运行时上。&lt;/li&gt;
&lt;li&gt;这是客户端-服务器架构的一种特殊形式，针对无需编码即可使用的众所周知的分布式原语进行了优化。另外，如果我们假设Mecha扮演服务器角色，那么每个实例都必须经过专门配置以便和单个客户端一起工作。它不是典型的客户端-服务器架构中的通用服务器实例，这种服务器实例旨在同时支持多个客户端。&lt;/li&gt;
&lt;li&gt;Micrologic中的用户代码不会直接与其他系统交互，也不会实现任何分布式系统原语。它通过事实上的标准（例如HTTP/gRPC，&lt;a href=&#34;https://github.com/cloudevents&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;CloudEvents&lt;/a&gt;规范）与Mecha进行交互，而Mecha使用丰富的功能与其他系统进行通信，通讯是在配置的步骤和机制的指导下进行。&lt;/li&gt;
&lt;li&gt;尽管Micrologic仅负责实现从分布式系统问题中剥离出来的业务逻辑，但它仍必须至少实现一些API。它必须允许Mecha和平台通过预定义的API和协议与其进行交互（例如，通过遵循Kubernetes部署的云原生&lt;a href=&#34;https://www.redhat.com/en/resources/cloud-native-container-design-whitepaper&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;设计原则&lt;/a&gt;）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;mecha运行时特征&#34;&gt;Mecha运行时特征&lt;/h3&gt;
&lt;p&gt;以下是一些Mecha运行时特征：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mecha是一个通用的，高度可配置的，可重用的组件，提供分布式原语作为现成的能力。&lt;/li&gt;
&lt;li&gt;Mecha的每个实例都必须配置为与单个Micrologic组件一起使用（边车模型），或者配置为与几个组件共享。&lt;/li&gt;
&lt;li&gt;Mecha不对Micrologic运行时做任何假设。它与使用开放协议和格式（例如HTTP/gRPC，JSON，Protobuf，CloudEvents）的多语言微服务甚至单体系统一起使用。&lt;/li&gt;
&lt;li&gt;Mecha以简单的文本格式（例如YAML，JSON）声明式地配置，指示要启用的功能以及如何将其绑定到Micrologic端点。对于特定的API交互，可以为Mechan附加规范，例如&lt;a href=&#34;https://github.com/OAI/OpenAPI-Specification&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;OpenAPI&lt;/a&gt;，&lt;a href=&#34;https://github.com/asyncapi/asyncapi&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;AsyncAPI&lt;/a&gt;，ANSI-SQL等。对于由多个处理步骤组成的有状态工作流，可以使用诸如 &lt;a href=&#34;https://states-language.net/spec.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Amazon State Language&lt;/a&gt; 的规范。对于无状态集成，可以使用与 &lt;a href=&#34;https://github.com/apache/camel-k-runtime/tree/master/camel-k-loader-yaml&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Camel-K YAML DSL&lt;/a&gt; 类似的方法来使用企业集成模式（&lt;a href=&#34;https://www.enterpriseintegrationpatterns.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;EIP&lt;/a&gt;）。这里的关键点是，所有这些都是简单的，基于文本的，声明性的，多语言的定义，Mecha无需编码即可实现。请注意，这些都是未来派的预测，目前，尚无用于有状态编排或EIP的Mechas，但我希望现有的Mechas（Envoy，Dapr，Cloudstate等）很快就会开始添加此类功能。Mecha是应用级的分布式原语抽象层。&lt;/li&gt;
&lt;li&gt;与其依靠多个代理来实现不同的目的（例如网络代理，缓存代理，绑定代理），不如使用一个Mecha提供所有这些能力。一些功能（例如存储，消息持久化，缓存等）的实现将被其他云或本地服务插入并支持。&lt;/li&gt;
&lt;li&gt;某些与生命周期管理有关的分布式系统问题可以由管理平台（例如Kubernetes或其他云服务）提供 ，而Mecha运行时则使用诸如 &lt;a href=&#34;https://github.com/oam-dev/spec&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Open App Model&lt;/a&gt; 这样的通用开放规范。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;这种架构的主要好处是什么&#34;&gt;这种架构的主要好处是什么？&lt;/h3&gt;
&lt;p&gt;好处是业务逻辑和越来越多的分布式系统问题之间的松耦合。软件系统的这两个要素具有完全不同的动态。业务逻辑始终是内部编写的唯一的自定义代码。它经常更改，具体取决于组织优先级和执行能力。另一方面，分布式原语是用来解决这篇文章中列出的问题的那些众所周知的内容。这些由软件供应商开发，并作为库，容器或服务使用。该代码根据供应商的优先级，发布周期，安全补丁，开放源代码管理规则等而更改。这两个组之间几乎不可见并且无法相互控制。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202003-multi-runtime-microservice-architecture/images/coupling-in-different-architectures_hu85888722b51123e0513e2ebaa152324f_39936_f4eecd49bebdb60ffb70b8759ddbfebc.webp 400w,
               /post/202003-multi-runtime-microservice-architecture/images/coupling-in-different-architectures_hu85888722b51123e0513e2ebaa152324f_39936_6ded9a4a8a13dd45ff8b92fe1ea597fb.webp 760w,
               /post/202003-multi-runtime-microservice-architecture/images/coupling-in-different-architectures_hu85888722b51123e0513e2ebaa152324f_39936_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202003-multi-runtime-microservice-architecture/images/coupling-in-different-architectures_hu85888722b51123e0513e2ebaa152324f_39936_f4eecd49bebdb60ffb70b8759ddbfebc.webp&#34;
               width=&#34;760&#34;
               height=&#34;246&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;（图：业务逻辑和分布式系统问题在不同架构中的耦合）&lt;/p&gt;
&lt;p&gt;微服务原理有助于通过有边界的上下文解耦不同的业务领域，每个微服务都可以独立发展。但是微服务架构无法解决业务逻辑与中间件问题耦合在一起带来的困难。对于某些轻度集成用例的微服务，这可能不是一个大因素。但是，如果您的领域涉及复杂的集成（情况越来越普遍），那么遵循微服务原则也无法帮助避免与中间件的耦合。即使中间件表现为包含在微服务中的类库，当您开始迁移和更改这些库时，这种耦合也将显而易见。还有需要的分布式原语越多，与集成平台的耦合就越多。通过预定义的API将中间件作为独立运行时/进程来使用（而不是类库），有助于松散耦合并实现每个组件的独立演化。&lt;/p&gt;
&lt;p&gt;对于供应商来说，这也是分发和维护复杂的中间件软件的更好方法。只要与中间件的交互是通过开放API和标准的进程间通信进行的，软件供应商就可以按照自己的节奏自由发布补丁和升级。消费者可以自由使用他们喜欢的语言，类库，运行时，部署方法和过程。&lt;/p&gt;
&lt;h3 id=&#34;这种架构的主要缺点是什么&#34;&gt;这种架构的主要缺点是什么？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;进程间通信&lt;/strong&gt;。分布式系统的业务逻辑和中间件机制（您可以看到名称的来源）在不同的运行时中，并且需要HTTP或gRPC调用而不是进程内方法调用。但是请注意，这不是转到其他计算机或数据中心的网络调用。Micrologic运行时和Mecha应该部署在同一主机上，以获得较低的延迟，还有最小化网络出问题的可能性。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;复杂度&lt;/strong&gt;。下一个问题是，为了获得的收益，开发和维护此类系统的复杂度是否值得。我认为答案将越来越倾向于“是”。分布式系统的需求和发布周期的步伐正在增加。而此架构为此进行了优化。我前段时间写道，未来的开发人员必须具备&lt;a href=&#34;https://www.infoq.com/articles/microservices-post-kubernetes&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;混合开发技能&lt;/a&gt;。这种架构进一步证实和加强了这一趋势。应用程序的一部分将使用高级编程语言编写，另一部分功能将由现成的组件提供，必须通过声明式配置。两个部分的互连不是在编译时，或在启动时通过进程内依赖注入，而是在部署时通过进程间通信。此模型可以实现更高的软件重用率和更快的变更速度。&lt;/p&gt;
&lt;h3 id=&#34;微服务不是function会发生什么&#34;&gt;微服务不是Function会发生什么？&lt;/h3&gt;
&lt;p&gt;微服务架构有一个明确的目标。它为变化而优化。通过将应用按照业务域拆分，这个架构通过解耦的，由独立团队进行管理和单独发布的服务，为软件的演进和可维护性提供了最佳的服务边界。&lt;/p&gt;
&lt;p&gt;让我们看一下 serverless 架构的编程模型，它主要基于 function。Function 针对可伸缩性进行了优化。通过 Function，我们将每个操作分解到一个独立的组件，以便可以快速、独立和按需扩展。在此模型中，部署粒度是 function。之所以选择 function，是因为它的代码结构：其输入的速率与缩放行为直接相关。这种架构针对极端可伸缩性进行优化，而不是复杂系统的长期可维护性。&lt;/p&gt;
&lt;p&gt;从AWS Lambda的流行和它完全托管的运维性质来看，Serverless的其他方面又如何呢？在这方面，“ AWS Serverless”为配置速度进行了优化，但缺少控制和锁定功能。但是完全托管不是应用架构，而是软件使用模型。它在功能上是正交的，类似于使用基于SaaS的平台，该平台在理想情况下应适用于任何类型的架构，无论是单体，微服务，mecha还是 Function。在许多方面，AWS Lambda类似于完全托管的Mecha架构，但有一个很大的区别：Mecha不强求 function 模型，而是允许围绕业务域使用更具凝聚力的代码构造，而剥离所有的中间件。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202003-multi-runtime-microservice-architecture/images/architecture-optimizations_hued2128990bd058df94fde70dc4f2a3b2_44703_47f8f8bc82f54c0a7ffe779be59abef4.webp 400w,
               /post/202003-multi-runtime-microservice-architecture/images/architecture-optimizations_hued2128990bd058df94fde70dc4f2a3b2_44703_bf032426e0e4f522eaed7bcd1ab2f7cb.webp 760w,
               /post/202003-multi-runtime-microservice-architecture/images/architecture-optimizations_hued2128990bd058df94fde70dc4f2a3b2_44703_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202003-multi-runtime-microservice-architecture/images/architecture-optimizations_hued2128990bd058df94fde70dc4f2a3b2_44703_47f8f8bc82f54c0a7ffe779be59abef4.webp&#34;
               width=&#34;760&#34;
               height=&#34;330&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;(图：架构优化)&lt;/p&gt;
&lt;p&gt;另一方面，Mecha架构针对中间件独立性优化了微服务。微服务尽管彼此独立，但它们在很大程度上依赖于侵入式分布式原语。Mecha架构将这两个问题分为单独的运行时，从而允许独立团队独立发布它们。这种解耦可以改善 day-2 的运维（例如打补丁和升级），并改善业务逻辑内聚单元的长期可维护性。从这个角度说，Mecha架构是微服务架构的自然演进，它基于引起最大摩擦的边界拆分软件。与function模型相比，该优化以软件重用和演进的形式提供了更多的好处，而 function 模型则为极致的可伸缩性而优化，代价就是代码的过度分布。&lt;/p&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;分布式应用程序有许多需求。创建有效的分布式系统需要多种技术和良好的集成方式。尽管传统的单体中间件提供了分布式系统所需的所有必要技术能力，但它却缺乏业务需要的快速更改，适应和扩展所需的能力。基于微服务的架构背后的思想为容器和Kubernetes的快速普及做出了贡献。随着云原生领域的最新发展，我们现在通过将所有传统中间件功能转移到平台和现成的辅助运行时中来全面发展。&lt;/p&gt;
&lt;p&gt;应用功能的这种商品化主要是使用进程外模型进行功能扩展，而不是运行时类库或纯平台功能。这意味着将来很有可能我们将使用多个运行时来实现分布式系统。多个运行时，不是因为有多个微服务，而是因为每个微服务由多个运行时组成：一个用于自定义微业务逻辑的运行时，以及一个用于分布式原语的现成的可配置运行时。&lt;/p&gt;
&lt;h2 id=&#34;作者介绍&#34;&gt;作者介绍&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202003-multi-runtime-microservice-architecture/images/bilgin-Ibryam_huf6c052dc63b43187a6d3066cfa041e65_10275_928ec9f91e45ef41c0edfdbfea26dc4f.webp 400w,
               /post/202003-multi-runtime-microservice-architecture/images/bilgin-Ibryam_huf6c052dc63b43187a6d3066cfa041e65_10275_77569e30c3946b43b8593b2c2cf42703.webp 760w,
               /post/202003-multi-runtime-microservice-architecture/images/bilgin-Ibryam_huf6c052dc63b43187a6d3066cfa041e65_10275_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202003-multi-runtime-microservice-architecture/images/bilgin-Ibryam_huf6c052dc63b43187a6d3066cfa041e65_10275_928ec9f91e45ef41c0edfdbfea26dc4f.webp&#34;
               width=&#34;85&#34;
               height=&#34;100&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bilgin Ibryam&lt;/strong&gt; 是Red Hat的首席架构师，Apache Software Foundation 的 committer 和成员。他是一个开源的布道师，博客作者，偶尔的演讲者，并且是书籍 Kubernetes Patterns 和 Camel Design Patterns 的作者。在日常工作中，Bilgin乐于指导，编码并带领开发人员成功构建开源解决方案。他目前的工作集中在区块链，分布式系统，微服务，devop和云原生应用开发。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>UDPA最新进展深度介绍</title>
      <link>https://skyao.net/post/202002-udpa-follow-up/</link>
      <pubDate>Mon, 24 Feb 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202002-udpa-follow-up/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;在2019年5月，CNCF 筹建通用数据平面API工作组（Universal Data Plane API Working Group / UDPA-WG)，以制定数据平面的标准API。&lt;/p&gt;
&lt;p&gt;当时我写了一个博客文章 &lt;a href=&#34;../201905-cncf-udpa-wg/&#34;&gt;&amp;ldquo;CNCF正在筹建通用数据平面API工作组，以制定数据平面的标准API&amp;rdquo;&lt;/a&gt; 对此进行了介绍。当时 UDPA 还处于非常早期的筹备阶段，信息非常的少。&lt;/p&gt;
&lt;p&gt;现在9个月过去了，我最近收集并整理了一下 UDPA 目前的情况和信息，给大家介绍一下 UDPA 目前最新的进展（截止2020年2月24日）。&lt;/p&gt;
&lt;h2 id=&#34;udpa介绍&#34;&gt;UDPA介绍&lt;/h2&gt;
&lt;p&gt;首先快速介绍一下什么是 UDPA：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;UDPA ：“Universal Data Plane API”的缩写， “通用数据平面API”。&lt;/li&gt;
&lt;li&gt;UDPA-WG：&amp;ldquo;Universal Data Plane API Working Group&amp;quot;的缩写，这是CNCF下的一个工作组，负责制定 UDPA。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;UDPA的目标，援引自 &lt;a href=&#34;https://github.com/cncf/udpa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/cncf/udpa&lt;/a&gt; 的描述：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;通用数据平面API工作组（UDPA-WG）的目标是召集对数据平面代理和负载均衡器的通用控制和配置API感兴趣的业界人士。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;UDPA的愿景，同样援引：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;通用数据平面API（UDPA）的愿景在 &lt;a href=&#34;https://blog.envoyproxy.io/the-universal-data-plane-api-d15cec7a&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://blog.envoyproxy.io/the-universal-data-plane-api-d15cec7a&lt;/a&gt; 中阐明。 我们将寻求一组API，它们为L4/L7数据平面配置提供事实上的标准，类似于SDN中L2/L3/L4的OpenFlow所扮演的角色。&lt;/p&gt;
&lt;p&gt;这些API将在proto3中规范定义，并通过定义良好的 稳定API版本控制策略，从现有的Envoy xDS API逐步演进。 API将涵盖服务发现，负载均衡分配，路由发现，监听器配置，安全发现，负载报告，运行状况检查委托等。&lt;/p&gt;
&lt;p&gt;我们将对API进行改进和成型，以支持客户端 lookaside 负载均衡（例如gRPC-LB），Envoy之外的数据平面代理，硬件LB，移动客户端以及其他范围。 我们将努力尽可能与供应商和实现无关，同时坚持支持已投入生产的UDPA的项目（到目前为止，Envoy和gRPC-LB）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;对 UDPA 感兴趣的同学，可以通过以下两个途径进一步深入了解：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/cncf/udpa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;UDPA @ GitHub&lt;/a&gt;：UDPA 在 github 上的项目，UDPA  API 定义的代码都在这里&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://lists.cncf.io/g/udpa-wg&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Universal Data Plane API Working Group (UDPA-WG)&lt;/a&gt;：CNCF 的 UDPA 工作组，可以通过加入工作组的方式了解更多信息&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;udpa和xds的关系&#34;&gt;UDPA和xDS的关系&lt;/h2&gt;
&lt;p&gt;在展开 UDPA 的细节之前，有必要先解释清楚 UDPA 和 xDS 的关系，因为这对理解 UDPA 会有很大帮助。&lt;/p&gt;
&lt;p&gt;在2019年11月的 EnvoyCon 上，Envoy 的 开发者，也是目前 UDPA 最主要的负责人之一，来自 Google 的 &lt;a href=&#34;https://github.com/htuch&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Harvey Tuch&lt;/a&gt;，有一个演讲非常详细而清晰的解答了这个问题，这个演讲的标题是：&lt;a href=&#34;https://envoycon2019.sched.com/event/UxwL/the-universal-dataplane-api-udpa-envoys-next-generation-apis-harvey-tuch-google&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;The Universal Dataplane API (UDPA): Envoy’s Next Generation APIs&amp;rdquo;&lt;/a&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：这里我直接援引这份演讲的部分内容，以下两张图片均出自 &lt;a href=&#34;https://static.sched.com/hosted_files/envoycon2019/ac/EnvoyCon%20UDPA%202019.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;这份演讲的PPT&lt;/a&gt;  。鸣谢 Harvey。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下图展示了近年来 xDS 协议的演进历程和未来规划：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202002-udpa-follow-up/images/xds-evolution_huf67a7db91ea4a680815a762630191e0c_296334_d7c207313bd63a709a25e12222202e6f.webp 400w,
               /post/202002-udpa-follow-up/images/xds-evolution_huf67a7db91ea4a680815a762630191e0c_296334_e32cdb82ce98289560c7a8591eba8c1a.webp 760w,
               /post/202002-udpa-follow-up/images/xds-evolution_huf67a7db91ea4a680815a762630191e0c_296334_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202002-udpa-follow-up/images/xds-evolution_huf67a7db91ea4a680815a762630191e0c_296334_d7c207313bd63a709a25e12222202e6f.webp&#34;
               width=&#34;760&#34;
               height=&#34;564&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2017年，xDS v2 引入 proto3 和 gRPC，同年 Istio 项目启动&lt;/li&gt;
&lt;li&gt;2018和2019年，xDS v2 API继续发展，陆续引入了新的API定义，如 HDS / LRS / SDS 等，尤其是为了改进 Pilot 下发性能，开始引入增量推送机制&lt;/li&gt;
&lt;li&gt;xDS v3 API 原计划于2019年年底推出，但目前看技术推迟，目前 v3 还是 alpha1 状态，预计在即将发布的 Istio 1.5 中会有更多的 v3 API 引入。同时 v3 API 也引入了 UDPA 的部分内容，但是由于 UDPA 目前进展缓慢，对 xDS 的影响并不大，主要还是 xDS 自身的发展，比如对API和技术债务的清理&lt;/li&gt;
&lt;li&gt;但在2020年，预计 UDPA 会有很大的进展，尤其是下面我们将会展开的 UDPA-TP 和 UDPA-DM 的设计开始正式制定为 API 之后。而 xDS v4 预计将基于 UDPA ，因此 xDS v4 可能会迎来比较大的变动。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;简单总结说：&lt;strong&gt;xDS 将逐渐向 UDPA 靠拢，未来将基于 UDPA&lt;/strong&gt; 。&lt;/p&gt;
&lt;p&gt;下面的图片则展示了 Envoy 在 xDS 版本支持上的时间线：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202002-udpa-follow-up/images/envoy-version-support-timeline_hu65c2b72d52511c1bf3844a7e53ef40f6_260425_4674573a3753b06ccdf2612ddca40c6c.webp 400w,
               /post/202002-udpa-follow-up/images/envoy-version-support-timeline_hu65c2b72d52511c1bf3844a7e53ef40f6_260425_3949358f525a8da2ecf0517b93c7511c.webp 760w,
               /post/202002-udpa-follow-up/images/envoy-version-support-timeline_hu65c2b72d52511c1bf3844a7e53ef40f6_260425_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202002-udpa-follow-up/images/envoy-version-support-timeline_hu65c2b72d52511c1bf3844a7e53ef40f6_260425_4674573a3753b06ccdf2612ddca40c6c.webp&#34;
               width=&#34;760&#34;
               height=&#34;383&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;目前看这个计划在执行时稍微有一点点延误，原计划于2019年年底推出的 v3 的 stable 版本实际上是在1月中定稿的。（备注：具体可参考 Envoy PR  &lt;a href=&#34;https://github.com/envoyproxy/envoy/pull/9694&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;api: freeze v3 API&lt;/a&gt; ）。然后目前正在广泛使用的 v2 API 将被标记为 depreated。而且在2020年底，v3 API 预计被 v4 API 取代（注意v4 API 将会是基于 UDPA），而目前我们最熟悉的 v2 API 将计划在2020年底移除，不再支持！&lt;/p&gt;
&lt;p&gt;上图也展示了未来 xDS 协议的大版本演进和更替的方式，总的来说规律是这样：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;一年一个大版本：2019 v2 -》 2020 v3 -》2021 v4  -》2022 v5&lt;/li&gt;
&lt;li&gt;每个大版本都要经历 alpha -》 stable -》deprecated -》removed 四个阶段，每个阶段历时一年&lt;/li&gt;
&lt;li&gt;稳定后 Envoy 会同时存在三个API大版本：正在使用的稳定版本，已经弃用的上一个稳定版本，准备开发的新的下一个大版本（但只会是Alpha）&lt;/li&gt;
&lt;li&gt;发布一个新的 stable 的大版本，就一定会 deprecated 上一个稳定的大版本，同时 remove 更前一个已经 deprecated 的大版本&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;所谓 “长江后浪推前浪，前浪死在沙滩上”，又或者说，“江山代有新版出，各领风骚12个月”。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：Envoy 具体的稳定API版本控制策略，可以参见 Envoy 的设计文档 &lt;a href=&#34;https://docs.google.com/document/d/1xeVvJ6KjFBkNjVspPbY_PwEDHC7XPi0J5p1SqUXcCl8/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;Stable Envoy API versioning&amp;rdquo;&lt;/a&gt; ，不过这个文档长的有点过分，嫌长的同学可以直接看这个文档的缩减版本 &lt;a href=&#34;https://github.com/envoyproxy/envoy/blob/master/api/API_VERSIONING.md&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;API versioning guidelines&lt;/a&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;udpa-api进展&#34;&gt;UDPA API进展&lt;/h2&gt;
&lt;p&gt;言归正传，我们来看一下 UDPA 目前的最新进展。&lt;/p&gt;
&lt;p&gt;从 &lt;a href=&#34;https://github.com/cncf/udpa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/cncf/udpa&lt;/a&gt; ，可以看到目前 UDPA 中已经定义好的部分 API 内容：&lt;/p&gt;
&lt;h3 id=&#34;类型定义&#34;&gt;类型定义&lt;/h3&gt;
&lt;p&gt;目前只定义了一个类型 TypedStruct。&lt;/p&gt;
&lt;p&gt;TypedStruct包含任意 JSON 序列化后的 protocol buffer 消息，以及一个描述序列化消息类型的URL。 这与 google.protobuf.Any 非常相似，它使用 google.protobuf.Struct 作为值，而不是使用 protocol buffer 二进制。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;TypedStruct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 用于唯一标识序列化 protocol buffer 消息的类型的URL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 这与 google.protobuf.Any 中描述的语义和格式相同：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type_url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 上述指定类型的JSON表示形式。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;google.protobuf.Struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;TypedStruct 定义的背景是：如何在 protocol buffer 的静态类型报文中嵌入一个不透明的配置？这是一个普遍需求，涉及 &lt;code&gt;google.protobuf.Any&lt;/code&gt; 和 &lt;code&gt;google.protobuf.Struct&lt;/code&gt; 的差别和权衡使用。具体内容请见我之前翻译的博客文章 “&lt;a href=&#34;../201909-dynamic-extensibility-and-protocol-buffers/&#34;&gt;[译] 动态可扩展性和Protocol Buffer&lt;/a&gt;”，对此做了非常好的介绍和分析讨论。&lt;/p&gt;
&lt;p&gt;TypedStruct 可以说是到目前为止对此需求的最佳实践，算是为这一话题正式画上了句号。&lt;/p&gt;
&lt;h3 id=&#34;数据定义&#34;&gt;数据定义&lt;/h3&gt;
&lt;p&gt;数据定义也只定义了一个数据 OrcaLoadReport。&lt;/p&gt;
&lt;p&gt;其中 ORCA 是 Open Request Cost Aggregation 的缩写，OrcaLoadReport 用于提交请求开销汇总的负载报告。&lt;/p&gt;
&lt;p&gt;ORCA的简短介绍：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如今，在Envoy中，可以通过考虑后端负载（例如CPU）的本地或全局知识来做出简单的负载均衡决策。更复杂的负载均衡决策可能需要借助特定于应用的知识，例如队列深度，或组合多个指标。&lt;/p&gt;
&lt;p&gt;这对于可能在多个维度上受到资源限制的服务（例如，CPU和内存都可能成为瓶颈，取决于所应用的负载和执行环境，无法确定是哪个先触及瓶颈），以及这些维度不在预定类别中的位置时很有用（例如，资源可能是“池中的可用线程数”，磁盘IOPS等）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;有关 Orca 的更详细的信息，请见设计文档 &lt;a href=&#34;https://docs.google.com/document/d/1NSnK3346BkBo1JUU3I9I5NYYnaJZQPt8_Z_XCBCI3uA/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Open Request Cost Aggregation (ORCA)&lt;/a&gt; 。&lt;/p&gt;
&lt;p&gt;目前 Envoy 正在实现对 ORCA 的支持，然后这个特性被作为 UPDA 标准的一部分直接在 UDPA API 中定义。&lt;/p&gt;
&lt;p&gt;以下为 OrcaLoadReport 定义，可以看到包含有CPU/内存的利用率和RPS信息：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;OrcaLoadReport&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// CPU利用率表示为可用CPU资源的一部分。 应该来自最新的样本或测量。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;double&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cpu_utilization&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;validate.rules&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;double&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gte&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;validate.rules&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;double&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lte&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 内存利用率表示为可用内存资源的一部分。 应该来自最新的样本或测量。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;double&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mem_utilization&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;validate.rules&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;double&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gte&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;validate.rules&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;double&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lte&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 端点已服务的总RPS。 应该涵盖端点负责的所有服务。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;uint64&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rps&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;服务定义&#34;&gt;服务定义&lt;/h3&gt;
&lt;p&gt;服务定义依然也只定义了一个服务 OpenRcaService。&lt;/p&gt;
&lt;p&gt;OpenRcaService是一个带外（Out-of-band/OOB）负载报告服务，它不在请求路径上。OpenRcaService定期以足够的频率对报告进行采样，以提供与请求的关联。 OOB报告弥补了带内（in-band）报告的局限性。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;service&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;OpenRcaService&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;rpc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;StreamCoreMetrics&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;OrcaLoadReportRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;returns&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;stream&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;udpa.data.orca.v1.OrcaLoadReport&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;注解定义&#34;&gt;注解定义&lt;/h3&gt;
&lt;p&gt;UDPA目前定义了四个注解（Annotation）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;MigrateAnnotation： 用于标记在前后版本中的和迁移相关的API变更，包括 rename / oneof_promotion / move_to_package 等多种语义。&lt;/li&gt;
&lt;li&gt;SensitiveAnnotation：将某个字段标记为“敏感”字段，例如个人身份信息，密码或私钥&lt;/li&gt;
&lt;li&gt;StatusAnnotation：标记状态，比如将某个文件标记为“work_in_progress/进行中”&lt;/li&gt;
&lt;li&gt;VersioningAnnotation：用于记录版本信息，比如通过 previous_message_type 表示当前message在上一个版本中的类型&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;还有一个 ProtodocAnnotation 在提出设计后，存在分歧，暂时还没有正式加入 UDPA。这个注解的目的是标记当前尚未实现的UDPA消息。&lt;/p&gt;
&lt;h3 id=&#34;udpa-api总结&#34;&gt;UDPA API总结&lt;/h3&gt;
&lt;p&gt;从上面列出的UDPA API列表可以看到，目前 UDPA 中正式推出的API 内容非常的少，也就：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;一个TypedStruct类型定义&lt;/li&gt;
&lt;li&gt;一个OpenRcaService服务定义和配套的OracLoadReport数据定义&lt;/li&gt;
&lt;li&gt;4个注解&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;考虑到UDPA推出的时间是 2019年5月份，迄今有9个月的时间，这个进展有些出乎意料。&lt;/p&gt;
&lt;p&gt;翻了一遍 &lt;a href=&#34;https://github.com/cncf/udpa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/cncf/udpa&lt;/a&gt; 上的内容，包括所有的 commit 和 PR ，发现活跃的开发者主要是两位同学：Google 的 htuch 和 Tetrate公司的 Lizan。然后 cncf/UDPA 项目的 star 数量也非常低，才 55 个 star，可以认为社区基本上没什么人关注。&lt;/p&gt;
&lt;p&gt;但是，稍后当我看到 UDPA 的设计文档时，才发现原来 UDPA 的精华都在设计中，只是进度原因还未能正式出成型的API。&lt;/p&gt;
&lt;h2 id=&#34;udpa设计&#34;&gt;UDPA设计&lt;/h2&gt;
&lt;p&gt;我们来重点看一下 UDPA 的设计，主要的设计文档有两份：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.google.com/document/d/1eubmNM2Kynzf7Rpms4nncvTSL6NnANTrpHNWzeIBoZw/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;UDPA-TP strawman&lt;/a&gt;: UDPA设计之传输协议(TransPort)，是用于UDPA的下一代传输协议&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.google.com/document/d/1orxTIL9FXtgmyl5TtPRBqGjgp1ekL7oOKDd95wxeCRY/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;UDPA-DM: L7 routing strawman&lt;/a&gt;: UDPA设计之数据模型(Data Model)，是对通过 UDPA-TP 传输的资源定义&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;UDPA对此的解释是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Envoy v2 xDS API 当前正在转向通用数据平面API（Universal Dataplane API/UDPA）。重点是传输协议与数据模型的关注点分离。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;关于传输协议与数据模型的关注点分离，一个典型的例子是“集装箱运输机制”（类比 UDPA-TP ）和 “集装箱中标准规格”（类比 UDPA-DM）。在 UDPA 的设计中，数据模型的定义和传输协议的实现是分离的，这意味着只要设计不同的数据模型，就可以重用一套统一的传输协议。因此，UDPA 的可扩展性就变得非常强大。&lt;/p&gt;
&lt;p&gt;对此，我个人有些惊喜，因为去年年底我和彦林同学在商讨通过 MCP/xDS/UDPA 协议融合注册中心和控制平面时，就发现这三者的工作机制非常类似。考虑到后续可能会有各种不同的资源需要定义并在这个工作机制上做资源同步和分发，当时有过类似的想法，希望能把底层这套资源同步机制标准化，以便重用：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202002-udpa-follow-up/images/mcp-xds_hu44c08e2b24c3ebfffe8b429320ee4d1f_217904_b229d2cb5b648d72837a26cee9994f83.webp 400w,
               /post/202002-udpa-follow-up/images/mcp-xds_hu44c08e2b24c3ebfffe8b429320ee4d1f_217904_596dcfa922c327a48dfe8cf2bd6c6ae4.webp 760w,
               /post/202002-udpa-follow-up/images/mcp-xds_hu44c08e2b24c3ebfffe8b429320ee4d1f_217904_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202002-udpa-follow-up/images/mcp-xds_hu44c08e2b24c3ebfffe8b429320ee4d1f_217904_b229d2cb5b648d72837a26cee9994f83.webp&#34;
               width=&#34;760&#34;
               height=&#34;429&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;目前看来，UDPA-TP 已经在朝这个目标迈出了坚实的步伐。当然如果能再往前迈进一步就更好了：这个底层资源同步的工作机制，没有必要限制在 UDPA 的范畴，完全可以变成一个用途更加广泛的通用机制。&lt;/p&gt;
&lt;p&gt;下面来详细看一下 UDPA-TP 和 UDPA-DM 的设计，以下内容来自 UDPA 的两份设计文档以及个人的解读。&lt;/p&gt;
&lt;h3 id=&#34;udpa-tp设计&#34;&gt;UDPA-TP设计&lt;/h3&gt;
&lt;p&gt;UDPA-TP的设计文档，在开始部分列出了 UDPA-TP 的关键设计动机，具体包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在保留 Core v2 xDS 中存在的概念性pub-sub模型的同时，还支持高级功能，例如LRS/HDS。&lt;/li&gt;
&lt;li&gt;支持Envoy Mobile和其他DPLB客户端的大规模扩展&lt;/li&gt;
&lt;li&gt;简单的客户端和简单的管理服务器实现。&lt;/li&gt;
&lt;li&gt;使增量更新资源高效而简单。（备注：增量更新是目前 Istio/Envoy 正在努力实现的重点特性）&lt;/li&gt;
&lt;li&gt;支持资源联邦。（备注：和我之前构想的通过MCP协议聚合多个注册中心/配置中心的思路一致，当现实中存在多个资源的来源时，就必须提供机制来聚合这些资源并提供一个全局的视图）&lt;/li&gt;
&lt;li&gt;使API资源的子资源变得简单且实现成本低，并且使其可以增量更新和可联合&lt;/li&gt;
&lt;li&gt;维护对一致性模型的支持&lt;/li&gt;
&lt;li&gt;消除v2 xDS奇怪之处：
&lt;ul&gt;
&lt;li&gt;ACK/NACK与订阅消息的合并。在v2 xDS中，DiscoveryRequest既是订阅请求，又是对先前消息的潜在确认。这导致了一些复杂的实现和调试体验。（备注：这会造成 UDPA 交互模式和xDS的不同）&lt;/li&gt;
&lt;li&gt;CDS/LDS是与EDS/RDS不同的API层。在v2 xDS中，EDS/RDS是准增量的，而CDS/LDS是最新状态。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;从概念上讲，在Envoy v2 xDS API 基础上小范围变更。我们不希望对UDPA管理服务器实现者造成重大的概念和实现开销。（备注：个人理解，这应该是目前 UDPA 没有大张旗鼓的制定各种API的原因，UDPA 和 xDS，包括和 xDS 的实际实现者 Envoy 的关系过于紧密，因此需要考虑从 xDS 到 UDPA 的过渡，不能简单的推出一套全新的API）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以下是 UDPA 的术语，对于后面理解 UDPA 非常有帮助：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DPLB：data plane load balancer的缩写。涵盖诸如代理（例如Envoy）或客户端RPC库（例如gRPC和Envoy Mobile）的用例。 DPLB是UDPA客户端。他们负责启动到管理服务器的UDPA流。（备注：注意，DPLB不仅仅包含以Envoy为代表的service mesh sidecar，也包括了以SDK形式存在的类库如 gRPC，而 gRPC 目前已经在实现 对 xDS 接口的支持）&lt;/li&gt;
&lt;li&gt;Management server/管理服务器：能够提供UDPA服务的实体。管理服务器可以仅是UDPA服务器，也可以是UDPA客户端和服务器（在联邦的情况下）。&lt;/li&gt;
&lt;li&gt;UDPA：通用数据平面API，其中包括数据模型（UDPA-DM）和传输协议（UDPA-TP）。&lt;/li&gt;
&lt;li&gt;UDPA-TP：UDPA API的基准传输协议。&lt;/li&gt;
&lt;li&gt;UDPA-DM：UDPA API的数据模型。&lt;/li&gt;
&lt;li&gt;UaaS：UDPA-as-a-service，云托管的UDPA管理服务。（备注：Google在 GCP 上提供的 Google Traffic Director 和 AWS 提供的 App Mesh，可以视为就是 UaaS 雏形）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然后是和联邦相关的术语：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Federation/联邦：多个UDPA管理服务器的互操作以生成UDPA配置资源。&lt;/li&gt;
&lt;li&gt;Direct federation/直接联邦：当DPLB直接连接到多个UDPA管理服务器并能够从这些流中合成其配置资源时。&lt;/li&gt;
&lt;li&gt;Indirect federation/间接联邦：当DPLB一次最多连接一个UDPA管理服务器（对于某些给定的资源类型），并且UDPA管理服务器执行所有与联邦有关的工作时。&lt;/li&gt;
&lt;li&gt;Advanced DPLB/高级DPLB：支持直接联邦的DPLB（需要UDPA-Fed-TP）。&lt;/li&gt;
&lt;li&gt;Simple DPLB/简单DPLB：不支持直接联邦的DPLB，即仅基线UDPA-TP。&lt;/li&gt;
&lt;li&gt;UDPA-Fed-DM：UDPA-DM的超集，具有用于联邦的其他资源类型。&lt;/li&gt;
&lt;li&gt;UDPA-Fed-TP：支持联邦的UDPA-TP的超集。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下图可以帮助理解这些术语：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202002-udpa-follow-up/images/udpa-tp-endpoint_hu24ce789077d44f51ecf67f2130b0ba82_34132_4b585240aeb5220ae4c258fad44b0403.webp 400w,
               /post/202002-udpa-follow-up/images/udpa-tp-endpoint_hu24ce789077d44f51ecf67f2130b0ba82_34132_540b28d7531b682e602241614785f371.webp 760w,
               /post/202002-udpa-follow-up/images/udpa-tp-endpoint_hu24ce789077d44f51ecf67f2130b0ba82_34132_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202002-udpa-follow-up/images/udpa-tp-endpoint_hu24ce789077d44f51ecf67f2130b0ba82_34132_4b585240aeb5220ae4c258fad44b0403.webp&#34;
               width=&#34;606&#34;
               height=&#34;394&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;(备注：图中可能有误，simple UDPA management server 和 Advanced UDPA management server 之间应该是 &amp;ldquo;UDPA-TP&amp;rdquo;, 而不应该是 &amp;ldquo;UDPA-Fed-TP&amp;rdquo;。)&lt;/p&gt;
&lt;p&gt;UDPA-TP 传输协议提供了在管理服务器和 DPLB 客户端之间传输命名和版本化资源的方法。我们称这些实体为 UDPA-TP 端点。 UDPA-TP 端点可以是客户端和管理服务器，也可以是两个管理服务器（例如，在联邦配置时）。 上图说明了使用 UDPA 在 UDPA-TP 端点之间传送资源的各种方式。&lt;/p&gt;
&lt;p&gt;其中，UDPA管理服务器分为两种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;简单(simple)：实际上只是对不透明资源的缓存（几乎不了解UDPA-DM），主要功能是从上游高级UDPA管理服务器获取资源，并分发资源给 DPLB，自身不产生资源。&lt;/li&gt;
&lt;li&gt;高级(advanced)：对 UDPA-DM 有感知，通常是用来获取信息并转换为标准化的资源（典型如 Istio 中的 Pilot）。可以直接分发资源给到 DPLB，也可以发送资源给简单UDPA管理服务器，然后由简单UDPA管理服务器再分发给 DPLB。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;而对应的 DPLB 客户端也分为两种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;简单(simple)：对于任何配置源，简单的DPLB在任何时间点最多只能与一台管理服务器进行对话。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;高级(advanced)：将实现对 UDPA-Fed-TP 的支持，并能够直接作为联邦端点参与。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;简单 DPLB 虽然只能连接一台管理服务器，但是也是可以实现联邦的：简单 DPLB 连接的管理服务器可以实现联邦，然后为 DPLB 实现了间接联邦。 （备注：上图中的简单 DPLB就是例子，两个 Advanced UDPA management server 之间做了联邦）&lt;/p&gt;
&lt;h3 id=&#34;udpa-tp设计解读&#34;&gt;UDPA-TP设计解读&lt;/h3&gt;
&lt;p&gt;在解读 UDPA-TP 的设计之前，我们回顾一下 Istio 经典的组件和架构图，下面分别是 Istio 1.0 和 Istio 1.1 的架构图：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202002-udpa-follow-up/images/istio-components_hu16b00f39aa48a01ef2fadf608c99ac51_390716_72e7be7eaeefe0493eca3b3395b67a5d.webp 400w,
               /post/202002-udpa-follow-up/images/istio-components_hu16b00f39aa48a01ef2fadf608c99ac51_390716_9e4b5909e94c7baca41b35448923132b.webp 760w,
               /post/202002-udpa-follow-up/images/istio-components_hu16b00f39aa48a01ef2fadf608c99ac51_390716_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202002-udpa-follow-up/images/istio-components_hu16b00f39aa48a01ef2fadf608c99ac51_390716_72e7be7eaeefe0493eca3b3395b67a5d.webp&#34;
               width=&#34;760&#34;
               height=&#34;348&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;考虑到 Mixer 和 Citadel 两个组件和 UDPA 的关系相比没那么大， 我们重点看 Proxy / Pilot / Galley：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Proxy在 Istio 中就是 Envoy （我们的MOSN正在努力成为候选方案） ，直接对等 UDPA 中的 DPLB 的概念。但是Istio 中的 Proxy，功能上只和上图中的 Simple DPLB 对齐。相比之下，UDPA-TP 设计中增加了一个能够连接多个 UDPA management server进行联邦的 Advanced DPLB。&lt;/li&gt;
&lt;li&gt;Pilot 和 Galley，从和 DPLB 的连接关系看，分别对应着UDPA-TP 设计中的 Simple UDPA management server 和 Advanced UDPA management server。但从实际实现的功能看，目前Pilot的职责远远超过了 Simple UDPA management server 的设计，而 Galley 的功能则远远少于 Advanced UDPA management server。如果未来 Istio 的架构和组件要向 UDPA 的设计靠拢，则显然 Pilot 和 Galley 的职责要发生巨大调整。&lt;/li&gt;
&lt;li&gt;最大的差异还是在于 UDPA-TP 中引入了联邦的概念，而且同时支持在 DPLB 和 Advanced UDPA management server 上做联邦。尤其是 DPLB 要实现联邦功能，则必然会让 DPLB 的功能大为增加，相应的 DPLB 和 UDPA management server 的通讯协议 （目前是xDS）也将为联邦的实现增加大量内容。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对照 UDPA-TP 的设计：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202002-udpa-follow-up/images/udpa-tp-endpoint_hu24ce789077d44f51ecf67f2130b0ba82_34132_4b585240aeb5220ae4c258fad44b0403.webp 400w,
               /post/202002-udpa-follow-up/images/udpa-tp-endpoint_hu24ce789077d44f51ecf67f2130b0ba82_34132_540b28d7531b682e602241614785f371.webp 760w,
               /post/202002-udpa-follow-up/images/udpa-tp-endpoint_hu24ce789077d44f51ecf67f2130b0ba82_34132_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202002-udpa-follow-up/images/udpa-tp-endpoint_hu24ce789077d44f51ecf67f2130b0ba82_34132_4b585240aeb5220ae4c258fad44b0403.webp&#34;
               width=&#34;606&#34;
               height=&#34;394&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;UDPA-TP的设计目前应该还没有对应的具体的实现产品，而且我也还没有找到 UDPA-Fed-TP 的详细的API设计。资料来源太少，所以只能简单的做一些个人的初步解读：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;首先，Simple UDPA management server 的引入是一大亮点，功能足够简单而且专注，聚焦在将数据（在UDPA中体现为资源）分发给 DPLB （如大家熟悉的数据平面）。毫无疑问，Simple UDPA management server 的重点必然会在诸如 容量 / 性能 / 下发效率 / 稳定性 等关键性能指标，弥补目前 Istio 设计中 Pilot 下发性能赢弱的短板。从这个角度说，我倾向于将 Simple UDPA management server 理解为一个新的组件，介于 DPLB 和 Pilot 之间。&lt;/p&gt;
&lt;p&gt;小结：&lt;strong&gt;解决容量和性能问题&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;其次，Advanced UDPA management server 引入了联邦的概念， 上面的图片显示是为了在两个不同的云供应商（Cloud Provider X 和 Cloud Provider Y）和本地（On-premise）之间进行联邦，这是典型的混合云的场景。而我的理解是，联邦不仅仅用于多云，也可以用于多数据来源，比如打通多个不同的注册中心，解决异构互通问题。&lt;/p&gt;
&lt;p&gt;小结：&lt;strong&gt;解决多数据来源的全局聚合问题&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后，比较费解的是引入了 Advanced DPLB 的概念，而且从图上看，使用场景还非常复杂：1. 第一个DPLB是间接联邦的典型场景，还比较简单 2. 第二个 DPLB除了以同样的方式做了间接联邦，还直接通过 UDPA-Fed-TP 协议和 On-Premise 的 Advanced UDPA management server 连接，实现了直接联邦 3. 第三个 DPLB 则更复杂，做了三个management server的联邦 。&lt;/p&gt;
&lt;p&gt;小结：&lt;strong&gt;复杂的场景必然带来复杂的机制，背后推动力待查&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;对于 UDPA-TP 的设计，我个人有些不太理解，主要是对于联邦的使用场景上，我的疑虑在于：真的有这么复杂的场景吗？尤其是将联邦的功能引入到 DPLB，这必然会使得 xDS/UDPA 协议不得不为此提供联邦 API 支持，而 Envoy/MOSN 等的实现难度也要大为提升。因此，除非有特别强烈的需求和场景推动，否则最好能在复杂度和功能性之间做好平衡。&lt;/p&gt;
&lt;p&gt;我个人更倾向于类似下面的设计：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202002-udpa-follow-up/images/udpa-tp-simplized_hu0270b559d6f98963b19ec38582a1d9b0_310926_f6283b22f57a5bcc51529e597e2b3ca5.webp 400w,
               /post/202002-udpa-follow-up/images/udpa-tp-simplized_hu0270b559d6f98963b19ec38582a1d9b0_310926_b2c3bf1020212a69dd9350c69f730869.webp 760w,
               /post/202002-udpa-follow-up/images/udpa-tp-simplized_hu0270b559d6f98963b19ec38582a1d9b0_310926_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202002-udpa-follow-up/images/udpa-tp-simplized_hu0270b559d6f98963b19ec38582a1d9b0_310926_f6283b22f57a5bcc51529e597e2b3ca5.webp&#34;
               width=&#34;760&#34;
               height=&#34;361&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;维持 DPLB 和 Simple UDPA management server 的简单性&lt;/li&gt;
&lt;li&gt;DPLB 只对接 Simple UDPA management server，协议固定为 UDPA-TP，联邦对DPLB透明（只实现间接联邦）&lt;/li&gt;
&lt;li&gt;Simple UDPA management server 重点在于容量和性能的提升，包括目前正在进行中的支持各种资源的增量更新。&lt;/li&gt;
&lt;li&gt;Advanced UDPA management server 负责完成联邦，包括和其他环境的Advanced UDPA management server做联邦，以及从本地的其他注册中心聚合数据。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总之，我个人更倾向于让 DPLB 和 Simple UDPA management server 保持简单和高性能，而将复杂功能交给 Advanced UDPA management server 。后续我会重点关注 UDPA 在联邦功能的实现，如有新进展尽量及时撰文分享。&lt;/p&gt;
&lt;h3 id=&#34;udpa的资源定义和设计&#34;&gt;UDPA的资源定义和设计&lt;/h3&gt;
&lt;p&gt;在 UDPA-TP 的设计中，根据资源的来源，资源被划分为两类类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configuration Resources/配置资源：控制平面生成，由管理服务器分发到 DPLB。平常大家熟悉的，通过xDS协议传输的 Listener / Route / Cluster / Endpoint 等资源就属于这种类型。&lt;/li&gt;
&lt;li&gt;Client Resources/客户资源：DPLB生成，准备交给控制平面使用。前面 UDPA 中定义的 OracLoadReport 就是典型例子，这是最近才有的新特性，由 DPLB 收集统计信息和状态，汇报给到控制平面，以便控制平面在决策时可以有多完善的参考信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;资源在定义时，将有三个重要属性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;名称/Name：对于给定类型是唯一的，而且资源名称是结构化的，其路径层次结构如下：&lt;code&gt;&amp;lt;namespace&amp;gt;/&amp;lt;resource&amp;gt;&lt;/code&gt; ，例如  &lt;code&gt;com.acme.foo/service-a&lt;/code&gt; 。注意 namespace 的引入，是后面的资源联邦和所有权委派的基础。&lt;/li&gt;
&lt;li&gt;类型/Type：资源类型由 Type URL 提供的字符串来表示。&lt;/li&gt;
&lt;li&gt;版本/Version：对于给定的命名资源，它可能在不同的时间点具有不同的版本。在资源定义中带上版本之后，检测资源是否有更新就非常方便了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以下是资源定义的实例（只是示意，暂时还没正式成为 UDPA API的内容）：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Resource&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 资源的名称，以区别于其他同类型的资源。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 遵循反向DNS格式，例如 com.acme.foo/listener-a
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 资源级别版本
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;version&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 资源有效负载。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 通过 Any 的 type URL 指定资源类型
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;google.protobuf.Any&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;resource&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 资源的TTL。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 此时间段后，资源将在DPLB上失效。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 当管理服务器的连接丢失时，将支持资源的优雅降级，例如端点分配。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 使用新的TTL接收到相同的资源 name/version/type 将不会导致除了刷新TTL之外的任何状态更改。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 按需资源可能被允许过期，并且可能在TTL过期时被重新获取。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// TTL刷新消息中的resource字段可能为空，name/version/type用于标识要刷新的资源。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;google.protobuf.Duration&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ttl&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 资源的出处（所有权，来源和完整性）。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;Provenance&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;origin_info&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;UDPA-TP 设计中的其他内容，如安全 / 错误处理 / 传输 / 用户故事 等，就不一一展开了，这些设计目前看离正式成为 API 还有点远。如有兴趣可以直接翻阅 UDPA-TP 的设计文档。&lt;/p&gt;
&lt;h3 id=&#34;udpa-dm设计&#34;&gt;UDPA-DM设计&lt;/h3&gt;
&lt;p&gt;UDPA 设计的一个核心内容就是将传输（TransPort）与数据模型（Date Model）的关注点分离，前面介绍了 UDPA-TP 的设计，可以说目前还在进行中，并未完全定型。&lt;/p&gt;
&lt;p&gt;而 UDPA-DM 的设计，感觉进度上比 UDPA-TP 还要更早期，这多少有点出乎意料：原以为 UDPA 会基于 xDS 现有的成熟 API 定义，快速推出一套覆盖常见通用功能的 API ，甚至直接把 xDS 中的部分内容清理干净之后搬过来。但事实是：目前 UDPA-DM 中已经定义的 API 内容非常少，仅有 L7 Routing ，而且还在设计中，其他大家熟悉的 Listener / Cluster / Endpoint / Security / RatingLimit 等API都还没有看到。&lt;/p&gt;
&lt;p&gt;而 UDPA-DM 的设计和实现方式，也因为资料较少而有些不够明朗。在 UDPA-DM 的设计文档的开头，有如下一段描述：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As a starting point, we recognize that the UDPA-DM is not required to be as expressive as any given DPLB client’s full set of capabilities, instead it should be possible to translate from UDPA-DM to various DPLB native configuration formats. We envisage UDPA-DM as a lingua franca that captures a large amount of useful functionality that a DPLB may provide, making it possible to build common control planes and ecosystems around UDPA capable DPLBs.&lt;/p&gt;
&lt;p&gt;首先，我们认识到 UDPA-DM 不需要像任何已有的 DPLB 客户端那样，全部能力都具备表现力，而是应该可以从 UDPA-DM 转换为各种 DPLB 原生配置格式。我们将 UDPA-DM 设想为一种通用语言，它具备大量 DPLB 应该提供的有用的功能，从而有可能在支持 UDPA 的 DPLB 周围构建通用的控制平面和生态系统。&lt;/p&gt;
&lt;p&gt;The UDPA-DM will be a living standard. We anticipate that it will initially cover some obvious common capabilities shared by DPLBs, while leaving other behaviors to proxy specific API fields. Over time, we expect that the UDPA-DM will evolves via a &lt;a href=&#34;https://docs.google.com/document/d/1xeVvJ6KjFBkNjVspPbY_PwEDHC7XPi0J5p1SqUXcCl8/edit&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;stable API versioning policy&lt;/a&gt; to accommodate functionalities as we negotiate a common representation.&lt;/p&gt;
&lt;p&gt;UDPA-DM 将成为事实标准。我们期望它最初将涵盖 DPLB 共有的一些显而易见的通用功能，同时将其他行为留给代理特定的API字段。随着时间的推移，我们期望 UDPA-DM 将通过稳定的API版本控制策略来发展，以容纳各种功能，而我们将协商通用的表示形式。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;对这两段文字描述的理解，我是有一些困惑的，主要在清楚解 UDPA-DM 的定义和具体的 DPLB 原生实现（典型如 Envoy 的 xDS）之间的关系。下面这张图是我画的：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202002-udpa-follow-up/images/udpa-dm-design_huf56838ffe78075f247ec8e1dd3c2e332_92993_01cfb0200d906017ee7ce2cdc3a3783b.webp 400w,
               /post/202002-udpa-follow-up/images/udpa-dm-design_huf56838ffe78075f247ec8e1dd3c2e332_92993_bfb8b2edbe98ccb24c6d32716efa389e.webp 760w,
               /post/202002-udpa-follow-up/images/udpa-dm-design_huf56838ffe78075f247ec8e1dd3c2e332_92993_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202002-udpa-follow-up/images/udpa-dm-design_huf56838ffe78075f247ec8e1dd3c2e332_92993_01cfb0200d906017ee7ce2cdc3a3783b.webp&#34;
               width=&#34;760&#34;
               height=&#34;281&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;左边的图是转换方案：按照第一段文字的描述，UDPA-DM 是做通用定义，然后转换（Translate）为各种 DPLB 的原生配置格式。这意味着 UDPA-DM API 和实际的 DPLB 原生配置格式可能会有非常大的不同，甚至有可能是完全不一样的格式定义。这个关系有点类似 Istio API 和 xDS API 的关系，也类似于 SMI （微软推出的 Service Mesh Interface）和 xDS 的关系。&lt;/li&gt;
&lt;li&gt;右边的图是子集方案：按照第二段文字的描述，UDPA-DM 是做通用定义，但是不会做转换，其他 DPLB 会直接复用这些 UDPA-DM 的 API 定义，然后补充自身特有的 API 定义。 这样 UDPA-DM 会以通用子集的形式出现，逐渐扩大范围，然后其他 API 会逐渐将自身的 API 中和 UDPA-DM 重叠的部分替换为 UDPA-DM API，只保留自身特有的扩展API。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;前面谈到 xDS 的演进路线， v3 / v4 会逐渐向 UDPA 靠拢，尤其 v4 会基于 UDPA 来。目前由于 UDPA API 远未成型，而 xDS v3 中对 UDPA API 的使用非常少（基本只用到了 annotation 定义），因此目前到底是哪个方案尚不明朗。&lt;/p&gt;
&lt;p&gt;以下是 UDPA-DM 设计文档中描述的 UDPA-DM 的关键设计：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;描述L7路由层，该层描述主要 L7 DPLB 之间的常见行为，包括 Envoy，HAproxy，Nginx，Google Cloud Platform URL mapping 和 Linkerd。&lt;/li&gt;
&lt;li&gt;为代理/LB的特有扩展提供灵活性，用于不适合通用抽象的行为。 即 逃生舱口（escape hatch）（备注：类似SQL 方言）&lt;/li&gt;
&lt;li&gt;提供L7路由表的可伸缩性和有效的对数评估（logarithmic evaluation）。 例如，Envoy v2 xDS是严格线性评估的路由表，具有明显的扩展限制。 对于可以支持 UDPA-TP 这个特性的DPLB，应该可以按需获取路由表段。&lt;/li&gt;
&lt;li&gt;在v2 Envoy xDS API中支持线性匹配路由表的旧有用户。&lt;/li&gt;
&lt;li&gt;删除多xDS样式API的需求，例如 RDS，VHDS和SRDS。&lt;/li&gt;
&lt;li&gt;资源的可组合性； 应该有可能支持UDPA联邦用例，带有诸如虚拟主机这种被独立管理的资源等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下面重点看 L7 Routing 的设计。&lt;/p&gt;
&lt;h3 id=&#34;routing-api-设计&#34;&gt;Routing API 设计&lt;/h3&gt;
&lt;p&gt;Routing API 中有三个术语：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务/Service：描述后端服务的不透明字符串（或在Envoy的术语中，为集群/Cluster）。 当前文档未提供有关服务表示的任何进一步详细说明，这留待以后的工作。&lt;/li&gt;
&lt;li&gt;路由表/Route table：一组匹配条件，用于HTTP请求和相关操作。 操作可以包括重定向或转发到特定服务。&lt;/li&gt;
&lt;li&gt;L7路由/L7 routing：根据路由表评估给定的HTTP请求。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在 UDPA-DM 的 Routing API 设计中，针对请求匹配的方式，相比 xDS 做了重大的改动，主要体现在除了线性匹配之外，还支持分层匹配。&lt;/p&gt;
&lt;p&gt;这里先解释一下线性匹配和分层匹配这两种路由时需要用到的请求匹配方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;线性（Linear）：其中路由表类似于&lt;code&gt;[([Match], Action)]&lt;/code&gt; 类型。 在此模型中，路由表是 匹配 criteria-action 条件的有序列表。 每个匹配的 criteria 是匹配 criteria 的逻辑&amp;quot;与&amp;rdquo;，例如&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If :authority == foo.com AND path == / AND x-foo == bar THEN route to X&lt;/li&gt;
&lt;li&gt;If :authority == bar.com AND x-baz == wh00t THEN route to Y&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;分层(Hierarchical)：其中路由表类似于树结构，每个节点具有&lt;code&gt; (MatchCriteria, [(Value, Action)])&lt;/code&gt; 类型。 通过这种结构，任何给定的节点都会只评估单个匹配条件，例如&lt;code&gt;:authority&lt;/code&gt; 的值。分层匹配能提供相对高效的实现。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;目前 xDS v2 API使用的是线性匹配方式，而 UDPA-DM 的 Routing API 会引入分层匹配，形成线性-分层的混合匹配方式，如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202002-udpa-follow-up/images/upda-hybird-model_hubac6fc310d483742f44cb3ee4e0fd6f4_458397_4c3f09b050a2d791c885d2b75d0b1c7f.webp 400w,
               /post/202002-udpa-follow-up/images/upda-hybird-model_hubac6fc310d483742f44cb3ee4e0fd6f4_458397_8851356bbc91fd7bd3daaecb5d8a8bd0.webp 760w,
               /post/202002-udpa-follow-up/images/upda-hybird-model_hubac6fc310d483742f44cb3ee4e0fd6f4_458397_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202002-udpa-follow-up/images/upda-hybird-model_hubac6fc310d483742f44cb3ee4e0fd6f4_458397_4c3f09b050a2d791c885d2b75d0b1c7f.webp&#34;
               width=&#34;760&#34;
               height=&#34;680&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;设计文档对这个混合匹配模型有如下说明：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The model does not map directly to any given DPLB today but borrows from some Envoy concepts and should have an efficient realization. It may be possible to use HAproxy ACLs to model this topology.&lt;/p&gt;
&lt;p&gt;目前该模型并没有直接映射到任何给定的DPLB，而是借鉴了Envoy的一些概念，这个模型应该会有一个有效的实现。可能会使用HAproxy ACL对这种拓扑进行建模。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;由于目前 Routing API 并没有完成设计，也没有正式成为 UDPA 的API，而在最新刚定稿的 xDS v3 协议中，RoutesDiscoveryService 和 ScopedRoutesDiscoveryService 也都没有引入这个新的模型，因此预期这个模型将在2020年继续完成设计和定稿，可能在年底的 xDS v4 中会有所体现。然后，UDPA-DM 和 xDS 之间到底会是转换模型，还是子集模型，届时就清楚了。&lt;/p&gt;
&lt;p&gt;由于 Routing API 尚未设计完成，所以这里不详细展开 Routing API 的定义了。Routing API 的相关资料如下，有兴趣的同学可以关注（然而已经很长时间没有新的进展了）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Issue 讨论 [&lt;a href=&#34;https://github.com/cncf/udpa/pull/4&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;WiP] L7 routing straw man&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;在 PR 中提交的 Routing API 定义文件 &lt;a href=&#34;https://github.com/cncf/udpa/pull/4/files#diff-40a6d8a368e77b5a9046c367cb47182b&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;udpa/config/v1alpha/routing.proto&lt;/a&gt;：可以自行和xDS v3 的API 做一个比较&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;UDPA 目前还处于早期设计阶段，关键的 UDPA-TP 和 UDPA-DM 的设计有推出草稿但是远未完成，内容也和我们期望的一个完整的通用数据平面API有很长的距离。&lt;/p&gt;
&lt;p&gt;而且项目进展并不理想，感觉重视程度和人力投入都有限。&lt;/p&gt;
&lt;h2 id=&#34;附言&#34;&gt;附言&lt;/h2&gt;
&lt;p&gt;最近因为想了解一下 UDPA 的进展，所以做了 UDPA 的调研和学习，比较遗憾的是 UDPA 的资料非常匮乏，除了我本文列出来的几个官方网站和设计文档之外，基本就只有 Harvey 的演讲。&lt;/p&gt;
&lt;p&gt;调研完成之后发现 UDPA 的进展不如人意，尤其是最近的工作几乎停滞，关键的 UDPA-TP 和 UDPA-DM 的设计未能完稿，xDS v3 中也只引用了极少的 UDPA API 定义。这篇总结文章差点因此难产，因为未知/待定/未完成的内容太多，而且由于缺乏资料输入，很多信息也只是我个人的理解和想法，按说这不是一个严谨的深度介绍文章应有的态度。&lt;/p&gt;
&lt;p&gt;但考虑到目前 UDPA 的资料实在是太少，本着“有比没有好”的想法，我硬着头皮完成了这篇文章。后续如果有新的输入，我会及时完善或者修订本文，也欢迎对 UDPA 有兴趣和了解的同学联系我讨论和指导。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/cncf/udpa&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/cncf/udpa&lt;/a&gt; ：UDPA在 github 的项目，API 定义来自这里&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.google.com/document/d/1y-H-pQ2mmhBPX_U9pP3mMMUbEpZskxBdEbwd5KlivY4/edit#heading=h.fdi15bvpmxen&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Universal Data Plane API Working Group (UDPA-WG)&lt;/a&gt;:  UDPA设计文档，但是内容很少&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://lists.cncf.io/g/udpa-wg&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Universal Data Plane API Working Group (UDPA-WG)&lt;/a&gt;：CNCF 下的 UDPA 工作组，加入之后能看到一些资料&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.google.com/document/d/1eubmNM2Kynzf7Rpms4nncvTSL6NnANTrpHNWzeIBoZw/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;UDPA-TP strawman&lt;/a&gt;: UDPA-TP的设计文档&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.google.com/document/d/1orxTIL9FXtgmyl5TtPRBqGjgp1ekL7oOKDd95wxeCRY/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;UDPA-DM: L7 routing strawman&lt;/a&gt;: UDPA-DM的设计文档&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.google.com/document/d/1xeVvJ6KjFBkNjVspPbY_PwEDHC7XPi0J5p1SqUXcCl8/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Stable Envoy API versioning&lt;/a&gt; ：Envoy 官方文档，讲述 Envoy 的稳定API版本控制策略&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://www.servicemesher.com/blog/cncf-udpa-wg/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;CNCF正在筹建通用数据平面API工作组，以制定数据平面的标准API&lt;/a&gt;：我去年写的 UDPA 介绍文章&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://envoycon2019.sched.com/event/UxwL/the-universal-dataplane-api-udpa-envoys-next-generation-apis-harvey-tuch-google&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The Universal Dataplane API (UDPA): Envoy’s Next Generation APIs&lt;/a&gt;：Harvey Tuch 的演讲，帮助理解 xDS 和 UDPA 的关系&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>[译] 从VM到Kubernetes的渐进式应用迁移(2) - 陷阱，流水线和避免复杂性</title>
      <link>https://skyao.net/post/202001-incremental-app-migration-from-vms-to-kubernetes-2/</link>
      <pubDate>Mon, 27 Jan 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202001-incremental-app-migration-from-vms-to-kubernetes-2/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://blog.getambassador.io/incremental-app-migration-from-vms-to-kubernetes-planning-and-tactics-5ffc18c151e&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Part 2: Incremental App Migration from VMs to Kubernetes — Pitfalls, Pipelines, and Avoiding Complexity&lt;/a&gt;，作者 &lt;a href=&#34;https://blog.getambassador.io/@danielbryantuk&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Daniel Bryant&lt;/a&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：快速翻译（机翻+人工校对，没有精修），质量不高，一般阅读可以，不适合传播，谢绝转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;现代软件系统的核心目标之一是使应用与运行它们的基础设施解耦。这可以带来许多好处，包括：工作负载可移植性，与云AI/ML服务的集成，降低成本，以及改进/委派安全性的特定方面。容器和编排框架（如Kubernetes）的使用可以使应用的部署和执行与底层硬件解耦。&lt;/p&gt;
&lt;p&gt;在本系列的&lt;a href=&#34;https://blog.getambassador.io/routing-in-a-multi-platform-data-center-from-vms-to-kubernetes-via-ambassador-47bbe658683c&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;前一篇文章中&lt;/a&gt;，我探讨了如何使用应用现代化程序来开始技术之旅：通过在系统边缘部署 Ambassador API Gateway 并在现有的基于VM的服务和新部署的基于Kubernetes的服务之间路由用户流量。&lt;/p&gt;
&lt;p&gt;第二篇文章以此为基础，概述了如何计划迁移，还提供了有关容器化工作负载和一些网络注意事项的指南。本系列的下一篇文章将探讨如何使用服务网格（例如HashiCorp的 &lt;a href=&#34;https://www.consul.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Consul&lt;/a&gt; ）在所有平台类型之间无缝路由服务到服务的通信，而不管您的应用是否已容器化。&lt;/p&gt;
&lt;h2 id=&#34;计划迁移常见的陷阱&#34;&gt;计划迁移：常见的陷阱&lt;/h2&gt;
&lt;p&gt;我将假设您已经因为 &lt;a href=&#34;https://www.infoq.com/articles/api-gateway-service-mesh-app-modernisation/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;现代化应用程序堆栈&lt;/a&gt; 的好处而被吸引，但是有一些警告需要提前说明：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;**您不能指望在一夜之间将您的堆栈迁移。**在典型的现有（旧版/传统）堆栈中，存在太多的活动组件和太多的复杂性。任何迁移都需要以零散的方式进行计划和实施，并且计划和基础设施必须足够灵活以适应变化，例如，如果一个团队决定明年将继续在VM上运行其应用程序，但也想利用新的SSO身份验证或速率限制保护。您的迁移必须具有弹性，并能够适应您不可避免的会遇到的问题。&lt;/li&gt;
&lt;li&gt;**您不应该计划大爆炸式的云迁移。**即使对于IT资产相对较小的团队，以大爆炸的方式更新几乎所有内容所涉及的风险也过高，更不用说更改整个基础基础架构了。您的迁移必须支持渐进式部署。&lt;/li&gt;
&lt;li&gt;**您将必须确保所有团队（开发人员和运营人员）都了解新技术，并相应地更新他们共享的思维模型。**传统上，运维可能会将基础设施平台视为由他们完全控制的计算节点和3/4层网络组成。通常，系统内组件标识的概念被认为是IP地址和端口。同时，开发人员通常认为底层平台基础设施的配置和通信属性（例如服务发现，安全性和速率限制）是“其他人的问题”。向云技术的迁移必须确保每个人都接受共享的自助服务平台的概念，系统身份基于服务身份，并且开发人员和运维人员共同工作以配置应用的运行时通信属性。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;迁移策略&#34;&gt;迁移策略&lt;/h2&gt;
&lt;p&gt;鉴于上述要求，现在让我们看一下如何实现这一点的几种策略。&lt;/p&gt;
&lt;h3 id=&#34;容器打包&#34;&gt;容器打包&lt;/h3&gt;
&lt;p&gt;我去年在DockerCon EU上的“ &lt;a href=&#34;https://www.youtube.com/watch?v=hJkhPP2OLA8&amp;amp;list=PLkA60AVN3hh_DVyQ13qGheO_Jg7jcAPcv&amp;amp;index=37&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;使用Docker容器和Java进行持续交付：好的，坏的和丑陋的&lt;/a&gt; ”中谈到了将现有的“继承”应用封装在容器中的挑战。演讲的重点是Java平台，但是对于其他语言堆栈应该也有用。&lt;/p&gt;
&lt;p&gt;如果您已订阅Docker Enterprise，那么Docker团队将提供几种工具来&lt;a href=&#34;https://blog.docker.com/2019/05/5-reasons-to-containerize-production-windows-apps-on-docker-enterprise/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;自动将现有.NET应用程序打包&lt;/a&gt;到Docker容器中。也有其他组织（例如Google）推出了&lt;a href=&#34;https://cloud.google.com/blog/products/gcp/introducing-jib-build-java-docker-images-better&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Jib容器构建工具的计划&lt;/a&gt;。CloudBees和Red Hat团队分别通过其&lt;a href=&#34;https://jenkins.io/projects/jenkins-x/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Jenkins X&lt;/a&gt;和&lt;a href=&#34;https://www.openshift.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;OpenShift&lt;/a&gt;工具提供了buildpack样式集成，可帮助自动为现有应用生成Dockerfile。在先前的DockerCons上已经进行了演示，其中将 &lt;a href=&#34;https://cnab.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Cloud Native Application Bundle（CNAB）之&lt;/a&gt; 类的技术与CLI工具相结合，也可以自动打包应用程序。&lt;/p&gt;
&lt;h3 id=&#34;调整您的交付渠道&#34;&gt;调整您的交付渠道&lt;/h3&gt;
&lt;p&gt;容器化现有应用可能需要一些Shell脚本魔术，但是从根本上讲，完成此任务的方法是公式化的-了解您的应用现在如何运行，并将其复制到容器中。最大的挑战通常是验证应用在各种使用情况下是否可以正常运行。要执行此质量保证，通常需要增强交付流水线，或者如果您尚未建立，则需要创建交付流水线。像前面提到的Jenkins X这样的交付流水线工具将在这里提供帮助，并且还有各种各样的开源和商业产品，例如&lt;a href=&#34;https://circleci.com/blog/using-circleci-workflows-to-replicate-docker-hub-automated-builds/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;CircleCI&lt;/a&gt;，&lt;a href=&#34;https://docs.gocd.org/current/gocd_on_kubernetes/designing_a_cd_pipeline/creating_a_test_pipeline.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;GoCD&lt;/a&gt;和&lt;a href=&#34;https://docs.gitlab.com/ee/ci/docker/using_docker_build.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;GitLab&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;我在DockerCon EU演讲中谈到了调整连续交付流水线以构建容器的过程，随附的&lt;a href=&#34;https://github.com/danielbryantuk/oreilly-docker-java-shopping&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;示例项目&lt;/a&gt;提供了一些实际的演示。关键要点是确保针对容器运行的应用程序或服务执行所有组件级和服务集成测试。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;images/pipeline.jpeg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我已经看到一些组织像往常一样继续对应用二进制文件执行测试，然后将应用打包到容器中，作为流水线的最后一步。这种方法经常会导致问题，因为容器技术可以巧妙地更改基础设施的运行时特性，例如限制CPU时间或内存，与底层块存储区不同的I/O性能，或者没有通过 &lt;code&gt;/dev/random&lt;/code&gt; 提供足够的熵来运行加密操作，例如令牌生成。&lt;/p&gt;
&lt;h3 id=&#34;注意网络的复杂性&#34;&gt;注意网络的复杂性&lt;/h3&gt;
&lt;p&gt;在本系列的下一篇文章中，我将演示如何使用Consul服务网格扩展本系列第一部分中包含的示例应用，该应用已部署在Google Cloud Platform VM和Kubernetes上。但是，值得一提的是，您将遇到的主要问题之一是需要&lt;a href=&#34;https://en.wikipedia.org/wiki/Network_topology#Fully_connected_network&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;完全连接的网络&lt;/a&gt;，这通常意味着使用&lt;a href=&#34;https://en.wikipedia.org/wiki/Flat_network&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;平面网络&lt;/a&gt;或使用一系列路由器或网关来桥接不同的网络。&lt;/p&gt;
&lt;p&gt;有个别 Ambassador 的用户使用它来分割网络或加入现有的网段，并且 HashiCorp 和 Rancher 等其他组织正在致力于实现可以桥接多个集群的 &lt;a href=&#34;https://www.hashicorp.com/blog/roadmap-preview-what-s-next-for-consul-service-mesh#gateways-to-bridge-multiple-clusters&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;网关&lt;/a&gt;，分别与 &lt;a href=&#34;https://www.hashicorp.com/blog/roadmap-preview-what-s-next-for-consul-service-mesh#gateways-to-bridge-multiple-clusters&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Consul Gateways&lt;/a&gt; 和 &lt;a href=&#34;https://rancher.com/blog/2019/announcing-submariner-multi-cluster-kubernetes-networking/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Submariner结合&lt;/a&gt; 。&lt;/p&gt;
&lt;h2 id=&#34;敬请关注&#34;&gt;敬请关注&lt;/h2&gt;
&lt;p&gt;在有关应用迁移系列的第二篇文章中，我指出了当客户对应用进行现代化改造时，Datawire团队和我所看到的一些挑战。在下一篇文章中，我将介绍 Consul 服务网格的用法，并演示它如何与 Ambassador 集成，以简化基于VM的应用程序和基于容器的服务之间的过渡。&lt;/p&gt;
&lt;p&gt;如有任何疑问，请通过网站或Twitter 上的 &lt;a href=&#34;https://www.twitter.com/getambassadorio&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;@getambassadorio &lt;/a&gt; &lt;a href=&#34;https://www.getambassador.io/contact&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;与我们联系&lt;/a&gt;。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译] 从VM到Kubernetes的渐进式应用迁移(1) - 跨平台和云路由流量</title>
      <link>https://skyao.net/post/202001-incremental-app-migration-from-vms-to-kubernetes-1/</link>
      <pubDate>Sun, 26 Jan 2020 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/202001-incremental-app-migration-from-vms-to-kubernetes-1/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://blog.getambassador.io/routing-in-a-multi-platform-data-center-from-vms-to-kubernetes-via-ambassador-47bbe658683c&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Part 1: Incremental App Migration from VMs to Kubernetes — Routing Traffic Across Platforms &amp;amp; Clouds&lt;/a&gt;，作者 &lt;a href=&#34;https://blog.getambassador.io/@danielbryantuk&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Daniel Bryant&lt;/a&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：快速翻译（机翻+人工校对，没有精修），质量不高，一般阅读可以，不适合传播，谢绝转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;在 &lt;a href=&#34;https://www.datawire.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Datawire&lt;/a&gt; 上，我们看到越来越多的组织正在往基于 Docker 和 Kubernetes 构建的“下一代”云原生平台上迁移。但是，这种迁移不会在一夜之间发生。取而代之的是，我们看到了多平台数据中心和云环境的增长，在这里应用可以跨越虚拟机和容器。在这些数据中心中，&lt;a href=&#34;https://www.getambassador.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Ambassador API Gateway&lt;/a&gt; 被用作入口（ingress）的中心点，解决 &lt;a href=&#34;https://www.getambassador.io/concepts/auth-overview&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;身份验证&lt;/a&gt;，&lt;a href=&#34;https://www.getambassador.io/user-guide/rate-limiting&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;速率限制&lt;/a&gt;和其他跨域运维问题。&lt;/p&gt;
&lt;p&gt;本文是系列文章的第一篇，讲述在将应用逐步迁移到Kubernetes时，如何使用 Ambassador 作为多平台入口解决方案。我们已将示例 Terraform 的代码添加到 &lt;a href=&#34;https://github.com/datawire/pro-ref-arch&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Ambassador Pro参考架构&lt;/a&gt;  的 GitHub 仓库中，该仓库支持在 Google Cloud Platform上创建多平台“沙盒”基础设施。这将允许您启动 Kubernetes 集群和多个VM，并练习将流量从 Ambassador 路由到现有应用。&lt;/p&gt;
&lt;h2 id=&#34;多平台世界中的边缘路由&#34;&gt;多平台世界中的边缘路由&lt;/h2&gt;
&lt;p&gt;我之前写过有关使用 &lt;a href=&#34;https://itnext.io/using-api-gateways-to-facilitate-your-transition-from-monolith-to-microservices-c08fe3489237&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;边缘代理或网关&lt;/a&gt; 的文章，帮助从单体迁移到微服务，或从本地迁移到云。Ambassador 可以充当所有类型平台的 API gateway 或边缘路由器，尽管它的设计和构建是专门在Kubernetes上运行的，但也可以简单的配置从集群到外部网络目标的流量路由，例如使用VPN的端点或虚拟私有云（VPC），云服务，云负载均衡器，或单个VM。只要具备对端点的网络访问权限，则 Ambassador 可以路由到该端点。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202001-incremental-app-migration-from-vms-to-kubernetes-1/images/edge-proxy_hu223160e25ee228a7c2e2f6d2c3c857fb_48221_88f02f1cdfdd25742b1ed17ad2dd9da7.webp 400w,
               /post/202001-incremental-app-migration-from-vms-to-kubernetes-1/images/edge-proxy_hu223160e25ee228a7c2e2f6d2c3c857fb_48221_207f61ab66a8a9f1473cba839def6238.webp 760w,
               /post/202001-incremental-app-migration-from-vms-to-kubernetes-1/images/edge-proxy_hu223160e25ee228a7c2e2f6d2c3c857fb_48221_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202001-incremental-app-migration-from-vms-to-kubernetes-1/images/edge-proxy_hu223160e25ee228a7c2e2f6d2c3c857fb_48221_88f02f1cdfdd25742b1ed17ad2dd9da7.webp&#34;
               width=&#34;760&#34;
               height=&#34;348&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们的 &lt;a href=&#34;https://github.com/datawire/pro-ref-arch&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Ambassador Pro参考架构&lt;/a&gt; GitHub 仓库包含几个提供文档和示例的文件夹，以帮助您了解如何最好地使用Ambassador 支持的所有功能，例如速率限制和分布式追踪。还有一个“cloud-infrastructure”文件夹，其中包含必要的Terraform代码和脚本，以使用Google Cloud Platform（GCP）启动示例多平台 VM / Kubernetes基础设施。生成的基础设施堆栈如下所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202001-incremental-app-migration-from-vms-to-kubernetes-1/images/infrastructure-stack_hub03430b11db205423478092095e6bc07_64043_7f9cac00b2cd5ac4f162e3185c543e80.webp 400w,
               /post/202001-incremental-app-migration-from-vms-to-kubernetes-1/images/infrastructure-stack_hub03430b11db205423478092095e6bc07_64043_b98ed8dd035acd4d46d3ea85e494146a.webp 760w,
               /post/202001-incremental-app-migration-from-vms-to-kubernetes-1/images/infrastructure-stack_hub03430b11db205423478092095e6bc07_64043_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202001-incremental-app-migration-from-vms-to-kubernetes-1/images/infrastructure-stack_hub03430b11db205423478092095e6bc07_64043_7f9cac00b2cd5ac4f162e3185c543e80.webp&#34;
               width=&#34;760&#34;
               height=&#34;438&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;构建示例vm--kubernetes平台&#34;&gt;构建示例VM / Kubernetes平台&lt;/h2&gt;
&lt;p&gt;Ambassador 参考架构仓库中提供的 Terraformed 基础设施示例将在GCP中创建一个简单的区域网络，其中包含一个&lt;a href=&#34;https://cloud.google.com/kubernetes-engine/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Kubernetes（GKE）&lt;/a&gt;集群和一些基于VM的服务，这些服务部署在（可公开寻址的）负载均衡器后面。部署在VM上的应用取自我的&lt;strong&gt;一个非常简单&lt;/strong&gt;的电子商务商店的“ &lt;a href=&#34;https://github.com/danielbryantuk/oreilly-docker-java-shopping&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Docker Java Shopping&lt;/a&gt; ”示例，该应用包括两个使用 Spring Boot 的Java服务和一个使用 Dropwizard 的Java服务。&lt;/p&gt;
&lt;p&gt;在Kubernetes集群中部署 Ambassador 可以简化整个网络的入口（ingress），还可以使工程团队集中化和标准化该网关的管理。对网络中的网关和边缘的集中运维提供了许多好处，例如“认证蔓延”的减少和规范横切面关注的能力，例如&lt;a href=&#34;https://www.getambassador.io/user-guide/tls-termination/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;TLS终止&lt;/a&gt;或穿透，基于上下文的路由（例如，使用&lt;a href=&#34;https://www.getambassador.io/reference/filter-reference/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;过滤器&lt;/a&gt;，基于HTTP标头的路由）和&lt;a href=&#34;https://www.getambassador.io/user-guide/advanced-rate-limiting&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;速率限制&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;克隆参考架构仓库后，导航至包含GCP Terraform代码的文件夹，您将找到一个&lt;a href=&#34;https://github.com/datawire/pro-ref-arch/blob/master/cloud-infrastructure/google-cloud-platform/README.md&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;README&lt;/a&gt;文件，其中包含复制我们的配置所需的分步说明。请注意，如果您超出了GCP免费试用的信用额度，则拆分此基础设施将需要付费：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ git clone git@github.com：datawire / pro-ref-arch.git 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ cd pro-ref-arch / cloud-infrastructure / google-cloud-platform
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;一旦完成所有配置并&lt;code&gt;terraform apply &lt;/code&gt;成功运行（可能需要花费几分钟时间），上图所示的基础设施将在您的GCP帐户中创建。您还将从Terraform的 &lt;code&gt;outputs&lt;/code&gt; 中看到一些可用于配置本地&lt;code&gt;kubectl&lt;/code&gt;工具以及设置Ambassador的信息。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Apply&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;complete&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Resources&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;15&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;added&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;changed&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;destroyed&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Outputs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;gcloud_get_creds&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;gcloud&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;container&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;clusters&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;credentials&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ambassador&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;demo&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;project&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;nodal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flagstaff&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;XXXX&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;zone&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;us&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;central1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;shop_loadbalancer_ip_port&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;35.192&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;25.31&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;shopfront_ambassador_config&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shopfront&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;annotations&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;getambassador&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;io&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;o&#34;&gt;---&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ambassador&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;Mapping&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;shopfront_mapping&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;prefix&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;shopfront&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;35.192&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;25.31&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;spec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;shopfront&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;第一个输出，名为 &lt;code&gt;gcloud_get_creds&lt;/code&gt; ，可以用来运行并配置本地 &lt;code&gt;kubectl&lt;/code&gt; 来指向新的 Terraformed Kubernetes 集群。例如，从上面的输出中，我将在本地终端上运行：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ gcloud container clusters get-credentials ambassador-demo --project nodal-flagstaff-XXXX --zone us-central1-f$ kubectl get svc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;NAME         TYPE        CLUSTER-IP    EXTERNAL-IP   PORT&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;S&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;   AGE
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kubernetes   ClusterIP   10.59.240.1   &amp;lt;none&amp;gt;        443/TCP   28m
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在，您可以按照 “ &lt;a href=&#34;https://www.getambassador.io/user-guide/getting-started/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;入门指南”&lt;/a&gt; 或自述文件中的 &lt;a href=&#34;https://www.getambassador.io/user-guide/getting-started/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;快速入门&lt;/a&gt; ，将 Ambassador 安装到集群中。网关启动并运行后，您就可以获得 Ambassador Kubernetes 服务的外部GCP负载平衡器IP，现在可以部署 Ambassador Mapping，该映射路由到Kubernetes群集之外的GCP负载平衡器。我故意使用当前的基础设施简化了&lt;a href=&#34;https://cloud.google.com/vpc/docs/routes&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;网络路由&lt;/a&gt;和&lt;a href=&#34;https://cloud.google.com/vpc/docs/firewalls&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;防火墙规则&lt;/a&gt;，但是本教程的后续版本将引入更具挑战性的配置。&lt;/p&gt;
&lt;p&gt;名为 &lt;code&gt;shopfront_ambassador_config&lt;/code&gt; 的 Terraform 输出提供了 Kubernetes 配置，可以将其复制粘贴到YAML文件中并应用于集群。然后，您应该能够通过 Ambassador IP和关联的映射访问运行在VM上的Shopfront服务（并与也在VM上运行的其他上游服务进行通信），例如：&lt;code&gt;http://{AMBASSADOR_LB_IP}/shopfront/&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;如果一切顺利，您应该可以在浏览器中看到以下内容：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/202001-incremental-app-migration-from-vms-to-kubernetes-1/images/shopfront_hu966734d70f91202462b4fbc881a4aed5_126079_956f1f2bb3010b66b437272baa1f4fff.webp 400w,
               /post/202001-incremental-app-migration-from-vms-to-kubernetes-1/images/shopfront_hu966734d70f91202462b4fbc881a4aed5_126079_54ff1cb65a83119b20f05b2521fffcb5.webp 760w,
               /post/202001-incremental-app-migration-from-vms-to-kubernetes-1/images/shopfront_hu966734d70f91202462b4fbc881a4aed5_126079_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/202001-incremental-app-migration-from-vms-to-kubernetes-1/images/shopfront_hu966734d70f91202462b4fbc881a4aed5_126079_956f1f2bb3010b66b437272baa1f4fff.webp&#34;
               width=&#34;760&#34;
               height=&#34;282&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这只是未来几个月我们将介绍的一系列教程的开始。我们渴望增加更多的复杂性，例如，创建具有对等VPC和更复杂的防火墙规则的网段，并且我们还将寻求展示如何使用 Kubernetes &lt;a href=&#34;https://kubernetes.io/docs/concepts/services-networking/service/#externalname&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;ExternalName&lt;/a&gt; 服务和 Consul Connect 来实现多集群服务网格，以实现完整端到端TLS。&lt;/p&gt;
&lt;p&gt;在完成对 Terraformed 基础设施的试验之后，请不要忘记删除它并进行清理，否则您可能会面临意外的GCP发票！&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ terraform destroy -force
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;本文和相关的多平台数据中心示例旨在帮助工程师将应用从VM迁移到Kubernetes集群。&lt;a href=&#34;https://www.getambassador.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Ambassador&lt;/a&gt; 经常被用作整个系统的中心入口，这可以整合&lt;a href=&#34;https://www.getambassador.io/concepts/auth-overview&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;身份验证&lt;/a&gt;，&lt;a href=&#34;https://www.getambassador.io/user-guide/rate-limiting&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;速率限制&lt;/a&gt;和其他跨域运维问题。&lt;/p&gt;
&lt;p&gt;我们将继续迭代示例基础结构代码，并计划支持其他云平台，例如 Digital Ocean 和 AWS。如果您对云供应商或复杂的路由方案有任何特殊要求，请与我联系。&lt;/p&gt;
&lt;p&gt;像往常一样，您还可以通过Twitter（&lt;a href=&#34;https://twitter.com/getambassadorio&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;@getambassadorio&lt;/a&gt;），&lt;a href=&#34;https://d6e.co/slack&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Slack&lt;/a&gt;或通过&lt;a href=&#34;https://github.com/datawire/ambassador&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;GitHub&lt;/a&gt;提出任何问题。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>诗和远方：蚂蚁金服Service Mesh深度实践</title>
      <link>https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/</link>
      <pubDate>Fri, 18 Oct 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;大家好，我是敖小剑，来自蚂蚁金服中间件团队，今天带来的主题是“诗和远方：蚂蚁金服 Service Mesh 深度实践”。&lt;/p&gt;
&lt;p&gt;在过去两年，我先后在 QCon 做过两次 ServiceMesh 的演讲：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2017年，当时 ServiceMesh 在国内还属于蛮荒时代，我当时做了一个名为“&lt;a href=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Servicemesh: 下一代微服务&lt;/a&gt;”的演讲，开始在国内布道 ServiceMesh 技术&lt;/li&gt;
&lt;li&gt;2018年，做了名为“&lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzUzMzU5Mjc1Nw==&amp;amp;mid=2247484395&amp;amp;idx=1&amp;amp;sn=0210fa2fd78828a05ea29e5eff074e20&amp;amp;chksm=faa0ec31cdd76527ad5c123511b1b5e684db1954920c36c794ee5c7391c867979946ed0f3b77&amp;amp;token=729443254&amp;amp;lang=zh_CN#rd&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;长路漫漫踏歌而行：蚂蚁金服Service Mesh实践探索&lt;/a&gt;”的演讲，介绍蚂蚁金服在 ServiceMesh 领域的探索性的实践，当时蚂蚁刚开始在 ServiceMesh 探索。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;今天，有幸第三次来到QCon，给大家带来的依然是蚂蚁金服在 Servicemesh 领域的实践分享。和去年不同的是，今年蚂蚁金服进入了Servicemesh 落地的深水区，规模巨大，而且即将迎来双十一大促考验。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：现场做了一个调研，了解听众对 ServicveMesh 的了解程度，结果不太理想：在此之前对 ServiceMesh 有了解的同学目测只有10%多点（肯定不到20%）。Servicemesh 的技术布道，依然任重道远。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;今天给大家带来的内容主要有三块：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;蚂蚁金服落地情况介绍：包括大家最关心的双十一落地情况；&lt;/li&gt;
&lt;li&gt;大规模落地的困难和挑战：分享一下我们过去一年中在大规模落地上遇到的问题；&lt;/li&gt;
&lt;li&gt;是否采用 ServiceMesh 的建议：这个问题经常被人问起，所以借这个机会给出一些中肯的建议供大家参考。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;蚂蚁金服落地情况介绍&#34;&gt;蚂蚁金服落地情况介绍&lt;/h2&gt;
&lt;h3 id=&#34;发展历程和落地规模&#34;&gt;发展历程和落地规模&lt;/h3&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-5_hu0e057b3f50d6f977126a0d99b32d5111_213132_dc1629b2add304f0e50df332a2f4ca08.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-5_hu0e057b3f50d6f977126a0d99b32d5111_213132_f5647c901f10a7129af51ccf88b233b8.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-5_hu0e057b3f50d6f977126a0d99b32d5111_213132_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-5_hu0e057b3f50d6f977126a0d99b32d5111_213132_dc1629b2add304f0e50df332a2f4ca08.webp&#34;
               width=&#34;760&#34;
               height=&#34;444&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;ServiceMesh 技术在蚂蚁金服的落地，先后经历过如下几个阶段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;技术预研&lt;/strong&gt; 阶段：2017年底开始调研并探索 Servicemesh 技术，并确定为未来发展方向；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;技术探索&lt;/strong&gt; 阶段：2018年初开始用 Golang 开发 Sidecar SOFAMosn，年中开源基于 Istio 的 SOFAMesh；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;小规模落地&lt;/strong&gt; 阶段：2018年开始内部落地，第一批场景是替代Java语言之外的其他语言的客户端SDK，之后开始内部小范围试点；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;规模落地&lt;/strong&gt; 阶段：2019年上半年，作为蚂蚁金融级云原生架构升级的主要内容之一，逐渐铺开到蚂蚁主站的业务应用，并平稳支撑了618大促；&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;全面大规模落地&lt;/strong&gt; 阶段：2019年下半年，在蚂蚁主站的业务中全面铺开，落地规模非常庞大，而且准备迎接双十一大促。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;目前 ServiceMesh 正在蚂蚁金服内部大面积铺开，我这里给出的数据是前段时间（大概9月中）在云栖大会上公布的数据：应用数百个，容器数量（pod数）超过10万。当然目前落地的pod数量已经远超过10万，这已经是目前全球最大的 ServiceMesh 集群，但这仅仅是一个开始，这个集群的规模后续会继续扩大，明年蚂蚁金服会有更多的应用迁移到 ServiceMesh。&lt;/p&gt;
&lt;h3 id=&#34;主要落地场景&#34;&gt;主要落地场景&lt;/h3&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-6_hu9e5bf0cbac2950413b600489b65c61be_276597_0e9a96d8e35f628e7453258cd61a4cb6.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-6_hu9e5bf0cbac2950413b600489b65c61be_276597_411892f2052bc18d8a3ef8c9a1956f34.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-6_hu9e5bf0cbac2950413b600489b65c61be_276597_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-6_hu9e5bf0cbac2950413b600489b65c61be_276597_0e9a96d8e35f628e7453258cd61a4cb6.webp&#34;
               width=&#34;760&#34;
               height=&#34;389&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;目前ServiceMesh在蚂蚁金服主站内部大量落地，包括支付宝的部分核心链路，落地的主要场景有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;多语言支持：目前除了支持 Java 之外，还支持 Golang，Python，C++，NodeJS 等语言的相互通信和服务治理；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;应用无感知的升级&lt;/em&gt;：关于这一点我们后面会有特别的说明；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;流量控制：经典的Istio精准细粒度流量控制；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RPC协议支持：和Istio不同，我们内部使用的主要是RPC协议；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可观测性&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;servicemesh的实际性能数据&#34;&gt;ServiceMesh的实际性能数据&lt;/h3&gt;
&lt;p&gt;之前和一些朋友和客户交流过，目前在ServiceMesh方面大家最关心的是ServiceMesh的性能表现，包括对于这次蚂蚁金服ServiceMesh上双十一，大家最想看到的也是性能指标。&lt;/p&gt;
&lt;p&gt;为什么大家对性能这么关注？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-7_hu4a1e18212622b82f092f3e8126ea57a8_14661_e815527aa2a1126b6c801eeb3149bf06.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-7_hu4a1e18212622b82f092f3e8126ea57a8_14661_c0d348cae1433160beb0f21c589cc568.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-7_hu4a1e18212622b82f092f3e8126ea57a8_14661_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-7_hu4a1e18212622b82f092f3e8126ea57a8_14661_e815527aa2a1126b6c801eeb3149bf06.webp&#34;
               width=&#34;760&#34;
               height=&#34;244&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;因为在ServiceMesh工作原理的各种介绍中，都会提到ServiceMesh是将原来的一次远程调用，改为走Sidecar（而且像Istio是客户端和服务器端两次Sidecar，如上图所示），这样一次远程调用就会变成三次远程调用，对性能的担忧也就自然而然的产生了：一次远程调用变三次远程调用，性能会下降多少？延迟会增加多少？&lt;/p&gt;
&lt;p&gt;下图是我们内部的大促压测数据，对比带MOSN和不带MOSN的情况（实现相同的功能）。其中MOSN是我们蚂蚁金服自行开发的基于Golang的Sidecar/数据平面，我们用它替代了Envoy，在去年的演讲中我有做过详细的介绍：&lt;/p&gt;
&lt;p&gt;SOFAMosn：https://github.com/sofastack/sofa-mosn&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-8_hu4148dceecb64b9201646b4ce8698228a_81762_38762d47fd48b849e6e4812343baf7e6.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-8_hu4148dceecb64b9201646b4ce8698228a_81762_ca57a7bc39c5360c532c9c81dc593dbd.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-8_hu4148dceecb64b9201646b4ce8698228a_81762_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-8_hu4148dceecb64b9201646b4ce8698228a_81762_38762d47fd48b849e6e4812343baf7e6.webp&#34;
               width=&#34;760&#34;
               height=&#34;260&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CPU：CPU使用在峰值情况下增加8%，均值约增加2%。在最新的一次压测中，CPU已经优化到基本持平（低于1%）；&lt;/li&gt;
&lt;li&gt;内存：带 Mosn 的节点比不带 Mosn 的节点内存占用平均多 15M；&lt;/li&gt;
&lt;li&gt;延迟：延迟增加平均约0.2ms。部分场景带MOSN比不带MOSN RT增加约5%，但是有部分特殊场景带MOSN比不带MOSN RT反而降低7.5%。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个性能表现，和前面&amp;quot;一次远程调用变三次远程调用&amp;quot;的背景和担忧相比有很大的反差。尤其是上面延迟的这个特殊场景，居然出现带MOSN（三次远程调用）比不带MOSN（一次远程调用） 延迟反而降低的情况。&lt;/p&gt;
&lt;p&gt;是不是感觉&lt;strong&gt;不科学&lt;/strong&gt;？&lt;/p&gt;
&lt;h3 id=&#34;servicemesh的基本思路&#34;&gt;ServiceMesh的基本思路&lt;/h3&gt;
&lt;p&gt;我们来快速回顾一下ServiceMesh实现的基本思路：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-9_hufdf03a37d1be847755b50a320d15f9b6_95992_4b68200fc2decacf80265b77fd00efaf.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-9_hufdf03a37d1be847755b50a320d15f9b6_95992_7a5dbece1eb8c879b22bb6ef938329c7.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-9_hufdf03a37d1be847755b50a320d15f9b6_95992_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-9_hufdf03a37d1be847755b50a320d15f9b6_95992_4b68200fc2decacf80265b77fd00efaf.webp&#34;
               width=&#34;760&#34;
               height=&#34;248&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在基于SDK的方案中，应用既有业务逻辑，也有各种非业务功能。虽然通过SDK实现了代码重用，但是在部署时，这些功能还是混合在一个进程内的。&lt;/p&gt;
&lt;p&gt;在ServiceMesh中，我们将SDK客户端的功能从应用中剥离出来，拆解为独立进程，以Sidecar的模式部署，让业务进程专注于业务逻辑：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;业务进程：专注业务实现；无需感知Mesh&lt;/li&gt;
&lt;li&gt;Sidecar进程：专注服务间通讯和相关能力；与业务逻辑无关&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们称之为&amp;quot;&lt;strong&gt;关注点分离&lt;/strong&gt;&amp;quot;：业务开发团队可以专注于业务逻辑，而底层的中间件团队（或者基础设施团队）可以专注于业务逻辑之外的各种通用功能。&lt;/p&gt;
&lt;p&gt;通过Sidecar拆分为两个独立进程之后，业务应用和Sidecar就可以实现“&lt;strong&gt;独立维护&lt;/strong&gt;”  ：我们可以单独更新/升级业务应用或者Sidecar。&lt;/p&gt;
&lt;h3 id=&#34;性能数据背后的情景分析&#34;&gt;性能数据背后的情景分析&lt;/h3&gt;
&lt;p&gt;我们回到前面的蚂蚁金服ServiceMesh落地后的性能对比数据：从原理上说，Sidecar拆分之后，原来SDK中的各种功能只是拆分到Sidecar中。整体上并没有增减，因此理论上说SDK和Sidecar性能表现是一致的。由于增加了应用和Sidecar之间的远程调用，性能不可避免的肯定要受到影响。&lt;/p&gt;
&lt;p&gt;首先我们来解释第一个问题：为什么性能损失那么小，和&amp;quot;一次远程调用变三次远程调用&amp;quot;的直觉不符？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-10_hua94d0732460306a0fe68651414454725_25775_5208923c31aa2044d4a7960f261cb10a.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-10_hua94d0732460306a0fe68651414454725_25775_0e8a02a5f03f00bb5e6f57257ae6d909.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-10_hua94d0732460306a0fe68651414454725_25775_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-10_hua94d0732460306a0fe68651414454725_25775_5208923c31aa2044d4a7960f261cb10a.webp&#34;
               width=&#34;760&#34;
               height=&#34;419&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;所谓的“直觉”，是将关注点都集中到了远程调用开销上，下意识的忽略了其他开销，比如SDK的开销、业务逻辑处理的开销，因此：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-10-2_hu581c8c6f92c7bd8080ca7dd9deabd415_20730_77be621fed42f1fd8ec6d904a725d064.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-10-2_hu581c8c6f92c7bd8080ca7dd9deabd415_20730_7c3f1e0b28a89f0f694b7ac5cc0176d4.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-10-2_hu581c8c6f92c7bd8080ca7dd9deabd415_20730_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-10-2_hu581c8c6f92c7bd8080ca7dd9deabd415_20730_77be621fed42f1fd8ec6d904a725d064.webp&#34;
               width=&#34;589&#34;
               height=&#34;131&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;推导出来的结果就是有3倍的开销，性能自然会有非常大的影响。&lt;/p&gt;
&lt;p&gt;但是，真实世界中的应用不是这样：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;业务逻辑的占比很高：Sidecar转发的资源消耗相比之下要低很多，通常是十倍百倍甚至千倍的差异。&lt;/li&gt;
&lt;li&gt;SDK也是有消耗的：即使不考虑各种复杂的功能特性，仅仅就报文（尤其是body）序列化的编解码开销也是不低的。而且，客户端和服务器端原有的编解码过程是需要处理Body的，而在Sidecar中，通常都只是读取Header而透传Body，因此在编解码上要快很多。另外应用和Sidecar的两次远程通讯，都是走的Localhost而不是真实的网络，速度也要快非常多。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此，在真实世界中，我们假定业务逻辑百倍于Sidecar的开销，而SDK十倍于Sidecar的开销，则：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-10-3_huf2ec04ca523d59035811024820dad1e5_22095_dd8cc9ba75000fa966e2b322a206c699.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-10-3_huf2ec04ca523d59035811024820dad1e5_22095_fcf9b4f0d073f0ba25f885a7d8d8b3fe.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-10-3_huf2ec04ca523d59035811024820dad1e5_22095_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-10-3_huf2ec04ca523d59035811024820dad1e5_22095_dd8cc9ba75000fa966e2b322a206c699.webp&#34;
               width=&#34;687&#34;
               height=&#34;131&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;推导出来的结果，性能开销从111增加到113，大约增加2%。这也就解释了为什么我们实际给出的ServiceMesh的CPU和延迟的性能损失都不大的原因。当然，这里我是刻意选择了100和10这两个系数来拼凑出2%这个估算结果，以迎合我们前面给出“均值约增加2%”的数据。这不是准确数值，只是用来模拟。&lt;/p&gt;
&lt;h3 id=&#34;情理当中的意外惊喜&#34;&gt;情理当中的意外惊喜&lt;/h3&gt;
&lt;p&gt;前面的分析可以解释性能开销增加不多的情景，但是，还记得我们的数据中有一个不科学的地方吗：“部分特殊场景带 SOFAMosn比不带 SOFAMosn RT反而降低7.5%”。&lt;/p&gt;
&lt;p&gt;理论上，无论业务逻辑和SDK的开销比Sidecar的开销大多少，也就是不管我们怎么优化Sidecar的性能，其结果也只能接近零。无论如何不可能出现多两个Sidecar，CPU消耗和延迟反而降低的情况。&lt;/p&gt;
&lt;p&gt;这个“不科学”是怎么出现的？&lt;/p&gt;
&lt;p&gt;我们继续来回顾这个ServiceMesh的实现原理图：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-11_hu277b384e0b4a3c71df66c096462c9be2_89424_281a9fc03fb1c3f4db869f5de71369e9.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-11_hu277b384e0b4a3c71df66c096462c9be2_89424_6ec84354a9fbad8712d5dddc49707ecb.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-11_hu277b384e0b4a3c71df66c096462c9be2_89424_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-11_hu277b384e0b4a3c71df66c096462c9be2_89424_281a9fc03fb1c3f4db869f5de71369e9.webp&#34;
               width=&#34;760&#34;
               height=&#34;246&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;出现性能大幅提升的主要的原因，是我们在 SOFAMosn 上做了大量的优化，特别是路由的缓存。在蚂蚁金服内部，服务路由的计算和处理是一个异常复杂的逻辑，非常耗资源。而在最近的优化中，我们为服务路由增加了缓存，从而使得服务路由的性能得到了大幅提升。因此：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-11-2_hu974c42d661eb9f392f0763979c947484_24516_af43c010c949949bbfa62dc84aa8b783.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-11-2_hu974c42d661eb9f392f0763979c947484_24516_3447dd8c9afeb54514b73a03907cf997.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-11-2_hu974c42d661eb9f392f0763979c947484_24516_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-11-2_hu974c42d661eb9f392f0763979c947484_24516_af43c010c949949bbfa62dc84aa8b783.webp&#34;
               width=&#34;754&#34;
               height=&#34;135&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：这里我依然是刻意拼凑出-7%这个估算结果，请注意这不是准确数值，只是用来模拟示意。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;也许有同学会说，这个结果不“公平”：这是优化了的服务路由实现在PK没有优化的服务路由实现。的确，理论上说，在Sidecar中做的任何性能优化，在SDK里面同样可以实现。但是，在SDK上做的优化需要等整个调用链路上的应用全部升级到优化后的SDK之后才能完全显现。而在传统SDK方案中，SDK的升级是需要应用配合，这通常是一个漫长的等待过程。很可能代码优化和发版一周搞定，但是让全站所有应用都升级到新版本的SDK要花费数月甚至一年。&lt;/p&gt;
&lt;p&gt;此时 ServiceMesh 的优点就凸显出来了：ServiceMesh下，业务应用和 Sidecar 可以“&lt;strong&gt;独立维护&lt;/strong&gt;” ，我们可以很方便的在业务应用无感知的情况下升级Sidecar。因此，任何Sidecar的优化结果，都可以非常快速的获取收益，从而推动我们对Sidecar进行持续不断的升级。&lt;/p&gt;
&lt;p&gt;前面这个延迟降低7%的例子，就是一个非常经典的故事：在中秋节前后，我们开发团队的同学，不辞辛苦加班加点的进行压测和性能调优，在一周之内连续做了多次性能优化，连发了多个性能优化的小版本，以“小步快跑”的方式，最后拿到了这个令大家都非常开心的结果。&lt;/p&gt;
&lt;p&gt;总结：&lt;strong&gt;持续不断的优化 + 无感知升级 = 快速获得收益&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是一个意外惊喜，但又在情理之中：这是SDK下沉到基础设施并具备独立升级能力后带来的红利。&lt;/p&gt;
&lt;p&gt;也希望这个例子，能够让大家更深刻的理解 ServiceMesh 的基本原理和优势。&lt;/p&gt;
&lt;h2 id=&#34;大规模落地的困难和挑战&#34;&gt;大规模落地的困难和挑战&lt;/h2&gt;
&lt;p&gt;当Servicemesh遇到蚂蚁金服的规模，困难和挑战也随之而来：当规模达到一定程度时，很多原本很小的问题都会急剧放大。后面我将在性能、容量、稳定性、可维护性和应用迁移几个方面给大家介绍我们遇到的挑战和实践。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-13_hu1a20be8fbf2aca9a07cbd1725fac8049_79494_6a4b4f49de99bd3912620f34d16b597f.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-13_hu1a20be8fbf2aca9a07cbd1725fac8049_79494_d69318f10612dbc24780da2aa3fc536d.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-13_hu1a20be8fbf2aca9a07cbd1725fac8049_79494_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-13_hu1a20be8fbf2aca9a07cbd1725fac8049_79494_6a4b4f49de99bd3912620f34d16b597f.webp&#34;
               width=&#34;760&#34;
               height=&#34;179&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;数据平面的优化&#34;&gt;数据平面的优化&lt;/h3&gt;
&lt;p&gt;在数据平面上，蚂蚁金服采用了自行研发的基于Golang的方案：SOFAMosn，简称MOSN。关于为什么选择全新开发SOFAMosn，而不是直接使用Envoy的原因，在去年QCon的演讲中我有过详细的介绍，有兴趣可以了解。&lt;/p&gt;
&lt;p&gt;前面我们给出的性能数据，实际上主要是数据平面的性能，也就是作为Sidecar部署的SOFAMosn的性能表现。从数据上看MOSN目前的性能表现还是很不错的，这背后是我们在MOSN上做了非常多的性能优化。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;CPU优化：在SOFAMosn中我们进行了Golang 的 writev 优化，将多个包拼装一次写以降低 syscall 调用。测试中发现，Golang 1.9 的时候 writev 有内存泄露的bug。当时debug的过程非常的辛苦&amp;hellip;&amp;hellip; 详情见我们当时给 Golang 提交的PR： &lt;a href=&#34;https://github.com/golang/go/pull/32138&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/golang/go/pull/32138&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;内存优化：在内存复用，我们发现报文直接解析会产生大量临时对象。SOFAMosn 通过直接复用报文字节的方式，将必要的信息直接通过 unsafe.Pointer 指向报文的指定位置来避免临时对象的产生。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;延迟优化：前面我们谈到Sidecar是通过只解析Header而透传Body来保证性能的。针对这一点，我们进行了协议升级，以便快速读取header。比如我们使用的 TR 协议请求头和 Body 均为 hessian 序列化，性能损耗较大。而 Bolt 协议中 Header 是一个扁平化map，解析性能损耗小。因此我们升级应用改走 Bolt 协议来提升 Sidecar 转发的性能。这是一个典型的针对 Sidecar 特性而做的优化。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外还有前面特意重点介绍的路由缓存优化（也就是那个不科学的延迟降低7%的场景）。犹豫蚂蚁内部路由的复杂性（一笔请求经常需要走多种路由策略最终确定路由结果目标），通过对相同条件的路由结果做秒级缓存，我们成功将某核心链路的全链路 RT 降低 7%。&lt;/p&gt;
&lt;p&gt;这里我简单给出了上述几个典型案例，双十一之后会有更多更详细的SOFAMosn资料分享出来，有兴趣的同学可以多关注。&lt;/p&gt;
&lt;p&gt;在双十一过后，我们也将加大 SOFAMosn 在开源上的投入，将 SOFAMosn 做更好地模块化地抽象，并且将双十一中经过考验的各种优化放进去，我们预计在 2020 年的 1 月底可以发布第一个优化后的版本。&lt;/p&gt;
&lt;h3 id=&#34;mixer的性能优化&#34;&gt;Mixer的性能优化&lt;/h3&gt;
&lt;p&gt;Mixer的性能优化是个老生常谈的话题，基本上只要谈及 Istio 的性能，都避无可避：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mixer的性能问题，一直都是Istio中最被人诟病的地方&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;尤其在Istio 1.1/1.2版本之后，引入 Out-Of-Process Adapter 之后，更是雪上加霜。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-15_hu58c9a60ad7cf778df35f165c1936874f_78059_971ca56783196a498bbfad77a34d23d4.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-15_hu58c9a60ad7cf778df35f165c1936874f_78059_758c370975ce5f7c1936723687b684d5.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-15_hu58c9a60ad7cf778df35f165c1936874f_78059_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-15_hu58c9a60ad7cf778df35f165c1936874f_78059_971ca56783196a498bbfad77a34d23d4.webp&#34;
               width=&#34;535&#34;
               height=&#34;491&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;原来Sidecar和Mixer之间的远程调用已经严重影响性能，在引入 Out-Of-Process Adapter 之后又在 Traffic 流程中引入了新的远程调用，性能更加不可接受。&lt;/p&gt;
&lt;p&gt;从落地的角度看，&lt;strong&gt;Mixer V1&lt;/strong&gt; 糟糕至极的性能，已经是“生命无法承受之重”。对于一般规模的生产级落地而言，Mixer性能已经是难于接受，更不要提大规模落地……&lt;/p&gt;
&lt;p&gt;Mixer V2方案则给了社区希望：将Mixer合并进Sidecar，引入web assembly进行Adapter扩展，这是我们期待的Mixer落地的正确姿势，是Mixer的未来，是Mixer的&amp;quot;诗和远方&amp;quot;。然而社区望穿秋水，但 Mixer V2 迟迟未能启动，长期处于 In Review 状态，远水解不了近渴。&lt;/p&gt;
&lt;p&gt;因此在Mixer落地上，我们只能接受妥协方案，所谓&amp;quot;眼前的苟且&amp;quot;：一方面我们弃用Mixer v1，改为在 SOFAMosn 中直接实现功能；另一方面我们并没有实现Mixer V2的规划。实际的落地方式是：我们只在 SOFAMosn 中提供最基本的策略检查功能如限流，鉴权等，另外可观测性相关的各种能力也都是从 SOFAMosn 直接输出。&lt;/p&gt;
&lt;h3 id=&#34;pilot的性能优化&#34;&gt;Pilot的性能优化&lt;/h3&gt;
&lt;p&gt;在Istio中，Pilot是一个被Mixer掩盖的重灾区：长期以来大家的性能关注点都在Mixer，表现糟糕而且问题明显的Mixer一直在吸引火力。但是当选择放弃Mixer（典型如官方在Istio新版本中提供的关闭Mixer的配置开关）之后，Pilot的性能问题也就很快浮出水面。&lt;/p&gt;
&lt;p&gt;这里简单展示一下我们在Pilot上做的部分性能优化：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;序列化优化：我们全面使用types.Any类型，弃用types.Struct类型，序列化性能提升70倍，整体性能提升4倍。Istio最新的版本中也已经将默认模式修改为types.Any类型。我们还进行了CR(CustomResource)的序列化缓存，将序列化时机从Get/List操作提前至事件触发时，并缓存结果。大幅降低序列化频率，压测场景下整体性能提升3倍，GC频率大幅下降&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;预计算优化：支持Sidecar CRD维度的CDS /LDS/RDS 预计算，大幅降低重复计算，压测场景下整体性能提升6倍；支持Gateway维度的CDS / LDS / RDS 预计算；计算变更事件的影响范围，支持局部推送，减少多余的计算和对无关sidecar的打扰&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;推送优化：支持运行时动态降级，支持熔断阈值调整，限流阈值调整，静默周期调整，日志级别调整；实现增量ADS接口，在配置相关处理上，sidecar cpu减少90%，pilot cpu减少42%&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里简单解释一下，Pilot在推送数据给Sidecar时，代码实现上的有些简单：Sidecar连接上Pilot时；Pilot就给Sidecar下发xDS数据。假定某个服务有100个实例，则这100个实例的Sidecar连接到Pilot时，每次都会进行一次下发数据的计算，然后进行序列化，再下发给连上来的Sidecar。下一个sidecar连接上来时，重复这些计算和序列化工作，而不管下发的数据是否完全相同。我们称之为“千人千面”。&lt;/p&gt;
&lt;p&gt;而实际中，同一个服务往往有多个实例，Pilot下发给这些实例的Sidecar的数据往往是相同的。因此我们做了优化，提前做预计算和序列化并缓存结果，以便后续重复的实例可以直接从缓存中取。因此，“千人千面”就可以优化为“千人百面”或者“千人十面”，从而大幅提高性能。&lt;/p&gt;
&lt;p&gt;另外，对于整个ServiceMesh体系，Pilot至关重要。因此Pilot本身也应该进行保护，也需要诸如熔断/限流等特性。&lt;/p&gt;
&lt;h3 id=&#34;servicemesh的运维&#34;&gt;ServiceMesh的运维&lt;/h3&gt;
&lt;p&gt;在ServiceMesh的运维上，我们继续坚持“线上变更三板斧”原则。这里的变更，包括发布新版本，也包括修改配置，尤其特指修改Istio的CRD。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-17_hu583fdd39bd893862aa06143c26eb8aab_51923_7e002aca7210c6d431a74ecb4763b8a9.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-17_hu583fdd39bd893862aa06143c26eb8aab_51923_7ced93915ff7cf15afb307d6de7bf400.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-17_hu583fdd39bd893862aa06143c26eb8aab_51923_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-17_hu583fdd39bd893862aa06143c26eb8aab_51923_7e002aca7210c6d431a74ecb4763b8a9.webp&#34;
               width=&#34;563&#34;
               height=&#34;300&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;线上变更“三板斧”指的是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;可灰度：任何变更，都必须是可以灰度的，即控制变更的生效范围。先做小范围内变更，验证通过之后才扩大范围。&lt;/li&gt;
&lt;li&gt;可监控：在灰度过程中，必须能做到可监控，能了解到变更之后对系统的应用。如果没有可监控，则可灰度也就没有意义了。&lt;/li&gt;
&lt;li&gt;可回滚：当通过监控发现变更后会引发问题时，还需要有方法可以回滚。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们在这里额外引入了一个名为“ScopeConfig”的配置变更生效范围的控制能力，即配置变更的灰度。什么是配置变更的灰度呢？&lt;/p&gt;
&lt;p&gt;Istio的官方实现，默认修改配置（Istio API 对应的各种CRD）时新修改的配置会直接全量推动到所有生效的Sidecar，即配置变更本身无法灰度。注意这里和平时说的灰度不同，比如最常见的场景，服务A调用服务B，并假定服务A有100个实例，而服务B有10个v1版本的服务实例正在进行。此时需要更新服务B到新的v2版本。为了验证v2新版本，我们通常会选择先上线一个服务B的v2版本的新实例，通过Istio进行流量百分比拆分，比如切1%的流量到新的v2版本的，这被称为“灰度发布”。此时新的“切1%流量到v2”的CRD被下发到服务A的Sidecar，这100个Sidecar中的每个都会执行该灰度策略。如果v2版本有问题不能正常工作，则只影响到1%的流量，即此时Istio的灰度控制的是CRD配置生效之后Sidecar的流量控制行为。&lt;/p&gt;
&lt;p&gt;但是，实际生产中，配置本身也是有风险的。假设在配置Istio CRD时出现低级错误，不小心将新旧版本的流量比例配反了，错误配置成了99%的流量去v2版本。则当新的CRD配置被下发到全部100个服务A的实例时并生效时，Sidecar控制的流量就会发生非常大的变化，造成生产事故。&lt;/p&gt;
&lt;p&gt;为了规避这个风险，就必须引入配置变更的范围控制，比如将新的CRD配置下发到少数Sidecar，验证配置无误后再扩展到其他Sidecar。&lt;/p&gt;
&lt;h3 id=&#34;应用平滑迁移的终极方案&#34;&gt;应用平滑迁移的终极方案&lt;/h3&gt;
&lt;p&gt;在ServiceMesh落地的过程中，现有应用如何平滑迁移到ServiceMesh，是一个至关重要的话题。典型如基于传统微服务框架如SpringCloud/Dubbo的应用，如何逐个（或者分批）的迁移到ServiceMesh上。&lt;/p&gt;
&lt;p&gt;蚂蚁金服在去年进行落地实践时，就特别针对应用平滑迁移进行了深入研究和探索。这个问题是 ServiceMesh 社区非常关注的核心落地问题，今天我们重点分享。&lt;/p&gt;
&lt;p&gt;在今年9月份的云栖大会上，蚂蚁推出了双模微服务的概念，如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-18_hu0e71831ea6f51948a735cc13add8dea1_111871_3e44acc562b57957a927e58e2c8607b5.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-18_hu0e71831ea6f51948a735cc13add8dea1_111871_6f54187700c3293fd45634c8af7074e6.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-18_hu0e71831ea6f51948a735cc13add8dea1_111871_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-18_hu0e71831ea6f51948a735cc13add8dea1_111871_3e44acc562b57957a927e58e2c8607b5.webp&#34;
               width=&#34;760&#34;
               height=&#34;400&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;“双模微服务”是指传统微服务和 ServiceMesh 双剑合璧，即“基于SDK的传统微服务”可以和“基于Sidecar的ServiceMesh微服务”实现下列目标：&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;双模还包括对应用运行平台的要求，即两个体系下的应用，既可以运行在虚拟机之上，也可以运行在容器/k8s之上。&lt;/p&gt;
&lt;p&gt;怎么实现这么一个美好的双模微服务目标呢？&lt;/p&gt;
&lt;p&gt;我们先来分析一下传统微服务体系和ServiceMesh体系在服务注册/服务发现/服务相关的配置下发上的不同。&lt;/p&gt;
&lt;p&gt;首先看传统微服务体系，其核心是服务注册中心/配置中心，应用通过引用SDK的方式来实现对接各种注册中心/配置中心。通常不同的注册中心/配置中心都有各自的实现机制和接口协议，SDK和注册中心/配置中心的交互方式属于内部实现机制，并不通用。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-19_hu67f04a40faee4df7ba1f7077b059582e_9426_d400e4f38c3e3b09c63bd1e7bd33a174.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-19_hu67f04a40faee4df7ba1f7077b059582e_9426_4f09a2d07b80ca7b42657e9d0b454cfb.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-19_hu67f04a40faee4df7ba1f7077b059582e_9426_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-19_hu67f04a40faee4df7ba1f7077b059582e_9426_d400e4f38c3e3b09c63bd1e7bd33a174.webp&#34;
               width=&#34;760&#34;
               height=&#34;163&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;优点是支持海量数据（十万级别甚至百万级别），具备极强的分发能力，而且经过十余年间的打磨，稳定可靠可谓久经考验。市面上有很多成熟的开源产品，各大公司也都有自己的稳定实现。如阿里集团的Nacos，蚂蚁金服的SOFARegistry。&lt;/p&gt;
&lt;p&gt;SOFARegistry：https://github.com/sofastack/sofa-registry&lt;/p&gt;
&lt;p&gt;缺点是注册中心/配置中心与SDK通常是透传数据，即注册中心/配置中心只进行数据的存储和分发。大量的控制逻辑需要在SDK中实现，而SDK是嵌入到应用中的。因此，任何变更都需要改动SDK并要求应用升级。&lt;/p&gt;
&lt;p&gt;再来看看ServiceMesh方案，以Istio为例：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-19-2_hu62d5d39ae532dee516e46f4c5f2adeaf_7951_54f7ce8d36ab531c6ee54877d8dcf224.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-19-2_hu62d5d39ae532dee516e46f4c5f2adeaf_7951_cab6fd08b8b95e9de8c711a6a8a59180.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-19-2_hu62d5d39ae532dee516e46f4c5f2adeaf_7951_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-19-2_hu62d5d39ae532dee516e46f4c5f2adeaf_7951_54f7ce8d36ab531c6ee54877d8dcf224.webp&#34;
               width=&#34;760&#34;
               height=&#34;78&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;ServiceMesh的优点是引入了控制平面（在Istio中具体指Pilot组件），通过控制平面来提供强大的控制逻辑。而控制平面的引入，MCP/xDS等标准协议的制订，实现了数据源和下发数据的解耦。即存储于注册中心/配置中心（在Istio中体现为k8s api server + Galley）的数据可以有多种灵活的表现形式，如CRD形式的Istio API，通过运行于Pilot中的Controller来实现控制逻辑和格式转换，最后统一转换到xDS/UDPA。这给API的设计提供了非常大的施展空间，极具灵活度，扩展性非常好。&lt;/p&gt;
&lt;p&gt;缺点也很明显，和成熟的注册中心/配置中心相比，支持的容量有限，下发的性能和稳定性相比之下有很大差距。&lt;/p&gt;
&lt;p&gt;控制平面和传统注册中心/配置中心可谓各有千秋，尤其他们的优缺点是互补的，如何结合他们的优势？&lt;/p&gt;
&lt;p&gt;此外，&lt;strong&gt;如何打通两个体系是ServiceMesh社区的老大难问题&lt;/strong&gt;。尤其是缺乏标准化的社区方案，只能自行其是，各自为战。&lt;/p&gt;
&lt;p&gt;最近，在综合了过去一年多的思考和探索之后，蚂蚁金服和阿里集团的同事们共同提出了一套完整的解决方案，我们戏称为“终极方案”：希望可以通过这个方案打通传统微服务体系和ServiceMesh体系，彻底终结这个困扰已久的问题。&lt;/p&gt;
&lt;p&gt;这个方案的核心在于： &lt;strong&gt;以MCP和xDS/UDPA协议为基础，融合控制平面和传统注册中心/配置中心&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-20_hu1938fc9d6b8953b5584abd1cc0708c0e_31598_f518b002245f3930f051f3de0257bc54.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-20_hu1938fc9d6b8953b5584abd1cc0708c0e_31598_9a65a0084b0db1b2b45c004af043c5a3.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-20_hu1938fc9d6b8953b5584abd1cc0708c0e_31598_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-20_hu1938fc9d6b8953b5584abd1cc0708c0e_31598_f518b002245f3930f051f3de0257bc54.webp&#34;
               width=&#34;760&#34;
               height=&#34;365&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如上图所示，如果我们将融合控制平面和传统注册中心/配置中心而来的新的产品形态视为一个整体，则这个新产品形态的能力主要有三块：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;传统注册中心的数据存储能力：支持海量数据&lt;/li&gt;
&lt;li&gt;ServiceMesh控制平面的能力：解耦之后API设计的弹性和灵活度&lt;/li&gt;
&lt;li&gt;传统注册中心的分发能力：性能、速度、稳定性&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这个新的产品形态可以理解为“带控制平面的注册中心/配置中心”，或者“存储/分发能力加强版的控制平面”。名字不重要，重要的是各节点的&lt;strong&gt;通讯交互协议必须标准化&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;MCP协议：MCP协议是Istio中用于Pilot和Galley之间同步数据的协议，源自xDS协议。我们设想通过MCP协议将不同源的注册中心集成起来，目标是聚合多注册中心的数据到Pilot中，实现打通异构注册中心（未来也会用于多区域聚合）。&lt;/li&gt;
&lt;li&gt;xDS/UDPA协议：xDS协议源自Envoy，是目前数据平面的事实标准，UDPA是正在进行中的基于xDS协议的标准化版本。Sidecar基于xDS/UDPA协议接入控制平面，我们还有进一步的设想，希望加强SDK方案，向Istio的功能靠拢，具体表现为SDK支持xDS协议（初期版本先实现最小功能集）。目标是希望在对接控制平面的前提下，应用可以在ServiceMesh和SDK方案之间自由选择和迁移。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;基于这个思路，我们给出如下图所示的解决方案，希望最大限度的整合传统微服务框架和ServiceMesh。其基本指导原则是：&lt;strong&gt;求同存异&lt;/strong&gt;，&lt;strong&gt;保持兼容&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-21_hu42f07de9e0efeb2608077a2709cd5273_40911_cbbc2ad5daa23e55748ed59454e0c4fb.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-21_hu42f07de9e0efeb2608077a2709cd5273_40911_a8bd18b35b6d66593500b0ccfe6144cd.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-21_hu42f07de9e0efeb2608077a2709cd5273_40911_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-21_hu42f07de9e0efeb2608077a2709cd5273_40911_cbbc2ad5daa23e55748ed59454e0c4fb.webp&#34;
               width=&#34;760&#34;
               height=&#34;383&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;上图中，蓝色部分是通用的功能模块，我们希望可以和社区一起共建。红色部分是不兼容的功能模块，但是保持API兼容。&lt;/p&gt;
&lt;p&gt;具体说，右边是各种注册中心（配置中心同理）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Galley和底下的k8s API Server可以视为一个特殊的注册中心，这是Istio的官方方式。&lt;/li&gt;
&lt;li&gt;Nacos/SOFARegistry 是阿里集团和蚂蚁金服的注册中心，支持海量规模。我们计划添加MCP协议的支持，直接对接Pilot。&lt;/li&gt;
&lt;li&gt;其他的注册中心，也可以通过提供MCP协议支持的方式，接入到这个方案中&lt;/li&gt;
&lt;li&gt;对于不支持MCP的注册中心，可以通过开发一个MCP Proxy模块以适配器模式的方式间接接入。当然最理想的状态是出现成熟的通用开源方案来统一解决，比如Nacos Sync 有计划做类似的事情。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;左边是数据平面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ServiceMesh体系下的Sidecar（如Envoy和我们蚂蚁金服的MOSN）目前都已经支持xDS/UDPA。&lt;/li&gt;
&lt;li&gt;相对来说，这个方案中比较“脑洞”的是在SDK方案如Spring Cloud/Dubbo/SOFARPC中提供xDS的支持，以便对接到已经汇总了全局数据的控制平面。从这个角度说，支持xDS的SDK方案，也可以视为广义的数据平面。我们希望后面可以推动社区朝这个方向推进，短期可以先简单对接，实现xDS的最小功能集；长期希望SDK方案的功能能向Istio看齐，实现更多的xDS定义的特性。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个方案对运行平台没有任何特别要求，只要网络能通，应用和各个组件可以灵活选择运行在容器（k8s）中或虚拟机中。&lt;/p&gt;
&lt;p&gt;需要特别强调的是，这个方案最大的优点在于它是一个&lt;strong&gt;高度标准化的社区方案&lt;/strong&gt;：通过MCP协议和xDS协议对具体实现进行了解耦和抽象，整个方案没有绑定到任何产品和供应商。因此，我们希望这个方案不仅仅可以用于阿里集团和蚂蚁金服，也可以用于整个 Istio 社区。阿里集团和蚂蚁金服目前正在和Istio社区联系，我们计划将这个方案贡献出来，并努力完善和加强Pilot的能力，使之能够满足我们上面提到的的美好愿景：融合控制平面和传统注册中心/配置中心的优点，打通传统微服务框架和ServiceMesh，让应用可以平滑迁移灵活演进。&lt;/p&gt;
&lt;p&gt;希望社区认可这个方案的同学可以参与进来，和我们一起努力来建设和完善它。&lt;/p&gt;
&lt;h2 id=&#34;是否采用servicemesh的建议&#34;&gt;是否采用ServiceMesh的建议&lt;/h2&gt;
&lt;p&gt;在过去一年间，这个问题经常被人问起。借这个机会，结合过去一年中的实践，以及相比去年此时更多的心得和领悟，希望可以给出一些更具参考价值的建议。&lt;/p&gt;
&lt;h3 id=&#34;建议一有没有直接痛点&#34;&gt;建议一：有没有直接痛点&lt;/h3&gt;
&lt;p&gt;有没有短期急迫需求，通常取决于当前有没有迫切需要解决的痛点。&lt;/p&gt;
&lt;p&gt;在ServiceMesh的发展过程中，有两个特别清晰而直接的痛点，它们甚至对ServceMesh的诞生起了直接的推动作用：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;多语言支持&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-23_hua9c219ffe072ca18ce95dd4ce58c1bb0_85122_d10c7d871897882e12c2fb7321b8d319.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-23_hua9c219ffe072ca18ce95dd4ce58c1bb0_85122_5a0a6a7f86c1a34c44fcdf42b3484487.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-23_hua9c219ffe072ca18ce95dd4ce58c1bb0_85122_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-23_hua9c219ffe072ca18ce95dd4ce58c1bb0_85122_d10c7d871897882e12c2fb7321b8d319.webp&#34;
               width=&#34;400&#34;
               height=&#34;231&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是SDK方案的天然局限，也是ServiceMesh的天然优势。需要支持的编程语言越多，为每个编程语言开发和维护一套SDK的成本就越高，就有越多的理由采用ServiceMesh。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;类库升级困难&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-23-2_hu98fb10d0a48712e80a2a5f2fe2194fc1_12106_a9a105e4e29cb5b3116f707316430454.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-23-2_hu98fb10d0a48712e80a2a5f2fe2194fc1_12106_e7ebc71f01ebdcf673ecbfb970adc428.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-23-2_hu98fb10d0a48712e80a2a5f2fe2194fc1_12106_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-23-2_hu98fb10d0a48712e80a2a5f2fe2194fc1_12106_a9a105e4e29cb5b3116f707316430454.webp&#34;
               width=&#34;201&#34;
               height=&#34;200&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;同样，这也是SDK方案的天然局限，也是ServiceMesh的天然优势（还记得前面那个不科学的-7%吗？）。SDK方案中类库和业务应用打包在一起，升级类库就不得不更新整个业务应用，而且是需要更新所有业务团队的所有应用。在大部分公司，这通常是一个非常困难的事情，而且每次SDK升级都要重复一次这种痛苦。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;而且，这两个痛点有可能会同时存在：有多个编程语言的类库需要升级版本&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;所以，第一个建议是先检查是否存在这两个痛点。&lt;/p&gt;
&lt;h3 id=&#34;建议二老应用升级改造&#34;&gt;建议二：老应用升级改造&lt;/h3&gt;
&lt;p&gt;ServiceMesh的无侵入性，在老应用升级改造，尤其是希望少改代码甚至完全不改代码的情况下，堪称神器。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-24_hu5e0727811a203c735304c3754734f514_137713_35dae1a2077718a479ae33be35d4be2d.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-24_hu5e0727811a203c735304c3754734f514_137713_d0f089633f173da34e8a928cf89148dd.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-24_hu5e0727811a203c735304c3754734f514_137713_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-24_hu5e0727811a203c735304c3754734f514_137713_35dae1a2077718a479ae33be35d4be2d.webp&#34;
               width=&#34;760&#34;
               height=&#34;327&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;所以，第二个建议是，如果有老应用无改动升级改造的需求，对流量控制、安全、可观测性有诉求，则可以考虑采用 ServiceMesh。&lt;/p&gt;
&lt;h3 id=&#34;建议三维护统一的技术栈&#34;&gt;建议三：维护统一的技术栈&lt;/h3&gt;
&lt;p&gt;这个建议仅仅适用于技术力量相对薄弱的企业，这些企业普遍存在一个问题：技术力量不足，或者主要精力投放在业务实现，导致无力维护统一的技术栈，系统呈现烟囱式架构。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-25_huf96e306f7dbff66399fa2b6de2bfdd44_410328_23a936e061841165ebdd04cd2042ec96.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-25_huf96e306f7dbff66399fa2b6de2bfdd44_410328_5f5bb1ea6ab9cf4a8c5ed948ddb07a39.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-25_huf96e306f7dbff66399fa2b6de2bfdd44_410328_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-25_huf96e306f7dbff66399fa2b6de2bfdd44_410328_23a936e061841165ebdd04cd2042ec96.webp&#34;
               width=&#34;708&#34;
               height=&#34;452&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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;这种情况下，建议引入 ServiceMesh 技术，通过 ServiceMesh 将非业务逻辑从应用剥离并下沉的特性，来统一整个公司的技术栈。&lt;/p&gt;
&lt;p&gt;特别需要强调的是，对于技术力量不足、严重依赖外包和采购的企业，尤其是银行/保险/证券类金融企业，引入 ServiceMesh 会有一个额外的特殊功效，至关重要：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;将乙方限制在业务逻辑的实现上&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;即企业自行建设和控制 ServiceMesh，作为统一的技术栈，在其上再开发运行业务应用。由于这些业务应用运行在 ServcieMesh 之上，因此只需要实现业务逻辑，非业务逻辑的功能由 ServcieMesh 来提供。通过这种方式，可以避免乙方公司借项目机会引入各种技术栈而造成技术栈混乱，导致后期维护成本超高；尤其是要避免引入私有技术栈，因为私有技术栈会造成对甲方事实上的技术绑定（甚至技术绑架）。&lt;/p&gt;
&lt;h3 id=&#34;建议四云原生落地&#34;&gt;建议四：云原生落地&lt;/h3&gt;
&lt;p&gt;最后一个建议，和云原生有关。在去年的QCon演讲中，我曾经提到我们在探索 kubernetes / servicemesh / serverless 结合的思路。在过去一年，蚂蚁金服一直在云原生领域做深度探索，也有一些收获。其中，有一点我们是非常明确的：&lt;strong&gt;Mesh化是云原生落地的关键步骤&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;下图展示了蚂蚁金服在云原生落地方面的基本思路：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-27_hudfca8226e135aff32c76c3e4c9981d58_85234_057f2ec60e9971d182858bd2b893f7d9.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-27_hudfca8226e135aff32c76c3e4c9981d58_85234_462727cfc79e06421247cb8d7cc788ce.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-27_hudfca8226e135aff32c76c3e4c9981d58_85234_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-27_hudfca8226e135aff32c76c3e4c9981d58_85234_057f2ec60e9971d182858bd2b893f7d9.webp&#34;
               width=&#34;760&#34;
               height=&#34;307&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;最下方是云，以kubernetes为核心，关于这一点社区基本已经达成共识：kubernetes 就是云原生下的操作系统&lt;/li&gt;
&lt;li&gt;在kubernetes之上，是Mesh层。不仅仅有我们熟悉的 ServiceMesh，还有诸如Database Mesh和Message Mesh等类似的其他 Mesh 产品形态，这些Mesh组成了一个标准化的通信层。&lt;/li&gt;
&lt;li&gt;运行在各种 Mesh 的应用，不管是微服务形态，还是传统非微服务形态，都可以借助Mesh的帮助实现应用轻量化。非业务逻辑的各种功能被剥离到Mesh中后，应用得以“瘦身减负”。&lt;/li&gt;
&lt;li&gt;瘦身之后的应用，其内容主要是业务逻辑实现。这样的工作负载形式，更适合 serverless 的要求，为接下来转型 serverless 做好准备。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，我的最后一个建议是，请结合你的长远发展方向考虑：&lt;strong&gt;如果云原生是你的诗和远方，那么ServiceMesh 就是必由之路&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-28_hu596cf91bb59ef8ef4319002ba5608797_89441_d3254c11d4ffae9765c3dc4b69668c71.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-28_hu596cf91bb59ef8ef4319002ba5608797_89441_ab68d5d4030a38718ebbb285edae39f8.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-28_hu596cf91bb59ef8ef4319002ba5608797_89441_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-28_hu596cf91bb59ef8ef4319002ba5608797_89441_d3254c11d4ffae9765c3dc4b69668c71.webp&#34;
               width=&#34;760&#34;
               height=&#34;353&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;kubernetes / servicemesh / serverless 是当下云原生落地实践的三驾马车，相辅相成，相得益彰。&lt;/p&gt;
&lt;h3 id=&#34;servicemesh-的核心价值&#34;&gt;ServiceMesh 的核心价值&lt;/h3&gt;
&lt;p&gt;在最后，重申一下 ServiceMesh 的核心价值：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实现业务逻辑和非业务逻辑的分离&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;前面的关于要不要采用 ServiceMesh 四个建议，归根到底，最终都是对这个核心价值的延展。只有在分离业务逻辑和非业务逻辑并以Sidecar形式独立部署之后，才有了这四个建议所依赖的特性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ServiceMesh的多语言支持和应用无感知升级&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;希望大家在理解 ServiceMesh 的核心价值之后，再来权衡要不要采用ServiceMesh，也希望我上面给出的四个建议可以对大家的决策有所帮助。&lt;/p&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;在今天的内容中，首先介绍了蚂蚁金服ServiceMesh的发展历程，给大家展示了双十一大规模落地的规模和性能指标，并解释了这些指标背后的原理。然后分享了蚂蚁金服在ServiceMesh大规模落地中遇到的困难和挑战，以及我们为此做的工作，重点介绍了应用平滑迁移的所谓“终极方案”；最后结合蚂蚁金服在云原生和ServiceMesh上的实践心得，对于是否应该采用ServiceMesh给出了几点建议。&lt;/p&gt;
&lt;p&gt;目前蚂蚁金服正在静待今年的双十一大考，这将是 ServiceMesh 的历史时刻：全球最大规模的ServiceMesh集群，ServiceMesh 首次超大规模部署&amp;hellip;&amp;hellip;一切都是如此的值得期待。&lt;/p&gt;
&lt;p&gt;请对ServiceMesh感兴趣的同学稍后继续关注，预期在双十一之后会有一系列的分享活动：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-31_hu9f76c89352eea92158fcd8a78f1aac56_55420_675d4d021bb3e61d045f5bf632d5f9de.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-31_hu9f76c89352eea92158fcd8a78f1aac56_55420_f44cee548d0c0b538d41771d348e6c8d.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-31_hu9f76c89352eea92158fcd8a78f1aac56_55420_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-31_hu9f76c89352eea92158fcd8a78f1aac56_55420_675d4d021bb3e61d045f5bf632d5f9de.webp&#34;
               width=&#34;760&#34;
               height=&#34;165&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;经验分享：会有更多的技术分享，包括落地场景，经验教训，实施方案，架构设计…&lt;/li&gt;
&lt;li&gt;开源贡献：蚂蚁金服会将落地实践中的技术实现和方案以不同的方式回馈社区，推动Servicemesh落地实践。目前这个工作正在实质性的进行中， 请留意我们稍后公布的消息。&lt;/li&gt;
&lt;li&gt;商务合作：蚂蚁金服即将推出ServiceMesh产品，提供商业产品和技术支持，提供金融级特性，欢迎联系&lt;/li&gt;
&lt;li&gt;社区交流：Servicemesher技术社区继续承担国内Servicemesh布道和交流的重任；欢迎参加我们今年正在持续举办的ServiceMesh Meetup活动。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-32_hua6c0e2a3a1effc1b2258f8969a709c6e_567490_4d1ea92cee90570d2d323ba2f4471252.webp 400w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-32_hua6c0e2a3a1effc1b2258f8969a709c6e_567490_b0a6786c890a7784129e16f8b5cc970c.webp 760w,
               /talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-32_hua6c0e2a3a1effc1b2258f8969a709c6e_567490_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201910-ant-finance-service-mesh-deep-practice/images/ppt-32_hua6c0e2a3a1effc1b2258f8969a709c6e_567490_4d1ea92cee90570d2d323ba2f4471252.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;今年是我在QCon演讲的第三年，这三年中的三次演讲，可以说是从一个侧面反映了国内ServiceMesh发展的不同阶段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2017年，国内ServiceMesh一片蛮荒的时候，我做了ServiceMesh的&lt;strong&gt;布道&lt;/strong&gt;，介绍了ServiceMesh的原理，喊出了“下一代微服务”的口号&lt;/li&gt;
&lt;li&gt;2018年，以蚂蚁金服为代表的国内互联网企业，陆陆续续开始了 ServiceMesh 的落地探索，所谓摸着石头过河不外如是。第二次演讲我分享了蚂蚁金服的&lt;strong&gt;探索&lt;/strong&gt;性实践，介绍了蚂蚁金服的ServiceMesh落地方式和思路。&lt;/li&gt;
&lt;li&gt;今天，2019年，第三次演讲，蚂蚁金服已经建立起了全球最大规模的ServiceMesh集群并准备迎接双十一的严峻挑战，这次的标题也变成了&lt;strong&gt;深度实践&lt;/strong&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从布道，到探索，再到深度实践，一路走来已是三年，国内的ServiceMesh发展，也从籍籍无名，到炙手可热，再到理性回归。ServiceMesh的落地，依然还存在非常多的问题，距离普及还有非常远的路要走。然而ServiceMesh的方向，已经被越来越多的人了解和认可。&lt;/p&gt;
&lt;p&gt;高晓松说：&amp;ldquo;生活不止眼前的苟且，还有诗和远方&amp;rdquo;。对于ServiceMesh这样的新技术来说，也是如此。&lt;/p&gt;
&lt;p&gt;感谢鸣谢 InfoQ 和 Qcon 提供的机会，让我得以每年一次的为大家分享 ServiceMesh 的内容。2020年，蚂蚁金服将继续推进和扩大 ServiceMesh 落地的规模，继续引领 ServiceMesh 在金融行业的实践探索。希望明年，可以有更多更深入的内容带给大家！&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译] 动态可扩展性和Protocol Buffer</title>
      <link>https://skyao.net/post/201909-dynamic-extensibility-and-protocol-buffers/</link>
      <pubDate>Fri, 20 Sep 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201909-dynamic-extensibility-and-protocol-buffers/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://blog.envoyproxy.io/dynamic-extensibility-and-protocol-buffers-dcd0bf0b8801/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dynamic extensibility and Protocol Buffers&lt;/a&gt;，作者 &lt;a href=&#34;https://blog.envoyproxy.io/@htuch&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Harvey Tuch&lt;/a&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：快速翻译（机翻+人工校对，没有精修），质量不高，一般阅读可以，不适合传播，谢绝转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;Protocol Buffers（protobuf）是Google推出的高效，静态类型，语言无关的数据序列化格式。我们在Envoy代理中使用protobuf 定义其v2 API，也称为网络代理的通用数据平面API。&lt;/p&gt;
&lt;p&gt;在本文中，我将深入探讨动态扩展 Protobuf 时的一些细微差别和权衡取舍。也就是说，在编译时将不透明的消息字段用未知类型消息嵌入到protobuf中。我将重点介绍Envoy项目，这是我们最近探讨了这种折衷方案的上下文，但是本文适用于任何需要不透明配置嵌入的情况。&lt;/p&gt;
&lt;h2 id=&#34;envoy可扩展性要求&#34;&gt;Envoy可扩展性要求&lt;/h2&gt;
&lt;p&gt;Envoy的主要功能之一是其可扩展性。每个 request/stream/connection 都要遍历 L4/L7过滤器的可配置堆栈。这些过滤器可以检查或更改流量，例如通过插入header，调用身份验证服务或在协议之间进行代码转换。筛选器遵循定义良好的API，任何Envoy使用者都可以链接自己的自定义筛选器，例如，包含组织特定业务逻辑的筛选器，并通过数据平面API配置客户筛选器。除了其L4/L7过滤器外，Envoy还具有用于记录，跟踪和统计信息输出的插件体系结构。&lt;/p&gt;
&lt;p&gt;我们在数据平面API中的 &lt;a href=&#34;https://github.com/envoyproxy/data-plane-api/tree/master/api&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/envoyproxy/data-plane-api/tree/master/api&lt;/a&gt;  的 &lt;code&gt;.proto&lt;/code&gt; 文件中定义了固定消息类型，用于Envoy的内置功能和过滤器。例如，Envoy的 &lt;a href=&#34;https://github.com/envoyproxy/data-plane-api/blob/30b519882b82d4f6a0cf1b502258e35cae9292a2/api/rds.proto#L534&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;RouteConfiguration&lt;/a&gt; 消息描述了一个路由表，从虚拟主机和路径到路由操作的映射：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;RouteConfiguration&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// The name of the route configuration. For example, it might match the
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// router_config_name in the HttpConnectionManager &amp;gt; route_specifier &amp;gt; rds
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// message.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// An array of virtual hosts that make up the route table.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;repeated&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;VirtualHost&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;virtual_hosts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// Specifies a list of HTTP headers that the connection manager will consider
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// to be internal only. If they are found on external requests they will be
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// cleaned prior to filter invocation. See x-envoy-internal for more
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// information.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;repeated&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;internal_only_headers&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;与Envoy核心功能的配置相对应的消息类型在我们的GitHub存储库中指定，并将随着Envoy功能的增长而扩展。但是，在配置更新中，Envoy用户需要一起指定Envoy核心功能的配置以及他们自己的自定义过滤器的配置。&lt;/p&gt;
&lt;p&gt;想象一下，Acme Corp编写了一个&lt;em&gt;AcmeWidget&lt;/em&gt;筛选器，在每次请求时向身份验证服务发起RPC。自定义过滤器的配置将在protobuf中定义，例如：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;AuthService&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cluster&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kd&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AuthType&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;OAUTH&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;JWT&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;AuthType&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;auth_type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个 proto 是专有的，不太可能托管在Envoy的数据平面API存储库中。因此，我们需要提供某种方式在Envoy的配置中进行编码，以更新&lt;em&gt;AuthService&lt;/em&gt;消息的值，而无需知道静态消息类型。Protobuf 为这种不透明配置嵌入提供了两种众所周知的形式：&lt;em&gt;Any&lt;/em&gt; 和 &lt;em&gt;STRUCT&lt;/em&gt; 消息类型。&lt;/p&gt;
&lt;h2 id=&#34;googleprotobufstruct&#34;&gt;google.protobuf.Struct&lt;/h2&gt;
&lt;p&gt;Struct是实现此角色的两种消息类型中最容易的，因为它只是JSON对象的proto表示。由于 proto3 具有规范的JSON表示形式，任何 proto3 消息都可以机械地转换为 JSON 并嵌入到此类型的字段中。&lt;/p&gt;
&lt;p&gt;这是一种非常灵活的类型，并为protobuf带来了动态类型的优点。今天，我们在Envoy中使用这个方式来嵌入任意过滤器：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Filter&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// The name of the filter to instantiate. The name must match a supported
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// filter.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// Filter specific configuration which depends on the filter being
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// instantiated. See the supported filters for further documentation.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;google.protobuf.Struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下面是一个具体示例，嵌入在 Filter 中的 AcmeValue 的文本 proto 表示：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;filter&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;acme.widget&amp;#34;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;fields&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;cluster&amp;#34;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;string_value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;some_cluster&amp;#34;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;auth_type&amp;#34;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;string_value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;JWT&amp;#34;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&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;ul&gt;
&lt;li&gt;
&lt;p&gt;没有Envoy特定的逻辑，无法进行静态类型检查，带有嵌入的不透明过滤器配置的Envoy配置，无法确定嵌入式不透明配置的类型正确性。相反，当Envoy提取其配置时，会在运行时确定过滤器的相应protobuf类型，并尝试转换 Struct 到 protobuf 类型，失败时会引发异常。外部工具不太可能执行相同的操作，因为从过滤器名称到架构的映射知识尚未标准化。但是，外部工具可以动态显示和操作过滤器的配置，而无需事先了解底层类型，因为它们只是JSON对象。您也可以从二进制proto3表示形式到JSON规范proto3表示形式来回转换，而无需了解每个过滤器的protobuf模式（也称为protobuf描述符）。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这种表示方式效率不高。与常规的protobuf相比低效率是一个事实，这种表示方法中字段名在每个定义重复，如对AcmeWidget我们将不得不有 {&amp;ldquo;cluster&amp;rdquo;: &amp;ldquo;foo&amp;rdquo;, &amp;ldquo;auth_type&amp;rdquo;: &amp;ldquo;JWT&amp;rdquo;}。使用已知的protobuf描述符，就不用 “cluster” 或 “ auth_type” 字段名称。这是Protobuf比XML小3到10倍的原因（在有效的二进制编码之外）。对于今天的Envoy配置而言，这并不是什么大问题，因为它的配置通常很小，并且属于Envoy控制平面的一部分，在该控制平面中，对性能的关注并不像在数据平面上那样重要。将来，随着我们扩展到非常大的配置，这可能是一个问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;官方语言特定的 protobuf 库不提供在 Struct 和任意 protobuf 消息类型之间进行转换的优先支持，而是始终需要通过JSON 序列化/反序列化操作进行转换。这有性能方面的考虑，但是如上所述，这些都不是当今Envoy中的头等大事。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;上面的文本 proto 格式的阅读或书写体验都不愉快。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;googleprotobufany&#34;&gt;google.protobuf.Any&lt;/h2&gt;
&lt;p&gt;Any 消息类型将带有类型信息的二进制序列化的protobuf嵌入到另一protobuf的字段内。在内部，它只是一个字节数组，具有嵌入式消息的protobuf格式序列化和一个包含 type URL 的字符串。Type URL本质上是一个字符串，其中包含形式为type.googleapis.com/packagename.messagename 的类型名称。如果我们使用Any，则上面的Filter定义将如下所示：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Filter&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// The name of the filter to instantiate. The name must match a supported
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// filter.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// Filter specific configuration which depends on the filter being
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// instantiated. See the supported filters for further documentation.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;google.protobuf.Any&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在，嵌入在Filter中的AcmeValue的文本 proto 表示的一个具体示例为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;filter&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;acme.widget&amp;#34;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type.googleapis.com&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;com.acme.AcmeWidget&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;cluster&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;some_cluster&amp;#34;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;n&#34;&gt;auth_type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;JWT&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;尽管这看起来类似于Struct示例，但请考虑以下差异：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;由于嵌入式 proto 具有紧凑的序列化表示，因此这几乎与将嵌入式 protobuf 内联的效率一样，即接近最优。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;由于没有模式（即protobuf描述符），没有任何有意义的方法可以理解嵌入式proto。对于Envoy二进制文件而言，这不是要考虑的问题，因为所有过滤器都是静态链接的，因此可以使用其关联的protobuf描述符。但是，请考虑独立Web应用程序，它具有用于构建和可视化Envoy配置的UI。可以预期，它已经为Envoy的核心数据平面API提供了protobuf描述符，但对于AcmeWidget的protobuf描述符却一无所知。为此，Web应用程序将需要额外的复杂性，您首先需要让Acme Corp编译protobuf描述符对象并上传它们。从经验中我们发现，当我们对gRPC转码器过滤器有此要求时，这会增加Envoy的运维困难。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Type URL 提供信息，可用于对Envoy配置及其嵌入式过滤器进行自动静态检查。关于上述问题，关于protobuf描述符的可用性的警告在这里也适用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可以有效地（反）序列化消息，而无需进行JSON往返操作。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有一个漂亮的文本 proto 表示，比Struct嵌入要干净得多。如果要使用文本 proto 作为Envoy的配置格式，这很有用，但是我们通常建议使用YAML，因为文本 proto 尚未标准化，也没有在开源protobuf中得到正式支持或文档。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;补充（2018-02-09）：我们最近发现的使用 Any 对象时的一个注意事项是，由于嵌入式消息的type URL在 Any 对象内部进行了序列化，因此任何对 Any 中嵌入的消息的包名称空间的变更都会破坏 protobuf 的兼容性。这是因为type URL是从嵌入式消息的包名称空间派生的。对于Struct不会发生这种情况，因为应用程序级有底层类型的知识，而与protobuf包的命名空间的细节不同。&lt;/p&gt;
&lt;h2 id=&#34;应该使用哪个&#34;&gt;应该使用哪个？&lt;/h2&gt;
&lt;p&gt;在Envoy数据平面API的早期设计中，我们在过滤器、统计、日志和追踪的扩展点采用 struct 。这主要是看重无模式表示的优点（看起来不错，没有proto描述符！）。容易生成Envoy配置并将其转储。&lt;/p&gt;
&lt;p&gt;在数据平面API的其他地方，当描述要嵌入很多不同资源类型的gRPC服务时，我们选择使用Any。在这种情况下，我们需要嵌入一组众所周知的proto，这些proto也存在于数据平面API的库中。此处无需担心proto描述符的可用性，并且效率优势是免费提供的。我们在这里也可以使用oneof，而只需要付出在每次添加新类型时都要更新其定义的小代价。&lt;/p&gt;
&lt;p&gt;通过构造如下的Filter配置，可以同时拥有Any和Struct的优势：&lt;/p&gt;
&lt;p&gt;进一步推动这一设计理念，Lizan Zhou建议，我们在Envoy中使用 Any 作为我们的基础不透明的嵌入类型，然后在 Any proto中嵌入一个Struct，以便实现类似的效果。这是一个超酷的主意，从根本上讲就是嵌套的protobuf类型。Type URL为 type.googleapis.com/google.protobuf.Struct 的任何嵌入式的 protobuf 可以被 Envoy 解释为 Struct，同时在不以这种方式嵌入时保持高效 Any的选项。这将为Envoy最终用户提供最大的灵活性，使他们自己可以进行上述的折衷。双重嵌套的具体示例是：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Filter&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// The name of the filter to instantiate. The name must match a supported
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// filter.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// Filter specific configuration which depends on the filter being
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// instantiated. See the supported filters for further documentation.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;oneof&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;config_specifier&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;google.protobuf.Any&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;config_any&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;google.protobuf.Struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;config_struct&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在将来的某个时候，我们很可能会采用上述 Any/Struct 组合方式中的一种来获得两全其美的效果。目前，我们已经冻结了核心数据平面API，以准备在Envoy 1.5版本中投入生产。在执行此操作时，我们将需要以向后兼容的方式进行此切换，同时在我们的可扩展API之间保持机制的一致性。&lt;/p&gt;
&lt;p&gt;Protobuf提供了一些强大的机制来支持将不透明配置嵌入其静态类型的消息模式中。为项目选择正确的方法需要了解这些机制之间的权衡以及如何进行组合。在Envoy项目中做出此设计决定时，我们会发现上面的详细信息非常宝贵，希望我们可以通过分享这些经验教训使社区受益。&lt;/p&gt;
&lt;p&gt;致谢：以上对Any与Struct取舍的调查是通过与 John Millikin 和 Lizan Zhou 进行的有益讨论而得出的，非常感谢。当我们制订 Envoy 数据平面API 的 proto 时，也要向 mattklein123 进行有关此主题的许多PR评论和讨论。&lt;/p&gt;
&lt;p&gt;免责声明：此处陈述的观点仅代表我个人，而非我公司（Google）的观点。&lt;/p&gt;
&lt;h2 id=&#34;后续补充&#34;&gt;后续补充&lt;/h2&gt;
&lt;p&gt;在2020年的最新的 UPPA 定义中，定义了名为 TypedStruct 的类型：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;TypedStruct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 用于唯一标识序列化 protocol buffer 消息的类型的URL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 这与 google.protobuf.Any 中描述的语义和格式相同：
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type_url&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 上述指定类型的JSON表示形式。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;google.protobuf.Struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&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;
</description>
    </item>
    
    <item>
      <title>[译] WebAssembly接口类型：与所有事物互操作！</title>
      <link>https://skyao.net/post/201908-webassembly-interface-types/</link>
      <pubDate>Sun, 08 Sep 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201908-webassembly-interface-types/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://hacks.mozilla.org/2019/08/webassembly-interface-types/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;WebAssembly Interface Types: Interoperate with All the Things!&lt;/a&gt;，作者 &lt;a href=&#34;https://twitter.com/linclark&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Lin Clark&lt;/a&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：快速翻译（机翻+人工校对，没有精修），质量不高，一般阅读可以，不适合传播，谢绝转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;人们兴奋于在浏览器外运行WebAssembly。&lt;/p&gt;
&lt;p&gt;这种兴奋不仅仅在于运行在自身独立运行时中的WebAssembly。人们也对使用Python，Ruby和Rust等语言运行WebAssembly感到兴奋。&lt;/p&gt;
&lt;p&gt;为什么想这么做？原因如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;使“原生”模块不那么复杂&lt;/strong&gt;
像Node或Python的CPython这样的运行时通常允许你用C++等低级语言编写模块。那是因为这些低级语言通常要快得多。因此，您可以在Node中使用原生模块，或在Python中使用扩展模块。但这些模块通常很难使用，因为它们需要在用户的设备上进行编译。使用WebAssembly“原生”模块，您可以获得差不多的速度而规避复杂化。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;使沙箱原生代码更容易&lt;/strong&gt;
另一方面，像Rust这样的低级语言不会使用WebAssembly来提高速度。但是他们可以用它来保证安全。正如我们在&lt;a href=&#34;https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;WASI公告中&lt;/a&gt;所讨论的那样，WebAssembly默认为您提供轻量级沙盒。因此像Rust这样的语言可以使用WebAssembly来沙箱化原生代码模块。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跨平台共享原生代码&lt;/strong&gt;
如果开发人员可以跨不同平台（例如，在Web和桌面应用程序之间）共享相同的代码库，则可以节省时间并降低维护成本。对于脚本和低级语言都是如此。WebAssembly为您提供了一种方法，可以运行在这些平台上，而不会减慢速度。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/01-01-why-768x313_hubca78fa3f7da9b9dce0cb282b4e36b35_76536_33e965496ecf37d9f4b0e5ce86cddbfe.webp 400w,
               /post/201908-webassembly-interface-types/images/01-01-why-768x313_hubca78fa3f7da9b9dce0cb282b4e36b35_76536_47601f4593ad400a344e22535b7ef75d.webp 760w,
               /post/201908-webassembly-interface-types/images/01-01-why-768x313_hubca78fa3f7da9b9dce0cb282b4e36b35_76536_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/01-01-why-768x313_hubca78fa3f7da9b9dce0cb282b4e36b35_76536_33e965496ecf37d9f4b0e5ce86cddbfe.webp&#34;
               width=&#34;760&#34;
               height=&#34;310&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;因此，WebAssembly可以真正帮助其他语言解决重要问题。&lt;/p&gt;
&lt;p&gt;但是对于今天的WebAssembly，您不希望以这种方式使用它。您可以在所有这些地方&lt;em&gt;运行&lt;/em&gt; WebAssembly，但这还不够。&lt;/p&gt;
&lt;p&gt;现在，WebAssembly只在数值上进行对话。这意味着两种语言可以相互调用对方的函数。&lt;/p&gt;
&lt;p&gt;但是如果一个函数接受或返回除数值之外的任何东西，事情变得复杂。你可以：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;传递一个有非常难用的API的模块，该API仅以数值对话&amp;hellip;&amp;hellip;让模块用户很为难。&lt;/li&gt;
&lt;li&gt;为希望此模块运行的每个环境添加胶水代码&amp;hellip;&amp;hellip;使模块开发人员很为难。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但事实并非如此。&lt;/p&gt;
&lt;p&gt;应该可以传递&lt;em&gt;单个&lt;/em&gt; WebAssembly模块并让它在任何地方运行&amp;hellip;&amp;hellip;而不会让模块的用户或开发人员为难。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/01-02-user-and-dev-768x737_hu76c17707e46211a681bd1981b94045a1_135281_fc9e79cb23817d2b3628e38fa1437d42.webp 400w,
               /post/201908-webassembly-interface-types/images/01-02-user-and-dev-768x737_hu76c17707e46211a681bd1981b94045a1_135281_5e1e559a7623641db7f78e2c32bdc50c.webp 760w,
               /post/201908-webassembly-interface-types/images/01-02-user-and-dev-768x737_hu76c17707e46211a681bd1981b94045a1_135281_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/01-02-user-and-dev-768x737_hu76c17707e46211a681bd1981b94045a1_135281_fc9e79cb23817d2b3628e38fa1437d42.webp&#34;
               width=&#34;760&#34;
               height=&#34;729&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;因此，相同的WebAssembly模块可以使用丰富的API对话，使用复杂类型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在自己的原生运行时运行的模块（例如，在Python运行时中运行的Python模块）&lt;/li&gt;
&lt;li&gt;用不同源代码语言编写的其他WebAssembly模块（例如，在浏览器中一起运行的Rust模块和Go模块）&lt;/li&gt;
&lt;li&gt;主机系统本身（例如，为操作系统提供系统接口或提供浏览器API的WASI模块）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/01-03-star-diagram-768x606_hu4cc575e8e62ee59cadbcbfffe3fcb8a9_136699_e4a559d383a6288a70ac2f562e9fe3c9.webp 400w,
               /post/201908-webassembly-interface-types/images/01-03-star-diagram-768x606_hu4cc575e8e62ee59cadbcbfffe3fcb8a9_136699_5d038c10ae8587f10bd9964a7fea29be.webp 760w,
               /post/201908-webassembly-interface-types/images/01-03-star-diagram-768x606_hu4cc575e8e62ee59cadbcbfffe3fcb8a9_136699_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/01-03-star-diagram-768x606_hu4cc575e8e62ee59cadbcbfffe3fcb8a9_136699_e4a559d383a6288a70ac2f562e9fe3c9.webp&#34;
               width=&#34;760&#34;
               height=&#34;600&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;通过一个新的早期提案，我们将看到如何制作这个Just Work™，正如您在本演示中所看到的那样。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/embed/Qn_4F3foB3Q&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://www.youtube.com/embed/Qn_4F3foB3Q&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;那么让我们来看看它是如何工作的。但首先，让我们看看我们今天的处境以及我们试图解决的问题。&lt;/p&gt;
&lt;h2 id=&#34;webassembly与js对话&#34;&gt;WebAssembly与JS对话&lt;/h2&gt;
&lt;p&gt;WebAssembly不仅限于Web。但到目前为止，WebAssembly的大部分开发都集中在Web上。&lt;/p&gt;
&lt;p&gt;那是因为当你专注于解决具体的用例时，你可以做出更好的设计。该语言肯定必须在Web上运行，因此这是一个很好的可以作为起点的用例。&lt;/p&gt;
&lt;p&gt;这给出一个很好的MVP范围。WebAssembly只需要能够与一种语言对话 - JavaScript。&lt;/p&gt;
&lt;p&gt;这样做相对容易。在浏览器中，WebAssembly和JS都在同一个引擎中运行，因此引擎可以帮助它们&lt;a href=&#34;https://hacks.mozilla.org/2018/10/calls-between-javascript-and-webassembly-are-finally-fast&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;有效地相互通信&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/02-01-js-interop-01-768x575_huf077b5e40252756f0fb369da7039a9d6_71305_0699d59c301060cb7248b968f4f31fc9.webp 400w,
               /post/201908-webassembly-interface-types/images/02-01-js-interop-01-768x575_huf077b5e40252756f0fb369da7039a9d6_71305_6a2cd128fd5ddd391850b388089e2031.webp 760w,
               /post/201908-webassembly-interface-types/images/02-01-js-interop-01-768x575_huf077b5e40252756f0fb369da7039a9d6_71305_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/02-01-js-interop-01-768x575_huf077b5e40252756f0fb369da7039a9d6_71305_0699d59c301060cb7248b968f4f31fc9.webp&#34;
               width=&#34;760&#34;
               height=&#34;569&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/02-01-js-interop-02-768x575_hu3a31e8ef3688851e729ce331926295e2_56813_66d776be6689a664b5d31db15547170a.webp 400w,
               /post/201908-webassembly-interface-types/images/02-01-js-interop-02-768x575_hu3a31e8ef3688851e729ce331926295e2_56813_978e3facea22ddaf4072ba982bdfdcdf.webp 760w,
               /post/201908-webassembly-interface-types/images/02-01-js-interop-02-768x575_hu3a31e8ef3688851e729ce331926295e2_56813_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/02-01-js-interop-02-768x575_hu3a31e8ef3688851e729ce331926295e2_56813_66d776be6689a664b5d31db15547170a.webp&#34;
               width=&#34;760&#34;
               height=&#34;569&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;但是当JS和WebAssembly试图互相对话时，有一个问题&amp;hellip;&amp;hellip;他们使用不同的类型。&lt;/p&gt;
&lt;p&gt;目前，WebAssembly只能以数值进行对话。JavaScript有数值，但也有很多类型。&lt;/p&gt;
&lt;p&gt;甚至数值都不一样。WebAssembly有4种不同的数值：int32，int64，float32和float64。JavaScript目前只有Number（虽然很快会有另一种数字类型，&lt;a href=&#34;https://github.com/tc39/proposal-bigint&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;BigInt&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;区别不仅在于这些类型的名称。值也是以不同方式存储在内存中。&lt;/p&gt;
&lt;p&gt;首先，在JavaScript中，任何值，无论类型，都被放入一个称为盒子（box）的东西（我在另一篇文章中解释了更多的&lt;a href=&#34;https://hacks.mozilla.org/2018/10/calls-between-javascript-and-webassembly-are-finally-fast/#js-to-wasm&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;boxing&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;相反，WebAssembly的数值具有静态类型。因此，它不需要（或理解）JS盒子。&lt;/p&gt;
&lt;p&gt;这种差异使得彼此之间难以沟通。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/02-03-number-mismatch-768x619_hucf0056dca870bb9939245093786ce69c_78151_50b1f53717257303af21d04814726e56.webp 400w,
               /post/201908-webassembly-interface-types/images/02-03-number-mismatch-768x619_hucf0056dca870bb9939245093786ce69c_78151_dd0162101b6aad72ca3af9c14543eb05.webp 760w,
               /post/201908-webassembly-interface-types/images/02-03-number-mismatch-768x619_hucf0056dca870bb9939245093786ce69c_78151_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/02-03-number-mismatch-768x619_hucf0056dca870bb9939245093786ce69c_78151_50b1f53717257303af21d04814726e56.webp&#34;
               width=&#34;760&#34;
               height=&#34;613&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;但是，如果要将值从一种数值类型转换为另一种数值类型，则有非常简单的规则。&lt;/p&gt;
&lt;p&gt;因为它很简单，所以很容易写下来。你可以在&lt;a href=&#34;https://www.w3.org/TR/wasm-js-api/#tojsvalue&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;WebAssembly的JS API规范中&lt;/a&gt;找到这个。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/02-04-mapping-book-768x376_hudef0d7cb6a1b1abf97392beb9b0d72b8_72492_f091251e0f3c9f2328404c42d4043666.webp 400w,
               /post/201908-webassembly-interface-types/images/02-04-mapping-book-768x376_hudef0d7cb6a1b1abf97392beb9b0d72b8_72492_633b5f89aeb8b6f358c8f7cc5168e958.webp 760w,
               /post/201908-webassembly-interface-types/images/02-04-mapping-book-768x376_hudef0d7cb6a1b1abf97392beb9b0d72b8_72492_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/02-04-mapping-book-768x376_hudef0d7cb6a1b1abf97392beb9b0d72b8_72492_f091251e0f3c9f2328404c42d4043666.webp&#34;
               width=&#34;760&#34;
               height=&#34;372&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;此映射硬编码在引擎中。&lt;/p&gt;
&lt;p&gt;这有点像引擎有一本参考书。每当引擎必须在JS和WebAssembly之间传递参数或返回值时，它就会从架子上提取该参考书，以了解如何转换这些值。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/02-05-number-conversion-768x619_hufb681b35d49d024df965492a09137687_106025_169a586411f38066dcfc573f704051a6.webp 400w,
               /post/201908-webassembly-interface-types/images/02-05-number-conversion-768x619_hufb681b35d49d024df965492a09137687_106025_c3fdd393ff3040f498e1c6fab0de0c18.webp 760w,
               /post/201908-webassembly-interface-types/images/02-05-number-conversion-768x619_hufb681b35d49d024df965492a09137687_106025_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/02-05-number-conversion-768x619_hufb681b35d49d024df965492a09137687_106025_169a586411f38066dcfc573f704051a6.webp&#34;
               width=&#34;760&#34;
               height=&#34;613&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;拥有如此有限的一组类型（只是数值）使得这种映射非常容易。这对于MVP来说非常棒。它的限制使得无需作出太多艰难的设计决策。&lt;/p&gt;
&lt;p&gt;但它使得开发人员使用WebAssembly变得更加复杂。要在JS和WebAssembly之间传递字符串，您必须找到一种方法将字符串转换为数值数组，然后将数值数组转换回字符串。我在上一篇&lt;a href=&#34;https://hacks.mozilla.org/2018/03/making-webassembly-better-for-rust-for-all-languages/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;文章中&lt;/a&gt;对此进行了解释。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/04_wasm_bindgen_02-768x453_hu0e3ec52a5d18826e203a8797bd1cf12f_81322_1bfc90680886c83f70eecaa0fe42346f.webp 400w,
               /post/201908-webassembly-interface-types/images/04_wasm_bindgen_02-768x453_hu0e3ec52a5d18826e203a8797bd1cf12f_81322_43e39942a89601033ac723ed7b9ed2a2.webp 760w,
               /post/201908-webassembly-interface-types/images/04_wasm_bindgen_02-768x453_hu0e3ec52a5d18826e203a8797bd1cf12f_81322_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/04_wasm_bindgen_02-768x453_hu0e3ec52a5d18826e203a8797bd1cf12f_81322_1bfc90680886c83f70eecaa0fe42346f.webp&#34;
               width=&#34;760&#34;
               height=&#34;448&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这并困难，但是很乏味。所以构建工具来抽象出来。&lt;/p&gt;
&lt;p&gt;例如，像 &lt;a href=&#34;https://rustwasm.github.io/docs/wasm-bindgen/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Rust的wasm-bindgen&lt;/a&gt; 和&lt;a href=&#34;https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#embind&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Emscripten的Embind&lt;/a&gt; 这样的工具会自动用Web粘合代码包装WebAssembly模块，该代码可以实现从字符串到数值的转换。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/02-07-js-glue-768x735_hu8fd3302aa6697a022255b07f118ee136_101266_058be87202d1f732344b47905c1a7e21.webp 400w,
               /post/201908-webassembly-interface-types/images/02-07-js-glue-768x735_hu8fd3302aa6697a022255b07f118ee136_101266_75d4a8f9807c90003bd4b11cf6f9d197.webp 760w,
               /post/201908-webassembly-interface-types/images/02-07-js-glue-768x735_hu8fd3302aa6697a022255b07f118ee136_101266_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/02-07-js-glue-768x735_hu8fd3302aa6697a022255b07f118ee136_101266_058be87202d1f732344b47905c1a7e21.webp&#34;
               width=&#34;760&#34;
               height=&#34;727&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这些工具也可以为其他高级类型执行类型转换，例如带有属性的复杂对象。&lt;/p&gt;
&lt;p&gt;这个方式可行，但存在一些非常明显的不能很好地工作的用例。&lt;/p&gt;
&lt;p&gt;例如，有时您只想通过 WebAssembly 透传字符串。您希望JavaScript函数将字符串传递给WebAssembly函数，然后让WebAssembly将其传递给另一个JavaScript函数。&lt;/p&gt;
&lt;p&gt;为了达到这个目标，需要做以下事情：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;第一个JavaScript函数将字符串传递给JS胶水代码&lt;/li&gt;
&lt;li&gt;JS胶水代码将该字符串对象转换为数值，然后将这些数值放入线性内存中&lt;/li&gt;
&lt;li&gt;然后将一个数值（指向字符串开头的指针）传递给WebAssembly&lt;/li&gt;
&lt;li&gt;WebAssembly函数将该数值传递给另一侧的JS胶水代码&lt;/li&gt;
&lt;li&gt;第二个JavaScript函数从线性内存中提取所有这些数值，然后将它们解码回字符串对象&lt;/li&gt;
&lt;li&gt;传递给第二个JS函数&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-01-768x189_hu1e05b635e9640625591eb4898df6a223_25971_8329237b4eb3b70c19a70d20fb2a3d64.webp 400w,
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-01-768x189_hu1e05b635e9640625591eb4898df6a223_25971_ff906e6fe289cebc087bb4a4c2dcb986.webp 760w,
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-01-768x189_hu1e05b635e9640625591eb4898df6a223_25971_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/02-08-encode-decode-01-768x189_hu1e05b635e9640625591eb4898df6a223_25971_8329237b4eb3b70c19a70d20fb2a3d64.webp&#34;
               width=&#34;760&#34;
               height=&#34;187&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-02-768x328_hu843f95d2e1bd808d8045bcad4ed465d0_46007_9d8dd467fd6b8dd9b82197f005eb790a.webp 400w,
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-02-768x328_hu843f95d2e1bd808d8045bcad4ed465d0_46007_2e60d86c2357c7efe7ce95955e1ae645.webp 760w,
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-02-768x328_hu843f95d2e1bd808d8045bcad4ed465d0_46007_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/02-08-encode-decode-02-768x328_hu843f95d2e1bd808d8045bcad4ed465d0_46007_9d8dd467fd6b8dd9b82197f005eb790a.webp&#34;
               width=&#34;760&#34;
               height=&#34;325&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-03-768x509_hu961e8d0f08e6b998b443b920f4efbf7c_81450_c5d2ae571e939ed67aa8421b339936bc.webp 400w,
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-03-768x509_hu961e8d0f08e6b998b443b920f4efbf7c_81450_3c8cacd43fe29e36890f9be514b7a382.webp 760w,
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-03-768x509_hu961e8d0f08e6b998b443b920f4efbf7c_81450_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/02-08-encode-decode-03-768x509_hu961e8d0f08e6b998b443b920f4efbf7c_81450_c5d2ae571e939ed67aa8421b339936bc.webp&#34;
               width=&#34;760&#34;
               height=&#34;504&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-04-768x509_hu45c22f6561cbfa155affc5b62a06a9e7_80544_ae3e1c9f90877249f830ef3932748565.webp 400w,
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-04-768x509_hu45c22f6561cbfa155affc5b62a06a9e7_80544_ee7e418eca06802e0cd35298c55fe5bc.webp 760w,
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-04-768x509_hu45c22f6561cbfa155affc5b62a06a9e7_80544_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/02-08-encode-decode-04-768x509_hu45c22f6561cbfa155affc5b62a06a9e7_80544_ae3e1c9f90877249f830ef3932748565.webp&#34;
               width=&#34;760&#34;
               height=&#34;504&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-05-768x328_hu68de2971cf397f93ded4c3c249683e2e_48961_2bcacdbb6a99b29b79d5ec5c4415fb85.webp 400w,
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-05-768x328_hu68de2971cf397f93ded4c3c249683e2e_48961_6ba1af4e850bfc686297ce9c097f0113.webp 760w,
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-05-768x328_hu68de2971cf397f93ded4c3c249683e2e_48961_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/02-08-encode-decode-05-768x328_hu68de2971cf397f93ded4c3c249683e2e_48961_2bcacdbb6a99b29b79d5ec5c4415fb85.webp&#34;
               width=&#34;760&#34;
               height=&#34;325&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-06-768x192_huf413a249e52091c9572267ec48a8fc52_27741_41b8812016af270d54d2c0b3cd483ea9.webp 400w,
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-06-768x192_huf413a249e52091c9572267ec48a8fc52_27741_0ab45bddfc3320f20aeea76220a656e2.webp 760w,
               /post/201908-webassembly-interface-types/images/02-08-encode-decode-06-768x192_huf413a249e52091c9572267ec48a8fc52_27741_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/02-08-encode-decode-06-768x192_huf413a249e52091c9572267ec48a8fc52_27741_41b8812016af270d54d2c0b3cd483ea9.webp&#34;
               width=&#34;760&#34;
               height=&#34;190&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;因此，一侧的JS胶水代码只是翻转了它在另一侧所做的工作。很多工作花费在重建基本相同的对象上。&lt;/p&gt;
&lt;p&gt;如果字符串只是直接通过WebAssembly透传而没有任何转换，那将更容易。&lt;/p&gt;
&lt;p&gt;WebAssembly将无法对此字符串执行任何操作 - 它无法理解该类型。我们不会解决这个问题。&lt;/p&gt;
&lt;p&gt;但它可以在两个JS函数之间来回传递字符串对象，因为它们理解类型。&lt;/p&gt;
&lt;p&gt;因此，这是&lt;a href=&#34;https://github.com/WebAssembly/reference-types/blob/master/proposals/reference-types/Overview.md#language-extensions&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;WebAssembly引用类型提议&lt;/a&gt;的原因之一。该提议添加了一个名为 &lt;code&gt;anyref&lt;/code&gt; 的新的基本WebAssembly类型。&lt;/p&gt;
&lt;p&gt;使用&lt;code&gt;anyref&lt;/code&gt;，JavaScript只为WebAssembly提供了一个引用对象（基本上是一个不会泄露内存地址的指针）。此引用指向JS堆上的对象。然后WebAssembly可以将它传递给其他JS函数，这些函数确切地知道如何使用它。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/02-09-anyref-01-768x627_hu2ebff94a24b0ac5f12f55f0871a27b7c_118651_d24d56778803c8cbbcdd4f6ba97caa25.webp 400w,
               /post/201908-webassembly-interface-types/images/02-09-anyref-01-768x627_hu2ebff94a24b0ac5f12f55f0871a27b7c_118651_296894c4c12e1275c98ccbd0e574faee.webp 760w,
               /post/201908-webassembly-interface-types/images/02-09-anyref-01-768x627_hu2ebff94a24b0ac5f12f55f0871a27b7c_118651_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/02-09-anyref-01-768x627_hu2ebff94a24b0ac5f12f55f0871a27b7c_118651_d24d56778803c8cbbcdd4f6ba97caa25.webp&#34;
               width=&#34;760&#34;
               height=&#34;620&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/02-09-anyref-02-768x668_hu5144c583adf5cd59a0e7b2bad14c804c_132014_6426ef263849ac013b410aaab43f066c.webp 400w,
               /post/201908-webassembly-interface-types/images/02-09-anyref-02-768x668_hu5144c583adf5cd59a0e7b2bad14c804c_132014_fc75260ae816caded16977940bdf1674.webp 760w,
               /post/201908-webassembly-interface-types/images/02-09-anyref-02-768x668_hu5144c583adf5cd59a0e7b2bad14c804c_132014_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/02-09-anyref-02-768x668_hu5144c583adf5cd59a0e7b2bad14c804c_132014_6426ef263849ac013b410aaab43f066c.webp&#34;
               width=&#34;760&#34;
               height=&#34;661&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;因此，这解决了和JavaScript互操作中最烦人的问题之一。但这不是浏览器中唯一要解决的互操作性问题。&lt;/p&gt;
&lt;p&gt;浏览器中还有另一组更大的类型。如果我们要获得良好的性能，WebAssembly需要能够与这些类型进行互操作。&lt;/p&gt;
&lt;h2 id=&#34;webassembly直接与浏览器通信&#34;&gt;WebAssembly直接与浏览器通信&lt;/h2&gt;
&lt;p&gt;JS只是浏览器的一部分。浏览器还有许多其他功能，称为Web API，您可以使用它们。&lt;/p&gt;
&lt;p&gt;在幕后，这些Web API函数通常用C++或Rust编写。他们有自己将对象存储在内存中的方式。&lt;/p&gt;
&lt;p&gt;Web API的参数和返回值可以是许多不同的类型。很难为这些类型中的每一种手动创建映射。因此，为简化起见，有一种标准的方式来讨论这些类型的结构 - &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Mozilla/WebIDL_bindings&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Web IDL&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;当您使用这些功能时，通常是通过使用JavaScript。这意味着您传递的是使用JS类型的值。如何将JS类型转换为Web IDL类型？&lt;/p&gt;
&lt;p&gt;就像存在从WebAssembly类型到JavaScript类型的映射一样，也存在从JavaScript类型到Web IDL类型的映射。&lt;/p&gt;
&lt;p&gt;所以它就像引擎有另一本参考书，展示了如何从JS到Web IDL。此映射也在引擎中进行了硬编码。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/03-02-mapping-book-768x376_huc14e5f981e726c01e724e1e5ffc4435b_70647_fe1fd57cd20a514b22bc843864702a98.webp 400w,
               /post/201908-webassembly-interface-types/images/03-02-mapping-book-768x376_huc14e5f981e726c01e724e1e5ffc4435b_70647_9fd406f44456830f657bec7652ccfa21.webp 760w,
               /post/201908-webassembly-interface-types/images/03-02-mapping-book-768x376_huc14e5f981e726c01e724e1e5ffc4435b_70647_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/03-02-mapping-book-768x376_huc14e5f981e726c01e724e1e5ffc4435b_70647_fe1fd57cd20a514b22bc843864702a98.webp&#34;
               width=&#34;760&#34;
               height=&#34;372&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对于许多类型，JavaScript和Web IDL之间的映射是非常直白的。例如，DOMString和JS的String等类型是兼容的，可以直接相互映射。&lt;/p&gt;
&lt;p&gt;现在，当您尝试从WebAssembly调用Web API时会发生什么？这是我们遇到问题的地方。&lt;/p&gt;
&lt;p&gt;目前，WebAssembly类型和Web IDL类型之间没有映射。这意味着，即使是像数字这样的简单类型，您的调用也必须通过JavaScript。&lt;/p&gt;
&lt;p&gt;这是具体工作的方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;WebAssembly将值传递给JS。&lt;/li&gt;
&lt;li&gt;在此过程中，引擎将此值转换为JavaScript类型，并将其放入内存中的JS堆中&lt;/li&gt;
&lt;li&gt;然后，将该JS值传递给Web API函数。在此过程中，引擎将JS值转换为Web IDL类型，并将其放入内存的不同部分，即渲染器的堆。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/03-03-wasm-to-browser-01-768x422_hu9c9e2a78f66190540e60e5a9b1f6fd17_36557_f9d920d17657f378b58ab01be57b8ea8.webp 400w,
               /post/201908-webassembly-interface-types/images/03-03-wasm-to-browser-01-768x422_hu9c9e2a78f66190540e60e5a9b1f6fd17_36557_ce12871f44250c758cfb3e74ce734dbb.webp 760w,
               /post/201908-webassembly-interface-types/images/03-03-wasm-to-browser-01-768x422_hu9c9e2a78f66190540e60e5a9b1f6fd17_36557_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/03-03-wasm-to-browser-01-768x422_hu9c9e2a78f66190540e60e5a9b1f6fd17_36557_f9d920d17657f378b58ab01be57b8ea8.webp&#34;
               width=&#34;760&#34;
               height=&#34;418&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/03-03-wasm-to-browser-02-768x422_huaf93b32b25a702791eaab082c3534a50_72930_8d48f6afea409b6557d720d53bc8a3f6.webp 400w,
               /post/201908-webassembly-interface-types/images/03-03-wasm-to-browser-02-768x422_huaf93b32b25a702791eaab082c3534a50_72930_94f0545190445e437207f64e3ac7efde.webp 760w,
               /post/201908-webassembly-interface-types/images/03-03-wasm-to-browser-02-768x422_huaf93b32b25a702791eaab082c3534a50_72930_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/03-03-wasm-to-browser-02-768x422_huaf93b32b25a702791eaab082c3534a50_72930_8d48f6afea409b6557d720d53bc8a3f6.webp&#34;
               width=&#34;760&#34;
               height=&#34;418&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/03-03-wasm-to-browser-03-768x422_hu7df4ad47d09b926f43e7baa2a7065746_74585_efc8556f698be06610ea4a9bb718561a.webp 400w,
               /post/201908-webassembly-interface-types/images/03-03-wasm-to-browser-03-768x422_hu7df4ad47d09b926f43e7baa2a7065746_74585_5385d4c6c8094160ae45d218fceaef36.webp 760w,
               /post/201908-webassembly-interface-types/images/03-03-wasm-to-browser-03-768x422_hu7df4ad47d09b926f43e7baa2a7065746_74585_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/03-03-wasm-to-browser-03-768x422_hu7df4ad47d09b926f43e7baa2a7065746_74585_efc8556f698be06610ea4a9bb718561a.webp&#34;
               width=&#34;760&#34;
               height=&#34;418&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这需要更多的工作，并且还会占用更多内存。&lt;/p&gt;
&lt;p&gt;有一个明显的解决方案 -创建从WebAssembly到Web IDL的直接映射。但这并不像看起来那么简单。&lt;/p&gt;
&lt;p&gt;对于像&lt;code&gt;boolean&lt;/code&gt;和&lt;code&gt;unsigned long&lt;/code&gt;（这是一个数字）的简单Web IDL类型，从WebAssembly到Web IDL有明确的映射。&lt;/p&gt;
&lt;p&gt;但在大多数情况下，Web API参数是更复杂的类型。例如，API可能需要一个字典，它基本上是一个具有属性或序列（就像一个数组的）对象。&lt;/p&gt;
&lt;p&gt;要在WebAssembly类型和Web IDL类型之间进行直接映射，我们需要添加一些更高级别的类型。我们正在这样做 - &lt;a href=&#34;https://github.com/WebAssembly/gc&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;GC提案&lt;/a&gt;。有了它，WebAssembly模块将能够创建GC对象 - 例如结构和数组 - 可以映射到复杂的Web IDL类型。&lt;/p&gt;
&lt;p&gt;但是，如果与Web API进行互操作的唯一方法是通过GC对象，那么对于像C++和Rust这样不会使用GC对象的语言来说，这会更加艰难。只要代码与Web API交互，就必须创建一个新的GC对象，并将值从其线性内存复制到该对象中。&lt;/p&gt;
&lt;p&gt;这只比我们今天的JS胶水代码略胜一筹。&lt;/p&gt;
&lt;p&gt;我们不希望JS胶水代码必须构建GC对象 - 这是浪费时间和空间。出于同样的原因，我们也不希望WebAssembly模块这样做。&lt;/p&gt;
&lt;p&gt;我们希望使用线性内存（如Rust和C ++）的语言能够像使用引擎内置GC的语言一样调用Web API。因此，我们需要一种方法来创建线性内存中的对象和Web IDL类型之间的映射。&lt;/p&gt;
&lt;p&gt;但是这里有一个问题。这些语言中的每一种都以不同方式表示线性内存中的东西。我们不能只选择一种语言的表示。这将使所有其他语言效率降低。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/03-07-picking-lang-768x497_hu8717d3bea18c76bd5d4aae31d7fd86e5_50320_dc0b9ba1cdc44afd44e66bb42b162b64.webp 400w,
               /post/201908-webassembly-interface-types/images/03-07-picking-lang-768x497_hu8717d3bea18c76bd5d4aae31d7fd86e5_50320_f40e93b9758f169406ee3b0783b714a9.webp 760w,
               /post/201908-webassembly-interface-types/images/03-07-picking-lang-768x497_hu8717d3bea18c76bd5d4aae31d7fd86e5_50320_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/03-07-picking-lang-768x497_hu8717d3bea18c76bd5d4aae31d7fd86e5_50320_dc0b9ba1cdc44afd44e66bb42b162b64.webp&#34;
               width=&#34;760&#34;
               height=&#34;492&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;但内存中针对这些东西的确切布局通常是不同的，也有一些已经通用的抽象概念。&lt;/p&gt;
&lt;p&gt;例如，对于字符串，语言通常有一个指向内存中字符串开头的指针，以及字符串的长度。即使字符串具有更复杂的内部表示，通常也需要在调用外部API时将字符串转换为此格式。&lt;/p&gt;
&lt;p&gt;这意味着我们可以将此字符串缩减为WebAssembly可以理解的类型&amp;hellip;两个i32。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/03-08-types-wasm-understands-768x411_hu63628fca9818b8795fef5618dd62b145_72065_c241588d7335f50f6e6adade7154dac3.webp 400w,
               /post/201908-webassembly-interface-types/images/03-08-types-wasm-understands-768x411_hu63628fca9818b8795fef5618dd62b145_72065_fba442061d7755be9fcba48be9c95fa6.webp 760w,
               /post/201908-webassembly-interface-types/images/03-08-types-wasm-understands-768x411_hu63628fca9818b8795fef5618dd62b145_72065_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/03-08-types-wasm-understands-768x411_hu63628fca9818b8795fef5618dd62b145_72065_c241588d7335f50f6e6adade7154dac3.webp&#34;
               width=&#34;760&#34;
               height=&#34;407&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们可以在引擎中硬编码这样的映射。因此引擎将有另一本参考书，这次是针对WebAssembly的Web IDL映射。&lt;/p&gt;
&lt;p&gt;但这里有一个问题。WebAssembly是一种类型检查的语言。为了保证&lt;a href=&#34;https://webassembly.org/docs/security/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;安全&lt;/a&gt;，引擎必须检查调用代码是否传递了与被调用者要求的类型相匹配的类型。&lt;/p&gt;
&lt;p&gt;这是因为攻击者有办法利用类型不匹配从而让引擎做不应该做的事情。&lt;/p&gt;
&lt;p&gt;如果你正在使用字符串调用东西，但是你试图将函数传递给整数，引擎会抗议。它也应该抗议。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/03-09-type-mismatch-768x418_hudb058fe137622aec40a4ab4a448d2e7d_50952_3e79e4f77834350a9ad99d65d66152dd.webp 400w,
               /post/201908-webassembly-interface-types/images/03-09-type-mismatch-768x418_hudb058fe137622aec40a4ab4a448d2e7d_50952_ee16f3845b28c4340ee8134687fac992.webp 760w,
               /post/201908-webassembly-interface-types/images/03-09-type-mismatch-768x418_hudb058fe137622aec40a4ab4a448d2e7d_50952_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/03-09-type-mismatch-768x418_hudb058fe137622aec40a4ab4a448d2e7d_50952_3e79e4f77834350a9ad99d65d66152dd.webp&#34;
               width=&#34;760&#34;
               height=&#34;414&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;所以我们需要一种方法让模块明确地告诉引擎，类似这样：“我知道 Document.createElement() 接受一个字符串。但是当我调用它时，我将传递两个整数。使用他们从我的线性内存中的数据创建DOMString。使用第一个整数作为字符串的起始地址，第二个整数作为长度。“&lt;/p&gt;
&lt;p&gt;这就是Web IDL提案的作用。它为WebAssembly模块提供了一种在它使用的类型和Web IDL类型之间进行映射的方法。&lt;/p&gt;
&lt;p&gt;这些映射在引擎中没有硬编码。相反，一个模块带有自己的映射小册子。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/03-10-booklet-500x272_hubf566076186b6c1cd42fc29feb09f4cb_28732_04b6f969e23240c51ec9d1ac7655dc5d.webp 400w,
               /post/201908-webassembly-interface-types/images/03-10-booklet-500x272_hubf566076186b6c1cd42fc29feb09f4cb_28732_bb67e535c186bee2ca4a5bc38373e813.webp 760w,
               /post/201908-webassembly-interface-types/images/03-10-booklet-500x272_hubf566076186b6c1cd42fc29feb09f4cb_28732_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/03-10-booklet-500x272_hubf566076186b6c1cd42fc29feb09f4cb_28732_04b6f969e23240c51ec9d1ac7655dc5d.webp&#34;
               width=&#34;500&#34;
               height=&#34;272&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;因此，这为引擎提供了一种方式来表述：“对于此函数，进行类型检查，就好像这两个整数是一个字符串一样。”&lt;/p&gt;
&lt;p&gt;不过，这本模块附带的小册子事实是有用的，是因为另一个原因。&lt;/p&gt;
&lt;p&gt;有时，通常将其字符串存储在线性内存中的模块希望在特定情况下使用 &lt;code&gt;anyref&lt;/code&gt; 或者GC类型&amp;hellip;例如，如果模块只是传递从JS函数获得的对象到Web API，如DOM节点。&lt;/p&gt;
&lt;p&gt;因此，模块需要能够逐个函数（甚至逐个参数）地选择，以便获知如何处理不同的类型。由于映射是由模块提供的，因此可以为该模块定制。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/03-11-granularity-500x272_hu0ae264cb14fc5b90d13d749e3c3f8b56_30298_cfe4a67b4958409a6fde499334f26883.webp 400w,
               /post/201908-webassembly-interface-types/images/03-11-granularity-500x272_hu0ae264cb14fc5b90d13d749e3c3f8b56_30298_1b5c0c1a7757f2dbbcb86527454945e1.webp 760w,
               /post/201908-webassembly-interface-types/images/03-11-granularity-500x272_hu0ae264cb14fc5b90d13d749e3c3f8b56_30298_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/03-11-granularity-500x272_hu0ae264cb14fc5b90d13d749e3c3f8b56_30298_cfe4a67b4958409a6fde499334f26883.webp&#34;
               width=&#34;500&#34;
               height=&#34;272&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;你怎么生成这本小册子？&lt;/p&gt;
&lt;p&gt;编译器会为您处理这些信息。它为WebAssembly模块添加了一个自定义部分。因此对于许多语言工具链，程序员不需要做太多工作。&lt;/p&gt;
&lt;p&gt;例如，让我们看一下Rust工具链如何处理最简单的一种情况：将字符串传递给&lt;code&gt;alert&lt;/code&gt;函数。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-rust&#34; data-lang=&#34;rust&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#[wasm_bindgen]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;extern&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;C&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;fn&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;alert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;s&lt;/span&gt;: &lt;span class=&#34;kp&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;程序员只需告诉编译器使用&lt;code&gt;#[wasm_bindgen]&lt;/code&gt; 注解将此函数包含在小册子中。默认情况下，编译器会将其视为线性内存字符串，并为我们添加正确的映射。如果我们需要以不同的方式处理它（例如，作为&lt;code&gt;anyref&lt;/code&gt;），我们必须使用第二个注解告诉编译器。&lt;/p&gt;
&lt;p&gt;因此，我们可以在中间剔除JS。这使得在WebAssembly和Web API之间传递值更快。此外，这意味着我们不需要运送太多的JS。&lt;/p&gt;
&lt;p&gt;而且我们不必对我们支持的语言做出任何妥协。可以将所有不同类型的语言编译为WebAssembly。这些语言都可以将它们的类型映射到Web IDL类型 - 无论语言是使用线性内存还是GC对象，还是两者都使用。&lt;/p&gt;
&lt;p&gt;一旦我们退后一步看看这个解决方案，我们意识到它解决了一个更大的问题。&lt;/p&gt;
&lt;h2 id=&#34;webassembly与所有事物对话&#34;&gt;WebAssembly与所有事物对话&lt;/h2&gt;
&lt;p&gt;这是我们回到介绍中的承诺的地方。&lt;/p&gt;
&lt;p&gt;有没有一种可行的方法让WebAssembly使用不同类型的系统与不同的东西对话？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/04-01-star-diagram-768x581_hu3da9c911b5d1884f614157bcae7a8d58_104463_8fcae631ee6ff291159c633ef80c61e5.webp 400w,
               /post/201908-webassembly-interface-types/images/04-01-star-diagram-768x581_hu3da9c911b5d1884f614157bcae7a8d58_104463_a22031e27f9a94d81ec5c08a46f546c4.webp 760w,
               /post/201908-webassembly-interface-types/images/04-01-star-diagram-768x581_hu3da9c911b5d1884f614157bcae7a8d58_104463_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/04-01-star-diagram-768x581_hu3da9c911b5d1884f614157bcae7a8d58_104463_8fcae631ee6ff291159c633ef80c61e5.webp&#34;
               width=&#34;760&#34;
               height=&#34;575&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们来看看有什么可选的方案。&lt;/p&gt;
&lt;p&gt;您&lt;em&gt;可以&lt;/em&gt;尝试创建在引擎中硬编码的映射，例如WebAssembly到JS和JS到Web IDL。&lt;/p&gt;
&lt;p&gt;但要做到这一点，对于每种语言，您必须创建一个特定的映射。并且引擎必须明确支持这些映射中的每一个，并在任何一方的语言发生变化时更新它们。这会造成真正的混乱。&lt;/p&gt;
&lt;p&gt;这就是早期编译器的设计方式。从每种源语言到每种机器代码语言都有一个管道。我&lt;a href=&#34;https://hacks.mozilla.org/2017/02/a-cartoon-intro-to-webassembly/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;在WebAssembly上的第一篇文章中&lt;/a&gt;对此进行了更多的讨论。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/03-05-langs05-768x474_hue56d37d234e61ccf27ab61c179e751b6_103135_87ceb065b8b878cdaca83bd26c80bdd8.webp 400w,
               /post/201908-webassembly-interface-types/images/03-05-langs05-768x474_hue56d37d234e61ccf27ab61c179e751b6_103135_506d747f22254e950d38f889f4339d36.webp 760w,
               /post/201908-webassembly-interface-types/images/03-05-langs05-768x474_hue56d37d234e61ccf27ab61c179e751b6_103135_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/03-05-langs05-768x474_hue56d37d234e61ccf27ab61c179e751b6_103135_87ceb065b8b878cdaca83bd26c80bdd8.webp&#34;
               width=&#34;760&#34;
               height=&#34;469&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们不想要这么复杂的东西。我们希望所有这些不同的语言和平台能够相互通信。但我们也需要它可扩展。&lt;/p&gt;
&lt;p&gt;所以我们需要一种不同的方式来做到这一点&amp;hellip;更像现代编译器架构。它们在前端和后端之间分离。前端从源语言到抽象中间表示（intermediate representation/IR）。后端从IR到目标机器代码。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/03-06-langs06_hu3dd3fead57c264ef806f705fb3b6f385_451167_8346ce26e018b24fb00886fa1e343459.webp 400w,
               /post/201908-webassembly-interface-types/images/03-06-langs06_hu3dd3fead57c264ef806f705fb3b6f385_451167_c8931d0df413a7aed46aab788fe0ed08.webp 760w,
               /post/201908-webassembly-interface-types/images/03-06-langs06_hu3dd3fead57c264ef806f705fb3b6f385_451167_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/03-06-langs06_hu3dd3fead57c264ef806f705fb3b6f385_451167_8346ce26e018b24fb00886fa1e343459.webp&#34;
               width=&#34;760&#34;
               height=&#34;483&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这就是来自Web IDL的洞察力所在。注意看，Web IDL很像一个IR。&lt;/p&gt;
&lt;p&gt;现在，Web IDL非常适合Web。而有很多Web外的WebAssembly用例。因此，Web IDL本身并不是一个很好的IR。&lt;/p&gt;
&lt;p&gt;但是，如果您只是使用Web IDL作为灵感并创建一组新的抽象类型呢？&lt;/p&gt;
&lt;p&gt;这就是我们提出WebAssembly接口类型提议的由来。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/04-06-types-as-IR-500x321_hu37a4d32be3ce47899f8dccc8aadcb41a_64666_f9e4021fd9b0678bdfeee3f1ced9018d.webp 400w,
               /post/201908-webassembly-interface-types/images/04-06-types-as-IR-500x321_hu37a4d32be3ce47899f8dccc8aadcb41a_64666_0d5c236bff2dc678a486db8d621332d4.webp 760w,
               /post/201908-webassembly-interface-types/images/04-06-types-as-IR-500x321_hu37a4d32be3ce47899f8dccc8aadcb41a_64666_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/04-06-types-as-IR-500x321_hu37a4d32be3ce47899f8dccc8aadcb41a_64666_f9e4021fd9b0678bdfeee3f1ced9018d.webp&#34;
               width=&#34;500&#34;
               height=&#34;321&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这些类型不是具体类型。他们不像今天WebAssembly中的 &lt;code&gt;int32&lt;/code&gt; 或 &lt;code&gt;float64&lt;/code&gt; 类型。WebAssembly中没有对它们进行任何操作。&lt;/p&gt;
&lt;p&gt;例如，WebAssembly中不会添加任何字符串连接操作。相反，所有操作都在两端的具体类型上执行。&lt;/p&gt;
&lt;p&gt;有一个可以实现这一点的关键点：对于接口类型，双方并不试图共享表示。相反，默认是在一侧和另一侧之间复制值。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/04-07-copy-768x565_hub38c8c69f9a04d1a5a72ab03e6b3b98b_97023_fe077e6eb8d7bf9b0a5ef0b8ba931943.webp 400w,
               /post/201908-webassembly-interface-types/images/04-07-copy-768x565_hub38c8c69f9a04d1a5a72ab03e6b3b98b_97023_0abc08cbc6e2537d59ac6da82921074b.webp 760w,
               /post/201908-webassembly-interface-types/images/04-07-copy-768x565_hub38c8c69f9a04d1a5a72ab03e6b3b98b_97023_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/04-07-copy-768x565_hub38c8c69f9a04d1a5a72ab03e6b3b98b_97023_fe077e6eb8d7bf9b0a5ef0b8ba931943.webp&#34;
               width=&#34;760&#34;
               height=&#34;559&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;有一种情况似乎是这条规则的例外：我之前提到的新参考值（如&lt;code&gt;anyref&lt;/code&gt;）。在这种情况下，在两侧之间复制的是指向对象的指针。所以两个指针指向同一个东西。理论上，这可能意味着他们需要共享一个表示。&lt;/p&gt;
&lt;p&gt;如果引用只是在WebAssembly模块中透传（就像我上面给出的示例 &lt;code&gt;anyref&lt;/code&gt;），双方仍然不需要共享表示。无论如何，模块不会理解该类型&amp;hellip;&amp;hellip;只需将其传递给其他函数即可。&lt;/p&gt;
&lt;p&gt;但有时双方都希望共享表示。例如，GC提案添加了一种&lt;a href=&#34;https://github.com/WebAssembly/gc/blob/master/proposals/gc/MVP-JS.md#type-definition-objects&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;创建类型定义&lt;/a&gt;的方法，以便双方可以共享表示。在这些情况下，选择共享多少表示取决于设计API的开发人员。&lt;/p&gt;
&lt;p&gt;这使得单个模块与许多不同语言对话变得容易得多。&lt;/p&gt;
&lt;p&gt;在某些情况下，如浏览器，从接口类型到主机的具体类型的映射将被引入引擎。&lt;/p&gt;
&lt;p&gt;因此，一组映射在编译时完成，另一组映射在加载时被传递给引擎。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/04-08-mapping-symmetry-host-500x243_hua5a36851c554765e3c956951f0ab5654_31760_3039dac1ffb176b3fb1f2bb01122f9a8.webp 400w,
               /post/201908-webassembly-interface-types/images/04-08-mapping-symmetry-host-500x243_hua5a36851c554765e3c956951f0ab5654_31760_8775d8b7c73ee9f33b8e1d7eb0a0d38e.webp 760w,
               /post/201908-webassembly-interface-types/images/04-08-mapping-symmetry-host-500x243_hua5a36851c554765e3c956951f0ab5654_31760_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/04-08-mapping-symmetry-host-500x243_hua5a36851c554765e3c956951f0ab5654_31760_3039dac1ffb176b3fb1f2bb01122f9a8.webp&#34;
               width=&#34;500&#34;
               height=&#34;243&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;但在其他情况下，比如当两个WebAssembly模块相互通信时，它们都会发送自己的小册子。它们每个都将它们的函数类型映射到抽象类型。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/04-09-mapping-symmetry-wasm-500x302_hud802d0d268df84ca86b9d5bf3fe7414a_43872_ac0810ac31e99318dff8442473da288c.webp 400w,
               /post/201908-webassembly-interface-types/images/04-09-mapping-symmetry-wasm-500x302_hud802d0d268df84ca86b9d5bf3fe7414a_43872_67987662f7cefae7c44abd10f3c6b4b1.webp 760w,
               /post/201908-webassembly-interface-types/images/04-09-mapping-symmetry-wasm-500x302_hud802d0d268df84ca86b9d5bf3fe7414a_43872_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/04-09-mapping-symmetry-wasm-500x302_hud802d0d268df84ca86b9d5bf3fe7414a_43872_ac0810ac31e99318dff8442473da288c.webp&#34;
               width=&#34;500&#34;
               height=&#34;302&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;要使用不同源语言编写的模块能够相互通信，这不是唯一需要的内容（我们将来会对此进行更多详细介绍），但这是朝这个方向迈出的一大步。&lt;/p&gt;
&lt;p&gt;所以现在你明白了为什么，让我们来看看如何。&lt;/p&gt;
&lt;h2 id=&#34;这些接口类型实际上是什么样的&#34;&gt;这些接口类型实际上是什么样的？&lt;/h2&gt;
&lt;p&gt;在我们审视细节之前，我要再说一遍：这个提案仍在制定之中。因此，最终提案可能看起来非常不同。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/05-01-construction-500x296_hu4945319ab0a0bf9d2b922bf2eff71454_38358_e78121a857e49c8eb97ab40e91c8579f.webp 400w,
               /post/201908-webassembly-interface-types/images/05-01-construction-500x296_hu4945319ab0a0bf9d2b922bf2eff71454_38358_cc320f68530b1efc62e252d11eed59b5.webp 760w,
               /post/201908-webassembly-interface-types/images/05-01-construction-500x296_hu4945319ab0a0bf9d2b922bf2eff71454_38358_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/05-01-construction-500x296_hu4945319ab0a0bf9d2b922bf2eff71454_38358_e78121a857e49c8eb97ab40e91c8579f.webp&#34;
               width=&#34;500&#34;
               height=&#34;296&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;此外，这完全由编译器处理。因此，即使提案最终确定，您也只需要知道工具链希望在代码中添加哪些注解（例如上面的wasm-bindgen示例）。你真的不需要知道这一切是如何运作的。&lt;/p&gt;
&lt;p&gt;不过该 &lt;a href=&#34;https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;提案的细节&lt;/a&gt; 非常简洁，所以让我们深入了解当前的想法。&lt;/p&gt;
&lt;h3 id=&#34;要解决的问题&#34;&gt;要解决的问题&lt;/h3&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;接受来自调用者的参数&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;ul&gt;
&lt;li&gt;将参数传递给函数&lt;/li&gt;
&lt;li&gt;接受函数的返回值&lt;/li&gt;
&lt;/ul&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;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/05-02-incoming-outgoing-500x306_huf71e5ee010a4d4474d6ff3e82f7e3648_47598_28994d37eef4bea4c9c5c3670e2c7a10.webp 400w,
               /post/201908-webassembly-interface-types/images/05-02-incoming-outgoing-500x306_huf71e5ee010a4d4474d6ff3e82f7e3648_47598_f51a9b9e10fec9ca743c8968814b5d8a.webp 760w,
               /post/201908-webassembly-interface-types/images/05-02-incoming-outgoing-500x306_huf71e5ee010a4d4474d6ff3e82f7e3648_47598_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/05-02-incoming-outgoing-500x306_huf71e5ee010a4d4474d6ff3e82f7e3648_47598_28994d37eef4bea4c9c5c3670e2c7a10.webp&#34;
               width=&#34;500&#34;
               height=&#34;306&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;告诉引擎如何在具体类型和接口类型之间进行转换&#34;&gt;告诉引擎如何在具体类型和接口类型之间进行转换&lt;/h3&gt;
&lt;p&gt;因此，我们需要一种方法来告诉引擎哪些转换可以应用于函数的参数和返回值。我们如何做到这一点？&lt;/p&gt;
&lt;p&gt;通过定义接口适配器。&lt;/p&gt;
&lt;p&gt;例如，假设我们有一个编译为WebAssembly的Rust模块。它导出一个&lt;code&gt;greeting_&lt;/code&gt; 函数，这个函数可以在没有任何参数的情况下调用并返回问候语。&lt;/p&gt;
&lt;p&gt;就是这个样子（WebAssembly文本格式）。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/05-03-original-function-500x162_hu052b491ddc19e769ce99dac9f3d8b6c2_27448_f65e5bb4e573489215c97465400d6f62.webp 400w,
               /post/201908-webassembly-interface-types/images/05-03-original-function-500x162_hu052b491ddc19e769ce99dac9f3d8b6c2_27448_7962f08c0c84c032210ca86cadec4929.webp 760w,
               /post/201908-webassembly-interface-types/images/05-03-original-function-500x162_hu052b491ddc19e769ce99dac9f3d8b6c2_27448_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/05-03-original-function-500x162_hu052b491ddc19e769ce99dac9f3d8b6c2_27448_f65e5bb4e573489215c97465400d6f62.webp&#34;
               width=&#34;500&#34;
               height=&#34;162&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;现在这个函数返回两个整数。&lt;/p&gt;
&lt;p&gt;但我们希望它返回&lt;code&gt;string&lt;/code&gt;接口类型。所以我们添加一个称为接口适配器的东西&lt;/p&gt;
&lt;p&gt;如果引擎理解接口类型，那么当它看到此接口适配器时，它将使用此接口包装原始模块。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/05-04-interface-500x184_hube4b5715e678a1ab54ecfe7f5de8dd30_26032_610531b93f49fc769ad3881f09f65722.webp 400w,
               /post/201908-webassembly-interface-types/images/05-04-interface-500x184_hube4b5715e678a1ab54ecfe7f5de8dd30_26032_8c966df57a4db84e3367387bc1b27de8.webp 760w,
               /post/201908-webassembly-interface-types/images/05-04-interface-500x184_hube4b5715e678a1ab54ecfe7f5de8dd30_26032_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/05-04-interface-500x184_hube4b5715e678a1ab54ecfe7f5de8dd30_26032_610531b93f49fc769ad3881f09f65722.webp&#34;
               width=&#34;500&#34;
               height=&#34;184&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;它将不再导出该&lt;code&gt;greeting_&lt;/code&gt;函数&amp;hellip;而是包裹了原始函数的 &lt;code&gt;greeting&lt;/code&gt;函数。这个新&lt;code&gt;greeting&lt;/code&gt;函数返回一个字符串，而不是两个数字。&lt;/p&gt;
&lt;p&gt;这提供了向后兼容性，因为不理解接口类型的引擎将只导出原始&lt;code&gt;greeting_&lt;/code&gt;函数（返回两个整数的函数）。&lt;/p&gt;
&lt;p&gt;接口适配器如何告诉引擎将两个整数转换为字符串？&lt;/p&gt;
&lt;p&gt;它使用一系列适配器指令。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/05-05-adapter-inst-return-500x252_hude6aae87572320c68a85e06963641370_41708_6b3539c187fcb2dedb8940622c7e7e54.webp 400w,
               /post/201908-webassembly-interface-types/images/05-05-adapter-inst-return-500x252_hude6aae87572320c68a85e06963641370_41708_ed9893f7dd5814b657f462cda651b8ba.webp 760w,
               /post/201908-webassembly-interface-types/images/05-05-adapter-inst-return-500x252_hude6aae87572320c68a85e06963641370_41708_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/05-05-adapter-inst-return-500x252_hude6aae87572320c68a85e06963641370_41708_6b3539c187fcb2dedb8940622c7e7e54.webp&#34;
               width=&#34;500&#34;
               height=&#34;252&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;上面的适配器指令是提案指定的一小组新指令中的两个。&lt;/p&gt;
&lt;p&gt;以下是对上述代码的说明：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用&lt;code&gt;call-export&lt;/code&gt;适配器指令调用原始&lt;code&gt;greeting_&lt;/code&gt;函数。这是原始模块导出的，返回两个数字。这些数字放在堆栈上。&lt;/li&gt;
&lt;li&gt;使用&lt;code&gt;memory-to-string&lt;/code&gt;适配器指令将数字转换为组成字符串的字节序列。我们必须在这里指定“mem”，因为WebAssembly模块有一天会有多个内存。这告诉引擎要查看哪个内存。然后引擎从堆栈顶部获取两个整数（指针和长度）并使用它们来确定要使用的字节。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这可能看起来像一个成熟的编程语言。但是这里没有控制流 - 没有循环或分支。因此，即使我们提供引擎指令，它仍然是声明性的。&lt;/p&gt;
&lt;p&gt;如果我们的函数也将字符串作为参数（例如，要问候的人的姓名），它会是什么样子？&lt;/p&gt;
&lt;p&gt;非常相似。我们只需更改适配器函数的接口即可添加参数。然后我们添加两个新的适配器指令。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/05-06-adapter-inst-param-500x291_hu4b0e4161fecba5dc1efb0bfd0c8a82b6_53727_1a0588323bab3041538a30f3aa50e77b.webp 400w,
               /post/201908-webassembly-interface-types/images/05-06-adapter-inst-param-500x291_hu4b0e4161fecba5dc1efb0bfd0c8a82b6_53727_f8d4ad9346c673bb025f0a5582cae897.webp 760w,
               /post/201908-webassembly-interface-types/images/05-06-adapter-inst-param-500x291_hu4b0e4161fecba5dc1efb0bfd0c8a82b6_53727_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/05-06-adapter-inst-param-500x291_hu4b0e4161fecba5dc1efb0bfd0c8a82b6_53727_1a0588323bab3041538a30f3aa50e77b.webp&#34;
               width=&#34;500&#34;
               height=&#34;291&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;以下是这些新指令的作用：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;使用 &lt;code&gt;arg.get&lt;/code&gt;指令获取对字符串对象的引用并将其放在堆栈中。&lt;/li&gt;
&lt;li&gt;使用该&lt;code&gt;string-to-memory&lt;/code&gt;指令从该对象获取字节并将它们放入线性内存中。再次，我们必须告诉它将字节放入哪个内存。我们还必须告诉它如何分配字节。我们通过给它一个分配器函数（这将是原始模块提供的导出函数）来实现这一点。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;使用这样的指令的好处是：我们可以在将来扩展它们&amp;hellip;&amp;hellip;就像我们可以扩展WebAssembly核心中的指令一样。我们认为我们所定义的指令是一个很好的集合，但我们并不承诺这些是有史以来唯一的指导。&lt;/p&gt;
&lt;p&gt;如果您有兴趣了解更多关于这一切是如何工作的，&lt;a href=&#34;https://github.com/WebAssembly/interface-types/blob/master/proposals/interface-types/Explainer.md&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;解释器&lt;/a&gt;会更加详细。&lt;/p&gt;
&lt;h3 id=&#34;将这些指令发送到引擎&#34;&gt;将这些指令发送到引擎&lt;/h3&gt;
&lt;p&gt;现在我们如何将它发送到引擎？&lt;/p&gt;
&lt;p&gt;这些注解会添加到二进制文件中的自定义部分。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/05-07-custom-section-500x252_hudd68781933ca8b3d1cf26f40fc7c98a4_31175_ecfba6106cb85d500ffaeeccecace478.webp 400w,
               /post/201908-webassembly-interface-types/images/05-07-custom-section-500x252_hudd68781933ca8b3d1cf26f40fc7c98a4_31175_b339bf31212f75c343bc5918f726f935.webp 760w,
               /post/201908-webassembly-interface-types/images/05-07-custom-section-500x252_hudd68781933ca8b3d1cf26f40fc7c98a4_31175_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/05-07-custom-section-500x252_hudd68781933ca8b3d1cf26f40fc7c98a4_31175_ecfba6106cb85d500ffaeeccecace478.webp&#34;
               width=&#34;500&#34;
               height=&#34;252&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如果引擎知道接口类型，则可以使用自定义部分。如果没有，引擎可以忽略它，你可以使用polyfill读取自定义部分并创建粘合代码。&lt;/p&gt;
&lt;h2 id=&#34;这与corbaprotocol-buffers等有什么不同&#34;&gt;这与CORBA，Protocol Buffers等有什么不同？&lt;/h2&gt;
&lt;p&gt;还有其他标准，似乎也可以解决相同的问题 - 例如CORBA，Protocol Buffers和Cap&amp;rsquo;n Proto。&lt;/p&gt;
&lt;p&gt;那些有什么不同？他们正在解决一个更难的问题。&lt;/p&gt;
&lt;p&gt;它们都经过精心设计，以便您可以与不共享内存的系统进行交互，因为它在不同的进程中运行，或者因为它位于网络上完全不同的计算机上。&lt;/p&gt;
&lt;p&gt;这意味着您必须能够在中间发送事物 - 跨越该边界的对象的“中间表示”。&lt;/p&gt;
&lt;p&gt;因此，这些标准需要定义可以有效跨越边界的序列化格式。这是他们标准化的重要组成部分。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/06-01-cross-boundary-ir-500x109_hu9ee106a13b575818aa19996f4a54f2cd_23262_54d8a6e55e61e13c16745fb33f1c09b2.webp 400w,
               /post/201908-webassembly-interface-types/images/06-01-cross-boundary-ir-500x109_hu9ee106a13b575818aa19996f4a54f2cd_23262_64f667681daa0b03117069b4fcc4467f.webp 760w,
               /post/201908-webassembly-interface-types/images/06-01-cross-boundary-ir-500x109_hu9ee106a13b575818aa19996f4a54f2cd_23262_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/06-01-cross-boundary-ir-500x109_hu9ee106a13b575818aa19996f4a54f2cd_23262_54d8a6e55e61e13c16745fb33f1c09b2.webp&#34;
               width=&#34;500&#34;
               height=&#34;109&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这看起来像一个类似的问题，它实际上完全不一样。&lt;/p&gt;
&lt;p&gt;对于接口类型，这个“IR”从来不需要离开引擎。模块本身甚至都看不到它。&lt;/p&gt;
&lt;p&gt;模块只能看到引擎在过程结束时为它们突出的内容 - 将哪些内容复制到线性内存中或作为引用给出。因此，我们不必告诉引擎为这些类型提供哪种布局 - 不需要指定。&lt;/p&gt;
&lt;p&gt;需要指定的是，和引擎对话的方式。这是发送到引擎的手册的声明性语言。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/06-02-no-boundary-ir-500x115_hu52512a8de9594981b5e9e5778e88cdf4_19277_dc0094be24cd335f75a3b6ace0f8c686.webp 400w,
               /post/201908-webassembly-interface-types/images/06-02-no-boundary-ir-500x115_hu52512a8de9594981b5e9e5778e88cdf4_19277_883248f4de2398274fda7085aebd028d.webp 760w,
               /post/201908-webassembly-interface-types/images/06-02-no-boundary-ir-500x115_hu52512a8de9594981b5e9e5778e88cdf4_19277_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/06-02-no-boundary-ir-500x115_hu52512a8de9594981b5e9e5778e88cdf4_19277_dc0094be24cd335f75a3b6ace0f8c686.webp&#34;
               width=&#34;500&#34;
               height=&#34;115&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这有一个很好的边际效应：因为这是声明性的，引擎可以看到何时不需要转换 - 例如两边的两个模块使用相同的类型 - 并完全跳过转换工作。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/06-03-opt-500x327_hu084b0f82672ea6047cab375e2bb3d584_42548_415c5bf7df3a684fa9678b7573847168.webp 400w,
               /post/201908-webassembly-interface-types/images/06-03-opt-500x327_hu084b0f82672ea6047cab375e2bb3d584_42548_3193640be8c1415f04ef4d1dbdc62f83.webp 760w,
               /post/201908-webassembly-interface-types/images/06-03-opt-500x327_hu084b0f82672ea6047cab375e2bb3d584_42548_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/06-03-opt-500x327_hu084b0f82672ea6047cab375e2bb3d584_42548_415c5bf7df3a684fa9678b7573847168.webp&#34;
               width=&#34;500&#34;
               height=&#34;327&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;今天你怎么尝试这个&#34;&gt;今天你怎么尝试这个？&lt;/h2&gt;
&lt;p&gt;正如我上面提到的，这是一个早期阶段的提案。这意味着事情会发生迅速变化，你不想在生产中依赖于此。&lt;/p&gt;
&lt;p&gt;但是如果你想开始尝试它，我们已经在工具链中实现了这一点，从生产到消费：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rust工具链&lt;/li&gt;
&lt;li&gt;WASM-BindGen&lt;/li&gt;
&lt;li&gt;Wasmtime WebAssembly运行时&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于我们维护所有这些工具，并且由于我们正在制定标准本身，因此我们可以跟随标准的发展。&lt;/p&gt;
&lt;p&gt;尽管所有这些部分都将继续改变，但我们将确保同步我们的更改。因此，只要您使用所有这些的最新版本，就不会有问题。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/07-01-construction-500x296_hud142bd19583ea824e2bd21b7fd86d8f0_39527_7e611de6fbde410bfdb5a96ca40389b8.webp 400w,
               /post/201908-webassembly-interface-types/images/07-01-construction-500x296_hud142bd19583ea824e2bd21b7fd86d8f0_39527_bad1d5997f899b67c009ae8ba9d0f167.webp 760w,
               /post/201908-webassembly-interface-types/images/07-01-construction-500x296_hud142bd19583ea824e2bd21b7fd86d8f0_39527_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/07-01-construction-500x296_hud142bd19583ea824e2bd21b7fd86d8f0_39527_7e611de6fbde410bfdb5a96ca40389b8.webp&#34;
               width=&#34;500&#34;
               height=&#34;296&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;所以今天有很多方法可以解决这个问题。有关最新版本，请查看此&lt;a href=&#34;https://github.com/CraneStation/wasmtime-demos&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;demo仓库&lt;/a&gt;。&lt;/p&gt;
&lt;h2 id=&#34;谢谢&#34;&gt;谢谢&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;感谢团队，将所有这些语言和运行时间整合在一起：Alex Crichton，Yury Delendik，Nick Fitzgerald，Dan Gohman和Till Schneidereit&lt;/li&gt;
&lt;li&gt;感谢提案的联合发起人及其工作与这个提案的同事：Luke Wagner，Francis McCabe，Jacob Gravelle，Alex Crichton和Nick Fitzgerald&lt;/li&gt;
&lt;li&gt;感谢我的精彩合作者Luke Wagner和Till Schneidereit对本文的宝贵意见和反馈&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;译者注&#34;&gt;译者注&lt;/h3&gt;
&lt;p&gt;简单总结，WASI 就是在使用WASM进行交互时提供的&lt;strong&gt;抽象中间表示&lt;/strong&gt;（intermediate representation/IR）：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-webassembly-interface-types/images/04-06-types-as-IR-500x321_hu37a4d32be3ce47899f8dccc8aadcb41a_64666_f9e4021fd9b0678bdfeee3f1ced9018d.webp 400w,
               /post/201908-webassembly-interface-types/images/04-06-types-as-IR-500x321_hu37a4d32be3ce47899f8dccc8aadcb41a_64666_0d5c236bff2dc678a486db8d621332d4.webp 760w,
               /post/201908-webassembly-interface-types/images/04-06-types-as-IR-500x321_hu37a4d32be3ce47899f8dccc8aadcb41a_64666_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-webassembly-interface-types/images/04-06-types-as-IR-500x321_hu37a4d32be3ce47899f8dccc8aadcb41a_64666_f9e4021fd9b0678bdfeee3f1ced9018d.webp&#34;
               width=&#34;500&#34;
               height=&#34;321&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;然后通过接口适配器来告诉引擎进行转换，以处理函数的参数和返回值，从而实现跨语言使用复杂类型的交互。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译] 标准化WASI：在Web外运行WebAssembly的系统接口</title>
      <link>https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/</link>
      <pubDate>Tue, 27 Aug 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Standardizing WASI: A system interface to run WebAssembly outside the web
&lt;/a&gt;，作者 &lt;a href=&#34;https://twitter.com/linclark&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Lin Clark&lt;/a&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：快速翻译（机翻+人工校对，没有精修），质量不高，一般阅读可以，不适合传播，谢绝转载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;p&gt;今天，我们宣布开始新的标准化工作&amp;ndash;WASI，WebAssembly系统接口。&lt;/p&gt;
&lt;p&gt;**原因：**开发人员开始将WebAssembly向浏览器之外推，因为它提供了一种快速，可扩展，安全的方式，可以在所有机器上运行同样的代码。&lt;/p&gt;
&lt;p&gt;但我们尚未打造好坚实的基础。浏览器之外的代码需要一种与系统通信的方式 - 系统接口（system interface）。WebAssembly平台还没有这个。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;内容：&lt;/strong&gt; WebAssembly是概念机器的汇编语言，而不是物理机器。这是它可以在各种不同机器架构上运行的原因。&lt;/p&gt;
&lt;p&gt;正如WebAssembly是概念机器的汇编语言一样，WebAssembly需要一个概念操作系统的系统接口，而不是单个操作系统。这样，它可以运行在所有不同的操作系统上。&lt;/p&gt;
&lt;p&gt;这就是WASI - WebAssembly平台的系统接口。&lt;/p&gt;
&lt;p&gt;我们的目标是创建一个系统接口，它将成为WebAssembly的真正伴侣并经受时间的考验。这意味着需要坚持WebAssembly的关键原则 - 可移植性和安全性。&lt;/p&gt;
&lt;p&gt;**谁：**我们正在组建一个WebAssembly小组，专注于标准化&lt;a href=&#34;https://wasi.dev/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;WASI&lt;/a&gt;。我们已经收集了感兴趣的合作伙伴，并且正在寻找更多的人加入。&lt;/p&gt;
&lt;p&gt;以下是我们，我们的合作伙伴以及我们的支持者认为这很重要的一些原因：&lt;/p&gt;
&lt;h4 id=&#34;sez-whitemozilla的首席研发官员&#34;&gt;Sez White，Mozilla的首席研发官员&lt;/h4&gt;
&lt;p&gt;“WebAssembly已经在改变网络使用方式，为人们带来新的引人注目的内容，并赋能开发人员和创作者能够在网络上做最好的工作。到目前为止是通过浏览器，但通过WASI，我们可以将WebAssembly和Web的优势扩展到更多的用户，更多的地方，更多的设备，带来更多的体验。“&lt;/p&gt;
&lt;h4 id=&#34;tyler-mcmullenfastly的首席技术官&#34;&gt;Tyler McMullen，Fastly的首席技术官&lt;/h4&gt;
&lt;p&gt;“我们将WebAssembly在浏览器之外使用，作为平台，在我们的边缘云中快速而安全地执行代码。尽管我们的边缘和浏览器之间的环境存在差异，但WASI意味着WebAssembly开发人员不必将代码移植到每个不同的平台。“&lt;/p&gt;
&lt;h4 id=&#34;myles-borinsnode技术指导委员会主管&#34;&gt;Myles Borins，Node技术指导委员会主管&lt;/h4&gt;
&lt;p&gt;“WebAssembly可以解决Node中最大的问题之一 - 如何获得接近原生的速度，并重用其他语言（如C和C ++）编写的代码，就像使用原生模块一样，同时仍保持可移植性和安全性。标准化系统界面是实现这一目标的第一步。“&lt;/p&gt;
&lt;h4 id=&#34;laurie-vossnpm的联合创始人&#34;&gt;Laurie Voss，npm的联合创始人&lt;/h4&gt;
&lt;p&gt;“npm非常感兴趣的是，WebAssembly可以扩展npm生态系统的功能，同时极大地简化了在服务器端JavaScript应用程序中运行原生代码的过程。我们期待着这个过程的结果。“&lt;/p&gt;
&lt;p&gt;这是个大新闻！🎉&lt;/p&gt;
&lt;p&gt;WASI目前有3个实现：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/CraneStation/wasmtime&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;wasmtime&lt;/a&gt;，Mozilla的WebAssembly运行时&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.fastly.com/blog/announcing-lucet-fastly-native-webassembly-compiler-runtime&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Lucet&lt;/a&gt;，Fastly的WebAssembly运行时&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://wasi.dev/polyfill/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;浏览器polyfill&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;您可以在此视频中看到WASI的运行情况：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/embed/ggtEJC0Jv8A&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://www.youtube.com/embed/ggtEJC0Jv8A&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;关于此系统接口应如何工作的建议，如果您想了解更多信息，请继续阅读。&lt;/p&gt;
&lt;h3 id=&#34;什么是系统界接口&#34;&gt;什么是系统界接口？&lt;/h3&gt;
&lt;p&gt;许多人谈论语言，像C那样可以直接访问系统资源。但是，这不是&lt;em&gt;很&lt;/em&gt;真实*。*&lt;/p&gt;
&lt;p&gt;这些语言在大多数系统上无法直接访问和操作，如打开或创建文件等。为什么不能？&lt;/p&gt;
&lt;p&gt;因为这些系统资源（例如文件，内存和网络连接）对于稳定性和安全性来说太重要了。&lt;/p&gt;
&lt;p&gt;如果一个程序无意中弄乱了另一个程序的资源，那么它可能会使程序崩溃。更糟糕的是，如果程序（或用户）故意与另一个程序（或用户）的资源混淆，它可能会窃取敏感数据。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/01-01_crash-data-leak-1-768x338_hube76f4fd22211bd109993666767eb821_41580_caeacf9884e598a2ea73d18dda3a8e4e.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/01-01_crash-data-leak-1-768x338_hube76f4fd22211bd109993666767eb821_41580_f30b0725f4b025106aa2b5b7e1c81c54.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/01-01_crash-data-leak-1-768x338_hube76f4fd22211bd109993666767eb821_41580_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/01-01_crash-data-leak-1-768x338_hube76f4fd22211bd109993666767eb821_41580_caeacf9884e598a2ea73d18dda3a8e4e.webp&#34;
               width=&#34;760&#34;
               height=&#34;334&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;因此，我们需要一种方法来控制程序和用户可以访问哪些资源。人们很早就发现了这一点，并提出了一种方法来提供这种控制：保护环安全（protection ring security）。&lt;/p&gt;
&lt;p&gt;通过保护环安全，操作系统基本上为系统资源提供了保护屏障。这是内核。内核是唯一可以执行操作的地方，例如创建新文件、打开文件或打开网络连接。&lt;/p&gt;
&lt;p&gt;用户的程序在内核之外运行，称为用户模式。如果某个程序想要打开文件，它必须要求内核为它打开文件。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/01-02-protection-ring-sec-1-768x457_hu5a733b4ac0304d1dea2f8ee32c9a7dac_104093_33bde26a4b2f394b5e0198010bdc1b3f.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/01-02-protection-ring-sec-1-768x457_hu5a733b4ac0304d1dea2f8ee32c9a7dac_104093_eab6bef19a2ea3d4da1e996723e5810d.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/01-02-protection-ring-sec-1-768x457_hu5a733b4ac0304d1dea2f8ee32c9a7dac_104093_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/01-02-protection-ring-sec-1-768x457_hu5a733b4ac0304d1dea2f8ee32c9a7dac_104093_33bde26a4b2f394b5e0198010bdc1b3f.webp&#34;
               width=&#34;760&#34;
               height=&#34;452&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这就是系统调用的概念。当程序需要请求内核执行其中一项操作时，它会要求使用系统调用。这使内核有机会找出是哪个用户在请求。然后它可以在打开之前查看该用户是否可以访问该文件。&lt;/p&gt;
&lt;p&gt;在大多数设备上，这是您的代码可以访问系统资源的唯一方法 —— 通过系统调用。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/01-03-syscall-1-768x349_huf1194d897885b7e2b8043b6be63a7b96_72836_c1ebd1ba46104a575abe8decbbfc4569.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/01-03-syscall-1-768x349_huf1194d897885b7e2b8043b6be63a7b96_72836_423a132e23699bd126432b9463565571.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/01-03-syscall-1-768x349_huf1194d897885b7e2b8043b6be63a7b96_72836_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/01-03-syscall-1-768x349_huf1194d897885b7e2b8043b6be63a7b96_72836_c1ebd1ba46104a575abe8decbbfc4569.webp&#34;
               width=&#34;760&#34;
               height=&#34;345&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;操作系统使系统调用可用。但是，如果每个操作系统都有自己的系统调用，那么您是否需要为每个操作系统使用不同版本的代码？幸运的是，你没有。&lt;/p&gt;
&lt;p&gt;这个问题如何解决的？抽象。&lt;/p&gt;
&lt;p&gt;大多数语言都提供标准库。在编码时，程序员不需要知道他们所针对的系统。他们只使用接口。&lt;/p&gt;
&lt;p&gt;然后，在编译时，工具链会根据针对的系统选择要使用的接口实现。此实现使用操作系统API中的函数，因此它特定于系统。&lt;/p&gt;
&lt;p&gt;这是系统接口的用武之地。例如，&lt;code&gt;printf&lt;/code&gt; 被编译为在Windows机器上使用Windows API与机器进行交互。如果为Mac或Linux编译的，它将使用POSIX。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/02-01-implementations-1-768x409_hu743f73dd56ffb81171cd94d07c4f4ce9_75055_c45c1b6bd15ec7559630e60dcfc1bd57.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/02-01-implementations-1-768x409_hu743f73dd56ffb81171cd94d07c4f4ce9_75055_d0acf930ef8cd1a5978437439cfd1091.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/02-01-implementations-1-768x409_hu743f73dd56ffb81171cd94d07c4f4ce9_75055_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/02-01-implementations-1-768x409_hu743f73dd56ffb81171cd94d07c4f4ce9_75055_c45c1b6bd15ec7559630e60dcfc1bd57.webp&#34;
               width=&#34;760&#34;
               height=&#34;405&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;但这对WebAssembly来说是个问题。&lt;/p&gt;
&lt;p&gt;使用WebAssembly，即使在编译时，也不知道要定位的操作系统类型。因此，无法在标准库的WebAssembly实现中使用任何单独的OS系统接口。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/02-02-implementations-1-768x399_hu451527656f9dda8aaa4a1260f3fbedf5_45562_b7d34e60572f250f6ebbc153e5d86a7d.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/02-02-implementations-1-768x399_hu451527656f9dda8aaa4a1260f3fbedf5_45562_6e850d8eef91d41b2aed6f80e9cefe86.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/02-02-implementations-1-768x399_hu451527656f9dda8aaa4a1260f3fbedf5_45562_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/02-02-implementations-1-768x399_hu451527656f9dda8aaa4a1260f3fbedf5_45562_b7d34e60572f250f6ebbc153e5d86a7d.webp&#34;
               width=&#34;760&#34;
               height=&#34;395&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我之前谈过WebAssembly如何是&lt;a href=&#34;https://hacks.mozilla.org/2017/02/creating-and-working-with-webassembly-modules/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;概念机器的汇编语言&lt;/a&gt;，而不是真正的机器。同样，WebAssembly需要一个概念操作系统的系统接口，而不是真实的操作系统。&lt;/p&gt;
&lt;p&gt;但是已经存在有可以在浏览器外运行WebAssembly的运行时，即使没有系统接口也是如此。他们是如何做到的呢？让我们来看看。&lt;/p&gt;
&lt;h3 id=&#34;今天webassembly如何在浏览器之外运行的&#34;&gt;今天WebAssembly如何在浏览器之外运行的？&lt;/h3&gt;
&lt;p&gt;生成WebAssembly的第一个工具是Emscripten。它在Web上模拟了特定的OS系统接口，POSIX。这意味着程序员可以使用C标准库（libc）中的函数。&lt;/p&gt;
&lt;p&gt;为此，Emscripten创建了自己的libc实现。实现分为两部分 - 一部分编译成WebAssembly模块，另一部分用JS粘合代码实现。然后，这个JS胶水代码会调用浏览器，然后与操作系统进行通信。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/03-01-emscripten-1-768x505_huce6e0cdba48c1c5ae2d90652baf41d31_53402_ee398fbb2f84e64ed547935a4a85586d.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/03-01-emscripten-1-768x505_huce6e0cdba48c1c5ae2d90652baf41d31_53402_29f9d14e37ab54ba056db08c8ecc4391.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/03-01-emscripten-1-768x505_huce6e0cdba48c1c5ae2d90652baf41d31_53402_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/03-01-emscripten-1-768x505_huce6e0cdba48c1c5ae2d90652baf41d31_53402_ee398fbb2f84e64ed547935a4a85586d.webp&#34;
               width=&#34;760&#34;
               height=&#34;500&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;大多数早期的WebAssembly代码都是使用Emscripten编译的。因此，当人们开始想要在没有浏览器的情况下运行WebAssembly时，他们首先要让Emscripten编译的代码运行起来。&lt;/p&gt;
&lt;p&gt;因此，这些运行时需要为JS粘合代码中的所有函数创建自己的实现。&lt;/p&gt;
&lt;p&gt;但是这里有一个问题。JS胶水代码提供的接口并不是标准的，甚至不是面向公开的接口。这不能解决问题。&lt;/p&gt;
&lt;p&gt;例如，对于一个类似  &lt;code&gt;read&lt;/code&gt; 调用的函数，而 &lt;code&gt;read&lt;/code&gt; 在被设计为公开接口的API中，JS胶水代码使用&lt;code&gt;_system3(which, varargs)&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/03-02-system3-1-768x275_huc0892e513ec124de76ee0727092b4517_39497_9b9c75e6329c7bc3212718841e2422bf.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/03-02-system3-1-768x275_huc0892e513ec124de76ee0727092b4517_39497_0d15dddebfbbf07986da7a356bac99c3.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/03-02-system3-1-768x275_huc0892e513ec124de76ee0727092b4517_39497_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/03-02-system3-1-768x275_huc0892e513ec124de76ee0727092b4517_39497_9b9c75e6329c7bc3212718841e2422bf.webp&#34;
               width=&#34;760&#34;
               height=&#34;272&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第一个参数&lt;code&gt;which&lt;/code&gt;是一个整数，它始终与名称中的数字相同（在本例中为3）。&lt;/p&gt;
&lt;p&gt;第二个参数&lt;code&gt;varargs&lt;/code&gt;是要使用的参数。它被称为 &lt;code&gt;varargs&lt;/code&gt; 时因为可以有可变数量的参数。但是WebAssembly没有提供将可变数量的参数传递给函数的方法。相反，参数通过线性内存传递。这不是类型安全的，并且比使用寄存器传递参数的速度慢。&lt;/p&gt;
&lt;p&gt;这对于在浏览器中运行的Emscripten来说没问题。但是现在运行时将它视为事实上的标准，实现了自己的JS胶水代码版本。他们正在模拟POSIX仿真层的内部细节。&lt;/p&gt;
&lt;p&gt;这意味着它们正在重新实现选择，基于Emscripten约束（比如在堆值中传递参数）这些选择时有意义的，即使这些约束不适用于它们的环境。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/03-03-emulation-1-768x524_hu0b917799fc171e237a7c46c128be676a_103892_1afc685d51253573f73129589a5d4e6d.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/03-03-emulation-1-768x524_hu0b917799fc171e237a7c46c128be676a_103892_0b8c55d8ce535dc595b26626529e9b70.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/03-03-emulation-1-768x524_hu0b917799fc171e237a7c46c128be676a_103892_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/03-03-emulation-1-768x524_hu0b917799fc171e237a7c46c128be676a_103892_1afc685d51253573f73129589a5d4e6d.webp&#34;
               width=&#34;760&#34;
               height=&#34;519&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如果我们要构建一个持续数十年的WebAssembly生态系统，我们需要坚实的基础。这意味着我们的事实标准不能是模拟器的模拟器。&lt;/p&gt;
&lt;p&gt;但是我们应该采用什么原则？&lt;/p&gt;
&lt;h3 id=&#34;webassembly系统接口需要遵循什么原则&#34;&gt;WebAssembly系统接口需要遵循什么原则？&lt;/h3&gt;
&lt;p&gt;WebAssembly中有两个重要的原则：&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;/p&gt;
&lt;p&gt;实际上，POSIX和Unix的访问控制安全方法并没有让我们打到目的。让我们来看看它们的不足之处。&lt;/p&gt;
&lt;h4 id=&#34;可移植性&#34;&gt;可移植性&lt;/h4&gt;
&lt;p&gt;POSIX提供源代码可移植性。可以使用不同版本的libc编译相同的源代码以定位不同的计算机。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-01-portability-1-768x576_hu7a4d456b0b41bee6ccc4a61de7a9001d_90608_cd7a93ec04b5bb266574a02f5241c0ad.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-01-portability-1-768x576_hu7a4d456b0b41bee6ccc4a61de7a9001d_90608_f37e6f683b7d0ef998917cbc75951d08.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-01-portability-1-768x576_hu7a4d456b0b41bee6ccc4a61de7a9001d_90608_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-01-portability-1-768x576_hu7a4d456b0b41bee6ccc4a61de7a9001d_90608_cd7a93ec04b5bb266574a02f5241c0ad.webp&#34;
               width=&#34;760&#34;
               height=&#34;570&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;但WebAssembly需要超越这一点。我们需要能够一次编译并运行在一大堆不同的机器。我们需要可移植性二进制文件。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-02-portability-1-768x743_huee3af706b33cf62d5fa950ff95b8cc40_89702_75e14c2f3d89ba47dded46f9da2a6ae6.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-02-portability-1-768x743_huee3af706b33cf62d5fa950ff95b8cc40_89702_b2b84c4b70c6bb76afcc6b121177b338.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-02-portability-1-768x743_huee3af706b33cf62d5fa950ff95b8cc40_89702_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-02-portability-1-768x743_huee3af706b33cf62d5fa950ff95b8cc40_89702_75e14c2f3d89ba47dded46f9da2a6ae6.webp&#34;
               width=&#34;760&#34;
               height=&#34;735&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这种可移植性使得向用户分发代码变得更加容易。&lt;/p&gt;
&lt;p&gt;例如，如果Node的原生模块是用WebAssembly编写的，那么当用户使用原生模块安装应用程序时，用户就不需要运行node-gyp，开发人员也不需要配置和分发数十个二进制文件。&lt;/p&gt;
&lt;h4 id=&#34;安全&#34;&gt;安全&lt;/h4&gt;
&lt;p&gt;当一行代码要求操作系统执行某些输入或输出时，操作系统需要确定执行代码所要求的操作是否安全。&lt;/p&gt;
&lt;p&gt;操作系统通常使用基于所有权和组的访问控制来处理此问题。&lt;/p&gt;
&lt;p&gt;例如，程序可能会要求操作系统打开文件。用户拥有有权访问的特定文件集。&lt;/p&gt;
&lt;p&gt;当用户启动程序时，程序代表该用户运行。如果用户有权访问该文件 - 要么是因为他们是所有者，要么是因为他们在具有访问权限的组中 - 那么该程序也具有相同的访问权限。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-03-access-control-1-768x344_hu743a5fd43f2a25dd9a10b4805e19474d_59064_ba4c1ea32e2fe3c39c8796515c0541ab.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-03-access-control-1-768x344_hu743a5fd43f2a25dd9a10b4805e19474d_59064_9fb1938f6156062da840d1ac01f1bfa7.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-03-access-control-1-768x344_hu743a5fd43f2a25dd9a10b4805e19474d_59064_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-03-access-control-1-768x344_hu743a5fd43f2a25dd9a10b4805e19474d_59064_ba4c1ea32e2fe3c39c8796515c0541ab.webp&#34;
               width=&#34;760&#34;
               height=&#34;340&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这可以保护用户彼此。在开发早期操作系统时，这很有意义。系统通常是多用户，管理员控制安装的软件。所以最突出的威胁是其他用户浏览你的文件。&lt;/p&gt;
&lt;p&gt;那已经改变了。系统现在通常是单用户，但它们运行的代码会引入许多未知可信度的其他第三方代码。现在最大的威胁是你自己运行的代码会针对你。&lt;/p&gt;
&lt;p&gt;例如，假设您在应用程序中使用的库有了新的维护者（通常在开源中发生）。那个维护者可能会把你的兴趣放在心上&amp;hellip;&amp;hellip;或者他们可能是坏人之一。如果他们有权在你的系统上做任何事情 - 例如，打开你的文件并通过网络发送它们 - 那么他们的代码就会造成很大的破坏。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-04-bitcoin-1-768x396_hub822075f2cb012774850eceb05cc108b_76014_20458851e614245673675624a0d94eac.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-04-bitcoin-1-768x396_hub822075f2cb012774850eceb05cc108b_76014_825754cf44a24102919841299171d621.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-04-bitcoin-1-768x396_hub822075f2cb012774850eceb05cc108b_76014_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-04-bitcoin-1-768x396_hub822075f2cb012774850eceb05cc108b_76014_20458851e614245673675624a0d94eac.webp&#34;
               width=&#34;760&#34;
               height=&#34;392&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这就是为什么使用可以直接与系统通信的第三方库可能是危险的。&lt;/p&gt;
&lt;p&gt;WebAssembly的安全方式有所不同。WebAssembly是沙箱。&lt;/p&gt;
&lt;p&gt;这意味着代码无法直接与操作系统通信。但那么它如何操作系统资源呢？主机（可能是浏览器，或者可能是wasm运行时）将函数放在代码可以使用的沙箱中。&lt;/p&gt;
&lt;p&gt;这意味着主机可以限制程序可执行的操作，基于编程的基础上。它不是简单让程序代表用户行事，从而使用用户的完全权限来调用任何系统调用。&lt;/p&gt;
&lt;p&gt;仅仅拥有沙盒机制并不会使系统本身安全 - 主机仍然可以将所有功能都放入沙箱中，在这种情况下我们也不会更好 - 但它至少让主机可以有机会创建一个更安全的系统。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-05-sandbox-1-768x427_hu7bd1183457403eeb2222df51ecfb7313_87515_c9b9f04d98a5cec060a4334c7bc566a6.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-05-sandbox-1-768x427_hu7bd1183457403eeb2222df51ecfb7313_87515_94eb609d9cfae726e040d8a8e0ecfb24.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-05-sandbox-1-768x427_hu7bd1183457403eeb2222df51ecfb7313_87515_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/04-05-sandbox-1-768x427_hu7bd1183457403eeb2222df51ecfb7313_87515_c9b9f04d98a5cec060a4334c7bc566a6.webp&#34;
               width=&#34;760&#34;
               height=&#34;423&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在我们设计的任何系统接口中，我们都需要坚持这两个原则。可移植性使得开发和分发软件变得更加容易，并且为主机提供保护自己或用户的工具是绝对必要的。&lt;/p&gt;
&lt;h3 id=&#34;这个系统界面应该是什么样的&#34;&gt;这个系统界面应该是什么样的？&lt;/h3&gt;
&lt;p&gt;鉴于这两个关键原则，WebAssembly系统接口的设计应该是什么样子？&lt;/p&gt;
&lt;p&gt;这就是我们在标准化过程中将要实现的。不过，我们确实有一个建议作为出发点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;创建一组模块化标准接口集合&lt;/li&gt;
&lt;li&gt;首先标准化最基本的模块，wasi-core&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-01-wasi-1-768x644_huf7b8ce225c3dbbcbc0935240b349e4b4_80938_8276c5585ff3a09a2c6f2d128881a190.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-01-wasi-1-768x644_huf7b8ce225c3dbbcbc0935240b349e4b4_80938_24774a98663881bcc97bac52143eea02.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-01-wasi-1-768x644_huf7b8ce225c3dbbcbc0935240b349e4b4_80938_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-01-wasi-1-768x644_huf7b8ce225c3dbbcbc0935240b349e4b4_80938_8276c5585ff3a09a2c6f2d128881a190.webp&#34;
               width=&#34;760&#34;
               height=&#34;637&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;哪些将在wasi-core中？&lt;/p&gt;
&lt;p&gt;wasi-core将包含所有程序需要的基础。它将覆盖与POSIX相同的基础内容，包括文件，网络连接，时钟和随机数等内容。&lt;/p&gt;
&lt;p&gt;对于这样场景，它将采用与POSIX非常类似的方法。例如，它将使用POSIX的面向文件的方法，在这种方法中，您可以进行系统调用，例如打开，关闭，读取和写入，其他一切基本上都是在顶部提供扩充。&lt;/p&gt;
&lt;p&gt;但是，wasi-core不会涵盖POSIX所做的一切。例如，流程概念没有清晰地映射到WebAssembly上。除此之外，每个WebAssembly引擎都需要支持像 &lt;code&gt;fork&lt;/code&gt; 这样的流程操作是没有意义的。但我们也希望能够实现标准化&lt;code&gt;fork&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这就是模块化策略的用武之地。这样，我们可以获得良好的标准化覆盖率，同时仍然允许平台仅使用对它们有意义的部分WASI。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-02-wasi-1-768x385_hu4700a33845ea99e8f4e8b2b5a05559b4_66560_44d5190177d1843ba4773a4be8471318.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-02-wasi-1-768x385_hu4700a33845ea99e8f4e8b2b5a05559b4_66560_4da729f45244f33399f43077dc875c34.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-02-wasi-1-768x385_hu4700a33845ea99e8f4e8b2b5a05559b4_66560_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-02-wasi-1-768x385_hu4700a33845ea99e8f4e8b2b5a05559b4_66560_44d5190177d1843ba4773a4be8471318.webp&#34;
               width=&#34;760&#34;
               height=&#34;381&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;像Rust这样的语言将直接在标准库中使用wasi-core。例如，Rust 的 &lt;code&gt;open&lt;/code&gt; 在编译为WebAssembly时是通过调用 &lt;code&gt;__wasi_path_open&lt;/code&gt; 来实现的。&lt;/p&gt;
&lt;p&gt;对于C和C ++，我们创建了 &lt;a href=&#34;https://github.com/CraneStation/wasi-sysroot&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;wasi-sysroot&lt;/a&gt;，为wasi-core函数实现libc。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-03-open-imps-1-768x352_hu2c52788c3ac6b55e6a9411ef87e29676_50932_f95b0bc4cc802a56ca4d448dabee2958.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-03-open-imps-1-768x352_hu2c52788c3ac6b55e6a9411ef87e29676_50932_7e08ff6b5082ab0716a265e8d2174866.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-03-open-imps-1-768x352_hu2c52788c3ac6b55e6a9411ef87e29676_50932_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-03-open-imps-1-768x352_hu2c52788c3ac6b55e6a9411ef87e29676_50932_f95b0bc4cc802a56ca4d448dabee2958.webp&#34;
               width=&#34;760&#34;
               height=&#34;348&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们希望像Clang这样的编译器能够与WASI API进行交互，并像Rust编译器和Emscripten那样完成工具链，将WASI作为系统实现的一部分来使用。&lt;/p&gt;
&lt;p&gt;用户代码如何调用这些WASI函数？&lt;/p&gt;
&lt;p&gt;运行代码的运行时将wasi-core函数作为 import 传递进来。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-04-imports-1-768x438_hud1e3e7ad384c1f7690a86d0321914c31_83614_ba75683067318aa8554e7d4683961f0b.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-04-imports-1-768x438_hud1e3e7ad384c1f7690a86d0321914c31_83614_76eda84441a764bbea42b544494843d4.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-04-imports-1-768x438_hud1e3e7ad384c1f7690a86d0321914c31_83614_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-04-imports-1-768x438_hud1e3e7ad384c1f7690a86d0321914c31_83614_ba75683067318aa8554e7d4683961f0b.webp&#34;
               width=&#34;760&#34;
               height=&#34;433&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这为我们提供了可移植性，因为每个主机都可以拥有自己的专为其平台编写的wasi-core实现 - 从WebAssembly运行时，如Mozilla的wasmtime和Fastly的Lucet，到Node，甚至是浏览器。&lt;/p&gt;
&lt;p&gt;它还为我们提供了沙盒，因为主机可以逐个程序地选择传入哪些 wasi-core 函数 - 这样决定了允许哪些系统调用。这保留了安全性。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-05-sec-port-2-768x1082_hucb8f9409bf7afca49c1c2b85ada8c2fb_193804_cc769a98b4c8b90ef78e1ec5bc3d3881.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-05-sec-port-2-768x1082_hucb8f9409bf7afca49c1c2b85ada8c2fb_193804_fe1983bafd484a32dd801e1ee17b06bb.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-05-sec-port-2-768x1082_hucb8f9409bf7afca49c1c2b85ada8c2fb_193804_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-05-sec-port-2-768x1082_hucb8f9409bf7afca49c1c2b85ada8c2fb_193804_cc769a98b4c8b90ef78e1ec5bc3d3881.webp&#34;
               width=&#34;539&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;WASI为我们提供了进一步扩展安全性的方法。它从基于功能的安全性中引入了更多概念。&lt;/p&gt;
&lt;p&gt;传统上，如果代码需要打开文件，它会带路径名字符串调用 &lt;code&gt;open&lt;/code&gt;。然后操作系统检查代码是否具有权限（基于启动程序的用户）。&lt;/p&gt;
&lt;p&gt;使用WASI，如果您正在调用需要访问文件的函数，则必须传入一个附加了权限的文件描述符。这可以是文件本身，也可以是包含该文件的目录。&lt;/p&gt;
&lt;p&gt;这样，您就无法拥有随机要求打开的代码&lt;code&gt;/etc/passwd&lt;/code&gt;。相反，代码只能操作传递给它的目录。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-06-openat-path-1-768x296_hucef58cabe691309d5df4445a079b35af_74287_a11d9548e60ba3b70df1ae08a145c727.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-06-openat-path-1-768x296_hucef58cabe691309d5df4445a079b35af_74287_f721e8ef948adde7d49205303d844f24.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-06-openat-path-1-768x296_hucef58cabe691309d5df4445a079b35af_74287_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-06-openat-path-1-768x296_hucef58cabe691309d5df4445a079b35af_74287_a11d9548e60ba3b70df1ae08a145c727.webp&#34;
               width=&#34;760&#34;
               height=&#34;293&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这使得可以安全地为沙盒代码提供对不同系统调用的更多访问 - 因为这些系统调用的功能可能受到限制。&lt;/p&gt;
&lt;p&gt;这是在逐个模块的基础上发生的。默认情况下，模块没有对文件描述符的任何访问权限。但是，如果一个模块中的代码具有文件描述符，则可以选择将该文件描述符传递给它在其他模块中调用的函数。或者它可以创建更多有限版本的文件描述符以传递给其他函数。&lt;/p&gt;
&lt;p&gt;因此，运行时传递应用程序可以使用的文件描述符到顶级代码，然后文件描述符根据需要传播到系统的其余部分。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-07-file-perms-1-768x649_hu9995474518a8cb38aead9f7dbb8d0230_127252_40782d2fbcfc189312ad0e261313b257.webp 400w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-07-file-perms-1-768x649_hu9995474518a8cb38aead9f7dbb8d0230_127252_c04022051581dec1367d07a732f955d3.webp 760w,
               /post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-07-file-perms-1-768x649_hu9995474518a8cb38aead9f7dbb8d0230_127252_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201908-standardizing-wasi-a-webassembly-system-interface/images/05-07-file-perms-1-768x649_hu9995474518a8cb38aead9f7dbb8d0230_127252_40782d2fbcfc189312ad0e261313b257.webp&#34;
               width=&#34;760&#34;
               height=&#34;642&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这使WebAssembly更接近最小权限原则，模块只能访问完成其工作所需的确切资源。&lt;/p&gt;
&lt;p&gt;这些概念来自面向功能的系统，如CloudABI和Capsicum。面向功能的系统的一个问题是通常很难将代码移植到它们。但我们认为这个问题可以解决。&lt;/p&gt;
&lt;p&gt;如果代码已经用相对文件路径来使用 &lt;code&gt;openat&lt;/code&gt;，那么代码就可以编译了。&lt;/p&gt;
&lt;p&gt;如果代码使用&lt;code&gt;open&lt;/code&gt;，而且迁移到&lt;code&gt;openat&lt;/code&gt;样式有太多的前期投资，WASI可以提供增量解决方案。使用&lt;a href=&#34;https://github.com/musec/libpreopen&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;libpreopen&lt;/a&gt;，您可以创建应用程序合法需要访问的文件路径列表。然后你可以使用&lt;code&gt;open&lt;/code&gt;，但只能使用这些路径。&lt;/p&gt;
&lt;h3 id=&#34;下一步&#34;&gt;下一步&lt;/h3&gt;
&lt;p&gt;我们认为wasi-core是一个良好的开端。它保留了WebAssembly的可移植性和安全性，为生态系统提供了坚实的基础。&lt;/p&gt;
&lt;p&gt;但是，在完全标准化之后，我们还需要解决一些问题。这些问题包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;异步I/O.&lt;/li&gt;
&lt;li&gt;文件监听&lt;/li&gt;
&lt;li&gt;文件锁定&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这只是一个开始，所以如果您有如何解决这些问题的想法，请&lt;a href=&#34;https://wasi.dev/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;加入我们&lt;/a&gt;！&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Service Mesh发展趋势(续)：棋到中盘路往何方</title>
      <link>https://skyao.net/talk/201908-servicemesh-development-trend2/</link>
      <pubDate>Tue, 27 Aug 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/201908-servicemesh-development-trend2/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;本文内容整理自8月10日在 ServiceMesh Meetup 广州站发表的主题演讲。标题“Service Mesh发展趋势(续)”中的“续”是指在今年5月底，我在 CloudNative Meetup上做了一个“&lt;a href=&#34;../201905-servicemesh-development-trend/&#34;&gt;ServiceMesh发展趋势：云原生中流砥柱&lt;/a&gt;”的演讲，当时主要讲了三块内容：Service Mesh产品动态，发展趋势，与云原生的关系。后来有同学反应希望部分感兴趣的内容能讲的更深一些，所以今天将继续“ServiceMesh发展趋势”这个话题。&lt;/p&gt;
&lt;p&gt;今天给大家分享的内容有部分是上次演讲内容的深度展开，如社区关心的Mixer v2；以及最近看到的一些业界新的技术方向，如web assembly技术，还有产品形态上的创新，如google traffic director对servicemesh的虚拟机形态的创新支持。&lt;/p&gt;
&lt;p&gt;在ServiceMesh出道四年之际，也希望和大家一起带着问题来对ServiceMesh未来的发展进行一些深度思考。&lt;/p&gt;
&lt;p&gt;在正式开始分享之前，让我们先轻松一下，下面是最近流行的梗，各种灵魂拷问：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/questions_huf423fcf2162f881c92199ce0965d0bbe_121180_b6e1d98b747f9a369803988641f691bf.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/questions_huf423fcf2162f881c92199ce0965d0bbe_121180_182dcd94b668ae7bbba20428b57b78ec.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/questions_huf423fcf2162f881c92199ce0965d0bbe_121180_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/questions_huf423fcf2162f881c92199ce0965d0bbe_121180_b6e1d98b747f9a369803988641f691bf.webp&#34;
               width=&#34;760&#34;
               height=&#34;326&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而我们今天的分享内容，将效仿上面的方式，对 ServicMesh 进行四个深入灵魂的拷问。&lt;/p&gt;
&lt;h2 id=&#34;servicemesh灵魂拷问一要架构还是要性能&#34;&gt;ServiceMesh灵魂拷问一：要架构还是要性能？&lt;/h2&gt;
&lt;p&gt;第一个灵魂拷问针对 Istio 的：要架构还是要性能？&lt;/p&gt;
&lt;h3 id=&#34;istio的回答要架构&#34;&gt;Istio的回答：要架构&lt;/h3&gt;
&lt;p&gt;Istio的回答很明确：架构优先，性能靠边。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/istio-answer-1_hub8ddf3c150219d3d3d51083c01838d99_215878_be1f17ba0a92a8950b51966b97ac439a.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/istio-answer-1_hub8ddf3c150219d3d3d51083c01838d99_215878_61937369203175044368c2e5e378fdba.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/istio-answer-1_hub8ddf3c150219d3d3d51083c01838d99_215878_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/istio-answer-1_hub8ddf3c150219d3d3d51083c01838d99_215878_be1f17ba0a92a8950b51966b97ac439a.webp&#34;
               width=&#34;760&#34;
               height=&#34;341&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;左边是 Istio 的架构图，从2017年的 0.1 版本开始，一直到 Istio1.0，控制平面和数据平面完全物理分离，包括我们今天要关注的Mixer模块。Sidecar 通过和 Mixer 的交互实现策略检查和遥测报告。&lt;/p&gt;
&lt;p&gt;右边是 Mixer 的架构图，在 Mixer 内部提供了很多 Adapter 实现，用来提供各种功能。这些 Adapter 运行在 Mixer 进程中，因此被称为进程内适配器（In-Process Adapter）。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;为什么Istio选择Mixer和Proxy分离的架构？&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;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/istio-reason-1_hub75f6e4e2c7c0a602caefa88a7f627b0_207763_b6c25567a5911112df61e838db3bcad3.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/istio-reason-1_hub75f6e4e2c7c0a602caefa88a7f627b0_207763_6e2115175d2618feaadf90eebb9efd40.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/istio-reason-1_hub75f6e4e2c7c0a602caefa88a7f627b0_207763_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/istio-reason-1_hub75f6e4e2c7c0a602caefa88a7f627b0_207763_b6c25567a5911112df61e838db3bcad3.webp&#34;
               width=&#34;760&#34;
               height=&#34;403&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;特别指出，上图右侧的红色竖线，是Istio 0.1 到 Istio 1.0 版本中 Istio 和后台基础设施的边界。这意味着，从k8s API Server 中读取 Adapter 相关的配置信息 （以 Istio CRD 的形式存在），是作为 Istio 功能的一部分。&lt;/p&gt;
&lt;p&gt;具体的优点是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Mixer的变动不影响Sidecar：包括Mixer的部署调整和版本升级&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Sidecar无需和Adapter耦合，具体有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sidecar不需要读取配置，因此也无需直接连接到 k8s AP Server/Istio Galley&lt;/li&gt;
&lt;li&gt;Adapter的运行时资源开销和Sidecar无关&lt;/li&gt;
&lt;li&gt;Sidecar不受Adapter增减/更新/升级影响&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;保持 Sidecar 代码简单：数以几十计的Adapter的代码无需直接进入Sidecar代码&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;数据平面可替换原则：如果有替换数据平面的需求，则Mixer分离的架构会让事情简单很多&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;至于缺点，只有一个：&lt;strong&gt;性能不好&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;而1.1版本之后，Istio 给出了新的回答：架构继续优先，性能继续靠边：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/istio-answer-2_huf6c9a9758277ff04ecd39395d01a1ed2_211347_2453dadb4b1a90b04797858568f771cc.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/istio-answer-2_huf6c9a9758277ff04ecd39395d01a1ed2_211347_26c56e65a1cb1beaa3868373771be0f6.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/istio-answer-2_huf6c9a9758277ff04ecd39395d01a1ed2_211347_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/istio-answer-2_huf6c9a9758277ff04ecd39395d01a1ed2_211347_2453dadb4b1a90b04797858568f771cc.webp&#34;
               width=&#34;760&#34;
               height=&#34;295&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;上图是Istio1.1版本之后新的架构图，和之前的差异在于Mixer发生了变化，增加了进程外适配器（Out-of-Process Adapter），而Mixer和新的Out-of-Process Adapter之前依然是远程调用。&lt;/p&gt;
&lt;p&gt;为什么 Istio 改而选择 Out-of-Process Adapter?&lt;/p&gt;
&lt;p&gt;下图是采用 Out-of-Process Adapter 之后的请求处理流程图，Mixer 通过 Bypass Adapter 选择需要的属性列表，然后通过远程调用发送给 Out-of-Process Adapter。Out-of-Process Adapter 实现和之前的 In-Process Adapter 类似的功能，但是改为独立于 Mixer 的单独进程。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/istio-reason-2_hu56437bb3b0130f215f72171b95a25ce3_147509_d2ffa9781480416c27e576af58bc14f9.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/istio-reason-2_hu56437bb3b0130f215f72171b95a25ce3_147509_21ed7d1b0431c58b62f4732af43f4e06.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/istio-reason-2_hu56437bb3b0130f215f72171b95a25ce3_147509_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/istio-reason-2_hu56437bb3b0130f215f72171b95a25ce3_147509_d2ffa9781480416c27e576af58bc14f9.webp&#34;
               width=&#34;760&#34;
               height=&#34;180&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;采用 Out-of-Process Adapter 之后，Istio的优点更加明显了，简单说就是：架构更优雅，职责更分明，边界更清晰。&lt;/p&gt;
&lt;p&gt;而且，请注意：按照 Istio 的设想，此时 Out-of-Process Adapter 已经不再作为 Istio 的组成部分，它的代码实现、安装部署、配置、维护等职责也不再由 Istio 承担，请留意上图中的红色竖线位置。Out-of-Process Adapter 的引入，对于 Istio 来说职责和边界的改变会让 Istio 简单，但是对于使用者（主要指运维）来说则增加了额外的负担，因此造成了很大的争议。&lt;/p&gt;
&lt;p&gt;至于缺点，除了上述的职责转移造成争议外，依然只有一个：&lt;strong&gt;性能不好&lt;/strong&gt;，原来 Sidecar 和 Mixer 之间的远程调用已经让性能变得非常糟糕，现在 Mixer 和 Out-of-Process Adapter 之间再增多加一次远程调用，可谓雪上加霜。&lt;/p&gt;
&lt;h3 id=&#34;mixer-v1-架构的优缺点分析&#34;&gt;Mixer v1 架构的优缺点分析&lt;/h3&gt;
&lt;p&gt;Mixer v1 架构的优点主要体现为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;集中式服务：提高基础设施后端的可用性，为前置条件检查结果提供集群级别的全局2级缓存&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;灵活的适配器模型，使其以下操作变得简单：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;运维添加、使用和删除适配器&lt;/li&gt;
&lt;li&gt;开发人员创建新的适配器（超过20个适配器）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;而 Mixer v1 架构的缺点，则主要体现为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;管理开销&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;管理Mixer是许多客户不想负担的&lt;/li&gt;
&lt;li&gt;而进程外适配器强制运维管理适配器，让这个负担更加重。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性能&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;即使使用缓存，在数据路径中同步调用Mixer也会增加端到端延迟&lt;/li&gt;
&lt;li&gt;进程外适配器进一步增加了延迟&lt;/li&gt;
&lt;li&gt;授权和认证功能是天然适合mixer pipeline的，但是由于mixer 设计的延迟和SPOF（单点故障）特性，导致直接在Envoy中实现(Envoy SDS)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;复杂性&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mixer使用一组称为模板的核心抽象，来描述传递给适配器的数据。这些包括“metrics”，“logentry”，“tracepan”等。这些抽象与后端想要消费的数据不匹配，导致运维需要编写一些手动配置，以便在规范的 Istio 样式和后端特定的样式之间进行映射。原本期望这种映射可以在适配器中实现很大程度上的自动化，但是最终还是太复杂并需要手动配置。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：上述优点和缺点的描述摘录自 mixer v2 proposal 。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;其中，Mixer 性能问题一直以来都是 Istio 最被人诟病的地方。&lt;/p&gt;
&lt;p&gt;那问题来了：如果要性能，该怎么做？&lt;/p&gt;
&lt;p&gt;下图是 Mixer v1 的调用流程，Proxy/Sidecar 是请求数据的起点，Infrastructure Backend 是终点。Mixer v1性能不好的原因是多了 Mixer 的一次远程访问，而 Out-of-Process Adapter 因为又额外引入了一次远程调用，导致性能更加糟糕：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/mixer-v1-flow_hud841f73420d1c3282297a8bc6387c759_146728_82630a9a3f8f52a97df781a99c5a0df7.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/mixer-v1-flow_hud841f73420d1c3282297a8bc6387c759_146728_a6de1916d1e304a0297f48935d9c65ae.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/mixer-v1-flow_hud841f73420d1c3282297a8bc6387c759_146728_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/mixer-v1-flow_hud841f73420d1c3282297a8bc6387c759_146728_82630a9a3f8f52a97df781a99c5a0df7.webp&#34;
               width=&#34;760&#34;
               height=&#34;198&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;因此，要彻底解决远程调用引入太多而造成的性能问题，答案很明显：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-flow_hueb874a06466f4660e42a4b14056cfb11_49948_064ddc469030f32a8bb3b56d353be3dd.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-flow_hueb874a06466f4660e42a4b14056cfb11_49948_56411bd7e18e7be8a98eab1869cfe5ac.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-flow_hueb874a06466f4660e42a4b14056cfb11_49948_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/mixer-v2-flow_hueb874a06466f4660e42a4b14056cfb11_49948_064ddc469030f32a8bb3b56d353be3dd.webp&#34;
               width=&#34;760&#34;
               height=&#34;85&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;将 Mixer 的功能内置到 Sidecar 中，使用  In-Process Adapter ，直接连接 Sidecar 和 Infrastructure Backend。&lt;/p&gt;
&lt;h3 id=&#34;mixer-v2&#34;&gt;Mixer v2&lt;/h3&gt;
&lt;p&gt;Mixer 带来的性能问题，以及 Mixer Cache 的失效，导致为了得到一个可用的性能，必须合并 Mixer 到 Sidecar。关于这个论断和行动，蚂蚁先行一步，在去年我的演讲&amp;quot;&lt;a href=&#34;../201810-ant-finance-service-mesh-practice/&#34;&gt;大规模微服务架构下的Service Mesh探索之路&lt;/a&gt;&amp;quot; (演讲时间：2018-06-30)中就介绍了蚂蚁的ServiceMesh方案，其中和Istio最大的变化就是合并Mixer：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/ant-financial_hu54583231e2e725167f5b767a13b90b5d_479309_3491439fadacdb49bece4972b073d98d.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/ant-financial_hu54583231e2e725167f5b767a13b90b5d_479309_433bb292fc6bcf79d3f966bc7c3f22f7.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/ant-financial_hu54583231e2e725167f5b767a13b90b5d_479309_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/ant-financial_hu54583231e2e725167f5b767a13b90b5d_479309_3491439fadacdb49bece4972b073d98d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而在 2018年底，Istio社区终于提出了 Mixer v2 的 Proposal：Mixer V2 Architecture。&lt;/p&gt;
&lt;p&gt;具体内容请见地址：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.google.com/document/d/1QKmtem5jU_2F3Lh5SqLp0IuPb80_70J7aJEYu4_gS-s/edit#heading=h.hvvcgepdykro&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://docs.google.com/document/d/1QKmtem5jU_2F3Lh5SqLp0IuPb80_70J7aJEYu4_gS-s/edit#heading=h.hvvcgepdykro&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;也可以看我之前对这个内容的摘要翻译：https://skyao.net/learning-istio/mixer/design/v2.html&lt;/p&gt;
&lt;p&gt;下图是这个 Mixer V2 Architecture 的信息摘要，当前状态为 In Review，创建时间为 2018年12月18，迄今八个月：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-proposal-summary_hu7de50cee713b4e2772a37a6a59deb953_56395_5cd00352cb091739cd60f6f7f5e12c31.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-proposal-summary_hu7de50cee713b4e2772a37a6a59deb953_56395_4bc47074183f7247a1bc637cc856612f.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-proposal-summary_hu7de50cee713b4e2772a37a6a59deb953_56395_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/mixer-v2-proposal-summary_hu7de50cee713b4e2772a37a6a59deb953_56395_5cd00352cb091739cd60f6f7f5e12c31.webp&#34;
               width=&#34;760&#34;
               height=&#34;134&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Mixer v2 Proposal 的内容比较多，我们忽略各种细节，只看最核心的内容：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Mixer-In-Proxy&lt;/strong&gt;. Mixer will be rewritten in C++ and directly embedded in Envoy. There will no longer be any stand-alone Mixer service. This will improve performance and reduce operational complexity.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mixer合并进Proxy&lt;/strong&gt;。 Mixer 将用C++重写并直接嵌入到Envoy。 将不再有任何独立的 Mixer 服务。 这将提高性能并降低运维复杂性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Mixer v2 的架构图如下：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-overview_huddbefd20e65fa66010c1bd2a85d81485_113859_2b20494f15c1934a181c22989c4323cf.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-overview_huddbefd20e65fa66010c1bd2a85d81485_113859_862b5226d60802613a0ee6c462b94c98.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-overview_huddbefd20e65fa66010c1bd2a85d81485_113859_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/mixer-v2-overview_huddbefd20e65fa66010c1bd2a85d81485_113859_2b20494f15c1934a181c22989c4323cf.webp&#34;
               width=&#34;760&#34;
               height=&#34;412&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;servicemesh灵魂拷问二性能有了架构怎么办&#34;&gt;ServiceMesh灵魂拷问二：性能有了，架构怎么办？&lt;/h2&gt;
&lt;p&gt;Mixer合并到Sidecar之后，性能有了，架构怎么办？这是我们今天的第二个灵魂拷问。&lt;/p&gt;
&lt;p&gt;之所以提出这个问题，在于我们前面列出的mixer v1的各种优点，在将mixer简单合并到sidecar之后，这些原来的优点就会摇身一变成为新方式下的缺点，而这是比较难接受的。从这个角度说，Istio 选择 mixer v1 的架构也不是完全没有理由，只是性能上付出的代价过于高昂无法接受。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mixer v1的优点不应该成为Mixer v2的缺点&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这是我们对于将 Mixer 合并到 Sidecar 的要求，最起码，不要全部优点都成为缺点。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;合并没问题，如何合并才是问题！&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&#34;envoy的可扩展设计&#34;&gt;envoy的可扩展设计&lt;/h3&gt;
&lt;p&gt;Envoy在设计上是可扩展的，设计有大量的扩展点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;L4/L7 filters&lt;/li&gt;
&lt;li&gt;Access loggers&lt;/li&gt;
&lt;li&gt;Tracers&lt;/li&gt;
&lt;li&gt;Health checkers&lt;/li&gt;
&lt;li&gt;Transport sockets&lt;/li&gt;
&lt;li&gt;Retry policy&lt;/li&gt;
&lt;li&gt;Resource monitors&lt;/li&gt;
&lt;li&gt;Stats sink&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而 Envoy 的扩展方式也有三种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;C++：直接编码&lt;/li&gt;
&lt;li&gt;Lua：目前仅限于HTTP Traffic&lt;/li&gt;
&lt;li&gt;Go extensions：beta, 用于 Cilium&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;但是这三种扩展方式对于mixer 来说都并不理想，Lua 和 Go extension 不适用于 Mixer，而c++直接编码方式则就会真的让之前的所有优点直接变成缺点。&lt;/p&gt;
&lt;p&gt;Envoy 最新尝试的新扩展方式 Web Assembly，则成为我们今天的希望所在：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/envpy-and-wasm_hu3bfae6f6cdb0469af301d94fd999e0ed_17559_93518c8dd74815c08c8730004408205d.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/envpy-and-wasm_hu3bfae6f6cdb0469af301d94fd999e0ed_17559_b467ab48b17d81cd9985bae4b1d2b7c1.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/envpy-and-wasm_hu3bfae6f6cdb0469af301d94fd999e0ed_17559_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/envpy-and-wasm_hu3bfae6f6cdb0469af301d94fd999e0ed_17559_93518c8dd74815c08c8730004408205d.webp&#34;
               width=&#34;375&#34;
               height=&#34;133&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最近 Envoy 在开始提供WASM的支持，具体可以看 &lt;a href=&#34;https://github.com/envoyproxy/envoy/issues/4272&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Support WebAssembly (WASM) in Envoy&lt;/a&gt; 这个 issue 的描述，目前从 github 的 milestone 中看到 Envoy 计划在1.12版本提供对 WASM 的支持（Envoy 1.11版本发布于7月12日）。&lt;/p&gt;
&lt;p&gt;还有一个 &lt;a href=&#34;https://github.com/envoyproxy/envoy-wasm&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;envoy-wasm项目&lt;/a&gt;，定位为&amp;quot;Playground for Envoy WASM filter&amp;quot;。&lt;/p&gt;
&lt;h3 id=&#34;wasm简单介绍&#34;&gt;WASM简单介绍&lt;/h3&gt;
&lt;p&gt;这里对 Web Assembly 做一个简单介绍，首先看来自 Mozilla 的官方定义：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;WebAssembly是一种新的编码方式，可以在现代的网络浏览器中运行 － 它是一种低级的类汇编语言，具有紧凑的二进制格式，可以接近原生的性能运行，并为诸如C / C ++等语言提供一个编译目标，以便它们可以在Web上运行。它也被设计为可以与JavaScript共存，允许两者一起工作。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;更通俗的理解是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;WebAssembly不是一门编程语言，而是一份字节码标准。WebAssembly字节码是一种抹平了不同CPU架构的机器码，WebAssembly字节码不能直接在任何一种CPU架构上运行，但由于非常接近机器码，可以非常快的被翻译为对应架构的机器码，因此WebAssembly运行速度和机器码接近。（类比Java bytecode）&lt;/p&gt;
&lt;p&gt;备注：摘录自 &lt;a href=&#34;http://blog.enixjin.net/webassembly-introduction/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;http://blog.enixjin.net/webassembly-introduction/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;而使用 Web Assembly 扩展 Envoy 的好处是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;避免修改Envoy&lt;/li&gt;
&lt;li&gt;避免网络远程调用（check &amp;amp; report）&lt;/li&gt;
&lt;li&gt;通过动态装载（重载）来避免重启envoy&lt;/li&gt;
&lt;li&gt;隔离性&lt;/li&gt;
&lt;li&gt;实时A/B测试&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;envoy的wasm支持&#34;&gt;Envoy的WASM支持&lt;/h3&gt;
&lt;p&gt;Envoy支持Web Assembly的架构和方式如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/envoy-wasm-architect_hua7878ea436d969f269b11780160d8a15_387702_9178357bb6f6b99f1a639777d9f313f4.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/envoy-wasm-architect_hua7878ea436d969f269b11780160d8a15_387702_8aa68e73ed3d15e3fac5d77d0cb9725e.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/envoy-wasm-architect_hua7878ea436d969f269b11780160d8a15_387702_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/envoy-wasm-architect_hua7878ea436d969f269b11780160d8a15_387702_9178357bb6f6b99f1a639777d9f313f4.webp&#34;
               width=&#34;760&#34;
               height=&#34;346&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：内容来自演讲 &lt;a href=&#34;https://www.youtube.com/watch?v=XdWmm_mtVXI&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;”Extending Envoy with WebAssembly”&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;目前Envoy支持的Web Assembly VM有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;WAVM (&lt;a href=&#34;https://github.com/WAVM/WAVM&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/WAVM/WAVM&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;V8(&lt;a href=&#34;https://v8.dev/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://v8.dev/&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Null Sandbox (use the API, compile directly into Envoy)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;mixer-v2和wasm&#34;&gt;Mixer v2和WASM&lt;/h3&gt;
&lt;p&gt;Mixer v2的终极目标形态应该是这样：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-target_hu8c1b47614b368506814ab5d0554a0676_145134_03deb6b29a24990ba4431c2ee09b7c3a.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-target_hu8c1b47614b368506814ab5d0554a0676_145134_1470cc2a4da072cace1a3f720474b866.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-target_hu8c1b47614b368506814ab5d0554a0676_145134_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/mixer-v2-target_hu8c1b47614b368506814ab5d0554a0676_145134_03deb6b29a24990ba4431c2ee09b7c3a.webp&#34;
               width=&#34;760&#34;
               height=&#34;307&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mixer 合并到 Envoy：Adapter 以 In-Proxy Adapter 的形式存在&lt;/li&gt;
&lt;li&gt;Envoy 支持 Web Assembly 扩展：各种 Adapter 以高级语言编写，然后编译为WASM，再被Envoy加载（静态/动态均可）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们欣喜的看到，在 WASM 这样的“黑科技”的加持下，Istio终于可以在弥补性能缺陷的同时，在系统架构上依然最大限度的维持Mixer v1的架构优雅、职责分明和边界清晰。&lt;/p&gt;
&lt;p&gt;基于WASM扩展的 Mixer v2 真是一个令人兴奋而期待的新颖设计。&lt;/p&gt;
&lt;p&gt;而对于 Mixer 的性能问题的解决方案，广大Istio社区可谓望穿秋水，从2017年初Istio开源发布0.1版本到今天，两年多时间过去，终于 Mixer v2 开始正视 Mixer 性能问题。但是，Mixer v2 要真正落地，还有非常长的路要走。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-plan_hu40645feda4afd14a151ab9aa2d347ba8_66893_ccbcd16a90d085f45233e3f3579cb09d.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-plan_hu40645feda4afd14a151ab9aa2d347ba8_66893_8d35b771034fc623a274a1044bca76fe.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-plan_hu40645feda4afd14a151ab9aa2d347ba8_66893_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/mixer-v2-plan_hu40645feda4afd14a151ab9aa2d347ba8_66893_ccbcd16a90d085f45233e3f3579cb09d.webp&#34;
               width=&#34;589&#34;
               height=&#34;306&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;要实现如上图所示 Mixer v2 终极目标形态，需要：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Envoy 提供对 WASM 的支持&lt;/li&gt;
&lt;li&gt;Istio 大规模架构调整，实施 mixer v2&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;目前，Envoy对Web Assembly的支持预计有希望在3-6个月内实现，具体情况可以通过下面的Issue来了解：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://github.com/envoyproxy/envoy/issues/4272&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/envoyproxy/envoy/issues/4272&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我们从这个Issue中可以大体总结Envoy对WASM支持的过程：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2018年8月28日，Issue创建，提交对WASM支持的想法&lt;/li&gt;
&lt;li&gt;2018年10月开始动手，进行poc&lt;/li&gt;
&lt;li&gt;2019年5月poc完成，然后创建envoy-wasm项目&lt;/li&gt;
&lt;li&gt;目前这个Issue放在envoy的下一个milestone1.12中&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Envoy 最近刚发布了 1.11版本，根据最近两年中Envoy的稳健表现，Envoy一般三个月发布一个版本，这样预计1.12版本会在未来三个月内提供。即使1.12版本未能完成，延后到1.13版本，也会在六个月内提供。&lt;/p&gt;
&lt;p&gt;但是 Istio 方面的进展，则非常不乐观：Mixer v2 从提出到现在8个月了，依然是In Review状态。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-in-review-status_hu2424c6bd4ea51b6e8e406c199903bc5e_30984_5ffef743bc7ce4529ea7125fe01d9287.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-in-review-status_hu2424c6bd4ea51b6e8e406c199903bc5e_30984_e0741d6765b10cc8b61a8cc71d76fa71.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/mixer-v2-in-review-status_hu2424c6bd4ea51b6e8e406c199903bc5e_30984_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/mixer-v2-in-review-status_hu2424c6bd4ea51b6e8e406c199903bc5e_30984_5ffef743bc7ce4529ea7125fe01d9287.webp&#34;
               width=&#34;760&#34;
               height=&#34;129&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;考虑到过去两年间 Istio 团队表现出来的组织能力和执行能力，我个人持悲观态度，我的疑问和担忧是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Istio能否接受Mixer v2？&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;Mixer v2 虽然前景美好，奈何还需时日，尤其取决于 Istio 的表现：社区的殷切期待和Istio的犹豫未决可谓耐人寻味。&lt;/p&gt;
&lt;p&gt;最后感叹一声：&lt;strong&gt;南望王师又一年，王师还在Review间&lt;/strong&gt;&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;h2 id=&#34;servicemesh灵魂拷问三要不要支持虚拟机&#34;&gt;ServiceMesh灵魂拷问三：要不要支持虚拟机？&lt;/h2&gt;
&lt;p&gt;在聊完性能与架构之后，我们继续今天的第三个灵魂拷问：在有了高大上的容器/k8s/云原生，还要不要支持土里土气的虚拟机？&lt;/p&gt;
&lt;h3 id=&#34;servicemesh-主流产品对虚拟机的支持&#34;&gt;ServiceMesh 主流产品对虚拟机的支持&lt;/h3&gt;
&lt;p&gt;首先我们看一下 ServiceMesh 主流产品对虚拟机的支持情况：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/vm-support-process_hu7c1986ca5b8ede2570501db492e364fa_225689_2653761c48defd6a5fae7066f5da021e.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/vm-support-process_hu7c1986ca5b8ede2570501db492e364fa_225689_9f253cf6d6e9c509881e2572e15f2e86.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/vm-support-process_hu7c1986ca5b8ede2570501db492e364fa_225689_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/vm-support-process_hu7c1986ca5b8ede2570501db492e364fa_225689_2653761c48defd6a5fae7066f5da021e.webp&#34;
               width=&#34;760&#34;
               height=&#34;276&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ServiceMesh 的第一代产品，典型如 &lt;code&gt;Linkered 1.*&lt;/code&gt; 和 Envoy，天然支持虚拟机&lt;/li&gt;
&lt;li&gt;ServiceMesh 的第二代产品，如 Istio，在刚开始发布时还计划提供对非k8s的支持，但是后面实质性的取消，基本只有在k8s上才好用。&lt;code&gt;Linkerd 2.*&lt;/code&gt; 更是明确只提供k8s的支持。&lt;/li&gt;
&lt;li&gt;AWS 在2018年推出的 app mesh，不仅仅可以支持虚拟机，而且可以支持虚拟机和容器相互访问；稍后Google 推出了 Traffic Director 产品，也是同样思路。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;稍加回顾，就会发现：历史总是惊人的相似，螺旋式上升？波浪式起伏？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/vm-support-next_hu64dad500515bfa6afdd993df49fe9aba_142483_962f3c392777484cc7dd9e140ab7529a.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/vm-support-next_hu64dad500515bfa6afdd993df49fe9aba_142483_d8f37779b3c43a2a9ccc0c785f854247.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/vm-support-next_hu64dad500515bfa6afdd993df49fe9aba_142483_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/vm-support-next_hu64dad500515bfa6afdd993df49fe9aba_142483_962f3c392777484cc7dd9e140ab7529a.webp&#34;
               width=&#34;760&#34;
               height=&#34;374&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;ServiceMesh 对于虚拟机的态度，从 &lt;code&gt;Linkerd 1.*&lt;/code&gt; 和 Envoy的支持，到 Istio / &lt;code&gt;Linkerd 2.*&lt;/code&gt; 的不支持，再到 AWS app mesh 和 Google Traffic Director 的支持，可谓一波三折。未来如果有新形态的 ServiceMesh 产品出现，对虚拟机的支持又会是如何？支持还是不支持，我们拭目以待。&lt;/p&gt;
&lt;h3 id=&#34;虚拟机支持与否的背后&#34;&gt;虚拟机支持与否的背后&lt;/h3&gt;
&lt;p&gt;第一个转折容易理解：相比虚拟机，k8s提供了太多便利。随着容器的普及，k8s的一统天下，社区对云原生的日益接受，虚拟机模式失宠容易理解。&lt;/p&gt;
&lt;p&gt;轻松一下，引用最近的一个梗 “小甜甜 VS 牛夫人”，感觉可以非常形象的描述虚拟机失宠的场面：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/vm-support-turn1_hu30cfc2cad8e69bad8203f3a0d5752cd3_900534_9a71084e110b5466a90153a81251dc25.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/vm-support-turn1_hu30cfc2cad8e69bad8203f3a0d5752cd3_900534_a4a5a98cda0111bdfa736c3bc7276329.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/vm-support-turn1_hu30cfc2cad8e69bad8203f3a0d5752cd3_900534_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/vm-support-turn1_hu30cfc2cad8e69bad8203f3a0d5752cd3_900534_9a71084e110b5466a90153a81251dc25.webp&#34;
               width=&#34;511&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第二个转折该如何解释？&lt;/p&gt;
&lt;p&gt;AWS App Mesh 提供对虚拟机支持是容易理解的，毕竟AWS上目前还是以虚拟机为主，而且k8s/云原生本来就是 Google 和 AWS 竞争的重要武器，AWS app mesh 提供对虚拟机的支持，并且可以打通就有的虚拟机体现和新的k8s体系，对AWS意义重大。&lt;/p&gt;
&lt;p&gt;但是，作为 k8s 和云原生的主要推动力量， Google 为什么在 Traffic Director 这个产品上没有继续 Istio / Linkerd2 只支持k8s的做法，而是效仿 AWS 呢？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/vm-support-turn2_hu9a5e198eb8ac60d36d69baa745232316_672643_6bd023bc70388e060e3ade93f7927ac6.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/vm-support-turn2_hu9a5e198eb8ac60d36d69baa745232316_672643_9b225d2b444158779e437693c063182c.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/vm-support-turn2_hu9a5e198eb8ac60d36d69baa745232316_672643_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/vm-support-turn2_hu9a5e198eb8ac60d36d69baa745232316_672643_6bd023bc70388e060e3ade93f7927ac6.webp&#34;
               width=&#34;760&#34;
               height=&#34;672&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;原因简单而直白：理想和现实的差距。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;理想：云原生普及，容器普遍落地，生产上k8s广泛使用&lt;/li&gt;
&lt;li&gt;现实：虚拟机大量存在，大量公司未能有效掌握k8s，大部分应用还是运行在虚拟机上&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关于ServiceMesh形态和云原生未能普及的思考，去年（2018-02-10
）在 &lt;a href=&#34;../../post/201802-dreammesh-brainstorm-cloudnative/&#34;&gt;DreamMesh抛砖引玉(2)-CloudNative&lt;/a&gt; 这篇博客中我有详细描述，当时也和很多社区同学深入讨论。援引当时的一小段总结：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;理想很丰满，现实很骨感。Cloud Native虽然令人向往，然而现实中，有多少企业是真的做好了Cloud Native的准备？&lt;/p&gt;
&lt;p&gt;问题：到底该先容器/k8s，再上微服务/servicemesh；还是先微服务/servicemesh，再上容器/k8s？&lt;/p&gt;
&lt;p&gt;每个公司都会有自己的实际情况和选择。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在去年底（2018-11-25），我和同事曾经做过一个名为 &lt;a href=&#34;../201811-service-mesh-step-by-step/&#34;&gt;&amp;ldquo;蚂蚁金服Service Mesh渐进式迁移方案&amp;rdquo;&lt;/a&gt; 的主题演讲，详细描述了 Service Mesh 和 k8s 落地可能的多种演进路线：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/servicemesh-roads_hu4c13520dd15d1ba80420c3daeb132505_176111_8811b9e2c10b831f1e56f7e6be657ec5.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/servicemesh-roads_hu4c13520dd15d1ba80420c3daeb132505_176111_a2e20bb0bb441bf7a6a208f178b8d18a.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/servicemesh-roads_hu4c13520dd15d1ba80420c3daeb132505_176111_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/servicemesh-roads_hu4c13520dd15d1ba80420c3daeb132505_176111_8811b9e2c10b831f1e56f7e6be657ec5.webp&#34;
               width=&#34;760&#34;
               height=&#34;366&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在关于先ServiceMesh，还是先k8s的这个问题上，Google Traffic Director的选择是：支持ServiceMesh先行。即容许应用在进行容器化改造和k8s落地之前，也能够从ServiceMesh获益。为此，Google Traffic Director在标准的k8s之外，为基于虚拟机的应用（未做容器化改造）和基于自管理的docker容器（有容器但不是k8s）提供支持：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/google-traffic-director-choose_hue5130368b62762e4953cff316e42a88e_231097_fbb463bbfe557488a36b8def192afda9.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/google-traffic-director-choose_hue5130368b62762e4953cff316e42a88e_231097_e239e4f4192b24c30d176acface8782f.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/google-traffic-director-choose_hue5130368b62762e4953cff316e42a88e_231097_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/google-traffic-director-choose_hue5130368b62762e4953cff316e42a88e_231097_fbb463bbfe557488a36b8def192afda9.webp&#34;
               width=&#34;760&#34;
               height=&#34;371&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对此，Traffic Director 官方文档是这样描述的：“按&lt;strong&gt;您的节奏&lt;/strong&gt;进行现代化改造”。&lt;/p&gt;
&lt;h3 id=&#34;创新google-traffic-director的虚拟机支持&#34;&gt;创新：Google Traffic Director的虚拟机支持&lt;/h3&gt;
&lt;p&gt;对于如何在虚拟机上提供ServiceMesh的支持，Google Traffic Director 给出了一个创新的思路。&lt;/p&gt;
&lt;p&gt;为了方便管理虚拟机实例，Google Traffic Director 提供了托管式实例组（Managed Instance Group，实际来自GCP），效仿容器和k8s的方式来管理虚拟机：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/managed-instance-group_hu8d3662541b2ce858f2504b6b253a3fc5_396216_ad941f3fec2631c9103e2922ccb61a0f.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/managed-instance-group_hu8d3662541b2ce858f2504b6b253a3fc5_396216_500bb370ffada51c3b540bbba8a5b6a4.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/managed-instance-group_hu8d3662541b2ce858f2504b6b253a3fc5_396216_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/managed-instance-group_hu8d3662541b2ce858f2504b6b253a3fc5_396216_ad941f3fec2631c9103e2922ccb61a0f.webp&#34;
               width=&#34;760&#34;
               height=&#34;315&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;其中最重要的是提供实例模版（Instance Template）来进行虚拟机的硬件配置/操作系统配置，然后基于实例模版来创建虚拟机实例，并通过自动启动脚本来获取并启动应用，从而实现了从零启动一个运行于虚拟机的应用的全过程自动化。&lt;/p&gt;
&lt;p&gt;而实例模版+自动启动脚本配合，可以实现类似容器和k8s下的很多类似功能，比如应用版本升级时只需要修改实例模版（和其中的自动启动脚本），类似容器下的修改镜像文件。实例模版提供对实例副本数的管理，包括固定大小和自动伸缩（由此提供类serverless的特性）。&lt;/p&gt;
&lt;p&gt;类似的，为了方便管理运行于虚拟机上的应用实例，Traffic Director 效仿 k8s/Istio 的方式来管理服务：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/traffic-director-service-management_hu98b01e1758998d62874cd1767a4fc551_399379_4545a5cbc47a419237d4ff72520d39d5.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/traffic-director-service-management_hu98b01e1758998d62874cd1767a4fc551_399379_48621330618b0744dfcdececf367a9ee.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/traffic-director-service-management_hu98b01e1758998d62874cd1767a4fc551_399379_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/traffic-director-service-management_hu98b01e1758998d62874cd1767a4fc551_399379_4545a5cbc47a419237d4ff72520d39d5.webp&#34;
               width=&#34;760&#34;
               height=&#34;312&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Traffic Director 提供了可同时用于k8s/容器/虚拟机三种模式下的统一的服务抽象，容许在控制台手工创建服务并关联到实例模版（以及实例模版背后的虚拟机实例和运行其上的应用），可以通过托管实例组配置健康检查/灰度发布等高级特性。&lt;/p&gt;
&lt;p&gt;Google Traffic Director 在 ServiceMesh 虚拟机支持上的创新思路在于：&lt;strong&gt;补齐虚拟机的短板，向容器看齐，维持一致的用户体验&lt;/strong&gt;。如下图所示，在通过托管式实例组向容器/k8s看齐（当然非常有限）之后，配合统一的 Traffic Director 服务抽象，就可以实现统一管理应用，如配置路由规则。从而实现在最上层为不同ServiceMesh模式提供一致的用户体验：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/traffic-director-vm-improve_huc6d89afaa6d30478050bb07539b3f755_216228_7367fd292d34424bf3cef0bb8d1c3585.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/traffic-director-vm-improve_huc6d89afaa6d30478050bb07539b3f755_216228_b4e63abc0c693e80a8bce68fbbfbcd00.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/traffic-director-vm-improve_huc6d89afaa6d30478050bb07539b3f755_216228_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/traffic-director-vm-improve_huc6d89afaa6d30478050bb07539b3f755_216228_7367fd292d34424bf3cef0bb8d1c3585.webp&#34;
               width=&#34;760&#34;
               height=&#34;317&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;通过上述的创新方式，Traffic Director 将 ServiceMesh 对虚拟机的支持提升到新的高度。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：关于Google Traffic Director 对虚拟机支持的细节，请见我的另一篇博客文档 &lt;a href=&#34;../../post/20190707-google-traffic-director-practice/&#34;&gt;&amp;ldquo;ServiceMesh先行：Google Traffic Director实践分析&amp;rdquo;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;servicemesh灵魂拷问四说好的供应商不锁定呢&#34;&gt;ServiceMesh灵魂拷问四：说好的供应商不锁定呢？&lt;/h2&gt;
&lt;p&gt;在夸赞完 google 和 Traffic Director 之后，我们进行今天的最后一个灵魂拷问，这个问题的目标直指 google：&lt;/p&gt;
&lt;p&gt;说好的供应商不锁定呢？&lt;/p&gt;
&lt;p&gt;供应商不锁定，是 google 和 CNCF 一直强调和倡导的理念，也是云原生最重要的基石之一。Google 一直用供应商不锁定这块大石头狠狠的砸AWS的脑袋，但是，这块石头也是可以用来砸google自己的脚的。&lt;/p&gt;
&lt;h3 id=&#34;smi的意义和最近的社区支持情况&#34;&gt;SMI的意义和最近的社区支持情况&lt;/h3&gt;
&lt;p&gt;在 ServiceMesh 领域，供应商不锁定的典型代表，就是SMI（Service Mesh Interface）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：关于 Service Mesh Interface 的介绍，我之前的博客文档 &lt;a href=&#34;../../post/201906-service-mesh-interface-detail/&#34;&gt;Service Mesh Interface详细介绍&lt;/a&gt; 有非常详细的描述。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;让我们来共同回味 SMI 为整个 ServiceMesh 社区带来的美好愿景：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“SMI 是在 Kubernetes 上运行服务网格的规范。它定义了由各种供应商实现的通用标准。这使得最终用户的标准化和服务网格供应商的创新可以两全其美。SMI 实现了灵活性和互操作性。”&lt;/p&gt;
&lt;p&gt;“SMI API的目标是提供一组通用的，可移植的Service Mesh API，Kubernetes用户可以以供应商无关的方式使用这些API。通过这种方式，可以定义使用Service Mesh技术的应用程序，而无需紧密绑定到任何特定实现。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下图这张图可以让我们更好的理解 SMI 在 ServiceMesh 生态中的位置和 SMI 对整个生态的重要：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/smi_hu0d7dcbf7a79e0c72ff751e5246914923_48551_0b7d15f65c4583fc43460d72ff3526b7.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/smi_hu0d7dcbf7a79e0c72ff751e5246914923_48551_d0f86790637227c8f3a1c2769474343e.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/smi_hu0d7dcbf7a79e0c72ff751e5246914923_48551_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/smi_hu0d7dcbf7a79e0c72ff751e5246914923_48551_0b7d15f65c4583fc43460d72ff3526b7.webp&#34;
               width=&#34;708&#34;
               height=&#34;643&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在 SMI 发布之后，最近 ServiceMesh 社区的主要玩家都纷纷开始提供对 SMI 的支持：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Linkerd：发布于 2019-07-11的 Linkerd 2.4.0 版本开始支持 SMI&lt;/li&gt;
&lt;li&gt;Consul Connect: 发布于 2019-07-09 的 Consul 1.6 版本开始支持 SMI&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;google在servicemesh标准化上的反常表现&#34;&gt;Google在ServiceMesh标准化上的反常表现&lt;/h3&gt;
&lt;p&gt;标准化是供应商不锁定的基石，只有实现标准化，才能基于统一的标准打造社区和生态，上层的应用/工具等才有机会在不同的厂商实现之间迁移，从而打造一个有序竞争的积极向上的生态系统。&lt;/p&gt;
&lt;p&gt;ServiceMesh 问世四年来，在标准化方面做的并不到位，而Google在ServiceMesh标准化上的表现更是反常。具体说，SMI出来之前：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Istio迟迟未贡献给CNCF，可以说Istio至今依然是Google（还有IBM/Lyft）的项目，而不是社区的项目。&lt;/li&gt;
&lt;li&gt;Istio API 是私有API，未见有标准化动作&lt;/li&gt;
&lt;li&gt;Envoy xDS v2 API是社区事实标准，但这其实是Envoy的功劳&lt;/li&gt;
&lt;li&gt;统一数据平面API（UDPA），感觉更像是Envoy在推动，和Istio关系不大&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Google作为ServiceMesh界的领头羊，在标准化方面表现可谓消极怠工，几乎可以说是无所作为。以至于SMI这样的标准，居然是微软出面牵头。而在SMI出来之后，除Istio/AWS之外几乎所有ServiceMesh玩家都参与的情况下，依然未见Istio有积极回应。&lt;/p&gt;
&lt;p&gt;AWS不加入社区容易理解，毕竟AWS自成体系，AWS本来也就是“供应商不锁定”的革命对象。而Google这位“供应商不锁定”运动的发起者，在 ServiceMesh 标准化上的反常表现，却是耐人寻味：屠龙的勇士，终将变成恶龙吗？&lt;/p&gt;
&lt;p&gt;再次以此图，致敬AWS和google：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/smi-google-aws_hu7dceb4608335aeb4427039f7b1a5fea5_668214_72d1ee04c189c94eeda34cc2eaa43879.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/smi-google-aws_hu7dceb4608335aeb4427039f7b1a5fea5_668214_65c9b3100f11b642c37979b70f476f69.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/smi-google-aws_hu7dceb4608335aeb4427039f7b1a5fea5_668214_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/smi-google-aws_hu7dceb4608335aeb4427039f7b1a5fea5_668214_72d1ee04c189c94eeda34cc2eaa43879.webp&#34;
               width=&#34;760&#34;
               height=&#34;641&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;下图是目前的SMI阵营：汇集几乎所有ServiceMesh玩家，唯独AWS和Google缺席：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201908-servicemesh-development-trend2/images/smi-community_hu1a1987b942fdae853ad77bf0e5a61b0d_172990_852e216698810cd989895e841056c344.webp 400w,
               /talk/201908-servicemesh-development-trend2/images/smi-community_hu1a1987b942fdae853ad77bf0e5a61b0d_172990_2456cd96515db0d98a82c3028e41317d.webp 760w,
               /talk/201908-servicemesh-development-trend2/images/smi-community_hu1a1987b942fdae853ad77bf0e5a61b0d_172990_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201908-servicemesh-development-trend2/images/smi-community_hu1a1987b942fdae853ad77bf0e5a61b0d_172990_852e216698810cd989895e841056c344.webp&#34;
               width=&#34;760&#34;
               height=&#34;232&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;期待Google后续的行动，说好的供应商不锁定，请勿忘此初心。&lt;/p&gt;
&lt;h2 id=&#34;总结与展望&#34;&gt;总结与展望&lt;/h2&gt;
&lt;p&gt;ServiceMesh 出道四年，对于一个新技术，四年时间不算短，到了该好好反思当下和着眼未来的时候了，尤其是目前 ServiceMesh 在落地方面表现远不能令人满意的情况下。&lt;/p&gt;
&lt;p&gt;正如标题所言：&lt;strong&gt;棋到中盘，路往何方？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;今天的Servicemesh发展趋势探讨，我们以灵魂拷问的方式提出了四个问题。每一个问题和答案，都会深刻影响未来几年Servicemesh的走向，请大家在未来一两年间密切关注这些问题背后所代表的ServiceMesh技术发展走向和产品形态演进：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;要架构，还是要性能？：关注点在于ServiceMesh的落地，落地还有落地。性能不是万能的，但是没有性能是万万不能的&lt;/li&gt;
&lt;li&gt;性能有了，架构怎么办？：关注点在于回归性能之后的架构优化，以创新的方式实现性能与架构的兼得，用新技术来解决老问题&lt;/li&gt;
&lt;li&gt;要不要支持虚拟机？：关注点依然是落地，对现实的妥协或者说学会接地气，以创新思维来实现用新方法解决老问题&lt;/li&gt;
&lt;li&gt;说好的供应商不锁定呢？：关注点在于标准化，还有标准化之后的生态共建和生态繁荣。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;本次ServiceMesh发展趋势的续篇到此为止，今年年底前也许还会有ServiceMesh发展趋势序列的第三篇（名字大概会叫做续2吧），希望届时能看到一些令人眼前一亮的新东西。敬请期待！&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>ServiceMesh先行：Google Traffic Director实践分析</title>
      <link>https://skyao.net/post/201907-google-traffic-director-practice/</link>
      <pubDate>Sun, 07 Jul 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201907-google-traffic-director-practice/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;Traffic Director 是 Google Cloud 推出的完全托管的服务网格流量控制平面。关于 Google Traffic Director 的介绍，可以先行阅读我之前的文章：&amp;quot;&lt;a href=&#34;../201905-google-traffic-director-detail/&#34;&gt;Google Traffic Director详细介绍&lt;/a&gt;&amp;quot;。本文内容将关注于 Google Traffic Director 的实际操作，可以理解为是上一篇  Google Traffic Director 介绍文章的实践篇。&lt;/p&gt;
&lt;p&gt;为此，本文将深入调研Google Traffic Director，内容会涉及到很多具体的操作和设置，
也会对Google Traffic Director的工作模式和产品思路进行分析。&lt;/p&gt;
&lt;h2 id=&#34;前期准备&#34;&gt;前期准备&lt;/h2&gt;
&lt;h3 id=&#34;启用-traffic-director&#34;&gt;启用 Traffic Director&lt;/h3&gt;
&lt;p&gt;Traffic Director 是 GCP 管理的一项服务，因此使用 Traffic Director 前需要在控制台页面上启用 Traffic Director：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201907-google-traffic-director-practice/images/google/enable-1_hud2dfa459c20df9652e9e0822bb074dcc_89385_f2b6fc8a612ff890b1d35d0ab791b80f.webp 400w,
               /post/201907-google-traffic-director-practice/images/google/enable-1_hud2dfa459c20df9652e9e0822bb074dcc_89385_fc040df28400571078a245d4397c4014.webp 760w,
               /post/201907-google-traffic-director-practice/images/google/enable-1_hud2dfa459c20df9652e9e0822bb074dcc_89385_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201907-google-traffic-director-practice/images/google/enable-1_hud2dfa459c20df9652e9e0822bb074dcc_89385_f2b6fc8a612ff890b1d35d0ab791b80f.webp&#34;
               width=&#34;760&#34;
               height=&#34;282&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;配置服务的说明：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201907-google-traffic-director-practice/images/google/enable-2_hu5901dd264ccacf184e2299cfefb85c0f_65025_f4f1d90864b4deb70772c01adc8f9088.webp 400w,
               /post/201907-google-traffic-director-practice/images/google/enable-2_hu5901dd264ccacf184e2299cfefb85c0f_65025_6947fb96c8a5b6c75e9a94cb20701b13.webp 760w,
               /post/201907-google-traffic-director-practice/images/google/enable-2_hu5901dd264ccacf184e2299cfefb85c0f_65025_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201907-google-traffic-director-practice/images/google/enable-2_hu5901dd264ccacf184e2299cfefb85c0f_65025_f4f1d90864b4deb70772c01adc8f9088.webp&#34;
               width=&#34;752&#34;
               height=&#34;407&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;从说明上看 Traffic Director 可以支持 Kubernetes 服务，也可以支持基于虚拟机的服务。后面我们的实践将包含这两块的内容。&lt;/p&gt;
&lt;p&gt;在使用之前，要再做一些设置，具体参考官方文档：https://cloud.google.com/traffic-director/docs/setting-up-traffic-director。主要操作是两个：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;启用Traffic Director API&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34;
           src=&#34;https://skyao.net/post/201907-google-traffic-director-practice/images/google/enable-traffic-director-api.gif&#34;
           loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;启用服务帐号以访问 Traffic Director API&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34;
           src=&#34;https://skyao.net/post/201907-google-traffic-director-practice/images/google/enable-serviceaccount.gif&#34;
           loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;完成这两个准备工作后，我们就将开始Traffic Director的实际使用，包括虚拟机模式和容器模式。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;了解traffic-director的工作方式&#34;&gt;了解Traffic Director的工作方式&lt;/h3&gt;
&lt;p&gt;参考官方文档&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cloud.google.com/traffic-director/docs/set-up-gce-vms#per_host_config&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://cloud.google.com/traffic-director/docs/set-up-gce-vms#per_host_config&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;的这个小节，可以在控制台上进入 Computer Engine，然后创建一个虚拟机实例，再SSH（通过浏览器）登录上去，手工验证上述操作。在正式开始实践前， 完成这个步骤的练习非常重要，因为这个过程会让我们充分理解 Traffic Director 下是如何搭建和配置运行环境的。&lt;/p&gt;
&lt;p&gt;在这个的过程中，服务器端应用将通过一个简单的apache web服务器来模拟，而客户端应用将通过 curl 命令来模拟。&lt;/p&gt;
&lt;p&gt;让我们开始，在SSH登录到刚才新建的虚拟机之后，依次执行下面的命令，请注意注释中详细的说明：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#! /bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;# 添加一个envoy用户名用于运行envoy。这个用户名不容许用于登录&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 这个 envoy 用户名后面在envoy的启动配置文件 sidecar.env 中会使用到&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo adduser --system --disabled-login envoy
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 下载并解压缩 Traffic Director tar.gz 文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 这个地方的下载地址，中文文档用的是 traffic-director/beta/traffic-director-beta.tar.gz，已经过期，不要用这个版本&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 英文文档中28号之前的地址是错误的，报错404，但是28号之后修订过来了&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo wget -P /home/envoy https://storage.googleapis.com/traffic-director/traffic-director.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo tar -xzf /home/envoy/traffic-director.tar.gz -C /home/envoy
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo rm /home/envoy/traffic-director.tar.gz
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;## 这里相当于直接配置 sidecar.env 文件，验证时可以不用这个命令，而是直接 vi 打开这个文件，手工配置当个选项，源文件有详细的注释&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo cat &lt;span class=&#34;s&#34;&gt;&amp;lt;&amp;lt; END &amp;gt; /home/envoy/traffic-director/sidecar.env
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;## 设置运行envoy的用户，这个用户名是我们在前面创建的
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;ENVOY_USER=envoy
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;# Exclude the proxy user from redirection so that traffic doesn&amp;#39;t loop back
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;# to the proxy
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;EXCLUDE_ENVOY_USER_FROM_INTERCEPT=&amp;#39;true&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;# SERVICE_CIDR 最好是准确设置，默认*是拦截所有的对外流量
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;# 我设置的是10.128.0.1/16，请自行修改为你实际的设置
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;SERVICE_CIDR=&amp;#39;10.128.0.1/16&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;GCP_PROJECT_NUMBER=&amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;VPC_NETWORK_NAME=&amp;#39;&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;ENVOY_PORT=&amp;#39;15001&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;# ENVOY_ADMIN_PORT在28号前文档中遗漏没有设置，导致envoy无法启动，28号更新修复
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;ENVOY_ADMIN_PORT=&amp;#39;15000&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;LOG_DIR=&amp;#39;/var/log/envoy/&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;LOG_LEVEL=&amp;#39;info&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;XDS_SERVER_CERT=&amp;#39;/etc/ssl/certs/ca-certificates.crt&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;s&#34;&gt;END&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 这里更新 apt-get，最终目的是安装docker工具，以便下载 envoy 的镜像文件并从其中提取envoy的二进制文件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get update -y
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install apt-transport-https ca-certificates curl gnupg2 software-properties-common -y
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo curl -fsSL https://download.docker.com/linux/debian/gpg &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sudo apt-key add -
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo add-apt-repository &lt;span class=&#34;s1&#34;&gt;&amp;#39;deb [arch=amd64] https://download.docker.com/linux/debian stretch stable&amp;#39;&lt;/span&gt; -y
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get update -y
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo apt-get install docker-ce apache2 -y
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 安装并启动 apache，用来简单模拟一个服务端应用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo service apache2 restart
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 修改apache下默认的 index.html 文件，功能是简单打印出当前机器的hostname，以便后面访问这个用apache模拟的服务时可以判断访问的是哪个服务和实例&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 当时这个地方有错误，下面这行是英文文档的写法，会无法工作&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# echo &amp;#39;&amp;lt;!doctype html&amp;gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;&amp;#39;\`/bin/hostname\`&amp;#39;&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;#39; &lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 需要修改为下面内容，这样才能正确打印 hostname&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;lt;!doctype html&amp;gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;/bin/hostname&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;#39;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; sudo tee /var/www/html/index.html
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 从网上下载 envoy 的镜像并从中提取 envoy 的二进制文件，这一步一定要先收工验证&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo /home/envoy/traffic-director/pull_envoy.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 用脚本启动envoy，这个脚本会使用 sidecar.env 的配置信息，设置 iptables 拦截，然后启动 envoy。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# 务必在启动之后，通过 run.sh status 命令检查 envoy 是否启动完成并正常工作&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sudo /home/envoy/traffic-director/run.sh start
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的这段命令，在 Traffic Director 的虚拟机模式中会有特殊的用途，后面我们会详细讲述。&lt;/p&gt;
&lt;p&gt;这个虚拟机环境实践完上述的操作和脚本之后，建议继续保留，后面用来模拟客户端（curl + envoy）验证搭建的 traffic director 的服务是否可以访问。为了对比没有 envoy 劫持的情况，可以再启动一台虚拟机，不配置上面的内容， 以模拟没有 envoy 劫持的情况。&lt;/p&gt;
&lt;p&gt;在使用 Traffic Director 前，需要先理解Traffic Director的服务模型和工作模式。&lt;/p&gt;
&lt;h2 id=&#34;服务模型和工作模式&#34;&gt;服务模型和工作模式&lt;/h2&gt;
&lt;h3 id=&#34;traffic-director的服务&#34;&gt;Traffic Director的服务&lt;/h3&gt;
&lt;p&gt;下面是我验证完成之后的 Traffic Director 服务列表：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201907-google-traffic-director-practice/images/google/service-list_hu8098fa29586311adf1f7b9b439ca9da9_127906_75da8953c483be7e8400c638c051fba0.webp 400w,
               /post/201907-google-traffic-director-practice/images/google/service-list_hu8098fa29586311adf1f7b9b439ca9da9_127906_06954066cdcafe3bdd81c9e80367a8f5.webp 760w,
               /post/201907-google-traffic-director-practice/images/google/service-list_hu8098fa29586311adf1f7b9b439ca9da9_127906_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201907-google-traffic-director-practice/images/google/service-list_hu8098fa29586311adf1f7b9b439ca9da9_127906_75da8953c483be7e8400c638c051fba0.webp&#34;
               width=&#34;760&#34;
               height=&#34;546&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;图中我创建了 details / ratings / reviews 三个服务：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个服务对应有不同的后端实例组，Traffic Director 支持多个实例组，简单期间这里只设置了一个实例组。&lt;/li&gt;
&lt;li&gt;每个服务有关联的路由规则，也可以在一个路由规则里面配置多个服务，图中我建立了一个名为 http-rule 的路由规则用来管理上面三个服务。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;实例组instance-group&#34;&gt;实例组/Instance Group&lt;/h3&gt;
&lt;p&gt;实例组用于管理虚拟机实例，下面是 details 服务关联的实例组：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201907-google-traffic-director-practice/images/google/backend-instance-group_hub6c4d65b11777b373c70ffb995f9ff77_73947_06b1d285c2ee4ef0d2d6e765682de869.webp 400w,
               /post/201907-google-traffic-director-practice/images/google/backend-instance-group_hub6c4d65b11777b373c70ffb995f9ff77_73947_2c7bb88530d105b4283d9a7119828a80.webp 760w,
               /post/201907-google-traffic-director-practice/images/google/backend-instance-group_hub6c4d65b11777b373c70ffb995f9ff77_73947_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201907-google-traffic-director-practice/images/google/backend-instance-group_hub6c4d65b11777b373c70ffb995f9ff77_73947_06b1d285c2ee4ef0d2d6e765682de869.webp&#34;
               width=&#34;760&#34;
               height=&#34;238&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;注意图上实例组有模版的概念，也就是 实例模版（Instance Template），这里有两个地方显示模版：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;实例组当前设置的模版&lt;/li&gt;
&lt;li&gt;实例组下的各个虚拟机实例实际使用的模版&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;两个地方的模版通常是一致的，但是如果修改实例组的模版，在旧有的虚拟机实例没有更新之前，会出现不同的模版。&lt;/p&gt;
&lt;p&gt;Compute Engine中的实例组有两种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;非托管式的实例组：这是传统的虚拟机管理方式，每台虚拟机都是&lt;strong&gt;手动&lt;/strong&gt;搭建系统+安装配置应用，然后再手动添加到实例组。重点在于实例组下的实例是&lt;strong&gt;固定的，手工配置&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;托管式实例组（Managerd Instance Group）：托管的概念是指可以配置实例模版，然后 Compute Engine 就可以根据这个实例模版来&lt;strong&gt;自动&lt;/strong&gt;搭建系统+安装配置应用。最关键的改变就在于这个虚拟机实例的自动化搭建，有了这个功能之后，就可以在此基础上实现很多高级特性。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们以托管式实例组创建的页面为例：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201907-google-traffic-director-practice/images/google/managed-instance-group-create_hu7a5985b254705ee9342af446179fac2f_146976_a621c1d135015018899af14eb29bd4c3.webp 400w,
               /post/201907-google-traffic-director-practice/images/google/managed-instance-group-create_hu7a5985b254705ee9342af446179fac2f_146976_b437fab52d1ddc23a54d84dbcaaac488.webp 760w,
               /post/201907-google-traffic-director-practice/images/google/managed-instance-group-create_hu7a5985b254705ee9342af446179fac2f_146976_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201907-google-traffic-director-practice/images/google/managed-instance-group-create_hu7a5985b254705ee9342af446179fac2f_146976_a621c1d135015018899af14eb29bd4c3.webp&#34;
               width=&#34;571&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;托管式实例组提供的高级特性包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;高可用：可以配置为在多个区域内部署实例，配合负载均衡/健康检查功能，就可以实现全球范围内的区域感知负载均衡/异地容灾/故障转移&lt;/li&gt;
&lt;li&gt;自动伸缩：托管式实例组支持设置为固定的实例数，也支持自动伸缩，类似于 serverless ，根据指定的策略来实现虚拟机实例数的自动伸缩。&lt;/li&gt;
&lt;li&gt;健康检查：可以配置健康检查，配置负载均衡实现高可用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而所有这些高级特性都建立在一个最基本的特性上：托管式实例组必须有能力&lt;strong&gt;自动&lt;/strong&gt;实现虚拟机的系统搭建和应用的安装配置。对于 Google Traffic Director 应用，还必须做到能自动安装/配置envoy，启用iptables流量劫持。&lt;/p&gt;
&lt;p&gt;托管式实例组通过&lt;strong&gt;实例模版&lt;/strong&gt;来实现这一关键的自动化过程。&lt;/p&gt;
&lt;h3 id=&#34;实例模版instance-template&#34;&gt;实例模版/Instance Template&lt;/h3&gt;
&lt;p&gt;实例模版是用来创建虚拟机的模版，除了基本的虚拟机信息如机器硬件配置/操作系统/磁盘/网络等之外，还有特别的安全设置：身份和API访问权限中“服务账号”默认设置为使用“Compute Engine default service account”，“访问权限范围”要设置为“容许所有cloud api的全面访问权限”。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201907-google-traffic-director-practice/images/google/instance-template-create_huea5ae2bdd994dce26a56cad5b733bf2a_161993_98b9d2a6197cc0084ea5bb45f3a767b8.webp 400w,
               /post/201907-google-traffic-director-practice/images/google/instance-template-create_huea5ae2bdd994dce26a56cad5b733bf2a_161993_63ea199478f4e68f2f46dc37ab7c28c3.webp 760w,
               /post/201907-google-traffic-director-practice/images/google/instance-template-create_huea5ae2bdd994dce26a56cad5b733bf2a_161993_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201907-google-traffic-director-practice/images/google/instance-template-create_huea5ae2bdd994dce26a56cad5b733bf2a_161993_98b9d2a6197cc0084ea5bb45f3a767b8.webp&#34;
               width=&#34;479&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;然后重点是需要打开“管理、安全、磁盘、网络……”，在“管理”中，“启动脚本”处填入在这个虚拟机上安装配置应用服务的脚本。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201907-google-traffic-director-practice/images/google/instance-template-manage_huddfd08010235c63e9ec4d3c225958d08_83500_6d14c364156e220cd246b51c2847b041.webp 400w,
               /post/201907-google-traffic-director-practice/images/google/instance-template-manage_huddfd08010235c63e9ec4d3c225958d08_83500_83ffeaaf050f12ea4f7e3a40977765d7.webp 760w,
               /post/201907-google-traffic-director-practice/images/google/instance-template-manage_huddfd08010235c63e9ec4d3c225958d08_83500_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201907-google-traffic-director-practice/images/google/instance-template-manage_huddfd08010235c63e9ec4d3c225958d08_83500_6d14c364156e220cd246b51c2847b041.webp&#34;
               width=&#34;744&#34;
               height=&#34;457&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在google traffic director的文档中，给出的案例是安装apache模拟服务器端，然后安装并启动envoy。&lt;/p&gt;
&lt;p&gt;这里的启动脚本就是我们前面验证 google traffic director 工作方式时一系列的命令，在 google traffic director的文档&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cloud.google.com/traffic-director/docs/set-up-gce-vms#creating_the_instance_template&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://cloud.google.com/traffic-director/docs/set-up-gce-vms#creating_the_instance_template&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;中有详细的脚本内容（注意里面有一个错误的地方，前面我们验证时有修订）。&lt;/p&gt;
&lt;p&gt;TODO：页面上还有一“将容器镜像部署到此虚拟机”的功能，推测应该可以实现类似功能，后续再研究。&lt;/p&gt;
&lt;h3 id=&#34;路由规则&#34;&gt;路由规则&lt;/h3&gt;
&lt;p&gt;Google Traffic Director 中通过路由规则来决定流量的目的地服务，在 Google Traffic Director 的控制台上可以通过设置路由规则，容许设置多个路由规则，每个路由规则可以关联多个服务。&lt;/p&gt;
&lt;p&gt;下图是我建立的实例规则，转发规则为 http协议 + 80 端口，内部IP设置为 0.0.0.0，这样 Traffic Director 会根据HTTP请求的 Host/Path 信息来匹配路由规则，如下图我将三个不同的 host 指向不同的三个服务。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201907-google-traffic-director-practice/images/google/route-rule_huba0e9ae5910cd4da9ca0ba21e2ef60a3_85440_28cb7034d9ccfa1e321609e714d04948.webp 400w,
               /post/201907-google-traffic-director-practice/images/google/route-rule_huba0e9ae5910cd4da9ca0ba21e2ef60a3_85440_c726ed35a81937cef2338ebf3e128b26.webp 760w,
               /post/201907-google-traffic-director-practice/images/google/route-rule_huba0e9ae5910cd4da9ca0ba21e2ef60a3_85440_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201907-google-traffic-director-practice/images/google/route-rule_huba0e9ae5910cd4da9ca0ba21e2ef60a3_85440_28cb7034d9ccfa1e321609e714d04948.webp&#34;
               width=&#34;760&#34;
               height=&#34;494&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;有个特别的地方，路由规则中强制要求一定要提供一个缺省的目的地服务，即任何没有和其他匹配规则匹配的请求都将默认去到这个服务，而不是通常的做法报错404。经过确认，在 Traffic Director 下发给 Envoy 的配置中，会有额外的一个名为 “_default” 的路由规则：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;dynamic_route_configs&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;       &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;_default&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;domains&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;routes&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;match&amp;#34;: &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;prefix&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;route&amp;#34;: &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;cluster&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;cloud-internal-istio:cloud_mp_705219407589_7507573930487991268&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;暂时没有想明白 Traffic Director 做这个强制的出发点是什么。&lt;/p&gt;
&lt;h3 id=&#34;traffic-director工作模式总结&#34;&gt;Traffic Director工作模式总结&lt;/h3&gt;
&lt;p&gt;Google Traffic Director的工作模式，在使用托管式实例组时能提供很多高级特性，有些特性的工作模式和配置我们可以从 容器/k8s/Istio 中找到类似之处，如下面所列：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;功能&lt;/th&gt;
&lt;th&gt;容器/k8s/Istio&lt;/th&gt;
&lt;th&gt;Google Traffic Director&lt;br/&gt;虚拟机模式&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;准备操作系统&lt;/td&gt;
&lt;td&gt;镜像文件的基础镜像&lt;/td&gt;
&lt;td&gt;实例模版的操作系统配置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;准备硬件&lt;/td&gt;
&lt;td&gt;容器的硬件配置&lt;/td&gt;
&lt;td&gt;实例模版的硬件配置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;准备应用&lt;/td&gt;
&lt;td&gt;打包到容器的镜像文件中&lt;br/&gt;（事实上也是一组命令）&lt;/td&gt;
&lt;td&gt;以自动启动脚本的方式&lt;br/&gt;获取/安装/配置应用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;启动应用程序&lt;/td&gt;
&lt;td&gt;启动业务的容器&lt;/td&gt;
&lt;td&gt;按照实例模版启动虚拟机+应用&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;管理实例副本&lt;br/&gt;（固定）&lt;/td&gt;
&lt;td&gt;k8s replicaset&lt;/td&gt;
&lt;td&gt;通过实例模版设置实例数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;管理实例副本&lt;br/&gt;（自动伸缩）&lt;/td&gt;
&lt;td&gt;k8s HPA或者serverless&lt;/td&gt;
&lt;td&gt;通过实例模版设置自动伸缩&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;服务定义&lt;/td&gt;
&lt;td&gt;k8s service&lt;/td&gt;
&lt;td&gt;Google Traffic Director 服务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;创建服务&lt;/td&gt;
&lt;td&gt;通过 k8s&lt;/td&gt;
&lt;td&gt;在 Google Traffic Director &lt;br/&gt;控制台手工创建&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;服务注册&lt;/td&gt;
&lt;td&gt;通过k8s自动注册&lt;/td&gt;
&lt;td&gt;在 Google Traffic Director 控制台&lt;br/&gt;手工关联服务和托管实例组&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;监控检查&lt;/td&gt;
&lt;td&gt;k8s进行健康检查，支持自动修复&lt;/td&gt;
&lt;td&gt;通过托管式实例组配置健康检查，支持自动修复&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;服务发现&lt;/td&gt;
&lt;td&gt;通过Istio Pilot 下发，xDS协议&lt;/td&gt;
&lt;td&gt;通过 Traffic Director，兼容xDS协议&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;服务调用&lt;/td&gt;
&lt;td&gt;流量劫持（iptables） + Sidecar（envoy）&lt;/td&gt;
&lt;td&gt;流量劫持（iptables） + Sidecar（envoy）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;数据平面API&lt;/td&gt;
&lt;td&gt;Envoy xDS v2&lt;/td&gt;
&lt;td&gt;Envoy xDS v2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;应用版本升级&lt;/td&gt;
&lt;td&gt;更改镜像文件，支持滚动升级&lt;/td&gt;
&lt;td&gt;更改实例模版，托管式实例组支持滚动升级&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;高可用&lt;/td&gt;
&lt;td&gt;k8s联邦 / Istio多集群 / 区域感知负载均衡&lt;/td&gt;
&lt;td&gt;通过托管式实例组支持多区域部署实例&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;灰度发布&lt;/td&gt;
&lt;td&gt;通过Istio支持&lt;/td&gt;
&lt;td&gt;通过托管式实例组支持&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;指定路由规则&lt;/td&gt;
&lt;td&gt;通过Istio CRD，功能非常丰富&lt;/td&gt;
&lt;td&gt;通过 Traffic Director 控制台设置路由规则，功能简单&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;实践在vm上使用traffic-director&#34;&gt;实践：在VM上使用Traffic Director&lt;/h2&gt;
&lt;p&gt;在VM上使用Traffic Director的整个过程，可以参考 Google Traffic Director 的官方文档：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cloud.google.com/traffic-director/docs/set-up-gce-vms&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://cloud.google.com/traffic-director/docs/set-up-gce-vms&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;但是特别强调：要看英文文档，不要参考中文文档，中文文档容易过期（不要问我是怎么知道的^0^）。当然，英文文档也有错误，但是英文文档更新很快。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这里有个花絮，我在6月28号操作时，卡在英文文档的错误下，后来一步一步验证才把错误的地方慢慢的一一纠正过来。但是在29号写总结时，发现英文文档中有错误的地方有些已经被修订，文档的最后更新时间显示为6月28号，也就是我刚踩完坑它就更新了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;在vm上安装-traffic-director-应用&#34;&gt;在VM上安装 Traffic Director 应用&lt;/h3&gt;
&lt;p&gt;为了演示 Traffic Director 的使用，我建立了三个Traffic Director 应用程序，步骤如下（操作细节前面都给出了，这里就直接给结果了）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;先建立实例模版：使用 Traffic Director 官方文档的实例，用一个apache服务器模拟服务器端应用&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201907-google-traffic-director-practice/images/google/practice-instance-template_hua8736fd46a86a2a86b4079a3f37f9da7_44718_62c14179b879b5dbb0d3127736d911a3.webp 400w,
               /post/201907-google-traffic-director-practice/images/google/practice-instance-template_hua8736fd46a86a2a86b4079a3f37f9da7_44718_c583e56a74c1773e58802d8754052ba0.webp 760w,
               /post/201907-google-traffic-director-practice/images/google/practice-instance-template_hua8736fd46a86a2a86b4079a3f37f9da7_44718_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201907-google-traffic-director-practice/images/google/practice-instance-template_hua8736fd46a86a2a86b4079a3f37f9da7_44718_62c14179b879b5dbb0d3127736d911a3.webp&#34;
               width=&#34;760&#34;
               height=&#34;103&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;使用实例模版建立三个托管式实例组：简单起见都使用上面的实例模版，真实应用是使用各自的模版&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201907-google-traffic-director-practice/images/google/practice-instance-group_hu2d2918fbfe1a1bda96961f1e8df2722a_51552_84e017e6cad3976f7e87f8543790a546.webp 400w,
               /post/201907-google-traffic-director-practice/images/google/practice-instance-group_hu2d2918fbfe1a1bda96961f1e8df2722a_51552_fb0c72a0af35dd1dcaacc3129480c5dc.webp 760w,
               /post/201907-google-traffic-director-practice/images/google/practice-instance-group_hu2d2918fbfe1a1bda96961f1e8df2722a_51552_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201907-google-traffic-director-practice/images/google/practice-instance-group_hu2d2918fbfe1a1bda96961f1e8df2722a_51552_84e017e6cad3976f7e87f8543790a546.webp&#34;
               width=&#34;760&#34;
               height=&#34;146&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;简单起见没有开启自动伸缩，每个实例组我固定为两个实例，下面是三个实例组启动完成之后的6个虚拟机实例：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201907-google-traffic-director-practice/images/google/practice-vm-instance-list_hu80aef5d603f95f21020bfc3ad75810fb_77973_c47db76744aeef35856ae1509f80415f.webp 400w,
               /post/201907-google-traffic-director-practice/images/google/practice-vm-instance-list_hu80aef5d603f95f21020bfc3ad75810fb_77973_d36f207a1b2966b76b27c026d43f6101.webp 760w,
               /post/201907-google-traffic-director-practice/images/google/practice-vm-instance-list_hu80aef5d603f95f21020bfc3ad75810fb_77973_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201907-google-traffic-director-practice/images/google/practice-vm-instance-list_hu80aef5d603f95f21020bfc3ad75810fb_77973_c47db76744aeef35856ae1509f80415f.webp&#34;
               width=&#34;760&#34;
               height=&#34;217&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在Traffic Director中新建三个服务，分别使用上面三个托管式实例组，并设置路由规则&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201907-google-traffic-director-practice/images/google/practice-route-rule_huf304f729b7381175796540c905a25353_19716_f813d100e776fdf818899a2214a1ffda.webp 400w,
               /post/201907-google-traffic-director-practice/images/google/practice-route-rule_huf304f729b7381175796540c905a25353_19716_959180862ce1c133f04629bb331b9ae0.webp 760w,
               /post/201907-google-traffic-director-practice/images/google/practice-route-rule_huf304f729b7381175796540c905a25353_19716_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201907-google-traffic-director-practice/images/google/practice-route-rule_huf304f729b7381175796540c905a25353_19716_f813d100e776fdf818899a2214a1ffda.webp&#34;
               width=&#34;617&#34;
               height=&#34;139&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;为了对比，再建立两台虚拟机，一台配置有 envoy 和流量劫持（也就是前面我们验证 traffic director 工作方式的虚拟机），一台没有配置envoy和流量劫持。&lt;/p&gt;
&lt;h3 id=&#34;模拟请求处理流程&#34;&gt;模拟请求处理流程&lt;/h3&gt;
&lt;p&gt;首先在没有安装envoy的虚拟机上，用curl命令模拟客户端请求，分别连接上面6台虚拟机，响应如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ curl 10.128.0.17 -i
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;HTTP/1.1 &lt;span class=&#34;m&#34;&gt;200&lt;/span&gt; OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Date: Sun, &lt;span class=&#34;m&#34;&gt;30&lt;/span&gt; Jun &lt;span class=&#34;m&#34;&gt;2019&lt;/span&gt; 11:06:36 GMT
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Server: Apache/2.4.29 &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;Ubuntu&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Last-Modified: Sat, &lt;span class=&#34;m&#34;&gt;29&lt;/span&gt; Jun &lt;span class=&#34;m&#34;&gt;2019&lt;/span&gt; 03:10:41 GMT
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;ETag: &lt;span class=&#34;s2&#34;&gt;&amp;#34;50-58c6dbd7abfdd&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Accept-Ranges: bytes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Content-Length: &lt;span class=&#34;m&#34;&gt;80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Vary: Accept-Encoding
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;Content-Type: text/html
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;!doctype html&amp;gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;ratings-instance-group-1-gksm&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中 Server Header 的信息是 apache，注意body内部中打印的 host 信息表明了服务器端的地址，如 ratings-instance-group-1-gksm。&lt;/p&gt;
&lt;p&gt;然后对比，在安装了Envoy和流量劫持的虚拟机上，我们同样通过curl命令模拟客户端请求，这是需要添加 Host header来指明目标服务：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;$ curl 10.128.0.1 -H &lt;span class=&#34;s2&#34;&gt;&amp;#34;Host: ratings&amp;#34;&lt;/span&gt; -i
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;HTTP/1.1 &lt;span class=&#34;m&#34;&gt;200&lt;/span&gt; OK
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;date: Sun, &lt;span class=&#34;m&#34;&gt;30&lt;/span&gt; Jun &lt;span class=&#34;m&#34;&gt;2019&lt;/span&gt; 11:11:17 GMT
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;server: envoy
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;last-modified: Sat, &lt;span class=&#34;m&#34;&gt;29&lt;/span&gt; Jun &lt;span class=&#34;m&#34;&gt;2019&lt;/span&gt; 03:10:41 GMT
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;etag: &lt;span class=&#34;s2&#34;&gt;&amp;#34;50-58c6dbd7abfdd&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;accept-ranges: bytes
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;content-length: &lt;span class=&#34;m&#34;&gt;80&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;vary: Accept-Encoding
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;content-type: text/html
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&amp;lt;!doctype html&amp;gt;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;ratings-instance-group-1-gksm&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;验证中发现:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;curl命令使用的 ip 地址并不要求正确，只要在 “SERVICE_CIDR” 的范围内即可，如我设置的SERVICE_CIDR为 &amp;ldquo;10.128.0.1/16”。从文档中看到，如果路由规则中的IP地址设置为 0.0.0.0，则请求的IP地址不会被envoy使用，envoy会通过 Host 和 Path 来进行路由，所以这个IP地址是什么完全不重要。&lt;/p&gt;
&lt;p&gt;备注：这里我没有找到 traffic director 中配置服务 &lt;strong&gt;虚拟IP&lt;/strong&gt; 的方式（类似 k8s service 的 cluster ip），如果 traffic director 的服务有虚拟ip并且能够和DNS集成，则可以通过  &lt;code&gt;curl ratings &lt;/code&gt; 这样的方式访问，开发体验会更好。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;应答中的 server header 已经修改为 envoy，不再是 apache&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;多次执行，应答中的 rating 服务器的 host 地址会在当前两个虚拟机实例中轮流出现，看来默认的负载均衡算法是轮询&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;将请求中的 Host header 换成其他服务名，如 detais/reviews，则会访问到其他服务的实例，验证了 envoy 的确是通过 host 来进行路由&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;将请求中的 Host header 换成一个不存在的服务名，如 aaaaa，则会访问到 路由规则 中强制要求指定的缺省服务&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;检查-envoy-的配置&#34;&gt;检查 envoy 的配置&lt;/h3&gt;
&lt;p&gt;对于路由规则，最直接的方式就是dump下来 envoy 的配置，看看  traffic director 的控制平面最终给 envoy 下发的配置，因为内容太长，就不都贴出来了，只看最关注的路由配置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;dynamic_route_configs&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;route_config&amp;#34;: &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;// 说明配置信息来自 google traffic director 中配置的名为 http-rule 的路由规则&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;URL_MAP/705219407589.http-rule&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;virtual_hosts&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;       &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;host_2534861607986333440&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;domains&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;reviews&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;		  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;// 对reviews服务的路由&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;routes&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;match&amp;#34;: &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;prefix&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;route&amp;#34;: &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;cluster&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;cloud-internal-istio:cloud_mp_705219407589_7507573930487991268&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;       &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;       &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;host_3289472182735543541&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;domains&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;details&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;// 对details服务的路由&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;routes&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;match&amp;#34;: &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;prefix&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;route&amp;#34;: &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;cluster&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;cloud-internal-istio:cloud_mp_705219407589_9114389520261341891&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;       &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;       &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;host_3170996105491916824&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;domains&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ratings&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;// 对ratings服务的路由&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;routes&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;match&amp;#34;: &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;prefix&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;route&amp;#34;: &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;cluster&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;cloud-internal-istio:cloud_mp_705219407589_4125301658927778747&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;       &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;       &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;name&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;_default&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;// traffic director中强制必须设置的缺省服务，我设置为 reviews 服务&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;domains&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;routes&amp;#34;: &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;match&amp;#34;: &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;prefix&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;}&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;route&amp;#34;: &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;// 因此路由到 reviews 服务的集群去了&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;cluster&amp;#34;: &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;cloud-internal-istio:cloud_mp_705219407589_7507573930487991268&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;           &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;       &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;参照我在 google traffic director 中配置的名为 http-rule 的路由规则的详细信息，就容易看出两者的对比关系了：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201907-google-traffic-director-practice/images/google/route-rule_huba0e9ae5910cd4da9ca0ba21e2ef60a3_85440_28cb7034d9ccfa1e321609e714d04948.webp 400w,
               /post/201907-google-traffic-director-practice/images/google/route-rule_huba0e9ae5910cd4da9ca0ba21e2ef60a3_85440_c726ed35a81937cef2338ebf3e128b26.webp 760w,
               /post/201907-google-traffic-director-practice/images/google/route-rule_huba0e9ae5910cd4da9ca0ba21e2ef60a3_85440_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201907-google-traffic-director-practice/images/google/route-rule_huba0e9ae5910cd4da9ca0ba21e2ef60a3_85440_28cb7034d9ccfa1e321609e714d04948.webp&#34;
               width=&#34;760&#34;
               height=&#34;494&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;验证非托管式实例组&#34;&gt;验证非托管式实例组&lt;/h3&gt;
&lt;p&gt;验证了一下非托管式实例组在 google traffic director 中的使用，没有问题，可以新建 google traffic director 的服务，然后选择非托管式实例组，同样的方式设置好这个使用非托管式实例组的服务的路由规则之后，请求可以正常处理。&lt;/p&gt;
&lt;p&gt;只是非托管式实例组，会少很多高级特性。&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;对 google traffic director 的调研在6月底完成，这篇操作记录性质的博客文档的草稿编写完成于7月7号。但是由于一直没能完成这篇稿件的总结，因此一直以草稿的方式存在github中未能公开发表。&lt;/p&gt;
&lt;p&gt;直到8月份在做 &lt;a href=&#34;../../talk/201908-servicemesh-development-trend2/&#34;&gt;“Service Mesh发展趋势(续)：棋到中盘路往何方”&lt;/a&gt; 主题演讲时，才将总结部分完成。因此，如果您阅读完这篇实践篇之后，继续对 google traffic director 支持虚拟机的分析和总结有兴趣，请阅读这个主题演讲文字稿的第三个部分：“ServiceMesh灵魂拷问三：要不要支持虚拟机？”。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[图] 离大神最近的一次：kubecon大会Linus清晰近照</title>
      <link>https://skyao.net/post/201906-kubecon-linus-photo/</link>
      <pubDate>Thu, 27 Jun 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201906-kubecon-linus-photo/</guid>
      <description>&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;6月25号，kubecon 上海，世博中心，大会堂（红厅/Red Hall），个人平生第一次近距离瞻仰大神 Linus Torvalds，并有幸拍下下面照片。&lt;/p&gt;
&lt;p&gt;当时现场通过微信实时分享了出来，后来被很多人/很多群转发，相信很多同学可能已经见过这组照片了。考虑到微信图片压缩的厉害，我现在重新发出来一次，包括3000万像素的原图。&lt;/p&gt;
&lt;p&gt;照片说明：当时刚好手上拿着佳能 EOS R 和 EF 135L F2 镜头，开始在后排太远拍摄效果不佳，后来冲动了一下，很小心的冲到第一排位置。现场如果有同学注意到当时第一排靠右边过道的位置有个半蹲着的手举相机的人，没错，就是在下 :)&lt;/p&gt;
&lt;h2 id=&#34;图片&#34;&gt;图片&lt;/h2&gt;
&lt;p&gt;文字不重要，请看图：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;3C2A9214&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/3C2A9214_hub0a9ce1f23f177b6c97d7a7d04cb440c_364207_f55aab51d4e03c18d9e2ad6508708df1.webp 400w,
               /post/201906-kubecon-linus-photo/images/3C2A9214_hub0a9ce1f23f177b6c97d7a7d04cb440c_364207_543084ac06a33f9a011259a8ed477f90.webp 760w,
               /post/201906-kubecon-linus-photo/images/3C2A9214_hub0a9ce1f23f177b6c97d7a7d04cb440c_364207_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/3C2A9214_hub0a9ce1f23f177b6c97d7a7d04cb440c_364207_f55aab51d4e03c18d9e2ad6508708df1.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;3C2A9215&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/3C2A9215_hu4c06fac2ef7545d322887fff9293938e_552911_df876b2bca594a91c5665a5658ed6a06.webp 400w,
               /post/201906-kubecon-linus-photo/images/3C2A9215_hu4c06fac2ef7545d322887fff9293938e_552911_b04c22f3637d63ba0b61a20ae101dc2b.webp 760w,
               /post/201906-kubecon-linus-photo/images/3C2A9215_hu4c06fac2ef7545d322887fff9293938e_552911_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/3C2A9215_hu4c06fac2ef7545d322887fff9293938e_552911_df876b2bca594a91c5665a5658ed6a06.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;3C2A9216&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/3C2A9216_hu259617eff19903b28b37bbb7e63351c0_332203_d81446c2df986179132974770df8b223.webp 400w,
               /post/201906-kubecon-linus-photo/images/3C2A9216_hu259617eff19903b28b37bbb7e63351c0_332203_bef772c1afa689b146678ccbccffae46.webp 760w,
               /post/201906-kubecon-linus-photo/images/3C2A9216_hu259617eff19903b28b37bbb7e63351c0_332203_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/3C2A9216_hu259617eff19903b28b37bbb7e63351c0_332203_d81446c2df986179132974770df8b223.webp&#34;
               width=&#34;507&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;3C2A9218&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/3C2A9218_hu67c9d7a04a4a7bb12552ee0d8ec12ffe_536835_50219321f6f9b93225e3c43429ff5038.webp 400w,
               /post/201906-kubecon-linus-photo/images/3C2A9218_hu67c9d7a04a4a7bb12552ee0d8ec12ffe_536835_42b3e263c0fc6d3a7a8fbf8bc2df972f.webp 760w,
               /post/201906-kubecon-linus-photo/images/3C2A9218_hu67c9d7a04a4a7bb12552ee0d8ec12ffe_536835_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/3C2A9218_hu67c9d7a04a4a7bb12552ee0d8ec12ffe_536835_50219321f6f9b93225e3c43429ff5038.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;3C2A9219&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/3C2A9219_hucb9e864f667dfc2df3db3a441d22047b_383048_f07e8d4c396d00724b52283ba24a5a55.webp 400w,
               /post/201906-kubecon-linus-photo/images/3C2A9219_hucb9e864f667dfc2df3db3a441d22047b_383048_d9c208a517ddb76b2e77de54f6bb0241.webp 760w,
               /post/201906-kubecon-linus-photo/images/3C2A9219_hucb9e864f667dfc2df3db3a441d22047b_383048_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/3C2A9219_hucb9e864f667dfc2df3db3a441d22047b_383048_f07e8d4c396d00724b52283ba24a5a55.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;3C2A9220&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/3C2A9220_hu6cdc1937ce8578b94070bacbf621b4e8_428720_c3cc662c872b0a277275265619439b57.webp 400w,
               /post/201906-kubecon-linus-photo/images/3C2A9220_hu6cdc1937ce8578b94070bacbf621b4e8_428720_6126c38c3451c0c4fc3ba31fe8ebdbdb.webp 760w,
               /post/201906-kubecon-linus-photo/images/3C2A9220_hu6cdc1937ce8578b94070bacbf621b4e8_428720_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/3C2A9220_hu6cdc1937ce8578b94070bacbf621b4e8_428720_c3cc662c872b0a277275265619439b57.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;3C2A9221&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/3C2A9221_huf7980f555b3267e60029630be3707d37_377670_653393a72abd79241dc9423f6a662b2d.webp 400w,
               /post/201906-kubecon-linus-photo/images/3C2A9221_huf7980f555b3267e60029630be3707d37_377670_d1ecafb3203d8f1c3fb6f4be287c98d1.webp 760w,
               /post/201906-kubecon-linus-photo/images/3C2A9221_huf7980f555b3267e60029630be3707d37_377670_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/3C2A9221_huf7980f555b3267e60029630be3707d37_377670_653393a72abd79241dc9423f6a662b2d.webp&#34;
               width=&#34;507&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;3C2A9222&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/3C2A9222_hu24e654d50a51a244701a50b3b1f0dd70_392684_e8f876caf80f8afcd14d3098fda9a98b.webp 400w,
               /post/201906-kubecon-linus-photo/images/3C2A9222_hu24e654d50a51a244701a50b3b1f0dd70_392684_5f3b67a1d27d60e03901dd8acc691609.webp 760w,
               /post/201906-kubecon-linus-photo/images/3C2A9222_hu24e654d50a51a244701a50b3b1f0dd70_392684_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/3C2A9222_hu24e654d50a51a244701a50b3b1f0dd70_392684_e8f876caf80f8afcd14d3098fda9a98b.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;3C2A9223&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/3C2A9223_hue5dc6aca1daf5e64441ec1208e917ad5_397708_8a5821247db15cb7be5b7b4b89bab88a.webp 400w,
               /post/201906-kubecon-linus-photo/images/3C2A9223_hue5dc6aca1daf5e64441ec1208e917ad5_397708_781ac8076bcb75a51ae75284761d4798.webp 760w,
               /post/201906-kubecon-linus-photo/images/3C2A9223_hue5dc6aca1daf5e64441ec1208e917ad5_397708_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/3C2A9223_hue5dc6aca1daf5e64441ec1208e917ad5_397708_8a5821247db15cb7be5b7b4b89bab88a.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;3C2A9224&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/3C2A9224_huf279dd73570b5d7ebc5c5aa1d64f1862_400399_9d553bd8e1d8a5497dbc0a1160dacb52.webp 400w,
               /post/201906-kubecon-linus-photo/images/3C2A9224_huf279dd73570b5d7ebc5c5aa1d64f1862_400399_019a19a86479c8f845e96c40174bcbfb.webp 760w,
               /post/201906-kubecon-linus-photo/images/3C2A9224_huf279dd73570b5d7ebc5c5aa1d64f1862_400399_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/3C2A9224_huf279dd73570b5d7ebc5c5aa1d64f1862_400399_9d553bd8e1d8a5497dbc0a1160dacb52.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;3C2A9226&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/3C2A9226_hub9fd9421c8904d26716e8bba5463e506_443072_0c8bad2844cfcbe455eb0321d8e32055.webp 400w,
               /post/201906-kubecon-linus-photo/images/3C2A9226_hub9fd9421c8904d26716e8bba5463e506_443072_9ebeba087e783def43c6d5d88a795f1b.webp 760w,
               /post/201906-kubecon-linus-photo/images/3C2A9226_hub9fd9421c8904d26716e8bba5463e506_443072_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/3C2A9226_hub9fd9421c8904d26716e8bba5463e506_443072_0c8bad2844cfcbe455eb0321d8e32055.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;3C2A9228&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/3C2A9228_huc1ee26d8be63be91f0179004f1ab01d1_442868_149bcd35bde456f8fa7d39a4205e4ba3.webp 400w,
               /post/201906-kubecon-linus-photo/images/3C2A9228_huc1ee26d8be63be91f0179004f1ab01d1_442868_a4a26db4147c42d9cb7334af2c00db0b.webp 760w,
               /post/201906-kubecon-linus-photo/images/3C2A9228_huc1ee26d8be63be91f0179004f1ab01d1_442868_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/3C2A9228_huc1ee26d8be63be91f0179004f1ab01d1_442868_149bcd35bde456f8fa7d39a4205e4ba3.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;3C2A9231&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/3C2A9231_hu365ac83a9cdefd3ba77872893dd3aad5_460672_49ad95cdcc2802599b0ca87d162fb77f.webp 400w,
               /post/201906-kubecon-linus-photo/images/3C2A9231_hu365ac83a9cdefd3ba77872893dd3aad5_460672_7d682d74bbfad939078c648fe25e449f.webp 760w,
               /post/201906-kubecon-linus-photo/images/3C2A9231_hu365ac83a9cdefd3ba77872893dd3aad5_460672_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/3C2A9231_hu365ac83a9cdefd3ba77872893dd3aad5_460672_49ad95cdcc2802599b0ca87d162fb77f.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;3C2A9232&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/3C2A9232_hu5ca75bdafeb0c8ca867e6d2e382d1724_506018_7a0f573d7e3e29f415b3ad0b6de22f2c.webp 400w,
               /post/201906-kubecon-linus-photo/images/3C2A9232_hu5ca75bdafeb0c8ca867e6d2e382d1724_506018_8f8071691e445a53db717dd09b65e23a.webp 760w,
               /post/201906-kubecon-linus-photo/images/3C2A9232_hu5ca75bdafeb0c8ca867e6d2e382d1724_506018_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/3C2A9232_hu5ca75bdafeb0c8ca867e6d2e382d1724_506018_7a0f573d7e3e29f415b3ad0b6de22f2c.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;3C2A9233&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/3C2A9233_hub43804b2c6d42eae48c4c4ce828eef52_426333_53a5ab988243b2e5ccde71ad89a249c1.webp 400w,
               /post/201906-kubecon-linus-photo/images/3C2A9233_hub43804b2c6d42eae48c4c4ce828eef52_426333_f2e02953a385b3f38527f67928d34d77.webp 760w,
               /post/201906-kubecon-linus-photo/images/3C2A9233_hub43804b2c6d42eae48c4c4ce828eef52_426333_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/3C2A9233_hub43804b2c6d42eae48c4c4ce828eef52_426333_53a5ab988243b2e5ccde71ad89a249c1.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;原图下载&#34;&gt;原图下载&lt;/h2&gt;
&lt;p&gt;清晰大图因文件太大，请通过百度盘下载。&lt;/p&gt;
&lt;p&gt;链接: &lt;a href=&#34;https://pan.baidu.com/s/1o2HlHhM13_p622ocJS9YBQ&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://pan.baidu.com/s/1o2HlHhM13_p622ocJS9YBQ&lt;/a&gt; 提取码: i9a3&lt;/p&gt;
&lt;p&gt;也可以使用微信扫一扫即可获取文件：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201906-kubecon-linus-photo/images/qrcode_hu1782d00520721ff4b99de9bf80a82b79_58212_4b67149c43044a3dd7d468f6dacd6914.webp 400w,
               /post/201906-kubecon-linus-photo/images/qrcode_hu1782d00520721ff4b99de9bf80a82b79_58212_9cc587420f4a592c193452a70ac3374a.webp 760w,
               /post/201906-kubecon-linus-photo/images/qrcode_hu1782d00520721ff4b99de9bf80a82b79_58212_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-kubecon-linus-photo/images/qrcode_hu1782d00520721ff4b99de9bf80a82b79_58212_4b67149c43044a3dd7d468f6dacd6914.webp&#34;
               width=&#34;280&#34;
               height=&#34;280&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;版权申明&#34;&gt;版权申明&lt;/h2&gt;
&lt;p&gt;上述图片为本人亲手拍摄，大家可以自由使用，但各商业收费图片网站请勿收集和二次发布。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Service Mesh Interface详细介绍</title>
      <link>https://skyao.net/post/201906-service-mesh-interface-detail/</link>
      <pubDate>Wed, 05 Jun 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201906-service-mesh-interface-detail/</guid>
      <description>&lt;h2 id=&#34;smi介绍&#34;&gt;SMI介绍&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201906-service-mesh-interface-detail/images/smi-logo_0_hu3a87f8245ab3762330380eb775186217_149470_585ca065e3367befa987026cebbd945e.webp 400w,
               /post/201906-service-mesh-interface-detail/images/smi-logo_0_hu3a87f8245ab3762330380eb775186217_149470_4cc97beaa29e182badd06571c50fc4c7.webp 760w,
               /post/201906-service-mesh-interface-detail/images/smi-logo_0_hu3a87f8245ab3762330380eb775186217_149470_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-service-mesh-interface-detail/images/smi-logo_0_hu3a87f8245ab3762330380eb775186217_149470_585ca065e3367befa987026cebbd945e.webp&#34;
               width=&#34;760&#34;
               height=&#34;285&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;smi是什么&#34;&gt;SMI是什么？&lt;/h3&gt;
&lt;p&gt;5月21号，在 kubeconf上，微软联合一众小伙伴，宣布了 Service Mesh Interface，简称SMI。SMI是一个服务网格规范，定义了通用标准，包含基本特性以满足大多数场景下的通用需求。&lt;/p&gt;
&lt;p&gt;援引来自SMI官方网站  &lt;a href=&#34;https://smi-spec.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;smi-spec.io&lt;/a&gt; 的介绍资料，对 Service Mesh Interface 的定位是 ：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A standard interface for service meshes on Kubernetes.&lt;/p&gt;
&lt;p&gt;Kubernetes上的 service mesh 的标准接口&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;微软的 &lt;a href=&#34;https://msft.today/hello-service-mesh-interface-smi-a-specification-for-service-mesh-interoperability/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;官方博客文章&lt;/a&gt; 这样介绍SMI：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SMI定义了一组通用可移植的API，为开发人员提供跨不同服务网格技术的互通性，包括Istio，Linkerd和Consul Connect。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201906-service-mesh-interface-detail/images/smi_hu4a1aea9de87e1103a949eeacdea70aaa_120175_bc2571363464e8d5b62bdf320cb9e299.webp 400w,
               /post/201906-service-mesh-interface-detail/images/smi_hu4a1aea9de87e1103a949eeacdea70aaa_120175_51b3c071a69f0a5dbbf83f6b8201bc41.webp 760w,
               /post/201906-service-mesh-interface-detail/images/smi_hu4a1aea9de87e1103a949eeacdea70aaa_120175_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-service-mesh-interface-detail/images/smi_hu4a1aea9de87e1103a949eeacdea70aaa_120175_bc2571363464e8d5b62bdf320cb9e299.webp&#34;
               width=&#34;760&#34;
               height=&#34;408&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;SMI 是希望在各家 Service Mesh 的实现之上建立一个抽象的API层，然后通过这个抽象来解耦和屏蔽底层 Service Mesh 实现，让上层的应用、工具、生态系统可以建立在一个业界标准之上，从而实现跨不同实现的可移植性和互通性。&lt;/p&gt;
&lt;h3 id=&#34;smi推出的背景&#34;&gt;SMI推出的背景&lt;/h3&gt;
&lt;p&gt;&lt;a href=&#34;https://medium.com/@idit.levine_92620&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Idit Levine&lt;/a&gt;，初创公司 solo.io 的创始人兼CEO，作为SMI推出的重要力量之一，撰文描述了 SMI 推出的背景：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;服务网格生态系统正在兴起，众多的网格供应商和不同的用例需要不同的技术。所以问题来了：我们如何实现在不破坏最终用户体验的前提下促进行业创新？通过以一组标准API达成一致，我们可以提供互通性，并在不同网格以及为这些网格构建的工具之上维持最终用户体验。&lt;/p&gt;
&lt;p&gt;今天发布的 Service Mesh Interface（SMI）是使这一构想走向行业现实的重要一步。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下面这幅图片可以非常清晰的表述SMI的定位，也可以帮助我们一起来解读SMI推出的背景：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201906-service-mesh-interface-detail/images/SMI-Graphic_hu51597e352f0ba4b9470c8f9ea8aaa966_356378_7f7730d89113eeb1f71a4a4efd5b5ed6.webp 400w,
               /post/201906-service-mesh-interface-detail/images/SMI-Graphic_hu51597e352f0ba4b9470c8f9ea8aaa966_356378_793af15cf366821f1094197460bd42ca.webp 760w,
               /post/201906-service-mesh-interface-detail/images/SMI-Graphic_hu51597e352f0ba4b9470c8f9ea8aaa966_356378_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-service-mesh-interface-detail/images/SMI-Graphic_hu51597e352f0ba4b9470c8f9ea8aaa966_356378_7f7730d89113eeb1f71a4a4efd5b5ed6.webp&#34;
               width=&#34;760&#34;
               height=&#34;400&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Service Mesh的价值正在被普遍认可：从最早的Linkerd，Envoy，到两年前Google力推Istio，以及 Linkerd2 的推出，最近 AWS 推出了 App Mesh，Google 则将 Istio 搬上了Google Cloud 推出了 Istio 的公有云托管版本 Google Cloud Service Mesh，还推出了单独的控制平面产品 Google Traffic Director。微软也在去年推出了Azure完全托管版本的Service Fabric Mesh （预览版）。云市场三巨头都已经先后出手。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;市场上出现了众多的Service Mesh产品：开源的，闭源的，大公司出的，小公司出的，市场繁荣的同时也带来了市场碎片化的问题。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201906-service-mesh-interface-detail/images/smi-background_hu432db2da3bf62d5224437e236f008ab6_35075_2083b8ba4204da6cf8352d9fcf8d336b.webp 400w,
               /post/201906-service-mesh-interface-detail/images/smi-background_hu432db2da3bf62d5224437e236f008ab6_35075_ff57748d2da904fed30dbb288dcee8ab.webp 760w,
               /post/201906-service-mesh-interface-detail/images/smi-background_hu432db2da3bf62d5224437e236f008ab6_35075_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-service-mesh-interface-detail/images/smi-background_hu432db2da3bf62d5224437e236f008ab6_35075_2083b8ba4204da6cf8352d9fcf8d336b.webp&#34;
               width=&#34;760&#34;
               height=&#34;234&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;在云原生理念下，我们推崇应用轻量化，只关注业务逻辑。Service Mesh技术很好的实现了这一战略目标：运行在 service mesh 上的应用可以和底层 service mesh 的具体实现解耦。理论上应用在不同的 service mesh 实现上迁移是可行的，从这一点说，service mesh 在云原生的道路上迈出了重要一步。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;但是，所有围绕业务应用的外围工作，比如通过 service mesh对流量进行控制，配置各种安全/监控/策略等行为，以及在这些需求上建立起来的工具和生态系统，却不得不牢牢的绑死在某个具体的 service mesh实现上，所谓&amp;quot;供应商锁定&amp;quot;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;其根本问题在于各家实现不同，又没有统一标准。因此，要想解决上述问题，就必须釜底抽薪：&lt;strong&gt;解决 Service Mesh 的标准化问题&lt;/strong&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;微软给出的解决方案就是引入SMI，作为一个通用的行业规范/标准，如果能让各家 service mesh 提供商都遵循这个标准，则有机会在具体的 service mesh 产品之上，抽象出一个公共层（如定义一组通用可移植的API），屏蔽掉上层应用/工具/生态系统对具体  service mesh 产品的实现细节。&lt;/p&gt;
&lt;p&gt;是不是觉得 SMI 的概念有种熟悉的味道？是的，没错，类似的事情在k8s中之前就发生过很多次，比如 CNI、CRI、CSI，还有下图展示的 Ingress：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201906-service-mesh-interface-detail/images/smi-concept_hu6cae474c8c97eee9eeea634195c5ce9c_43127_e195eab6e7cd97fe504f00aafc12b1e1.webp 400w,
               /post/201906-service-mesh-interface-detail/images/smi-concept_hu6cae474c8c97eee9eeea634195c5ce9c_43127_627a793c9a4317ad018e90228543a77d.webp 760w,
               /post/201906-service-mesh-interface-detail/images/smi-concept_hu6cae474c8c97eee9eeea634195c5ce9c_43127_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-service-mesh-interface-detail/images/smi-concept_hu6cae474c8c97eee9eeea634195c5ce9c_43127_e195eab6e7cd97fe504f00aafc12b1e1.webp&#34;
               width=&#34;760&#34;
               height=&#34;416&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在SMI中，将这个目标称为 &amp;ldquo;&lt;strong&gt;Interoperability&lt;/strong&gt;&amp;rdquo; / 互通性。我个人理解，这其实和 google 一直在倡导的 &amp;ldquo;not lock-in&amp;rdquo; 是一个概念：有通用的社区标准/行业标准，在此基础上客户可以在多个实现/多个供应商之间自由选择和迁移，没有被绑定的风险，而且提供给用户的功能以及使用方式也保持一致，也就是 Idit Levine 所强调的 &amp;ldquo;维持最终用户体验&amp;rdquo;。&lt;/p&gt;
&lt;p&gt;从这个角度说，我很欣喜的看到 SMI 的推出，虽然这条路可能不是那么容易走，但是，的确，&amp;ldquo;Service Mesh Interface（SMI）是使这一构想走向行业现实的重要一步&amp;rdquo;。&lt;/p&gt;
&lt;h3 id=&#34;和通用数据平面api的关系&#34;&gt;和通用数据平面API的关系&lt;/h3&gt;
&lt;p&gt;在SMI提出来之前不久（大概早两个星期），CNCF也在进行类似的标准化操作：CNCF正在筹建通用数据平面API工作组（Universal Data Plane API Working Group / UDPA-WG)，以制定数据平面的标准API，为L4/L7数据平面配置提供事实上的标准，初始成员将包括 Envoy 和 gRPC 项目的代表。事实上是 Google 在驱动，主要参与的项目是 Istio 和 Envoy。&lt;/p&gt;
&lt;p&gt;下面这张图片展示UDPA 和 SMI 这两个新近推出的 Service Mesh 标准API的关系：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201906-service-mesh-interface-detail/images/two-api_hua970b559b9d743d44c34e6fbe181f921_10038_564b44ec944fc1ff3fe23653eaa39405.webp 400w,
               /post/201906-service-mesh-interface-detail/images/two-api_hua970b559b9d743d44c34e6fbe181f921_10038_9e21e958ea892d91b4a65fd5b5849086.webp 760w,
               /post/201906-service-mesh-interface-detail/images/two-api_hua970b559b9d743d44c34e6fbe181f921_10038_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-service-mesh-interface-detail/images/two-api_hua970b559b9d743d44c34e6fbe181f921_10038_564b44ec944fc1ff3fe23653eaa39405.webp&#34;
               width=&#34;600&#34;
               height=&#34;546&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Universal Data Plane API 是数据平面的标准，控制平面通过这个API来控制数据平面的行为。工作组的初始成员来自包括 Envoy 和 gRPC 项目的代表，&lt;strong&gt;背后的公司主要是 Google&lt;/strong&gt; 。&lt;/li&gt;
&lt;li&gt;Service Mesh Interface 是控制平面的标准，上层的应用/工具/生态体系通过 Service Mesh Interface 来实现跨不同的Service Mesh实现为最终用户提供一致性的体验。&lt;strong&gt;SMI由微软牵头&lt;/strong&gt;，联合 Linkerd，HashiCorp，Solo，Kinvolk和Weaveworks。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;smi的目标和愿景&#34;&gt;SMI的目标和愿景&lt;/h3&gt;
&lt;p&gt;关于 SMI 的目标和愿景，我援引  Idit Levine 的这段话（这段话也同样出现在 smi-spec 的 github 首页）：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SMI 是在 Kubernetes 上运行服务网格的规范。它定义了由各种供应商实现的通用标准。这使得最终用户的标准化和服务网格供应商的创新可以两全其美。SMI 实现了灵活性和互通性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;更详细而明确的目标描述来自 smi-spec 的 github 首页：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;目标&lt;/p&gt;
&lt;p&gt;SMI API的目标是提供一组通用的，可移植的Service Mesh API，Kubernetes用户可以以供应商无关的方式使用这些API。通过这种方式，可以定义使用Service Mesh技术的应用程序，而无需紧密绑定到任何特定实现。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;然后还特别强调：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;非目标&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SMI项目本身不实现服务网格&lt;/strong&gt;。SMI只是试图定义通用规范。同样，SMI不定义服务网格的具体范围，而是一个通用子集。 欢迎SMI供应商添加超出SMI规范的供应商特定扩展和API。 我们希望随着时间的推移，随着更多功能被普遍接受为服务网格的一部分，这些定义将迁移到SMI规范中。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;总结：首先非常明确的一点是，SMI是定义标准API，而不是标准实现。&lt;/p&gt;
&lt;p&gt;而 SMI 的具体目标，在 SMI 的官方网站是这样介绍的：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A standard interface for service meshes on Kubernetes: Kubernetes上的 service mesh 的标准接口&lt;/li&gt;
&lt;li&gt;A basic feature set for the most common service mesh use cases：用于最通用的服务网格用例的基本特性&lt;/li&gt;
&lt;li&gt;Flexibility to support new service mesh capabilities over time：随着时间的推移灵活地支持新的服务网格能力&lt;/li&gt;
&lt;li&gt;Space for the ecosystem to innovate with service mesh technology: 使用服务网格技术实现生态系统创新的空间&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;smi社区&#34;&gt;SMI社区&lt;/h3&gt;
&lt;p&gt;有需求，有市场，有想法，有目标，我们再来看看 SMI 阵营现在都有什么力量。&lt;/p&gt;
&lt;p&gt;微软在推出 SMI 时的描述到：SMI是一个开放项目，由微软，Linkerd，HashiCorp，Solo，Kinvolk和Weaveworks联合启动; 并得到了Aspen Mesh，Canonical，Docker，Pivotal，Rancher，Red Hat和VMware的支持。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201906-service-mesh-interface-detail/images/partnership_hub4457b7f81084c722c08045523aee746_100734_a766153b54f865e51e7f7ab944bc1754.webp 400w,
               /post/201906-service-mesh-interface-detail/images/partnership_hub4457b7f81084c722c08045523aee746_100734_71b279b770a212e9ad3905cea24bba0f.webp 760w,
               /post/201906-service-mesh-interface-detail/images/partnership_hub4457b7f81084c722c08045523aee746_100734_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-service-mesh-interface-detail/images/partnership_hub4457b7f81084c722c08045523aee746_100734_a766153b54f865e51e7f7ab944bc1754.webp&#34;
               width=&#34;760&#34;
               height=&#34;284&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;阵营还是挺强大的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;微软：SMI的带头大哥，云计算的三巨头之一&lt;/li&gt;
&lt;li&gt;Buoyant：Service Mesh 技术的拓荒牛 + 布道者，小而弥坚的初创公司，有一个不大但是力量很强又非常有经验还很务实的团队。其旗下的 Linkerd2 已经明确表示将支持 SMI。&lt;/li&gt;
&lt;li&gt;HashiCorp：大名鼎鼎的 consul 就出自这里，Consul Connect 也是目前活跃的 service mesh 实现之一，虽然Consul Connect在国内知名度和影响力都很小（也就年度总结的时候捎带着看一眼状态的那种）。Consul Connect 目前也表示提供了对 SMI 的支持。&lt;/li&gt;
&lt;li&gt;Solo.io：深藏不露的初创型小公司，&amp;ldquo;产品面很广，除了 Service Mesh 方面大有名气的 SuperGloo 和 Service Mesh hub 之外，还有远程调试、混沌工程、unikernels 以及微服务网关等几个产品。&amp;quot;（这段话我从秀龙的文章里面抄过来的，总结的很好）。另外，业界网红 Christian Posta 前段时间加入这家公司。solo公司旗下的 SuperGloo 是业界第一个 service mesh 编排产品，因此对 SMI 的热爱和支持是无可复加的。SuperGloo 和 Service Mesh Hub 已经实现了对 SMI 的支持。&lt;/li&gt;
&lt;li&gt;Mesery 和 Kinvolk：这两家公司最近在 service mesh社区有点名气，因为他们近期做了 Istio vs Linkerd 的性能测试并给出了报告，闹的满城风雨。而且他们也都喜欢用 solo 出的 SuperGloo（毕竟业界号称 service mesh 编排的也就独此一家）。&lt;/li&gt;
&lt;li&gt;Aspen Mesh： F5 （没错，就是那个巨贵的F5）出的的Istio商业版本。但是没有看到 Aspen Mesh 给出支持 SMI 的信息，暂时还不知道 Aspen Mesh 和 SMI 的关系。&lt;/li&gt;
&lt;li&gt;vmware：vmware在2018年底推出了 VMware NSX Service Mesh ，和Aspen Mesh一样也是基于 Istio 。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其他公司就不再一一列出来了，主要是不清楚他们在 SMI 这个事情上扮演什么角色。&lt;/p&gt;
&lt;p&gt;而关键点在于，Google （还有同属Istio阵营的 IBM / Lyft）不在其列。而 Service Mesh 的其他玩家，几乎都参与了 SMI，甚至包括原本在 Istio 项目上和 google 一直合作的公司，耐人寻味。&lt;/p&gt;
&lt;h2 id=&#34;smi规范内容&#34;&gt;SMI规范内容&lt;/h2&gt;
&lt;h3 id=&#34;smi规范介绍&#34;&gt;SMI规范介绍&lt;/h3&gt;
&lt;p&gt;Service Mesh Interface 规范涵盖最常见服务网格能力：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Traffic Policy/流量策略 - 跨服务应用身份和传输加密等策略&lt;/li&gt;
&lt;li&gt;Traffic Telemetry/流量遥测 - 捕获关键指标，如错误率和服务间的延迟&lt;/li&gt;
&lt;li&gt;Traffic Management/流量管理 - 在不同服务之间转移流量&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SMI规范由多个API组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Traffic Access Control/流量访问控制 - 根据客户端的身份配置对特定pod和路由的访问，以将应用程序锁定到仅允许的用户和服务。&lt;/li&gt;
&lt;li&gt;Traffic Specs/流量规范 - 定义流量的表示方式，基于每个协议的基础。 这些资源与访问控制和其他类型的策略协同工作，以在协议级别管理流量。&lt;/li&gt;
&lt;li&gt;Traffic Split/流量分割 - 逐步引导各种服务之间的流量百分比，以帮助构建金丝雀推出。&lt;/li&gt;
&lt;li&gt;Traffic Metrics/流量指标 - 暴露通用的流量指标，供dashboard和autoscaler等工具使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注意：SMI 被指定为 Kubernetes Custom Resource Definitions（CRD）和 Extension API Servers 的集合。 这些API可以安装到Kubernetes集群上，并使用标准工具进行操作。&lt;/p&gt;
&lt;p&gt;在设计上，SMI 强调 &amp;ldquo;Provider Agnostic（供应商无关）&amp;quot;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SMI API的目标是提供一组通用的可移植的服务网格API，Kubernetes用户可以以供应商无关的方式使用这些API。 通过这种方式，人们可以定义使用服务网格技术的应用程序，而无需紧密绑定到任何特定实现。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下面我们来详细看一下 SMI 规范的具体API定义，其定义来自https://github.com/deislabs/smi-spec 。&lt;/p&gt;
&lt;h3 id=&#34;traffic-spec&#34;&gt;Traffic Spec&lt;/h3&gt;
&lt;p&gt;Traffic Spec资源用于让用户定义流量。通常与Access Control（访问控制）和其他策略一起使用，以具体定义需要如何处理流经网格的特定类型流量。&lt;/p&gt;
&lt;p&gt;用户往往希望在服务网格内运行许多不同的协议。 当然，主要会是HTTP，但也会有其他协议。 Traffic Spec规范中的每个资源都旨在与特定协议1：1匹配。 这让用户可以以协议特定的方式来定义流量。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HTTPRouteGroup&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;HTTPRouteGroup 资源用于描述HTTP/1和HTTP/2流量，它枚举了应用程序可以提供的路由。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;specs.smi-spec.io/v1alpha1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;HTTPRouteGroup&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;the-routes&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;matches&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;metrics&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;pathRegex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/metrics&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;methods&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;GET&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;health&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;pathRegex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/ping&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;methods&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的例子定义两个&lt;code&gt;match&lt;/code&gt;，&lt;code&gt;metrics&lt;/code&gt;和&lt;code&gt;health&lt;/code&gt;。 name 字段是key，所有字段都是必需的。 正则表达式用于匹配URI。 HTTP Mesh可以具体制定如 &lt;code&gt;GET&lt;/code&gt; 或用 &lt;code&gt;*&lt;/code&gt; 来匹配所有。&lt;/p&gt;
&lt;p&gt;HTTPRouteGroup 当前的功能限制（未来会加入，只是当前作为第一个版本内容还比较少）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;只支持 HTTP 协议，连 gRPC 都还未支持&lt;/li&gt;
&lt;li&gt;&lt;code&gt;match&lt;/code&gt; 字段当前仅适用于 &lt;code&gt;URI&lt;/code&gt;。 很明显这是不够的，未来计划扩展以支持HTTP header，Host等。&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;个人看法：目前在只有 HTTP 协议支持，而且 HTTP 路由定义居然不支持 HTTP header 匹配，足够说明目前 SMI 的确是处于项目早期状态。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;TCPRoute&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;TCPRoute资源用于描述 L4 TCP流量。 这个路由极其简单（或者叫做简陋），定义应用程序接收到的原始的、无协议特征的流量。&lt;/p&gt;
&lt;p&gt;看完下面的yaml例子就明白为什么称为极其简单了：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;specs.smi-spec.io/v1alpha1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;TCPRoute&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;tcp-route&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;上面的路由只做了定义，尚未与任何资源相关联。 我们继续看如何使用，比如与Access Control 配合。&lt;/p&gt;
&lt;h3 id=&#34;traffic-access-control&#34;&gt;Traffic Access Control&lt;/h3&gt;
&lt;p&gt;Traffic Access Control 资源用来为应用程序定义访问控制策略：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;访问控制属于授权（authorization）范畴，默认身份验证（Authentication）已经由底层实现处理&lt;/li&gt;
&lt;li&gt;SMI规范中的访问控制是附加的，默认情况下&lt;strong&gt;拒绝所有流量&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;TrafficTarget 规范&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;TrafficTarget 规范用来定义流量访问控制，而 SMI 中访问控制是基于服务身份（service identity）的，并且目前只支持通过 Kubernetes service account 来指派服务身份（其他身份机制将在稍后支持）。&lt;/p&gt;
&lt;p&gt;流量访问控制有三个概念，分别在 TrafficTarget 中以三个字段定义：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Source：流量的来源，体现为具体的 Pod 列表，目前支持通过selector来实现，暂时不支持以资源的方式选择（如指定Deployment、指定Service）&lt;/li&gt;
&lt;li&gt;Destination：流量的目标，同样体现为具体的 Pod 列表，也只支持selector&lt;/li&gt;
&lt;li&gt;Route：流量规范，用来区分 Destination 提供的多种不同的流量访问方式，如下图中的api访问和获取metrics信息&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201906-service-mesh-interface-detail/images/smi-traffic-target_hu9c235f034760d8e5d89b04046e6e58e2_101156_be5fd37795957f385328b967223995a4.webp 400w,
               /post/201906-service-mesh-interface-detail/images/smi-traffic-target_hu9c235f034760d8e5d89b04046e6e58e2_101156_dd1ef129a690ec1f6c71b688419cb9b1.webp 760w,
               /post/201906-service-mesh-interface-detail/images/smi-traffic-target_hu9c235f034760d8e5d89b04046e6e58e2_101156_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-service-mesh-interface-detail/images/smi-traffic-target_hu9c235f034760d8e5d89b04046e6e58e2_101156_be5fd37795957f385328b967223995a4.webp&#34;
               width=&#34;760&#34;
               height=&#34;350&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在这个例子中，展示对api进行访问和获取metrics信息这两个操作的流量访问控制：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 定义TrafficSpec&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;specs.smi-spec.io/v1alpha1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;HTTPRouteGroup&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;api-service-routes&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;matches&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;api &lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# api访问的流量&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;pathRegex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;/api&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;methods&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;metrics&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 获取metrics的流量&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;pathRegex&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;/metrics&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;methods&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;TrafficTarget&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;access.smi-spec.io/v1alpha1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;api-service-metrics&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 定义获取metrics的Target&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;namespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;destination:	# 通过 ServiceAccount 选择pods&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ServiceAccount&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;api-service&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;namespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;specs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 引用traficSec定义的route，指定为获取metrics&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;HTTPRouteGroup&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;api-service-routes&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;matches&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;metrics&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;sources&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 通过 ServiceAccount 选择pods&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ServiceAccount&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;prometheus&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;namespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nn&#34;&gt;---&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;TrafficTarget&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;access.smi-spec.io/v1alpha1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;api-service-api&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 定义访问api接口的Target&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;namespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;destination&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 通过 ServiceAccount 选择pods&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ServiceAccount&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;api-service&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;namespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;8080&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;specs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 引用traficSec定义的route，指定为api访问&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;HTTPRouteGroup&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;api-service-routes&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;matches&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;api&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;sources&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# 通过 ServiceAccount 选择pods&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ServiceAccount&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;website-service&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;namespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ServiceAccount&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;payments-service&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;namespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;w&#34;&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;ol&gt;
&lt;li&gt;对于以 ServiceAccount 为 api-service 运行的 pods，容许来自以 ServiceAccount 为 prometheus 的 pods 访问 api-service-routes 定义下的 metrics 路由&lt;/li&gt;
&lt;li&gt;对于以 ServiceAccount 为 api-service 运行的 pods，容许来自以 ServiceAccount 为 website-service 和 payments-service  的 pods 访问 api-service-routes 定义下的 api 路由&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;其中有部分字段为可选字段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;matches 字段：如果省略，则对 TrafficSpec 下定义的所有Route都生效&lt;/li&gt;
&lt;li&gt;Port字段：如果省略，则表示所有端口&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SMI 流量访问控制的规则是默认都不容许访问，只有通过 TrafficTarget 指定的符合条件的流量才容许访问。而访问控制的执行，是明确要求在访问的服务器端（即Destination）强制执行，而是否在客户端（即Source）进行访问控制则由SMI的具体实现来决定。&lt;/p&gt;
&lt;p&gt;注意目前 Traffic Access Control 在定义 Source 和 Destination 时，都是通过 Selector 来定义的，我们细看这张图片：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201906-service-mesh-interface-detail/images/smi-traffic-target_hu9c235f034760d8e5d89b04046e6e58e2_101156_be5fd37795957f385328b967223995a4.webp 400w,
               /post/201906-service-mesh-interface-detail/images/smi-traffic-target_hu9c235f034760d8e5d89b04046e6e58e2_101156_dd1ef129a690ec1f6c71b688419cb9b1.webp 760w,
               /post/201906-service-mesh-interface-detail/images/smi-traffic-target_hu9c235f034760d8e5d89b04046e6e58e2_101156_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-service-mesh-interface-detail/images/smi-traffic-target_hu9c235f034760d8e5d89b04046e6e58e2_101156_be5fd37795957f385328b967223995a4.webp&#34;
               width=&#34;760&#34;
               height=&#34;350&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;从访问控制的业务语义上看，上面两个 TrafficTarget 翻译出来就是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;容许以 ServiceAccount prometheus 运行的服务访问以 ServiceAccount api-service 运行的服务的 metrics&lt;/li&gt;
&lt;li&gt;容许以 ServiceAccount web-service 和 payment-service 运行的服务访问以 ServiceAccount api-service 运行的服务的 api&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而不是我们平时熟悉的资源方式如&amp;quot;容许A服务访问B服务&amp;rdquo;，即访问控制中对服务的标示目前只能通过 ServiceAccount + Selector 来完成，而不是通过简单的服务Id或者名称来指定资源。请注意&amp;quot;容许以身份A运行的服务访问以身份B运行的服务&amp;rdquo; 和 &amp;ldquo;容许A服务访问B服务&amp;rdquo; 的细微差别。&lt;/p&gt;
&lt;p&gt;关于这一点，在 SMI 的文档的&amp;quot;Tradeoffs&amp;quot;中提到：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Resources vs selectors - it would be possible to reference concrete resources such as a deployment instead of selecting across pods.&lt;/p&gt;
&lt;p&gt;资源 vs 选择器 - 可以引用具体资源（如deployment）而不是pod选择。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;traffic-split&#34;&gt;Traffic Split&lt;/h3&gt;
&lt;p&gt;Traffic Split 资源用来实现流量的百分比拆分，熟悉Istio的同学应该非常了解这个功能的强大。&lt;/p&gt;
&lt;p&gt;但是 SMI 中 Traffic Split 的配置方式和 Istio 有非常大的不同，比如下面的配置，要对 foobar 服务按照版本进行流量拆分，v1 和 v2 权重分别为 1 和 500m （1=1000m），在 Traffic Split 的配置中会出现多个 service：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;split.smi-spec.io/v1alpha1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;TrafficSplit&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;foobar-rollout&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;spec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;foobar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# root service，客户端用这个服务名来连接目标应用&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;backends&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# root service 后面的服务，有自己的selectors, endpoints 和 configuration&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;foobar-v1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;weight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;foobar-v2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;weight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;500m&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;
&lt;li&gt;&amp;ldquo;foobar&amp;rdquo;：通过 &lt;code&gt;spec.service&lt;/code&gt; 指定，这是 Traffic Split 的 root service，是要配置进行流量拆分的目标服务的FQDN，客户端用这个 service 进行通信，也就是说这个 root service 是暴露给客户端的。&lt;/li&gt;
&lt;li&gt;&amp;ldquo;footer-v1&amp;rdquo; 和 &amp;ldquo;footer-v2&amp;rdquo;：这两个后端服务，是&amp;quot;隐藏&amp;quot;在 root service 后面的，通常是 root service 的子集，典型实现上是 selector 多加一个 version label 限制。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样，如果要对某个服务的两个子集进行流量拆分，典型如版本v1和版本v2，在 SMI 中就会有三个 k8s service 定义：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;资源&lt;/th&gt;
&lt;th&gt;selector （label）&lt;/th&gt;
&lt;th&gt;描述&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;service foobar&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app: foobar&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;root service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;service foobar-v1&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app: foobar&lt;/code&gt;, &lt;code&gt;version: v1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;backend service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;service foobar-v2&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app: foobar&lt;/code&gt;, &lt;code&gt;version: v2&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;backend service&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这三个 service 和 pod 的关系如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201906-service-mesh-interface-detail/images/smi-traffic-split_huaddcd7e9102718607d20de96a4a4f7e1_80014_49caca2a6786a130380beb214b26c58c.webp 400w,
               /post/201906-service-mesh-interface-detail/images/smi-traffic-split_huaddcd7e9102718607d20de96a4a4f7e1_80014_80335599212297b6c7a49e0e24bc5ae0.webp 760w,
               /post/201906-service-mesh-interface-detail/images/smi-traffic-split_huaddcd7e9102718607d20de96a4a4f7e1_80014_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-service-mesh-interface-detail/images/smi-traffic-split_huaddcd7e9102718607d20de96a4a4f7e1_80014_49caca2a6786a130380beb214b26c58c.webp&#34;
               width=&#34;760&#34;
               height=&#34;358&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们来对比 Istio 中实现类似功能的方式，Istio中需要为准备进行流量拆分的服务定义 VirtualService，通过 subset 来区分不同的流量去向：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;networking.istio.io/v1alpha3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;VirtualService&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;foobar-route&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;spec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;hosts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;foobar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;route&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;destination&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;foobar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;subset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;v2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;weight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;25&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;destination&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;foobar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;subset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;v1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;weight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;75&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;subset 在 DestinationRule 中定义，注意这里只涉及到 labels，服务（以host标志）并没有多个，还是 foobar：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;apiVersion: networking.istio.io/v1alpha3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;kind: DestinationRule
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;metadata:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  name: foobar-destination
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;spec:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  host: foobar
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  subsets:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - name: v1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    labels:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      version: v1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - name: v2
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    labels:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      version: v2
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在Istio 中，service 和 subset 的关系如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201906-service-mesh-interface-detail/images/istio-traffic-split_hu342454daf6550c3d94a7f94651c1b7be_75174_a625871805d4d15b9a0b71ad39bc472c.webp 400w,
               /post/201906-service-mesh-interface-detail/images/istio-traffic-split_hu342454daf6550c3d94a7f94651c1b7be_75174_99adc95e6ed1d12cd9ef0525385b1fc7.webp 760w,
               /post/201906-service-mesh-interface-detail/images/istio-traffic-split_hu342454daf6550c3d94a7f94651c1b7be_75174_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-service-mesh-interface-detail/images/istio-traffic-split_hu342454daf6550c3d94a7f94651c1b7be_75174_a625871805d4d15b9a0b71ad39bc472c.webp&#34;
               width=&#34;760&#34;
               height=&#34;358&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;可以看到 SMI 中的 backend service 和 Istio 中的 subset 在功能上几乎是对等的。&lt;/p&gt;
&lt;p&gt;但是：SMI 和 Istio 的根本差异在于 Istio 中的 subset 是一个虚拟的抽象对象，在k8s中并没有实体资源。而在 SMI 中，backend service 是实实在在存在的 k8s service 资源。&lt;/p&gt;
&lt;p&gt;这里个人觉得有一个隐忧：在 SMI 中，为了进行流量拆分，就不得不为每个版本建立一个独立的k8s service，service 数量会比 Istio 方案多很多。&lt;/p&gt;
&lt;p&gt;另外就是在权重设置上的细微的差别，SMI 用的是相对weight（比如可以设置为1:2），而 Istio 是严格的百分比，而且要求总和为100。&lt;/p&gt;
&lt;h3 id=&#34;traffic-metrics&#34;&gt;Traffic Metrics&lt;/h3&gt;
&lt;p&gt;Traffic Metrics 资源提供通用集成点，工具可以通过访问这些集成点来抓取指标。Traffic Metrics 遵循 &lt;code&gt;metrics.k8s.io&lt;/code&gt; 的模式，其即时指标可用于各种 CLI工具，HPA伸缩等。&lt;/p&gt;
&lt;p&gt;和大多数Metrics系统一致，SMI的Traffic Metrics 数据包含两个核心对象：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Resource：Metrics 和资源绑定，资源可以是 pod 和更高级别的概念如 namespaces, deployments 或者 services 。Pod是 Metrics 可以关联的最细粒度的资源，通过集合可以得到推断出其他。&lt;/li&gt;
&lt;li&gt;Edge：表示流量来源或其目的地，描述力量的方向。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;TrafficMetrics&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;TrafficMetrics是核心资源，关联到资源，具有edge，延迟百分位数和请求量：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;metrics.smi-spec.io/v1alpha1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;TrafficMetrics&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;resource&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;foo-775b9cbd88-ntxsl&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;namespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;foobar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Pod&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;edge&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;direction&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;to&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;resource&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;baz-577db7d977-lsk2q&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;namespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;foobar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Pod&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;timestamp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;ld&#34;&gt;2019-04-08T22:25:55Z&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;window&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;30s&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metrics&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;p99_response_latency&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;unit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;seconds&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;10m&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;p90_response_latency&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;unit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;seconds&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;10m&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;p50_response_latency&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;unit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;seconds&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;10m&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;success_count&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;failure_count&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;100&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;TrafficMetrics 的定义和使用暂时没看到有特殊之处。&lt;/p&gt;
&lt;h3 id=&#34;smi规范总结&#34;&gt;SMI规范总结&lt;/h3&gt;
&lt;p&gt;从上面我们详细分析的 SMI 主要规范的定义看，Traffic Access Control / Traffic Specs / Traffic Split / Traffic Metrics 这四个目前定义好的规范，无论从功能还是从API设计上看，都缺乏亮点，至少与目前大家熟悉的 Istio API 相比，没有明显优势：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Traffic Specs 中 HTTPRouteGroup 只支持HTTP1.1，甚至不支持header，TCPRoute更是简陋到极致&lt;/li&gt;
&lt;li&gt;Traffic Access Control 只支持 ServiceAccount&lt;/li&gt;
&lt;li&gt;Traffic Split：需要为每个需要拆分的流量额外增加 k8s service&lt;/li&gt;
&lt;li&gt;TrafficMetrics：平平无奇&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;考虑到目前 SMI 还是第一个版本，处于项目早期阶段，不够成熟情有可原，我们更要关注的是其后续版本的演进，希望未来 SMI 可以成长为一个足够坚实而可用的标准API。&lt;/p&gt;
&lt;h2 id=&#34;smi分析&#34;&gt;SMI分析&lt;/h2&gt;
&lt;p&gt;前面我们分析过 SMI 推出的背景，我归结为关键的两点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;有利可图：Service Mesh技术被普遍看好，其长远价值被各大厂商认可&lt;/li&gt;
&lt;li&gt;有机可趁：作为市场领头羊的Google和Istio，表现疲软&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;另外Google在Istio项目上，表现也有些令人费解：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;迟迟不进CNCF：早先还有未能发布1.0版本不满足CNCF要求的借口，而最近则感觉Google一直在避免讨论这个话题&lt;/li&gt;
&lt;li&gt;Istio一直没有对 Service Mesh 技术进行标准化：只关注自己的 Istio API，对于标准化和基于标准化构建生态系统完全没兴趣。即便是统一数据平面API的标准化动作，也让人觉得是 Envoy 在推动。&lt;/li&gt;
&lt;li&gt;宣传和现实的差距：Istio 1.0 的 &amp;ldquo;Product Ready&amp;rdquo;，1.1 版本的&amp;quot;Enterprise Ready&amp;quot;，很让人无语，我很期待 1.2 版本出来时的口号。&lt;/li&gt;
&lt;li&gt;架构设计的不务实：Mixer 是被嘲弄的重灾区，躲在Mixer身后的Pilot其实问题也一堆，而 Mixer v2 的进展则成为衡量 Istio 未来走向的风向标，是要成为工业级可用的坚实产品，还是继续摆弄优雅架构做花瓶？未来一年我们拭目以待。&lt;/li&gt;
&lt;li&gt;整个社区对Istio的不满情绪一直在酝酿和累积：这次 SMI 推出引发的轰动，很大程度是这种情绪的发泄——除了Google之外几乎所有的 Servic Mesh 的玩家都参与进来了，这就足够说明问题了。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在过去两年，社区一直在期待Google和Istio，但是，这种期待在持续两年的失望之后，开始转向另外的方向：或许我们要更多的考虑Istio之外的选择了。&lt;/p&gt;
&lt;p&gt;Service Mesh 的战争，我们原以为会以Istio的胜利而迅速结束，但是现在看来，可能这场战争才刚刚开始。&lt;/p&gt;
&lt;p&gt;是重新认真审视这张图片的时候了：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201906-service-mesh-interface-detail/images/gartner_hu0cefc59b1305d4b12fbb9ada76f070b9_62500_0fa1e93316379ec538455e5d787110f4.webp 400w,
               /post/201906-service-mesh-interface-detail/images/gartner_hu0cefc59b1305d4b12fbb9ada76f070b9_62500_df3280845a50fe10024dd72156b273b2.webp 760w,
               /post/201906-service-mesh-interface-detail/images/gartner_hu0cefc59b1305d4b12fbb9ada76f070b9_62500_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201906-service-mesh-interface-detail/images/gartner_hu0cefc59b1305d4b12fbb9ada76f070b9_62500_0fa1e93316379ec538455e5d787110f4.webp&#34;
               width=&#34;760&#34;
               height=&#34;505&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;SMI 的推出，意义并不仅仅在于这个 Service Mesh 标准本身，而是带有另外一种特殊含义，就如陈胜吴广的揭竿而起，传递给四方的消息是：天下苦秦久矣！&lt;/p&gt;
&lt;p&gt;文章最后，希望未来有更多的优秀 Service Mesh 产品出现，也希望 Istio 可以知耻而后勇。Service Mesh 技术要想成功普及，一定需要一个或者多个强力产品的出现，而 SMI 的出现则为这场短期不能结束的纷争带来了一个理论可能：无论产品竞争如何激烈，都不影响上层生态，从而避免站队失败的风险和由此带来的犹豫与观望。这才是我个人觉得 SMI 推出的最大意义所在。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://smi-spec.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;smi官方网站&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/deislabs/smi-spec&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;smi-spec项目@github &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.redhat.com/en/blog/interoperability-new-service-mesh-interface&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Interoperability with the new Service Mesh Interface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.fleeto.us/post/servicemesh-interface/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;意外：Servicemesh Interface（SMI）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://msft.today/hello-service-mesh-interface-smi-a-specification-for-service-mesh-interoperability/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Hello Service Mesh Interface (SMI): A specification for service mesh interoperability&lt;/a&gt;: 来自微软的博客，比较权威，本文很多内容是援引自此文&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://medium.com/solo-io/service-mesh-interface-smi-and-our-vision-for-the-community-and-ecosystem-2edc7b728c43&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Service Mesh Interface (SMI) and our Vision for the Community and Ecosystem&lt;/a&gt;：作者 &lt;a href=&#34;https://medium.com/@idit.levine_92620&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Idit Levine&lt;/a&gt;，是初创公司 solo.io 的创始人兼CEO，本文同样大量援引此文的内容&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kccnceu19.sched.com/event/MRz7/sponsored-keynote-democratizing-service-mesh-on-kubernetes-gabe-monroy-lead-product-manager-microsoft-azure-container-compute&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Democratizing Service Mesh on Kubernetes&lt;/a&gt;: kubecon上宣布SMI的 keynote，作者 Gabe Monroy ，Microsoft Azure Container Compute的 Lead Product Manager，本文部分图片来自这个演讲的PPT&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://kinvolk.io/blog/2019/05/how-the-service-mesh-interface-smi-fits-into-the-kubernetes-landscape/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;How the Service Mesh Interface (SMI) fits into the Kubernetes landscape&lt;/a&gt;: 介绍SMI和其他类似的kubernetes Interface 如 CNI、CRI、CSI等。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.getambassador.io/kubecon-eu-2019-top-10-takeaways-123b5fcb30a8&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;KubeCon EU 2019: Top 10 Takeaways&lt;/a&gt;: 来自网红 Daniel Bryant 的文章，包含对 SMI 和 Istio 的看法。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://softwareengineeringdaily.com/2019/05/31/service-mesh-wars-with-william-morgan/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Service Mesh Wars with William Morgan&lt;/a&gt;：这是我见过的抨击Istio最为猛烈的一篇文章，极其火爆，又很有道理的样子&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.infoworld.com/article/3400116/introducing-the-service-mesh-interface.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;To Istio and beyond: Azure’s Service Mesh Interface&lt;/a&gt;: 有软文嫌疑，但是还是能看出微软推出SMI的基本想法&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.hashicorp.com/blog/hashicorp-consul-supports-microsoft-s-new-service-mesh-framework&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;HashiCorp Consul supports Microsoft’s new Service Mesh Interface&lt;/a&gt;: 介绍 Consul Connect 对 SMI 的支持&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>[译] William Morgan的服务网格之战</title>
      <link>https://skyao.net/post/201906-service-mesh-wars-with-william-morgan/</link>
      <pubDate>Mon, 03 Jun 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201906-service-mesh-wars-with-william-morgan/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;英文原文来自 &lt;a href=&#34;https://softwareengineeringdaily.com/2019/05/31/service-mesh-wars-with-william-morgan/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Service Mesh Wars with William Morgan&lt;/a&gt;，这是我见过的抨击Istio最为猛烈的一篇文章，极其火爆，又很有道理的样子。特别申明：仅做翻译，不代表本人立场。&lt;/p&gt;
&lt;h2 id=&#34;正文&#34;&gt;正文&lt;/h2&gt;
&lt;p&gt;服务网格是一种抽象，为分布式应用程序提供流量路由，策略管理和遥测。&lt;/p&gt;
&lt;p&gt;服务网格由数据平面和控制平面组成。在数据平面中，代理与服务一起运行，服务的每个请求都通过代理进行路由。在控制平面中，应用程序所有者可以控制分布在整个应用程序中的代理的行为。&lt;/p&gt;
&lt;p&gt;随着Kubernetes生态系统的发展，服务网格抽象已经成为“云原生”应用技术栈中越来越受欢迎的组件。&lt;/p&gt;
&lt;p&gt;随着公司热情地采用Kubernetes，他们最终发现自己拥有一个难以操作的大型分布式系统。正如我们在之前的探讨的那样，服务网格简化了这些运维困难。&lt;/p&gt;
&lt;p&gt;Kubernetes社区已经发展到包括许多企业，而这些企业希望采用服务网络。但是今天，他们中的许多人都害怕采用这项技术，因为有多种竞争产品，而且不清楚社区将选择哪一个，或者社区最终是否会支持多种产品。&lt;/p&gt;
&lt;p&gt;在接下来的几周内，我们将播出在巴塞罗那的KubeCon EU 2019 的采访。这些访谈是进入Kubernetes世界和云原生生态系统的窗口，它正在改变基础设施软件的世界。&lt;/p&gt;
&lt;p&gt;这些节目中最突出的主题是服务网格。为什么服务网格如此重要？因为服务网络之上的争夺战是一个巨人和资源少得多的创业公司之间的经典技术竞争。&lt;/p&gt;
&lt;p&gt;Kubernetes生态系统设计精美，是可以让最有价值的竞争对手获胜的交战市场 - 但在某些情况下，多个产品可以占据市场的不同部分。&lt;/p&gt;
&lt;p&gt;在这些事件中，我们将探讨的主题是这些竞争解决方案的治理和外交，以及Kubernetes生态系统如何构建以允许和谐解决技术纷争。&lt;/p&gt;
&lt;p&gt;很容易将服务网格之间的竞争视为赢家通吃。但截至2019年5月下旬，我们还不知道它是否会成为赢者通吃。为了预测服务网格战将如何发展，我们能做的最好的事情就是看历史例子。&lt;/p&gt;
&lt;p&gt;容器编排战争是一个赢家通吃的市场。容器编排是非常有深度的问题，例如技术的复杂性和集成，生态系统必须有单一的赢家。&lt;/p&gt;
&lt;p&gt;在容器编排战争期间，Mesos和Docker Swarm，以及HashiCorp Nomad，在和Kubernetes争夺至高无上的地位，许多大型企业对 Kubernetes 以外的容器编排系统下了赌注。尘埃落定后，Kubernetes成为胜利者，这些采用Kubernetes以外的编排系统的大型企业不得不开始考虑如何迁移到Kubernetes。&lt;/p&gt;
&lt;p&gt;但在编排战争期间，更多的企业选择围观。他们没有选择Kubernetes或Mesos或Swarm。他们选择了等待。&lt;/p&gt;
&lt;p&gt;企业技术人员很聪明，他们可以判断技术何时不成熟。虽然许多企业想要一个编排系统来管理他们的Docker容器，但他们并不想引入日后必须拆除的大量抽象。&lt;/p&gt;
&lt;p&gt;一旦Kubernetes赢得了编排战争，企业资金就会涌入这个领域。云原生社区的增长速度超过了任何人的预期，因为我们解决了集中在容器编排器上的集体行动问题。&lt;/p&gt;
&lt;p&gt;从企业到云供应商再到ISV到播客，我们对Kubernetes有着共同的愿景：它是分布式系统的Linux。&lt;/p&gt;
&lt;p&gt;在Kubernetes生态系统中，思想领导者不会挑选优胜者。如果获胜者是通过竞争决定的，那对每个人来说都会更好。为了促进竞争，与Kubernetes的接口可以提供一层标准化，不同的产品可以与之竞争。企业可以选择接口而无需选择任何特定产品。&lt;/p&gt;
&lt;p&gt;示例包括容器网络接口（CNI）和容器存储接口（CSI）。每个Kubernetes应用程序都需要存储和网络，但这些Kubernetes应用程序不希望被锁定到特定的供应程序。由于存在用于网络和存储的标准化接口，因此这些应用程序可以替换存储提供商，或者替换网络提供商。&lt;/p&gt;
&lt;p&gt;这与服务网格有什么关系？&lt;/p&gt;
&lt;p&gt;在服务网格市场，Buoyant率先推出了开源项目Linkerd。今天的客人William Morgan是Buoyant的首席执行官。在过去的四年中，Linkerd已经慢慢培养了一批在生产中运行开源服务网格的专用用户。&lt;/p&gt;
&lt;p&gt;在过去四年中，Linkerd已经从其在Twitter开发的JVM服务代理的初始技术转变为基于Rust的Sidecar数据平面和基于Go的控制平面。Buoyant专注于服务网格领域，赢得了社区的大部分支持，Linkerd成为Kubecon EU 2019的主要服装品牌就是证明：会议中到处都是 Linkerd 的帽子和T恤。&lt;/p&gt;
&lt;p&gt;为什么Linkerd变得时髦？具有讽刺意味的是，某些服务网络的竞争策略被广泛的视为是对云原生社区精神的侮辱。&lt;/p&gt;
&lt;p&gt;Istio是在谷歌内部创建的，并与IBM和其他公司建立了一系列脆弱的合作伙伴关系。Istio通过暴力宣传进入Kubernetes生态系统，通过无尽的横幅广告，营销电子邮件活动和KubeCon编程宣传自己为云原生服务网络。&lt;/p&gt;
&lt;p&gt;这个播客的任何听众都知道我和任何技术专家一样容易上当受骗。我是一个理想主义者 - 我愿意相信Istio代表服务网格，相当于Kubernetes。它来自谷歌，推出了一系列令人印象深刻的徽标，它具有鼓舞人心的愿景。看起来像云原生，闻起云原生，必须是云原生，对吧？&lt;/p&gt;
&lt;p&gt;不幸的是，Istio的早期营销与项目的现实脱节。Istio有缺陷，很难搭建。Istio迅速发展成为谷歌制造的笑柄：好主意，几乎没有做好生产准备。&lt;/p&gt;
&lt;p&gt;对于Linkerd来说，时机正好。&lt;/p&gt;
&lt;p&gt;Istio对路由流量，管理安全策略和网络遥测的运维平面的浪漫愿景引诱了企业用户。由于他们对Istio的渴望未得到满足，这些企业对市场进行了调查，并迅速找到了通往隔壁的廉价服务网格Linkerd的大门，他一直耐心等待。&lt;/p&gt;
&lt;p&gt;潮流已经转向反对Istio，并转向Linkerd。但服务网格战争刚刚开始。批评Istio是很容易的，但是该项目是不只是笑柄。Istio有详细的运维平面的愿景，将与Lyft开发的服务代理Sidecar Envoy一起发展。&lt;/p&gt;
&lt;p&gt;也许Istio的早期失败是因为有过多的营销，但该项目仍然可以成功。谷歌是世界上最先进，资源最充足的公司 - 从谷歌围绕Anthos和其他战略计划的相关战略信息来看，该公司已经决定Istio将长期存在。&lt;/p&gt;
&lt;p&gt;作为社区，我们应该感谢Istio地毯式轰炸营销战略的愚蠢。它验证了云原生社区的真正弹性，即使在谷歌营销的无处不在的胁迫下，社区也能够集体拒绝Istio Kool Aid。&lt;/p&gt;
&lt;p&gt;这应该不足为奇。云原生计算基金会（CNCF）驻留在Linux基金会内部，而Kubernetes生态系统已经被Linus Torvalds的热切技术追求所感染。&lt;/p&gt;
&lt;p&gt;CNCF是在AWS的阴影下形成的。CNCF由谷歌捐赠Kubernetes播种。就像Linux社区被定位为对微软的主导地位作出反应的反叛运动一样，Kubernetes社区代表了一种强烈的愿望，即向云供应商开放市场，超越亚马逊的守口如瓶。&lt;/p&gt;
&lt;p&gt;由于具有如此深刻的不服从精神，社区已经拒绝了Istio，就像一组松散耦合的器官一样拒绝外来试图将自己分层的皮肤。尽管CNCF是由谷歌创立的，但社区是在大型集中云的敌视下形成的，而不是作为其产品的营销容器，这些产品可能是也可能不是开源的。&lt;/p&gt;
&lt;p&gt;微软似乎比谷歌更了解这一事实，至少在服务网格领域。&lt;/p&gt;
&lt;p&gt;在接受William采访后的第二天，微软宣布推出Service Mesh Interface（SMI），这是一个与Buoyant和其他公司合作的项目，旨在为Kubernetes部署提供服务网络应该提供的最小规范。SMI为想要服务网络的企业提供了一个安全的买入点，但不至于陷入Istio和Linkerd的交火中。&lt;/p&gt;
&lt;p&gt;正是在这种环境下，我们开始了当前云原生生态系统的下一系列节目。&lt;/p&gt;
&lt;p&gt;感谢Cloud Native Computing Foundation在KubeCon上组建了一个令人惊叹的播客区，并允许我进行这些采访。&lt;/p&gt;
&lt;h2 id=&#34;译者注&#34;&gt;译者注&lt;/h2&gt;
&lt;p&gt;文章有些偏激，用词夸张，有种美式脱口秀节目的味道，因此读者们请保持冷静。&lt;/p&gt;
&lt;p&gt;不过Istio的确存在很多问题，问世两年来，期望和现实差距太大，伤了很多人的心，大概是爱之深责之切吧。Istio 也到了该好好骂一骂的时候了，我个人只想问一句：Mixer V2 什么时候能实现啊？&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Service Mesh发展趋势：云原生中流砥柱</title>
      <link>https://skyao.net/talk/201905-servicemesh-development-trend/</link>
      <pubDate>Sat, 25 May 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/201905-servicemesh-development-trend/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;本文内容整理自5月25日在 Kubernetes &amp;amp; Cloud Native Meetup 上海站发表的主题演讲，主要介绍了ServiceMesh最新的产品动态，分析其发展趋势和未来走向；结合蚂蚁的上云实践，阐述在云原生背景下Service Mesh的核心价值，以及对云原生落地的关键作用。&lt;/p&gt;
&lt;p&gt;内容主要有三个部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Service Mesh产品动态：介绍最近半年 Service Mesh 的产品动态，包括开源项目和云厂商推出的云上服务&lt;/li&gt;
&lt;li&gt;Service Mesh发展趋势：根据最近的产品动态，总结 Service Mesh 的发展趋势，推断未来的走向&lt;/li&gt;
&lt;li&gt;Service Mesh与云原生：结合云原生，更好的理解 Service Mesh 的价值和作用&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;service-mesh产品动态&#34;&gt;Service Mesh产品动态&lt;/h2&gt;
&lt;h3 id=&#34;istio11发布&#34;&gt;Istio1.1发布&lt;/h3&gt;
&lt;p&gt;Istio是目前 Service Mesh 社区最引人注目的开源项目，在今年的3月份发布了期待已久的 Istio 1.1 版本，我们来看看 Istio 最近几个版本的发布情况：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2018年6月1日，Istio 发布了 0.8 版本，这是Istio历史上第一个LTS版本，也是Istio历史上变动最大的一个版本&lt;/li&gt;
&lt;li&gt;2018年7月31日，Istio发布了1.0版本，号称 &amp;ldquo;Product Ready&amp;rdquo;&lt;/li&gt;
&lt;li&gt;然后就是漫长的等待，Istio 1.0 系列以每个月一个小版本的方式一路发布了1.0.1 到 1.0.6，然后才开始 1.1.0 snapshot 1到6，再 1.1.0-rc 1到6，终于在2019年3月20日发布了 1.1 版本，号称 &amp;ldquo;Enterprise Ready&amp;rdquo;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从 Istio 1.0 到 Istio 1.1，中间的时间跨度高达9个月！我们来看看经过这漫长的开发时间才发布的 Istio 1.1 版本带来了哪些新的东西：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/istio1.1-new-feature_hu22554fc7c4b2ceac2b0f6082cf90fe93_453660_e7e997b9261f1f390bd2eff49e4b2d11.webp 400w,
               /talk/201905-servicemesh-development-trend/images/istio1.1-new-feature_hu22554fc7c4b2ceac2b0f6082cf90fe93_453660_72cd8daa9496f7a9f93558e9976a8f77.webp 760w,
               /talk/201905-servicemesh-development-trend/images/istio1.1-new-feature_hu22554fc7c4b2ceac2b0f6082cf90fe93_453660_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/istio1.1-new-feature_hu22554fc7c4b2ceac2b0f6082cf90fe93_453660_e7e997b9261f1f390bd2eff49e4b2d11.webp&#34;
               width=&#34;760&#34;
               height=&#34;260&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;图中标红的部分，涉及到 Istio 的架构调整，下面将详细介绍 Istio 1.1 版本中带来的架构变化。&lt;/p&gt;
&lt;h3 id=&#34;istio-11架构变化&#34;&gt;Istio 1.1架构变化&lt;/h3&gt;
&lt;p&gt;下图是 Istio 1.0 和 Istio 1.1 的架构图对比：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/istio-constructure_hu8e11c8a458c7d826f5233931417ca224_308773_a59105292850aa8024f4a494427eea90.webp 400w,
               /talk/201905-servicemesh-development-trend/images/istio-constructure_hu8e11c8a458c7d826f5233931417ca224_308773_489f12e1f25a51bec32a954c0e5eb4b7.webp 760w,
               /talk/201905-servicemesh-development-trend/images/istio-constructure_hu8e11c8a458c7d826f5233931417ca224_308773_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/istio-constructure_hu8e11c8a458c7d826f5233931417ca224_308773_a59105292850aa8024f4a494427eea90.webp&#34;
               width=&#34;760&#34;
               height=&#34;339&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Istio 1.1的第一个架构变化来自 Galley：在 Istio 1.1 的架构图中增加了 Galley 组件。但是实际上在 Istio 1.0 版本中 Gallay 组件就已经存在，只是当时 Galley 的功能非常简单，只是做配置更新之后的验证（Validation），在 Istio 1.0 的架构图中都没有出现。而在 Istio 1.1 版本之后，Galley 的定位发生了巨大的变化：Galley开始分担 Pilot/Mixer 的职责。&lt;/p&gt;
&lt;p&gt;在 Istio 1.1 版本之前的设计中，Istio的三大组件 Pilot/Mixer/Citadel 都需要访问 kubernetes 的 API Server，以获取服务注册信息和配置信息，包括kubernetes原生资源如 service/deployment/pod 等，还有 Istio 的自定义资源（数量多达50多个的 CRD） 。这个设计导致 Istio 的各个组件都不得不和 kubernetes 的 API Server产生强绑定，不仅仅代码大量冗余，而且在测试中也因为需要和 kubernetes 的 API Server 交互导致 Pilot/Mixer 模块测试困难。&lt;/p&gt;
&lt;p&gt;为了解决这个问题，在 Istio 1.1 之后，访问 kubernetes 的 API Server 的工作将逐渐交给 Galley 组件，而其他组件如 Pilot/Mixer 就会和  kubernetes 解耦。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/galley_hu2dffe8b45aa4cebb6d84282a91c630af_36356_172c6cd132e60119acb1cb4193142e71.webp 400w,
               /talk/201905-servicemesh-development-trend/images/galley_hu2dffe8b45aa4cebb6d84282a91c630af_36356_7fb4baf6621e2f58621200b9906eb9ce.webp 760w,
               /talk/201905-servicemesh-development-trend/images/galley_hu2dffe8b45aa4cebb6d84282a91c630af_36356_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/galley_hu2dffe8b45aa4cebb6d84282a91c630af_36356_172c6cd132e60119acb1cb4193142e71.webp&#34;
               width=&#34;400&#34;
               height=&#34;457&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这个工作还在进行中，目前 Istio 的CRD 已经修改为由 Galley 读取，而 K8s 的原生资源（Service / Deployment / Pod等），暂时还是由 Pilot 读取。&lt;/p&gt;
&lt;p&gt;为了方便在各个组件中同步数据，Istio 引入了MCP（Mesh Configuration Protocol）协议。在 Istio 1.1 版本中，Pilot 通过MCP协议从 Galley 同步数据。MCP是受 xDS v2 协议（准确说是 aDS）的启发而制定的新协议，用于在Istio 各模块之间同步数据。&lt;/p&gt;
&lt;p&gt;Istio 1.1的第二个架构变化来自于 Mixer，在 Istio 1.1 版本中，推荐使用 Out-of-Process Adapter，即进程外适配器。Istio预计下一个版本将弃用 In-Proxy Adapter，目前所有的 Adapter 都将改为 Out-of-Process adapter。&lt;/p&gt;
&lt;p&gt;什么是In-Proxy Adapter？下图是 Mixer 的架构图，在 Istio 的设计中，Mixer 是一个独立进程，Proxy 通过远程调用来和 Mixer 交互。而 Mixer 的实现了 Adapter 模式，定义了 Adapter API，然后内建了数量非常多的各种Adapter。这些 Adatper 的代码存放在 Mixer 代码中，运行时也在 Mixer 的进程内，因此称为 In-Process Adapter。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/in-process-adapter_hu0e413921d04a602bda5580f19ca7f0bd_271554_ab330147bdf1a5cbbc3755b3d573d9a4.webp 400w,
               /talk/201905-servicemesh-development-trend/images/in-process-adapter_hu0e413921d04a602bda5580f19ca7f0bd_271554_6e1af8bf2bcfde2b6f9cd7e6b3029aae.webp 760w,
               /talk/201905-servicemesh-development-trend/images/in-process-adapter_hu0e413921d04a602bda5580f19ca7f0bd_271554_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/in-process-adapter_hu0e413921d04a602bda5580f19ca7f0bd_271554_ab330147bdf1a5cbbc3755b3d573d9a4.webp&#34;
               width=&#34;760&#34;
               height=&#34;532&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;In-Process Adapter 的问题在于所有的 Adapter 的实现都和 Mixer 直接绑定，包括代码和运行时。因此当 Adapter 需要更新时就需要更新整个 Mixer，任意一个 Adapter 的实现出现问题也会影响整个 Mixer，而且数量众多的 Adapter 也带来了数量众多的CRD。为此，Istio 1.1 版本中通过引入 Out-of-Process Adapter 来解决这个问题。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/out-of-process-adapter_hu91a09d74411c03a18a68f69ab5a35610_214646_2c52483be3cfacf5b2782983bdb393b2.webp 400w,
               /talk/201905-servicemesh-development-trend/images/out-of-process-adapter_hu91a09d74411c03a18a68f69ab5a35610_214646_406f6940e900ce4a2115b769664bb49a.webp 760w,
               /talk/201905-servicemesh-development-trend/images/out-of-process-adapter_hu91a09d74411c03a18a68f69ab5a35610_214646_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/out-of-process-adapter_hu91a09d74411c03a18a68f69ab5a35610_214646_2c52483be3cfacf5b2782983bdb393b2.webp&#34;
               width=&#34;760&#34;
               height=&#34;390&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Out-of-Process Adapter以独立进程的方式运行在 Mixer 进程之外，因此 Out-of-Process Adapter 的开发/部署和配置都可以独立于 Mixer，从而将 Mixer 从 Adaper 的实现细节中解脱出来。&lt;/p&gt;
&lt;p&gt;但是，Out-of-Process Adapter的引入，会导致新的性能问题：原来 Mixer 和 In-Process Adapter 之间是方法调用，现在改成 Out-of-Process Adapter 之后就变成远程调用了。而 Mixer 一直以来都是 Istio 架构设计中最大的争议，之前 Proxy 和 Mixer 之间的远程调用，已经造成非常大的性能瓶颈，而引入 Out-of-Process Adapter 之后远程调用会从一次会变成多次（每个配置生效的 Out-of-Process Adapter 就意味着一次远程调用），这会让性能雪上加霜。&lt;/p&gt;
&lt;p&gt;总结 Out-of-Process Adapter 的引入：&lt;strong&gt;架构更加的优雅&lt;/strong&gt;，&lt;strong&gt;性能更加的糟糕&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在 Istio 1.1 为了架构而不顾性能的同时，Istio 内部也有其他的声音传出，如正在规划中的 Mixer v2。这个规划最重要的决策就是放弃 Mixer 独立进程的想法，改为将 Mixer 的功能合并到 Envoy 中，从而避免 Envoy 和 Mixer 之间远程调用的开销。关于 Mixer 的性能问题和 Mixer 合并的思路，蚂蚁金服在去年六月份开始 SOFAMesh 项目时就有清晰的认识和计划，时隔一年，终于欣喜的看到 Istio 开始正视 Mixer 的架构设计问题并回到正确的方向上。&lt;/p&gt;
&lt;p&gt;对此有兴趣的朋友可以通过阅读下面的文章获取更详细的信息（发表于一年前，但是依然有效）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://skyao.net/talk/201806-service-mesh-explore/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;大规模微服务架构下的Service Mesh探索之路&lt;/a&gt;: 第二节架构设计中的&amp;quot;合并部分Mixer功能&amp;quot;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skyao.net/post/201804-servicemesh-architecture-introspection/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Service Mesh架构反思：数据平面和控制平面的界线该如何划定？&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skyao.net/post/201804-istio-achilles-heel/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Mixer Cache: Istio的阿克琉斯之踵?&lt;/a&gt;： 系列文章，有两篇&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skyao.net/post/201804-istio-mixer-cache-concepts/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Istio Mixer Cache工作原理与源码分析&lt;/a&gt;: 系列文章，有四篇&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;目前 Mixer v2 的规划还处于 Review 状态，实现方式尚未有明确决定。如果要合并 Mixer，考虑到目前 Mixer 是基于 Golang 编写，而 Envoy 是基于c++ ，这意味着需要用c++重写所有的 Adapter，工作量巨大，恐怕不是短期之内能够完成的。当然也有另外一个新颖（或者说脑洞大开）的思路：引入 Web Assembly（WASM）。目前 Envoy 在进行支持 Web Assembly 的尝试，如果成功，则通过 Web Assembly 的方式来支持 Mixer Adapter 不失为一个好选择。&lt;/p&gt;
&lt;h3 id=&#34;其他社区产品动态&#34;&gt;其他社区产品动态&lt;/h3&gt;
&lt;p&gt;最近，CNCF 在筹建 Universal Data Plane API （UDPA/通用数据平面API）工作组，以制定数据平面的标准API，为L4/L7数据平面配置提供事实上的标准。Universal Data Plane API 的创意来自 Envoy，实现为 xDS API。而目前 xDS v2 API 已经是数据平面API的事实标准，这次的 UDPA 会以xDS v2 API 为基础。工作组的初始成员来自包括 Envoy 和 gRPC 项目的代表，蚂蚁金服也在积极参与 UDPA 工作组，目前还处于非常早期的筹备阶段。&lt;/p&gt;
&lt;p&gt;Linkerd2 在2019年4月17日发布了最新的稳定版本 Linkerd 2.3 版本。Linkerd2 是目前开源产品中唯一正面对抗 Istio 的存在，不过在国内知名度不高，使用者也很少。比较有意思的是，开发Linkerd2 的初创公司 Buoyant 最近的B轮融资来自 Google 的投资部门。&lt;/p&gt;
&lt;h3 id=&#34;云厂商的产品动态&#34;&gt;云厂商的产品动态&lt;/h3&gt;
&lt;p&gt;随着 Service Mesh 技术的发展，和各方对 Service Mesh 前景的看好，各大主流云提供商都开始在 Service Mesh 技术上发力。&lt;/p&gt;
&lt;p&gt;首先看 AWS，在2019年4月，AWS 宣布 App Mesh GA。App Mesh 是 AWS 推出的AWS原生服务网格，与AWS完全集成，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;网络（AWS cloud map）&lt;/li&gt;
&lt;li&gt;计算（Amazon EC2和AWS Fargate）&lt;/li&gt;
&lt;li&gt;编排工具（AWS EKS，Amazon ECS和EC2上客户管理的k8s）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/appmesh_hu82dc9b635921e2fb6fb4d2e4e2e711a8_131887_0b060e7a6253fe3e564780f322a48e8a.webp 400w,
               /talk/201905-servicemesh-development-trend/images/appmesh_hu82dc9b635921e2fb6fb4d2e4e2e711a8_131887_333315954acea5951c2ceb5d5fc9f766.webp 760w,
               /talk/201905-servicemesh-development-trend/images/appmesh_hu82dc9b635921e2fb6fb4d2e4e2e711a8_131887_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/appmesh_hu82dc9b635921e2fb6fb4d2e4e2e711a8_131887_0b060e7a6253fe3e564780f322a48e8a.webp&#34;
               width=&#34;760&#34;
               height=&#34;415&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;App Mesh的数据平面采用 Envoy，产品非常有创意的同时支持VM和容器，支持多种产品形态，如上图所示。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;AWS App Mesh 的更多详细内容，请浏览文章 &lt;a href=&#34;https://skyao.net/post/201904-aws-app-mesh/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;用AWS App Mesh重新定义应用通讯&lt;/a&gt; 。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Google 的打法则是围绕 Istio 。首先是在2018年底推出了 Istio on GKE，即&amp;quot;一键集成Istio&amp;quot;，并提供遥测、日志、负载均衡、路由和mTLS 安全能力。接着 Google 又推出 Google Cloud Service Mesh，这是 Istio的完全托管版本，不仅仅提供Istio开源版本的完整特性，还集成了 Google Cloud上的重要产品 Stackdriver 。&lt;/p&gt;
&lt;p&gt;近期，Google推出 Traffic Director 的 beta 测试版本，Traffic Director 是完全托管的服务网格流量控制平面，支持全局负载均衡，适用于虚拟机和容器，提供混合云和多云支持、集中式健康检查和流量控制，还有一个非常特别的特性：支持基于流量的自动伸缩。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/google-traffic-director_hud1becd506401a24bb8320f4ce8489cab_413874_7a1c76d5b5f05bcc90160903f66a0d72.webp 400w,
               /talk/201905-servicemesh-development-trend/images/google-traffic-director_hud1becd506401a24bb8320f4ce8489cab_413874_e1acf4a108b7752c9f68d7b4cfd92a7e.webp 760w,
               /talk/201905-servicemesh-development-trend/images/google-traffic-director_hud1becd506401a24bb8320f4ce8489cab_413874_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/google-traffic-director_hud1becd506401a24bb8320f4ce8489cab_413874_7a1c76d5b5f05bcc90160903f66a0d72.webp&#34;
               width=&#34;760&#34;
               height=&#34;372&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Google Traffic Director 的详细介绍，请查看我之前的博客文章 &lt;a href=&#34;https://skyao.net/post/201905-google-traffic-director-detail/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Google Traffic Director详细介绍&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;微软则推出了Service Fabric Mesh。Azure Service Fabric 是Microsoft的微服务框架，设计用于公共云，内部部署以及混合和多云架构。而 Service Fabric Mesh 是Azure完全托管的产品，在2018年8月推出预览版。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/service-fabric-mesh_hu295ff58e69e8014448a5af9bcad813d7_912320_23e85c5abaf7b6d9d9bfc0443de3cea8.webp 400w,
               /talk/201905-servicemesh-development-trend/images/service-fabric-mesh_hu295ff58e69e8014448a5af9bcad813d7_912320_e45a3c8a1e78522c8606c1037deacb08.webp 760w,
               /talk/201905-servicemesh-development-trend/images/service-fabric-mesh_hu295ff58e69e8014448a5af9bcad813d7_912320_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/service-fabric-mesh_hu295ff58e69e8014448a5af9bcad813d7_912320_23e85c5abaf7b6d9d9bfc0443de3cea8.webp&#34;
               width=&#34;760&#34;
               height=&#34;451&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;上周（5月21号）最新消息，微软在 kubeconf 上推出 Service Mesh Interface。SMI 是在 Kubernetes 上运行服务网格的规范，定义了由各种供应商实现的通用标准，使得最终用户的标准化和服务网格供应商的创新可以两全其美，SMI 预期将为 Service Mesh 带来了灵活性和互通性。&lt;/p&gt;
&lt;p&gt;SMI是一个开放项目，由微软，Linkerd，HashiCorp，Solo，Kinvolk和Weaveworks联合启动; 并得到了Aspen Mesh，Canonical，Docker，Pivotal，Rancher，Red Hat和VMware的支持。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/smi_huf6b71bf4c5aead35d5086efd927da877_662176_adad3933678873cb013d85672a3cc914.webp 400w,
               /talk/201905-servicemesh-development-trend/images/smi_huf6b71bf4c5aead35d5086efd927da877_662176_426567cc2e0255e8430a00fee7b865f9.webp 760w,
               /talk/201905-servicemesh-development-trend/images/smi_huf6b71bf4c5aead35d5086efd927da877_662176_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/smi_huf6b71bf4c5aead35d5086efd927da877_662176_adad3933678873cb013d85672a3cc914.webp&#34;
               width=&#34;760&#34;
               height=&#34;400&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;service-mesh发展趋势&#34;&gt;Service Mesh发展趋势&lt;/h2&gt;
&lt;p&gt;在分享完最近半年 Service Mesh 产品的动态之后，我们来分析探讨 Service Mesh 的发展趋势。&lt;/p&gt;
&lt;h3 id=&#34;趋势1上云托管&#34;&gt;趋势1：上云+托管&lt;/h3&gt;
&lt;p&gt;在微服务/容器这些年的发展历程中，我们会发现一个很有意思（甚至有些哭笑不得）的现象：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/trend1_hu94157af2c92bc19be9e7942749c34a85_107263_355b363063986dab568900f7c048c634.webp 400w,
               /talk/201905-servicemesh-development-trend/images/trend1_hu94157af2c92bc19be9e7942749c34a85_107263_483db29a924c45991342893c9a990b41.webp 760w,
               /talk/201905-servicemesh-development-trend/images/trend1_hu94157af2c92bc19be9e7942749c34a85_107263_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/trend1_hu94157af2c92bc19be9e7942749c34a85_107263_355b363063986dab568900f7c048c634.webp&#34;
               width=&#34;760&#34;
               height=&#34;308&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为了解决单体的复杂度问题，我们引入微服务架构&lt;/li&gt;
&lt;li&gt;为了解决微服务架构下大量应用部署的问题，我们引入容器&lt;/li&gt;
&lt;li&gt;为了解决容器的管理和调度问题，我们引入kubernetes&lt;/li&gt;
&lt;li&gt;为了解决微服务框架的侵入性问题，我们引入Service Mesh&lt;/li&gt;
&lt;li&gt;为了让 Service Mesh 有更好的底层支撑，我们又将 Service Mesh 运行在 k8s上&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在这个过程中，从单个应用（或者微服务）的角度看，的确自身的复杂度降低，在有底层系统支撑的情况下部署/维护/管理/控制/监控等也都大为简化。但是站在整个系统的角度，整体复杂度并没有消失，只是从单体分解到微服务，从应用下沉到Service Mesh，复杂度从总量上不但没有减少，反而大为增加。&lt;/p&gt;
&lt;p&gt;解决这个问题最好的方式就是 &lt;strong&gt;上云&lt;/strong&gt;，使用 &lt;strong&gt;托管&lt;/strong&gt; 版本的 k8s 和 Service Mesh，从而将底层系统的复杂度交给云厂商，而客户只需要在云的基础上享受 Service Mesh 技术带来的使用便利和强大功能。&lt;/p&gt;
&lt;p&gt;前面我们分享产品动态时，可以看到目前 Google / AWS / 微软 这三巨头都已经推出了各自的 Service Mesh 托管产品，而在国内，阿里云/华为云等也有类似的产品推出，我们蚂蚁金服也将在稍后在金融云上推出 SOFAMesh 的云上托管版本。在这里，我总结为一句话：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;几乎所有的主要公有云提供商都在提供（或者准备提供）Service Mesh托管方案&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&#34;趋势2vm和容器混用&#34;&gt;趋势2：VM和容器混用&lt;/h3&gt;
&lt;p&gt;第二个趋势就是VM和容器混用，即 Service Mesh 对服务的运行环境的支持，不仅支持容器（尤其指k8s），也支持虚拟机，而且支持运行在这两个环境下的服务相互访问，甚至直接在产品层面上屏蔽两者的差异。&lt;/p&gt;
&lt;p&gt;比如 Google 的 Traffic Director 产品：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/google-traffic-director_hud1becd506401a24bb8320f4ce8489cab_413874_7a1c76d5b5f05bcc90160903f66a0d72.webp 400w,
               /talk/201905-servicemesh-development-trend/images/google-traffic-director_hud1becd506401a24bb8320f4ce8489cab_413874_e1acf4a108b7752c9f68d7b4cfd92a7e.webp 760w,
               /talk/201905-servicemesh-development-trend/images/google-traffic-director_hud1becd506401a24bb8320f4ce8489cab_413874_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/google-traffic-director_hud1becd506401a24bb8320f4ce8489cab_413874_7a1c76d5b5f05bcc90160903f66a0d72.webp&#34;
               width=&#34;760&#34;
               height=&#34;372&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;AWS 的 App Mesh产品：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/appmesh_hu82dc9b635921e2fb6fb4d2e4e2e711a8_131887_0b060e7a6253fe3e564780f322a48e8a.webp 400w,
               /talk/201905-servicemesh-development-trend/images/appmesh_hu82dc9b635921e2fb6fb4d2e4e2e711a8_131887_333315954acea5951c2ceb5d5fc9f766.webp 760w,
               /talk/201905-servicemesh-development-trend/images/appmesh_hu82dc9b635921e2fb6fb4d2e4e2e711a8_131887_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/appmesh_hu82dc9b635921e2fb6fb4d2e4e2e711a8_131887_0b060e7a6253fe3e564780f322a48e8a.webp&#34;
               width=&#34;760&#34;
               height=&#34;415&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;都是在产品层面直接提供VM和容器混用的支持，不管应用是运行在vm上还是容器内都可以支持，而且可以方便的迁移。&lt;/p&gt;
&lt;h3 id=&#34;趋势3混合云和多云支持&#34;&gt;趋势3：混合云和多云支持&lt;/h3&gt;
&lt;p&gt;混合云和多云支持最近正成为一个新的技术热点和商业模式，甚至 Google Cloud 都喊出口号，要 &amp;ldquo;All in Hybrid Cloud&amp;rdquo;！&lt;/p&gt;
&lt;p&gt;Google Traffic Director 旗帜鲜明的表达了 Google Cloud 对混合云的重视：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/google-traffic-director-hybird_huce2be9135a5517fbf394e68709310a38_401371_fb13556e9001c2f86118ca5049a97ef9.webp 400w,
               /talk/201905-servicemesh-development-trend/images/google-traffic-director-hybird_huce2be9135a5517fbf394e68709310a38_401371_0f4d2743ed0e0a7b38bd05da81405d98.webp 760w,
               /talk/201905-servicemesh-development-trend/images/google-traffic-director-hybird_huce2be9135a5517fbf394e68709310a38_401371_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/google-traffic-director-hybird_huce2be9135a5517fbf394e68709310a38_401371_fb13556e9001c2f86118ca5049a97ef9.webp&#34;
               width=&#34;760&#34;
               height=&#34;303&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;下图是 Google Traffic Director  给出的一个应用改造示例：从单体结构转为微服务架构，从私有云转为公有云加私有云的混合云模式。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/google-traffic-director-hybird2_hue1961457013e92c14b2dca03b63e6b56_466835_1a18b67d00a9cf7c791d877bc6897a97.webp 400w,
               /talk/201905-servicemesh-development-trend/images/google-traffic-director-hybird2_hue1961457013e92c14b2dca03b63e6b56_466835_2f8fc1cce6ce33485fbccac4de3ac153.webp 760w,
               /talk/201905-servicemesh-development-trend/images/google-traffic-director-hybird2_hue1961457013e92c14b2dca03b63e6b56_466835_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/google-traffic-director-hybird2_hue1961457013e92c14b2dca03b63e6b56_466835_1a18b67d00a9cf7c791d877bc6897a97.webp&#34;
               width=&#34;760&#34;
               height=&#34;352&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Service Mesh 毫无疑问是实现上述转型并提供混合云和多云支持的一个非常理想的解决方案。&lt;/p&gt;
&lt;h3 id=&#34;趋势4和-serverless-的结合&#34;&gt;趋势4：和 Serverless 的结合&lt;/h3&gt;
&lt;p&gt;Service Mesh 技术和 Serverless 技术是工作在不同纬度的两个技术：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Service Mesh技术的关注点在于&lt;strong&gt;服务间通讯&lt;/strong&gt;，其目标是剥离客户端SDK，为应用减负，提供的能力主要包括安全性、路由、策略执行、流量管理等。&lt;/li&gt;
&lt;li&gt;Serverless 技术的关注点在于&lt;strong&gt;服务运维&lt;/strong&gt;，目标是客户无需关注服务运维，提供服务实例的自动伸缩，以及按照实际使用付费。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;理论上 Service Mesh 技术和 Serverless 技术并没有冲突的地方，可以结合使用。事实上目前业界也开始出现这个趋势，而融合的方式有两种：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在Serverless中引入Servicemesh：典型如 knative 项目和 knative 的 Google Cloud 托管版本 Google Cloud Run，通过引入对容器的支持和使用 Istio，knative 将 Serverless 的支持扩展到 Function 之外，在极大的扩展 Serverless 适用范围的前提下，也将服务间通讯的能力引入到 Serverless。&lt;/li&gt;
&lt;li&gt;在Servicemesh中引入 Serverless：典型如 Google Traffic Director 产品，在提供 Service Mesh 各种能力的同时，支持按照流量自动伸缩服务的实例数量，从而融入了部分 serverless 的特性。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对于 Serverless 和 Servicemesh 的结合，我们来展望未来形态：未来应该会出现一种新型服务模式，Serverless 和 Servicemesh 合二为一。只要将服务部署上来，就自动可以得到 Servicemesh 的服务间通讯能力和 Serverless的无服务器运维。在蚂蚁金服，我们将这理解成为是未来云原生应用的终态之一，正在积极的探索其落地的实际方式。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/servicemesh-serverless_hub8d93c56ef289e60a469b5f8d523c594_50977_f6b878f8b9e23ec161b9cbe6960c219e.webp 400w,
               /talk/201905-servicemesh-development-trend/images/servicemesh-serverless_hub8d93c56ef289e60a469b5f8d523c594_50977_75fef93d0a0ccbddcfd770ac7fb6ea79.webp 760w,
               /talk/201905-servicemesh-development-trend/images/servicemesh-serverless_hub8d93c56ef289e60a469b5f8d523c594_50977_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/servicemesh-serverless_hub8d93c56ef289e60a469b5f8d523c594_50977_f6b878f8b9e23ec161b9cbe6960c219e.webp&#34;
               width=&#34;400&#34;
               height=&#34;300&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;趋势5mesh模式延伸&#34;&gt;趋势5：Mesh模式延伸&lt;/h3&gt;
&lt;p&gt;回顾一下 Service Mesh 模式的核心，其基本原理在于将客户端SDK剥离，以 Proxy 独立进程运行；目标是将原来存在于SDK中的各种能力下沉，为应用减负，以帮助应用云原生化。&lt;/p&gt;
&lt;p&gt;遵循这个思路，将 Service Mesh 的应用场景泛化，不局限于服务间的同步通信，就可以推广到更多的场景：特征是有网络访问，而是通过客户端SDK来实现。&lt;/p&gt;
&lt;p&gt;在蚂蚁金服的实践中，我们发现Mesh模式不仅仅适用于服务间同步通讯，也可以延伸到以下场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Database Mesh: 数据库访问&lt;/li&gt;
&lt;li&gt;Message Mesh：消息机制&lt;/li&gt;
&lt;li&gt;Cache Mesh：缓存&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上模式的产品蚂蚁金服都在探索中，相关的产品正在开发和尝试落地。社区也有一些相关的产品，比如 Database Mesh 方面张亮同学在力推的  &lt;a href=&#34;https://shardingsphere.apache.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Apache Shardingsphere&lt;/a&gt; 项目。&lt;/p&gt;
&lt;p&gt;通过更多的 Mesh 模式，我们可以覆盖更多的场景，从而实现让应用在各个方面都做到减负，而不仅仅是 Service Mesh 对应的服务间通讯，从而为后续的应用云原生化奠定基础。&lt;/p&gt;
&lt;h3 id=&#34;趋势6标准化不锁定&#34;&gt;趋势6：标准化，不锁定&lt;/h3&gt;
&lt;p&gt;云原生的一个重要主张，就是希望在云上为用户提供一致的用户体验，提倡标准化，避免供应商绑定（Not Lock-In）。&lt;/p&gt;
&lt;p&gt;从前面分享的 Service Mesh 产品动态可以看出，目前 Service Mesh 市场上出现了众多的供应商和产品：开源的，闭源的，大公司出的，小公司出的，市场繁荣的同时也带来了市场碎片化的问题——所有围绕业务应用的外围工作，比如通过 Service Mesh 对流量进行控制，配置各种安全/监控/策略等行为，以及在这些需求上建立起来的工具和生态系统，却不得不牢牢的绑死在某个具体的 Service Mesh 实现上，所谓”供应商锁定”。其根本问题在于各家实现不同，又没有统一标准。因此，要想解决上述问题，就必须釜底抽薪：&lt;strong&gt;解决 Service Mesh 的标准化问题&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;就在最近这一个月，Service Mesh 社区出现了两个推动标准化的大事件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;CNCF筹建 Universal Data Plane API （通用数据平面API）工作组，计划以 xDS v2 API 为基础制定数据平面的标准API，工作组的初始成员来自包括 Envoy 和 gRPC 项目的代表（可以理解为 Google 为首）&lt;/li&gt;
&lt;li&gt;微软在 kubeconf 上推出 Service Mesh Interface，准备定义在 Kubernetes 上运行服务网格的规范，为 Service Mesh 带来了灵活性和互通性。SMI由微软牵头，联合 Linkerd，HashiCorp，Solo，Kinvolk和Weaveworks。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;为了方便理解这两个标准，我为大家准备了一张图：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/trend6_hua970b559b9d743d44c34e6fbe181f921_10038_16b77d3bb2dbde335a960ab880e8e01f.webp 400w,
               /talk/201905-servicemesh-development-trend/images/trend6_hua970b559b9d743d44c34e6fbe181f921_10038_464c342d3f9903da00c7c0f060e86390.webp 760w,
               /talk/201905-servicemesh-development-trend/images/trend6_hua970b559b9d743d44c34e6fbe181f921_10038_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/trend6_hua970b559b9d743d44c34e6fbe181f921_10038_16b77d3bb2dbde335a960ab880e8e01f.webp&#34;
               width=&#34;600&#34;
               height=&#34;546&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;其中，Universal Data Plane API 是数据平面的标准，控制平面通过这个API来控制数据平面的行为。而Service Mesh Interface 是控制平面的标准，上层的应用/工具/生态体系通过 Service Mesh Interface 来实现跨不同的Service Mesh实现为最终用户提供一致性的体验。&lt;/p&gt;
&lt;p&gt;当然这两个标准化API都刚刚起步，而且，标准化的工作通常不仅仅是技术问题，涉及到复杂的利益关系，具体未来走向现在难于推断，只能密切关注。&lt;/p&gt;
&lt;h3 id=&#34;发展趋势分析&#34;&gt;发展趋势分析&lt;/h3&gt;
&lt;p&gt;我们总结一下上面列出的 Service Mesh 最近的6个发展趋势：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/trend-analysis_hua232e8e9916a15cd493f0919cb4adfca_134286_722e78881c6752995a36c7d38a570df7.webp 400w,
               /talk/201905-servicemesh-development-trend/images/trend-analysis_hua232e8e9916a15cd493f0919cb4adfca_134286_61c6271b07529eb0095d43ce2027fe8d.webp 760w,
               /talk/201905-servicemesh-development-trend/images/trend-analysis_hua232e8e9916a15cd493f0919cb4adfca_134286_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/trend-analysis_hua232e8e9916a15cd493f0919cb4adfca_134286_722e78881c6752995a36c7d38a570df7.webp&#34;
               width=&#34;760&#34;
               height=&#34;373&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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;strong&gt;专注业务&lt;/strong&gt;的战略目标。&lt;/p&gt;
&lt;p&gt;对于 Service Mesh 技术未来的走向，我的看法是：Service Mesh 技术必然不是孤立的自行发展，而是在云原生的大环境下，与云原生的其他技术、理念、最佳实践一起相互影响、相互促进、相互支撑、共同发展。云原生是一个庞大的技术体系，Service Mesh 需要在这个体系中获得各种支撑和配合，才能最大限度的发挥自身的优势。&lt;/p&gt;
&lt;h2 id=&#34;service-mesh与云原生&#34;&gt;Service Mesh与云原生&lt;/h2&gt;
&lt;p&gt;在最后一段，我们来谈谈 Service Mesh 技术和云原生的关系，也就是本次分享的标题所说的：云原生中流砥柱。&lt;/p&gt;
&lt;p&gt;凭什么？&lt;/p&gt;
&lt;h3 id=&#34;什么是云原生&#34;&gt;什么是云原生？&lt;/h3&gt;
&lt;p&gt;在解释之前，首先问一个问题：什么是云原生？相信这个问题很多同学都问过，或者被问过，每个人心里可能都有自己的理解和表述。在今年年初，我也特意就这个问题问了自己，然后尝试着给出了一个我的答案：&lt;/p&gt;
&lt;p&gt;云原生指 &amp;ldquo;原生为云设计&amp;rdquo;，具体说就是：&lt;strong&gt;应用原生被设计为在云上以最佳方式运行，充分发挥云的优势。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/cloud-native_hufc06ada688985255dcadf2c9e3533556_140958_1ebd2cb0e3038cee826a172e089c49ef.webp 400w,
               /talk/201905-servicemesh-development-trend/images/cloud-native_hufc06ada688985255dcadf2c9e3533556_140958_7c4071bddb421d1a35139ca18737452b.webp 760w,
               /talk/201905-servicemesh-development-trend/images/cloud-native_hufc06ada688985255dcadf2c9e3533556_140958_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/cloud-native_hufc06ada688985255dcadf2c9e3533556_140958_1ebd2cb0e3038cee826a172e089c49ef.webp&#34;
               width=&#34;600&#34;
               height=&#34;450&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;关于云原生的理解，以及对这句话的详细阐述，这里不详细展开，有兴趣的同学可以浏览我之前的演讲内容，讲的比较深入，厚颜自荐一下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;畅谈云原生（上）&lt;/a&gt;: 如何理解云原生？云原生应用应该是什么样子？云原生下的中间件该如何发展？&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;畅谈云原生（下）&lt;/a&gt;: 云和应用该如何衔接？如何让产品更符合云原生？&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;service-mesh的核心价值&#34;&gt;Service Mesh的核心价值&lt;/h3&gt;
&lt;p&gt;关于 Service Mesh 的核心价值，我个人的理解，不在于 Service Mesh 提供的玲琅满目的各种功能和特性，而是：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;实现业务逻辑和非业务逻辑的分离&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;将非业务逻辑的功能实现，从客户端SDK中剥离出来，放到独立的 Proxy 进程中，这是 Service Mesh 在技术实现上走出的第一步，也是至关重要的第一步：因为这一步，实现了&lt;strong&gt;业务逻辑&lt;/strong&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;下沉到基础设施，基础设施可以是基于VM的，可以是基于容器和k8s的；也可以是VM和容器混合&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;ul&gt;
&lt;li&gt;为下沉到基础设施提供可能&lt;/li&gt;
&lt;li&gt;为上云提供可能&lt;/li&gt;
&lt;li&gt;为应用轻量化提供可能&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：这里说的上云，指的是上云原生(Cloud Native)的云，而不是上云就绪(Cloud Ready)的云。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;mesh化是云原生落地的关键步骤&#34;&gt;Mesh化是云原生落地的关键步骤&lt;/h3&gt;
&lt;p&gt;在过去一年中，蚂蚁金服一直在努力探索云原生落地的方式，在这个过程中，我们有一些感悟，其中非常重要的一条就是：Mesh化是云原生落地的关键步骤。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/cloud-native-important-step_hua0f2f0fe3c5d79f21d73209605b9da89_170505_63a06d38a717b2a46ca33003391a00cf.webp 400w,
               /talk/201905-servicemesh-development-trend/images/cloud-native-important-step_hua0f2f0fe3c5d79f21d73209605b9da89_170505_9c4c130e594c20f838dc9106e7902772.webp 760w,
               /talk/201905-servicemesh-development-trend/images/cloud-native-important-step_hua0f2f0fe3c5d79f21d73209605b9da89_170505_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/cloud-native-important-step_hua0f2f0fe3c5d79f21d73209605b9da89_170505_63a06d38a717b2a46ca33003391a00cf.webp&#34;
               width=&#34;760&#34;
               height=&#34;308&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如上图所示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;最下方是云，基于k8s和容器打造，提供各种基础能力，这些能力有一部分来自传统中间件的下沉&lt;/li&gt;
&lt;li&gt;在云上是 Mesh 层，包含 Service Mesh 以及我们前面提到的各种扩展的Mesh模式，实现通信的标准化&lt;/li&gt;
&lt;li&gt;在通过 Mesh 剥离非业务功能并下沉之后，应用实现了轻量化，传统的App和新兴的微服务都可以受益于此&lt;/li&gt;
&lt;li&gt;更进一步，轻量化之后的业务应用，其工作负载在瘦身减负之后变得相当的干净，基本只剩业务逻辑，包括传统的App，以Container形式运行的服务和新颖的Function，这些负载在往 Serverless 形态转换时相对要轻松很多&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;配合 Serverless 技术领域最新的技术潮流和产品发展（如以 knative 项目为代表，Serverless 不再仅仅是 Function 形式，也支持 BaaS 等偏传统的工作负载），Mesh化为现有应用转型为 Serverless 模式提供助力。&lt;/p&gt;
&lt;p&gt;在这里我们再分享一下蚂蚁金服对未来中间件产品发展的感悟，我们认为中间件的未来在于&lt;strong&gt;Mesh化，并融入基础设施&lt;/strong&gt;，如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/middleware-future_hu121e5b800aec21a23093d66e9875763b_239717_d5372710b7ba80bbcb14bb760516ce31.webp 400w,
               /talk/201905-servicemesh-development-trend/images/middleware-future_hu121e5b800aec21a23093d66e9875763b_239717_f4320fe6218dc58460610bb73b4af4ab.webp 760w,
               /talk/201905-servicemesh-development-trend/images/middleware-future_hu121e5b800aec21a23093d66e9875763b_239717_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/middleware-future_hu121e5b800aec21a23093d66e9875763b_239717_d5372710b7ba80bbcb14bb760516ce31.webp&#34;
               width=&#34;760&#34;
               height=&#34;314&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;左边是传统的中间件形态，在云原生时代，我们希望将非业务功能从传统中间件的富客户端中剥离出来，然后将这些能力以及这些能力背后的中间件能力，下沉到基础设施，下沉到云。而中间件产品也会融入基础设施，如图中右边所示。未来的中间件将作为基础设施和云的一部分，而 Mesh 则成为连接应用和基础设施以及其他中间件产品的桥梁。&lt;/p&gt;
&lt;p&gt;更重要的是：业务应用因此而实现轻量化，在剥离各种非业务功能之后，业务应用就实现了只关注业务逻辑的战略目标，从而实现从传统应用到云原生应用的转型。&lt;/p&gt;
&lt;p&gt;总结：通过 Service Mesh 技术，我们实现了业务逻辑和非业务逻辑的分离，为应用的轻量化和云原生化提供可能；并通过将非业务逻辑的各种功能下沉到基础设施和云，极大的增强了基础设施和云的能力，为云原生的落地提供了极大助力。&lt;/p&gt;
&lt;p&gt;因此，我们认为： Service Mesh技术将在云原生落地中扮演了非常重要的作用，不可或缺。&lt;/p&gt;
&lt;h3 id=&#34;service-mesh发展展望&#34;&gt;Service Mesh发展展望&lt;/h3&gt;
&lt;p&gt;最后再次展望一下 Service Mesh 的未来发展。&lt;/p&gt;
&lt;p&gt;左边是 Service Mesh 发展初期的最重要的两个原始动力：&lt;strong&gt;多语言支持&lt;/strong&gt;和&lt;strong&gt;类库升级&lt;/strong&gt;。关于这两点，最近这两年中介绍和推广 Service Mesh 理念和产品的同学基本都讲过，但是今天我想指出的是：这只是 Service Mesh 的&lt;strong&gt;起点&lt;/strong&gt;，而远不是 Service Mesh 的终点。&lt;/p&gt;
&lt;p&gt;Service Mesh 的未来，不会停留在仅仅满足多语言支持和类库升级，而是跟随云原生的大潮，解决各种实际需求，同时又尽量维持上层业务应用的简单直白。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/future-of-servicemesh_hubbfdecd30f6b91110416561dad47ca11_293783_c29df64ea14b07b5f5026eddce3aac48.webp 400w,
               /talk/201905-servicemesh-development-trend/images/future-of-servicemesh_hubbfdecd30f6b91110416561dad47ca11_293783_a1eb0be69648390cee00d1b8ad509d26.webp 760w,
               /talk/201905-servicemesh-development-trend/images/future-of-servicemesh_hubbfdecd30f6b91110416561dad47ca11_293783_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/future-of-servicemesh_hubbfdecd30f6b91110416561dad47ca11_293783_c29df64ea14b07b5f5026eddce3aac48.webp&#34;
               width=&#34;760&#34;
               height=&#34;363&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在这次分享的最后，我想给大家一个留一个课外作业，有心的同学可以尝试一下：如果您想更深入的理解 Service Mesh 的价值，想对 Service Mesh 未来的发展方向有更清晰的认识，尤其是希望能通过自身的思考和感悟来理解 Service Mesh 而不是简单的被灌输（包括被我灌输），那么请尝试独立的做如下思考：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;抛开左边的这两点，不要将思维局限在这个范围内&lt;/li&gt;
&lt;li&gt;考虑云原生的大背景，结合您自身对云原生的理解，和对云的期望&lt;/li&gt;
&lt;li&gt;针对右边的 Service Mesh 的六个趋势，忘记我前面讲述的内容，只考虑其背后的实际场景和客户需求，以及这个场景带来的业务价值，然后认真对比使用 Service Mesh 和不使用 Service Mesh 两种情况下的解决方案&lt;/li&gt;
&lt;li&gt;请在上述思考的过程中，更多的从业务应用的角度来看待问题，假设你是那个云上的应用（还记得前面图上的小baby吗？），你会希望被如何对待&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;希望这样的思考能让您有所收获。&lt;/p&gt;
&lt;h2 id=&#34;尾声&#34;&gt;尾声&lt;/h2&gt;
&lt;p&gt;最后做个广告，欢迎大家参加 SOFAStack 云原生工作坊，我们将在这次活动中，推出蚂蚁金服金融云完全托管版本的SOFAMesh的体验版本，欢迎报名参加。我将在上海 kubeconf 的 workshop 现场恭候大驾。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201905-servicemesh-development-trend/images/workshop_hu769bafe6856dfc72f0ba8103862c97c2_296900_6d412a9d42e980232e3e3d68c3ba97ee.webp 400w,
               /talk/201905-servicemesh-development-trend/images/workshop_hu769bafe6856dfc72f0ba8103862c97c2_296900_31cf4dd33277489a56fe88b7ddb8922e.webp 760w,
               /talk/201905-servicemesh-development-trend/images/workshop_hu769bafe6856dfc72f0ba8103862c97c2_296900_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201905-servicemesh-development-trend/images/workshop_hu769bafe6856dfc72f0ba8103862c97c2_296900_6d412a9d42e980232e3e3d68c3ba97ee.webp&#34;
               width=&#34;760&#34;
               height=&#34;379&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;提示：请使用&lt;strong&gt;钉钉&lt;/strong&gt;扫描上面的二维码。或者直接访问 &lt;a href=&#34;https://www.lfasiallc.com/events/kubecon-cloudnativecon-china-2019/schedule-chinese/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;kubeconf的活动页面&lt;/a&gt; 查看这次 workshop 的详细内容。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译] Hello Service Mesh Interface(SMI):服务网格互通性规范</title>
      <link>https://skyao.net/post/201905-smi-a-specification-for-service-mesh-interoperability/</link>
      <pubDate>Wed, 22 May 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201905-smi-a-specification-for-service-mesh-interoperability/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://msft.today/hello-service-mesh-interface-smi-a-specification-for-service-mesh-interoperability/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Hello Service Mesh Interface (SMI): A specification for service mesh interoperability&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;今天，我们很高兴的推出 Service Mesh Interface（SMI）。SMI定义了一组通用可移植的API，为开发人员提供跨不同服务网格技术的互通性，包括Istio，Linkerd和Consul Connect。SMI是一个开放项目，由微软，Linkerd，HashiCorp，Solo，Kinvolk和Weaveworks联合启动; 并得到了Aspen Mesh，Canonical，Docker，Pivotal，Rancher，Red Hat和VMware的支持。&lt;/p&gt;
&lt;p&gt;多年来，网络架构的口头禅是让网络管道尽可能愚蠢，并在应用中构建智能。网络的工作是转发数据包，而加密，压缩或身份的任何逻辑都存在于网络端点内。互联网是以这个口头禅为前提的，运作得相当好。&lt;/p&gt;
&lt;p&gt;但是，随着微服务，容器和像Kubernetes这样的编排系统的爆炸式增长，工程团队面临的问题是越来越多的网络端点需要进行安全，管理和监控。服务网格技术通过使网络更智能来提供解决此问题的方案。服务网格技术不再要求所有服务进行加密会话，授权客户端，发出合理的遥测，并在应用程序版本之间无缝转换流量，而是将此逻辑推入网络，由一组单独的管理API控制。&lt;/p&gt;
&lt;p&gt;这是云原生生态系统中的流行模式。我们看到服务网格技术激增，许多供应商为应用程序开发人员提供了新的令人兴奋的选择。问题是转向网格技术的开发人员必须选择供应商并直接使用这些API编码。他们被锁定在服务网格实现中。如果没有通用接口，开发人员就会失去可移植性，灵活性，而且能力限制导致无法从广泛的生态系统中获益。&lt;/p&gt;
&lt;p&gt;Service Mesh Interface提供：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Kubernetes上网格的标准接口&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;h2 id=&#34;smi涵盖的内容&#34;&gt;SMI涵盖的内容&lt;/h2&gt;
&lt;p&gt;我们与HashiCorp，Buoyant，Solo和其他公司合作，为我们从企业客户那里获得的三大服务网格功能构建初始规范：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Traffic policy/流量策略 - 跨服务应用身份和传输加密等策略&lt;/li&gt;
&lt;li&gt;Traffic telemetry/流量遥测 - 捕获服务之间的关键指标，如错误率和延迟&lt;/li&gt;
&lt;li&gt;Traffic management/流量管理 - 在不同服务之间转移和加权流量&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这只是我们希望通过SMI得到的起点。考虑到开发中有许多令人兴奋的网格功能，我们非常希望随着时间的推移不断发展SMI API，并期待通过新功能扩展当前规范。&lt;/p&gt;
&lt;h2 id=&#34;smi如何运作&#34;&gt;SMI如何运作&lt;/h2&gt;
&lt;p&gt;Service Mesh Interface背后的想法并不新鲜。它追随 Ingress，Network Policy 和 CNI 等现有Kubernetes资源的脚步。与Ingress或 Network Policy 一样，SMI不提供实现。相反，SMI规范定义了一组通用API，允许网格供应商提供自己的最佳实现。可以通过两种方式实现与SMI的集成。工具和网格供应商可以直接使用SMI API，也可以构建 Operator 以将SMI转换为原生API。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“SMI是Linkerd实现服务网络民主化目标的一大进步，我们很高兴能够为更多Kubernetes用户提供Linkerd的简单性和性能。”——William Morgan，Linkerd维护者&lt;/p&gt;
&lt;p&gt;“接口的标准化对于确保跨技术和生态系统协作的最佳用户体验至关重要。凭借这种精神，我们很高兴能与微软和其他公司合作开发SMI规范，并已经通过Service Mesh Hub和SuperGloo项目提供了第一个参考实现。“——Solo.io创始人兼首席执行官Idit Levine说道。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;生态系统友好&#34;&gt;生态系统友好&lt;/h2&gt;
&lt;p&gt;对于服务网格这样的早期技术，我们必须为生态系统创造空间，以进行创新并探索解决客户问题的不同方法。随着服务网格技术的不断发展，SMI提供的互通性将有助于与现有网格供应商集成的新兴工具和实用程序的生态系统。而不是单独与每个网格集成，像flagger和SuperGloo这样的工具可以与SMI集成，从而获得跨网格功能。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;VMware NSX Service Mesh 首席架构师 Sushil Singh表示：“服务网络的兴趣和动力已达到一个关键点——行业需要在一系列的标准上进行协作，以确保成功。” “服务网络为应用程序的未来提供了丰富的基础功能。现在是制定标准API的最佳时机，这些API可简化服务网格技术的使用和功能，从而实现健康的生态系统。VMware很高兴可以参与这项非常重要的工作”&lt;/p&gt;
&lt;p&gt;“客户和社区成员都在寻求一种方法来更好地标准化服务网格的配置和运维。随着Service Mesh Interface（SMI）的出现，我们认为这是一种很好的方法，可以帮助我们最大化Red Hat OpenShift客户选择的灵活度。这种灵活度让用户可以优先考虑功能而不纠结实现细节” —— Red Hat服务网络首席产品经理 Brian Redbeard Harrington说道。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;加入对话&#34;&gt;加入对话&lt;/h2&gt;
&lt;p&gt;我们迫不及待地想看看Service Mesh Interface如何发展，欢迎大家加入对话。请访问&lt;a href=&#34;https://smi-spec.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;SMI网站&lt;/a&gt;。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译] Service Mesh Interface (SMI) 以及我们对社区和生态系统的愿景</title>
      <link>https://skyao.net/post/201905-smi-and-our-vision/</link>
      <pubDate>Wed, 22 May 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201905-smi-and-our-vision/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://medium.com/solo-io/service-mesh-interface-smi-and-our-vision-for-the-community-and-ecosystem-2edc7b728c43&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Service Mesh Interface (SMI) and our Vision for the Community and Ecosystem&lt;/a&gt;，作者 &lt;a href=&#34;https://medium.com/@idit.levine_92620&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Idit Levine&lt;/a&gt;，是初创公司 solo.io 的创始人兼CEO。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;服务网格生态系统正在兴起，众多的网格供应商和不同的用例需要不同的技术。所以问题来了：我们如何实现在不破坏最终用户体验的前提下促进行业创新？通过以一组标准API达成一致，我们可以提供互通性，并在不同网格以及为这些网格构建的工具之上维持最终用户体验。&lt;/p&gt;
&lt;p&gt;今天发布的 Service Mesh Interface（SMI）是使这一构想走向行业现实的重要一步。&lt;/p&gt;
&lt;p&gt;SMI 是在 Kubernetes 上运行服务网格的规范。它定义了由各种供应商实现的通用标准。这使得最终用户的标准化和服务网格供应商的创新可以两全其美。SMI 实现了灵活性和互通性。&lt;/p&gt;
&lt;h3 id=&#34;smi最大限度地降低复杂度同时最大化服务网格的优势&#34;&gt;SMI最大限度地降低复杂度，同时最大化服务网格的优势&lt;/h3&gt;
&lt;p&gt;不同服务网格的复杂度和差异使得难以研究和运营单个解决方案，更不用说多个解决方案。为了让服务网格的采用变得简单而平滑，Solo.io 正在与 Microsoft 和其他公司合作，对接口进行标准化，以确保优异的用户体验，以及生态系统在实现创新时的一致性和互通性。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SMI负责与网格相关的关键功能&lt;/strong&gt;，包括加密，遥测和跟踪。启动这些功能就像按开关一般简单，完全不需要复杂的配置步骤。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SMI将简化以尝试不同的网格并在它们之间进行迁移。&lt;/strong&gt; 标准接口和API可以快速无痛地从一个网格转换到另一个网格，以防止网格供应商锁定。随着生态系统的快速发展，众多网格供应商和最终用户希望拥有改变想法的灵活性。&lt;/p&gt;
&lt;p&gt;**SMI对生态系统友好，允许最终用户使用相同的工具集。**一致的API让为一个网格构建的产品可以与另一个符合规范的网格互操作，最终用户可以因此维护一致的工作流程。&lt;/p&gt;
&lt;h3 id=&#34;smi-在-soloio&#34;&gt;SMI 在 Solo.io&lt;/h3&gt;
&lt;p&gt;在Solo.io，我们去年开始了这个多网格愿景之旅，开源了&lt;a href=&#34;https://github.com/solo-io/Supergloo&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;strong&gt;SuperGloo&lt;/strong&gt;&lt;/a&gt;项目，这是一个抽象层，统一并自动化编排任意服务网格。SuperGloo 提供了一个简单的API，可以安装并运营来自一个或多个供应商的单个或多个集群网格。&lt;/p&gt;
&lt;p&gt;上周，我们通过 &lt;a href=&#34;https://servicemeshhub.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;strong&gt;Service Mesh Hub&lt;/strong&gt;&lt;/a&gt; 的发布继续这一愿景，Service Mesh Hub 是第一个用于最终用户、社区和生态系统进行构建、共享和协作的行业中心。Service Mesh Hub是一个统一的Dashboard，用于安装、发现和运维单个或一组网格，以及在其上运行的服务和扩展。Hub的扩展目录（Extensions Catalog）是社区和生态系统用于构建和共享工具的地方，这些工具特意设计来为网格环境带来附加功能。Service Mesh Hub构建于SuperGloo项目的基础之上并进行扩展。&lt;/p&gt;
&lt;p&gt;随着今天的发布，SuperGloo和Service Mesh Hub已经更新以支持SMI规范，并且是第一个可用的参考实现。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：这里有一个视频，由于原文所在的 medium.com 拒绝直接链接视频，所以只能请读者通过访问英文原文页面观看视频。（注意 medium.com 需要科学上网）&lt;/p&gt;
&lt;p&gt;或者直接访问 &lt;a href=&#34;https://www.youtube.com/watch?time_continue=4&amp;amp;v=SkPXlW1M5No&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;youtube&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;多网格的愿景并未完成，请在Solo.io上与我们联系，了解我们接下来要做什么。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译] 为何 WebAssembly 如此重要</title>
      <link>https://skyao.net/post/201905-why-webassembly-is-a-big-deal/</link>
      <pubDate>Thu, 16 May 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201905-why-webassembly-is-a-big-deal/</guid>
      <description>&lt;p&gt;英文原文来自 &lt;a href=&#34;https://medium.com/@mikevdg/why-webassembly-is-a-big-deal-a308d72c6de1&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Why WebAssembly is a Big Deal&lt;/a&gt;，作者 &lt;a href=&#34;https://medium.com/@mikevdg&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Michael van der Gulik&lt;/a&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;WebAssembly是一个每个程序员都应该关注的技术。它会变得更流行。它将取代JavaScript。它将取代HTML和CSS。它将取代手机应用。它将取代桌面应用。在10年内，我保证每个程序员至少需要知道如何使用工具来操作WebAssembly并理解它是如何工作的。&lt;/p&gt;
&lt;p&gt;你可能会说，“太离谱了！” 好吧，请继续阅读。&lt;/p&gt;
&lt;h3 id=&#34;什么是webassembly&#34;&gt;什么是WebAssembly&lt;/h3&gt;
&lt;p&gt;当前形式的WebAssembly是Web浏览器的新扩展，可以运行预编译代码…&lt;strong&gt;快速&lt;/strong&gt;运行。在C ++中编写了一些小代码，然后使用Emscripten编译器将该代码编译为WebAssembly。通过一些Javascript粘合，就可以在Web浏览器中调用这一小段代码，例如，运行&lt;a href=&#34;https://embed.plnkr.co/jsMi5oltGnT0Jn38js3v/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;粒子模拟&lt;/a&gt;。&lt;/p&gt;
&lt;p&gt;WebAssembly文件，扩展名为.wasm，本身是包含可执行指令的&lt;a href=&#34;https://webassembly.github.io/spec/core/binary/index.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;二进制格式&lt;/a&gt;。要使用该文件，必须编写一个运行某些Javascript的HTML文件来获取、编译和执行WebAssembly文件。WebAssembly文件在基于堆栈的虚拟机上执行，并使用共享内存与其Javascript包装器进行通信。&lt;/p&gt;
&lt;p&gt;到目前为止，这似乎并不有趣。它看起来只不过是Javascript的加速器。但是，精明的读者会对WebAssembly可能成为什么有所了解。&lt;/p&gt;
&lt;h3 id=&#34;webassembly将成为什么&#34;&gt;WebAssembly将成为什么？&lt;/h3&gt;
&lt;p&gt;第一个重要发现是WebAssembly是一个安全的沙盒虚拟机。可以从Internet运行喜欢的WebAssembly代码，而确保它不会接管PC或服务器。四个主流Web浏览器对它的安全性非常有信心，它已经默认实现并启用了。它的真正安全性还有待观察，但安全性是WebAssembly的核心设计目标。&lt;/p&gt;
&lt;p&gt;第二个重要发现是WebAssembly是一个通用的编译目标。它的原始编译器是一个C编译器，这个编译器很好地指示了WebAssembly虚拟机的低级和可重定向性。许多编程语言都使用C语言编写虚拟机，其他一些语言甚至使用C本身作为编译目标。&lt;/p&gt;
&lt;p&gt;此时，有一个&lt;a href=&#34;https://github.com/appcypher/awesome-wasm-langs&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;可以编译为WebAssembly的编程语言列表&lt;/a&gt;。这份名单将在未来很多年中继续增长。&lt;/p&gt;
&lt;p&gt;WebAssembly允许使用任何编程语言编写代码，然后让其他人在任何平台上安全地运行该代码而无需安装任何内容。朋友们，这是美好梦想的开始。&lt;/p&gt;
&lt;h3 id=&#34;部署问题&#34;&gt;部署问题&lt;/h3&gt;
&lt;p&gt;我们来谈谈如何将软件提供给用户。&lt;/p&gt;
&lt;p&gt;为新项目选择编程语言的一个重要因素是如何将项目部署到客户。您的程序员喜欢用Haskell，Python，Visual Basic或其他语言编写应用程序，具体取决于他们的喜好。要使用喜欢的语言，他们需要编译应用，制作一些可安装的软件包，并以某种方式将其安装在客户端的计算机上。有许多方法可以提供软件 - 包管理器，可执行安装程序或安装服务，如Steam，Apple App Store，Google Play或Microsoft store。&lt;/p&gt;
&lt;p&gt;每一个安装机制都意味着痛苦，从应用商店安装时的轻微疼痛，到管理员要求在他的PC上运行一些旧的COBOL代码时的集群头痛。&lt;/p&gt;
&lt;p&gt;部署是一个问题，对于开发人员和系统管理员来说，这一直是一个痛点。我们使用的编程语言与我们所针对的平台密切相关。如果大量用户在PC或移动设备上，我们使用HTML和Javascript。如果用户是Apple移动设备用户，我们使用&amp;hellip;&amp;hellip;呃&amp;hellip;&amp;hellip; Swift？（我实际上不知道）。如果用户在Android设备上，我们使用Java或Kotlin。如果用户在真实计算机上并且愿意处理掉他们的部署问题，那么我们开发人员才能在我们使用的编程语言中有更多选择。&lt;/p&gt;
&lt;p&gt;WebAssembly有可能解决部署问题。&lt;/p&gt;
&lt;p&gt;使用WebAssembly，您可以使用任何编程语言编写应用，只要这些编程语言可以支持WebAssembly，而应用可以在任何设备和任何具有现代Web浏览器的操作系统上运行。&lt;/p&gt;
&lt;h3 id=&#34;硬件垄断&#34;&gt;硬件垄断&lt;/h3&gt;
&lt;p&gt;想购买台式机或笔记本电脑。有什么选择？好吧，有英特尔，有AMD。多年来一直是双寡头垄断。保持这种双寡头垄断的一个原因是x86架构只在这两家公司之间交叉许可，而且通常预编译的代码需要x86或x86-64（也就是 AMD-64）架构。还有其他因素，例如设计世界上最快的CPU是一件很艰难而去很昂贵的事情。&lt;/p&gt;
&lt;p&gt;WebAssembly是一种可让您在任何平台上运行代码的技术（之一）。如果它成为下一个风口，硬件市场将变得商品化。应用编译为WebAssembly，就可以在任何东西上运行 - x86，ARM，RISC-V，SPARC。即便是操作系统市场也会商品化; 您所需要的只是一个支持WebAssembly的浏览器，以便在硬件可以运行时运行最苛刻的应用程序。&lt;/p&gt;
&lt;h3 id=&#34;云计算&#34;&gt;云计算&lt;/h3&gt;
&lt;p&gt;但等等，还有更多。云计算成为IT经理办公室的流行词已有一段时间，WebAssembly可以直接迎合它。&lt;/p&gt;
&lt;p&gt;WebAssembly在安全沙箱中执行。可以制作一个容器，它可以在服务器上接受和执行WebAssembly模块，而资源开销很小。对于提供的每个服务，无需在虚拟机上运行完整的操作系统。托管提供商只提供对可以上传代码的WebAssembly容器的访问权限。它可以是一个原始容器，接收socket并解析自己的HTTP连接，也可以是一个完整的Web 服务容器，其中WebAssembly模块只需要处理预解析的HTTP请求。&lt;/p&gt;
&lt;p&gt;这还不存在。如果有人想变得富有，那么可以考虑这个想法。&lt;/p&gt;
&lt;h3 id=&#34;不是云计算&#34;&gt;不是云计算&lt;/h3&gt;
&lt;p&gt;WebAssembly足以取代PC上本地安装的大多数应用程序。我们已经使用WebGL（又名OpenGL ES 2.0）移植了游戏。我预测不久之前，像LibreOffice这样的大型应用可以直接从网站上获得而无需使用WebAssembly进行安装。&lt;/p&gt;
&lt;p&gt;在这种情况下，在本地安装应用没什么意义。本地安装的应用和WebAssembly应用之间几乎没有区别。WebAssembly应用已经可以使用屏幕，键盘和鼠标进行交互。它可以在2D或OpenGL中进行图形处理，并使用硬件对视频流进行解码。可以播放和录制声音。可以访问网络摄像头。可以使用WebSockets。可以使用IndexedDB存储大量数据在本地磁盘上。这些已经是Web浏览器中的标准功能，并且都可以使用Javascript向WebAssembly暴露。&lt;/p&gt;
&lt;p&gt;目前唯一困难的地方是WebAssembly无法访问本地文件系统。好吧，可以通过HTML使用文件上传对话，但这不算。最终，总会有人为此创建API，并可能称之为“WASI”。&lt;/p&gt;
&lt;p&gt;“从互联网上运行应用程序！？胡说八道！“，你说。&lt;a href=&#34;http://example.qt.io/qt-webassembly/widgets/richtext/textedit/textedit.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;好吧，这是使用Qt和WebAssembly 实现的文本编辑器&lt;/a&gt; （&lt;a href=&#34;https://blog.qt.io/blog/2018/05/22/qt-for-webassembly-examples/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;以及更多&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;这是一个简单的例子。复杂的例子是在WebBrowser中运行的 Adobe Premier Pro 或 Blender。或者考虑像Steam游戏一样可以直接从网络上运行。这听起来像小说，但从技术上说这并非不能发生。&lt;/p&gt;
&lt;p&gt;它会来的。&lt;/p&gt;
&lt;h3 id=&#34;让我们裸奔&#34;&gt;让我们裸奔！&lt;/h3&gt;
&lt;p&gt;目前，WebAssembly在包含HTML和Javascript包装器的环境中执行。为什么不脱掉这些？使用WebAssembly，为什么要在浏览器中包含HTML渲染器和Javascript引擎？&lt;/p&gt;
&lt;p&gt;通过为所有服务提供标准化API，这些服务通常是Web浏览器提供的，可以创建裸 WebAssembly。就是没有HTML和Javascript包装来管理的WebAssembly。访问的网页是.wasm文件，浏览器会抓取并运行该文件。浏览器为WebAssembly模块提供画布，事件处理程序以及对浏览器提供的所有服务的访问。&lt;/p&gt;
&lt;p&gt;这目前还不存在。如果现在使用Web浏览器直接访问.wasm文件，它会询问是否要下载它。我假设将设计所需的API并使其工作。&lt;/p&gt;
&lt;p&gt;结果是web可以发展。网站不再局限于HTML，CSS和Javascript。可以创建全新的文档描述语言。可以发明全新的布局引擎。而且，对于像我这样的polyglots最相关，我们可以选择任何编程语言来实现在线服务。&lt;/p&gt;
&lt;h3 id=&#34;可访问性&#34;&gt;可访问性&lt;/h3&gt;
&lt;p&gt;但我听到了强烈抗议！可访问性怎么样？？搜索引擎怎么办？&lt;/p&gt;
&lt;p&gt;好吧，我还没有一个好的答案。但我可以想象几种技术解决方案。&lt;/p&gt;
&lt;p&gt;一个解决方案是我们保留内容和表现的分离。内容以标准化格式编写，例如HTML。演示文稿由WebAssembly应用管理，该应用可以获取并显示内容。这允许网页设计师使用想要的任何技术进行任意演示 - 不需要CSS，而搜索引擎和需要不同类型的可访问性的用户仍然可以访问内容。&lt;/p&gt;
&lt;p&gt;请记住，许多WebAssembly应用并不是可以通过文本访问的，例如游戏和许多应用。盲人不会从图像编辑器中获得太多好处。&lt;/p&gt;
&lt;p&gt;另一个解决方案是发明一个API，它可以作为WebAssembly模块，来提供想在屏幕上呈现的DOM，供屏幕阅读器或搜索引擎使用。基本上会有两种表示形式：一种是在图形画布上，另一种是产生结构化文本输出。&lt;/p&gt;
&lt;p&gt;第三种解决方案是使用屏幕阅读器或搜索引擎可以使用的元数据来增强画布。执行WebAssembly并在画布上呈现内容，其中包含描述渲染内容的额外元数据。例如，该元数据将包括屏幕上的区域是否是菜单以及存在哪些选项，或者区域是否想要文本输入，以及屏幕上的区域的自然排序（也称为标签顺序）是什么。基本上，曾经在HTML中描述的内容现在被描述为具有元数据的画布区域。同样，这只是一个想法，它可能在实践中很糟糕。&lt;/p&gt;
&lt;h3 id=&#34;可能是什么&#34;&gt;可能是什么&lt;/h3&gt;
&lt;p&gt;1995年，Sun Microsystems发布了Java，带有Java applets和大量的宣传。有史以来第一次，网页可以做一些比&lt;code&gt;&amp;lt;marquee&amp;gt;&lt;/code&gt;和GIF动画更有趣的事情。开发人员可以使应用完全在用户的Web浏览器中运行。它们没有集成到浏览器中，而是实现为繁重的插件，需要安装整个JVM。1995年，这不是一个小的安装。applets也需要一段时间来加载并使用大量内存。我们现在凭借大量内存，这不再是一个问题，但在Java生命的第一个十年里，它让体验变得令人厌烦。&lt;/p&gt;
&lt;p&gt;applets也不可靠。无法保证它们会运行，尤其是在用户使用Microsoft的实现时。他们也不安全，这是棺材里的最后一颗钉子。&lt;/p&gt;
&lt;p&gt;以JVM为荣，其他语言最终演变为在JVM上运行。但现在，那艘船航行了。&lt;/p&gt;
&lt;p&gt;FutureSplash / Macromedia / Adobe Flash也是一个竞争者，但是是专有的，具有专有工具集和专有语言的专有格式。我读到他们确实在2009年开启了文件格式。最终从浏览器中删除了支持，因为它存在安全风险。&lt;/p&gt;
&lt;p&gt;这里的结论是，如果希望您的技术存在于每个人的机器上，那么安全性就需要正视。我真诚地希望WebAssembly作为标准对安全问题做出很好的反应。&lt;/p&gt;
&lt;h3 id=&#34;需要什么&#34;&gt;需要什么？&lt;/h3&gt;
&lt;p&gt;WebAssembly仍处于初期阶段。它目前能很好的运行代码，而规范版本是1.0，二进制格式定型。目前正在开展SIMD指令支持。通过Web Workers进行多线程处理也正在进行中。&lt;/p&gt;
&lt;p&gt;工具可用，并将在未来几年不断改进。浏览器已经让你窥视WebAssembly文件。至少Firefox允许查看WebAssembly字节码，设置断点并查看调用堆栈。我听说浏览器也有profiling支持。&lt;/p&gt;
&lt;p&gt;语言支持包括一套不错的语言集合&amp;ndash;C，C++和Rust是一流的公民。C＃，Go和Lua显然有稳定的支持。Python，Scala，Ruby，Java和Typescript都有实验性支持。这可能是一个傲慢的陈述，但我真的相信任何想要在21世纪存在的语言都需要能够在WebAssembly上编译或运行。&lt;/p&gt;
&lt;p&gt;在访问外部设备的API支持方面，我所知道的唯一可用于裸WebAssembly的API是WASI，它允许文件和流访问等核心功能，允许WebAssembly在浏览器外运行。否则，任何访问外部世界的API都需要在浏览器中的Javascript中实现。除了本地机器上的文件访问，打印机访问和其他新颖的硬件访问（例如非标准蓝牙或USB设备）之外，应用所需的一切几乎都可以满足。“裸WebAssembly”并不是它成功的必要条件; 它只是一个小的优化，不需要浏览器包含对HTML，CSS或Javascript的支持。&lt;/p&gt;
&lt;p&gt;我不确定在桌面环境中让WebAssembly成为一等公民需要什么。需要良好的复制和粘贴支持，拖放支持，本地化和国际化，窗口管理事件以及创建通知的功能。也许这些已经可以从网络浏览器中获得; 我经常惊讶与已经可能的事情。&lt;/p&gt;
&lt;p&gt;引发爆炸的火花是创建允许现有应用移植的环境。如果创造了“用于WebAssembly的Linux子系统”，那么可以将大量现有的开源软件移植到WebAssembly上。它需要模拟一个文件系统 - 可以通过将文件系统的所有只读部分都缓存为HTTP请求来完成，并且所有可写部分都可以在内存中，远程存储或使用浏览器可以提供的任何文件访问。图形支持可以通过移植X11或Wayland的实现来使用WebGL（我理解已经作为AIGLX存在？）。&lt;/p&gt;
&lt;p&gt;一些SDL游戏已经被移植到WebAssembly - 最着名的是官方演示。&lt;/p&gt;
&lt;p&gt;一旦JVM在WebAssembly中运行，就可以在浏览器中运行大量的Java软件。同样适用于其他虚拟机和使用它们的语言。&lt;/p&gt;
&lt;p&gt;与Windows软件的巨大世界一样，我没有答案。WINE和ReactOS都需要底层的x86或x86-64机器，所以唯一的选择是获取源代码并移植它，或者使用&lt;a href=&#34;https://copy.sh/v86/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;x86模拟器&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id=&#34;尾声&#34;&gt;尾声&lt;/h3&gt;
&lt;p&gt;WebAssembly即将到来。它来得很慢，但现在所有的部分都可以在你正在使用的浏览器上使用。现在我们等待构建用于从各种编程语言中定位WebAssembly的基础设施。一旦构建完成，我们将摆脱HTML，CSS和Javascript的束缚。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://webassembly.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://webassembly.org/&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>[译] 使用服务网格进行事件驱动消息的潜力</title>
      <link>https://skyao.net/post/201905-service-mesh-event-driven-messaging/</link>
      <pubDate>Mon, 13 May 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201905-service-mesh-event-driven-messaging/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;备注：英文原文来自InfoQ网站文章 &lt;a href=&#34;https://www.infoq.com/articles/service-mesh-event-driven-messaging&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The Potential for Using a Service Mesh for Event-Driven Messaging&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;关键点&#34;&gt;关键点&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;当前流行的服务网格实现（Istio，Linkerd，Consul Connect等）仅满足微服务之间的请求-响应式同步通信&lt;/li&gt;
&lt;li&gt;对于服务网格的推进和采用，我们认为支持事件驱动或基于消息传递的通信是至关重要的&lt;/li&gt;
&lt;li&gt;在服务网格中实现消息支持有两种主要的架构模式; 协议代理Sidecar，用于消费者和生产者的所有入站和出站事件的代理; 以及将事件驱动的通信协议翻译或者转换为HTTP或类似协议的HTTP桥接Sidecar&lt;/li&gt;
&lt;li&gt;无论使用何种桥接模式，Sidecar都可以促进跨功能特性的实现（和校正抽象），例如可观察性，限流，跟踪等。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;正文&#34;&gt;正文&lt;/h2&gt;
&lt;p&gt;作为基础技术和基于微服务和云原生架构的架构模式，服务网格越来越受欢迎。服务网格主要是一个网络基础设施组件，允许从基于微服务的应用程序下放网络通信逻辑，以便完全专注于服务的业务逻辑。&lt;/p&gt;
&lt;p&gt;服务网格围绕代理的概念构建，代理以Sidecar的方式与服务协作。虽然服务网格通常被宣传为可用于任何云原生应用的平台，但是服务网格的流行实现（Istio / Envoy，Linkerd等）目前仅满足微服务之间同步通信的请求/响应风格。但是，在大多数实用的微服务用例中，服务间通信通过各种模式进行，例如请求/响应（HTTP，gRPC，GraphQL）和事件驱动的消息传递（NATS，Kafka，AMQP）。由于服务网格实现不支持事件驱动的通信，服务网格提供的大多数功能仅可用于同步请求/响应服务 - 事件驱动的微服务必须以服务代码本身的一部分的方式来支持这些功能，这与服务网格架构的目标相矛盾。&lt;/p&gt;
&lt;p&gt;服务网格支持事件驱动的通信至关重要。本文着眼于支持服务网格中事件驱动架构的关键问题，以及现有服务网格技术如何尝试解决这些问题。&lt;/p&gt;
&lt;h3 id=&#34;实现事件驱动的消息机制&#34;&gt;实现事件驱动的消息机制&lt;/h3&gt;
&lt;p&gt;在典型的请求/响应同步消息场景中，您将找到一个服务（服务器端）和一个调用该服务的使用者（客户端）。服务网格数据平面充当客户端和服务器端之间的中介。在事件驱动的通信中，通信模式是截然不同的。事件生产者异步地将事件发送到事件代理，生产者和消费者之间没有直接的通信通道。通信风格可以是pub-sub（多个消费者）或基于队列的（单个消费者），并且根据样式，生产者可以分别向主题或队列发送消息。&lt;/p&gt;
&lt;p&gt;消费者决定订阅驻留在事件代理中的主题或队列，与生产者完全解耦。当有可用于该主题或队列的新消息时，代理会将这些消息推送给消费者。&lt;/p&gt;
&lt;p&gt;有几种方法可以将服务网格抽象用于事件驱动的消息机制。&lt;/p&gt;
&lt;h3 id=&#34;协议代理sidecar&#34;&gt;协议代理Sidecar&lt;/h3&gt;
&lt;p&gt;协议代理模式构建的基本概念是：所有事件驱动的通信信道（channel）应该通过服务网格数据平面（即，Sidecar代理）。要支持事件驱动的消息协议（如NATS，Kafka或AMQP），您需要构建特定于通信协议的协议处理程序/过滤器，并将其添加到sidecar代理。图1显示了使用服务网格进行事件驱动的消息机制的典型通信模式。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-service-mesh-event-driven-messaging/images/protocol-proxy-sidecar_hua92c64d89bc4f5c3c5df84e374fc6a72_42929_f6ba6ff666330ee41537f2f3b960b96a.webp 400w,
               /post/201905-service-mesh-event-driven-messaging/images/protocol-proxy-sidecar_hua92c64d89bc4f5c3c5df84e374fc6a72_42929_c6b0557f43830f6c040bf604574a29e5.webp 760w,
               /post/201905-service-mesh-event-driven-messaging/images/protocol-proxy-sidecar_hua92c64d89bc4f5c3c5df84e374fc6a72_42929_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-service-mesh-event-driven-messaging/images/protocol-proxy-sidecar_hua92c64d89bc4f5c3c5df84e374fc6a72_42929_f6ba6ff666330ee41537f2f3b960b96a.webp&#34;
               width=&#34;599&#34;
               height=&#34;300&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

&lt;strong&gt;图1: 使用服务网格的事件驱动消息机制&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由于大多数事件驱动的通信协议是在TCP之上实现的，因此sidecar代理可以具有构建在TCP之上的协议处理程序/过滤器，以专门处理支持各种消息协议所需的抽象。&lt;/p&gt;
&lt;p&gt;生产者微服务（微服务A）必须通过底层消息传递协议（Kafka，NATS，AMQP等）向 Sidecar 发送消息，使用最简单的生产者客户端代码，而 Sidecar 处理与之相关的大多数复杂性。类似地，消费者服务（微服务B）的逻辑也非常简单，而复杂性存在于Sidecar。服务网格提供的抽象可以转换协议。&lt;/p&gt;
&lt;p&gt;Envoy 团队目前正致力于根据上述模式实施Envoy代理的Kafka支持。它仍在进行中，但您可以 &lt;a href=&#34;https://github.com/envoyproxy/envoy/issues/2852&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;在GitHub上&lt;/a&gt; 跟踪进度。&lt;/p&gt;
&lt;h3 id=&#34;http桥接sidecar&#34;&gt;HTTP桥接Sidecar&lt;/h3&gt;
&lt;p&gt;我们构建一个HTTP桥接，实现消息和要求的消息传递协议的转换，而不是使用代理来实现事件驱动的消息协议。构建此桥接模式的关键动机之一是大多数事件代理提供 REST API（例如，&lt;a href=&#34;https://github.com/confluentinc/kafka-rest&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Kafka REST API&lt;/a&gt;）来使用和生成消息。如图2所示，现有的微服务可以简单地通过控制桥接两个协议的 sidecar 来透明地使用底层事件代理的消息系统。sidecar代理主要负责接收 HTTP 请求并将其转换为 Kafka/NATS/AMQP /等。消息，反之亦然。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-service-mesh-event-driven-messaging/images/http-bridge-sidecar_hu9450a5197cce6783de5a26decf980450_43266_a49a8a9e6660401a7a41e1c242a1d871.webp 400w,
               /post/201905-service-mesh-event-driven-messaging/images/http-bridge-sidecar_hu9450a5197cce6783de5a26decf980450_43266_2f0c21cb63aea097eecd31574ac1d639.webp 760w,
               /post/201905-service-mesh-event-driven-messaging/images/http-bridge-sidecar_hu9450a5197cce6783de5a26decf980450_43266_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-service-mesh-event-driven-messaging/images/http-bridge-sidecar_hu9450a5197cce6783de5a26decf980450_43266_a49a8a9e6660401a7a41e1c242a1d871.webp&#34;
               width=&#34;599&#34;
               height=&#34;273&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

&lt;strong&gt;图2：HTTP桥接允许服务通过HTTP与事件代理通信&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;同样，您可以使用HTTP桥接器允许基于Kafka/NATS/AMQP的微服务直接与HTTP（或其他请求/响应消息协议）微服务进行通信，如图3所示。在这种情况下，sidecar接收Kafka/NATS/AMQP请求，将它们转发为HTTP，并将HTTP响应转换回Kafka/NATS/AMQP。目前正在努力在Envoy和NATS上添加对此模式的支持（例如，用于Envoy的 &lt;a href=&#34;https://github.com/envoyproxy/envoy/issues/3415&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;AMQP/HTTP Bridge&lt;/a&gt;和&lt;a href=&#34;https://github.com/solo-io/envoy-nats-streaming&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;NATS/HTTP Bridge&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-service-mesh-event-driven-messaging/images/http-bridge-sidecar2_huf30593ab5c6ddd7a8922483db8cd709e_25498_3eb5dae76e6fdeb9407af5e68523d188.webp 400w,
               /post/201905-service-mesh-event-driven-messaging/images/http-bridge-sidecar2_huf30593ab5c6ddd7a8922483db8cd709e_25498_6a03cc9e3514b581536578b87a3f9e87.webp 760w,
               /post/201905-service-mesh-event-driven-messaging/images/http-bridge-sidecar2_huf30593ab5c6ddd7a8922483db8cd709e_25498_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-service-mesh-event-driven-messaging/images/http-bridge-sidecar2_huf30593ab5c6ddd7a8922483db8cd709e_25498_3eb5dae76e6fdeb9407af5e68523d188.webp&#34;
               width=&#34;599&#34;
               height=&#34;157&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

&lt;strong&gt;图3：HTTP Bridge允许基于事件驱动消息协议的服务使用HTTP服务&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;尽管HTTP桥接模式适用于某些用例，但它不足以作为标准方法，在服务网格架构中处理事件驱动的消息传递，因为桥接事件驱动的消息传递协议始终具有请求/响应消息传递协议有限制。它或多或少只是一种可能适用于某些用例的解决方法。&lt;/p&gt;
&lt;h2 id=&#34;事件驱动的服务网格的关键功能&#34;&gt;事件驱动的服务网格的关键功能&lt;/h2&gt;
&lt;p&gt;基于请求/响应式消息传递的传统服务网格的功能，与支持消息范例的服务网格的功能有些不同。以下是支持事件驱动的消息传递的服务网格将提供的一些独特功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;消费者和生产者抽象&lt;/strong&gt; - 对于大多数消息系统，例如Kafka，代理本身非常抽象和简单（微服务环境中的哑管（dumb pipe ）），而服务是智能终端（大多数智能存在与生产者或消费者代码中）。这意味着生产者或消费者必须在业务逻辑旁边拥有大量的消息传递协议代码。通过引入服务网格，您可以将与消息传递协议相关的此类功能（例如，Kafka中的分区重新平衡）下放到Sidecar，并完全关注微服务代码中的业务逻辑。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消息传递语义&lt;/strong&gt; - 有许多消息传递语义，例如“最多一次”，“至少一次”，“恰好一次”等。取决于底层消息传递系统的支持，可以将这些任务下放到服务网格（这类似于在请求/响应范例中支持熔断器，超时等）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;订阅语义&lt;/strong&gt; - 还可以使用服务网格层来处理订阅语义，例如消费者端逻辑的持久订阅。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限流&lt;/strong&gt; - 可以根据各种参数如消息数量，消息大小等来控制和管理消息限制（速率限制）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务发现&lt;/strong&gt;（代理，主题和队列发现） - 服务网格Sidecar允许您在消息生成和消费期间发现代理位置，topic或queue名称。这涉及处理不同的topic层次结构和通配符。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消息验证&lt;/strong&gt; - 验证用于事件驱动消息机制的消息变得越来越重要，因为大多数消息传递协议（如Kafka，NATS等）都是协议无关的。因此，消息验证是消费者或生产者实现的一部分。服务网格可以提供这种抽象，以便消费者或生产者可以下放消息验证。例如，如果您使用Kafka和Avro进行模式验证，则可以使用sidecar进行验证（即，从外部方案注册表（如Confluent）获取模式，并根据该方案验证消息）。还可以使用它来检查消息中的恶意内容。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消息压缩&lt;/strong&gt; - 某些基于事件的消息传递协议（如&lt;a href=&#34;https://cwiki.apache.org/confluence/display/KAFKA/Compression&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Kafka&lt;/a&gt;）允许数据由生产者压缩，以压缩格式写入服务器，并由消费者解压缩。您可以在sidecar-proxy级别轻松实现此类功能，并在服务网格控制平面上控制它们。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;安全性&lt;/strong&gt; - 您可以通过在服务网格sidecar级别启用TLS来保护代理与消费者/生产者之间的通信，以便您的生产者和消费者实现不需要担心安全通信并且可以以纯文本方式与Sidecar通信。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可观测性&lt;/strong&gt; - 由于所有通信都在服务网格数据平面上进行，因此您可以为所有事件驱动的消息系统部署指标，跟踪和日志。&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Google Cloud Run详细介绍</title>
      <link>https://skyao.net/post/201905-google-cloud-run-detail/</link>
      <pubDate>Fri, 10 May 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201905-google-cloud-run-detail/</guid>
      <description>&lt;h2 id=&#34;cloud-run介绍&#34;&gt;Cloud Run介绍&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/google-cloud-run-logo_hu56fd9cd776a8827a0967174cec6e7e17_18552_de147d5b1f1f7a96b2714f9e91a7576a.webp 400w,
               /post/201905-google-cloud-run-detail/images/google-cloud-run-logo_hu56fd9cd776a8827a0967174cec6e7e17_18552_a643619f95077f8384b986a7fd3e1b7b.webp 760w,
               /post/201905-google-cloud-run-detail/images/google-cloud-run-logo_hu56fd9cd776a8827a0967174cec6e7e17_18552_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/google-cloud-run-logo_hu56fd9cd776a8827a0967174cec6e7e17_18552_de147d5b1f1f7a96b2714f9e91a7576a.webp&#34;
               width=&#34;160&#34;
               height=&#34;143&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在旧金山举办的 Google Cloud Next 2019 大会上，Google 宣布了 Cloud Run，这是一个新的基于容器运行 Serverless 应用的解决方案。Cloud Run 基于开源的 knative 项目，是 knative 的 Google Cloud 托管版本，也是业界第一个基于 Knative + Kubernetes 的 Serverless 托管服务。&lt;/p&gt;
&lt;p&gt;援引来自 Google Cloud 官方网站的介绍资料，对 Cloud Run 的定位是 ：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Run stateless HTTP containers on a fully managed environment or in your own GKE cluster.&lt;/p&gt;
&lt;p&gt;在完全托管的环境或者自己的GKE集群中运行serverless HTTP容器。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;目前 Google Cloud 还处于测试阶段，尚未GA，而且暂时只在美国地区提供。&lt;/p&gt;
&lt;h2 id=&#34;cloud-run推出的背景&#34;&gt;Cloud Run推出的背景&lt;/h2&gt;
&lt;p&gt;这里有一个大的背景：在 knative 出来之前，serverless 市场虽然火热，但是有一个根本性的问题，就是市场碎片化极其严重，有大大小小几十个产品和开源项目，而且存在严重的供应商绑定风险。因此，Google 牵头推出了 knative 开源项目，希望实现 serverless 的标准化和规范化。&lt;/p&gt;
&lt;p&gt;关于knative的详细情况，这里不继续展开，有兴趣的同学可以阅读我之前的演讲分享 &lt;a href=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/&#34;&gt;Knative: 重新定义Serverless&lt;/a&gt; 。&lt;/p&gt;
&lt;h3 id=&#34;google-cloud上的serverless&#34;&gt;Google Cloud上的Serverless&lt;/h3&gt;
&lt;p&gt;在 Cloud Run 出现之后，目前 Google Cloud 上就有三种 Serverless 产品了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Cloud Functions: 事件驱动的serverless计算平台&lt;/li&gt;
&lt;li&gt;App Engine: 高可扩展的serverless web应用&lt;/li&gt;
&lt;li&gt;Cloud Run: 无状态的 serverless HTTP 容器，口号是 &lt;strong&gt;Bringing Serverless to Containers&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/serverless-computer-on-google-cloud_hu1b082ef840916b7491dfc2a4cb690656_202166_478ab93f506b433a47cacc6cedf855d2.webp 400w,
               /post/201905-google-cloud-run-detail/images/serverless-computer-on-google-cloud_hu1b082ef840916b7491dfc2a4cb690656_202166_1ae8b78efe43aa3c3676b3830dc09985.webp 760w,
               /post/201905-google-cloud-run-detail/images/serverless-computer-on-google-cloud_hu1b082ef840916b7491dfc2a4cb690656_202166_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/serverless-computer-on-google-cloud_hu1b082ef840916b7491dfc2a4cb690656_202166_478ab93f506b433a47cacc6cedf855d2.webp&#34;
               width=&#34;760&#34;
               height=&#34;296&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;bring-serverless-to-containers&#34;&gt;Bring Serverless to Containers&lt;/h3&gt;
&lt;p&gt;这是 Cloud Run/knative 区别于之前的各种 serverless 产品的本质不同之处：支持的工作负载不再局限于 Function，而是任意容器！&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：当然基本的容器运行时契约还是要遵守的，具体要求见下面的介绍。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;和 Function 相比，以 container 方式呈现的工作负载，给使用者更大的自由度，Google Cloud 对此给出的口号是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Any langurage / 不限语言&lt;/li&gt;
&lt;li&gt;Any library / 不限类库&lt;/li&gt;
&lt;li&gt;Any binary 不限二进制文件（备注：格式还是要限制的，要求 Linux x86_64 ABI 格式）&lt;/li&gt;
&lt;li&gt;Ecosystem of base images / 基础镜像的生态系统&lt;/li&gt;
&lt;li&gt;Industry standard/工业标准&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/bring-serverless-to-container_huf9373524d5d48f06c6f0724d23c74b91_55107_32892e476b4389c8b01c56896ba44f0f.webp 400w,
               /post/201905-google-cloud-run-detail/images/bring-serverless-to-container_huf9373524d5d48f06c6f0724d23c74b91_55107_2a4de852f293d3845901c7589e58538e.webp 760w,
               /post/201905-google-cloud-run-detail/images/bring-serverless-to-container_huf9373524d5d48f06c6f0724d23c74b91_55107_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/bring-serverless-to-container_huf9373524d5d48f06c6f0724d23c74b91_55107_32892e476b4389c8b01c56896ba44f0f.webp&#34;
               width=&#34;440&#34;
               height=&#34;530&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Google Cloud Run / Knative 对容器的要求，和通用容器相比，强调 &lt;strong&gt;无状态（Stateless）&lt;/strong&gt; / &lt;strong&gt;请求驱动（request-triggered）&lt;/strong&gt; / &lt;strong&gt;可自动伸缩（autoscaled）&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/workload-container_huf839eaf0c4661fae4c0855c958789846_45553_c4659f3ec96dca596966d1a4cfaa7cfc.webp 400w,
               /post/201905-google-cloud-run-detail/images/workload-container_huf839eaf0c4661fae4c0855c958789846_45553_5970f79edda6fba6f0e60b1f3bb61713.webp 760w,
               /post/201905-google-cloud-run-detail/images/workload-container_huf839eaf0c4661fae4c0855c958789846_45553_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/workload-container_huf839eaf0c4661fae4c0855c958789846_45553_c4659f3ec96dca596966d1a4cfaa7cfc.webp&#34;
               width=&#34;712&#34;
               height=&#34;435&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如上图所示，请求流量通常并非均匀分布，有突发高峰，有长期低谷，甚至有时没有流量。因此，从资源使用率的角度考虑，处理这些请求流量的服务容器的实例也应该随请求流量变化，做到自动伸缩，按需使用，以节约成本。&lt;/p&gt;
&lt;h2 id=&#34;cloud-run的特性和要求&#34;&gt;Cloud Run的特性和要求&lt;/h2&gt;
&lt;h3 id=&#34;cloud-run-的特性概述&#34;&gt;Cloud Run 的特性概述&lt;/h3&gt;
&lt;p&gt;下图是整理的 Cloud Run 的几个主要特性，其核心还是那句口号 &amp;ldquo;Bring Serverless to Container&amp;rdquo;：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/cloud-run-features_huae5a47959ed90ceb95a619f4be7fcd5e_95215_ab29e80b8b8690de8523b58fe0b225f3.webp 400w,
               /post/201905-google-cloud-run-detail/images/cloud-run-features_huae5a47959ed90ceb95a619f4be7fcd5e_95215_4a1ff5a1b1c6d6a2e20a47c578bba185.webp 760w,
               /post/201905-google-cloud-run-detail/images/cloud-run-features_huae5a47959ed90ceb95a619f4be7fcd5e_95215_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/cloud-run-features_huae5a47959ed90ceb95a619f4be7fcd5e_95215_ab29e80b8b8690de8523b58fe0b225f3.webp&#34;
               width=&#34;760&#34;
               height=&#34;380&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;以容器形式出现的工作负载：不只是 Function，极大的丰富了 serverless 的玩法&lt;/li&gt;
&lt;li&gt;兼容 knative API：这也是近年来 Google 的一贯打法，开源项目先行，对社区开放，拉拢盟友建立标准，以无厂商锁定的风险来吸引客户，我将其简称为&amp;quot;开源开放不锁定&amp;quot;。&lt;/li&gt;
&lt;li&gt;GCP托管：托管的好处自然是客户无需运维，这也是 serverless 的由来和最基本的特性&lt;/li&gt;
&lt;li&gt;流量驱动模式：请求驱动，实例数量可自动伸缩，甚至伸缩到0，因此无需在业务高峰时预先配置资源和事后手工释放资料，极大的减少运维需要。在此基础上，执行按使用付费，因此可以在不同的应用之间（在公有云上则可以在不同的客户之间）共享成本，以低成本的方式应付短期突发高并发请求。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cloud Run 的其他特性还有：&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;和 Stackdrive的集成，监控/日志/错误报告都是开箱即用&lt;/li&gt;
&lt;li&gt;可自定义域名&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些特性容易理解，就不一一展开。&lt;/p&gt;
&lt;h3 id=&#34;适用于更多的场景&#34;&gt;适用于更多的场景&lt;/h3&gt;
&lt;p&gt;传统的基于 Function 负载的 serverless，受限于 Function ，适用范围相对有限，尤其不适合非 Function 方式编写的旧有应用，而将应用改造为 Function 一来工作量巨大，二来也不是所有的应用都适合用 Function 形式开发。&lt;/p&gt;
&lt;p&gt;在以 Function 为负载的 serverless 系统中，调用往往发生在外部对 Function 的访问，类似API gateway下的南北向通信。Function 之间通常不直接相互调用（某些情况下需要调用时，往往也是走外部调用的通道），因此调用关系相对简单。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/serverless-north-south_hu3963cca5f8dbe2331a5cd8c61a9ce72c_29242_74b9359d1e6192a5edc4191a63066a13.webp 400w,
               /post/201905-google-cloud-run-detail/images/serverless-north-south_hu3963cca5f8dbe2331a5cd8c61a9ce72c_29242_a0e3ab2ddc417fc275f4d5991cf9b980.webp 760w,
               /post/201905-google-cloud-run-detail/images/serverless-north-south_hu3963cca5f8dbe2331a5cd8c61a9ce72c_29242_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/serverless-north-south_hu3963cca5f8dbe2331a5cd8c61a9ce72c_29242_74b9359d1e6192a5edc4191a63066a13.webp&#34;
               width=&#34;300&#34;
               height=&#34;365&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;当工作负载从 Function 转变为 Container之后，不仅仅有 serverless 原有的南北向通信，而且以容器形态出现的工作负载之间相互调用的场景大为增加，这些负载之间的相互调用类似于传统SOA/微服务框架的东西向服务间通信。Cloud Run 通过支持容器作为工作负载，极大的扩大了 serverless 的适用范围。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/serverless-east-west_hu59813f168f522b579186d5237d3cc8b3_35681_d95862f803850a5b3ab56ebccc097aa9.webp 400w,
               /post/201905-google-cloud-run-detail/images/serverless-east-west_hu59813f168f522b579186d5237d3cc8b3_35681_22411f9c888a56bc6b484a9a20b9ba48.webp 760w,
               /post/201905-google-cloud-run-detail/images/serverless-east-west_hu59813f168f522b579186d5237d3cc8b3_35681_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/serverless-east-west_hu59813f168f522b579186d5237d3cc8b3_35681_d95862f803850a5b3ab56ebccc097aa9.webp&#34;
               width=&#34;300&#34;
               height=&#34;305&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;除了前面列出来的两种场景之外，Cloud Run 还可以适用于其他场景，如事件驱动/异步任务/调度服务等：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/workload-more-style_hu655733cdd6f76c198b14ae25cbc44f6f_48374_49dcad983cacebb6761f6f532cd10804.webp 400w,
               /post/201905-google-cloud-run-detail/images/workload-more-style_hu655733cdd6f76c198b14ae25cbc44f6f_48374_1ebd1c213a6cbe14c00d6bcb15d883a6.webp 760w,
               /post/201905-google-cloud-run-detail/images/workload-more-style_hu655733cdd6f76c198b14ae25cbc44f6f_48374_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/workload-more-style_hu655733cdd6f76c198b14ae25cbc44f6f_48374_49dcad983cacebb6761f6f532cd10804.webp&#34;
               width=&#34;760&#34;
               height=&#34;180&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这也迎合了目前 serverless 的发展趋势：未来 serverless 将渗透到各种场景，任何需要按照请求自动实现资源动态调度的工作负载都应该 serverless 化。我称之为：&lt;strong&gt;万物皆可 serverless&lt;/strong&gt;！从 Function 到 Container，serverless 朝这个目标迈出了一大步。&lt;/p&gt;
&lt;h3 id=&#34;cloud-run的并发模型&#34;&gt;Cloud Run的并发模型&lt;/h3&gt;
&lt;p&gt;重点看一下 Cloud Run 对请求并发的处理，因为这涉及到如何动态调配服务容器实例的个数。&lt;/p&gt;
&lt;p&gt;在 Cloud Run 中，每个服务都要自动伸缩容器的实例数量来应对请求流量。在 Cloud Run 中对并发（Concurrency）的定义是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Concurrency&lt;/strong&gt; = &amp;ldquo;maximum number of requests that can be sent at the same time to a given container instance&amp;rdquo;&lt;/p&gt;
&lt;p&gt;并发 = &amp;ldquo;可以同时对给定容器实例发送请求的最大数量&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;也就是我们平时理解的&amp;quot;最大并发请求数&amp;quot;，或者&amp;quot;最大工作线程数&amp;quot;。在这一点上，Cloud Run 的做法和 AWS Lambda 还有 Google 自己的 Cloud Function 不同，后两者的做法是每个实例只能同时接受一个请求，相当于 “Concurrency=1”。如图，当有多个并发请求时就需要启动多个实例。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/concurrency-1_hu75736370aae660a2e3615bf083c23da8_7990_8f1e1d0f5501466375873cb551ed3dce.webp 400w,
               /post/201905-google-cloud-run-detail/images/concurrency-1_hu75736370aae660a2e3615bf083c23da8_7990_722737fa052ee79fe8b5b33061b62122.webp 760w,
               /post/201905-google-cloud-run-detail/images/concurrency-1_hu75736370aae660a2e3615bf083c23da8_7990_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/concurrency-1_hu75736370aae660a2e3615bf083c23da8_7990_8f1e1d0f5501466375873cb551ed3dce.webp&#34;
               width=&#34;160&#34;
               height=&#34;265&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而在 Cloud Run 中，并发度是可以设置的，容许的值范围是从1到80，默认值是80，如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/concurrency-setting_hu4297463ac599d2d20446ac96427e9a18_39163_f1742be64930f6011f821e22e4fd5b2b.webp 400w,
               /post/201905-google-cloud-run-detail/images/concurrency-setting_hu4297463ac599d2d20446ac96427e9a18_39163_f6cb4277beaeaa5eb6f9a2b3207c0fc3.webp 760w,
               /post/201905-google-cloud-run-detail/images/concurrency-setting_hu4297463ac599d2d20446ac96427e9a18_39163_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/concurrency-setting_hu4297463ac599d2d20446ac96427e9a18_39163_f1742be64930f6011f821e22e4fd5b2b.webp&#34;
               width=&#34;518&#34;
               height=&#34;247&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如果并发度设置为 1 则 Cloud Run 的行为也就和AWS Lambda/Google Cloud Function一致了，不过对于容器形式的工作负载而言，容器启动和销毁的资源消耗和成本就有过高了，因此 Cloud Run 下通常建议根据实际业务场景设置合适的并发度/请求数上限。这样在处理请求时，可以用一个实例对应多个请求，从而不必启动太多的实例。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/concurrency-20_hua462b616323fc6ff9ef79df74b83228b_16044_226ca36a4481939bf274f0d5c44f66ec.webp 400w,
               /post/201905-google-cloud-run-detail/images/concurrency-20_hua462b616323fc6ff9ef79df74b83228b_16044_3fac474409d5d662e89a951f89b21283.webp 760w,
               /post/201905-google-cloud-run-detail/images/concurrency-20_hua462b616323fc6ff9ef79df74b83228b_16044_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/concurrency-20_hua462b616323fc6ff9ef79df74b83228b_16044_226ca36a4481939bf274f0d5c44f66ec.webp&#34;
               width=&#34;340&#34;
               height=&#34;205&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;cloud-run对容器的要求&#34;&gt;Cloud Run对容器的要求&lt;/h3&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/container-runtime-contract_hu5c32c5ca85e1b81f40d900ab36c8bd43_51107_920f1a2b86dfa219f584de7596b35c71.webp 400w,
               /post/201905-google-cloud-run-detail/images/container-runtime-contract_hu5c32c5ca85e1b81f40d900ab36c8bd43_51107_00b398555bfd9e1dfc4f1618a32e25c9.webp 760w,
               /post/201905-google-cloud-run-detail/images/container-runtime-contract_hu5c32c5ca85e1b81f40d900ab36c8bd43_51107_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/container-runtime-contract_hu5c32c5ca85e1b81f40d900ab36c8bd43_51107_920f1a2b86dfa219f584de7596b35c71.webp&#34;
               width=&#34;760&#34;
               height=&#34;163&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在 Google Cloud Run 的文档中， &lt;a href=&#34;https://cloud.google.com/run/docs/reference/container-contract&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Container运行时契约&lt;/a&gt; 中列出了 Cloud Run 对容器的要求，主要包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;语言支持&lt;/p&gt;
&lt;p&gt;可以使用任意语言编写代码，可以使用任意基础镜像，但是容器镜像必须是为64位Linux编译的; Cloud Run 支持 Linux x86_64 ABI 格式&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;请求监听&lt;/p&gt;
&lt;p&gt;容器必须在 &lt;code&gt;0.0.0.0&lt;/code&gt; 上监听，端口由环境变量 &lt;code&gt;PORT&lt;/code&gt; 定义。目前在 Cloud Run 中，PORT 环境变量总是设置为 8080，但是为了可移植性，不能hardcode。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;启动时间和响应时间&lt;/p&gt;
&lt;p&gt;容器实例必须在收到请求后的四分钟内启动HTTP服务器; 容器实例必须收到HTTP请求后的规定时间内发送响应，该时间由 &lt;a href=&#34;https://cloud.google.com/run/docs/configuring/request-timeout&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;code&gt;request timeout setting&lt;/code&gt;&lt;/a&gt; 配置，包含容器实例的启动时间。否则请求会被终止并返回 504 错误。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&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;/li&gt;
&lt;li&gt;
&lt;p&gt;容器实例生命周期考虑&lt;/p&gt;
&lt;p&gt;服务的每个版本都将自动伸缩，如果某个版本没有流量，则会缩减到 0 。&lt;/p&gt;
&lt;p&gt;服务应该是无状态的，计算应该限定于请求的范围，如果没有请求则不能使用CPU。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;容器实例资源&lt;/p&gt;
&lt;p&gt;每个容器实例分配 1 vCPU 而且不能修改。每个容器实例默认256M内存，可以修改，最多为2G。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;请注意，Cloud Run 目前处于测试阶段，因此这些要求可能会随时间而发生变化。&lt;/p&gt;
&lt;p&gt;Container Runtime Contract 更详细的信息，请参考：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://cloud.google.com/run/docs/reference/container-contract&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Google Container Runtime Contract &lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/knative/serving/blob/master/docs/runtime-contract.md&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Knative Container Runtime Contract&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/opencontainers/runtime-spec/blob/master/spec.md&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Open Container Initiative Runtime Specification&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;cloud-run的限制&#34;&gt;Cloud Run的限制&lt;/h3&gt;
&lt;p&gt;目前 Cloud Run 的限制有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;最多 1 个vCPU 和 2 G内存&lt;/li&gt;
&lt;li&gt;不能访问 GPU&lt;/li&gt;
&lt;li&gt;没有 Cloud SQL （即将提供）&lt;/li&gt;
&lt;li&gt;没有 VPS 访问（即将提供）&lt;/li&gt;
&lt;li&gt;不支持全局负载均衡&lt;/li&gt;
&lt;li&gt;只支持 HTTP （未来会支持gRPC）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而这些限制，都可以通过选择使用 Cloud Run on GKE 来解决。&lt;/p&gt;
&lt;h3 id=&#34;安全容器gvisor的使用&#34;&gt;安全容器gVisor的使用&lt;/h3&gt;
&lt;p&gt;gVisor 是由 Google 开源的容器沙箱运行时(Container sandbox runtime)。用于在宿主机操作系统与容器中的应用之间创建一个安全的隔离边界，便于安全的对外提供大规模部署的容器服务——关于安全容器和 gVisor 的介绍就不在这里展开。&lt;/p&gt;
&lt;p&gt;在 Cloud Run 中，容器是运行在 gVisor 之上的，而不是默认的Kubernetes runc runtime。gVisor为 Cloud Run 带来了安全容器的隔离，但是也带来了一些限制。如下图所示，gVisor 支持的 System Call 是有限的，不支持所有的 Linux System Call。但是考虑到 Cloud Run 的主要使用场景是无状态的 HTTP 容器，正常情况下应该不会触发这个限制。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/gvisor_hud2c749b238077bbe7dc95b2fdabad158_60248_e8df3952878cb30b3c21c2a9e777c257.webp 400w,
               /post/201905-google-cloud-run-detail/images/gvisor_hud2c749b238077bbe7dc95b2fdabad158_60248_21a4d577b0d0e29695c51d60a138bca6.webp 760w,
               /post/201905-google-cloud-run-detail/images/gvisor_hud2c749b238077bbe7dc95b2fdabad158_60248_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/gvisor_hud2c749b238077bbe7dc95b2fdabad158_60248_e8df3952878cb30b3c21c2a9e777c257.webp&#34;
               width=&#34;760&#34;
               height=&#34;488&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;和knative的关系&#34;&gt;和knative的关系&lt;/h2&gt;
&lt;p&gt;Google Cloud 给出的一些PPT中宣称 Cloud Run 就是托管版本的 knative，当然这一点我个人有些质疑：当前开源版本的 knative 实在有些不够成熟，应该还达不到生产级强度，Google Cloud 托管的有可能是 knative 的内部版本。但可以肯定的是，Cloud Run 一定是兼容 knative API 的。&lt;/p&gt;
&lt;p&gt;目前 Knative 发展趋势非常不错，尤其社区快速成长，聚拢了一批大小盟友。这里有一份 google 给出的长长列表，列出了当前参与 knative 开发的贡献者来自的公司：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;VMware, Huawei, Cisco, TriggerMesh, Dropbox, SAP, Microsoft, Schibsted, Apache, Independent, China Mobile NTT, CloudBees, Caicloud, Inovex, Docker, Heureka, CNCF, Liz Rice, Zalando, Douyu.com, Nebula. OpsGenie. Terracotta, Eldarion, Giant Swarm, Heroku, Revolgy, SORINT.lab, Switch, Ticketmaster, Virtustream,, Alipay, Blue Box, Cruise Automation, EPAM Systems, EVRY, Foreningen Kollegienet Odense, Giddyinc, IPB, Manifold.co, Orange, Puppet, Stark &amp;amp; Wayne, Weaveworks, Disney Interactive, Ivx, Mediative, Ministère de l&amp;rsquo;Agriculture et de l&amp;rsquo;Alimentation, NatureServe, Samsung SDS. Typeform, Wise2c&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;当然，其中最重要的力量还是来自 google 自己，以及 Redhat、Pivotal、IBM 这三位社区巨头。下图是以公司为单位的贡献度比例：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/knative-company_hud1a57ff7c9ef949cc45f4b3fb03fff31_100078_bd23b32d4e95816eeca91c9c1f8d1f09.webp 400w,
               /post/201905-google-cloud-run-detail/images/knative-company_hud1a57ff7c9ef949cc45f4b3fb03fff31_100078_838ec978d1ad54e59ea2a1d24b0b96f6.webp 760w,
               /post/201905-google-cloud-run-detail/images/knative-company_hud1a57ff7c9ef949cc45f4b3fb03fff31_100078_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/knative-company_hud1a57ff7c9ef949cc45f4b3fb03fff31_100078_bd23b32d4e95816eeca91c9c1f8d1f09.webp&#34;
               width=&#34;760&#34;
               height=&#34;577&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;下图是基于Knative的几个主要 serverless 产品，除了Google 的 Cloud Run 之后，还有 Redhat / Pivotal / IBM 等大厂：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/knative-based-products_hu609f52f6325d85a46ba94fcc7ed22cc6_95000_80ba52b6d0abe9443041eccf9ec05110.webp 400w,
               /post/201905-google-cloud-run-detail/images/knative-based-products_hu609f52f6325d85a46ba94fcc7ed22cc6_95000_e0ab992ff7bd6240ae27c3874cb75848.webp 760w,
               /post/201905-google-cloud-run-detail/images/knative-based-products_hu609f52f6325d85a46ba94fcc7ed22cc6_95000_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/knative-based-products_hu609f52f6325d85a46ba94fcc7ed22cc6_95000_80ba52b6d0abe9443041eccf9ec05110.webp&#34;
               width=&#34;760&#34;
               height=&#34;286&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;serverless计算平台选择&#34;&gt;Serverless计算平台选择&lt;/h2&gt;
&lt;p&gt;Cloud Run是一个serverless计算平台，用于运行无状态HTTP应用程序。 它有两种风格：完全托管的环境或Google Kubernetes Engine集群。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Cloud Run：完全托管，完整的serverless体验，客户不需要管理集群，按使用付费。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cloud Run on GKE：只具有 serverless 的开发体验，客户需要在自己的 GKE 集群中运行，价格包含在 GKE 集群中。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/cloud-run-on-gke_hu315e95cc2124d295bdb24a607da0c2b0_24703_b8fa61903aff3947fb058f55df4f1c8c.webp 400w,
               /post/201905-google-cloud-run-detail/images/cloud-run-on-gke_hu315e95cc2124d295bdb24a607da0c2b0_24703_9488ae34fb2cafbc7d1e9e902fc06cce.webp 760w,
               /post/201905-google-cloud-run-detail/images/cloud-run-on-gke_hu315e95cc2124d295bdb24a607da0c2b0_24703_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/cloud-run-on-gke_hu315e95cc2124d295bdb24a607da0c2b0_24703_b8fa61903aff3947fb058f55df4f1c8c.webp&#34;
               width=&#34;300&#34;
               height=&#34;231&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Cloud Run on GKE 具有和 Cloud Run 相同的开发体验，但是 Cloud Run on GKE 运行在 k8s 上，有更多的灵活性和控制力，不过需要自己运维。Cloud Run on GKE 可以集成基于k8s的策略、控制和管理。允许访问自定义计算机类型，额外的网络和GPU支持，以扩展Cloud Run服务的运行方式。&lt;/p&gt;
&lt;p&gt;可以在 Cloud Run 和 Cloud Run on GKE 之间按需要选择，另外 Google Cloud 容许在 Cloud Run 和 Cloud Run on GKE 之间切换，无需改动应用。&lt;/p&gt;
&lt;p&gt;Cloud Run 和 Cloud Run on GKE 的详细对比：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:left&#34;&gt;&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;Cloud Run&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;GKE上的Cloud Run&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;价钱&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;按使用付费（见下文）。&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;作为Kubernetes Engine的一部分提供。定价将在GA之前确定。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;机器类型&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;每个实例一个vCPU，可以更改内存&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;GKE上的标准或自定义机器类型，包括GPU。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;身份和政策&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;管理允许调用服务的身份（或允许未经身份验证的调用）。&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;将服务发布到Internet或仅将其提供给群集或VPC网络。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;联网&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;无法访问VPC /计算引擎网络。服务不是Istio服务网格的一部分。&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;访问VPC /计算引擎网络。服务参与Istio服务网格。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;网址&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;自动提供URL和SSL证书&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;自定义域仅包含手动SSL证书。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;考虑到 Cloud Run 是 knative 的 google cloud 托管版本，对于客户，则理论上在 Cloud Run 和 Cloud Run on GKE 之外还存在另外一种选择：直接使用开源版本的 knative。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/serverless-wherever_hu36514f353d8ba30c8d75a3f38cf1a2b0_160031_02eaf4521c2b96632f746fb089268206.webp 400w,
               /post/201905-google-cloud-run-detail/images/serverless-wherever_hu36514f353d8ba30c8d75a3f38cf1a2b0_160031_b47fead260deedb533dfd1f203555c43.webp 760w,
               /post/201905-google-cloud-run-detail/images/serverless-wherever_hu36514f353d8ba30c8d75a3f38cf1a2b0_160031_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/serverless-wherever_hu36514f353d8ba30c8d75a3f38cf1a2b0_160031_02eaf4521c2b96632f746fb089268206.webp&#34;
               width=&#34;760&#34;
               height=&#34;230&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;或者 google 之外的其他基于 knative 的产品，如Redhat / IBM / Pivotal 等，从而避免了供应商锁定的风险。&lt;/p&gt;
&lt;p&gt;这也是google 在宣传 Cloud Run 产品是一直反复强调的：开源、开放、不绑定。&lt;/p&gt;
&lt;p&gt;回到在 google cloud上进行 serverless 平台选择这个话题，现在 google cloud 上的 serverless 有 function/app/container三种模式，而其中的 container 模式又可以细分为 Cloud Run 和 Cloud Run on GKE 两种形态，还有一个自由度极高可以自由发挥的GKE。下图摘录自 google 的演讲PPT，做了很好的分类和总结：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-cloud-run-detail/images/serverless-hosting-on-gcp_hufe6c50996e910406ee6c1df2aac9a502_139883_5033c3f52a7e252017d4c4a47686606f.webp 400w,
               /post/201905-google-cloud-run-detail/images/serverless-hosting-on-gcp_hufe6c50996e910406ee6c1df2aac9a502_139883_cb23975ea272b4e461479a0679292815.webp 760w,
               /post/201905-google-cloud-run-detail/images/serverless-hosting-on-gcp_hufe6c50996e910406ee6c1df2aac9a502_139883_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/serverless-hosting-on-gcp_hufe6c50996e910406ee6c1df2aac9a502_139883_5033c3f52a7e252017d4c4a47686606f.webp&#34;
               width=&#34;760&#34;
               height=&#34;281&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;cloud-run的计费&#34;&gt;Cloud Run的计费&lt;/h2&gt;
&lt;p&gt;最后关注一下 Cloud Run的计费，Cloud Run 的官方文档 &lt;a href=&#34;https://cloud.google.com/run/pricing&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Pricing&lt;/a&gt; 对此有详细的描述，这里摘录部分内容。&lt;/p&gt;
&lt;p&gt;首先，完全托管式的 Cloud Run 仅为使用的资源收取费用，计费到最近的100毫秒。而 Cloud Run on GKE 则不同，GKE上的 Cloud Run 是Google Kubernetes Engine集群的附加组件。而 Cloud Run on GKE部署的工作量包含在GKE定价中。而GKE上 Cloud Run 的最终定价要到 GA 才确定。&lt;/p&gt;
&lt;p&gt;Cloud Run 的计费模型也颇具创新性，不是完全按请求数量计费，而是同时考量三个指标：CPU/内存/请求数量。搬运一下官方文档作为示意：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:left&#34;&gt;CPU&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;Memory&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;Requests&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;Networking&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;First 180,000 vCPU-seconds free&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;First 360,000 GB-seconds free&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;2 million requests free&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;Free during beta.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;$0.00002400 / vCPU-seconds beyond free quota&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;$0.00000250 / GB-second beyond free quota&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;$0.40 / million requests beyond free quota&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;测试期间免费&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;按照这个计费模型，将 concurrency 设置为合适的数值（起码不是1），让一个容器实例可以同时服务多个请求，分享CPU和内存，在费用上会更合适。另外上面的计费信息中可以看到，CPU/内存/请求数量都有免费配额，只有超过免费配额的使用才需要付费。免费配额会每月重置。&lt;/p&gt;
&lt;p&gt;Cloud Run 对可计费时间的计算比较良心，只有在容器实例有请求在处理时才计算，从第一个请求开始到最后一个请求结束。而容器实例启动的时间和空闲的时间不计算在内，如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34;
           src=&#34;https://skyao.net/post/201905-google-cloud-run-detail/images/billable-time.svg&#34;
           loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;cloud-run-分析&#34;&gt;Cloud Run 分析&lt;/h2&gt;
&lt;p&gt;总结前面的功能介绍，我们可以看到，在 serverless 的常规特性和托管带来的运维便利之外，Cloud Run 的主要特性和卖点在于：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;拥抱容器生态&lt;/p&gt;
&lt;p&gt;将 serverless 与容器结合，极大的扩展了 serverless 的适用范围，对于 serverless 市场是一个巨大的创新。对于习惯使用容器/微服务技术的客户，可以更好的迁移过来。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;拥抱社区&lt;/p&gt;
&lt;p&gt;基于开源的 knative，拉拢社区和盟友，通过 knative 实现 serverless 的标准化和平台化，解决了 serverless 市场碎片化的问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;极佳的可迁移性&lt;/p&gt;
&lt;p&gt;为客户提供了没有供应商锁定风险的解决方案。理论上	客户可以根据实际需要选择完全托管的 Cloud Run 或 Cloud Run on GKE，或者开源版本的 knative，以及其他基于 knative 的托管平台，。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;拥抱云原生技术栈&lt;/p&gt;
&lt;p&gt;结合使用 servicemesh 技术和安全容器技术，配合容器/kubernetes，用 Cloud Native 技术栈打通了从底层到上层应用的通道。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总结说，Cloud Run 是 Google Cloud 在 serverless 领域的全新尝试，具有创新的产品思路，未来的发展值得关注和借鉴。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;
&lt;p&gt;Cloud Run 刚刚发布才一个多月，目前能找到的资料不多，基本都是Google Cloud放出来的新闻稿/博客和官方文档，还有Cloud Next大会上的介绍演讲及PPT。第三方的介绍文章非常的少，因此在调研和整理资料时不得不大量引用来自Cloud Run官方渠道的资料和图片。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://cloud.google.com/run/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Cloud Run官网&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=gx8VTa1c8DA&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Cloud Run Overview&lt;/a&gt;: 不到2分钟的介绍视频，官方宣传片&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=RVdhyprptTQ&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Differences between Cloud Run and Cloud Run on GKE&lt;/a&gt;: 官方视频，5分钟长度，展示 cloud run 和 Cloud Run on GKE 之间的相同点和不同点。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://cloud.withgoogle.com/next/sf/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Google Cloud Next&amp;rsquo; 19 大会上和 serverless 相关的演讲&lt;/a&gt;：主要信息还是来自 Next&amp;rsquo; 19 的演讲，在这个页面中选择 &amp;ldquo;serverless&amp;rdquo; 会列出本次大会和 serverless 相关的演讲，大概十余个，视频可以回放，也提供PPT下载。（本文的大部分的信息和图片来自这些演讲内容），数量比较多就不一一列举了。&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>CNCF正在筹建通用数据平面API工作组，以制定数据平面的标准API</title>
      <link>https://skyao.net/post/201905-cncf-udpa-wg/</link>
      <pubDate>Tue, 07 May 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201905-cncf-udpa-wg/</guid>
      <description>&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;刚刚从进超同学那边得到的消息，CNCF正在筹建通用数据平面API工作组（Universal Data Plane API Working Group / UDPA-WG)，以制定数据平面的标准API，为L4/L7数据平面配置提供事实上的标准，初始成员将包括 Envoy 和 gRPC 项目的代表。&lt;/p&gt;
&lt;p&gt;目前还处于非常早期的筹备阶段，具体内容可以见下面的文档：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://docs.google.com/document/d/1y-H-pQ2mmhBPX_U9pP3mMMUbEpZskxBdEbwd5KlivY4/edit#heading=h.fdi15bvpmxen&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://docs.google.com/document/d/1y-H-pQ2mmhBPX_U9pP3mMMUbEpZskxBdEbwd5KlivY4/edit#heading=h.fdi15bvpmxen&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;方便起见，我将目前文档的内容搬运出来并简单翻译如下：&lt;/p&gt;
&lt;h2 id=&#34;文档内容&#34;&gt;文档内容&lt;/h2&gt;
&lt;h3 id=&#34;目标&#34;&gt;目标&lt;/h3&gt;
&lt;p&gt;通用数据平面API工作组（Universal Data Plane API Working Group/UDPA-WG）的目标是将对数据平面代理和负载均衡器的通用控制和配置API感兴趣的行业各方聚集在一起。&lt;/p&gt;
&lt;h3 id=&#34;愿景&#34;&gt;愿景&lt;/h3&gt;
&lt;p&gt;通用数据平面API（UDPA）的愿景在 &lt;a href=&#34;https://blog.envoyproxy.io/the-universal-data-plane-api-d15cec7a&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://blog.envoyproxy.io/the-universal-data-plane-api-d15cec7a&lt;/a&gt; 中阐述。我们将寻求一套API，为L4/L7数据平面配置提供事实上的标准，类似于 OpenFlow 在SDN L2 /L3/L4 中所扮演的角色。&lt;/p&gt;
&lt;p&gt;API 以 proto3 的规范方式定义，并通过定义良好的稳定API版本控制策略从现有的 Envoy xDS API 逐步演变。 API将涵盖服务发现，负载均衡分配，路由发现，监听器配置，安全发现，负载报告，健康检查委派等。&lt;/p&gt;
&lt;p&gt;我们将发展和塑造 API 以支持客户端旁视（lookaside）负载均衡（例如 gRPC-LB），Envoy之外的数据平面代理，硬件LB，移动客户端等。我们将努力尽可能地与供应商和实现无关，同时不回归支持已投入生产中的UDPA的项目（Envoy＆gRPC-LB，到目前为止）。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We will strive to be vendor and implementation agnostic to the degree possible while not regressing on support for projects that have committed to UDPA in production (Envoy &amp;amp; gRPC-LB so far).&lt;/p&gt;
&lt;p&gt;后半句的没能理解在说什么，稍后更新…&amp;hellip;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;成员&#34;&gt;成员&lt;/h3&gt;
&lt;p&gt;初始成员将包括 Envoy 和 gRPC 项目的代表。这将包括来自 谷歌 和 Lyft 的维护者，以及微软和亚马逊的成员。我们正在征求数据平面代理社区更广泛的对初始成员资格的额外兴趣，因为我们认为真正的通用API应该反映各种各样的项目，组织和个人。&lt;/p&gt;
&lt;p&gt;我们希望工作组保持小规模，并紧密关注有效平衡增量API，同时追求长期战略演变。我们将每两周举行一次Zoom会议，并通过TBD邮件列表进行沟通。&lt;/p&gt;
&lt;h2 id=&#34;解释&#34;&gt;解释&lt;/h2&gt;
&lt;p&gt;上面文档中提到的几个内容：&lt;/p&gt;
&lt;h3 id=&#34;现有的-envoy-xds-api&#34;&gt;现有的 Envoy xDS API&lt;/h3&gt;
&lt;p&gt;Universal Data Plane API 的介绍和设想见Matt Klein 的博客文章 &lt;a href=&#34;https://blog.envoyproxy.io/the-universal-data-plane-api-d15cec7a&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;The universal data plane API&lt;/a&gt;，发表于2017-09-06。也可以看 servermesher 网站翻译的中文版本 &lt;a href=&#34;http://www.servicemesher.com/blog/the-universal-data-plane-api/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Service Mesh中的通用数据平面API设计&lt;/a&gt;。这个博客阐述了 xDS API 诞生的想法/设计和从v1到v2版本的演进&lt;/p&gt;
&lt;p&gt;Envoy xDS API最新的定义请见：https://github.com/envoyproxy/data-plane-api&lt;/p&gt;
&lt;h3 id=&#34;稳定的api版本控制策略&#34;&gt;稳定的API版本控制策略&lt;/h3&gt;
&lt;p&gt;见文档 &lt;a href=&#34;https://docs.google.com/document/d/1xeVvJ6KjFBkNjVspPbY_PwEDHC7XPi0J5p1SqUXcCl8/edit#heading=h.c0uts5ftkk58&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Stable Envoy API versioning&lt;/a&gt; : 这个文档提供了解决Envoy API中稳定性问题的设计方案，以及有关API当前状态的一些背景，考虑的替代方案以及Envoy API中未来方向的讨论。（文档有点长）&lt;/p&gt;
&lt;h3 id=&#34;client-side-lookaside-load-balancing&#34;&gt;client-side lookaside load balancing&lt;/h3&gt;
&lt;p&gt;介绍见 &lt;a href=&#34;https://grpc.io/blog/loadbalancing/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://grpc.io/blog/loadbalancing/&lt;/a&gt; 中的 &amp;ldquo;Lookaside Load Balancing&amp;rdquo; 一节。&lt;/p&gt;
&lt;p&gt;注意：旁视（lookaside）负载平衡器也称为外部（external）负载平衡器或单臂（one-arm）负载平衡器&lt;/p&gt;
&lt;p&gt;使用c时，负载均衡的智能在特殊的LB服务器中实现。客户端查询旁视LB，LB响应最合适服务器给客户端使用。保持服务器状态和LB算法的实现在旁视LB中实现。 请注意，客户端可能会选择在LB中实现的复杂算法之上实现简单算法。 gRPC使用该模型定义客户端和LB之间的通信协议。&lt;/p&gt;
&lt;p&gt;下图说明了这种方法。 客户端从旁视LB (#1)获取至少一个地址。 然后客户端使用此地址生成RPC (#2)，服务器将负载报告发送到LB (#3)。 旁视LB与其他基础设施通信，例如名称解析，服务发现等 (#4)。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;https://grpc.io/img/image_2.png&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;分析&#34;&gt;分析&lt;/h2&gt;
&lt;p&gt;之前 servicemesher 社区在多次讨论 servicemesh 市场竞争时，都在笑说：Envoy 才是真正的赢家。&lt;/p&gt;
&lt;p&gt;不仅仅在于 Envoy 表现稳定、使用广泛、顺利从CNCF毕业，也在于 Envoy 的 xDS v2 API，已经成为数据平面的事实标准。而这一次CNCF组织通用数据平面API工作组，准备基于 xDS v2 API 制定官方标准，可以说是水到渠成。&lt;/p&gt;
&lt;p&gt;我目前唯一担心的是：Buoyant会不会参与进来？Linkerd2 会不会选择放弃现在使用的私有API而遵循新标准？&lt;/p&gt;
&lt;p&gt;最新更新：在Slack上咨询 Buoyant 是否会加入 UDPA 和 Linkerd2 是否会遵循新的标准API，CEO William 的回复是：I don’t see anything that is relevant to Linkerd in there。有些可惜，目前 Linkerd2 的基于Rust的 proxy 是市面上唯一做的不错又不遵循 xDS API 的开源数据平面。&lt;/p&gt;
&lt;h2 id=&#34;相关资讯&#34;&gt;相关资讯&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://lists.cncf.io/g/udpa-wg/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://lists.cncf.io/g/udpa-wg/&lt;/a&gt;：Universal Data Plane API Working Group 的 mail list。&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>[译] Traffic Director如何为开放服务网格提供全局负载均衡</title>
      <link>https://skyao.net/post/201905-google-traffic-director-global-lb/</link>
      <pubDate>Mon, 06 May 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201905-google-traffic-director-global-lb/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;备注：英文原文来自Google Cloud网站博客文章 &lt;a href=&#34;https://cloud.google.com/blog/products/networking/traffic-director-global-traffic-management-for-open-service-mesh&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Google Cloud networking in depth: How Traffic Director provides global load balancing for open service mesh&lt;/a&gt;，发布时间 2019-04-18&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在上周的Next &amp;lsquo;19，我们宣布了用于服务网格的&lt;a href=&#34;https://youtu.be/PZ1Lqxfs1yw?t=330&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Traffic Director&lt;/a&gt;，为您的VM和容器服务带来全局流量管理。我们还在博客中向您展示了&lt;a href=&#34;https://cloud.google.com/blog/products/networking/powering-enterprise-transformation-announcing-new-additions-to-google-cloud-networking&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Traffic Director的功能&lt;/a&gt;。今天，我们将深入探讨其特性和优势。&lt;/p&gt;
&lt;h2 id=&#34;用于服务网格的traffic-director&#34;&gt;用于服务网格的Traffic Director&lt;/h2&gt;
&lt;p&gt;服务网络的核心在于为独立微服务提供基础，这些微服务可以使用不同语言编写，并由不同团队维护。服务网格有助于将开发与运维解耦。开发人员不再需要在他们的应用程序中编写和维护策略和网络代码，这些会转移到服务代理（如Envoy）和服务网格控制平面，它们提供并动态管理代理。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;Traffic Director for service mesh.png&#34; srcset=&#34;
               /post/201905-google-traffic-director-global-lb/images/Traffic_Director_for_service_mesh.max-1200x1200_hu7c86dba5d75d13e7e380cb6a84df3851_54515_406bf679c8126c5f9e323be024b2dd77.webp 400w,
               /post/201905-google-traffic-director-global-lb/images/Traffic_Director_for_service_mesh.max-1200x1200_hu7c86dba5d75d13e7e380cb6a84df3851_54515_134d762a9841eacfdc1380587cdcab75.webp 760w,
               /post/201905-google-traffic-director-global-lb/images/Traffic_Director_for_service_mesh.max-1200x1200_hu7c86dba5d75d13e7e380cb6a84df3851_54515_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-global-lb/images/Traffic_Director_for_service_mesh.max-1200x1200_hu7c86dba5d75d13e7e380cb6a84df3851_54515_406bf679c8126c5f9e323be024b2dd77.webp&#34;
               width=&#34;760&#34;
               height=&#34;318&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;em&gt;“Traffic Director可以更轻松地将服务网格和Envoy的优势带到生产环境中，” Envoy Proxy的创建者Matt Klein说。&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Traffic Director是Google Cloud用于服务网格的完全托管的流量控制平面。Traffic Director开箱即用，可以用于VM和容器。它使用开源 &lt;a href=&#34;https://www.envoyproxy.io/docs/envoy/latest/api-v2/api&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;xDS API&lt;/a&gt; 与数据平面中的服务代理进行通信，确保不会被锁定在专有接口中。&lt;/p&gt;
&lt;h2 id=&#34;traffic-director功能&#34;&gt;Traffic Director功能&lt;/h2&gt;
&lt;h3 id=&#34;全局负载均衡&#34;&gt;全局负载均衡&lt;/h3&gt;
&lt;p&gt;许多人使用Google的全局负载均衡来实现面向互联网的服务。Traffic Director为服务网格中的内部微服务带来全局负载均衡。借助全局负载均衡，您可以在全世界的&lt;a href=&#34;https://cloud.google.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Google Cloud Platform&lt;/a&gt;（GCP）区域中配置服务实例。Traffic Director为客户端提供智能，以便将流量发送到具有可用容量的最近的服务实例。这优化了发起流量的服务和使用流量的服务之间的全局流量分配，为每个请求采用最短往返时间（RTT）。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;Global load balancing.png&#34; srcset=&#34;
               /post/201905-google-traffic-director-global-lb/images/Global_load_balancing.max-1400x1400_hu99b142d0bdd06f2010d2d43760a35c6d_251931_96b984ae16c296f82f3feccede94add9.webp 400w,
               /post/201905-google-traffic-director-global-lb/images/Global_load_balancing.max-1400x1400_hu99b142d0bdd06f2010d2d43760a35c6d_251931_4fe16f07e0c79a66e43d9e126feec616.webp 760w,
               /post/201905-google-traffic-director-global-lb/images/Global_load_balancing.max-1400x1400_hu99b142d0bdd06f2010d2d43760a35c6d_251931_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-global-lb/images/Global_load_balancing.max-1400x1400_hu99b142d0bdd06f2010d2d43760a35c6d_251931_96b984ae16c296f82f3feccede94add9.webp&#34;
               width=&#34;760&#34;
               height=&#34;649&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如果最接近客户端服务的实例已关闭或过载，则Traffic Director会提供智能，以便将流量无缝转移到下一个最近区域中的健康实例。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;Traffic Director intelligence.png&#34; srcset=&#34;
               /post/201905-google-traffic-director-global-lb/images/Traffic_Director_intelligence.max-1400x1400_hud642fa9dbeb70bf16dd38a751343fe01_253972_6a3b1309df122ea735465aba031f792d.webp 400w,
               /post/201905-google-traffic-director-global-lb/images/Traffic_Director_intelligence.max-1400x1400_hud642fa9dbeb70bf16dd38a751343fe01_253972_a14b705200ae4fac9c0e152631f87c3a.webp 760w,
               /post/201905-google-traffic-director-global-lb/images/Traffic_Director_intelligence.max-1400x1400_hud642fa9dbeb70bf16dd38a751343fe01_253972_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-global-lb/images/Traffic_Director_intelligence.max-1400x1400_hud642fa9dbeb70bf16dd38a751343fe01_253972_6a3b1309df122ea735465aba031f792d.webp&#34;
               width=&#34;760&#34;
               height=&#34;591&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;集中式的健康检查&#34;&gt;集中式的健康检查&lt;/h3&gt;
&lt;p&gt;大型服务网格会生成大量的健康检查流量，因为每个sidecar代理都必须对服务网格中的所有服务实例进行健康检查。随着网格的增长，让每个客户端代理健康检查每个服务器实例，这种做法会产生一个 n^2 健康检查问题，这将成为增长和扩展部署的障碍。&lt;/p&gt;
&lt;p&gt;Traffic Director通过集中运行健康检查来解决此问题，其中全局分布的弹性系统监控所有服务实例。然后，Traffic Director使用 &lt;a href=&#34;https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/eds.proto#envoy-api-file-envoy-api-v2-eds-proto&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;EDS API&lt;/a&gt; 将聚合的健康检查结果分发到全局网格中的所有代理。&lt;/p&gt;
&lt;h3 id=&#34;基于负载的自动伸缩&#34;&gt;基于负载的自动伸缩&lt;/h3&gt;
&lt;p&gt;Traffic Director 根据代理向其报告的负载信号启用自动伸缩。Traffic Director通知 Compute Engine autoscaler 流量变化，并让 autoscaler 一次性增长到所需的大小（而不是像其他 autoscaler 那样重复步骤），从而减少 autoscaler 对流量峰值做出反应所需的时间。&lt;/p&gt;
&lt;p&gt;当 Compute Engine autoscaler 正在增加所需的容量时，Traffic Director 会暂时将流量重定向到其他可用实例 - 即使在其他区域也是如此。一旦 autoscaler 增加了足够的工作负载容量以维持峰值，Traffic Director 就会将流量移回最近的zone和region，再次优化流量分配以最小化每个请求的RTT。&lt;/p&gt;
&lt;h3 id=&#34;内建弹性&#34;&gt;内建弹性&lt;/h3&gt;
&lt;p&gt;由于 Traffic Director 是GCP提供的完全托管服务，因此您无需担心其正常运行时间，生命周期管理，可扩展性或可用性。Traffic Director 基础设施在全世界范围内具有全局分布和弹性，并使用与Google面向用户的服务相同的经过实战检验的系统。Traffic Director将在GA时提供99.99％的服务水平协议（SLA）。&lt;/p&gt;
&lt;h3 id=&#34;流量管理功能&#34;&gt;流量管理功能&lt;/h3&gt;
&lt;p&gt;Traffic Director允许控制流量，而无需修改应用代码本身。&lt;/p&gt;
&lt;p&gt;您可以创建自定义流量控制规则和策略，通过指定：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP匹配规则：指定参数，包括要在传入请求中匹配的host，path和header。&lt;/li&gt;
&lt;li&gt;HTTP操作：匹配后根据请求执行的操作。这些包括重定向，重写，header转换，镜像，故障注入等。&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;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;traffic splitting.png&#34; srcset=&#34;
               /post/201905-google-traffic-director-global-lb/images/traffic_splitting.max-900x900_hu684554789c2da4a03ea0fe468bcc58b7_128283_ea2eef304b70abc3fb68b18e56220f17.webp 400w,
               /post/201905-google-traffic-director-global-lb/images/traffic_splitting.max-900x900_hu684554789c2da4a03ea0fe468bcc58b7_128283_1f6acc2752363189951ada9cda8c89c1.webp 760w,
               /post/201905-google-traffic-director-global-lb/images/traffic_splitting.max-900x900_hu684554789c2da4a03ea0fe468bcc58b7_128283_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-global-lb/images/traffic_splitting.max-900x900_hu684554789c2da4a03ea0fe468bcc58b7_128283_ea2eef304b70abc3fb68b18e56220f17.webp&#34;
               width=&#34;760&#34;
               height=&#34;643&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;让我们看一下 Traffic Director 的流量控制功能的示例：&lt;strong&gt;流量分割&lt;/strong&gt;。通过Traffic Director，您可以轻松配置场景，例如推出新版本的服务，如购物车，并逐步增加路由到该服务的流量。&lt;/p&gt;
&lt;p&gt;您还可以配置流量控制以根据HTTP header引导流量，使用故障注入来测试服务的弹性，镜像以便将生产流量的副本发送到影子服务等等。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;traffic control alpha.png&#34; srcset=&#34;
               /post/201905-google-traffic-director-global-lb/images/traffic_control_alpha.max-900x900_hu00517a1eeb5a38977c4e5493d4992bc2_161748_2cff495d80ef06dd8d788eed42abb10e.webp 400w,
               /post/201905-google-traffic-director-global-lb/images/traffic_control_alpha.max-900x900_hu00517a1eeb5a38977c4e5493d4992bc2_161748_13f6132b22ae8722d10a2c1c3daf0436.webp 760w,
               /post/201905-google-traffic-director-global-lb/images/traffic_control_alpha.max-900x900_hu00517a1eeb5a38977c4e5493d4992bc2_161748_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-global-lb/images/traffic_control_alpha.max-900x900_hu00517a1eeb5a38977c4e5493d4992bc2_161748_2cff495d80ef06dd8d788eed42abb10e.webp&#34;
               width=&#34;760&#34;
               height=&#34;584&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;您可以通过注册 &lt;a href=&#34;https://services.google.com/fb/forms/trafficdirectoralphas/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;流量控制alpha&lt;/a&gt; 来使用这些功能。&lt;/p&gt;
&lt;h2 id=&#34;vm和容器服务的一致流量管理&#34;&gt;VM和容器服务的一致流量管理&lt;/h2&gt;
&lt;p&gt;Traffic Director 允许您无缝地部署和管理由容器和VM服务组成的异构部署。每个服务的实例可以跨越多个区域。&lt;/p&gt;
&lt;p&gt;使用Traffic Director，可以使用 &lt;a href=&#34;https://cloud.google.com/compute/docs/instance-groups/#managed_instance_groups&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;托管实例组&lt;/a&gt; 和容器端点将VM端点配置为 &lt;a href=&#34;https://cloud.google.com/kubernetes-engine/docs/how-to/standalone-neg&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;独立网络端点组&lt;/a&gt;。如上所述，像 &lt;a href=&#34;http://envoyproxy.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Envoy&lt;/a&gt; 这样的开源服务代理被注入到每一个实例中。容器和VM的其余数据模型和策略保持不变，如下所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;Consistent traffic management.png&#34; srcset=&#34;
               /post/201905-google-traffic-director-global-lb/images/Consistent_traffic_management.max-1100x1100_huef8335b83379bb0492c73e7007adc3c1_107471_fa80bd7b9a8e320ed6993e01dc3f2792.webp 400w,
               /post/201905-google-traffic-director-global-lb/images/Consistent_traffic_management.max-1100x1100_huef8335b83379bb0492c73e7007adc3c1_107471_b4ed8f508c8adf1f49192cc111e93a6f.webp 760w,
               /post/201905-google-traffic-director-global-lb/images/Consistent_traffic_management.max-1100x1100_huef8335b83379bb0492c73e7007adc3c1_107471_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-global-lb/images/Consistent_traffic_management.max-1100x1100_huef8335b83379bb0492c73e7007adc3c1_107471_fa80bd7b9a8e320ed6993e01dc3f2792.webp&#34;
               width=&#34;760&#34;
               height=&#34;349&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;此模型在服务部署时提供一致性，并且能够提供无缝地全局负载均衡，跨越服务的VM实例和容器实例。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Google Traffic Director详细介绍</title>
      <link>https://skyao.net/post/201905-google-traffic-director-detail/</link>
      <pubDate>Mon, 06 May 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201905-google-traffic-director-detail/</guid>
      <description>&lt;h2 id=&#34;traffic-director介绍&#34;&gt;Traffic Director介绍&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/google-traffic-director-logo_hu5f52e89819f6cef13f7a148c501e2d68_17752_181272ae6a0947cb683bcf974afa8e70.webp 400w,
               /post/201905-google-traffic-director-detail/images/google-traffic-director-logo_hu5f52e89819f6cef13f7a148c501e2d68_17752_737efce6bd1f9bf09ef7dd06ebe5b2dc.webp 760w,
               /post/201905-google-traffic-director-detail/images/google-traffic-director-logo_hu5f52e89819f6cef13f7a148c501e2d68_17752_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/google-traffic-director-logo_hu5f52e89819f6cef13f7a148c501e2d68_17752_181272ae6a0947cb683bcf974afa8e70.webp&#34;
               width=&#34;200&#34;
               height=&#34;200&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Traffic Director 是 Google Cloud 推出的完全托管的服务网格流量控制平面。&lt;/p&gt;
&lt;p&gt;援引来自Traffic Director官方网站的介绍资料，Traffic Director的定位是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Enterprise-ready traffic management for open service mesh.&lt;/p&gt;
&lt;p&gt;适用于开放式服务网格的企业级流量管理工具。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;目前 Traffic Director 还处于测试阶段，尚未GA：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在2018年7月的 Cloud Next &amp;lsquo;18 大会上，Google Cloud 推出了 Traffic Director 的 alpha 版本&lt;/li&gt;
&lt;li&gt;在2019年4月的  Cloud Next &amp;lsquo;19 大会上，Google Cloud 推出了 Traffic Director 的 beta 版本&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;traffic-director推出的背景&#34;&gt;Traffic Director推出的背景&lt;/h2&gt;
&lt;p&gt;在详细介绍 Traffic Director 的功能之前，我们先看一下 Traffic Director 推出的背景。由于 Traffic Director 刚推出不久，资料非常少，所以下面的内容有很多来自仅有的一点 Traffic Director 的演讲和官方文档。&lt;/p&gt;
&lt;p&gt;在Cloud Next &amp;lsquo;18 /19 介绍Traffic Director的演讲中，都谈到 Traffic Director 推出和下列两个趋势有关：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;微服务的普及和Service Mesh技术的兴起&lt;/li&gt;
&lt;li&gt;混合云和多云部署&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;从微服务到service-mesh&#34;&gt;从微服务到Service Mesh&lt;/h3&gt;
&lt;p&gt;近年来微服务架构大热，传统的单体应用按照微服务的理念进行拆分。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/microservices_hucfd836d385bb94adc5158f45501899da_403143_3f7c272a6524b6de23ff092710e217bf.webp 400w,
               /post/201905-google-traffic-director-detail/images/microservices_hucfd836d385bb94adc5158f45501899da_403143_764434cec1861e7bc52cc9328601038b.webp 760w,
               /post/201905-google-traffic-director-detail/images/microservices_hucfd836d385bb94adc5158f45501899da_403143_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/microservices_hucfd836d385bb94adc5158f45501899da_403143_3f7c272a6524b6de23ff092710e217bf.webp&#34;
               width=&#34;730&#34;
               height=&#34;310&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;但是当应用从单个巨型单体拆分为数量大增的微服务之后，新的问题出现：如果高效的部署、连接、管理这些服务，并提供安全和监控能力？如果按照传统的侵入式微服务框架的思路，则开发人员就不得不在进行微服务改造时，承受微服务拆分带来的各种技术复杂度。&lt;/p&gt;
&lt;p&gt;但是，当将单体应用拆分到微服务时，客户关注的并不是微服务或者和微服务相关的各种技术，他们真正关注的是：微服务可以给他们带来什么。因此，必须要有一种解决方案，抽象并屏蔽掉微服务实现的技术细节。&lt;/p&gt;
&lt;p&gt;服务网格就是这样一种功能强大的抽象层，在微服务交付方面得到了越来越多的使用。其核心价值有两点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Separates applications from app networking / 分离应用和网络&lt;/li&gt;
&lt;li&gt;Decouples operation from development / 解耦开发和运维&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;混合云和多云环境&#34;&gt;混合云和多云环境&lt;/h3&gt;
&lt;p&gt;考虑另一个趋势：在混合云和多云环境下部署和管理服务。客户可能使用公有云，如GCP或其他公有云，也可能混合使用私有云。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/multicloud_hude3863f08cc35d94c5cad63dd39dfba1_31204_74d446553d800803b82145e9c214f8fd.webp 400w,
               /post/201905-google-traffic-director-detail/images/multicloud_hude3863f08cc35d94c5cad63dd39dfba1_31204_e2c7bd24cbc1ab8d9b52a97d9d3e65de.webp 760w,
               /post/201905-google-traffic-director-detail/images/multicloud_hude3863f08cc35d94c5cad63dd39dfba1_31204_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/multicloud_hude3863f08cc35d94c5cad63dd39dfba1_31204_74d446553d800803b82145e9c214f8fd.webp&#34;
               width=&#34;532&#34;
               height=&#34;361&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在这种场景下，该如何简化混合和多云服务的部署？Traffic Director的思路是这样：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;引入ServiceMesh技术：通过ServiceMesh将通用的核心部分从服务中移除，典型如网络通信代码中的负载均衡，错误注入，失败恢复，流量管理，路由，安全等。&lt;/li&gt;
&lt;li&gt;托管：需要ServiceMesh来管理服务，但最好不要自己直接管理ServiceMesh，而是使用提供托管的基础设施&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;控制平面与托管&#34;&gt;控制平面与托管&lt;/h3&gt;
&lt;p&gt;在服务网格中，服务网格数据平面与服务代理一起传输流量，而服务网格控制平面为这些服务代理提供政策、配置和智能建议:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/servicemesh_hud312f2ffd7283eba6d35e184c8ba0603_107915_142679ad5fde0b055d00dea2111c8bee.webp 400w,
               /post/201905-google-traffic-director-detail/images/servicemesh_hud312f2ffd7283eba6d35e184c8ba0603_107915_01e1dd6aa229cf6a686f806a2d6eefc5.webp 760w,
               /post/201905-google-traffic-director-detail/images/servicemesh_hud312f2ffd7283eba6d35e184c8ba0603_107915_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/servicemesh_hud312f2ffd7283eba6d35e184c8ba0603_107915_142679ad5fde0b055d00dea2111c8bee.webp&#34;
               width=&#34;760&#34;
               height=&#34;381&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Traffic Director 是 GCP 专为服务网格打造的完全托管式流量控制平面，其架构如下：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;../201905-google-traffic-director-global-lb/images/Traffic_Director_for_service_mesh.max-1200x1200.png&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;托管式服务的好处是有服务等级协议 (SLA) 的保障，下面是Google Cloud官方对此的声明：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;作为 Google 的一项托管式服务，Traffic Director 提供生产级 99.99% 可用性的 SLA：如果出现问题，收到通知并负责解决问题是我们的运营人员，而不是您的。您不必担心部署和管理控制平面，因而您的员工可以专注于发展业务。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;当然目前 Traffic Director 还是beta测试阶段，上述SLA保障需要在GA之后才能提供。&lt;/p&gt;
&lt;p&gt;最后我们援引 Matt Klein（Envoy 作者）的这段致辞作为Traffic Director推出的背景总结，虽然这段话有做托的嫌疑：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Traffic Director 可以更加便捷地将 Envoy 和服务网格的优势运用到生产环境。由于 Envoy 提供通用型数据平面，Traffic Director 可提供具有开放接口的完全托管式流量控制平面，避免锁定于某一种产品。Traffic Director 的 SLA、全球负载平衡和丰富的流量控制措施可帮助企业和云原生最终用户减少流量管理工作。”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这里列出的功能我们后面会详细解析，重点看&amp;quot;开放接口&amp;quot;/&amp;ldquo;避免锁定&amp;rdquo; 这两个关键词：这可以说是Google乃至整个CNCF/Cloud Native社区一直念念不忘反复提醒的关键字，极其强调标准接口和避免供应商绑定。&lt;/p&gt;
&lt;p&gt;与此对应的是，Traffic Director 采用了开放的 &lt;a href=&#34;https://www.envoyproxy.io/docs/envoy/latest/api-v2/api&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;xDS v2 API&lt;/a&gt; 与数据平面中的服务代理进行通信。xDS v2 API 来自 Envoy， 目前已经成为 Service Mesh 的事实API标准。Traffic Director 通过采用 xDS v2 API 这样的开发API实现了其倡导的避免绑定。&lt;/p&gt;
&lt;h2 id=&#34;traffic-director的功能&#34;&gt;Traffic Director的功能&lt;/h2&gt;
&lt;h3 id=&#34;全局负载均衡&#34;&gt;全局负载均衡&lt;/h3&gt;
&lt;p&gt;这个功能是 Traffic Director 在各种演讲和介绍中强调的最多的功能，其官方介绍为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Traffic Director 将服务作为虚拟机或容器部署在多个区域中来保证它正常运行，并使用 Traffic Director 通过自动化的跨区域溢出和故障转移来提供全局负载均衡。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&amp;ldquo;作为虚拟机或容器&amp;quot;我们在下一节展开，先看看 Traffic Director 提供的全局负载均衡是什么。&lt;/p&gt;
&lt;p&gt;这是  Traffic Director 官方给出的示例，图中的三个服务分别部署在两个不同的区域。在 Traffic Director 的控制下，流量按照就近原则被发送到具有可用容量的最近的服务实例：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;../201905-google-traffic-director-global-lb/images/Global_load_balancing.max-1400x1400.png&#34; alt=&#34;Global_load_balancing.max-1400x1400&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;故障转移是指，如果最接近客户端服务的实例已关闭或过载，则 Traffic Director 会控制流量无缝转移到下一个最近区域中的健康实例。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;../201905-google-traffic-director-global-lb/images/Traffic_Director_intelligence.max-1400x1400.png&#34; alt=&#34;Traffic_Director_intelligence.max-1400x1400&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;跨区域溢出则是指当流量超出当前区域部署的实例的承受能力之后，会突破就近路由的原则，将部分流量导流到其他区域。这背后的逻辑是：就近路由的收益的是本地访问的低网络延迟，在流量突发时，宁可牺牲延迟也要将流量引导到其他区域以保证可用性。&lt;/p&gt;
&lt;p&gt;下面这个动画可以更生动的展示上述描述的&amp;quot;全局负载均衡&amp;rdquo;/&amp;ldquo;故障转移&amp;quot;和&amp;quot;跨区域溢出&amp;quot;的功能：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34;
           src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/Traffic_Director_for_open_service_mesh.gif&#34;
           loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;适用于虚拟机和容器&#34;&gt;适用于虚拟机和容器&lt;/h3&gt;
&lt;p&gt;在上面的示例中，提到&amp;quot;Traffic Director 将服务作为虚拟机或容器部署在多个区域中&amp;rdquo;，这是 Traffic Director 重点强调的另外一个重要功能：支持虚拟机和容器，而且支持混合使用。&lt;/p&gt;
&lt;p&gt;下面这张图片强调了服务部署的多样性：三个服务分别是自己管理的 docker 服务 / 基于虚拟机的服务 / 部署在 GKE 的服务。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/mixed-service_hu0cdf26fd1ba79308e17960f21e2f04b1_109514_24a6dbf3f0f9f1c69bee565e2b89f63b.webp 400w,
               /post/201905-google-traffic-director-detail/images/mixed-service_hu0cdf26fd1ba79308e17960f21e2f04b1_109514_4a1f5fa63bfe1a5c509bc3e696bbb5c7.webp 760w,
               /post/201905-google-traffic-director-detail/images/mixed-service_hu0cdf26fd1ba79308e17960f21e2f04b1_109514_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/mixed-service_hu0cdf26fd1ba79308e17960f21e2f04b1_109514_24a6dbf3f0f9f1c69bee565e2b89f63b.webp&#34;
               width=&#34;760&#34;
               height=&#34;372&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Traffic Director 官方文档给出的解释是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;按您的节奏进行现代化改造&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Traffic Director 既适用于基于虚拟机 (Compute Engine) 的应用，也适用于容器化应用（Google Kubernetes Engine 或自行管理的 Kubernetes），并可以增量方式逐步应用于您的服务。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这背后的考虑是：service mesh 和 k8s 的普及，不会一蹴而就，基于虚拟机的服务会长期存在，因此提供对基于虚拟机服务的支持和打通与容器服务的交互访问就至关重要。这个思路同样出现在AWS的app mesh产品中，app mesh也是强调同时支持VM服务和容器服务。&lt;/p&gt;
&lt;p&gt;Service Mesh技术的典型使用场景是运行和管理已经拆解为微服务并按照云原生理念开发的服务，但是考虑到大量遗留应用存在的现实， Traffic Director 通过支持VM服务，可以为这些非云原生服务引入高级功能。这个做法在我们之前的介绍中，被戏称为&amp;quot;先上车再买票&amp;quot;，即在不做应用大规模改造的前提下先体现享受Service Mesh带来的部分红利，再慢慢逐步和分批做应用改造。&lt;/p&gt;
&lt;p&gt;注意：在 Traffic Director 的支持中，基于虚拟机的服务和基于容器的服务采用一致的流量管理功能，两者并没有功能上的差别。&lt;/p&gt;
&lt;h3 id=&#34;混合云和多云支持&#34;&gt;混合云和多云支持&lt;/h3&gt;
&lt;p&gt;最近看到 Google Cloud 提出要&amp;quot;All in Hybird Cloud&amp;quot;，在这个大背景下，Traffic Director 提供对混合云和多云环境的支持：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/hybird-multicloud_hu66fe28fb0d2ef91bd698ba26d4e9fb1d_128429_b2110cc908ec6da23a0e06d3f88fbee9.webp 400w,
               /post/201905-google-traffic-director-detail/images/hybird-multicloud_hu66fe28fb0d2ef91bd698ba26d4e9fb1d_128429_343f236d3eee017403d2bab902004779.webp 760w,
               /post/201905-google-traffic-director-detail/images/hybird-multicloud_hu66fe28fb0d2ef91bd698ba26d4e9fb1d_128429_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/hybird-multicloud_hu66fe28fb0d2ef91bd698ba26d4e9fb1d_128429_b2110cc908ec6da23a0e06d3f88fbee9.webp&#34;
               width=&#34;760&#34;
               height=&#34;304&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是完整的应用改造示意，从原有在私有环境下运行的单体应用，转换到在公有云和私有云上的 service mesh 中运行的多个微服务：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/hybird-support_hu390e81bb44fbbdee47b48d362bd42fc0_95229_11c7fdd9162721e21eae962f12bf800d.webp 400w,
               /post/201905-google-traffic-director-detail/images/hybird-support_hu390e81bb44fbbdee47b48d362bd42fc0_95229_20dd5fe6496c1caf19b6e804d8ade42e.webp 760w,
               /post/201905-google-traffic-director-detail/images/hybird-support_hu390e81bb44fbbdee47b48d362bd42fc0_95229_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/hybird-support_hu390e81bb44fbbdee47b48d362bd42fc0_95229_11c7fdd9162721e21eae962f12bf800d.webp&#34;
               width=&#34;760&#34;
               height=&#34;352&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;集中式健康检查&#34;&gt;集中式健康检查&lt;/h3&gt;
&lt;p&gt;Traffic Director 官方文档对集中式健康检查给出的介绍是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;大规模执行运行状况检查&lt;/p&gt;
&lt;p&gt;Traffic Director 通过 GCP 进行大规模运行状况检查。因此，运行状况检查从 Envoy/服务代理分流到 Google 的弹性系统，这样您就可以对各种规模的部署进行大规模运行状况检查。另外，您的实例本身不会因网格规模的运行状况检查而不堪重负。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;解释一下这里所说的&amp;quot;因网格规模的运行状况检查而不堪重负&amp;quot;：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;大型服务网格会生成大量的健康检查流量，因为每个sidecar代理都必须对服务网格中的所有服务实例进行健康检查。随着网格的增长，让每个客户端代理健康检查每个服务器实例，这种做法会产生一个 n^2 健康检查问题，这将成为增长和扩展部署的障碍。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Traffic Director 对此给出的解决方案是提供集中式健康检查，Traffic Director 会提供一个全局分布的弹性系统监控所有服务实例。然后，Traffic Director使用 &lt;a href=&#34;https://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/eds.proto#envoy-api-file-envoy-api-v2-eds-proto&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;EDS API&lt;/a&gt; 将聚合的健康检查结果分发到全局网格中的所有代理。如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/health-check_hu1c81ae6240034224121d14c7d929be6d_129146_78dd09b3e92d3cbb618b0cf0980dfb7f.webp 400w,
               /post/201905-google-traffic-director-detail/images/health-check_hu1c81ae6240034224121d14c7d929be6d_129146_7466c429df7b57ba1f1f771821b855b7.webp 760w,
               /post/201905-google-traffic-director-detail/images/health-check_hu1c81ae6240034224121d14c7d929be6d_129146_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/health-check_hu1c81ae6240034224121d14c7d929be6d_129146_78dd09b3e92d3cbb618b0cf0980dfb7f.webp&#34;
               width=&#34;760&#34;
               height=&#34;385&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这样Proxy就不需要自行实现健康检测，只要接受 EDS 更新即可（当然客户端被动健康检测还是需要的，当发生无法连接等错误时还是需要处理的）。&lt;/p&gt;
&lt;p&gt;这里 Traffic Director 的做法和 Istio 的标准做法是很类似的，Istio 在 k8s 上部署时，是依赖 k8s 的探测机制来做服务的探活的。Traffic Director 的 health check 机制没有找到详细的介绍资料，暂时不清楚具体的机制，Traffic Director 的介绍中只是提到这个功能是由 GCP 统一提供。&lt;/p&gt;
&lt;p&gt;集中式健康检查这个功能也算是一个卖点，毕竟，虽然 Envoy 自带健康检测机制，但是如果由客户端来实现健康检测，的确是需要每个客户端都检查所有其他服务，连接太多，请求太多，而且随着服务数量和实例数量的增加，健康检测的开销会直线上涨。由平台/基础设施/云等来统一提供集中式健康检查，再通过 xDS/EDS API 下发结果应该会是一个通用的做法。&lt;/p&gt;
&lt;h3 id=&#34;流量控制&#34;&gt;流量控制&lt;/h3&gt;
&lt;p&gt;Traffic Director 目前提供流量控制功能，包括流量路由和策略执行。官方文档的介绍描述如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;通过请求路由和丰富的流量政策进行流量控制（Alpha 版）&lt;/p&gt;
&lt;p&gt;Traffic Director 支持高级请求路由功能，如流量拆分、启用 Canary 更新等用例、网址重写/重定向、故障注入、流量镜像，以及基于各种标头值的高级路由功能，包括 Cookie。此外，Traffic Director 还支持许多高级流量政策，包括多种负载平衡方案、熔断和后端异常检测。&lt;/p&gt;
&lt;p&gt;您可以使用 Traffic Director 轻松部署一切功能：从简单的负载平衡，到请求路由和基于百分比的流量拆分等高级功能。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;从最新的 Traffic Director 的介绍PPT上看到，Traffic Director 的流量控制功能包含两个部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Routing Rules&lt;/strong&gt;：定义请求如何路由到网格中的服务&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Traffic splitting&lt;/li&gt;
&lt;li&gt;Traffic steering&lt;/li&gt;
&lt;li&gt;Timeouts and retries&lt;/li&gt;
&lt;li&gt;Fault Injection&lt;/li&gt;
&lt;li&gt;Mirroring&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Traffic Policies&lt;/strong&gt;：用于服务的路由相关策略&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Load balancing schemes.&lt;/li&gt;
&lt;li&gt;Outlier detection.&lt;/li&gt;
&lt;li&gt;Circuit breakers&lt;/li&gt;
&lt;li&gt;Timeouts&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;熟悉 Istio API 和 Envoy xDS API 的同学就会发现这些功能非常眼熟，基本上和 Isito / Envoy 提供的功能相同。&lt;/p&gt;
&lt;p&gt;和包括Istio在内的所有Service Mesh产品一致， Traffic Director 也在强调说这些功能都是可以在不修改应用代码的前提下获得，这是理所当然的重要卖点。&lt;/p&gt;
&lt;p&gt;但是注意：目前这些功能都还是 alpha 阶段，因此支持度应该不会像 Istio 那么齐全。&lt;/p&gt;
&lt;p&gt;我们快速过一下目前提供的功能（图片来自 Google Traffic Director 的演讲PPT）：&lt;/p&gt;
&lt;p&gt;Traffic Splitting/流量拆分，支持百分比拆分，这是 version based routing，用于实现金丝雀发布/蓝绿部署/AB测试等：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/traffic-splitting_hucb7202c960f3b7f94d97cc980aacf338_129566_3bd742653dd59ce1e72ff0e6dbe6f80c.webp 400w,
               /post/201905-google-traffic-director-detail/images/traffic-splitting_hucb7202c960f3b7f94d97cc980aacf338_129566_f16178b5094b13b8449ffbf310ada44b.webp 760w,
               /post/201905-google-traffic-director-detail/images/traffic-splitting_hucb7202c960f3b7f94d97cc980aacf338_129566_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/traffic-splitting_hucb7202c960f3b7f94d97cc980aacf338_129566_3bd742653dd59ce1e72ff0e6dbe6f80c.webp&#34;
               width=&#34;750&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Traffic Steering，这是 content based routing，支持 Host / Path / Header 匹配：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/traffic-steering_hucb7202c960f3b7f94d97cc980aacf338_132688_2cc48a255e05f4a878339e20aca0020b.webp 400w,
               /post/201905-google-traffic-director-detail/images/traffic-steering_hucb7202c960f3b7f94d97cc980aacf338_132688_5b49aeef60cd692dd9296e660399072a.webp 760w,
               /post/201905-google-traffic-director-detail/images/traffic-steering_hucb7202c960f3b7f94d97cc980aacf338_132688_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/traffic-steering_hucb7202c960f3b7f94d97cc980aacf338_132688_2cc48a255e05f4a878339e20aca0020b.webp&#34;
               width=&#34;750&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在匹配完成之后，除了做流量拆分之外，还可以由其他的功能，如错误注入。Traffic Director 支持的错误注入同样有 Delay 和 Abort 两种：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/fault-injection_hucb7202c960f3b7f94d97cc980aacf338_106790_5ec05754eac279fa00a5477b0097286a.webp 400w,
               /post/201905-google-traffic-director-detail/images/fault-injection_hucb7202c960f3b7f94d97cc980aacf338_106790_c84187d545925ea5fbf45004d3912588.webp 760w,
               /post/201905-google-traffic-director-detail/images/fault-injection_hucb7202c960f3b7f94d97cc980aacf338_106790_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/fault-injection_hucb7202c960f3b7f94d97cc980aacf338_106790_5ec05754eac279fa00a5477b0097286a.webp&#34;
               width=&#34;750&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;熔断和异常检测，支持每服务配置，具体的配置方式也和 Istio / Envoy 差不多。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/circuit-breakers_hu367f2b6a950d2f9229cb05d778a8ee92_102527_0a0176cb4d13cb1caa37ac4f873884ba.webp 400w,
               /post/201905-google-traffic-director-detail/images/circuit-breakers_hu367f2b6a950d2f9229cb05d778a8ee92_102527_e41f8a7b70d8ebef846b231d951249d4.webp 760w,
               /post/201905-google-traffic-director-detail/images/circuit-breakers_hu367f2b6a950d2f9229cb05d778a8ee92_102527_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/circuit-breakers_hu367f2b6a950d2f9229cb05d778a8ee92_102527_0a0176cb4d13cb1caa37ac4f873884ba.webp&#34;
               width=&#34;760&#34;
               height=&#34;746&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;流量镜像功能，也称为影子流量。流量会复制一份发送给接受镜像流量的服务，Traffic Director的实现会在发送给镜像服务的请求的 Host/Authority header 中增加一个 “-shadow” 后缀。镜像请求是发出去就不管的，无视应答，和Istio的处理方式一致。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/traffic-mirror_hucb7202c960f3b7f94d97cc980aacf338_107586_9edb1e8b841be29e70d32668e9b4247c.webp 400w,
               /post/201905-google-traffic-director-detail/images/traffic-mirror_hucb7202c960f3b7f94d97cc980aacf338_107586_c8def0e55fcfda2358226bbd957b9f9d.webp 760w,
               /post/201905-google-traffic-director-detail/images/traffic-mirror_hucb7202c960f3b7f94d97cc980aacf338_107586_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/traffic-mirror_hucb7202c960f3b7f94d97cc980aacf338_107586_9edb1e8b841be29e70d32668e9b4247c.webp&#34;
               width=&#34;750&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;总结：在流量控制这块功能上，Traffic Director 除了因为是 alpha 版本，可能功能支持不够齐全之外，基本和 Istio / Envoy 是一致的。考虑到 Traffic Director 支持 xDS V2 API，和目前只支持Envoy（理论上兼容任何支持 xDS v2的代理，但是实际只测试过Envoy） 的现状，Traffic Director 在流量控制上和 Istio / Envoy 高度一致也就非常容易理解。&lt;/p&gt;
&lt;p&gt;需要特别指出的是：目前 beta 版本的 Traffic Director 只支持用 GCP 的 API 来设置流量控制的规则，目前还不支持直接使用 Istio 的API （CRD）。但是，预计未来将提供支持，从Roadmap上也看到有和 Istio 集成的规划。&lt;/p&gt;
&lt;h3 id=&#34;基于流量的自动伸缩&#34;&gt;基于流量的自动伸缩&lt;/h3&gt;
&lt;p&gt;Traffic Director 前面支持的功能，基本都有不出意外的感觉，毕竟熟悉 Istio/Envoy 体系的同学对这些功能都了如指掌。而 自动伸缩这个功能是一个特例。&lt;/p&gt;
&lt;p&gt;援引 Traffic Director 官方文档对此功能的描述：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;根据您的服务规模智能快速进行地自动扩缩&lt;/p&gt;
&lt;p&gt;Traffic Director 可根据您的需求自动扩缩，您只需按实际用量付费，并且快速智能地进行扩容，无需联系云服务提供商也不必进行任何预热。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;看到这段描述，第一反应是：这不是 serverless 吗？按需伸缩，按使用付费。&lt;/p&gt;
&lt;p&gt;Traffic Director 在提供标准的 service mesh 功能的同时，也引入了 serverless 的特性。下面是 Traffic Director 中自动伸缩功能的实现方式：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Traffic Director 根据代理向其报告的负载信号启用自动伸缩。Traffic Director通知 Compute Engine autoscaler 流量变化，并让 autoscaler 一次性增长到所需的大小（而不是像其他 autoscaler 那样重复步骤），从而减少 autoscaler 对流量峰值做出反应所需的时间。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;自动伸缩的功能不仅仅可以用于常规的按照请求流量进行扩容和缩容，也支持某些特殊场景，如前面在介绍全局负载均衡时提到的：如果最接近客户端服务的实例已关闭或过载，则 Traffic Director 会控制流量无缝转移到下一个最近区域中的健康实例。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;../201905-google-traffic-director-global-lb/images/Traffic_Director_intelligence.max-1400x1400.png&#34; alt=&#34;Traffic_Director_intelligence.max-1400x1400&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;此时由于原来两个区域的流量都进入了一个区域的Shopping Car服务，可能出现流量超出当前承受能力的情况，此时 Traffic Director 会指示 Compute Engine autoscaler 增加Shopping Car服务的容量。同理，Payments 服务的容量也会随之增加。&lt;/p&gt;
&lt;p&gt;按照 Google Cloud 官方博客文章的介绍， Traffic Director 在这块的处理非常的复杂而智能：在新增加的容量生效之前，Traffic Director 会暂时将流量重定向到其他可用实例 - 即使在其他区域也是如此。（也就是前面所说的跨区域溢出，其指导原则是可用性目标高于低延迟目标）一旦 autoscaler 增加了足够的工作负载容量以维持峰值，Traffic Director 就会将流量移回最近的zone和region，再次优化流量分配以最小化每个请求的RTT。&lt;/p&gt;
&lt;p&gt;从这里可以看到， Traffic Director 结合使用了 Service Mesh 的路由控制能力和 Serverless 的按需自动伸缩的资源调度能力，在故障处理和自动运维上表现非常突出。&lt;/p&gt;
&lt;p&gt;可以说，Traffic Director 在 servicemesh 和 serverless 整合的道路上迈出了重要的一步。这是一个非常有创新的想法，值得借鉴和学习。&lt;/p&gt;
&lt;h3 id=&#34;功能限制&#34;&gt;功能限制&lt;/h3&gt;
&lt;p&gt;Traffic Director 官方文档中列出了一些目前的功能限制，这里摘录其中比较重要的部分：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Beta版本的Traffic Director仅支持GCP API。Beta版本的Traffic Director不支持Istio API。&lt;/li&gt;
&lt;li&gt;Traffic Director仅支持HTTP流量。&lt;/li&gt;
&lt;li&gt;Traffic Director流量控制功能是 Alpha 状态。&lt;/li&gt;
&lt;li&gt;本文档讨论了Envoy代理，但您可以将任何 &lt;a href=&#34;https://www.envoyproxy.io/docs/envoy/latest/api-v2/api&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;开放标准API（xDS v2）代理&lt;/a&gt; 与Traffic Director一起使用。但请注意，Google仅使用Envoy代理测试了Traffic Director。在此测试期间，Traffic Director仅支持Envoy版本1.9.1或更高版本。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;和istio的关系&#34;&gt;和Istio的关系&lt;/h2&gt;
&lt;p&gt;在了解 Traffic Director 之后，相信很多人会和我一样有同样的问题：Traffic Director 和 Istio 到底有什么关系？&lt;/p&gt;
&lt;p&gt;简单介绍Istio：Istio提供控制平面来保护，连接和监控微服务。它有三个组成部分：Pilot 负责流量管理，Mixer 负责可观察性，Istio Security（Citadel） 负责服务到服务的安全性。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/istio_hu0c841bee830971ae61a487f3586dd4e6_269319_87689420eaeef1df887d651f67365db5.webp 400w,
               /post/201905-google-traffic-director-detail/images/istio_hu0c841bee830971ae61a487f3586dd4e6_269319_111710412b56ee26f00bcd05a85bef06.webp 760w,
               /post/201905-google-traffic-director-detail/images/istio_hu0c841bee830971ae61a487f3586dd4e6_269319_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/istio_hu0c841bee830971ae61a487f3586dd4e6_269319_87689420eaeef1df887d651f67365db5.webp&#34;
               width=&#34;760&#34;
               height=&#34;360&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Traffic Director 和 Istio 的基本区别在于，Istio 是一个开源产品，而 Traffic Director 是一个完全托管的服务。&lt;/p&gt;
&lt;p&gt;在具体的功能模块上，Traffic Director 将取代 Pilot 的位置：所有 Pilot 能提供的功能，Traffic Director 都将提供。这也是采用 open xDS v2 API的原因，以便在开源的 Pilot 和 Traffic Director 之间切换。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/pilot-replace_hu6eb4f33b247785a577c6652ca45e4754_391303_2473f82daf25df952eecb14df663527c.webp 400w,
               /post/201905-google-traffic-director-detail/images/pilot-replace_hu6eb4f33b247785a577c6652ca45e4754_391303_f41d80b217542c928c61b7e4e8ddf956.webp 760w,
               /post/201905-google-traffic-director-detail/images/pilot-replace_hu6eb4f33b247785a577c6652ca45e4754_391303_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/pilot-replace_hu6eb4f33b247785a577c6652ca45e4754_391303_2473f82daf25df952eecb14df663527c.webp&#34;
               width=&#34;760&#34;
               height=&#34;372&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;总结说：Traffic Director 提供了 GCP 托管的 Pilot ，以及全局负载均衡和集中式健康检查等其他功能。&lt;/p&gt;
&lt;p&gt;但请注意，当前 Traffic Director Beta 版本还无法使用 Istio API 配置 Traffic Director，暂时只能使用GCP API进行配置。&lt;/p&gt;
&lt;p&gt;在 Sidecar 的注入上，Istio 支持自动注入，而 Traffic Director 目前需要手工注入 Sidecar，不过未来 Traffic Director 应该会支持自动注入，毕竟这个功能实现上并不复杂。&lt;/p&gt;
&lt;p&gt;Traffic Director 的 Roadmap 中，有和 Istio 进一步集成的计划，从下图上看是准备引入 Istio Security（Citadel），以提供安全特性如mTLS，RBAC等。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/istio-integration_hue0d80d814b4694c41cfe429a576b729b_181992_08621e665a5abff802f7dedc201cd449.webp 400w,
               /post/201905-google-traffic-director-detail/images/istio-integration_hue0d80d814b4694c41cfe429a576b729b_181992_30ae95253222da4730b8e1e66d16c6fb.webp 760w,
               /post/201905-google-traffic-director-detail/images/istio-integration_hue0d80d814b4694c41cfe429a576b729b_181992_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/istio-integration_hue0d80d814b4694c41cfe429a576b729b_181992_08621e665a5abff802f7dedc201cd449.webp&#34;
               width=&#34;760&#34;
               height=&#34;315&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;暂时未看到有引入 Mixer 的信息。&lt;/p&gt;
&lt;h2 id=&#34;traffic-director-roadmap&#34;&gt;Traffic Director Roadmap&lt;/h2&gt;
&lt;p&gt;援引最新 Traffic Director 介绍的PPT，Traffic Director 的 Roadmap 中未来准备加入以下内容：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/roadmap_hu48a98ee9aa4c7dfd60e434ca2f316580_107609_bb335d3c36fd790ea9ce54a6a1642b53.webp 400w,
               /post/201905-google-traffic-director-detail/images/roadmap_hu48a98ee9aa4c7dfd60e434ca2f316580_107609_555ac064f06026de2c51a256542175e7.webp 760w,
               /post/201905-google-traffic-director-detail/images/roadmap_hu48a98ee9aa4c7dfd60e434ca2f316580_107609_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/roadmap_hu48a98ee9aa4c7dfd60e434ca2f316580_107609_bb335d3c36fd790ea9ce54a6a1642b53.webp&#34;
               width=&#34;760&#34;
               height=&#34;187&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;安全方面的集成，要支持 mTLS/RBAC，看前面的图片是打算引入Istio Security （Citadel）模块。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;可观测性集成：按说是Istio Mixer模块，但是没见到介绍，怀疑是不是因为 Mixer 在性能上的拙劣表现，导致Traffic Director 可能采用其他方案，后续关注。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;hybird/Multi-cloud支持&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过 Istio API 来进行控制&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;和其他控制平面组建联邦&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director-detail/images/federation_hu660e9a7a64ed43587ea3395cb8d39442_229435_65746fef1fcf47931b3a24ad05e2755a.webp 400w,
               /post/201905-google-traffic-director-detail/images/federation_hu660e9a7a64ed43587ea3395cb8d39442_229435_2f05de0806e0ff1973a0079c9b42c5d2.webp 760w,
               /post/201905-google-traffic-director-detail/images/federation_hu660e9a7a64ed43587ea3395cb8d39442_229435_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director-detail/images/federation_hu660e9a7a64ed43587ea3395cb8d39442_229435_65746fef1fcf47931b3a24ad05e2755a.webp&#34;
               width=&#34;760&#34;
               height=&#34;291&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;traffic-director-分析&#34;&gt;Traffic Director 分析&lt;/h2&gt;
&lt;p&gt;从前面的功能介绍中可以看到，Traffic Director 的重要卖点和特色在于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;对混合云/多云的支持&lt;/li&gt;
&lt;li&gt;对VM服务（或者说非云原生服务）的支持&lt;/li&gt;
&lt;li&gt;整合了 serverless 的部分特性&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;其他功能不是说不重要，而是相对来说比较常规化，即托管的服务网格理论上说应该都会提供这些功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;完全托管，无需运维，GA后提供SLA保证&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;从产品定位上说，Traffic Director 只提供控制平面，对于数据平面理论上只要兼容xDS v2 API即可，也就是说 Traffic Director  完全关注在控制平面，前面列出来的几个重要的卖点也都属于控制平面的创新和深耕，和数据平面关系不大，或者说数据平面只需简单的提供底层支持。从这点上看，和Istio专注在控制平面，而将数据平面完全委托给 Envoy 的做法可谓一脉相承。&lt;/p&gt;
&lt;p&gt;在API的选择上，Traffic Director 的做法是支持开放的 xDS v2 API，以及计划中的通过 Istio API 来进行配置。一方面在产品层面上和开源的Envoy/Istio保持一致，另一方面也通过这种方式实现了其一直宣传的不锁定的目标，对于市场宣传和争取客户应该是有利的，也有助于实现混合云和多云战略。&lt;/p&gt;
&lt;p&gt;目前 Traffic Director 还处于 beta 测试阶段，尤其流量配置更是还在 alpha 阶段，产品的成熟度还不够高，roadmap中也还有很多非常重要甚至急迫（如可观测性）的内容有待完成。因此不适合对 Traffic Director 过早的做判断和评论，我的观点是 Traffic Director 代表的产品方向应该是非常有前途，可以给客户带来实际价值。这是Google 在ServiceMesh领域（甚至是Serverless领域）新的探索和尝试，期望有好的结果。&lt;/p&gt;
&lt;p&gt;对 Traffic Director 的理解，我的观点是不能单独的只看 Traffic Director  这一个产品，而是要结合近期 Google 陆续推出的几个相关产品：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Google Cloud Service Mesh：ServiceMesh产品，简单理解为 Istio 的GCP托管版本（猜测可能是兼容Istio API的内部实现/扩展版本），探索方向为在公有云上提供 Service Mesh 托管服务&lt;/li&gt;
&lt;li&gt;Google Cloud Run：Serverless 产品，简单理解为 knative 的GCP托管版本（猜测依然可能是兼容 Knative API的内部实现/扩展版本），探索方向为在公有云上提供 Serverless 托管服务&lt;/li&gt;
&lt;li&gt;Anthos：Hybird/Multi-Cloud产品，号称业界&amp;quot;第一个真正的混合和多云平台&amp;quot;，探索方向为 Google 宣称要 &amp;ldquo;All in&amp;quot;的混合云市场&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然后再来看，作为托管版 Service Mesh 控制平台而推出 Traffic Director 产品，我们前面列出的三个卖点和特色：对混合云/多云的支持；对VM服务（或者说非云原生服务）的支持；整合 serverless 的部分特性。和这三个新产品可谓交相呼应。&lt;/p&gt;
&lt;p&gt;摘录两句从最近的  Google Cloud Next 大会信息中看到的话，是不是更有体会？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write once, Run Anywhere/一次写好，哪都能跑&lt;/li&gt;
&lt;li&gt;Use open-source technology easily and in a cloud-native way / 以云原生的方式，轻松使用开源技术&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Google / Google Cloud 在下一盘很大的棋，一盘围绕云和云原生的大棋:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;以云为战场，以kubernetes为根据地，以开源开放不锁定为口号，以云原生为旗帜，以ServiceMesh和Serviceless为桥梁连接起应用和基础设施，以混合云为突破口……剑指当前云计算市场排名第一/第二的AWS/Azure。&lt;/p&gt;
&lt;h2 id=&#34;参考资料&#34;&gt;参考资料&lt;/h2&gt;
&lt;p&gt;Traffic Director目前能找到的资料不多，基本都是Google Cloud放出来的新闻稿/博客和官方文档，还有两次cloud next大会上的介绍演讲及PPT。第三方的介绍文章非常的少，因此在调研和整理资料时不得不大量引用来自Traffic Director官方渠道的资料和图片。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://cloud.google.com/traffic-director/docs/traffic-director-concepts&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Traffic Director concepts&lt;/a&gt;: Google Cloud 上的 Traffic Director 官方文档&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://cloud.google.com/blog/products/networking/traffic-director-global-traffic-management-for-open-service-mesh&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Google Cloud networking in depth: How Traffic Director provides global load balancing for open service mesh&lt;/a&gt;：来自Google Cloud网站的官方博客文章，发表时间为 2019-04-18&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://medium.com/cloudzone/google-clouds-traffic-director-what-is-it-and-how-is-it-related-to-the-istio-service-mesh-c199acc64a6d&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Google Cloud’s Traffic Director — What is it and how is it related to the Istio service-mesh?&lt;/a&gt;：来自Medium网站的博客文章，原作者为 &lt;a href=&#34;https://medium.com/@iftachsc&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Iftach Schonbaum&lt;/a&gt;，发表时间 2019-04-16&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.infoq.com/news/2019/04/google-traffic-director&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Introducing Traffic Director: Google’s Service Mesh Control Plane&lt;/a&gt;：来自 InfoQ 网站的文章，发布时间 2019-04-25&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=FUITCYMCEhU&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Traffic Director &amp;amp; Envoy-Based L7 ILB for Production-Grade Service Mesh &amp;amp; Istio&lt;/a&gt;: Google 在 Cloud Next &amp;lsquo;19 大会上的主题演讲，发表时间 2019-04-10（本文的很多图片摘录自这个演讲的ppt）&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?time_continue=2759&amp;amp;v=4U4X_OzJaNY&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Hybrid and Open Services with GCP, Envoy and Istio: A Talk with Google and Lyft &lt;/a&gt;: Google 在 Cloud Next &amp;lsquo;18 大会上的主题演讲，发表时间 2018-07-26&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>[译] Google Cloud的Traffic Director - 介绍以及与Istio服务网格的关系</title>
      <link>https://skyao.net/post/201905-google-traffic-director/</link>
      <pubDate>Sun, 05 May 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201905-google-traffic-director/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;备注：英文原文来自Medium网站博客文章 &lt;a href=&#34;https://medium.com/cloudzone/google-clouds-traffic-director-what-is-it-and-how-is-it-related-to-the-istio-service-mesh-c199acc64a6d&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Google Cloud’s Traffic Director — What is it and how is it related to the Istio service-mesh?&lt;/a&gt;，原作者为 &lt;a href=&#34;https://medium.com/@iftachsc&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Iftach Schonbaum&lt;/a&gt;，发布时间 2019-04-16&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201905-google-traffic-director/images/traffic_huff3f4d9d0808a65fd6a5387f10958bc8_235004_8b5be8dd0342678a98db38b19f505263.webp 400w,
               /post/201905-google-traffic-director/images/traffic_huff3f4d9d0808a65fd6a5387f10958bc8_235004_8e748bd91eb86257829bcb450a6377e2.webp 760w,
               /post/201905-google-traffic-director/images/traffic_huff3f4d9d0808a65fd6a5387f10958bc8_235004_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director/images/traffic_huff3f4d9d0808a65fd6a5387f10958bc8_235004_8b5be8dd0342678a98db38b19f505263.webp&#34;
               width=&#34;760&#34;
               height=&#34;526&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对于最近跟进 Google Cloud 路线图的人来说，可能听说过Traffic Director。对于那些了解 Istio 的人来说，可能听起来有些重叠和混乱（特别是如果使用了最新的 GKE Istio 插件）。&lt;/p&gt;
&lt;p&gt;在这篇文章中，我将介绍Traffic Director是什么，它与Istio服务网格有什么关系，以及对于那些已经在GKE上运行生产Istio网格的人来说意味着什么。&lt;/p&gt;
&lt;p&gt;在这篇文章中，我不会介绍 Istio 或服务网格是什么。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Traffic Director是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Enterprise-ready traffic management for open service mesh”…&lt;/p&gt;
&lt;p&gt;“用于开放式服务网络的企业级流量管理”&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;它是用于服务网格的完全托管的控制平面，可以通过智能流量控制策略，在Kubernetes集群（托管或非托管）和虚拟机之间全局地控制流量。与任何其他服务网格控制平面一样，它控制网格内服务代理的配置。&lt;/p&gt;
&lt;p&gt;Traffic Director拥有99.99％的SLA（需要在达到GA时，目前处于beta测试阶段），这意味着您可以管理网格配置，而无需担心控制平面的健康和维护。Traffic Director也在后台伸缩以适应网格的大小，因此您不必担心这一点。&lt;/p&gt;
&lt;p&gt;概括的说，可以使用Traffic Director执行以下操作：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;复杂的流量管理&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;流量操纵，如拆分，镜像和故障注入&lt;/li&gt;
&lt;li&gt;智能部署策略，如易于使用的A/B和金丝雀&lt;/li&gt;
&lt;li&gt;请求操纵，如URL重写&lt;/li&gt;
&lt;li&gt;基于内容的路由，通过header，cookie等&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;构建弹性服务&lt;/strong&gt;  - 使用单个IP和服务代理实现全局跨区域感知负载均衡，实现低延迟、最近端点访问，并在出现问题时故障转移到另一个端点。最近端点可以是同一zone的其他集群，不同zone或不同region。此外，在服务之间配置弹性功能，例如熔断器检测，解放开发人员。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;大规模的健康检查&lt;/strong&gt;  - 使用GCP管理的健康检查，取代网格内代理的健康检查，以减少网格大小相关的健康检查。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;现代化非云原生服务&lt;/strong&gt;  - 由于它也适用于VM，因此它允许您为遗留应用程序引入高级功能。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;img&#34; srcset=&#34;
               /post/201905-google-traffic-director/images/global-lb_huc06e71b9c7bfd37c52cee067ebfaba75_51080_d9e30a5ae615ca83bb8974755e2e48c0.webp 400w,
               /post/201905-google-traffic-director/images/global-lb_huc06e71b9c7bfd37c52cee067ebfaba75_51080_708eef1a6d28f0cac285adb12db59925.webp 760w,
               /post/201905-google-traffic-director/images/global-lb_huc06e71b9c7bfd37c52cee067ebfaba75_51080_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201905-google-traffic-director/images/global-lb_huc06e71b9c7bfd37c52cee067ebfaba75_51080_d9e30a5ae615ca83bb8974755e2e48c0.webp&#34;
               width=&#34;736&#34;
               height=&#34;618&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;全局负载均衡部署中的Traffic Director（cloud.google.com）&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;我们之间的 Istio 管理员可能跳起来说“这是一个托管的Istio控制平面”。那是因为Istio支持上面的许多功能。（更确切地说，是Istio使用的Envoy代理）。当然，使用Istio可以实现上述许多功能 - 但它将包括大量的管理工作（特别是在扩展到多个Kubernetes集群和VM时）。此外，控制平面和整个网格的维护也可能造成麻烦。&lt;/p&gt;
&lt;p&gt;那么它确实是某种托管的Istio控制平面吗？嗯，不完全&amp;hellip;&amp;hellip;可以说是以某种方式重叠。&lt;/p&gt;
&lt;p&gt;让我简化一下&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Istio和 Google Cloud 的 Traffic Director 有几个地方不同。&lt;/p&gt;
&lt;h3 id=&#34;sla和管理&#34;&gt;SLA和管理&lt;/h3&gt;
&lt;p&gt;Istio是一个开源项目，当包含在 Openshift 或 IBM Cloud Private 等产品中时，它们具有一些生产级支持，目前没有公共云完全托管的Istio服务。Istio的大多数公共云部署都是纯开源，非托管，非SLA部署 - 通常用官方的Istio helm chart 安装。&lt;/p&gt;
&lt;p&gt;相反，Traffic Director拥有99.99％的SLA，是一项完全托管的服务。&lt;/p&gt;
&lt;h3 id=&#34;控制平面&#34;&gt;控制平面&lt;/h3&gt;
&lt;p&gt;Istio有三个核心组件：&lt;strong&gt;用于流量管理的Pilot&lt;/strong&gt;，&lt;strong&gt;用于可观察性的Mixer&lt;/strong&gt;和&lt;strong&gt;用于服务到服务安全的Citadel&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Traffic Director 提供 GCP 托管的 Pilot 以及所提及的其他功能，如全局负载均衡和集中式健康检查。&lt;/p&gt;
&lt;h3 id=&#34;缩放控制平面&#34;&gt;缩放控制平面&lt;/h3&gt;
&lt;p&gt;在Istio中，控制平面组件（如Citadel，Mixer和Pilot）通过默认设置来用HPA（HorizontalPodAutoscalers）交付 - HAP是一个负责部署的自动伸缩的Kubernetes资源。您需要调整这些设置以适合Mesh，以备在需要时使用。您还需要指定 PodAntiAffinity 规则以确保控制平面跨越多个Kubernetes 节点。&lt;/p&gt;
&lt;p&gt;使用Traffic Director，控制平面可以与网格一起缩放，无需担心。&lt;/p&gt;
&lt;h3 id=&#34;api&#34;&gt;API&lt;/h3&gt;
&lt;p&gt;作为Beta版本，无法使用 Istio API 来配置 Traffic Director。可以使用GCP API进行配置。Traffic Director和Pilot都使用开放标准API（xDS v2）与服务代理进行通信。使用Istio API配置Traffic Director在Traffic Director的路线图中。&lt;/p&gt;
&lt;h3 id=&#34;数据平面代理&#34;&gt;数据平面代理&lt;/h3&gt;
&lt;p&gt;Traffic Director使用开放式xDSv2 API与数据平面中的服务代理进行通信，从而确保您不会被锁定到专有接口。这意味着Traffic Director可以使用像Envoy这样的xDSv2兼容的开放服务代理。&lt;strong&gt;值得注意&lt;/strong&gt;的是，Traffic Director仅使用Envoy代理进行了测试，并且在当前的beta版本中仅支持Envoy版本1.9.1或更高版本。&lt;/p&gt;
&lt;p&gt;另一方面，Istio目前仅与Envoy一起发行，虽然有像&lt;a href=&#34;https://github.com/nginxinc/nginmesh&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;nginMesh&lt;/a&gt;这样的项目，使用 nginx 作为 Sidecar 代理配合 Istio 控制平面，但这是一个单独的项目。&lt;/p&gt;
&lt;p&gt;值得一提的是，Envoy拥有领先的网格代理，为服务网格而设计，具有高性能和低内存占用。&lt;/p&gt;
&lt;h3 id=&#34;sidecar注入和部署&#34;&gt;Sidecar注入和部署&lt;/h3&gt;
&lt;p&gt;在 Istio 和 Traffic Director 中，代理可以在 Kubernetes 部署（最终是POD）和VM上。在VM上部署的两种情况下，都会提供多个脚本和文件来安装代理并使用控制器对其进行配置。&lt;/p&gt;
&lt;p&gt;对于Kubernetes工作负载，Istio开箱即用，具有自动注入机制（与MutatingAdmissionController 配合使用），当在标记为自动注入的命名空间或使用专用POD注释创建POD时，它会自动将Sidecar代理注入到POD。&lt;/p&gt;
&lt;p&gt;使用 Traffic Director，您当前需要手动注入 Sidecar。并且还要使用注释从服务创建NEG（&lt;a href=&#34;https://cloud.google.com/load-balancing/docs/negs/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;请参阅GCP网络端点组&lt;/a&gt;），以便可以将其作为服务添加到Traffic Director中。&lt;/p&gt;
&lt;p&gt;考虑到创建 &lt;a href=&#34;https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;MutatingAdmissionWebhook&lt;/a&gt; 和注入服务相对容易，我相信Traffic Director 迟早会提供自动注入的&amp;hellip;&lt;/p&gt;
&lt;h3 id=&#34;多集群网格&#34;&gt;多集群网格&lt;/h3&gt;
&lt;p&gt;在Istio中，为了让网格跨越多个Kubernetes 集群，Istio提供了一个专用 chart 用于扩展网格，名为 istio-remote。我这里就不再展开。&lt;/p&gt;
&lt;p&gt;由于 Traffic Director 是一个控制平面，位于 Kubernetes 集群之外，可以从任意集群添加Kubernetes工作负载到 Traffic Director，没有跨越多个集群的网格的特定演练。&lt;/p&gt;
&lt;h3 id=&#34;网格可观测性&#34;&gt;网格可观测性&lt;/h3&gt;
&lt;p&gt;目前，Istio推出了Kiali - 一个很好用的网格可观测性，极大的帮助了我们的客户在微服务应用程序中调试问题。Kiali一直在不断发展，迅速发布新版本。&lt;/p&gt;
&lt;p&gt;Traffic Director的特点是可以使用多个工具进行观测，包括&lt;a href=&#34;http://skywalking.apache.org/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Apache Skywalking&lt;/a&gt;。&lt;/p&gt;
&lt;h3 id=&#34;-pricing-&#34;&gt;$ Pricing $&lt;/h3&gt;
&lt;p&gt;Istio是开源和免费的。Traffic Director目前免费提供Beta版本。&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&#34;如果我已经在gke上使用istio运维生产网格怎么办&#34;&gt;“如果我已经在GKE上使用Istio运维生产网格怎么办？”&lt;/h3&gt;
&lt;p&gt;如上所述，Traffic Director是一个托管的Pilot（具有额外功能），它将支持使用 Istio API 进行管理。因此，如果您想要使用具有高SLA的完全托管的版本替换您集群内的非托管版本，它应该能够轻松选择更换。据我所知，将有适当的选择指示。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;&lt;a href=&#34;https://medium.com/@googlecloud&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Google Cloud&lt;/a&gt;最近发布了 Traffic Director。由于它基于Istio的核心模式，而谷歌是Istio主要贡献者之一，我预测它会有美好未来。现在正是所有公有云提供商宣布他们自己的Mesh解决方案的时候了。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Traffic Director 的路线图目前包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;支持Istio的安全特性，如mTLS，RBAC（Istio RBAC）&lt;/li&gt;
&lt;li&gt;可观测性集成&lt;/li&gt;
&lt;li&gt;混合和多云支持&lt;/li&gt;
&lt;li&gt;使用Istio API进行管理&lt;/li&gt;
&lt;li&gt;Anthos集成&lt;/li&gt;
&lt;li&gt;与其他服务网格控制平面的联邦（Federation）&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>[译] Traffic Director介绍：Google的服务网格控制平面</title>
      <link>https://skyao.net/post/201904-introduce-traffic-director/</link>
      <pubDate>Sun, 28 Apr 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201904-introduce-traffic-director/</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;备注：英文原文来自 InfoQ网站文章 &lt;a href=&#34;https://www.infoq.com/news/2019/04/google-traffic-director&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Introducing Traffic Director: Google&amp;rsquo;s Service Mesh Control Plane&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在 Google Cloud Next 19上，服务网格的控制平面 &lt;a href=&#34;https://cloud.google.com/traffic-director/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Traffic Director&lt;/a&gt; 宣布发布 beta 测试版。Traffic Director是Google Cloud Platform（GCP）完全托管的服务网格控制平面，可提供弹性，负载平衡和流量控制功能，如金丝雀部署和A/B测试。&lt;/p&gt;
&lt;p&gt;Traffic Director 为 &lt;a href=&#34;https://www.infoq.com/articles/vp-microservices-communication-governance-using-service-mesh&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;服务网格数据平面&lt;/a&gt; 中的代理提供流量配置和控制选项。&amp;ldquo;数据平面&amp;quot;由客户端代理组成，客户端代理通常作为进程外&amp;quot;Sidecar&amp;quot;与现有服务一起部署，并负责执行网络级别操作并观察所有的入站和出站流量。使用开源 &lt;a href=&#34;http://github.com/envoyproxy/envoy/blob/32e4d286668731594eb5c81ed664bd144d8d2d88/api/XDS_PROTOCOL.md&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Envoy xDS v2 API&lt;/a&gt;)（Google称为“xDSv2”）可使 Traffic Director 与任何兼容代理（如Envoy）一起运行。&lt;/p&gt;
&lt;p&gt;Traffic Director 支持基于VM和容器化的服务，并为跨多个区域中的VM和群集提供全局负载均衡。通过向服务代理提供健康检查、路由和后端信息，Traffic Director可 &lt;a href=&#34;https://cloud.google.com/blog/products/networking/traffic-director-global-traffic-management-for-open-service-mesh&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;优化全局流量分配&lt;/a&gt;，并将流量发送到最近可以的服务。使用Traffic Director，用户可以在多个区域中部署集群，如果离原始请求最近的集群发生健康状态下降，则流量将定向到最近的可用集群。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34;
           src=&#34;https://skyao.net/post/201904-introduce-traffic-director/images/td-global-lb.svg&#34;
           loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Traffic Director全局负载均衡&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;作为负载均衡解决方案的一部分，Traffic Director下放对每个服务的健康检查需求给单个代理，通过这种方式来集中进行服务健康（因为需要的请求数量将相对于服务数量呈平方关系）。聚合的服务健康信息通过  &lt;a href=&#34;http://www.envoyproxy.io/docs/envoy/latest/api-v2/api/v2/eds.proto#envoy-api-file-envoy-api-v2-eds-proto&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Envoy Endpoint Discovery Service (EDS) API&lt;/a&gt; 从集中式存储分发到每个代理。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;译者注：如果由服务的调用方在客户端进行服务健康检查，则n个服务都需要对剩下的 n-1 个服务进行连接和检查，数量级为 &lt;code&gt; n * n&lt;/code&gt; 。 使用 Sidecar 只需要对服务进行1:1的检查，然后汇总到控制平面，再分发到其他服务。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Traffic Director还监视代理报告的负载，以确定何时需要进行自动扩展。当负载增加时，Traffic Director 会 &lt;a href=&#34;https://cloud.google.com/blog/products/networking/traffic-director-global-traffic-management-for-open-service-mesh&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;通知 Autoscaler&lt;/a&gt; 并等待它扩展到所需的大小，通过减少伸缩过程中的步骤数来最小化流量峰值响应时间。这种按需驱动的自动扩展减少了预热或联系云提供商的需求。&lt;/p&gt;
&lt;p&gt;Traffic Director是一个完全托管的GCP服务，在GA为企业准备就绪时，将具有 &lt;a href=&#34;https://cloud.google.com/compute/sla&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;99.99％ 的SLA保证&lt;/a&gt;。Traffic Director配置允许用户通过将操作（例如重写，重定向和header转换）应用于HTTP匹配规则来设置自定义流量控制策略。&lt;a href=&#34;https://cloud.google.com/traffic-director/docs/traffic-director-concepts&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;据谷歌称&lt;/a&gt;，Traffic Director的优势包括简化的服务流量管理，服务弹性以及跟随用户应用程序增长的无缝扩展。&lt;/p&gt;
&lt;p&gt;Traffic Director目前处于测试阶段，不受SLA或弃用策略的约束，可能会有向后不兼容的更改。测试版目前&lt;a href=&#34;https://cloud.google.com/traffic-director/docs/traffic-director-concepts&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;限定&lt;/a&gt;于支持HTTP流量和Google API，并且不支持Istio API。流量控制功能（如路由规则和流量策略）  &lt;a href=&#34;https://services.google.com/fb/forms/trafficdirectoralphas/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;仅在Alpha中可用&lt;/a&gt;。要开始使用测试版，请访问&lt;a href=&#34;https://cloud.google.com/traffic-director/docs/setting-up-traffic-director&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Traffic Director设置指南&lt;/a&gt;。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Istio性能问题讨论</title>
      <link>https://skyao.net/post/201904-istio-performance-issue/</link>
      <pubDate>Tue, 23 Apr 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201904-istio-performance-issue/</guid>
      <description>&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;今天，来自 Shopify 的 &lt;a href=&#34;https://twitter.com/michaelkipper&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Michael Kipper&lt;/a&gt; 发表了一篇文章：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://medium.com/@michael_87395/benchmarking-istio-linkerd-cpu-c36287e32781&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Benchmarking Istio &amp;amp; Linkerd CPU&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Shopify 在部署Istio作为他们的服务网格解决方案，但是遇到问题（hitting a wall：撞墙）：cost/成本！&lt;/p&gt;
&lt;p&gt;作者自己做了一次对比测试，详细的测试情况请见原文。我们这里直奔结果，看 Istio 和 Linkerd2 的对比。&lt;/p&gt;
&lt;h2 id=&#34;测试结果&#34;&gt;测试结果&lt;/h2&gt;
&lt;h3 id=&#34;控制平面&#34;&gt;控制平面&lt;/h3&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201904-istio-performance-issue/images/linkerd-cpu_hu1fab23bce9d432d218e73ad4d920314b_154623_4d06f3631729ef367007abfcf3c3e56c.webp 400w,
               /post/201904-istio-performance-issue/images/linkerd-cpu_hu1fab23bce9d432d218e73ad4d920314b_154623_7c589dcc6e487d7e2f54d918265d4538.webp 760w,
               /post/201904-istio-performance-issue/images/linkerd-cpu_hu1fab23bce9d432d218e73ad4d920314b_154623_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201904-istio-performance-issue/images/linkerd-cpu_hu1fab23bce9d432d218e73ad4d920314b_154623_4d06f3631729ef367007abfcf3c3e56c.webp&#34;
               width=&#34;760&#34;
               height=&#34;302&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Linkerd2 的控制平面，大概22 mcore。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201904-istio-performance-issue/images/istio-cpu_huc78c7609a7a38bdc17efb1563df28f71_179102_807c58ce9e5e04312f4f3fde78a63463.webp 400w,
               /post/201904-istio-performance-issue/images/istio-cpu_huc78c7609a7a38bdc17efb1563df28f71_179102_e9b5823939f34e87260cdb6d8f936769.webp 760w,
               /post/201904-istio-performance-issue/images/istio-cpu_huc78c7609a7a38bdc17efb1563df28f71_179102_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201904-istio-performance-issue/images/istio-cpu_huc78c7609a7a38bdc17efb1563df28f71_179102_807c58ce9e5e04312f4f3fde78a63463.webp&#34;
               width=&#34;760&#34;
               height=&#34;302&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Istio 的控制平面，约 750 mcore，大约是 linkerd2 的35倍。而且从图片上的数据看，istio-telemetry 使用 643 mcore，占比高达 85%。但即使去除 mixer（ istio-telemetry），istio 依然超过100 mcore，依然是 Linkerd2 的4到5倍。&lt;/p&gt;
&lt;h3 id=&#34;数据平面&#34;&gt;数据平面&lt;/h3&gt;
&lt;p&gt;再看控制平面的表现，Istio 这边是基于c++的成熟稳重的 Envoy，Linkerd2 则是基于新型语言Rust全新开发。&lt;/p&gt;
&lt;p&gt;Linkerd2 Proxy 的表现，这是客户端 Sidecar：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201904-istio-performance-issue/images/linkerd-cpu2_hu87024031706fb45637a19ad2410cd7b5_158491_ca2866c014d90c4d9d5fb9cc4405bebd.webp 400w,
               /post/201904-istio-performance-issue/images/linkerd-cpu2_hu87024031706fb45637a19ad2410cd7b5_158491_13cc65416c6d9603a2eb17c938a6079d.webp 760w,
               /post/201904-istio-performance-issue/images/linkerd-cpu2_hu87024031706fb45637a19ad2410cd7b5_158491_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201904-istio-performance-issue/images/linkerd-cpu2_hu87024031706fb45637a19ad2410cd7b5_158491_ca2866c014d90c4d9d5fb9cc4405bebd.webp&#34;
               width=&#34;760&#34;
               height=&#34;300&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Istio/Envoy的表现（客户端 Sidecar）：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201904-istio-performance-issue/images/istio-cpu2_hu9c1bef5aea564f52f7545d9deff4e774_159705_bb15d80e059523669217400d3c25e4a1.webp 400w,
               /post/201904-istio-performance-issue/images/istio-cpu2_hu9c1bef5aea564f52f7545d9deff4e774_159705_bb4e75f9e5a12ffb51da71b29fad8396.webp 760w,
               /post/201904-istio-performance-issue/images/istio-cpu2_hu9c1bef5aea564f52f7545d9deff4e774_159705_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201904-istio-performance-issue/images/istio-cpu2_hu9c1bef5aea564f52f7545d9deff4e774_159705_bb15d80e059523669217400d3c25e4a1.webp&#34;
               width=&#34;760&#34;
               height=&#34;301&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;还有服务器端sidecar的使用对比，就不继续转了，简单说结果是Istio/Envoy的CPU使用比 Linkerd 多 60%。&lt;/p&gt;
&lt;p&gt;总体来说，在数据平面，Istio/Envoy的CPU使用比 Linkerd 多 50%～60%。&lt;/p&gt;
&lt;h3 id=&#34;测试结果总结&#34;&gt;测试结果总结&lt;/h3&gt;
&lt;p&gt;综上所述，Istio在控制平面的CPU消耗约是 Linkerd2 的35倍（开启Mixer）或者4倍（关闭Mixer），在数据平面的CPU消耗是 Linkerd2 的1.5倍。&lt;/p&gt;
&lt;p&gt;这个消耗还是很明显的，尤其控制平面更是有些夸张。&lt;/p&gt;
&lt;h2 id=&#34;twitter上的讨论&#34;&gt;Twitter上的讨论&lt;/h2&gt;
&lt;p&gt;有兴趣的同学可以直接去看 twitter 上的讨论：https://twitter.com/michaelkipper&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201904-istio-performance-issue/images/twitter_huf3c4e17ed980bde867b1b1db169fd36a_181392_2c498bbecca10c685cf6bdb11131691a.webp 400w,
               /post/201904-istio-performance-issue/images/twitter_huf3c4e17ed980bde867b1b1db169fd36a_181392_4633ec4b746b12fd5d2433da838f5272.webp 760w,
               /post/201904-istio-performance-issue/images/twitter_huf3c4e17ed980bde867b1b1db169fd36a_181392_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201904-istio-performance-issue/images/twitter_huf3c4e17ed980bde867b1b1db169fd36a_181392_2c498bbecca10c685cf6bdb11131691a.webp&#34;
               width=&#34;556&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;讨论中谈到说既然mixer消耗最大，可以关闭，如果你不需要。但是明显这个建议是不能被接受的：毕竟使用Istio的一个很主要的原因就是可观测行，简单粗暴的去掉mixer的telemetry功能是不可取的。&lt;/p&gt;
&lt;p&gt;然后就是一个搞笑的地方，Karl 质疑说测试对比中 Linkerd2 是否提供了同样的可观测行，William Morgan（开发Linkerd2 的 Beoyant 公司的CEO）跳出来说 Yes！&lt;/p&gt;
&lt;p&gt;后面 Envoy 的灵魂人物，Matt Klein接连发了几个twitter&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201904-istio-performance-issue/images/mixer_hu4885d1dcc275dfe9aa6bca812b925c8e_228385_029f1a0e5b76efe045ef4103494466b9.webp 400w,
               /post/201904-istio-performance-issue/images/mixer_hu4885d1dcc275dfe9aa6bca812b925c8e_228385_fa42ae87d64021b489345c1534267452.webp 760w,
               /post/201904-istio-performance-issue/images/mixer_hu4885d1dcc275dfe9aa6bca812b925c8e_228385_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201904-istio-performance-issue/images/mixer_hu4885d1dcc275dfe9aa6bca812b925c8e_228385_029f1a0e5b76efe045ef4103494466b9.webp&#34;
               width=&#34;404&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最后这条值得注意：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;具体到 Istio, 在我看来, 他们围绕 Mixer 做出了一些不幸(unfortunate)的架构决定。好消息是, 我被告知, 在1.2 发布后这些问题会被解除, 这应该会大大提高proxy资源的利用率。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;看来是个好消息，问题是具体会有什么内容？Matt 没说，准备去调研一下，如有收获后续更新。注意这个用词，&lt;strong&gt;不幸(unfortunate)&lt;/strong&gt;，Matt 用它来形容 Istio Mixer 设计，Mixer的设计问题可见一斑。&lt;/p&gt;
&lt;h2 id=&#34;mixer背景补充&#34;&gt;Mixer背景补充&lt;/h2&gt;
&lt;p&gt;在这里补充一些Mixer的背景知识，关于Mixer的功能，可以分为两大块：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;策略/policy：或者叫做precondition，体现在api上的方法名是 check()，实现上是同步阻塞+每个请求都要执行，因此对性能影响极大，早早就被质疑，考虑到策略的必要性没那么强而性能消耗又实在过高，因此社区很多人选择关闭mixer的policy功能。后来Istio依从社区的声音，在Istio1.1版本之后默认将mixer的policy功能关闭，从而结束了社区没完没了的类似问题：为什么这么慢？怎么关闭policy？&lt;/li&gt;
&lt;li&gt;遥测/telemetry：包括metric/trace等，用于实现可观测行，体现在api上的方法名是 report()，这块也有一些质疑，不过好在report的实现是异步+批量，性能影响没check()那么夸张，而可观测性又太过重要，因此一直凑合在用。然后今天，被 Linkerd2 吊打。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;有关 Mixer telemetry的实现，和mixer cache存在的问题，请见我去年的博客文章：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;../201804-istio-achilles-heel/&#34;&gt;Mixer Cache: Istio的阿克琉斯之踵?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;../201804-istio-mixer-cache-concepts/&#34;&gt;Istio Mixer Cache工作原理与源码分析&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;另外，为什么Linkerd2 的可观测性的实现性能可以高这么多？&lt;/p&gt;
&lt;p&gt;这里涉及到Istio的架构设计，Istio的解决方案是 Sidecar 将各种请求信息发送给Mixer，由Mixer中的adapter进行各种处理，有很好的设计弹性和灵活度，但是付出了多一次 Sidecar 到Mxier的远程调用的开销。而 Linkerd2 的前身 Conduit，采用的方式是在 Sidecar 中直接完成处理，不走mixer远程访问。&lt;/p&gt;
&lt;p&gt;有关这块的详细分析，请见我去年的演讲文章 &lt;a href=&#34;../../talk/201806-service-mesh-explore/&#34;&gt;大规模微服务架构下的Service Mesh探索之路&lt;/a&gt; 的 &lt;strong&gt;架构设计&lt;/strong&gt; 一节。&lt;/p&gt;
&lt;h2 id=&#34;尾声&#34;&gt;尾声&lt;/h2&gt;
&lt;p&gt;Mixer中这两块的问题，去年就已经很明显。遗憾的是一年过去了，截止到Istio 1.1版本还是没有改变。希望Istio 1.2 中会有实质性的改善。&lt;/p&gt;
&lt;p&gt;另外，从我们团队最近的遭遇看，Istio的性能问题，不仅仅在于Mixer，之前一直觉得不会有大问题的Pilot也是状况百出，有关这块，后续会撰文说明。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>译：微服务反模式</title>
      <link>https://skyao.net/post/201904-microservice-anti-patten/</link>
      <pubDate>Wed, 10 Apr 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201904-microservice-anti-patten/</guid>
      <description>&lt;p&gt;微服务领域的著名专家 Chris Richardson 在其 &lt;a href=&#34;http://chrisrichardson.net/blog.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;博客&lt;/a&gt; 上发表了微服务反模式序列文章，描述他在与全球众多客户合作时，观察到多种微服务采用的反模式，目前有四篇：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://chrisrichardson.net/post/antipatterns/2019/01/07/microservices-are-a-magic-pixie-dust.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Microservices are a magic pixie dust anti-pattern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://chrisrichardson.net/post/antipatterns/2019/01/14/antipattern-microservices-are-the-goal.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Anti-pattern: microservices as the goal&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://chrisrichardson.net/post/antipatterns/2019/02/25/antipattern-scattershot-adoption.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Microservices adoption anti-pattern - scattershot adoption&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://chrisrichardson.net/post/antipatterns/2019/04/09/antipattern-flying-before-walking.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Microservices adoption anti-pattern - Trying to fly before you can walk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201904-microservice-anti-patten/images/cover_hucf967c33f389130ab619766a81118218_565547_ebf4617ecbf5f0235595f54cf4f86f58.webp 400w,
               /post/201904-microservice-anti-patten/images/cover_hucf967c33f389130ab619766a81118218_565547_42ed6afac5757f1b519d668c589464d5.webp 760w,
               /post/201904-microservice-anti-patten/images/cover_hucf967c33f389130ab619766a81118218_565547_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201904-microservice-anti-patten/images/cover_hucf967c33f389130ab619766a81118218_565547_ebf4617ecbf5f0235595f54cf4f86f58.webp&#34;
               width=&#34;760&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;许多企业应用程序都是庞大而复杂的巨型单体，由大型团队开发，努力满足业务需求。因此，采用微服务架构是很吸引人的选择。正如您所料，迁移到微服务需要企业应对众多技术挑战。但企业也遇到了与技术无关的障碍，这些障碍与战略，流程和组织更相关。&lt;/p&gt;
&lt;p&gt;我在与全球众多客户合作时，观察到多种微服务采用反模式，这篇文章是这个系列的第一篇。与常规模式不同（常规模式是一个问题与一个解决方案配对），反模式则由三个元素组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Problem/问题 - 试图解决的问题，在采用微服务的情况下，通常是如何提高软件交付的速度，频率和可靠性&lt;/li&gt;
&lt;li&gt;Anti-pattern solution/反模式解决方案 - 效果不佳的解决方案&lt;/li&gt;
&lt;li&gt;Refactored solution/重构后的解决方案 - 解决问题的更好方法&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;让我们来看看第一个反模式。&lt;/p&gt;
&lt;h2 id=&#34;反模式微服务是一种神奇的精灵粉尘&#34;&gt;反模式：微服务是一种神奇的精灵粉尘&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201904-microservice-anti-patten/images/magic-pixie-dust_hu2d79ac2f5d8e26d4385333ed7d51fa51_177196_5ca1a52eec8c64be1e735b5f4496b57c.webp 400w,
               /post/201904-microservice-anti-patten/images/magic-pixie-dust_hu2d79ac2f5d8e26d4385333ed7d51fa51_177196_e0fd9654ffe5c2e93175eee5ea7c4106.webp 760w,
               /post/201904-microservice-anti-patten/images/magic-pixie-dust_hu2d79ac2f5d8e26d4385333ed7d51fa51_177196_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201904-microservice-anti-patten/images/magic-pixie-dust_hu2d79ac2f5d8e26d4385333ed7d51fa51_177196_5ca1a52eec8c64be1e735b5f4496b57c.webp&#34;
               width=&#34;760&#34;
               height=&#34;583&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;译者注：a magic pixie dust/神奇的精灵粉尘，参见迪斯尼动画片&amp;quot;Tinker Bell&amp;quot; 序列，这是一种精灵们使用的具有各种魔力的粉尘。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;我观察到的一种反模式是：&lt;strong&gt;相信微服务可以解决所有的开发问题&lt;/strong&gt;。遗憾的是，事实并非如此。微服务架构只是一种具有良好可部署性和可测试性的架构风格。它是一种松耦合的体系结构，支持高效自治的团队，支持DevOps风格的开发。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201904-microservice-anti-patten/images/successtriangle_hubd8ff64e258ef804764686d6addead64_14924_177aadbdc6c750c0ac6fc057b865a241.webp 400w,
               /post/201904-microservice-anti-patten/images/successtriangle_hubd8ff64e258ef804764686d6addead64_14924_715e2c07e25a6c4fa7010d01bc608760.webp 760w,
               /post/201904-microservice-anti-patten/images/successtriangle_hubd8ff64e258ef804764686d6addead64_14924_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201904-microservice-anti-patten/images/successtriangle_hubd8ff64e258ef804764686d6addead64_14924_177aadbdc6c750c0ac6fc057b865a241.webp&#34;
               width=&#34;735&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;例如，微服务架构无法解决实施不充分的开发和部署过程。例如，许多企业依靠单独的QA团队进行人工测试。同样，他们经常使用手动部署流程。并且，有时代码混乱，过于复杂且难以理解。甚至可能存在重复和不同的代码库。微服务架构不能解决这些问题，采用微服务架构很可能相当于火上浇油。&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;/ul&gt;
&lt;h2 id=&#34;反模式以微服务为目标&#34;&gt;反模式：以微服务为目标&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201904-microservice-anti-patten/images/microservices-as-the-goal_huc92598167555195c6df12c02c9bfaeb9_379129_d07284db4ec462729d7e957e929bf3f7.webp 400w,
               /post/201904-microservice-anti-patten/images/microservices-as-the-goal_huc92598167555195c6df12c02c9bfaeb9_379129_5f1c2caca01ea495082b25a78f435ec1.webp 760w,
               /post/201904-microservice-anti-patten/images/microservices-as-the-goal_huc92598167555195c6df12c02c9bfaeb9_379129_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201904-microservice-anti-patten/images/microservices-as-the-goal_huc92598167555195c6df12c02c9bfaeb9_379129_d07284db4ec462729d7e957e929bf3f7.webp&#34;
               width=&#34;760&#34;
               height=&#34;462&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在上一篇文章中，我描述了反模式：微服务是一种神奇的精灵粉尘。我观察到的另一种反模式是：组织以微服务为目标。例如，一位高管可能宣布一项微服务转型计划，并希望每个开发团队都“做微服务”。然后开发团队争相“做微服务”。也许，团队的年度或季度奖金会受到他们“做微服务”的影响。在极端情况下，它可能取决于他们部署了多少微服务。&lt;/p&gt;
&lt;h3 id=&#34;后果&#34;&gt;后果&lt;/h3&gt;
&lt;p&gt;一方面，采用微服务是一项重大任务，高层的支持至关重要。但另一方面，将微服务作为目标的问题在于它忽略了其他障碍，这些障碍会阻碍快速，频繁和可靠的交付软件，包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;低效的流程和实践 - 瀑布流程，手动测试，手动部署&lt;/li&gt;
&lt;li&gt;Silo&amp;rsquo;d组织 - 例如开发把代码交给QA进行测试。&lt;/li&gt;
&lt;li&gt;软件质量差 - 应用程序是一个很大的漏洞，代码不干净，等等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;遭受这些问题的组织可能无法从采用微服务中受益。它甚至可能使事情变得更糟。此外，要求团队采用微服务，有可能在对应用没有意义的情况下，给开发团队强加架构。&lt;/p&gt;
&lt;h3 id=&#34;更好的方法&#34;&gt;更好的方法&lt;/h3&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;ul&gt;
&lt;li&gt;改进交货时间 - 消除浪费的工作，自动化等&lt;/li&gt;
&lt;li&gt;增加部署频率 - 自动化测试和部署等&lt;/li&gt;
&lt;li&gt;降低故障率 - 自动化测试，自动部署，GitOps等&lt;/li&gt;
&lt;li&gt;缩短恢复时间 - 改进监控，自动恢复等&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;反模式散射采用&#34;&gt;反模式：散射采用&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201904-microservice-anti-patten/images/scattershot-adoption_hue00ce7f4d03dc72ce16b59b1c8d91e5a_231695_7e8a4397867696ca68bda2f716abb589.webp 400w,
               /post/201904-microservice-anti-patten/images/scattershot-adoption_hue00ce7f4d03dc72ce16b59b1c8d91e5a_231695_dafdaedb251ded39996d7dc400bcef63.webp 760w,
               /post/201904-microservice-anti-patten/images/scattershot-adoption_hue00ce7f4d03dc72ce16b59b1c8d91e5a_231695_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201904-microservice-anti-patten/images/scattershot-adoption_hue00ce7f4d03dc72ce16b59b1c8d91e5a_231695_7e8a4397867696ca68bda2f716abb589.webp&#34;
               width=&#34;760&#34;
               height=&#34;509&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我遇到的另一种反模式是&lt;em&gt;散射采用&lt;/em&gt;，当多个应用开发团队试图采用微服务架构而没有任何协调时，就会出现这种情况。例如，几个团队可能会同时开发开发基础设施，例如自动部署管道，并搭建运行时基础设施，例如Kubernetes。这种反模式的常见原因是该组织的领导者让采用微服务成为每个人的目标。&lt;/p&gt;
&lt;h3 id=&#34;后果-1&#34;&gt;后果&lt;/h3&gt;
&lt;p&gt;一方面，组织内部越来越多的基层在努力地采用微服务架构，这很好。但另一方面，让多个团队同时调研微服务而没有任何协调是很低效的。可能存在重复工作，例如，多个团队构想如何开发微服务，为部署管道构建基础设施以及搭建运行时环境。此外，开发团队可能没有技能或时间来构建和管理开发和运行时基础设施。&lt;/p&gt;
&lt;h2 id=&#34;更好的方法-1&#34;&gt;更好的方法&lt;/h2&gt;
&lt;p&gt;更好的方法是为组织定义和执行微服务的迁移路线图。该路线图包含许多活动，包括：&lt;/p&gt;
&lt;ol&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;li&gt;迭代地从单体中提取服务（&lt;a href=&#34;https://microservices.io/patterns/refactoring/strangler-application.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;绞杀单体&lt;/a&gt;)：
&lt;ol&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;/ol&gt;
&lt;/li&gt;
&lt;li&gt;扩展到其他应用&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;反模式未走先飞&#34;&gt;反模式：未走先飞&lt;/h2&gt;
&lt;p&gt;我观察到的另一种反模式是&lt;strong&gt;未走先飞&lt;/strong&gt;（fly before you can walk）。当组织试图采用微服务架构（一种先进技术）而没有（或不承诺有）实践基本软件开发技术（例如干净的代码，良好的设计和自动化测试）时，就会发生这种情况。&lt;/p&gt;
&lt;p&gt;通常，管理层持续关注计划和功能，因此忽略了关键的软件质量因素，例如可维护性，可测试性和代码覆盖率。&lt;/p&gt;
&lt;h3 id=&#34;后果-2&#34;&gt;后果&lt;/h3&gt;
&lt;p&gt;试图采用微服务而不实践软件开发的基础可能会导致失望。微服务架构需要良好的设计技巧和测试自动化。设计糟糕并缺乏自动化测试的微服务架构可能比单体架构更差。此外，凌乱的代码会降低快速，频繁地交付软件的能力。&lt;/p&gt;
&lt;h3 id=&#34;更好的方法-2&#34;&gt;更好的方法&lt;/h3&gt;
&lt;p&gt;采用微服务时，组织需要接受基础知识，例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;清洁代码 - 作为部署管道的一部分，实施自动代码质量强化&lt;/li&gt;
&lt;li&gt;自动化测试 - 必须要求开发人员编写自动化测试，以作为开发的一部分。虽然&lt;a href=&#34;https://martinfowler.com/bliki/TestCoverage.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;测试覆盖率不是最佳度量标准&lt;/a&gt;，但它也应该由部署管道强制执行。此外，虽然测试驱动开发（TDD）不是强制性的，但组织可能还是需要它才能在最初时灌输测试习惯。&lt;/li&gt;
&lt;li&gt;设计技能 - 例如面向对象设计（OOD）或领域驱动设计（DDD）。服务必须具有稳定，设计良好的API。此外，为了避免创建分布式单体，分布式单体需要在锁定步骤中更改大量服务，开发人员需要具备设计技能，以仔细定义服务边界和职责。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;更多资料&#34;&gt;更多资料&lt;/h2&gt;
&lt;p&gt;在 &lt;a href=&#34;http://chrisrichardson.net/post/antipatterns/2019/01/28/melbourne-microservices.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Microservices anti-patterns in Melbourne&lt;/a&gt; 这篇博客中介绍了这个序列博客是从作者的一个 微服务采用反模式的演讲而来。&lt;/p&gt;
&lt;p&gt;这个演讲的PPT可以从这里浏览：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.slideshare.net/chris.e.richardson/melbourne-jan-2019-microservices-adoption-antipatterns-obstacles-to-decomposing-for-testability-and-deployability&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&lt;strong&gt;Melbourne Jan 2019 - Microservices adoption anti-patterns: Obstacles to decomposing for testability and deployability&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>译：用AWS App Mesh重新定义应用通讯</title>
      <link>https://skyao.net/post/201904-aws-app-mesh/</link>
      <pubDate>Tue, 02 Apr 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201904-aws-app-mesh/</guid>
      <description>&lt;p&gt;在 re:Invent 2018，AWS宣布了AWS App Mesh 的公开预览版，App Mesh是一个服务网格，可以轻松监视和控制跨应用的通信。今天，我很高兴地宣布App Mesh 已经可以为用户提供使用了（GA）。&lt;/p&gt;
&lt;h2 id=&#34;新的架构模式&#34;&gt;新的架构模式&lt;/h2&gt;
&lt;p&gt;许多客户正在对现有应用进行现代化改造，以求更快更灵活地进行创新。微服务等架构模式使团队能够独立测试服务并不断持续发布应用变更。这种方式可以让开发团队更快地进行实验和迭代，从而提高团队生产力。它还可以让团队快速扩展他们构建和运行应用的方式。&lt;/p&gt;
&lt;p&gt;当构建所有需要以一个应用的形式一起工作的新服务时，他们需要一种方式来在整个应用间连接，监视，控制和调试通信。此类功能的示例包括服务发现，应用级度量和日志，帮助调试流量模式的跟踪，流量整形以及保护服务之间通信的能力。&lt;/p&gt;
&lt;p&gt;通常需要在SDK中构建通信管理逻辑，并要求每个开发团队使用它。但是，随着应用的增长和团队数量的增加，跨服务一致地提供这些功能会变得复杂而耗时。&lt;/p&gt;
&lt;p&gt;我们的目标是自动化和抽象通信基础设施，以支撑每个现代应用程序，使团队能够专注于构建业务逻辑并更快地进行创新。&lt;/p&gt;
&lt;h2 id=&#34;重新定义网络&#34;&gt;重新定义网络&lt;/h2&gt;
&lt;p&gt;从历史上看，当您必须为应用搭建服务时，首先要做的就是搭建网络，即虚拟私有云（virtual private cloud / VPC）。 一切都发生在 VPC 的背景下。 我们的目标是，只要您在AWS上运行应用，就不必担心管理网络基础设施。 它应该由我们的应用感知网络来处理。 我们的网络可自动将您对服务需求的输入转换为基础设施所需的配置并管理其生命周期。 今天的App Mesh，是这个旅程的第一步。&lt;/p&gt;
&lt;h2 id=&#34;app-mesh愿景&#34;&gt;App Mesh愿景&lt;/h2&gt;
&lt;p&gt;如果您正在运行由不同团队管理的多个服务，每个团队理想地仅根据其自身服务的特定需求提供输入。他们无需了解为其服务提供支持的基础设施的详细信息。&lt;/p&gt;
&lt;p&gt;与我交谈的开发人员并不关心每个应用的连接。他们关心的问题包括，我的服务可以与谁通信？我可以访问哪些AWS资源？我如何处理错误和重试？在接受所有流量之前，如何连接和测试新的服务版本？我需要什么身份和授权才能建立连接或接受连接？这是App Mesh尝试做的事情。&lt;/p&gt;
&lt;p&gt;App Mesh提供简单的声明式方式来建模服务通信。可以定义服务到服务通信的规则，而其他所有内容将会自动处理。将其用作应用中所有服务间通信的控制单点。&lt;/p&gt;
&lt;p&gt;它提供一致的指标，日志和跟踪，并提供跨应用的端到端可见性，以帮助快速识别和调试问题。 App Mesh提供流量路由控制，以支持测试和部署服务的新版本。&lt;/p&gt;
&lt;p&gt;我们对App Mesh的愿景是一个AWS原生服务网格，与AWS原语和高级服务完全集成。包括网络原语和高级服务（类似AWS Cloud Map的），计算原语（类似Amazon EC2和AWS Fargate），以及编排工具（包括 AWS EKS，Amazon ECS和EC2上的客户管理的Kubernetes）。通过App Mesh本地集成到AWS Cloud Map，服务网格中的任何服务都会获得到帐户中每个其他AWS资源的映射。&lt;/p&gt;
&lt;h2 id=&#34;app-mesh如何运作&#34;&gt;App Mesh如何运作？&lt;/h2&gt;
&lt;p&gt;App Mesh并行运行并管理部署的每一个微服务的通信，为整个应用形成服务网格。App Mesh提供AWS托管的控制平面，您可以使用该平面为服务建模，并提供识别服务实例的声明式配置和每个服务所需的策略。&lt;/p&gt;
&lt;p&gt;App Mesh与一个名为 Envoy 的开源高性能网络代理一起工作，该代理作为应用的 Sidecar 运行。它被认为是管理分布式应用网络流量的标准。最重要的是，我们使用 Envoy 是因为我们的许多客户已经在使用它，这使得 App Mesh 的采用变得非常简单。如果您已经在运行基于 Envoy 的服务网格，那么采用 App Mesh 只需要几个基本步骤。&lt;/p&gt;
&lt;p&gt;要开始使用，请使用 App Mesh 控制台，API 或 AWS SDK 来配置服务网格并控制服务之间的流量。接下来，将 Envoy 添加到 EC2 实例，ECS 或 Fargate 任务，或者为部署的每个服务添加 Amazon EKS 或 Kubernetes pod 定义。&lt;/p&gt;
&lt;p&gt;App Mesh根据提供者服务中设置的策略，计算和分发所需的配置到和每个服务一起部署的代理。App Mesh数据平面是App Mesh控制平面配置的代理集合，用于处理服务的所有传入和传出流量。&lt;/p&gt;
&lt;p&gt;使用App Mesh，可以轻松导出服务指标，如延迟，错误率，错误代码，服务通信跟踪和服务级别日志。可以将指标发送到多个 AWS 和第三方工具，包括 Amazon CloudWatch，AWS X-Ray 或与 Envoy 集成的任何第三方监控和跟踪工具。&lt;/p&gt;
&lt;p&gt;现在，通过App Mesh，您可以用加权方式在服务之间路由流量，这样可以轻松实现安全而一致地部署服务。将来，您将能够以一致的方式配置新的流量路由功能，如重试，超时，断电和服务器端限速。&lt;/p&gt;
&lt;h2 id=&#34;app-mesh是如何构建的&#34;&gt;App Mesh是如何构建的？&lt;/h2&gt;
&lt;p&gt;App Mesh致力于提供高度可扩展而灵活的服务网络，支持任何客户工作负载，这些工作负载可以有数十个到数百个不同服务。 我们以同样的高标准来构建App Mesh的运维可用性，可扩展性和安全性，我们认为这是所有AWS服务的关键原则。&lt;/p&gt;
&lt;p&gt;我们的目标是消除运维复杂应用的无差别繁重工作。 我们提供工具，服务和可观测性，以确保您可以为自己的架构维护高标准。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201904-aws-app-mesh/images/appmesh_hu82dc9b635921e2fb6fb4d2e4e2e711a8_131887_0b060e7a6253fe3e564780f322a48e8a.webp 400w,
               /post/201904-aws-app-mesh/images/appmesh_hu82dc9b635921e2fb6fb4d2e4e2e711a8_131887_333315954acea5951c2ceb5d5fc9f766.webp 760w,
               /post/201904-aws-app-mesh/images/appmesh_hu82dc9b635921e2fb6fb4d2e4e2e711a8_131887_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201904-aws-app-mesh/images/appmesh_hu82dc9b635921e2fb6fb4d2e4e2e711a8_131887_0b060e7a6253fe3e564780f322a48e8a.webp&#34;
               width=&#34;760&#34;
               height=&#34;415&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;App Mesh支持服务运行于EKS，ECS，Fargate，EC2和 EC2 上的 Kubernetes。一些客户已经在AWS内的托管平台上运行他们的应用。但是，我们了解许多客户需要能够将跨AWS部署的服务连接到单个网格中。他们可能还需要灵活地在异构的计算资源集合中运行服务。&lt;/p&gt;
&lt;p&gt;App Mesh允许跨不同计算环境中的服务运行网格，并提供迁移路径以允许根据需要使用计算资源。它在不同的计算环境中提供一致的可观测性和路由控制。我们希望简化，使连接到网络的任何应用成为网格数据平面中的参与者。&lt;/p&gt;
&lt;p&gt;在您的应用通过服务网络进行通信之后，下一个目标是提供明确的所有权和受控的服务资源变更。App Mesh API旨在为服务提供所有权边界，以及实现它们的网络组件。从拥有整个服务网格的小型团队到拥有许多不同团队的大型公司，App Mesh可以对服务网格数据平面上的组件进行安全的事务性更改。&lt;/p&gt;
&lt;p&gt;例如，服务所有者可以为应用定义流量策略，App Mesh会自动将这些策略分发给适当的消费者。通过与其他AWS产品（如Amazon CloudWatch Logs，Amazon CloudWatch metrics 和 AWS X-Ray）的集成，我们提供了实现网格应用安全部署和运维所需的可观测性工具。&lt;/p&gt;
&lt;h2 id=&#34;采用app-mesh的合作伙伴&#34;&gt;采用App Mesh的合作伙伴&lt;/h2&gt;
&lt;p&gt;我们的合作伙伴生态系统一直与AWS密切合作，将产品与App Mesh集成，并为您提供可观测性，服务发现和安全性的工具。 这些伙伴包括：&lt;/p&gt;
&lt;p&gt;Alcide，Aqua，Datadog，Hashicorp，Neuvector，SignalFx，Solarwinds，SpotInst，Sysdig，Tetrate，Twistlock，VMWare Wavefront和Weaveworks&lt;/p&gt;
&lt;h2 id=&#34;开始使用app-mesh&#34;&gt;开始使用App Mesh&lt;/h2&gt;
&lt;p&gt;从今天开始，您可以将App Mesh与管理的服务一起使用，这些服务由ECS，EKS，Fargate以及在EC2上运行的AWS上的任何Kubernetes部署管理。 您甚至可以将它与直接在EC2上运行的应用程序一起使用。&lt;/p&gt;
&lt;p&gt;我们将 GA 视为起点，而不是终点。 我们希望为您提供与我们一起构建的机会，很快我们将启动 AWS App Mesh Beta Channel。 它是一个新的公共服务端点，允许您在新服务功能 GA 之前试用新的服务功能并提供反馈。 此新服务端点将与标准生产端点分开。它将与 AWS CLI for App Mesh 的预览版本相结合，允许您在不影响其当前生产基础设施的情况下测试新功能。&lt;/p&gt;
&lt;p&gt;要了解更多信息，请参阅 &lt;a href=&#34;https://www.allthingsdistributed.com/2019/03/redefining-application-communications-with-aws-app-mesh.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;AWS App Mesh&lt;/a&gt; 详情页面。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：英文原文请见 &lt;a href=&#34;https://www.allthingsdistributed.com/2019/03/redefining-application-communications-with-aws-app-mesh.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Redefining application communications with AWS App Mesh&lt;/a&gt;，By Werner Vogels on 2019-03-27&lt;/p&gt;
&lt;/blockquote&gt;
</description>
    </item>
    
    <item>
      <title>Istio1.1新特性之控制HTTP Retry</title>
      <link>https://skyao.net/post/201903-istio-http-retry/</link>
      <pubDate>Fri, 22 Mar 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201903-istio-http-retry/</guid>
      <description>&lt;h2 id=&#34;背景介绍&#34;&gt;背景介绍&lt;/h2&gt;
&lt;p&gt;看到崔秀龙同学发了一篇文章，&lt;a href=&#34;https://blog.fleeto.us/post/istio-book-update-for-1-1/?hmsr=toutiao.io&amp;amp;utm_medium=toutiao.io&amp;amp;utm_source=toutiao.io&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;quot;《深入浅出 Istio》在 Istio 1.1 中的一些已知情况&amp;quot;&lt;/a&gt;，其中提到：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;重试无法工作	，HTTPRetry 结构发生变更。加入 retryOn: 5xx 即可。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;想知道具体什么情况，就跑去翻了翻 Istio 的文档和代码。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://istio.io/docs/reference/config/networking/v1alpha3/virtual-service/#HTTPRetry&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://istio.io/docs/reference/config/networking/v1alpha3/virtual-service/#HTTPRetry&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;HTTPRetry 结构中增加了一个名为 retryOn 的字段，&amp;ldquo;Specifies the conditions under which retry takes place. One or more policies can be specified using a ‘,’ delimited list. &amp;ldquo;。这个字段用来指定重试的发生条件，可以有多个，用&amp;rdquo;,&amp;ldquo;分割。&lt;/p&gt;
&lt;p&gt;参考资料有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.envoyproxy.io/docs/envoy/latest/configuration/http_filters/router_filter#x-envoy-retry-on&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Envoy x-envoy-retry-on 说明&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.envoyproxy.io/docs/envoy/latest/configuration/http_filters/router_filter#x-envoy-retry-grpc-on&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Envoy x-envoy-retry-grpc-on说明&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;底层envoy早就提供了 retryOn 字段来指定重试的条件。找到相关的 issue，&lt;a href=&#34;https://github.com/istio/istio/issues/8081&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Add more configuration options to the retry policy&lt;/a&gt; ，有非常明确的说明了Istio1.1之前的做法：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Currently Istio (v1.0) hard codes the retry policy to 5xx,connect-failure,refused-stream.
See
当前Istio (v1.0)  hard code retry policy 为 5xx,connect-failure,refused-stream&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Istio1.1版本将 Envoy 的 retryOn 字段暴露出来，以便提供更灵活的设置，按说是个很常规的操作。但是为什么会导致重试无法工作呢？&lt;/p&gt;
&lt;h2 id=&#34;问题所在&#34;&gt;问题所在&lt;/h2&gt;
&lt;p&gt;这是Istio1.1之前的代码，&lt;code&gt;pilot/pkg/networking/core/v1alpha3/route/route.go&lt;/code&gt;, 其中 RetryOn 默认写死为 &amp;ldquo;5xx,connect-failure,refused-stream&amp;rdquo;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;			&lt;span class=&#34;nx&#34;&gt;RetryOn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;       &lt;span class=&#34;s&#34;&gt;&amp;#34;5xx,connect-failure,refused-stream&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;而最新的 Istio1.1版本的代码，&lt;code&gt;pilot/pkg/networking/core/v1alpha3/route/retry/retry.go&lt;/code&gt;, 提供了 retryOn 字段来指定重试的条件，如果没有明确设置（如Istio1.1之前就没有这个字段自然也就没有设置），则默认值如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;		&lt;span class=&#34;nx&#34;&gt;RetryOn&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;              &lt;span class=&#34;s&#34;&gt;&amp;#34;connect-failure,refused-stream,unavailable,cancelled,resource-exhausted&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&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;ul&gt;
&lt;li&gt;新的Istio1.1版本增加了 unavailable,cancelled,resource-exhausted 三种情况下的重试条件，非常合理&lt;/li&gt;
&lt;li&gt;新的Istio1.1版本去除了5xx&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;问题就在于默认值不再包含5xx，因此如果直接使用之前版本的测试方式，HTTPRetry中没有指定 retryOn 字段，而测试场景使用的错误码刚好是5xx，就会因为这个默认值变化的原因导致重试无法生效。&lt;/p&gt;
&lt;p&gt;但是在Istio的文档中，关于 retryOn 字段的说明中，没有提到底层默认值有改变，尤其是，“最常用的5xx错误会默认不重试”这么一个非常重要的信息，没有给出提示，所以容易造成困扰：为什么之前能工作，升级到Istio1.1就不行了？&lt;/p&gt;
&lt;p&gt;因此，如果大家测试时遇到重试功能为能生效，请检查你设置的错误条件。&lt;/p&gt;
&lt;h2 id=&#34;默认值的讨论&#34;&gt;默认值的讨论&lt;/h2&gt;
&lt;p&gt;RetryOn 的默认值应该如何设置才合理？才是必要而安全的重试？&lt;/p&gt;
&lt;p&gt;Istio1.1之前的默认值是 &amp;ldquo;5xx,connect-failure,refused-stream&amp;rdquo;，这里面 connect-failure 和 refused-stream 两个错误是连接级别的错误，也就是请求都未能发送过去，因此有必要重试，而且重试也是非常安全的。&lt;/p&gt;
&lt;p&gt;Istio1.1的新默认值设置为 “connect-failure,refused-stream,unavailable,cancelled,resource-exhausted”，其中 unavailable,cancelled,resource-exhausted 是给gRPC协议用的，重试也是安全的。&lt;/p&gt;
&lt;p&gt;真正的改变在于默认值中不再有 5xx ，具体的讨论可以参考Issue &lt;a href=&#34;https://github.com/istio/istio/pull/9840&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/istio/istio/pull/9840&lt;/a&gt;。 摘录部分重要内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RetryOn: what should we retry on by default? The question here revolves around idempotence. I suspect that connect-failure and refused-stream should be safe, regardless. But what about gateway-error (i.e. 502, 503, 504) for non-idempotent requests?&lt;/li&gt;
&lt;li&gt;For non-idempotent requests, gateway-error (i.e. 502, 503, 504) may make things even worse. But 503s is just during periods of pod churn. So we should not simply set gateway-error by default.&lt;/li&gt;
&lt;li&gt;BTW our current retry setup retries on gateway-error, connect-failure, and refused-stream and we do it with envoy headers due to the fact isito currently hardcoded retires any 5xx error (this pr addressing that), which in our opinion is bad.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最终讨论的结果是从默认值中去除了 5xx。这个决定是有道理，默认5xx就重试的确存在风险。&lt;/p&gt;
&lt;h2 id=&#34;总结分析&#34;&gt;总结分析&lt;/h2&gt;
&lt;p&gt;这是一个非常小的细节，改动的地方很小，理解起来也很容易，但还是能说明一些问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Istio/Envoy 体系的确在功能上做的非常的齐全，细微之处的考虑非常多，而且一直在完善中&lt;/li&gt;
&lt;li&gt;Istio的工程管理有点拖沓，从issue记录看，这个小改动最早在2018年8月就提出来了，最后发布却到了2019年3月，时间未免长了点&lt;/li&gt;
&lt;li&gt;重点批评一下：Istio1.1版本修改了原有的HTTP retry的默认行为，从分析上看这次修改还属于改善性质，但我觉得也还是应该在文档上有所体现，避免使用者犯错——这应该是一个基本原则，反例可以参考波音737 MAX。&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Istio1.1新特性之弃用Delta Encoding</title>
      <link>https://skyao.net/post/201903-istio-delta-encoding/</link>
      <pubDate>Wed, 20 Mar 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201903-istio-delta-encoding/</guid>
      <description>&lt;h2 id=&#34;变更分析&#34;&gt;变更分析&lt;/h2&gt;
&lt;p&gt;在istio1.1的 &lt;a href=&#34;https://istio.io/about/notes/1.1/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;release note&lt;/a&gt; 中，轻描淡写的提到一点：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Policies and telemetry
Reduced Overhead. Added several performance and scale improvements including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Improved the protocol between Envoy and Mixer&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;Envoy 和 Mixer 的API涉及到 check 和 report 的功能，最近我们正在做这块的内容，因此翻查了 &lt;code&gt;istio/api&lt;/code&gt; 项目下的 &lt;code&gt;mixer/v1/mixer.proto&lt;/code&gt; 文件，想知道到底修改了什么。检查git历史记录发现，主要改动是在 ReportRequest 请求中增加了 repeated_attributes_semantics 字段 ：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;ReportRequest&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;......&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 就是指这个属性集合，这是 envoy 往 mixer 做 report 上报的内容
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;repeated&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CompressedAttributes&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gogoproto.nullable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 指示如何解码此请求中的属性集合
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;RepeatedAttributesSemantics&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;repeated_attributes_semantics&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;RepeatedAttributesSemantics的定义：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 用于表示应如何在服务器端重组压缩属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RepeatedAttributesSemantics&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// Use delta encoding between sets of compressed attributes to reduce the overall on-wire
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// request size. Each individual set of attributes is used to modify the previous set.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// NOTE: There is no way with this encoding to specify attribute value deletion. This 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// option should be used with extreme caution.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 在压缩属性集之间使用增量编码(delta encoding)来减少整体线上请求的大小。 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 属性的每个单独集合都用于修改前一个集合。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt; &lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 注意：此编码无法指定删除属性值。 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt; &lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 应谨慎使用此选项。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;DELTA_ENCODING&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// Treat each set of compressed attributes as complete - independent from other sets
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// in this request. This will result in on-wire duplication of attributes and values, but
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// will allow for proper accounting of absent values in overall encoding.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 将每组压缩属性视为完整个体 - 独立于此请求中的其他集。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 这将导致属性和值的重复，但将允许正确计算整体编码中的不存在的值。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;INDEPENDENT_ENCODING&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这次改动对应的PR为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/istio/api/pull/770&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Add way to signal encoding used for CompressedAttributes to Mixer&lt;/a&gt;: Based on discussions around &lt;a href=&#34;https://github.com/istio/istio/issues/11151&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;istio/istio#11151&lt;/a&gt;, this PR is meant to add a way to distinguish between the mixed ways in which &lt;code&gt;release-1.0&lt;/code&gt; and &lt;code&gt;release-1.1&lt;/code&gt; handle encoding of &lt;code&gt;attributes&lt;/code&gt; in the client.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;ldquo;添加用于标记发送到Mixer的  CompressedAttributes 所使用的编码&amp;rdquo;： 此PR旨在添加一种方法来区分 &lt;code&gt;release-1.0&lt;/code&gt; 和 &lt;code&gt;release-1.1&lt;/code&gt; 在处理客户端属性编码的混合方式。&lt;/p&gt;
&lt;h2 id=&#34;背景介绍&#34;&gt;背景介绍&lt;/h2&gt;
&lt;p&gt;这里所说的 delta encoding 是什么？&lt;/p&gt;
&lt;p&gt;这里就涉及到一个背景：envoy 是如何向 mixer 发送 report 数据的。&lt;/p&gt;
&lt;p&gt;这是mixer暴露给envoy的接口定义，定义在 &lt;code&gt;mixer/v1/mixer.proto&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;service&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Mixer&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;rpc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Check&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CheckRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;returns&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CheckResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;rpc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Report&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ReportRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;returns&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ReportResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;ReportRequest 的内容（简化版本）：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;ReportRequest&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;......&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 每个`Attributes`元素表述单个动作的状态。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 可以在单个消息中提供多个动作以提高通信效率。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 客户端可以累积一组操作并将它们全部发送到一条消息中。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;repeated&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CompressedAttributes&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;gogoproto.nullable&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;attributes 是上要上报的内容，如注释所说，考虑到通讯的效率，需要将多个数据放在同一个请求中做批量上报。因此是 repeated，在一个 ReportRequest 请求中携带批量数据。CompressedAttributes 是一个为传输进行了特别优化的压缩格式，具体格式涉及到 dictionary 的使用，就不展开了。&lt;/p&gt;
&lt;p&gt;进入正题：在将多个数据批量打包上报的基础上，在 Istio1.1之前，为了更高的效率，Istio对这些同一个请求里面的多个 attributes 做了优化，称为 Delta Encoding。&lt;/p&gt;
&lt;p&gt;以下注释内容在Istio1.1之前存在的，Istio1.1之后删除：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Although&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;each&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Attributes&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;`&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;semantically&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;treated&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;as&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;an&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;independent&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;stand&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;alone&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;entity&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;unrelated&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;the&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;other&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;within&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;the&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;format&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;leverages&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;delta&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;encoding&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;between&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attribute&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;messages&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;order&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;substantially&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;reduce&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;the&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;improve&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;to&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;end&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;efficiency.&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Each&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;individual&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;set&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;used&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;modify&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;the&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;previous&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;set.&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;This&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;eliminates&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;the&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;need&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;redundantly&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;send&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;the&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;same&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;multiple&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;times&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;over&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;within&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;single&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request.&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;尽管每个“&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Attributes&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;”在语义上被视为独立实体，与消息中的其他属性无关的，但此消息格式利用属性消息之间的&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;delta&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;encoding&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;，以便显着减少请求大小并改进端到端效率。每组单独的属性用于修改前一组。这消除了在单个请求中多次冗余地发送相同属性的需要。
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;delta-encoding 的设计出发点是在于上报的数据存在大量的重复性，相邻的几条数据可能只有细微差别，因此可以考虑只传递增量。&lt;/p&gt;
&lt;p&gt;如下面三条数据，所有字段都相同，只有字段 destination_version 和 destination_workload  的值不同：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;istio_requests_total&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;connection_security_policy=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;unknown&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_app=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;reviews&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_principal=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;unknown&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_service=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;details.bookinfo.svc.cluster.local&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_service_name=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;details&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_service_namespace=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;bookinfo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_version=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;v1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_workload=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;reviews-v1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_workload_namespace=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;bookinfo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;instance=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;172.17.0.9:42422&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;job=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;istio-mesh&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;permissive_response_code=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;none&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;permissive_response_policyid=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;none&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;reporter=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;source&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;request_protocol=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;response_code=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;555&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_app=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;productpage&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_principal=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;unknown&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_version=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;v1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_workload=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;productpage-v1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_workload_namespace=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;bookinfo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;istio_requests_total&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;connection_security_policy=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;unknown&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_app=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;reviews&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_principal=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;unknown&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_service=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;details.bookinfo.svc.cluster.local&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_service_name=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;details&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_service_namespace=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;bookinfo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_version=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;v2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_workload=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;reviews-v2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_workload_namespace=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;bookinfo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;instance=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;172.17.0.9:42422&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;job=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;istio-mesh&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;permissive_response_code=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;none&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;permissive_response_policyid=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;none&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;reporter=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;source&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;request_protocol=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;response_code=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;555&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_app=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;productpage&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_principal=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;unknown&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_version=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;v1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_workload=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;productpage-v1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_workload_namespace=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;bookinfo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;istio_requests_total&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;connection_security_policy=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;unknown&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_app=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;reviews&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_principal=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;unknown&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_service=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;details.bookinfo.svc.cluster.local&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_service_name=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;details&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_service_namespace=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;bookinfo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_version=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;v3&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_workload=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;reviews-v3&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_workload_namespace=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;bookinfo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;instance=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;172.17.0.9:42422&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;job=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;istio-mesh&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;permissive_response_code=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;none&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;permissive_response_policyid=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;none&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;reporter=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;source&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;request_protocol=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;response_code=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;555&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_app=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;productpage&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_principal=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;unknown&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_version=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;v1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_workload=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;productpage-v1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_workload_namespace=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;bookinfo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&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=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-json&#34; data-lang=&#34;json&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;istio_requests_total&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;connection_security_policy=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;unknown&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_app=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;reviews&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_principal=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;unknown&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_service=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;details.bookinfo.svc.cluster.local&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_service_name=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;details&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_service_namespace=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;bookinfo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_version=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;v1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_workload=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;reviews-v1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_workload_namespace=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;bookinfo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;instance=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;172.17.0.9:42422&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;job=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;istio-mesh&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;permissive_response_code=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;none&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;permissive_response_policyid=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;none&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;reporter=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;source&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;request_protocol=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;http&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;response_code=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;555&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_app=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;productpage&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_principal=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;unknown&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_version=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;v1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_workload=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;productpage-v1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;source_workload_namespace=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;bookinfo&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;istio_requests_total&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_version=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;v2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_workload=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;reviews-v2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;istio_requests_total&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_version=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;v3&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;destination_workload=&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;&amp;#34;reviews-v3&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样数据包的大小就可以显著减少，mixer在收到请求后，只要正常解析出第一条完整数据，然后以这条数据为基础叠加第二条的增量，就可以算出第二条数据的完整值。再以第二条数据为基础，继续计算第三条&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;按说这个想法和设计很好，但是 Istio 1.1 之后放弃了 delta encoding，改成了普通的编码，即每条数据单独编码。&lt;/p&gt;
&lt;p&gt;给出的解释在代码注释中：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;enum&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;RepeatedAttributesSemantics&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;o&#34;&gt;//&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;NOTE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;There&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;no&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;way&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;this&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;encoding&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;specify&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attribute&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;deletion&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;This&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;o&#34;&gt;//&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;option&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;should&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;be&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;used&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;with&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extreme&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;caution&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;o&#34;&gt;//&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;注意：此编码无法指定属性值的删除。&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;o&#34;&gt;//&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;应谨慎使用此选项。&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;DELTA_ENCODING&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Delta Encoding有bug：无法指定属性值的删除。因此如果某条数据和上一条相比，没有某个属性，则会自动将上一条的属性继承下来，造成错误。&lt;/p&gt;
&lt;p&gt;可以通过这个 issue 了解详情&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/istio/istio/issues/11151&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Telemetry resulting from injected faults is wrong&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;摘录部分关键信息，以下是对这个issue报告的bug的总结：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mixer client (prior to 1.1-pre) uses batch compression protocol to compress multiple bags into a single report request sent to Mixer. The protocol does not support deletions.
When an attribute like destination.uid is not present in a bag, it incorrectly assumes value from the previous bag.
Mixer客户端（1.1-pre之前）使用批量压缩协议将多个包压缩成单个report请求发送到mixer。 该协议不支持删除。
当包中没有类似 destination.uid 这样的属性时，它会错误地假定获取前一个包中的值。&lt;/p&gt;
&lt;p&gt;At present 1.1-pre snapshots (Post Oct 2018) , the client does not send batch compressed data. This change was made as part of a performance change in Mixer client. 1.1-pre mixer however treats incoming data as batch compressed. This change also fixes the above problem. The proposed change:
目前1.1-pre快照（2018年10月后发布），客户端不发送批量压缩数据。 此更改是作为Mixer客户端性能更改的一部分而进行的。 然而，1.1之前的 mixer将输入数据视为批量压缩。 此次更改也解决了上述问题。 拟议的变更：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更新API以标明CompressedAttributes是否是批量压缩&lt;/li&gt;
&lt;li&gt;更新服务器端 Mixer to forgo decompression logic if batch compression is not done.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;非常坚决的提出直接去掉delta encoding的特性。也有质疑的声音：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What&amp;rsquo;s the motivation to turn off batching completely?
完全关闭批处理的动机是什么？&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;The design intent was always to break up a batch on the client if deletion were necessary. This would seem to me as the lowest impact change, rather than messing with the wire-protocol and potentially introduce some upgrade challenges (when a V1.1 proxy sends stuff to a V1.0 Mixer during an upgrade cycle).
如果需要删除，设计上可以在客户端上分解批量处理（即遇到需要删除的情况，就结束当前批量，再新起一个批量）。这在我看来是影响最小的变化，而不是搞乱线上协议并可能引入一些升级挑战（在升级期间，V1.1代理向V1.0 mixer发送内容）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;对此有解释：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;the issues that may arise are that the ordering of the reporting could have a large impact on number of requests sent to Mixer and there may be a fair amount of additional logic that has to be added to detect and handle batch segregation client-side. If the compression logic was removed for perf reasons, we may end up regressing with the intro of new batch separation logic (and return to compression).&lt;/p&gt;
&lt;p&gt;可能出现的问题是，报告的排序可能会对发送到Mixer的请求数量产生很大影响，并且可能需要添加大量额外的逻辑来检测和处理客户端的批处理隔离。 如果删除压缩逻辑造成性能问题，我们可能会结束回归，引入新的批量分离逻辑。&lt;/p&gt;
&lt;p&gt;I guess it comes down to a choice of where to dedicate resources for 1.1. My familiarity (and hence preference) would be to do that work server-side &amp;ndash; and leave the client (mostly) alone. But that definitely reflects my bias.&lt;/p&gt;
&lt;p&gt;我想这可以归结为1.1的专用资源选择。 我熟悉的是（也就是偏好）是在服务器端进行这个工作 - 并且不让客户端参与（大多数情况下）。 但这肯定反映了我的偏见。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;最后的盖棺定论：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I don&amp;rsquo;t think we should to re-open batch compression issue.
It has been removed, we can take advantage of the fact that it has been removed on the server to simplify and optimize code.&lt;/p&gt;
&lt;p&gt;我认为我们不应该重新打开批量压缩的Issue。
它已被删除，我们可以利用它已在服务器上被删除的事实来简化和优化代码。&lt;/p&gt;
&lt;p&gt;regarding upgrades: v1.1 proxy should not send traffic to v1.0 Mixer. The upgrade sequence is istio components first and then sidecars. Other types of updates are not supported.&lt;/p&gt;
&lt;p&gt;关于升级：v1.1代理不应该向v1.0mixer发送流量。 升级顺序首先是istio组件，然后是sidecars。 不支持其他类型的更新。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;总结分析&#34;&gt;总结分析&lt;/h2&gt;
&lt;p&gt;由于 Delta Encoding 有不能提现属性被删除的缺陷，会造成很大的bug。以及出于简化客户端和服务器端处理代码的考虑，因此，最终的结果是在Istio1.1中废弃了一直沿用的 Delta Encoding 优化特性。&lt;/p&gt;
&lt;p&gt;在这里，个人提出几点疑问：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Delta Encoding 到底有没有性能提升？&lt;/p&gt;
&lt;p&gt;从设计上看，正常工作时，如果多条记录有大量重复的属性，的确可以做到减少重复。但是从Istio这么坚决的放弃这个特性来看，似乎 Delta Encoding 最终也没起到应有的作用。但话又要说回来：当年选择做 Delta Encoding 的优化时又是如何决策的？有实际验证过开启Delta Encoding前后的性能提升吗？&lt;/p&gt;
&lt;p&gt;这里有个悖论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果 Delta Encoding 没效果，那么当时选择上 Delta Encoding 就是盲目提前优化而且优化无效&lt;/li&gt;
&lt;li&gt;如果 Delta Encoding 有效果，那么当前仅仅因为一个bug就立即全面废弃就太过草率&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;看后续是否有资料可以说明实际情况，再做补充更新。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Delta Encoding 的缺陷是不是可以有办法解决？&lt;/p&gt;
&lt;p&gt;从目前的bug看，主要是如果有属性缺失时，delta encoding没法体现出来。但是这个还是有办法解决的，比如前面提到的遇到属性要删除的情况，直接新起一个批量好了。不过这个的确可能因为属性删除的情况太多会造成包被拆解的太小而影响传输效率，失去批量的意义。另外的确代码复杂度上升了。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;为什么这个bug一直没被发现？&lt;/p&gt;
&lt;p&gt;从描述上看，Delta Encoding 存在很长时间了，但是一直没被发现，直到最新。而这个bug触发的情况其实并不复杂，只要某个场景下某条数据的属性相对上一条数据要少，就会触发，而且一旦触发，后续的数据都会被这个错误传染。但是就是这样还是存在很长时间才发现，是否说明，istiio的真的实际使用不多？&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;最后，不能不说， Kiali 帮了大忙，从几个 issue 的报告来看，都是通过 kiali 的调用关系图发现问题，才最终查找到是 Delta Encoding 引入的bug。可观测性的确是ServiceMesh中至关重要的特性，太重要了！&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Istio1.1新特性之TCP Weighted Cluster</title>
      <link>https://skyao.net/post/201903-istio-weighted-tcp-cluster/</link>
      <pubDate>Tue, 19 Mar 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201903-istio-weighted-tcp-cluster/</guid>
      <description>&lt;h3 id=&#34;weighted-cluster&#34;&gt;Weighted Cluster&lt;/h3&gt;
&lt;p&gt;Istio支持在多个cluster之间设置权重，通过设置不同的subset和weight，可以实现很多丰富的功能，如大家熟悉的各种灰度发布（金丝雀发布/蓝绿部署/ABTest）等都是由此变化而来。&lt;/p&gt;
&lt;p&gt;下面的例子熟悉Istio的同学应该都不陌生：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;networking.istio.io/v1alpha3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;VirtualService&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;reviews-route&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;spec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;hosts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;reviews.prod.svc.cluster.local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;http&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;route&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;destination&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;reviews.prod.svc.cluster.local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;subset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;v2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;weight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;25&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;destination&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;reviews.prod.svc.cluster.local&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;subset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;v1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;weight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;75&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个例子来自官方实例 bookinfo ：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://istio.io/docs/reference/config/istio.networking.v1alpha3/#DestinationWeight&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://istio.io/docs/reference/config/istio.networking.v1alpha3/#DestinationWeight&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;在这里设置了v1和v2的流量分别为75%和25%。&lt;/p&gt;
&lt;h3 id=&#34;只支持http&#34;&gt;只支持HTTP&lt;/h3&gt;
&lt;p&gt;但是，1.1版本之前的Istio，对于 Weighted Cluster 只支持HTTP协议（包括HTTP1.1/HTTP2/gRPC）。对于 TCP 和 TLS，虽然 VirtualService 的设置上和HTTP一直，但是实际上在执行时会做验证。&lt;/p&gt;
&lt;p&gt;在 &lt;code&gt;pilot/pkg/model/validation.go&lt;/code&gt; 中，validateTLSRoute()会对 TLS 做限制：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tls&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Route&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;errs&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;appendErrors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;errs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;New&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;TLS route must have exactly one destination&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;validateTCPRoute()会对 TCP 做限制：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tcp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Route&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;errs&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;appendErrors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;errs&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;New&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;TCP route must have exactly one destination&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;导致 TCP 和 TLS 都只能设置一个destination，也就无法实现分流。&lt;/p&gt;
&lt;h3 id=&#34;增加对tcp和tls的支持&#34;&gt;增加对TCP和TLS的支持&lt;/h3&gt;
&lt;p&gt;在 Envoy 1.8 版本之后，增加对TCP和TLS的 Weighted Cluster 支持。而在即将发布的Istio 1.1 版本中也加入同样提供支持。&lt;/p&gt;
&lt;p&gt;具体的 github PR 如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/istio/istio/pull/9112&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;pilot: add support for weighted TCP/TLS clusters&lt;/a&gt;: This PR adds support for weighted clusters in TCP and TLS implementations as supported in Envoy.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/envoyproxy/envoy/pull/4430&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;tcp_proxy: add support for weighted clusters&lt;/a&gt;:This PR adds support for optional weighted clusters in TCP Proxy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这两个PR的作者 Venil Noronha 写了一篇博客文章详细说明了 TCP和TLS的 Weighted Cluster 的用法，具体请见下文：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://venilnoronha.io/raw-tcp-traffic-shaping-with-istio-1.1.0&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Raw TCP Traffic Shaping with Istio 1.1.0&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;简单摘录一下关键点：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;networking.istio.io/v1alpha3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;VirtualService&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;route&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;spec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;hosts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;gateways&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;l&#34;&gt;gateway&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;tcp&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# &amp;lt;-- 这里！&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;match&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;31400&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;route&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;destination&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;tcp-echo-server&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;9000&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;subset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;v1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;weight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;destination&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;tcp-echo-server&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;9000&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;subset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;v2&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;weight&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;总结&#34;&gt;总结&lt;/h3&gt;
&lt;p&gt;这个特性很小，基本上一看就明白，如果有需要的时候直接用就好。&lt;/p&gt;
&lt;p&gt;唯一需要感叹的是：Envoy 和 Istio 的社区基础真好，总有人把各种之前没有完成的细节做好。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>蚂蚁金服容器与服务创新组毕业生招聘</title>
      <link>https://skyao.net/post/201903-ant-financial-guangzhou/</link>
      <pubDate>Tue, 19 Mar 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201903-ant-financial-guangzhou/</guid>
      <description>&lt;h1 id=&#34;2019春招广告&#34;&gt;2019春招广告&lt;/h1&gt;
&lt;p&gt;蚂蚁金服容器与服务创新组毕业生招聘&lt;/p&gt;
&lt;p&gt;蚂蚁金服容器与服务创新组招聘优秀毕业生啦，欢迎致力于云原生微服务研发的同学投递简历。容器与服务创新组负责金融级云原生微服务基础设施的研发与创新，招聘的岗位包括：“微服务架构研发工程师”，“Serverless架构研发工程师”。我们会提前进行面试，加速你们的面试进程。&lt;/p&gt;
&lt;h2 id=&#34;岗位描述&#34;&gt;岗位描述：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;从事ServiceMesh/Serverless研发，在这里，你可以参与业界最前沿的技术落地，与微服务领域的专家共事。&lt;/li&gt;
&lt;li&gt;面向数百万容器，数万微服务，打造基于Kubernetes的高效，智能，规模化的云原生微服务基础设施平台。&lt;/li&gt;
&lt;li&gt;跟踪最前沿的服务网格/Serverless，打造业界第一的金融级云原生Serverless平台。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;岗位要求&#34;&gt;岗位要求：&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;您不一定是计算机科班出身，但是对云原生有热忱与兴趣，对技术或科学有执着的追求。&lt;/li&gt;
&lt;li&gt;希望您了解并使用过这些开发语言中的一种：Go，C/C++，Java，Python，Rust。&lt;/li&gt;
&lt;li&gt;希望您了解并深入过如下技术领域中的一个：操作系统，虚拟化，容器技术，TCP/IP协议栈，TLS/VPC/DPDK/负载均衡等网络技术，微服务，Istio，Serverless。&lt;/li&gt;
&lt;li&gt;希望您有过实习或课程设计等实践经验。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;面向对象&#34;&gt;面向对象：&lt;/h2&gt;
&lt;p&gt;2019年11月-2020年10月期间毕业的同学&lt;/p&gt;
&lt;h2 id=&#34;地点&#34;&gt;地点:&lt;/h2&gt;
&lt;p&gt;广州&lt;/p&gt;
&lt;h2 id=&#34;简历投递&#34;&gt;简历投递：&lt;/h2&gt;
&lt;p&gt;如果您对蚂蚁金服容器与服务组的工作岗位有兴趣，希望来工作或实习，欢迎投递简历到邮箱：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;mailto:bin.zengb@alibaba-inc.com&#34;&gt;bin.zengb@alibaba-inc.com&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我们会在3个工作日内回复您，信中请注明您希望从事的工作方向。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>未来架构：从服务化到云原生</title>
      <link>https://skyao.net/publication/201903-future-architecture/</link>
      <pubDate>Tue, 19 Mar 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/publication/201903-future-architecture/</guid>
      <description>&lt;p&gt;本书有多位作者: 张亮、吴晟、敖小剑、宋净超&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /publication/201903-future-architecture/images/cover_hu46ed49d8b6e5b99ce5116e1b50d60cf6_1428833_f7601bb5aabb408f3f8f473f54b13265.webp 400w,
               /publication/201903-future-architecture/images/cover_hu46ed49d8b6e5b99ce5116e1b50d60cf6_1428833_31dd971b3a3e08abd340ef663bab98e8.webp 760w,
               /publication/201903-future-architecture/images/cover_hu46ed49d8b6e5b99ce5116e1b50d60cf6_1428833_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/publication/201903-future-architecture/images/cover_hu46ed49d8b6e5b99ce5116e1b50d60cf6_1428833_f7601bb5aabb408f3f8f473f54b13265.webp&#34;
               width=&#34;610&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;书籍说明&#34;&gt;书籍说明&lt;/h2&gt;
&lt;p&gt;本书的发起人和主笔是 &lt;strong&gt;张亮&lt;/strong&gt; 兄，另外两位作者 吴晟 和 宋净超 也是熟识已久多次合作。书籍由电子工业出版社出版，在2019年3月发售。&lt;/p&gt;
&lt;p&gt;在2018年年中，我非常荣幸的受邀参与本书的编写，贡献了其中的“第8章 跨语言服务治理方案Service Mesh”——这是我参与编写并出版的第一本实体书。非常巧合的是，这本书在京东开始销售的第一天，3月19号，正是我的生日，算是一份很独特的生日礼物。&lt;/p&gt;
&lt;h2 id=&#34;书籍介绍&#34;&gt;书籍介绍&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：以下内容转自 张亮 兄的微信公众号&amp;quot;点亮架构&amp;quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;成书缘由&#34;&gt;成书缘由&lt;/h3&gt;
&lt;p&gt;身处互联网行业的我们一向处在变革的最前端，受到世界浪潮的洗礼，不停歇地追赶着这一波又一波的技术潮流，才不会落在时代脚步之后。特别是近几年来，互联网架构不断演化，经历了从集中式架构到分布式架构，再到云原生架构的过程。云原生因能解决传统应用升级缓慢、架构臃肿、不能快速迭代等问题而逐渐成为这个时代舞台的主角。&lt;/p&gt;
&lt;p&gt;身处在这个变化浪潮中，我看着它改变着互联网架构的航行方向，并给越来越多的公司和个人带来新的思想和发展，也用我这些年走过的路、积累的经验、沉淀的眼界去学习它、读懂它，并让它融入我的知识体系网，来更新大脑里那张探索不断、充满指南针意义的架构地图。&lt;/p&gt;
&lt;p&gt;2017、2018年，我与这些变化同进同退，让Elastic-Job、&lt;a href=&#34;https://github.com/sharding-sphere&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Sharding-Sphere&lt;/a&gt;成为业界里大家认可的项目、让所负责的开源项目开始走向国际化、也认识了更多的良师益友……这种种的经历和发展，触动我开始将所闻、所见、所知、所感的珠玑落到了笔尖，串联成了这本书：《未来架构——从服务化到云原生》。&lt;/p&gt;
&lt;p&gt;这本书里有你想认识的分布式、服务化、服务网格、容器、编排治理、云原生、云数据库……&lt;/p&gt;
&lt;p&gt;这本书里既有我多年深思熟虑的见解和沉淀良久的经验，也有我弃笔又拾笔的挣扎，因为我需要让书的内容对读者负责……&lt;/p&gt;
&lt;p&gt;这本书里更有这些资深大咖的精彩章节叙述：Apache孵化器项目SkyWalking创始人&amp;amp;APM专家吴晟、CNCF Ambassador&amp;amp;云原生布道师&lt;a href=&#34;https://jimmysong.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;宋净超&lt;/a&gt;、Servicemesher社区联合创始人&amp;amp;ServiceMesh布道师&lt;a href=&#34;https://skyao.net/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;敖小剑&lt;/a&gt;……&lt;/p&gt;
&lt;h2 id=&#34;内容预览&#34;&gt;内容预览&lt;/h2&gt;
&lt;p&gt;《未来架构——从服务化到云原生》将互联网架构近几年发展的起承转合进行提炼解读、推陈出新，并和我的这些挚友们共同为大家展示互联网架构的变迁、最新最热技术的深度解读。本书预计于2019年3月中旬发售。也总算能对一直询问这本书进展的读者朋友有所交代了。在发售前，先将书籍目录汇总整理给大家，先睹为快，看是否能命中你所关心的热点技术靶心吧。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ini&#34; data-lang=&#34;ini&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第1章 云原生&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;1.1 互联网架构变迁&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;1.1.1 互联网架构核心问题&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;1.1.2 从集中式到分布式架构&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;1.1.3 从分布式到云原生架构&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;1.2 什么是云原生&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;1.2.1 概述&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;1.2.2 云原生与十二要素&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;1.2.3 十二要素进阶&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;1.2.4 云原生与CNCF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;1.2.5 小结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第2章 远程通信&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;2.1 通信方式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;2.1.1 通信协议&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;2.1.2 I/O模型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;2.1.3 Java中的I/O&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;2.2 序列化&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;2.2.1 文本序列化&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;2.2.2 二进制Java序列化&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;2.2.3 二进制异构语言序列化&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;2.2.4 小结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;2.3 远程调用&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;2.3.1 核心概念&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;2.3.2 Java远程通信RMI&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;2.3.3 异构语言RPC框架 gRPC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;2.3.4 小结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第3章 配置&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;3.1 本地配置&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;3.2 配置集中化&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;3.3 配置中心和注册中心&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;3.3.1 快速传播&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;3.3.2 变更稀疏&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;3.3.3 环境相关&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;3.4 读性能&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;3.4.1 集中式缓存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;3.4.2 本地缓存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;3.5 变更实时性&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;3.5.1 监听&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;3.5.2 定时同步&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;3.6 可用性&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;3.6.1 服务冗余&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;3.6.2 缓存&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;3.7 数据一致性&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;3.8 总结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第4章 服务治理&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;4.1 服务发现&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;4.1.1 概述&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;4.1.2 ZooKeeper&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;4.1.3 Eureka&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;4.1.4 总结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;4.2 负载均衡&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;4.2.1 服务端负载均衡&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;4.2.2 客户端负载均衡&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;4.3 限流&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;4.3.1 限流算法&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;4.3.2 限流实现方案&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;4.3.3 限流的维度与粒度&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;4.3.4 小结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;4.4 熔断&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;4.4.1 概述&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;4.4.2 熔断器模式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;4.4.3 Hystrix&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第5章 观察分布式服务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;5.1 层次划分&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;5.2 核心概念&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;5.3 分布式追踪&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;5.4 常见开源解决方案&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;5.5 应用性能监控&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;5.6 Apache SkyWalking&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;5.6.1 项目定位&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;5.6.2 SkyWalking 5核心架构&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;5.6.3 SkyWalking 5公开案例&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;5.6.4 SkyWalking 6可观测性分析平台&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第6章 侵入式服务治理方案&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;6.1 Dubbo&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;6.1.1 概述&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;6.1.2 核心流程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;6.1.3 注册中心&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;6.1.4 负载均衡&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;6.1.5 远程通信&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;6.1.6 限流&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;6.1.7 治理中心&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;6.1.8 监控中心&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;6.1.9 DubboX的扩展&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;6.2 Spring Cloud&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;6.2.1 概述&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;6.2.2 开发脚手架Spring Boot&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;6.2.3 服务发现&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;6.2.4 负载均衡&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;6.2.5 熔断&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;6.2.6 远程通信&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;6.3 总结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第7章 云原生生态的基石Kubernetes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;7.1 Kubernetes架构&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;7.2 分层设计理念及架构模型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;7.3 设计哲学&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;7.4 Kubernetes中的原语&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;7.4.1 Kubernetes中的对象&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;7.4.2 对象的期望状态与实际状态&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;7.4.3 描述Kubernetes对象&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;7.4.4 服务发现与负载均衡&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;7.4.5 安全性与权限管理&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;7.4.6 Sidecar设计模式&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;7.5 应用Kubernetes&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;7.6 Kubernetes与云原生生态&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;7.6.1 下一代云计算标准&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;7.6.2 当前存在的问题&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;7.6.3 未来趋势&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第8章 跨语言服务治理方案Service Mesh  &amp;lt;-- 本章由我编写&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;8.1 介绍&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.1.1 Service Mesh的由来&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.1.2 Service Mesh的定义&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.1.3 Service Mesh详解&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;8.2 Service Mesh演进历程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.2.1 远古时代的案例&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.2.2 微服务时代的现状&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.2.3 侵入式框架的痛点&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.2.4 解决问题的思路&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.2.5 Proxy模式的探索&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.2.6 Sidecar的出现&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.2.7 第一代Service Mesh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.2.8 第二代Service Mesh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.2.9 总结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;8.3 Service Mesh市场竞争&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.3.1 Service Mesh的萌芽期&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.3.2 急转而下的Linkerd&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.3.3 波澜不惊的Envoy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.3.4 背负使命的Istio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.3.5 背水一战的Buoyant&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.3.6 其他参与者&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.3.7 Service Mesh国内发展&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.3.8 总结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;8.4 Istio&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.4.1 介绍&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;8.4.2 架构和核心组件&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第9章 云原生数据架构&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;9.1 关系型数据库尚能饭否&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;9.1.1 优势&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;9.1.2 不足&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;9.1.3 小结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;9.2 未达预期的NoSQL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;9.2.1 键值数据库&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;9.2.2 文档数据库&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;9.2.3 列族数据库&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;9.2.4 小结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;9.3 冉冉升起的NewSQL&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;9.3.1 New Architecture&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;9.3.2 Transparent Sharding Middleware&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;9.3.3 Database-as-a-Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;9.3.4 小结&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;9.4 云原生数据库中间件的核心功能&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;9.4.1 数据分片&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;9.4.2 分布式事务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;9.4.3 数据库治理&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;第10章 分布式数据库中间件生态圈Sharding-Sphere&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;10.1 缘起&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;10.1.1 内部应用框架&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;10.1.2 开源历程&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;10.2 核心功能&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;10.2.1 数据分片&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;10.2.2 分布式事务&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;10.2.3 数据库治理&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;10.3 Sharding-JDBC&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;10.3.1 简介&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;10.3.2 使用介绍&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;10.4 ShardingProxy&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;10.4.1 简介&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;10.4.2 使用介绍&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;10.5 Database Mesh&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;10.5.1 概述&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;10.5.2 Service Mesh回顾&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;10.5.3 Database Mesh与Service Mesh的异同&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;10.5.4 Sharding-Sidecar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;10.6 未来规划&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;na&#34;&gt;10.7 社区化&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;寄托期翼&#34;&gt;寄托期翼&lt;/h3&gt;
&lt;p&gt;书的封页是张亮老师选择的老特拉福德球场前矗立的曼联Holy Trinity雕像作为背景图。&lt;/p&gt;
&lt;p&gt;1958年2月6日，曼联队在南斯拉夫参加欧冠杯获得半决赛权后，回程途中遭遇慕尼黑空难，曼联战队瞬间消失在夜空。为了曼联的复兴，幸存下来的曼联队的主帅马特·巴斯比强忍悲痛，用血泪和汗水重建曼联。1968年5月29日，在慕尼黑空难整整10年后，巴斯比带领他的新战队终于捧起了欧洲冠军杯，告慰了那些故去的亡魂！这座Holy Trinity雕像变成了永恒的纪念！&lt;/p&gt;
&lt;p&gt;信仰、永不言弃、坚持不懈、创造奇迹、浴火重生…，是我从这座雕塑中感受到的力量。每个人的一生一定都会经历高峰和低谷，见过山川和沙漠，也希望这本书不仅仅能为大家带来互联网架构的干货知识，也能寄托我对大家的祝福：希望在这十万长征路上正在不懈拼搏的你，能够拥有自己的信仰和希望，即使要途径无数沙漠和海洋，也能在经历千帆后柳暗花明！&lt;/p&gt;
&lt;h2 id=&#34;补充说明&#34;&gt;补充说明&lt;/h2&gt;
&lt;p&gt;本书截稿于2018年10月初，因此“第8章 跨语言服务治理方案Service Mesh”这部分内容，有关Istio/Linkerd等的介绍就只更新到2018年九月，到本书出版发售的2019年3月，有近半年时间。期间 Service Mesh 飞速发展，半年时间有了不少变化，最新的内容可以浏览 &lt;a href=&#34;../201902-service-mesh-2018-summary/&#34;&gt;“Service Mesh2018年度总结”&lt;/a&gt; 一文（该文发布于2019年2月中）。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Istio1.1新特性之限制服务可见性</title>
      <link>https://skyao.net/post/201903-istio-service-visibility/</link>
      <pubDate>Mon, 18 Mar 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201903-istio-service-visibility/</guid>
      <description>&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;对于服务的可见性，在 Istio 设计之初，是没有特别考虑的，或者说，Istio 一开始的假定，就是建立在如下这个前提下的：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Istio中的每个服务都可以访问Mesh中的任意服务&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;即在服务发现/请求转发这个层面，对服务访问的可见性不做任何限制，而通过安全机制来解决服务间调用权限的问题，如RBAC的使用。在这个思想的指导下，Pilot组件是需要将全量的服务信息（服务注册信息和服务治理信息）下发到 Sidecar，这样Sidecar才能在做到不管服务要请求的目标是哪个服务，都可以做到正确的路由。&lt;/p&gt;
&lt;p&gt;这个机制在 demo 和小规模使用时不是问题，但是，在实际项目落地时，如果服务数量比较多，数以百计/数以千计，则立即显露出来：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;下发的信息量太大：因此Pilot和Sidecar的CPU使用会很高，因为每次都要将全量的数据下发到每一个sidecar，需要编解码。Sidecar的内存使用也会增加。&lt;/li&gt;
&lt;li&gt;下发的频度非常密集：系统中任何一个服务的变动，都需要通知到每一个Sidecar，即使这个Sidecar所在的服务完全不访问它&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201903-istio-service-visibility/images/istio_hu3f11dd13ef9f2f752a905a9d3875d768_316970_c1937edaa7b5349f9de48d5df48a41c0.webp 400w,
               /post/201903-istio-service-visibility/images/istio_hu3f11dd13ef9f2f752a905a9d3875d768_316970_6304ebe58dc7dad23de01da9323e943a.webp 760w,
               /post/201903-istio-service-visibility/images/istio_hu3f11dd13ef9f2f752a905a9d3875d768_316970_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201903-istio-service-visibility/images/istio_hu3f11dd13ef9f2f752a905a9d3875d768_316970_c1937edaa7b5349f9de48d5df48a41c0.webp&#34;
               width=&#34;760&#34;
               height=&#34;517&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;试想：假定 A 服务只需要访问 B/C 两个服务，但是在一个有1000个服务的系统中，A服务的 Sidecar 会不得不接收到其他 998 个服务的数据和每一次的变化通知。其所需有效数据和实际得到数据的比例高达 2:1000！&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201903-istio-service-visibility/images/istio2_hu3f11dd13ef9f2f752a905a9d3875d768_425575_1d7343f8233cb41b12cc1bfeb959df28.webp 400w,
               /post/201903-istio-service-visibility/images/istio2_hu3f11dd13ef9f2f752a905a9d3875d768_425575_95d25f51df6765aefe6133bb926d2484.webp 760w,
               /post/201903-istio-service-visibility/images/istio2_hu3f11dd13ef9f2f752a905a9d3875d768_425575_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201903-istio-service-visibility/images/istio2_hu3f11dd13ef9f2f752a905a9d3875d768_425575_1d7343f8233cb41b12cc1bfeb959df28.webp&#34;
               width=&#34;760&#34;
               height=&#34;517&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;因此，在没有服务可见性控制的情况下，Pilot到Sidecar的数据下发的有效性低得可谓令人发指！&lt;/p&gt;
&lt;p&gt;理想模式：同样假定 A 服务只需要访问 B/C 两个服务，如果能通过某个方式将这个信息（成为服务依赖或者服务可见性）提供出来，让Istio得到这个信息，那么在Pilot往A服务的Sidecar下发数据时，就可以做一个简单的过滤：只发送B/C服务的信息，和只在B/C服务发生变更时通知A。而这个简单过滤所带来的Pilot和Sidecar之间数据下发的性能提升，是和系统内服务数量成线性关系，很容易就实现两个或者三个数量级的提升。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201903-istio-service-visibility/images/istio3_hu3f11dd13ef9f2f752a905a9d3875d768_345700_0a82dfadafad2a9b86092e9e809dbc3b.webp 400w,
               /post/201903-istio-service-visibility/images/istio3_hu3f11dd13ef9f2f752a905a9d3875d768_345700_5debe3ea2d6e3fb8b7b906980b62e23d.webp 760w,
               /post/201903-istio-service-visibility/images/istio3_hu3f11dd13ef9f2f752a905a9d3875d768_345700_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201903-istio-service-visibility/images/istio3_hu3f11dd13ef9f2f752a905a9d3875d768_345700_0a82dfadafad2a9b86092e9e809dbc3b.webp&#34;
               width=&#34;760&#34;
               height=&#34;517&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在Istio问世快2年之际，Istio终于开始正视这个问题——好吧，我坦白，在这一点上，我是有怨言的：Istio的工程实现中，对实际生产问题的考虑，非常不到位。&lt;/p&gt;
&lt;h2 id=&#34;istio11新动态&#34;&gt;Istio1.1新动态&lt;/h2&gt;
&lt;p&gt;Istio 1.1 即将发布，这几天陆续看到新文章介绍istio1.1的新功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzIzNzU5NTYzMA==&amp;amp;mid=2247486344&amp;amp;idx=1&amp;amp;sn=342514c520f8977b4c4ab73b81c099e9&amp;amp;chksm=e8c77509dfb0fc1fa5fc9480988a1a93ad501a6bf981c4ed4fcab86db0fed65b169270fc2193&amp;amp;mpshare=1&amp;amp;scene=1&amp;amp;srcid=&amp;amp;pass_ticket=MpgumPaw3Tf881FIiIQQD8PBdu7hskmvp3ANufYG3jLs0TogoH8jvKON9IUTqvt8#rd&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Istio1.1 功能预告&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzIxMDY5ODM1OA==&amp;amp;mid=2247484493&amp;amp;idx=1&amp;amp;sn=57e1637d309257ae43bacd0e4d9b2b6f&amp;amp;chksm=9761ed54a01664429e2c9c2fb74a2e183f6caac2fb927bc3ccd6528f591df7f9de5b97faef5a&amp;amp;mpshare=1&amp;amp;scene=1&amp;amp;srcid=&amp;amp;pass_ticket=MpgumPaw3Tf881FIiIQQD8PBdu7hskmvp3ANufYG3jLs0TogoH8jvKON9IUTqvt8#rd&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;鸿沟前的服务网格—Istio 1.1 新特性预览&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;其中和服务可见性直接相关的内容主要是 Sidecar CRD 和 ExportTo 属性。&lt;/p&gt;
&lt;p&gt;引用上面文章的内容，&amp;ldquo;鸿沟前的服务网格—Istio 1.1 新特性预览&amp;rdquo; 的介绍如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;新增 Sidecar 资源&lt;/p&gt;
&lt;p&gt;目前版本中，Sidecar 会包含整个网格内的服务信息，在 1.1 中，新建了 Sidecar 资源，通过对这一 CRD 的配置，不但能够限制 Sidecar 的相关服务的数量，从而降低资源占用，提高传播效率；还能方便的对 Sidecar 的代理行为做出更多的精细控制——例如对 Ingress 场景中的被代理端点的配置能力。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ExportTo&lt;/p&gt;
&lt;p&gt;多个路由管理对象加入了这一字段，用于指定该资源的生效范围。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;ldquo;Istio1.1 功能预告&amp;rdquo; 一文的介绍是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;新的sidecar：资源：在指定命名空间中使用sidecar资源时，支持定义可访问的服务范围，这样可以降低发给proxy的配置数量。在大规模的集群中，我们推荐给每个namespace增加sidecar对象。 这个功能主要是为了提升性能，减轻proxy计算的负担。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;限制网络资源的生效范围：为所有的网络资源增加了exportTo的字段，用来表示此网络资源在哪些namespace中生效。这个字段目前只有两个值：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;. &lt;/code&gt; 表示此网络资源只在自己定义的namespace生效；&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;* &lt;/code&gt; 表示此网络资源在所有的namespace生效。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们来围绕服务可见性，对Istio1.1新特性做一个深入了解。&lt;/p&gt;
&lt;h2 id=&#34;exportto-属性&#34;&gt;ExportTo 属性&lt;/h2&gt;
&lt;p&gt;Istio 1.1 在 DestinationRule / ServiceEntry / VirtualService 三个 CRD 上新增加了 export_to 字段（忽略其他字段）：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;DestinationRule&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;repeated&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;export_to&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;ServiceEntry&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;repeated&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;export_to&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;VirtualService&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;repeated&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;export_to&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下面是 exportTo 的字段说明，以 destination rule 为例：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;字段&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;&lt;code&gt;exportTo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;string[]&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;当前destination rule要导出的 namespace 列表。 应用于 service 的 destination rule 的解析发生在 namespace 层次结构的上下文中。 destination rule 的导出允许将其包含在其他 namespace 中的服务的解析层次结构中。 此功能为服务所有者和网格管理员提供了一种机制，用于控制跨 namespace 边界的 destination rule 的可见性。&lt;br/&gt;&lt;br/&gt;如果未指定任何 namespace，则默认情况下将 destination rule 导出到所有 namespace。&lt;br/&gt;&lt;br/&gt;值&lt;code&gt;.&lt;/code&gt; 被保留，用于定义导出到 destination rule 被声明所在的相同 namespace ，类似的值&lt;code&gt;*&lt;/code&gt;保留，用于定义导出到所有 namespaces. &lt;br/&gt;&lt;br/&gt;NOTE：在当前版本中，exportTo值被限制为&lt;code&gt;.&lt;/code&gt;或&lt;code&gt;*&lt;/code&gt;（即， 当前namespace或所有namespace）。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;从此，对以上三个CRD的使用，都必须满足 exportTo 对namespace的要求，才能被正确引用。如 gateway CRD 的说明：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// NOTE: Only virtual services exported to the gateway&amp;#39;s namespace
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// (e.g., `exportTo` value of `*`) can be referenced.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// Private configurations (e.g., `exportTo` set to `.`) will not be
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// available. Refer to the `exportTo` setting in `VirtualService`,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// `DestinationRule`, and `ServiceEntry` configurations for details.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;repeated&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hosts&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;k8s原生service&#34;&gt;k8s原生service&lt;/h3&gt;
&lt;p&gt;前面 exportTo 只能用于 DestinationRule / ServiceEntry / VirtualService ，对于我们最关注的 k8s 原生的 service对象没有涉及。而日常大多数服务都还是普通k8s服务，既然 ServiceEntry 这样Istio管理之外的服务都有可见性支持，没有理由不控制Istio内的服务。&lt;/p&gt;
&lt;p&gt;在 ServiceEntry 的定义中，发现注释部分有如下说明：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-properties&#34; data-lang=&#34;properties&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;message&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;ServiceEntry {&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;//&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;For a Kubernetes Service, the equivalent effect can be achieved by setting&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;//&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;the annotation &amp;#34;networking.istio.io/exportTo&amp;#34; to a comma-separated list&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;//&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;of namespace names.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;na&#34;&gt;repeated&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;string export_to = 7;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;对于k8s原生service，上面的注释说用 annotation &amp;ldquo;networking.istio.io/exportTo&amp;rdquo; 可以达到同样的效果。&lt;/p&gt;
&lt;p&gt;翻了一下Isito最新的代码，&lt;code&gt;install/kubernetes/helm/istio/charts/mixer/templates/service.yaml&lt;/code&gt; 的例子：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;v1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Service&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;istio-{{ $key }}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;namespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;{{&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;$.Release.Namespace }}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;annotations&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;networking.istio.io/exportTo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在&lt;code&gt;pilot/pkg/serviceregistry/kube/conversion.go&lt;/code&gt; 文件中有这个annotation的常量定义：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// ServiceExportAnnotation specifies the namespaces to which this service should be exported to.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//   &amp;#34;*&amp;#34; which is the default, indicates it is reachable within the mesh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//   &amp;#34;.&amp;#34; indicates it is reachable within its namespace
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ServiceExportAnnotation&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;networking.istio.io/exportTo&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;只在 &lt;code&gt;pilot/pkg/serviceregistry/kube/conversion.go&lt;/code&gt; 的convertService() 方法中使用，这个方法将k8s 的 api core 中的 v1.Service 转为 istio 抽象模型中的 service：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;convertService&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;svc&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;v1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;domainSuffix&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;model&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Service&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;o&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;svc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Annotations&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ServiceExportAnnotation&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;exportTo&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;make&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;model&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Visibility&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;e&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;range&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;strings&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Split&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;svc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Annotations&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ServiceExportAnnotation&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;,&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;exportTo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;model&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Visibility&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;逻辑很简单：用&amp;quot;,&amp;ldquo;将 annotation &amp;ldquo;networking.istio.io/exportTo&amp;rdquo; 的值拆开，然后转成对应 Visibility 对象作为key，以value为true保存起来。&lt;/p&gt;
&lt;p&gt;Visibility 类型定义如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Visibility defines whether a given config or service is exported to local namespace, all namespaces or none
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Visibility&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// VisibilityPrivate implies namespace local config
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;VisibilityPrivate&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Visibility&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// VisibilityPublic implies config is visible to all
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;VisibilityPublic&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Visibility&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// VisibilityNone implies config is visible to none
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;nx&#34;&gt;VisibilityNone&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Visibility&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;~&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里有三个特殊值，除了前面描述到的 &lt;code&gt;.&lt;/code&gt; 和 &lt;code&gt;*&lt;/code&gt; 之外，还有一个 &lt;code&gt;~&lt;/code&gt; 表示 none，不过目前没有使用。&lt;/p&gt;
&lt;p&gt;理论上说，这里可以通过 exportTo 字段（或者等效的  annotation &amp;ldquo;networking.istio.io/exportTo&amp;rdquo; ）指定特定的 namespace，比如&amp;rdquo;.,namespace1,namespace2&amp;quot;。但是目前文档中明确指出，只能使用  &lt;code&gt;.&lt;/code&gt; 和 &lt;code&gt;*&lt;/code&gt; 。&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-mysql&#34; data-lang=&#34;mysql&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NOTE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;in&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;current&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;release&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;exportTo&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;`&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;is&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;restricted&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;to&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;//&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;or&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;*&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;e&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;current&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;namespace&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;or&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;all&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;namespaces&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;).&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/blockquote&gt;
&lt;h2 id=&#34;sidecar-crd&#34;&gt;Sidecar CRD&lt;/h2&gt;
&lt;p&gt;在 Istio 1.1 中增加了新的CRD Sidecar，具体的定义可见 &lt;a href=&#34;https://github.com/istio/api/blob/8463cba039d858e8a849847b872ecea50b0994df/networking/v1alpha3/sidecar.proto&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/istio/api/blob/8463cba039d858e8a849847b872ecea50b0994df/networking/v1alpha3/sidecar.proto&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;从中摘录部分内容：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Sidecar描述了sidecar代理的配置，sidecar代理调解与其连接的工作负载的 inbound 和 outbound 通信。 默认情况下，Istio将为网格中的所有Sidecar代理服务，使其具有到达网格中每个工作负载所需的必要配置，并在与工作负载关联的所有端口上接收流量。 Sidecar资源提供了一种的方法，在向工作负载转发流量或从工作负载转发流量时，微调端口集合和代理将接收的协议。 &lt;strong&gt;此外，可以限制代理在从工作负载转发 outbound 流量时可以达到的服务集合。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sidecar CRD的其他功能我们暂时不展开，只看和服务可见性相关的内容，看看Sidecar CRD是如何限制可以到达的服务结合的。文档中给出了下面这个简单例子：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;networking.istio.io/v1alpha3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Sidecar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;namespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;prod-us1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;spec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;egress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;hosts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s2&#34;&gt;&amp;#34;prod-us1/*&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s2&#34;&gt;&amp;#34;prod-apis/*&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s2&#34;&gt;&amp;#34;istio-system/*&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这个示例在 prod-us1 命名空间中声明了Sidecar资源，该资源配置命名空间中的sidecars，允许出口流量到prod-us1，prod-apis和istio-system命名空间中的公共服务。&lt;/p&gt;
&lt;p&gt;但是注意这个CRD需要配合前面的 exportTo 字段使用：即如果A服务(namespace为ns1)要访问B服务(namespace为ns2)，则需要：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;首先需要B服务申明 exportTo 到 ns1 中&lt;/li&gt;
&lt;li&gt;然后再通过Sidecar CRD 设置 ns1 的 egress 的 hosts 为 &lt;code&gt;&amp;quot;ns2/*&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这样通过 exportTo 字段 + Sidecar.egress.hosts 字段的配合，实现了对服务可见性的限制。&lt;/p&gt;
&lt;p&gt;基本原理不复杂，具体实现时还有一些细节需要注意。&lt;/p&gt;
&lt;h3 id=&#34;workloadselector&#34;&gt;WorkloadSelector&lt;/h3&gt;
&lt;p&gt;上面的例子没有使用WorkloadSelector，因此设置的是整个 namespace 下所有的Sidecar的行为，或者说默认行为。可以通过带有 WorkloadSelector 的 Sidecar 资源来覆盖默认设置，hosts中也可以不用通配符，实现精确控制。&lt;/p&gt;
&lt;p&gt;例如下面的例子，就明确限制了 ns1 下的 服务 service-a 可以访问 ns2 下的服务：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;networking.istio.io/v1alpha3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Sidecar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;service-a-sidecar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;namespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ns1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;spec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;workloadSelector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;labels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;service-a&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;egress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;hosts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s2&#34;&gt;&amp;#34;ns2/*&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;hosts字段&#34;&gt;hosts字段&lt;/h3&gt;
&lt;p&gt;hosts 字段也是可以灵活设置的。文档中描述 hosts 字段为：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;必需：以 namespace/dnsName 格式被监听器暴露的的一个或多个服务主机。在指定namespace内与dnsName匹配的服务将被暴露（也就是可以访问）。相应的服务可以是服务注册表中的服务（例如，Kubernetes或cloud foundry服务）或使用ServiceEntry或 VirtualServicec 配置指定的服务。还可以使用同一名称空间中的任何关联的DestinationRule。&lt;/p&gt;
&lt;p&gt;应使用FQDN格式指定dnsName，在最左侧的组件中可以包含通配符（例如，prod / * .example.com）。将dnsName设置为 * 可以从指定的命名空间中选择所有服务（例如，prod/&lt;em&gt;.example.com）。命名空间也可以设置为 * 以从任何可用的命名空间中选择特定服务（例如，&amp;quot;&lt;/em&gt;/ foo.example.com&amp;quot;）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;前面的例子我们使用了通配符，也可以不使用通配符而明确的指定特定可以访问的服务：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;networking.istio.io/v1alpha3&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Sidecar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;service-a-sidecar&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;namespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;ns1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;spec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;workloadSelector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;labels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;app&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;service-a&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;egress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;hosts&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s2&#34;&gt;&amp;#34;ns2/service-b.example.com&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;s2&#34;&gt;&amp;#34;ns2/service-c.example.com&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当然，记得有个前提条件：service-b/service-c 的 k8s service 和相关的 CRD（DestinationRule / ServiceEntry / VirtualService）都必须正确的设置 exportTo。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201903-istio-service-visibility/images/istio4_hue125b321d2fecf58d709d98809b8159d_225429_0ed15e94e0146cba1aa1301eb991e7cc.webp 400w,
               /post/201903-istio-service-visibility/images/istio4_hue125b321d2fecf58d709d98809b8159d_225429_94650cdf4a5602a570d05e7e701e2b6c.webp 760w,
               /post/201903-istio-service-visibility/images/istio4_hue125b321d2fecf58d709d98809b8159d_225429_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201903-istio-service-visibility/images/istio4_hue125b321d2fecf58d709d98809b8159d_225429_0ed15e94e0146cba1aa1301eb991e7cc.webp&#34;
               width=&#34;760&#34;
               height=&#34;332&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：这里设计的有点复杂，按照这个思路，如果要实现上述的精确限制，多个环节都必须明确设置。一旦有一个地方出错，就会无法访问，然后debug的过程估计不会轻松。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;小结：Istio1.1 通过 exportTo 字段 + Sidecar.egress.hosts 字段的配合，实现了对服务可见性的约束&lt;/p&gt;
&lt;h2 id=&#34;代码实现&#34;&gt;代码实现&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;pilot/pkg/model/push_context.go&lt;/code&gt; 中，PushContext 在保存 Service 和 VirtualService 信息时，都分为 private 和 public 两个结构：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;PushContext&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// privateServices are reachable within the same namespace.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;privateServicesByNamespace&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// publicServices are services reachable within the mesh.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;publicServices&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;privateVirtualServicesByNamespace&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;][]&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;publicVirtualServices&lt;/span&gt;             &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Config&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以服务为例，会按照 ExportTo 字段的可见性设置来进行区分，将服务分别存放：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Caches list of services in the registry, and creates a map
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// of hostname to service
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;PushContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;initServiceRegistry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;env&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Environment&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;error&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;range&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;allServices&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;ns&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Namespace&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ExportTo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;defaultServiceExportTo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;VisibilityPrivate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               &lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;privateServicesByNamespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ns&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;privateServicesByNamespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ns&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;defaultServiceExportTo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;VisibilityPublic&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;publicServices&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;publicServices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ExportTo&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;VisibilityPrivate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                &lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;privateServicesByNamespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ns&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                   &lt;span class=&#34;nb&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;privateServicesByNamespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ns&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;],&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;               &lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;publicServices&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;publicServices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ServiceByHostname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Hostname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ServicePort2Name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Hostname&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)]&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;s&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Ports&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;当给具体的proxy下发数据时：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Services returns the list of services that are visible to a Proxy in a given config namespace
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;func&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;PushContext&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;Services&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;proxy&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Proxy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Service&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 如果 proxy 有 sidecar scope，则从 sidecar scope 获取 service 列表
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;proxy&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;proxy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SidecarScope&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;proxy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SidecarScope&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Config&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; 		   &lt;span class=&#34;nx&#34;&gt;proxy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;SidecarProxy&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;proxy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;SidecarScope&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Services&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;out&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Service&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 没有 sidecar scope，就只考虑 exportTo 的影响
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;proxy&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;kc&#34;&gt;nil&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;privateServices&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;:=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;range&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;privateServicesByNamespace&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;nx&#34;&gt;out&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;privateServices&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 只给当前 proxy 所在 namespace 的 private 服务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;nx&#34;&gt;out&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;privateServicesByNamespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;proxy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;ConfigNamespace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 和 public 的服务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;out&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;out&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ps&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;publicServices&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;out&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;SidecarScope 的说明，来自代码注释：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;SidecarScope是 Sidecar resource 的包装器，带有一些预处理数据，用于确定给定 Sidecar 可访问的Service，VirtualService和 DestinationRule。 预先计算 Sidecar 的 Service，VirtualService和 DestinationRule 可以提高性能，因为我们不再需要为每个 Sidecar 计算此列表。 我们只需将 Sidecar 与 SidecarScope 相匹配。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;SidecarScope&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// Union of services imported across all egress listeners for use by CDS code.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;services&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Service&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&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;h2 id=&#34;分析&#34;&gt;分析&lt;/h2&gt;
&lt;p&gt;从目前Istio1.1给出的信息看，Istio开始着手限制服务间可见性，以“&lt;strong&gt;降低资源占用，提高传播效率&lt;/strong&gt;”——虽然我个人认为这个本应该是设计伊始就应该考虑的问题，但是无论如何，有比没有好。&lt;/p&gt;
&lt;p&gt;对于目前Istio1.1在限制服务可见性的做法，聊一下个人看法（保留后续更新修改的权利）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;总算提供了一个避免全量数据下发的方式，理论上在服务数量比较多时，通过严格约束服务间的可见性，是可以让 Pilot 到 Sidecar 的数据下发数量起码降低一到两个数量级（1/10到1/100），Pilot的CPU使用/Sidecar的CPU使用/Sidecar的内存占用 应该都可以有明显改善。当然这是理论推断，具体是否做到了还要看 Istio 1.1 的实际测试结果。拭目以待吧，希望是个惊喜。&lt;/li&gt;
&lt;li&gt;可见性的边界，是 namespace，这一点我有些担心：k8s 的 namespace 在实践中一般不会做非常细致的细分，搞不好一个体系里面可能就几个甚至一个 namespace，以 namespace 为边界来决定服务的可见性我个人觉得粒度太大——这一点稍后咨询一下各方情况再做更新。&lt;/li&gt;
&lt;li&gt;设置上有些麻烦，从上面的分析上看，要实现服务A对服务B的精确限制，需要设置服务B的exportTo，包括k8s Service/Istio VitualService/Istio Destination Rule，还要设置服务A的 Sidecar CRD，至少要设置4个地方。繁琐且容易出错，而且语义也不直白：我相信大部分同学如果没有看过类似本文这样的讲解，恐怕很难一下就把这里面的条条道道梳理清楚。&lt;/li&gt;
&lt;li&gt;只是限制服务的可见性，而不是明确的强制要求管理服务间的静态依赖关系，后者其实是我，或者说我们团队想要的。服务可见性和服务静态依赖关系之间有语义上的明确差别：服务可见性不具备强制性的，是笼统的，是可以含糊一点的，从Istio的意图看主要是为了效率的提升（毕竟之前的做法太浪费资源）；而服务静态依赖关系是强制性的，依赖明确，设置精准，目标是为体系中的服务调用关系进行强力管控。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;先写到这，稍后深入后再补充。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>畅谈云原生（上）</title>
      <link>https://skyao.net/talk/201902-cloudnative-freely-talk/</link>
      <pubDate>Fri, 22 Feb 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/201902-cloudnative-freely-talk/</guid>
      <description>&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-1_hu6cc03c5fd06f4f171e86863c8768451e_778484_7de61bc86bbb5fd6fa544a63603a3a04.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-1_hu6cc03c5fd06f4f171e86863c8768451e_778484_1219891e5f13f73d3d9c285678d47e5a.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-1_hu6cc03c5fd06f4f171e86863c8768451e_778484_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-1_hu6cc03c5fd06f4f171e86863c8768451e_778484_7de61bc86bbb5fd6fa544a63603a3a04.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;今天和大家一起聊一聊云原生这个话题，内容来自蚂蚁金服中间件服务与容器团队。&lt;/p&gt;
&lt;p&gt;由于内容比较多，我们分为上下两个半场。&lt;/p&gt;
&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-2_hu060f432b6ceee5f93aff2e9aed12658b_26587_043aa8cd44a8087631c061ff4aa12d78.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-2_hu060f432b6ceee5f93aff2e9aed12658b_26587_3b9e4f5f72cca3f0c45c8bcb49aff11e.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-2_hu060f432b6ceee5f93aff2e9aed12658b_26587_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-2_hu060f432b6ceee5f93aff2e9aed12658b_26587_043aa8cd44a8087631c061ff4aa12d78.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;特别指出：这次分享主要是希望起到抛砖引玉的作用，让大家更多的参与到云原生这个话题的讨论，希望后面有更多更好的分享。我们笨鸟先飞，来一个头。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-3_hucecde2f6c7bda76b32f4cae974d0d849_120280_d0ba2e4a79b3f3a5d3e1b5734dc37537.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-3_hucecde2f6c7bda76b32f4cae974d0d849_120280_7d12398a93cc30056dc564f5f7363c2c.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-3_hucecde2f6c7bda76b32f4cae974d0d849_120280_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-3_hucecde2f6c7bda76b32f4cae974d0d849_120280_d0ba2e4a79b3f3a5d3e1b5734dc37537.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;内容主要围绕这几个问题，上半场我们将围绕前三个问题。&lt;/p&gt;
&lt;h2 id=&#34;如何理解云原生&#34;&gt;如何理解云原生？&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-4_hu7acd4a9f7ebb19fc7359d7a28ebb6ed3_42603_d76aba4624f6018d83be9c08011d6a63.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-4_hu7acd4a9f7ebb19fc7359d7a28ebb6ed3_42603_540e307a2039d8582b3e0402eb3003f5.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-4_hu7acd4a9f7ebb19fc7359d7a28ebb6ed3_42603_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-4_hu7acd4a9f7ebb19fc7359d7a28ebb6ed3_42603_d76aba4624f6018d83be9c08011d6a63.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第一个话题：如何理解“云原生”？之所以将这个话题放在前面，是因为，这是对云原生概念的最基本的理解，而这会直接影响到后续的所有认知。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-5_hu7fd3916a621953c3be1892a3ca17b1ab_451443_36079c56f750bbcfead3713e10f6baf4.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-5_hu7fd3916a621953c3be1892a3ca17b1ab_451443_f631265dc6265bfcbeac369d657d6c1a.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-5_hu7fd3916a621953c3be1892a3ca17b1ab_451443_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-5_hu7fd3916a621953c3be1892a3ca17b1ab_451443_36079c56f750bbcfead3713e10f6baf4.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;每个人对云原生的理解都可能不同，就如莎士比亚所说：一千个人眼中有一千个哈姆雷特。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-6_hu14bd356dc90ac8cc6ca969268c1f7b9d_8267_2c4376e7b4c77771613c837287817f25.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-6_hu14bd356dc90ac8cc6ca969268c1f7b9d_8267_e37fee66131af6289e37de21fb677c43.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-6_hu14bd356dc90ac8cc6ca969268c1f7b9d_8267_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-6_hu14bd356dc90ac8cc6ca969268c1f7b9d_8267_2c4376e7b4c77771613c837287817f25.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们来快速回顾一下云原生这个词汇在近年来定义的变化。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-7_hu7f75a566052f441bdcfeeaf3598e6140_66676_5f5a92f8a6a6e3f7927038e343c4013d.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-7_hu7f75a566052f441bdcfeeaf3598e6140_66676_317b6304e4f2436a2cee612dd28d6ee9.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-7_hu7f75a566052f441bdcfeeaf3598e6140_66676_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-7_hu7f75a566052f441bdcfeeaf3598e6140_66676_5f5a92f8a6a6e3f7927038e343c4013d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;先看Pivotal，云原生的提出者，是如何定义云原生的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-8_hu70c0fa07c61460ae3e30d9cd47760514_191478_10e96d37f777fb49662cd738647dc09a.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-8_hu70c0fa07c61460ae3e30d9cd47760514_191478_5ad86d8dc4ac858f5208dc5a0dccdc7f.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-8_hu70c0fa07c61460ae3e30d9cd47760514_191478_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-8_hu70c0fa07c61460ae3e30d9cd47760514_191478_10e96d37f777fb49662cd738647dc09a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是2015年，云原生刚刚开始推广时，Matt Stine给出的定义。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-9_hu2dfffb745518c5ffd667cc917d6383b0_258303_97749f657845b251b70a2edad303b51e.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-9_hu2dfffb745518c5ffd667cc917d6383b0_258303_80a98a523c0b8be2f2d6cb378854c138.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-9_hu2dfffb745518c5ffd667cc917d6383b0_258303_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-9_hu2dfffb745518c5ffd667cc917d6383b0_258303_97749f657845b251b70a2edad303b51e.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;两年之后，同样是Matt Stine。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-10_hub444af10d8d95ba396767e2a37bf31a8_104198_82bcc66772aa40976e4ca2f53b19d977.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-10_hub444af10d8d95ba396767e2a37bf31a8_104198_7768aefc11bd44d8fb1115aeb9317dce.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-10_hub444af10d8d95ba396767e2a37bf31a8_104198_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-10_hub444af10d8d95ba396767e2a37bf31a8_104198_82bcc66772aa40976e4ca2f53b19d977.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而这是Pivotal最新官方网站的描述。可见Pivotal对云原生的定义一直在变。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-11_hu658e618fecb2018fc1fb3762ca0cb52e_61125_86b5324f06ad3391fb519a10d4569be3.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-11_hu658e618fecb2018fc1fb3762ca0cb52e_61125_865e5653464160b692f448804ba212f0.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-11_hu658e618fecb2018fc1fb3762ca0cb52e_61125_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-11_hu658e618fecb2018fc1fb3762ca0cb52e_61125_86b5324f06ad3391fb519a10d4569be3.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;再来看看目前云原生背后最大的推手，CNCF，这是2015年CNCF刚成立时对云原生的定义。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-12_hua84d51a4a8c9ee821a824ec418714ff7_98911_77683c6f2f14ce04dd3c5d93b54f0592.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-12_hua84d51a4a8c9ee821a824ec418714ff7_98911_c62a7d5f5293ac0c6825c047230837e5.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-12_hua84d51a4a8c9ee821a824ec418714ff7_98911_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-12_hua84d51a4a8c9ee821a824ec418714ff7_98911_77683c6f2f14ce04dd3c5d93b54f0592.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;2018年CNCF更新了云原生的定义。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-13_hu61e6a7dbf56e467d161cd7e46a78c1b2_38965_7bbb48645f80696c16b779d39a3c9221.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-13_hu61e6a7dbf56e467d161cd7e46a78c1b2_38965_b4c05a7c2d8ce395323f34132cf0976b.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-13_hu61e6a7dbf56e467d161cd7e46a78c1b2_38965_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-13_hu61e6a7dbf56e467d161cd7e46a78c1b2_38965_7bbb48645f80696c16b779d39a3c9221.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是新定义中描述的代表技术，其中容器和微服务两项在不同时期的不同定义中都有出现，而服务网格这个在2017年才开始被社区接纳的新热点技术被非常醒目的列出来，和微服务并列，而不是我们通常认为的服务网格只是微服务在实施时的一种新的方式。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-14_hu43c994374cd51f9d127ec727fc33f0bc_48560_9d6d673d8d1b91560983c76bfdbd4cf8.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-14_hu43c994374cd51f9d127ec727fc33f0bc_48560_4e070d242bae0f651d1b3c4ddf1502f5.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-14_hu43c994374cd51f9d127ec727fc33f0bc_48560_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-14_hu43c994374cd51f9d127ec727fc33f0bc_48560_9d6d673d8d1b91560983c76bfdbd4cf8.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;云原生自身的定义一直在变，这让我们该如何才能准确的理解云原生呢？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-15_hu318707650f44af584614ea94171dd765_66772_8476be640b060c241c115e0340a635e8.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-15_hu318707650f44af584614ea94171dd765_66772_6aa9f63b09e5a9f1de1e674ebaa8914d.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-15_hu318707650f44af584614ea94171dd765_66772_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-15_hu318707650f44af584614ea94171dd765_66772_8476be640b060c241c115e0340a635e8.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里我们尝试，将Cloud Native这个词汇拆开来理解，先看看什么是Cloud。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-16_hu43fdaded790428abae55a9c77fb17d7c_8334_6d27a74df49925dda82626380f6395e1.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-16_hu43fdaded790428abae55a9c77fb17d7c_8334_9a4328c52f9031278d789f527a6020a1.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-16_hu43fdaded790428abae55a9c77fb17d7c_8334_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-16_hu43fdaded790428abae55a9c77fb17d7c_8334_6d27a74df49925dda82626380f6395e1.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;快速回顾一下云计算的历史，来帮助我们对云有个更感性的认识。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-17_hu001a737d30e424caa89215ccbd70aa65_74192_72949b7891870a3179366f87e279bca2.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-17_hu001a737d30e424caa89215ccbd70aa65_74192_74140b38591cacfe781794d2e45ef1a7.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-17_hu001a737d30e424caa89215ccbd70aa65_74192_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-17_hu001a737d30e424caa89215ccbd70aa65_74192_72949b7891870a3179366f87e279bca2.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;云计算的出现和虚拟化技术的发展和成熟密切相关，2000年前后x86的虚拟机技术成熟后，云计算逐渐发展起来。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-18_hubbf60d042b388f721adf9d76ff39884c_96393_d91ae1905c7b3a2f3e5558393c865471.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-18_hubbf60d042b388f721adf9d76ff39884c_96393_9fac2c75fb21cff42469f982447aa957.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-18_hubbf60d042b388f721adf9d76ff39884c_96393_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-18_hubbf60d042b388f721adf9d76ff39884c_96393_d91ae1905c7b3a2f3e5558393c865471.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;基于虚拟机技术，陆续出现了IaaS/PaaS/FaaS等形态，以及他们的开源版本。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-19_hub2d955a06efc832162729d614169604f_86851_631f761f9f6e5f94f72c603f0af16762.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-19_hub2d955a06efc832162729d614169604f_86851_d516a79a3107c7751d49fa5ba2120cd3.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-19_hub2d955a06efc832162729d614169604f_86851_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-19_hub2d955a06efc832162729d614169604f_86851_631f761f9f6e5f94f72c603f0af16762.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;2013年docker出现，容器技术成熟，然后围绕容器编排一场大战，最后在2017年底，kubernetes胜出。2015年CNCF成立，并在近年形成了cloud native生态。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-20_huaea518f45dbe0e499b6a2c05474b248e_162128_2f4fcd77ad7e46b80bf1496430e1b465.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-20_huaea518f45dbe0e499b6a2c05474b248e_162128_0c8122bf579dc4f74c1ae546c318130d.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-20_huaea518f45dbe0e499b6a2c05474b248e_162128_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-20_huaea518f45dbe0e499b6a2c05474b248e_162128_2f4fcd77ad7e46b80bf1496430e1b465.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是云的形态变化，可以看到：供应商提供的功能越来越多，而客户或者说应用需要自己管理的功能越来越少。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-21_hu44c6234ded8a7fb13434312b7734c924_56334_4d36862d7b768c152cd9b85951663677.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-21_hu44c6234ded8a7fb13434312b7734c924_56334_84e716cb8cf84df8b1f667375d399214.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-21_hu44c6234ded8a7fb13434312b7734c924_56334_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-21_hu44c6234ded8a7fb13434312b7734c924_56334_4d36862d7b768c152cd9b85951663677.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;当云发生如此之大的变化时，云上的应用要如何适应？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-22_hue067ef1a6b675d348aa78f561ea91c8f_69306_adb9ccfd108aa0339ca1a91ea21875e0.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-22_hue067ef1a6b675d348aa78f561ea91c8f_69306_e9ce53d32259bb5aed86811f0d3810ea.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-22_hue067ef1a6b675d348aa78f561ea91c8f_69306_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-22_hue067ef1a6b675d348aa78f561ea91c8f_69306_adb9ccfd108aa0339ca1a91ea21875e0.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在回顾完云计算的历史之后，我们对Cloud有更深的认识，接着继续看一下：什么是Native？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-23_hue3109fbf4baa2bfc7c6bf0f665ce7d4c_48375_c10bd68631bac87f48846d5aa66fd44d.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-23_hue3109fbf4baa2bfc7c6bf0f665ce7d4c_48375_d0534449f7fef196e4f8989a0a548a51.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-23_hue3109fbf4baa2bfc7c6bf0f665ce7d4c_48375_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-23_hue3109fbf4baa2bfc7c6bf0f665ce7d4c_48375_c10bd68631bac87f48846d5aa66fd44d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是从字典中摘抄下来的对Native词条的解释，注意其中标红的关键字。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-24_hufe72e3b42381032e3129fda6fed7665d_525100_f4a367ba6b71625f396ca523b4c62fc5.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-24_hufe72e3b42381032e3129fda6fed7665d_525100_6405bce6f6a04a78ff1035d3c8a1e02d.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-24_hufe72e3b42381032e3129fda6fed7665d_525100_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-24_hufe72e3b42381032e3129fda6fed7665d_525100_f4a367ba6b71625f396ca523b4c62fc5.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Native，总是和关键字 Born 联系在一起。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-25_huad856f7e4137f749ff2d6f8ea3aa126b_31097_6bd9fc1afcdba563d0e2239161e73c23.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-25_huad856f7e4137f749ff2d6f8ea3aa126b_31097_b86f94b1025f998a8da5f55faf3346e0.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-25_huad856f7e4137f749ff2d6f8ea3aa126b_31097_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-25_huad856f7e4137f749ff2d6f8ea3aa126b_31097_6bd9fc1afcdba563d0e2239161e73c23.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;那Cloud和native和在一起，又该如何理解？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-26_hu87034eda74ce9e2f6e91fada549071fe_142938_38d4581811aac152bef55de9865bd8f3.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-26_hu87034eda74ce9e2f6e91fada549071fe_142938_0a649740faba4cebcb64e6e83db887d5.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-26_hu87034eda74ce9e2f6e91fada549071fe_142938_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-26_hu87034eda74ce9e2f6e91fada549071fe_142938_38d4581811aac152bef55de9865bd8f3.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里我们抛出一个我们自己的理解：云原生代表着原生为云设计。详细的解释是：应用原生被设计为在云上以最佳方式运行，充分发挥云的优势。&lt;/p&gt;
&lt;p&gt;这个理解有点空泛，但是考虑到云原生的定义和特征在这些年间不停的变化，以及完全可以预料到的在未来的必然变化，我觉得，对云原生的理解似乎也只能回到云原生的出发点，而不是如何具体实现。&lt;/p&gt;
&lt;h2 id=&#34;云原生应用应该是什么样子&#34;&gt;云原生应用应该是什么样子？&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-27_hu5856f5112bf1a3ffbc196a4ba6213da8_47709_0dcd6224baa126f9024e9e27f5645281.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-27_hu5856f5112bf1a3ffbc196a4ba6213da8_47709_0d034c9369fdf717286b4c5845472158.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-27_hu5856f5112bf1a3ffbc196a4ba6213da8_47709_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-27_hu5856f5112bf1a3ffbc196a4ba6213da8_47709_0dcd6224baa126f9024e9e27f5645281.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;那在这么一个云原生理解的背景下，我再来介绍一下我对云原生应用的设想，也就是我觉得云原生应用应该是什么样子。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-28_hu36172e0c64419763f9ae6466b2e8b5f2_36417_d01a9422731500741bb5e465c9d46e83.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-28_hu36172e0c64419763f9ae6466b2e8b5f2_36417_1c9bb7b432ca2e073a0a6d6a95665aa3.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-28_hu36172e0c64419763f9ae6466b2e8b5f2_36417_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-28_hu36172e0c64419763f9ae6466b2e8b5f2_36417_d01a9422731500741bb5e465c9d46e83.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在云原生之前，底层平台负责向上提供基本运行资源。而应用需要满足业务需求和非业务需求，为了更好的代码复用，通用型好的非业务需求的实现往往会以类库和开发框架的方式提供，另外在SOA/微服务时代部分功能会以后端服务的方式存在，这样在应用中就被简化为对其客户端的调用代码。&lt;/p&gt;
&lt;p&gt;然后应用将这些功能，连同自身的业务实现代码，一起打包。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-29_hufed7e06ea105823f296c25a439a040e3_439625_7d74eaa566f802729b0a9ec344b74c8f.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-29_hufed7e06ea105823f296c25a439a040e3_439625_b9017f8d5399fd9c9d1e8fc14d05172a.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-29_hufed7e06ea105823f296c25a439a040e3_439625_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-29_hufed7e06ea105823f296c25a439a040e3_439625_7d74eaa566f802729b0a9ec344b74c8f.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是传统非云原生应用的一个形象表示：在业务需求的代码实现之后，包裹厚厚的一层非业务需求的实现（当然以类库和框架的形式出现时代码量没这么夸张）。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-30_hu6f5ebb13d796829cfc321f27084a1507_27074_3d8403d0a74c0e84a5d19b07dca9670b.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-30_hu6f5ebb13d796829cfc321f27084a1507_27074_be7eef61ecad6c1066928d869c38257f.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-30_hu6f5ebb13d796829cfc321f27084a1507_27074_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-30_hu6f5ebb13d796829cfc321f27084a1507_27074_3d8403d0a74c0e84a5d19b07dca9670b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而云的出现，可以在提供各种资源之外，还提供各种能力，从而帮助应用，使得应用可以专注于业务需求的实现。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-31_hu3fc87cf60af344b55f999e116ad464b5_331438_5f2fac1dc2e108e21f1e0134caabf73d.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-31_hu3fc87cf60af344b55f999e116ad464b5_331438_b188c0e37683963bf02a9e011b7cc0d5.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-31_hu3fc87cf60af344b55f999e116ad464b5_331438_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-31_hu3fc87cf60af344b55f999e116ad464b5_331438_5f2fac1dc2e108e21f1e0134caabf73d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在我们设想中，理想的云原生应用应该是这个样子：业务需求的实现占主体，只有少量的非业务需求相关的功能。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-32_hu66b73f3b643bb2f68346ae67a6be6947_29207_d554a2e44dce43c320904b6d12b5e227.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-32_hu66b73f3b643bb2f68346ae67a6be6947_29207_fcc989a7761db7c600a39e4a5aa7b452.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-32_hu66b73f3b643bb2f68346ae67a6be6947_29207_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-32_hu66b73f3b643bb2f68346ae67a6be6947_29207_d554a2e44dce43c320904b6d12b5e227.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;非业务需求相关的功能都被移到云，或者说基础设施中去了，以及下沉到基础设施的中间件。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-33_hu9879c978efa4002dae4e78bc6bc8dff9_30644_7a13a572491744930de6acd0e15d581e.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-33_hu9879c978efa4002dae4e78bc6bc8dff9_30644_cfa45c94c11e2f6cb2bd599ae2bb9f6d.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-33_hu9879c978efa4002dae4e78bc6bc8dff9_30644_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-33_hu9879c978efa4002dae4e78bc6bc8dff9_30644_7a13a572491744930de6acd0e15d581e.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;以服务间通讯为例：需要实现上面列举的各种功能。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-34_huef9551ae79060956ff1df9d7096cc04d_37544_5350db8fde59da99dad511dcf9571a79.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-34_huef9551ae79060956ff1df9d7096cc04d_37544_62c4d972c3def34e3ba50d7ff4662e37.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-34_huef9551ae79060956ff1df9d7096cc04d_37544_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-34_huef9551ae79060956ff1df9d7096cc04d_37544_5350db8fde59da99dad511dcf9571a79.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;SDK的思路：通过一个胖客户端，在这个客户端中实现各种功能。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-35_hu1a51dca67b8a9186b4b4e47a8428a17b_48610_c1f1fa166146d013213e345f917d5534.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-35_hu1a51dca67b8a9186b4b4e47a8428a17b_48610_8a71be3d5e36cb7571c5fd693cda002b.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-35_hu1a51dca67b8a9186b4b4e47a8428a17b_48610_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-35_hu1a51dca67b8a9186b4b4e47a8428a17b_48610_c1f1fa166146d013213e345f917d5534.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Service Mesh的思路，体现在将SDK客户端的功能剥离出来，放到Sidecar中。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-36_hud483df875c23110d3f5cb320b5624431_56755_8a3de6ba75fa8e2b9ea638489e3381f1.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-36_hud483df875c23110d3f5cb320b5624431_56755_d96e536675aad579c4e49db9a5520a91.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-36_hud483df875c23110d3f5cb320b5624431_56755_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-36_hud483df875c23110d3f5cb320b5624431_56755_8a3de6ba75fa8e2b9ea638489e3381f1.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;通过这种方式，实现应用的轻量化。此时绝大部分的功能都在剥离，应用中只留下一个轻量级的客户端。这个轻量级客户端中还保留有少数功能和信息，比如目标服务的标识（指出要调用的目标），序列化的实现。&lt;/p&gt;
&lt;p&gt;这里特别指出，有一个功能是我们努力尝试但是始终没有找到办法的：业务动态配置的客户端。也就是如何获取和应用&lt;strong&gt;业务逻辑&lt;/strong&gt;实现相关的&lt;strong&gt;动态&lt;/strong&gt;配置信息。如果有哪位同学对此有研究，希望可以指教。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-37_hu93ea2d0eee585a4683c51980086950b4_382152_4d7a41298ec893d661a328f281d97c9c.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-37_hu93ea2d0eee585a4683c51980086950b4_382152_368aeacb53040b43f92ce490798c7058.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-37_hu93ea2d0eee585a4683c51980086950b4_382152_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-37_hu93ea2d0eee585a4683c51980086950b4_382152_4d7a41298ec893d661a328f281d97c9c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们的想法，云原生应用应该超轻量化的方向努力，尽量将业务需求之外的功能剥离出来。当然要实现理想中的状态还是比较难的，但是及时是比较务实的形态，也能比非云原生下要轻量很多。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-38_hue96b9ffc1868b34e0724b95dd13642e6_43076_0ecaef7cbaa0e986a99f2fc7aaaff0dd.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-38_hue96b9ffc1868b34e0724b95dd13642e6_43076_3b78345500b4300f0b43fe387915710a.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-38_hue96b9ffc1868b34e0724b95dd13642e6_43076_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-38_hue96b9ffc1868b34e0724b95dd13642e6_43076_0ecaef7cbaa0e986a99f2fc7aaaff0dd.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在这里举一个效果比较理想的实际案例，在service mesh中实现密文通讯。&lt;/p&gt;
&lt;p&gt;由于客户端和服务器端两个sidecar的存在，因此我们可以通过Sidecar之间的协商与合作分别实现加密和解密，从而实现远程通讯的密文传输，而这个加密和解密的过程对于原有应用是透明的。&lt;/p&gt;
&lt;h2 id=&#34;云原生下的中间件该如何发展&#34;&gt;云原生下的中间件该如何发展？&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-39_hu0c845febe32372299ba00b98901ed340_56987_7ebafd70994e490551c3602275b522c8.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-39_hu0c845febe32372299ba00b98901ed340_56987_a7c52cb21fae4250bf38082329f163f7.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-39_hu0c845febe32372299ba00b98901ed340_56987_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-39_hu0c845febe32372299ba00b98901ed340_56987_7ebafd70994e490551c3602275b522c8.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;云原生涉及到的面非常广，对开发测试运维都会有影响，我们这里将聚焦在中间件，给出我们的一些粗浅的想法，因为我们来自中间件部门。大家也可以将中间件自行替换为自己关心的领域，尝试思考一下这个问题。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-40_hued51420a1ef6b167505c3c13c7b28ec6_381388_1706f7665ebdcedf9bd5bddfc3b58534.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-40_hued51420a1ef6b167505c3c13c7b28ec6_381388_7d0b8e39aa6efdf9b11c9698a9c74219.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-40_hued51420a1ef6b167505c3c13c7b28ec6_381388_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-40_hued51420a1ef6b167505c3c13c7b28ec6_381388_1706f7665ebdcedf9bd5bddfc3b58534.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;前面我们讲到云原生应用的理想形态和轻量化方向，这里隐含了一个前提：不管云原生应用的形态如何变化，云原生应用最终对外提供的功能应该是保持一致的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-41_hu43550ef957925b7718263ef1c6d646bf_238136_2fd9bd6fa31da8552ffcb42dcb57122e.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-41_hu43550ef957925b7718263ef1c6d646bf_238136_62e48a50f5ca9a182d64f6e8668adbb1.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-41_hu43550ef957925b7718263ef1c6d646bf_238136_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-41_hu43550ef957925b7718263ef1c6d646bf_238136_2fd9bd6fa31da8552ffcb42dcb57122e.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而要实现这一点，应用需要依赖于云提供的能力，来替换因应用轻量化而剥离的原有能力，云提供的能力是应用形态演变的基础和前提。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-42_huaa63b45e3eb8392fdb6a6e512c934f01_101489_d0ffa0b76778851da05d7f68154e873e.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-42_huaa63b45e3eb8392fdb6a6e512c934f01_101489_ea92af7392e9832a99cd63a9d9fb75bc.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-42_huaa63b45e3eb8392fdb6a6e512c934f01_101489_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-42_huaa63b45e3eb8392fdb6a6e512c934f01_101489_d0ffa0b76778851da05d7f68154e873e.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;理想状态下，我们期望云能够提供应用需要的所有能力，这样应用就可以以最原生化的形态出现。但是现实是这一点远还没有做到，我们依然需要在云之外额外提供一些功能，比如原有中间件的功能。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-43_huc49188627988dd21797d722048d095b6_152907_ae4b47eeebbe40ac6b768b3873ac2126.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-43_huc49188627988dd21797d722048d095b6_152907_cf92d13be88cba823632f893b403fdd4.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-43_huc49188627988dd21797d722048d095b6_152907_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-43_huc49188627988dd21797d722048d095b6_152907_ae4b47eeebbe40ac6b768b3873ac2126.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在云原生之前，中间件的做法通常是以类库和框架的形式出现，近年来也有服务形式。而在云原生时代，我们的想法是让中间件下沉到基础设施，成为云的一部分。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-44_huf18125403c43d76454ce3a6666fe43cc_48730_f946ceeb06a60462c74684d6f18bf3cf.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-44_huf18125403c43d76454ce3a6666fe43cc_48730_4ab73ccec182c4fb3c04ee484802d333.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-44_huf18125403c43d76454ce3a6666fe43cc_48730_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-44_huf18125403c43d76454ce3a6666fe43cc_48730_f946ceeb06a60462c74684d6f18bf3cf.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在这里解释一下，在前面就提到了“下沉”，什么是&lt;strong&gt;下沉&lt;/strong&gt;？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-45_huf33dfec5fee0888a57e306ea6cb623fb_267206_5aa2264262e056c5c5bdfafec6ba5437.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-45_huf33dfec5fee0888a57e306ea6cb623fb_267206_019b71a0f1171f651638083934135e60.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-45_huf33dfec5fee0888a57e306ea6cb623fb_267206_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-45_huf33dfec5fee0888a57e306ea6cb623fb_267206_5aa2264262e056c5c5bdfafec6ba5437.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-46_hu50377d9954dd85448c13c7f4e0495cd9_92337_a8505b31453b6e6e672d1c43a6da9012.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-46_hu50377d9954dd85448c13c7f4e0495cd9_92337_355f4cbf541024328b0dc413d18ec778.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-46_hu50377d9954dd85448c13c7f4e0495cd9_92337_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-46_hu50377d9954dd85448c13c7f4e0495cd9_92337_a8505b31453b6e6e672d1c43a6da9012.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们以Service Mesh模式为例来详细讲解，首先我们以白盒的视角来看Service Mesh的工作原理：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;以原生模式开发应用：应用只需具备最基本的能力，如客户端简单发一个请求给服务器端&lt;/li&gt;
&lt;li&gt;部署时动态插入Sidecar：当我们将开发的云原生应用部署到云上，具体说是部署在k8s的pod中时，我们会自动在pod中再部署一个Sidecar，用于实现为应用赋能&lt;/li&gt;
&lt;li&gt;在运行时，我们会改变云原生应用的行为：如前面所说客户端简单发一个请求给服务器端，在这里会被改变为将请求劫持到Sidecar，注意这个改变对应用而言是透明无感知的&lt;/li&gt;
&lt;li&gt;在Sidecar中实现各种功能：Sidecar里面就可以实现原有SDK客户端实现的各种功能，如服务发现，负载均衡，路由等等&lt;/li&gt;
&lt;li&gt;Sidecar在实现这些功能时，可以对接更多的基础设施，也可以对接其他的中间件产品，这种情况下，Service Mesh产品会成为应用和基础设施/中间件之间的桥梁&lt;/li&gt;
&lt;li&gt;可以通过控制平面来控制Sidecar的行为，而这些控制可以独立于应用之外&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-47_hu7a395640200a5c6bbf69ac068717d151_45034_a9219961ddf0168d966020c83bea1b54.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-47_hu7a395640200a5c6bbf69ac068717d151_45034_a162122d67ba0f2033928b0752a73fb3.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-47_hu7a395640200a5c6bbf69ac068717d151_45034_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-47_hu7a395640200a5c6bbf69ac068717d151_45034_a9219961ddf0168d966020c83bea1b54.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们再以应用的视角，将云和下沉到云中的Service Mesh产品视为黑盒，来看Service Mesh模式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;以原生模式开发应用&lt;/li&gt;
&lt;li&gt;以标准模式部署应用：底下发生了什么不关心&lt;/li&gt;
&lt;li&gt;客户端简单发一个请求给服务器端：底下是如何实现的同样不关心，应用只知道请求最终顺利发送完成&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Service Mesh产品的存在和具体工作模式，对于运行于其上的云原生应用来说是透明无感知的，但是在运行时这些能力都动态赋能给了应用，从而帮助应用在轻量化的同时依然可以继续提供原有的功能。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-48_hu7ce9f74704fddd7bb33da3b17c46f46f_148896_ba0baf2958fc41a60aab5aa0d54565e2.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-48_hu7ce9f74704fddd7bb33da3b17c46f46f_148896_3db359c728ed3e9f8826664a77b8241f.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-48_hu7ce9f74704fddd7bb33da3b17c46f46f_148896_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-48_hu7ce9f74704fddd7bb33da3b17c46f46f_148896_ba0baf2958fc41a60aab5aa0d54565e2.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Mesh模式不仅仅可以用于服务间通讯，也可以应用于更多的场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Database mesh：用于数据库访问&lt;/li&gt;
&lt;li&gt;Message mesh：用于消息系统&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-51_hub73652c1a3ef4d0455f03b46d3cbbc23_360148_8a80d083f9fda87df8f90b42e73165f4.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-51_hub73652c1a3ef4d0455f03b46d3cbbc23_360148_df82b4243f304ad4d3056a6df9115c76.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-51_hub73652c1a3ef4d0455f03b46d3cbbc23_360148_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-51_hub73652c1a3ef4d0455f03b46d3cbbc23_360148_8a80d083f9fda87df8f90b42e73165f4.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;中间件下沉到基础设施的方式，不只是有Mesh模式一种，而且也不是每个中间件都需要改造为Mesh模式，比如前面我们提到有些中间件是可以通过与Mesh集成的方式来间接为应用提供能力，典型如监控，日志，追踪等。&lt;/p&gt;
&lt;p&gt;我们也在探索mesh模式之外的更多模式，比如DNS模式，目前还在探索中。&lt;/p&gt;
&lt;p&gt;简单归纳一下我们目前总结的云原生赋能（Cloud Empower）的基本工作原理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首先要将功能实现从应用中剥离出来：这是应用轻量化的前提和基础&lt;/li&gt;
&lt;li&gt;然后在运行时为应用 &lt;strong&gt;动态赋能&lt;/strong&gt;：给应用的赋能方式也要云原生化，要求在运行时动态提供能力，而应用无感知&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk/images/ppt1-53_hub93a204e6ed00a13f2ec13e1371a0fb4_685421_a4a2ee886fc1a3a218926ceee1843486.webp 400w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-53_hub93a204e6ed00a13f2ec13e1371a0fb4_685421_7cdc6778c6195a46ae5ec3ecd2630235.webp 760w,
               /talk/201902-cloudnative-freely-talk/images/ppt1-53_hub93a204e6ed00a13f2ec13e1371a0fb4_685421_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk/images/ppt1-53_hub93a204e6ed00a13f2ec13e1371a0fb4_685421_a4a2ee886fc1a3a218926ceee1843486.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;本次畅谈云原生分享的上半场内容就到这里结果了，欢迎继续观看下半场内容。&lt;/p&gt;
&lt;p&gt;如开头所说，这次分享是希望起到一个抛砖引玉的作用，期待后面会有更多同学出来就云原生这个话题进行更多的分享和讨论。也希望能有同学介绍更多云原生的实现模式，更多云原生的发展思路，拭目以待。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>畅谈云原生（下）</title>
      <link>https://skyao.net/talk/201902-cloudnative-freely-talk2/</link>
      <pubDate>Fri, 22 Feb 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/201902-cloudnative-freely-talk2/</guid>
      <description>&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-1_hue9c651a0c7210be60ae0bd309d8ac773_778498_578fcf7d57c3dd4e8ab9281e06cae84a.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-1_hue9c651a0c7210be60ae0bd309d8ac773_778498_e71981a532de885ca4c33cd7f65dad26.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-1_hue9c651a0c7210be60ae0bd309d8ac773_778498_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-1_hue9c651a0c7210be60ae0bd309d8ac773_778498_578fcf7d57c3dd4e8ab9281e06cae84a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;接上半场的内容，继续和大家一起聊一聊云原生这个话题，内容来自蚂蚁金服中间件服务与容器团队。&lt;/p&gt;
&lt;h2 id=&#34;前言和上半场回顾&#34;&gt;前言和上半场回顾&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-2_hu060f432b6ceee5f93aff2e9aed12658b_26587_940dc37e5595c908cfa6c53740a1234a.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-2_hu060f432b6ceee5f93aff2e9aed12658b_26587_c6ac7d4f62ce2e6786388b7a9afbb9e0.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-2_hu060f432b6ceee5f93aff2e9aed12658b_26587_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-2_hu060f432b6ceee5f93aff2e9aed12658b_26587_940dc37e5595c908cfa6c53740a1234a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;特别指出：这次分享主要是希望起到抛砖引玉的作用，让大家更多的参与到云原生这个话题的讨论，希望后面有更多更好的分享。我们笨鸟先飞，先来开个头。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-3_huf1910f8cbcb0f5e8e08569fab88b7d9f_130699_041a38bf859c50a366b278ff8dbc5af8.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-3_huf1910f8cbcb0f5e8e08569fab88b7d9f_130699_c462ce3c12d2312de75a1776ca1fbefa.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-3_huf1910f8cbcb0f5e8e08569fab88b7d9f_130699_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-3_huf1910f8cbcb0f5e8e08569fab88b7d9f_130699_041a38bf859c50a366b278ff8dbc5af8.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在开始下半场的内容前，快速回顾一下上半场的内容。第一个话题是如何理解云原生，然后给出了一个我们团队的理解：应用原生被设计为在云上以最佳方式运行，充分发挥云的优势。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-4_hud8d89f80746db0eaf9f47134d60867ff_393394_549cc9078dc9cd56032421d9c5054343.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-4_hud8d89f80746db0eaf9f47134d60867ff_393394_efbc301d67172956f942e23bd036d28b.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-4_hud8d89f80746db0eaf9f47134d60867ff_393394_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-4_hud8d89f80746db0eaf9f47134d60867ff_393394_549cc9078dc9cd56032421d9c5054343.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第二个话题是：云原生应用应该是什么样子？在这里给出了我们团队的一个初步想法：云原生应用应该往轻量化方向努力。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-5_hu82c189686940a0f42f5bf0b136cf5bda_282018_76fd0d21318fa2720d386c8dcf9f91f1.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-5_hu82c189686940a0f42f5bf0b136cf5bda_282018_4a7049a14363c0c629a7d6940fa97307.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-5_hu82c189686940a0f42f5bf0b136cf5bda_282018_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-5_hu82c189686940a0f42f5bf0b136cf5bda_282018_76fd0d21318fa2720d386c8dcf9f91f1.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第三个话题：云原生的中间件该如何发展？同样尝试给出了一个我们团队目前的想法：中间件应该下沉到基础设施，然后中间价对应用的赋能方式要云原生化。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-6_hua13efc1e60beffc3ce0e56b357504a48_119744_96137dfc7922dac0941547436a067ecb.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-6_hua13efc1e60beffc3ce0e56b357504a48_119744_5a8c1da3b3ff161904f4b852d5836006.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-6_hua13efc1e60beffc3ce0e56b357504a48_119744_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-6_hua13efc1e60beffc3ce0e56b357504a48_119744_96137dfc7922dac0941547436a067ecb.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是全部内容的目录，前面三个在上半场中，今天我们将继续下半场的三个话题。&lt;/p&gt;
&lt;h2 id=&#34;云和应用该如何衔接&#34;&gt;云和应用该如何衔接？&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-7_hufc151146b4e45dacfbce1dad8c3d3e40_45032_b8bc500d93d8fa4bfd346b672143cfb0.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-7_hufc151146b4e45dacfbce1dad8c3d3e40_45032_b1e18d7b14bf6b8e371bdd9e47b069fb.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-7_hufc151146b4e45dacfbce1dad8c3d3e40_45032_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-7_hufc151146b4e45dacfbce1dad8c3d3e40_45032_b8bc500d93d8fa4bfd346b672143cfb0.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;下半场的第一个话题：云和应用该如何衔接？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-8_huaf9ee24b7a18bcef9915535e8f29a49d_233694_7362768d2b58865f6f2a9502bcd6677e.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-8_huaf9ee24b7a18bcef9915535e8f29a49d_233694_78bf76441f2c06b005cd1b1d93fba2cd.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-8_huaf9ee24b7a18bcef9915535e8f29a49d_233694_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-8_huaf9ee24b7a18bcef9915535e8f29a49d_233694_7362768d2b58865f6f2a9502bcd6677e.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-9_hu3b88d4dae8a5a4a3770e2566c713e549_256832_8d0c79a2adbe87216504ae02526196f9.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-9_hu3b88d4dae8a5a4a3770e2566c713e549_256832_fe0ab156562630a396ff5fab3048ba6a.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-9_hu3b88d4dae8a5a4a3770e2566c713e549_256832_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-9_hu3b88d4dae8a5a4a3770e2566c713e549_256832_8d0c79a2adbe87216504ae02526196f9.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;但是，这里需要先强调一下，云原生的演进过程，不仅仅需要云的努力，也需要应用作配合。否则，即便云已经可以提供各种能力，但是如果应用本身没有进行轻量化改造，未能使用云提供的能力，而是继续保持原有的非云原生的形态，那么效果就会大打折扣。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-10_hu3d4ba47d35856539ea6951d8a92299ed_36482_adea7c504ee02b1d62520898430aa756.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-10_hu3d4ba47d35856539ea6951d8a92299ed_36482_557e712b5659626243c3074bf83d6332.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-10_hu3d4ba47d35856539ea6951d8a92299ed_36482_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-10_hu3d4ba47d35856539ea6951d8a92299ed_36482_adea7c504ee02b1d62520898430aa756.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;回顾上半场的第一个话题“如何理解云原生”：应用原生被设计为在云上以最佳方式运行，充分发挥云的优势。这里强调的是，应用需要以原生形态来设计，以充分发挥云的优势。&lt;/p&gt;
&lt;p&gt;然后回到我们的话题，假设现在云已经准备妥当，各种能力都可以提供，而应用也按照云原生的理念设计，那当云原生应用部署在云上时，这些应用和云之间应该如何衔接？既可以让应用使用云提供的能力，又不至于侵入应用，破坏应用的云原生特性？简单说，就是要实现应用无感知。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-11_hu17a03d81bfbc39d109646e3805f9ddcf_111832_4f9cfb539ab7f2b99f1e134a2e590b5a.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-11_hu17a03d81bfbc39d109646e3805f9ddcf_111832_1d93f3bc7ada11fbf4689c7e69ec2744.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-11_hu17a03d81bfbc39d109646e3805f9ddcf_111832_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-11_hu17a03d81bfbc39d109646e3805f9ddcf_111832_4f9cfb539ab7f2b99f1e134a2e590b5a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-12_huee02c2f69ff8739cf3d9d1b1020fb309_50297_7eaa2c791326b478d64ce9b760ddab67.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-12_huee02c2f69ff8739cf3d9d1b1020fb309_50297_444fce916ac6da2526d9d5847c5bb748.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-12_huee02c2f69ff8739cf3d9d1b1020fb309_50297_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-12_huee02c2f69ff8739cf3d9d1b1020fb309_50297_7eaa2c791326b478d64ce9b760ddab67.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;流量透明劫持&lt;/strong&gt; 是我们目前比较认可的动态赋能方式之一，在上半场谈到 Service Mesh 模式的工作原理时，讲到当我们讲应用部署在 Service Mesh 中时，我们会在部署时动态的在应用所在的 pod 中插入 Sidecar 容器，然后在运行时，会以对用户透明的方式来改变应用的行为。典型如将应用发出的服务间远程调用的请求，改为转向本地部署的 Sidecar，从而引入 Service Mesh 能提供的各种能力。&lt;/p&gt;
&lt;p&gt;这个在运行时透明的改变远程调用请求的行为，我们称之为 “流量透明劫持”。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-13_hua76224148f1b2f8baf96739d85f11a10_88250_5a03067ab9677b7c0137dce93faa1033.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-13_hua76224148f1b2f8baf96739d85f11a10_88250_4440430a57e030862a7ed47c99757ce5.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-13_hua76224148f1b2f8baf96739d85f11a10_88250_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-13_hua76224148f1b2f8baf96739d85f11a10_88250_5a03067ab9677b7c0137dce93faa1033.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;透明劫持的部署模式如上图所示，右边图片是应用容器与 Sidecar 容器在k8s/Sigma中的部署模式，左边图片是单个 pod 的放大。其中绿色方块为应用容器，蓝色方块为Sidecar容器，蓝色线条表示服务间通讯。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-14_hu221b66c3ac7064a85ba03fd2cd7bff62_54523_3a158ef9b3e6a502e477b71539f8a9d3.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-14_hu221b66c3ac7064a85ba03fd2cd7bff62_54523_9ea4882186c1537786a0f0c1ced9b376.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-14_hu221b66c3ac7064a85ba03fd2cd7bff62_54523_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-14_hu221b66c3ac7064a85ba03fd2cd7bff62_54523_3a158ef9b3e6a502e477b71539f8a9d3.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;透明劫持的具体工作流程是这样，我们以 iptables 流量劫持方案为例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Init 流程(编号为0的两条紫色虚线)：在Pod启动时，通过Init Container特权容器，开启流量劫持并设置流量劫持规则（分为 Inbound 规则和 Outbound 规则）。注意这个流程时部署时进行，因为不是真实请求流量所以用的虚线表示。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inbound流程(左边编号为1,2,3的黄色实现)：Inbound请求，被 traffic interception 劫持，根据 Inbound规则请求被转发到Sidecar，然后Sidecar再转发给应用。这是用于劫持 Inbound流量，也就是外部访问当前应用的流量，使之在通过Sidecar再由Sidecar转发给应用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Outbound流程(右边编号为4,5,6的黑色实现)：应用发出的 Outbound 请求会被 traffic interception 劫持，根据 Outbound 规则请求被转发给 Sidecar，然后 Sidecar 处理之后将请求发送给目的地。这是用于劫持 Outbound 流量，也就是当前应用访问外部服务的流量，使之先通过Sidecar，然后由sidecar进行转发。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过上述三个流程，我们就实现了让应用的 Inbound 请求和 Outbound 请求在运行时改变行为方式，在应用无感知的情况下实现了将流量劫持到 Sidecar 中。然后我们在 Sidecar 中就有机会为当前请求赋予各种能力，典型如服务发现/负载均衡/实施各种路由策略/认证/加密等一系列能力，从而实现了对应用的动态赋能。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-15_hu523f447fb71ad38ed1e6d2e7ad403fcb_57904_d8381704b76ba4dea319aa9051383501.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-15_hu523f447fb71ad38ed1e6d2e7ad403fcb_57904_5ae5c4f10f9a0f5bf02ec3be062921e3.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-15_hu523f447fb71ad38ed1e6d2e7ad403fcb_57904_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-15_hu523f447fb71ad38ed1e6d2e7ad403fcb_57904_d8381704b76ba4dea319aa9051383501.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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;业务应用在开始时无需关注各种功能的实现细节和调用方式，也不需要依赖SDK，这些能力会在运行时动态赋予&lt;/li&gt;
&lt;li&gt;对于已有的应用，旧有代码可以无需改动就直接运行在service mesh上&lt;/li&gt;
&lt;li&gt;从而避免修改代码，和相关的重新打包发布上线等复杂流程&lt;/li&gt;
&lt;li&gt;另外透明劫持支持直连(不经过sidecar)/单跳(只经过一个Sidecar)/双跳(经过两个Sidecar)，方便开发调试，容易实现和现有系统的兼容&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;透明劫持近乎完美的实现了我们要求的目标：在运行时为应用 &lt;strong&gt;动态赋能&lt;/strong&gt;，应用无感知。&lt;/p&gt;
&lt;p&gt;另外透明劫持还有一个比较隐蔽但是又非常关键的优点：不丢失重要信息。这指的是在透明劫持模式下，请求的原始目标地址和端口信息(original_dest)得以保留，让应用可以工作在特定协议应该绑定的端口上，从而更符合12 factor中”Port Binding”的要求，关于这一点的细节，可以见最后的花絮部分。&lt;/p&gt;
&lt;p&gt;由于原始目标地址和端口信息(original_dest)得以保留，因此透明劫持容许服务在多个端口上绑定多个不同协议而Sidecar只需要一个端口就可以实现流量转发。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-18_hu6f5067fb5e2f2dd8dfcdfe8abdc50e49_39059_093472e20a57cf2e0ae67a9a68d3f4dc.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-18_hu6f5067fb5e2f2dd8dfcdfe8abdc50e49_39059_05c4a73dd05e1c88ba69391887baa56c.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-18_hu6f5067fb5e2f2dd8dfcdfe8abdc50e49_39059_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-18_hu6f5067fb5e2f2dd8dfcdfe8abdc50e49_39059_093472e20a57cf2e0ae67a9a68d3f4dc.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;流量透明劫持的重要使用场景之一就是实现平滑迁移，即从现有的体系向 service mesh 体系逐渐迁移。&lt;/p&gt;
&lt;p&gt;图中时典型的服务注册/服务发现机制：应用向注册中心注册，然后客户端在发起请求时通过服务发现获得目标服务的地址列表，再选择其中的某个地址发出请求。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-19_hu62353c947abcbe1885bf16fdb7cd7d78_44815_e06a2a234ec410d1de12b8ab4aa246d0.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-19_hu62353c947abcbe1885bf16fdb7cd7d78_44815_ebe17229e66c2a4ff8f6da90257b1e81.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-19_hu62353c947abcbe1885bf16fdb7cd7d78_44815_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-19_hu62353c947abcbe1885bf16fdb7cd7d78_44815_e06a2a234ec410d1de12b8ab4aa246d0.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;当我们将其中的一个应用 (如图中的 Servcie B) 迁移到 Service Mesh 中，此时会和 Service B 一起部署 Sidecar 并设置流量劫持的规则。当 Service B 作为服务器端接收客户端请求时的，原有请求 Service B 的流量就会被劫持到 Sidecar。此时 Service A 和 Service B 都对此无感知。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-20_hu0e5ce43ba108866f42ddd9acaedc7f04_41909_d0bb269e5c56169835f75d6c4eda87cc.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-20_hu0e5ce43ba108866f42ddd9acaedc7f04_41909_a170b78cc7b1c2eab5f8ae78664b5f5c.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-20_hu0e5ce43ba108866f42ddd9acaedc7f04_41909_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-20_hu0e5ce43ba108866f42ddd9acaedc7f04_41909_d0bb269e5c56169835f75d6c4eda87cc.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;当 Service B 作为客户端对外发起请求时，请求会被流量劫持到 Sidecar，然后 Sidecar 再转发请求。同样，图中的 Service B 和 Service C 对此也是没有感知。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-21_hu1dc58e2500e93be24c24c6f59706d10b_46279_d2990839a731e27913bf52ce3367aeda.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-21_hu1dc58e2500e93be24c24c6f59706d10b_46279_1ccc4665dd6f1391db7999245a3fcbbf.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-21_hu1dc58e2500e93be24c24c6f59706d10b_46279_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-21_hu1dc58e2500e93be24c24c6f59706d10b_46279_d2990839a731e27913bf52ce3367aeda.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;当客户端和服务器端的应用都迁移到 service mesh 之后，此时两端都部署有 Sidecar，请求会按照 service mesh 的标准方式在客户端和服务器端都做两次透明劫持进入Sidecar。依然，两端的服务对此无感知。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-22_hu841eda542f255d5db8278df933735a4a_83382_1c27f1ea3b32d4844e4c83e5e113dfeb.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-22_hu841eda542f255d5db8278df933735a4a_83382_66326c5f88448bc6a2a8488966c50f56.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-22_hu841eda542f255d5db8278df933735a4a_83382_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-22_hu841eda542f255d5db8278df933735a4a_83382_1c27f1ea3b32d4844e4c83e5e113dfeb.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;透明劫持对于现有系统的升级非常有帮助，主要体现在为升级带来的弹性。如图所示：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当客户端和服务器端都没有进行升级时，应用是直接连接的&lt;/li&gt;
&lt;li&gt;当客户端接入 service mesh 时，客户端会有改造，有Sidecar和透明劫持，因此客户端会有一次流量劫持，再往服务器端发送请求时，由于服务器端没有改造，因此服务器端是继续沿用原有方式直接连接。此时流量只经过一次 sidecar，我们称为“单跳”，客户端单跳。&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;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-23_hu5c73b0d98b8548c181743a623fa2d2e2_51799_4ac8194722054c5b0c3a2a63b27ffbb4.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-23_hu5c73b0d98b8548c181743a623fa2d2e2_51799_5f2a10ba42b23bdb4702dd7884b6b805.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-23_hu5c73b0d98b8548c181743a623fa2d2e2_51799_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-23_hu5c73b0d98b8548c181743a623fa2d2e2_51799_4ac8194722054c5b0c3a2a63b27ffbb4.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;前面我们详细介绍流量透明劫持这种动态赋能的方式，下面我们继续介绍另外一种常见的动态赋能方式，DNS。&lt;/p&gt;
&lt;p&gt;在上半场我们介绍 Service Mesh 的思路时，我们提到在让应用轻量化的过程中，最终在应用里面还是会有一个轻量级的客户端，里面保留有少数功能和信息。这其中就有“目标服务标识”这一项，用于标识当前请求要发送的目标服务。&lt;/p&gt;
&lt;p&gt;而在此时，有一个很常见的方式就是用域名来做标识符，从而让客户端可以发起一次 DNS 解析请求到 DNS 服务器。而我们可以通过各种方式在 DNS 服务器中预设 DNS 信息，比如最中间的方式就是和服务注册中心拉通，通过某种方式将服务注册信息中的服务域名和IP地址信息（典型如k8s中使用ClusterIP）导入到 DNS 服务器中。&lt;/p&gt;
&lt;p&gt;通过这样一个方式，就可以实现通过操作 DNS 记录来控制 DNS 解析的结果，从而实现特定目的。而将数据拉到到 DNS 服务器的方式可以有多种，域名和DNS记录信息的使用方式也可以有很多，配合流量透明劫持，Sidecar 也是可以获知这个请求的 DNS 解析结果…… 这里就有很多的想象空间了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-24_hu74146dfa498c4e0e3547ab32bcbf13c8_57920_918d0200f4f966e8dbd73230edf18de6.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-24_hu74146dfa498c4e0e3547ab32bcbf13c8_57920_9d0690f7932731cc3c53ab73832178b0.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-24_hu74146dfa498c4e0e3547ab32bcbf13c8_57920_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-24_hu74146dfa498c4e0e3547ab32bcbf13c8_57920_918d0200f4f966e8dbd73230edf18de6.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;具体 DNS 赋能的典型例子，在 SOFAMesh 项目中，为了兼容现有的单进程多接口的应用，而且容许客户端代码继续维持原有的用接口名而不是应用名来进行访问，我们就是利用了 DNS。&lt;/p&gt;
&lt;p&gt;如图，我们通过打通服务注册环节，在服务注册时获取到当前应用所提供的接口，然后将这些接口和应用的 ClusterIP 添加为 DNS 记录，使得这些接口名称对应的域名都指向 cluster ip。然后在请求过程中，客户端会通过接口名进行 DNS 解析，获取 cluster ip，接着以 cluster ip为目标地址发出请求，然后被透明流量劫持进Sidecar，sidecar 从请求的原始目标地址中获取到 cluster ip，就可以得到请求的目标服务，从而可以开始后面的各种流程。&lt;/p&gt;
&lt;p&gt;在这一过程中，我们组合使用了服务注册 + DNS信息同步 + 流量透明劫持 + Sidecar逻辑处理，比较好的实现了对旧有应用的兼容。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-25_hu85c6a7ab233b95f64e376c3c62621b71_118388_d32e162a9dbe44629304234873205240.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-25_hu85c6a7ab233b95f64e376c3c62621b71_118388_c9c1d6d2c6623794b2fa234f157ad3a3.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-25_hu85c6a7ab233b95f64e376c3c62621b71_118388_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-25_hu85c6a7ab233b95f64e376c3c62621b71_118388_d32e162a9dbe44629304234873205240.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在介绍动态赋能方式之后，我们再来继续看应用和云衔接的另外一个话题：在应用被赋予能力之后，应用该如何控制这些能力？&lt;/p&gt;
&lt;p&gt;控制的方式通常有两种：命令式和声明式。&lt;/p&gt;
&lt;p&gt;对于对于我们云原生的场景而言，有些微妙：这些能力时动态赋予应用的，应用根本无法直接控制这些能力的具体实现，而且从云原生的理念上可说，应用也不应该知道这些来自云的能力的具体实现方式，因此，在动态赋能的场景下，命令式是不合适。&lt;/p&gt;
&lt;p&gt;应用能为此做什么？应用肯定知道自己要达到的控制目标，即应用期待的目标状态。比如，应用可以要求说，当我访问某个服务时：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;要用轮询的负载均衡算法&lt;/li&gt;
&lt;li&gt;要10%的流量去v2版本，其他的去v1版本&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;p&gt;使用 声明式API 的好处在于：&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;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-28_hu9a7572219165a8de667b0a601d215403_39221_7f180bd08923fffb177b1e2cc5f71414.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-28_hu9a7572219165a8de667b0a601d215403_39221_dff3ca64c1900fc3ce1ab7195e6cc7d6.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-28_hu9a7572219165a8de667b0a601d215403_39221_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-28_hu9a7572219165a8de667b0a601d215403_39221_7f180bd08923fffb177b1e2cc5f71414.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;声明式API的哲学：把&lt;strong&gt;方便&lt;/strong&gt;留给别人，把&lt;strong&gt;麻烦&lt;/strong&gt;留给自己。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-29_hu00c583621df020cd8d59d619170bfe83_35735_f29bfe5337adf03f37f04493037a952a.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-29_hu00c583621df020cd8d59d619170bfe83_35735_b40e924af09863b17d802d6ff5493ef7.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-29_hu00c583621df020cd8d59d619170bfe83_35735_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-29_hu00c583621df020cd8d59d619170bfe83_35735_f29bfe5337adf03f37f04493037a952a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;关于云和应用如何衔接这个话题，目前我们能给出的方案还不多，远谈不上理想，期望能够在未来会找到有更多更好的做法。对此有兴趣的同学，非常欢迎一起探讨这个话题，如果有好的想法和方式，欢迎随时指教。&lt;/p&gt;
&lt;h2 id=&#34;如何让产品更符合云原生&#34;&gt;如何让产品更符合云原生？&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-30_huc20a9636784fb4c28062b250316c8497_46914_1d87a4323e66b2589d729e356659e49a.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-30_huc20a9636784fb4c28062b250316c8497_46914_b2504b5454906ded53fda19e703edb26.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-30_huc20a9636784fb4c28062b250316c8497_46914_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-30_huc20a9636784fb4c28062b250316c8497_46914_1d87a4323e66b2589d729e356659e49a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;下半场的第二个话题：如何让&lt;strong&gt;产品&lt;/strong&gt;更符合云原生？。&lt;/p&gt;
&lt;p&gt;注意这里要说的是产品，而不是应用。如何让应用更符合云原生有足够多的文章和理论了，但是如何提供一个产品，让这个产品为云原生应用提供服务和支持，然后要让这个产品本身更符合云原生，能找到的资料就不多了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-31_hu710aea4b74dd31f8fb50625b36658816_136662_b921466a78342f6106728f33f38b1031.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-31_hu710aea4b74dd31f8fb50625b36658816_136662_a037d30f65ea2fe6afd1f8cf493f33bd.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-31_hu710aea4b74dd31f8fb50625b36658816_136662_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-31_hu710aea4b74dd31f8fb50625b36658816_136662_b921466a78342f6106728f33f38b1031.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们先总结一下从前面内容中得到的一些规律：其核心在于，不仅提供功能，更强调体验：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在讨论云原生应用应该是一个什么样子时提出，云原生应用就应该是原生形态，轻量化：云应该让应用更&lt;strong&gt;舒服&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;在回顾云计算历史，探讨云的形态变化时，我们给出了中间这个图表：云应该让应用少做事&lt;/li&gt;
&lt;li&gt;刚刚探讨的声明式API的哲学，把&lt;strong&gt;方便&lt;/strong&gt;留给别人，把&lt;strong&gt;麻烦&lt;/strong&gt;留给自己：云应该让应用更方便。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那么，当我们在云上开发产品，试图将产品的能力融合进云，让云上应用可以自如的使用这些能力时，应该遵循什么样的方式？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-32_hu9d25b1ccc35d1fda98fadfda6e20651d_131229_fbeb3fdcd11016e1fd2dd75fce9634a1.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-32_hu9d25b1ccc35d1fda98fadfda6e20651d_131229_5e9806147717b4cc99ed8e46b5473d4e.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-32_hu9d25b1ccc35d1fda98fadfda6e20651d_131229_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-32_hu9d25b1ccc35d1fda98fadfda6e20651d_131229_fbeb3fdcd11016e1fd2dd75fce9634a1.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在这里，我们介绍一个云原生的飞轮理论，其创意由我们团队的 典韦 同学，参考了亚马逊的飞轮理论。&lt;/p&gt;
&lt;p&gt;亚马逊的飞轮理论相信大家都很熟悉，在这里亚马逊努力打造了两个飞轮，即闭环循环，通过“选品与便利”和“更低价格”实现了更好的“客户体验”。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-33_hu05aac58cabb1f8f1755cb89d47a86e7e_36978_6a5352d7d5f40501f2b73abf0a32bb5f.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-33_hu05aac58cabb1f8f1755cb89d47a86e7e_36978_72bd7f463e0327a8f72f10b80286fd7d.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-33_hu05aac58cabb1f8f1755cb89d47a86e7e_36978_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-33_hu05aac58cabb1f8f1755cb89d47a86e7e_36978_6a5352d7d5f40501f2b73abf0a32bb5f.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;详细介绍一下云原生的飞轮理论。首先，在云计算和云原生出现之前，下面的这个大循环其实就已经存在了。这个循环主要关注的是功能性方面的需求，提供商的产品主要通过提供功能来满足客户需求，当然不是说没有功能性之外的其他需求，只是在早期对非功能性的需求远没有今天这么多。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-34_hu2291d85d4790b403e301ec0f03500eb4_41911_85c296b7af5beff5df5bbac11e58f6f6.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-34_hu2291d85d4790b403e301ec0f03500eb4_41911_4c91cf4ebcbe3b5339ef61ccf58fb397.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-34_hu2291d85d4790b403e301ec0f03500eb4_41911_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-34_hu2291d85d4790b403e301ec0f03500eb4_41911_85c296b7af5beff5df5bbac11e58f6f6.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;进入互联网时代，尤其是移动互联网时代之后，这个大循环面临新的挑战，一方面在功能性方面要求越来越高：除了简单功能实现之外，还有对性能/安全/稳定性/高可用/可扩展性的诸多要求，而且越来越苛刻。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-35_hud4e1dcb40f4ec8a51d96c34b33848550_50408_d5854e8f25aaf21c75aa582a63a182c5.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-35_hud4e1dcb40f4ec8a51d96c34b33848550_50408_46ffcc6e1b98391c8ecaffe97c8f25bb.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-35_hud4e1dcb40f4ec8a51d96c34b33848550_50408_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-35_hud4e1dcb40f4ec8a51d96c34b33848550_50408_d5854e8f25aaf21c75aa582a63a182c5.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;另一个方面，在功能性之外，更多的需求来自对效率的追求：包括开发、测试、部署、维护、变更的效率，以及对成本的要求。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-36_hu6c6a95250afffea30f757dd69bca4d08_62813_b65bd80118a022409d2628e06d1f22f8.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-36_hu6c6a95250afffea30f757dd69bca4d08_62813_f72b694f7aebb7a8acdb00ad14cbd5ea.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-36_hu6c6a95250afffea30f757dd69bca4d08_62813_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-36_hu6c6a95250afffea30f757dd69bca4d08_62813_b65bd80118a022409d2628e06d1f22f8.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对效率的追求，推动了云计算的产生和发展，以及云原生理念和架构的产生，我们熟知的容器技术，微服务架构，以及新生的 Service Mesh 架构都由此诞生，不可变基础设施和声明式API 的理念也在实践中被总结出来，并为后续的云原生架构提供理论指导。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-37_hu60ce08251dc198642f86fd8322408e21_68319_e3afbbdf9a5e0206180a8318b32f8237.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-37_hu60ce08251dc198642f86fd8322408e21_68319_4d58a3e228121dbc93ebf8551d3f356d.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-37_hu60ce08251dc198642f86fd8322408e21_68319_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-37_hu60ce08251dc198642f86fd8322408e21_68319_e3afbbdf9a5e0206180a8318b32f8237.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;云计算的发展，云原生的推出，为云和云上产品带来了功能性之外的一个重要特征：易用性。体现在有了云的支撑之后，云上应用可以简单开发，开发人员容易上手，由于大部分维护工作由云承担，因此降低了客户的维护工作量（甚至 serverless 提出了无维护的理念）。这些产品使用简单，对客户心智要求低，无需客户具体相关的专业知识。&lt;/p&gt;
&lt;p&gt;其核心在于分离关注点：客户和客户应用应该关注与业务实现，而非业务实现的内容应该由云和云上产品提供。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-38_hu285bbb96108eb48c0b4752f3f66be489_75328_db22e7795990baee3a1317c589b509a0.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-38_hu285bbb96108eb48c0b4752f3f66be489_75328_74aeabb988edd647f12d72e00a449172.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-38_hu285bbb96108eb48c0b4752f3f66be489_75328_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-38_hu285bbb96108eb48c0b4752f3f66be489_75328_db22e7795990baee3a1317c589b509a0.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而易用性的飞跃，在满足各种功能性的前提下，不仅仅满足了客户需求，也极大的改善了开发体验。在开发、测试、部署、维护、变更等环节的效率提升，也帮助用户控制了成本。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-39_hua98bdd33b96c808dc45a55424fd3f686_37871_9e57c0e23e79ef6edd1c2b282a717e97.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-39_hua98bdd33b96c808dc45a55424fd3f686_37871_60e1195bbcc62dbeffb4c0d4f1f6fb7c.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-39_hua98bdd33b96c808dc45a55424fd3f686_37871_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-39_hua98bdd33b96c808dc45a55424fd3f686_37871_9e57c0e23e79ef6edd1c2b282a717e97.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这样，围绕易用性，新的闭环循环产生：对效率的追求，催生了云和云原生架构，带来了易用性的提升，改善了开发体验，从而进一步提供了效率。这个环形的过程会持续发生，云原生架构就会沿着这个飞轮循环不断的发展演进。在过去几年间，这个飞轮循环已经在运转，云原生架构中的容器/微服务等架构都是在这个循环中不断完善和普及。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-40_hu1aa52c8272ba10da7b7cdf2a849de095_54207_fbdaef13e852ba6932db7b4192452b8d.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-40_hu1aa52c8272ba10da7b7cdf2a849de095_54207_d469dff65ad22e20b25572e02bb5071c.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-40_hu1aa52c8272ba10da7b7cdf2a849de095_54207_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-40_hu1aa52c8272ba10da7b7cdf2a849de095_54207_fbdaef13e852ba6932db7b4192452b8d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是完整的云原生架构飞轮理论，两个飞轮分别关注功能性和易用性，两者结合来满足客户需求，改善开发体验，最终实现云原生架构的良性循环。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-41-1_hu3ac7d7759950e6bd36d14228892b62b6_39132_a44ced005b95af10b7b02a71f85e8120.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-41-1_hu3ac7d7759950e6bd36d14228892b62b6_39132_ae1b99ec234d27a0f7165b5029995065.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-41-1_hu3ac7d7759950e6bd36d14228892b62b6_39132_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-41-1_hu3ac7d7759950e6bd36d14228892b62b6_39132_a44ced005b95af10b7b02a71f85e8120.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;为了更好的理解云原生的飞轮理论，我们以云计算中至关重要的虚拟化技术为例，看看这二十年间以虚拟化技术为基础，云和云原生架构是如何一步一步演进和发展的。&lt;/p&gt;
&lt;p&gt;首先，在物理机时代，在虚拟化技术出来之前，提供商只能提供服务器托管/服务器租用以及基于web服务器的虚拟主机服务，此时云还不存在。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-41-2_hu2a483f893f70f3bdd1871ea8a6b7b465_58216_3cb5470e8856a62ffe7825eb09ad2f94.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-41-2_hu2a483f893f70f3bdd1871ea8a6b7b465_58216_07e333541b6c6eecf3c06069fc661033.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-41-2_hu2a483f893f70f3bdd1871ea8a6b7b465_58216_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-41-2_hu2a483f893f70f3bdd1871ea8a6b7b465_58216_3cb5470e8856a62ffe7825eb09ad2f94.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在2000年前后，出于对资源利用率的追求，在虚拟机技术成熟之后，基于虚拟机技术首先诞生了VPS，然后陆续出现了大家熟悉的VMWare/Xen/KVM/VirtalBox等技术和产品，云计算开始出现。&lt;/p&gt;
&lt;p&gt;之后围绕易用性，先是amazon推出s3和EC2，IaaS出现；后面HeroKu推出了 PaaS。此时云已经走向成熟，而云原生架构也出现了早期形态，比如HeroKu提出的12 factor 应用，DevOps的流行。后面陆续出现了其他Xaas形态：SaaS/FaaS等。&lt;/p&gt;
&lt;p&gt;此时的开发体验和物理机时代相比已经有质的飞跃。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-41-3_hu0d8faaa5fa5a1ee3bcf8ab39a4e41b8f_60104_e487c7e98d41784811c6ceabaae3f7db.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-41-3_hu0d8faaa5fa5a1ee3bcf8ab39a4e41b8f_60104_d099c8e92cd66d075bb3277066494970.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-41-3_hu0d8faaa5fa5a1ee3bcf8ab39a4e41b8f_60104_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-41-3_hu0d8faaa5fa5a1ee3bcf8ab39a4e41b8f_60104_e487c7e98d41784811c6ceabaae3f7db.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;2013年前后，以docker为标志的容器技术开始成熟，催生了容器编排、不可变基础设施等技术和理念。而容器这种轻量化虚拟计划的出现也极大的促进了微服务架构等的演进，2015年前后，云原生架构被正式提出。而之前基于虚拟机技术的XaaS也开始向容器化方向转变。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-41-4_huaf0b506c71d41c782cd46bd84d6c8b06_59312_872d6ddd1e31f0a6e29dbd573b4ccf7c.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-41-4_huaf0b506c71d41c782cd46bd84d6c8b06_59312_84986754cd80fa222edaefa0308af993.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-41-4_huaf0b506c71d41c782cd46bd84d6c8b06_59312_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-41-4_huaf0b506c71d41c782cd46bd84d6c8b06_59312_872d6ddd1e31f0a6e29dbd573b4ccf7c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;随着 kubernetes 完成了对容器编排市场的统一，云和云原生架构进入kubernetes时代，虽然底层虚拟化技术依然是虚拟机和容器，但是上层的XaaS形态已经开始陆陆续续开始向k8s转型。此时k8s奉行的声明式API等理念也成为云原生架构的指导思想之一。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-41-5_hu758619f256c24445580e5596180e2ba9_62070_8e0713f20d3f93fa97a228ba588c0465.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-41-5_hu758619f256c24445580e5596180e2ba9_62070_9c7646602794f34dd0dc25ed754a0ed0.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-41-5_hu758619f256c24445580e5596180e2ba9_62070_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-41-5_hu758619f256c24445580e5596180e2ba9_62070_8e0713f20d3f93fa97a228ba588c0465.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最近安全容器技术发展迅速，预期未来一旦技术成熟，很可能会带来新一轮的变革，未来的云和XaaS会可能会转为基于安全容器，也许还会有新的未知的形态出现，值得期待。&lt;/p&gt;
&lt;p&gt;从上述演进过程可以看到，随着虚拟化技术的一步一步演进，飞轮的一次一次循环，云开始诞生，XaaS形态开始出现，各种技术和理念相继诞生并日益完善，云原生架构出现并开始成熟，新的理念和架构出现/实践/改进，整个云原生架构就这样在一次一次的飞轮循环中走向成熟。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-45_huea52c5176faf023495fa88f2e0b22391_72209_a9927f4fd60aefeec3aee28c632982f9.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-45_huea52c5176faf023495fa88f2e0b22391_72209_a5d4214747c21329c5b6dcf8ba73c2c2.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-45_huea52c5176faf023495fa88f2e0b22391_72209_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-45_huea52c5176faf023495fa88f2e0b22391_72209_a9927f4fd60aefeec3aee28c632982f9.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;以云原生飞轮理论为基础和指导，分享一些我们团队在设计云原生产品的一点点心得：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首先，在关注功能/性能之外，应该更多的关注易用性，关注开发者的体验，要将应用和应用开发者当成bady来呵护，努力让产品的使用者可以更舒适更简单的使用产品&lt;/li&gt;
&lt;li&gt;产品应该依托云原生架构，具体说，就是应该基于云，基于容器，基于kubernetes。其核心观点在于，要让产品表现的更符合云原生，产品本身就应该是云原生的。&lt;/li&gt;
&lt;li&gt;顺势而为，要顺着飞轮的方向，迎合云原生的理念，迎合社区的发展方向。不要逆势而为，不要试图挑战整个社区。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-46_hu853d78fbe472db512434713f482b1834_50595_afcb72137e7308d33077d0394f9ba626.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-46_hu853d78fbe472db512434713f482b1834_50595_f8cff24b82bae90bfc15e61d6e06f65a.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-46_hu853d78fbe472db512434713f482b1834_50595_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-46_hu853d78fbe472db512434713f482b1834_50595_afcb72137e7308d33077d0394f9ba626.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Kubernetes 是云原生的关键所在，怎么强调都不为过。这里有一个被越来越多人认可的说法：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Kubernetes是云原生时代的Linux&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对这句话，我们有两个认识，在这里分享一下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;应该以 kubernetes 为底座进行能力建设：简单说就是如果是 kubernetes 已有的能力则直接使用，如果 k8s 的能力不足，则在 kubernetes 上做改进和争强，充分利用k8s的能力，而不是选择无视。&lt;/li&gt;
&lt;li&gt;把kubernetes当kubernetes用：即要符合 kubernetes 的理念和设计，遵循kubernetes的游戏规则&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;谈到遵循kubernetes的游戏规则，我们深入一下，核心在于遵循kubernetes的 CRD + Controller 模型：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果k8s底座的能力不够：则应该去补充和加强k8s的能力，体现为实现新的Controller&lt;/li&gt;
&lt;li&gt;如果k8s的抽象不够：比如说对于某些复杂场景，现有CRD不适用或不够用，则应该定义新的抽象，体现为添加新的CRD&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两者结合起来，加固k8s底座（Controller）+ 扩展k8s抽象（CRD），就可以得到新的云原生基础设施。&lt;/p&gt;
&lt;p&gt;另外，重要的事情说三遍：声明式API，声明式API，声明式API！&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-48_hudce404ce97f622d7cf534c696baf66f3_58872_020dfcd64d70c241e5a9f06eca76ad77.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-48_hudce404ce97f622d7cf534c696baf66f3_58872_81080929b1e32b8bb12f9f538014ca27.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-48_hudce404ce97f622d7cf534c696baf66f3_58872_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-48_hudce404ce97f622d7cf534c696baf66f3_58872_020dfcd64d70c241e5a9f06eca76ad77.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;举几个用 CRD 做扩展的例子，典型如 Istio。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-49_hua8bc97cf61871c96722946d9e3ea07f2_90770_b1c8a807ede90949d92ae369b31e3b1d.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-49_hua8bc97cf61871c96722946d9e3ea07f2_90770_e33710802569e095e989ea1c46b5515c.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-49_hua8bc97cf61871c96722946d9e3ea07f2_90770_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-49_hua8bc97cf61871c96722946d9e3ea07f2_90770_b1c8a807ede90949d92ae369b31e3b1d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;还有 Google 新推出的 serverless 项目 knative。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-50_hu70640a23d5fffdb2e21aa7551b426aab_58627_47c94519cddd9106ab1644d204bb6f12.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-50_hu70640a23d5fffdb2e21aa7551b426aab_58627_cc465b15cf82490e48f05b35d4ec815c.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-50_hu70640a23d5fffdb2e21aa7551b426aab_58627_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-50_hu70640a23d5fffdb2e21aa7551b426aab_58627_47c94519cddd9106ab1644d204bb6f12.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在通过以 加固k8s底座（Controller）+ 扩展k8s抽象（CRD）的方式打造新的云原生基础设施后，再在这些云原生基础设施的基础上，生长新的云原生产品。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-51_hud4f79c2f4680a4586871f69c7325c1e5_55728_be0916efc8508e0482b89d2383720fc6.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-51_hud4f79c2f4680a4586871f69c7325c1e5_55728_547eeae37f1a155ce4fe25e06f37b0ab.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-51_hud4f79c2f4680a4586871f69c7325c1e5_55728_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-51_hud4f79c2f4680a4586871f69c7325c1e5_55728_be0916efc8508e0482b89d2383720fc6.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里给出一个利用k8s能力的例子：Knative的 Autoscaler 的实现。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-52_hu3c1707685a7c1985d2fd594d4d89656e_55376_abcf272489c1d224af97efbc37a49ce6.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-52_hu3c1707685a7c1985d2fd594d4d89656e_55376_f6954a41c03ca1c43ddd189eaff8990e.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-52_hu3c1707685a7c1985d2fd594d4d89656e_55376_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-52_hu3c1707685a7c1985d2fd594d4d89656e_55376_abcf272489c1d224af97efbc37a49ce6.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;尽量遵循标准，尽量和社区一起玩：一方面可以从社区借力，跟随社区一起成长；另一方面，在产品对外输出时也容易被社区接受。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-53_hud1782c294df7a1fefc334710c41ee93c_54889_64774857296ecec583f439202e46d8ab.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-53_hud1782c294df7a1fefc334710c41ee93c_54889_010035da6f046e8f013b02be90f7d198.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-53_hud1782c294df7a1fefc334710c41ee93c_54889_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-53_hud1782c294df7a1fefc334710c41ee93c_54889_64774857296ecec583f439202e46d8ab.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最后再次强调一点：尽量不要逆势而为，尽量顺着云原生飞轮转动的方向。&lt;/p&gt;
&lt;p&gt;小结：&lt;/p&gt;
&lt;p&gt;关于如何让产品更符合云原生这个话题，我们这次只带来了一些比较基础的想法，由于在云原生这个领域我们也还处于摸索阶段，所以目前的看法和想法可能都还不够成熟。而且，更具体更深入的建议应该结合实际产品讲，但是本次分享中不太适合再进一步深入展开了，希望后面会有机会。&lt;/p&gt;
&lt;p&gt;此外，受工作范围限制，我们专注的领域偏中间件和服务间通讯，对于其他产品领域，期望后续有其他同学带来更深入分享。这也是我们本次分享的重要目的：抛砖引玉。&lt;/p&gt;
&lt;h2 id=&#34;花絮有哪些有趣的角色转变&#34;&gt;花絮：有哪些有趣的角色转变？&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-55_huca548eaa1b7c130afa1539e38952de18_49371_cb242ea6fcf3d074b681f3ff7e30bba3.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-55_huca548eaa1b7c130afa1539e38952de18_49371_742de82132e63fca8f73be00a3c74f2a.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-55_huca548eaa1b7c130afa1539e38952de18_49371_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-55_huca548eaa1b7c130afa1539e38952de18_49371_cb242ea6fcf3d074b681f3ff7e30bba3.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在本次分享的最后是花絮内容，我们轻松一下，来看看在云原生的演进过程中，有哪些有趣的角色转变？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-56_hu8db87957f31ac5cf5e4ea157fd0b18e2_500629_b0ded6d113bfa80f8883d7df2bfb89e5.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-56_hu8db87957f31ac5cf5e4ea157fd0b18e2_500629_fe5dbd56a5927a001bbd760e612f08fd.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-56_hu8db87957f31ac5cf5e4ea157fd0b18e2_500629_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-56_hu8db87957f31ac5cf5e4ea157fd0b18e2_500629_b0ded6d113bfa80f8883d7df2bfb89e5.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里所说的角色，指的是一个云计算中的口头禅或者说典故，通常在英文资料中经常看到：Pets VS. Cattle。&lt;/p&gt;
&lt;p&gt;宠物或者奶牛，为了表述的更形象一些，我喜欢翻译为宠物或者牲口。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-57_hu7908230dfb4c80c3ffe082651123d2af_492498_4a739598e8d1233104cc98baeb53f6a7.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-57_hu7908230dfb4c80c3ffe082651123d2af_492498_d07fbfa8d8815dc6a67d0c2b25c5a544.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-57_hu7908230dfb4c80c3ffe082651123d2af_492498_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-57_hu7908230dfb4c80c3ffe082651123d2af_492498_4a739598e8d1233104cc98baeb53f6a7.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里有个问题：在云原生时代，有哪些概念发生了角色转变？大家有兴趣可以试试回答一下。&lt;/p&gt;
&lt;p&gt;我这里给出两个回答，一个是IP 地址，从宠物到牲口；另一个是 端口/port，从牲口到宠物。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-58_hu1fdca34d48a47f0efee13665993205b5_75841_b6fa68cae9005391fe948f487c8b128c.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-58_hu1fdca34d48a47f0efee13665993205b5_75841_fe3c9cdf84964f7cf67992505da1118e.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-58_hu1fdca34d48a47f0efee13665993205b5_75841_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-58_hu1fdca34d48a47f0efee13665993205b5_75841_b6fa68cae9005391fe948f487c8b128c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;IP 地址在云原生时代，从宠物到牲口，基本大家都比较认可了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-59_hu65ba1ff54e3595349643a31ab28dac7e_86889_7a2e8a338bb83ca64db98acc45fcb6fc.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-59_hu65ba1ff54e3595349643a31ab28dac7e_86889_c37a1bdd6c14dca58595b478e5599a22.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-59_hu65ba1ff54e3595349643a31ab28dac7e_86889_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-59_hu65ba1ff54e3595349643a31ab28dac7e_86889_7a2e8a338bb83ca64db98acc45fcb6fc.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而端口/port，从云原生之前的牲口，转变为云原生之后的宠物，则还存在比较大的争议。这里列出当牲口和当宠物的两个不同的端口使用方式。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-60_hu230ebb773d292f244ea3a8931e1d0864_73008_d93f474d99a445a23c4142e43353aa84.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-60_hu230ebb773d292f244ea3a8931e1d0864_73008_5a5a5ab144c838ac3e6f9028b1eaa12d.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-60_hu230ebb773d292f244ea3a8931e1d0864_73008_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-60_hu230ebb773d292f244ea3a8931e1d0864_73008_d93f474d99a445a23c4142e43353aa84.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;视端口为宠物的一个重要理论依据，来自 12 Factor 中的 Port Binding原则。实践中很多产品，包括 Envoy / Istio 等都遵循这一原则。在我们的SOFAMesh产品中，我们也同样遵循这一原则。&lt;/p&gt;
&lt;p&gt;当然这个花絮的主要目的，还是希望可以借这个话题，让大家有个心理准备：在云原生之后，可能会有些之前理所当然的理念会发生变化。因此，请保持良好的心态 :)&lt;/p&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201902-cloudnative-freely-talk2/images/ppt2-61_hu1d38ef43ef074975e65aee597778c626_673888_50c28e90fc26c957ee456b4170909b27.webp 400w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-61_hu1d38ef43ef074975e65aee597778c626_673888_aa5533855704d3bbdd7e0b12b8113b42.webp 760w,
               /talk/201902-cloudnative-freely-talk2/images/ppt2-61_hu1d38ef43ef074975e65aee597778c626_673888_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201902-cloudnative-freely-talk2/images/ppt2-61_hu1d38ef43ef074975e65aee597778c626_673888_50c28e90fc26c957ee456b4170909b27.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在最后，再一次强调，这次云原生分享是希望起到一个抛砖引玉的作用，期待后面会有更多同学出来就云原生这个话题进行更多的分享和讨论。我们团队目前在云原生这条全新的道路上努力的探索，但是云原生应该如何进行，这是一个非常大的话题，希望有更多的人一起来参与，一起来讨论，一起来交流。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Service Mesh2018年度总结</title>
      <link>https://skyao.net/publication/201902-service-mesh-2018-summary/</link>
      <pubDate>Wed, 20 Feb 2019 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/publication/201902-service-mesh-2018-summary/</guid>
      <description>&lt;p&gt;作者: 敖小剑、崔秀龙、单家骏、宋净超、田晓亮、徐蓓、张超盟&lt;/p&gt;
&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;在2017年年底，在Service Mesh刚刚兴起之时，应InfoQ的邀请撰写过一篇名为 &lt;a href=&#34;https://skyao.net/publication/201801-service-mesh-2017-summary/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;Service Mesh年度总结：群雄逐鹿烽烟起&amp;rdquo;&lt;/a&gt; 的文章，对2017年Service Mesh的发展做了一次年度回顾。当时正是Service Mesh技术方兴未艾，各家产品你争我夺之时，一片欣欣向荣的气象。&lt;/p&gt;
&lt;p&gt;时隔一年，江湖风云变幻。再次有幸收到InfoQ的邀请，继续进行Service Mesh 2018年的年度总结。本次年度总结将由来自聚集国内ServiceMesh爱好者的 &lt;a href=&#34;http://www.servicemesher.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;ServiceMesher 社区&lt;/a&gt; 的多位嘉宾共襄盛举，希望能为 Service Mesh 2018年的发展做一个系统而全面的总结。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：为了不重复去年年度总结的内容，我们将直接从2018年初开始本次年度总结，如果您想了解 service mesh 在2018年前的发展历程，请先参阅2017年年度总结。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;为了更有成效的完成总结，我们将以问答的方式来让下文中陆续出场的各个Service Mesh产品和解决方案提供自己的答案，问题很简单：&lt;strong&gt;在2018年，做了什么？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;考虑到在2018年，Service Mesh在国内大热，有多家公司推出自己的Service Mesh产品和方案，因此本次Servicemesh 2018 年度总结我们将分为国际篇和国内篇。&lt;/p&gt;
&lt;h2 id=&#34;国际篇&#34;&gt;国际篇&lt;/h2&gt;
&lt;p&gt;2018年，Service Mesh市场的主要竞争者还是2017年底的出场的几位重量级选手：Linkerd、Envoy、Istio、Conduit等。&lt;/p&gt;
&lt;h3 id=&#34;istio&#34;&gt;Istio&lt;/h3&gt;
&lt;p&gt;首先来看 Istio，这是 Service Mesh 市场当之无愧的头号网红。&lt;/p&gt;
&lt;p&gt;2018年对于Istio来说是蓄势待发的一年，这一年Istio接连发布了 0.5、0.6、0.7、0.8 和 1.0 版本。&lt;/p&gt;
&lt;p&gt;到2018年7月31日 1.0 GA 时，Istio其实已经陆续开发了近两年。1.0版本对Istio来说是一个重要的里程碑，官方宣称所有的核心功能现在都可以用于生产。1.0版本的到来也意味着其基本架构和API逐渐稳定，那些锐意创新的企业可以开始试用。&lt;/p&gt;
&lt;p&gt;我们以GitHub上的star数量的角度来看一下 Istio 在2018年的受欢迎程度，下图显示的是Istio的GitHub star数量随时间变化曲线。可以看到在2018年，Istio 的star数量增长了大概一万颗，目前已经接近15000颗星，其增长趋势非常平稳。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://starcharts.herokuapp.com/istio/istio&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;https://starcharts.herokuapp.com/istio/istio.svg&#34; alt=&#34;Stargazers over time&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;我们来按照时间顺序回顾一下2018年Istio的几个重要版本的发布情况，以便对Istio这个目前最受关注的Service Mesh项目在2018年的发展有深入了解：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2018年1月31日，Istio发布0.5.0版本：支持Sidecar自动注入（需要 Kubernetes 1.9及以上版本），加强RBAC支持，尝试修改通信规则。&lt;/li&gt;
&lt;li&gt;2018年3月1日，Istio发布0.6.0版本：支持发送自定义Envoy配置给Proxy，支持基于Redis的速率限制，容许为检查和报告分别设置Mixer集群，提供正式的存活以及就绪检测功能。&lt;/li&gt;
&lt;li&gt;2018年3月29日，Istio发布0.7.0版本：只包含问题修复和性能提升，没有新的功能。初步支持 v1alpha3 版本的流量管理功能。&lt;/li&gt;
&lt;li&gt;2018年6月1日，&lt;strong&gt;Istio发布0.8.0版本&lt;/strong&gt;：在之前三个平淡无奇的小版本发布之后，Istio 迎来了2018年第一个重大版本0.8.0，这也是 Istio 第一个LTS（长期支持）版本，这个版本带来了大量的更新，架构方面也做了很多改进，主要有：v1alpha3 版本的流量管理功能就绪；缺省使用 Envoy 的 ADS API 进行配置发送；新增 Istio Gateway模型，不再支持Kubernetes Ingress；支持Helm 安装；支持按需安装Mixer和Citadel模块。另外原有的 API 都经过了重构，CRD 的名字全部更改。&lt;/li&gt;
&lt;li&gt;2018年7月31日，&lt;strong&gt;Istio发布1.0.0版本&lt;/strong&gt;：这是社区期待已久的版本，也是 Istio 的重要里程碑。不过相对0.8.0版本，主要是修复错误和提高性能，新功能不多。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;进入2018年下半年之后，Istio的开发进度明显放缓，1.1版本的发布多次推迟，直到2018年结束也未能发布（备注：直到本文截稿日的2019年2月10日，Istio最新的版本是1.1-snapshot5）。在1.0版本发布之后的6个月时间，Istio只是以平均每个月一个Patch版本的方式陆续发布了1.0.1到1.0.5总共5个Patch版本，这些Patch版本都只有错误修复和性能改善，未带来新的特性。&lt;/p&gt;
&lt;p&gt;简单总结 Istio 2018年的发布情况：Istio在上半年通过0.5.0/0.6.0/0.7.0三个小版本陆续进行了小改，在0.8.0版本中进行了唯一一次大改，然后年中发布了2018年最重要的里程碑1.0.0版本，接着是长达6个月的修整期，最后带着迟迟未能发布1.1版本的小遗憾平淡的结束2018年。&lt;/p&gt;
&lt;p&gt;与产品演进和版本发布的平淡相比，Istio在市场和社区的接受程度方面表现非常火爆，成为2018年最热门的项目之一，也在各种技术会议上成为备受关注的技术新星。尤其在 Kubernetes社区，更是被视为有望继Kubernetes成功之后的下一个现象级产品。&lt;/p&gt;
&lt;p&gt;目前各主流云平台也纷纷提供对Istio的支持：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;NetApp：2018年9月17日宣布收购成立仅3年的云原生创业公司&lt;a href=&#34;https://stackpoint.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Stackpoint&lt;/a&gt;，Stackpoint Cloud 支持创建和管理安全、多云、多region的Istio Service Mesh。&lt;/li&gt;
&lt;li&gt;GKE：作为Istio的主要推动力量，Google自然不遗余力的支持Istio。在2018年7月Istio 1.0发布之后，Google Kubernetes Engine就提供了对Istio的支持。&lt;/li&gt;
&lt;li&gt;IBM Cloud Kubernetes Service：Istio作为一个开源项目，IBM主要关注流量路由、版本控制和A/B测试方面，Google专注于安全和遥测（来自&lt;a href=&#34;http://www.servicemesher.com/blog/istio-aims-to-be-the-mesh-plumbing-for-containerized-microservices/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;IBM云计算CTO讲述Istio项目的起源、分工及目标&lt;/a&gt;），IBM Cloud 于 2018 年中已提供 Istio 试用。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://maistra.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Maistra&lt;/a&gt;：2018年9月，Red Hat的OpenShift Service Mesh技术预览版上线，基于Istio。Red Hat是Istio项目的早期采用者和贡献者，希望将Istio正式成为OpenShift平台的一部分。Red Hat为OpenShift上的Istio开始了一个技术预览计划，为现有的OpenShift Container Platform客户提供在其OpenShift集群上部署和使用Istio平台的能力，为此Red Hat创建了一个名为Maistra的社区项目。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在市场一片红红火火之时，我们不得不指出，到2018年底，Istio 依然在几个关键领域上未能给出足够令人满意的答案，典型如性能、稳定性，Istio 的 1.0 版本并不是一个有足够生产强度的稳定版本。Istio 在2018年交出的答案，对于对Istio抱有非常大期待的 Service Mesh 社区来说，是远远不够的。这直接导致 Istio 目前在生产落地上陷入尴尬境地：虽然试水 Istio 的公司非常多，但是真正大规模的实践很少。&lt;/p&gt;
&lt;p&gt;Istio 的2018年年度总结：如期发布了1.0版本，顺利完成了市场布局，扩大了己方阵营，压制了所有竞争对手。&lt;/p&gt;
&lt;p&gt;2018年的 Istio 的表现不可谓不成功，但是离社区的期待依然有非常大的距离：关键在于未能真正实现大规模普及。如何打破这一叫好不叫座的僵局，实现真正意义上的生产落地，证明自己，将会是 Istio 2019年面临的最大挑战。&lt;/p&gt;
&lt;h3 id=&#34;envoy&#34;&gt;Envoy&lt;/h3&gt;
&lt;p&gt;相比网红 Istio 在社区的红红火火和产品发布的疲软，另一位重量级选手 Envoy 则是完全不同的表现风格：低调，务实，稳扎稳打，堪称实力派。&lt;/p&gt;
&lt;p&gt;在2017年的总结中，我们称Envoy为&amp;quot;波澜不惊的Envoy&amp;quot;，以下这段内容援引自2017年的年度总结：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;在功能方面，由于定位在数据平面，因此Envoy无需考虑太多，很多工作在Istio的控制平面完成就好，Envoy从此专心于将数据平面做好，完善各种细节。在市场方面，Envoy和Linkerd性质不同，不存在生存和发展的战略选择，也没有正面对抗生死大敌的巨大压力。Envoy在2017年有条不紊地陆续发布了1.2、1.3、1.4和1.5版本，稳步地完善自身，表现非常稳健。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在2018年，Envoy也是同样的波澜不惊，上面这段总结几乎可以一字不变的继续在2018年沿用：只要简单的将版本号变成1.6.0、1.7.0、1.8.0和1.9.0即可。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://starcharts.herokuapp.com/istio/istio&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;https://starcharts.herokuapp.com/envoyproxy/envoy.svg&#34; alt=&#34;Stargazers over time&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;这是Envoy Github Star的情况。总数7800（只有Istio的一半），其中2018年大致增加了5000个Star，而且增长趋势异常的平稳。&lt;/p&gt;
&lt;p&gt;我们再来细看一下2018年Envoy的版本发布情况，这次我们换个特别的角度，关注一个细节：Envoy每次版本发布时，都会在Release Note中列出本版本包含的变更列表，非常细致，所以很长很长，每次都是三四页的样子。我们同时简单计算了一下每次发布包含的commit数量，整体情况如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2018年5月20日，Envoy发布1.6.0版本：包含392个commit，Release Note 长达四页&lt;/li&gt;
&lt;li&gt;2018年6月21日，Envoy发布1.7.0版本：包含468个commit，Release Note 长达四页。这个版本是配套Istio 1.0版本作为 Production Ready 的 Service mesh 解决方案。全面支持RBAC鉴权模型, TLS&amp;amp;JWT加密，网络通信安全性有极大提升。&lt;/li&gt;
&lt;li&gt;2018年10月4日，Envoy发布1.8.0版本：包含425个commit，Release Note 长达三页&lt;/li&gt;
&lt;li&gt;2018年12月21日，Envoy发布1.9.0版本：包含414个commit，Release Note 长达三页&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果有兴趣去浏览Envoy在这几次版本发布时的Release Note，就可以发现Envoy在2018年中数量惊人的各种细微改进。我们也可以简单计算一下，Envoy全年四个版本大概1800次commit，考虑到Envoy在2018年并没有大规模的架构改动和特别大的新特性支持，这些commit基本都是各种完善、改进和补充。不得不惊叹于Envoy在这种细致之处刻意打磨的精神，毕竟&amp;quot;细节才是魔鬼&amp;quot;。&lt;/p&gt;
&lt;p&gt;Envoy的稳健和成熟，在2018年带来了丰硕成果：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;被越来越多企业使用，不仅仅稳稳占据Istio官配Sidecar的位置，而且在网络代理、负载均衡器、网关等领域开始占据传统产品的领地，如nginx、kong。&lt;/li&gt;
&lt;li&gt;被 Istio 之外的多个公司的 Service Mesh 框架项目采用，如AWS的App Mesh, F5的Aspen Mesh, 微软的 Service Frabric Mesh，国内包括腾讯Tecent Service Mesh，阿里的Dubbo Mesh。&lt;strong&gt;Envoy明显有成为 Service Mesh 的数据平面标准的趋势&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;Envoy的xDS API，已经成为Service Mesh数据平面API的事实标准。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Envoy在2018年的成功，还体现在社区开始出现基于Envoy的衍生产品：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ambassador：构建于envoy之上的API Gateway，紧追着envoy的新版本，支持与Istio集成，可作为service mesh架构中的ingress gateway。&lt;/li&gt;
&lt;li&gt;Gloo：基于Envoy的Hybrid App Gateway，可作为Kubernetes  ingress controller 和API gateway，来自 &lt;a href=&#34;https://solo.io&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;solo.io&lt;/a&gt;。&lt;/li&gt;
&lt;li&gt;Rotor：Envoy的轻量级控制平面，来自Turbine Labs（由于Turbine Labs的公司变动，这个项目已经不再维护）。&lt;/li&gt;
&lt;li&gt;Contour：基于Envoy的Kubernetes Ingress Controller，来自 Heptio 公司&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在2017年的总结中，我们对Envoy的评价是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Envoy随后收获了属于它的殊荣：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2017年9月14日，Envoy加入CNCF，成为CNCF的第二个Service Mesh项目。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可谓名至实归，水到渠成。作为一个无需承载一家公司未来的开源项目，Envoy在2017年的表现，无可挑剔。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;而在2018年，Envoy继续稳健发展，一边伴随Istio一起成长，一边在各个领域开疆扩土。Envoy的成功故事在延续，并再次收获属于它的殊荣：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2018年11月28日，CNCF宣布Envoy毕业，成为继Kubernetes和Prometheus后，第三个孵化成熟的CNCF项目。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;同样的名至实归，同样的水到渠成，Envoy在2018年的表现，同样的无可挑剔。&lt;/p&gt;
&lt;p&gt;Envoy 的2018年年度总结，对这位低调的实力派选手，我们的评价只有一个字：稳！&lt;/p&gt;
&lt;h3 id=&#34;buoyant-linkerd系列&#34;&gt;Buoyant Linkerd系列&lt;/h3&gt;
&lt;p&gt;作为 Service Mesh 的先驱，Linkerd 和 Linkerd 背后的初创公司 Buoyant 在过去两年间的故事可谓波澜起伏，面对出身豪门的网红 Istio ，Buoyant 在2017年便被逼入绝境，2018年的 Buoyant 几乎是以悲剧英雄的形象在进行各种突围尝试，寻找生路。&lt;/p&gt;
&lt;h4 id=&#34;linkerd-1&#34;&gt;Linkerd 1.×&lt;/h4&gt;
&lt;p&gt;Linkerd的2018年，是突围的一年，作为定义Service Mesh概念的先驱，其Github Star数量在2017年底就已经被Istio超越，虽然一直有平稳增长，已经无力与Istio一较高下了。下面按照时间顺序整理一下 Linkerd1.x 版本在2018年之中的几个关键节点。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2018年5月1日，在持续了几个月对1.3.x版本的修修补补之后，发布了1.4.0版本，其中使用了最新版本的Finagle和Netty组件，尝试降低在大规模应用的情况下的内存占用，并开始在可观察性方面的持续改进；&lt;/li&gt;
&lt;li&gt;2018年6月，宣布成立Linkerd + GraalVM工作组。尝试使用GraalVM提高Linkerd的性能。据笔者观察，其讨论到9月就已经再无更新，并且并未产生可发布的任何进展；&lt;/li&gt;
&lt;li&gt;2018年7月14日发布的1.4.5中，提供了对&lt;a href=&#34;https://www.eclipse.org/openj9/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Open J9 JVM&lt;/a&gt;的支持，声称可能降低40%的内存占用以及大幅降低p99延迟；&lt;/li&gt;
&lt;li&gt;2018年10月3日，发布了1.5.0，其中有一项很值得注意的变更：Istio特性被标记为deprecated。事实上在&lt;a href=&#34;https://github.com/linkerd/linkerd/issues/2092&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;8月份的讨论&lt;/a&gt;中，已经有人提出，在Linkerd 1.1.1版本之后，对Istio的支持并未进步，同时也没有明确迹象表明有用户对Linkerd数据平面结合Istio控制平面的方案感兴趣，因此Linkerd开始逐步停止对Istio的支持。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以看到，2018年中，Linkerd的Istio Sidecar方案和GraalVM性能优化方案均已无疾而终，目前硕果仅存的是Open J9 JVM的优化版本，其测试版本还在继续发行。&lt;/p&gt;
&lt;h4 id=&#34;conduit&#34;&gt;Conduit&lt;/h4&gt;
&lt;p&gt;而诞生于2017年底的Conduit，形势稍微乐观一点，但是根据Github star的观察，表现也仅是优于同门的Linkerd，和Istio相比，仍然不在同一数量级，其更新频度非常高，基本做到每周更新，呈现了一种小步快跑的态势。当然，这种快速更新的最重要原因应该就是其相对稚嫩的状态，和成熟的Linkerd相比，Conduit还只是刚刚起步，下面也根据Release情况看看2018年里 Conduit 项目的进展：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2018年2月1日，发布Conduit v0.2.0，提供了TCP和HTTP的支持；&lt;/li&gt;
&lt;li&gt;2018年2月21日，发布v0.3，宣布进入Alpha阶段，为负载均衡功能提供了负载感知的能力；&lt;/li&gt;
&lt;li&gt;2018年4月17日，发布v0.4.0，提供了对MySQL和SMTP的透明支持能力；&lt;/li&gt;
&lt;li&gt;2018年6月5日，发布v0.4.2，支持全部Kubernetes Workload；&lt;/li&gt;
&lt;li&gt;2018年7月6日，发布最后一个Conduit版本，v0.5.0，提供了Web Socket支持，加入自动TLS支持，更名为Linkerd 2.0；&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&#34;linkerd-2&#34;&gt;Linkerd 2.×&lt;/h4&gt;
&lt;p&gt;很明显，在2018年年中，Buoyant 意识到继续同时支撑 Linkerd1.x 和 Conduit 两条产品线已经不合时宜。而且 Linkerd1.x 的硬伤太过明显：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基于Scala/JVM的数据平面，在性能和资源消耗方面，对阵基于 c++ 而且表现异常成熟稳重的 Envoy，毫无优势。在2018年针对 Linkerd 1.× 的各种性能优化无疾而终之后，答案已经很明显：Linkerd 1.× 已经不再适合继续用来作为数据平面。&lt;/li&gt;
&lt;li&gt;相对 Istio 强大的控制平面，Linkerd 1.x 在控制平面上的缺失成为关键弱点。尤其 Linkerd 1.x 晦涩难懂的 dtab 规则，面对 Envoy 的 xDS API，在设计和使用上都存在代差。&lt;/li&gt;
&lt;li&gt;而以 Linkerd 为数据平面去结合 Istio 控制平面的设想，在经过一年多的尝试后无奈的发现：这个方案根本没有市场。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，合并产品线，放弃 Linkerd 1.×，将力量集中到 Conduit 这个未来方案就成为自然选择。而 Linkerd 原有的市场品牌和号召力，还有 CNCF 项目的地位也应该保留，因此，Buoyant 选择了在2018年7月，在 Conduit 发布 v0.5.0 时将 Conduit 更名为 Linkerd 2.0。&lt;/p&gt;
&lt;p&gt;Linkerd 2.x 版本的目标则具有很明确的针对性：提供一个轻量级、低难度、支持范围有限的Service Mesh方案，9月份宣布GA并得到客户采用，证明这一策略还是行之有效的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2018年9月18日，Linkerd 2.0宣布被WePay、Hush、Studyo以及JustFootball采用，进入GA阶段；&lt;/li&gt;
&lt;li&gt;2018年12月6日，Linkerd 2.1发布，推出了路由级的遥测能力。更重要的是，提出了Service Profile的概念，这一概念以服务为中心，将服务相关的大量CRD聚合成统一一个，对服务网格的管理无疑是一个强大助益。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;2018年底提出的Service Profile概念，虽然只是一个雏形，目前仅提供了一点监控方面的功能，但是其Roadmap中指出，日后将会把大量特性集成到Service Profile之中，笔者认为相对于Istio的Mixer适配器模型来说，这一概念能够极大的降低运维工作难度工作量，并有效的简化服务网格的管理工作。&lt;/p&gt;
&lt;p&gt;在 Istio 封锁了 Service Mesh 的门之后，经过一年摸索和碰壁，Linkerd2发现了Service Profile的这扇窗，可以说是尚存希望。&lt;/p&gt;
&lt;h4 id=&#34;对buoyant的总结&#34;&gt;对Buoyant的总结&lt;/h4&gt;
&lt;p&gt;作为 Service Mesh 的业界先驱，Buoyant 在早期有非常大的贡献和成就，但是在 Istio/Envoy 发起的强力攻势面前，几乎没有招架之力。2018年，如果不是 Istio 因为自身原因在产品发展上表现疲软留给了 Buoyant 一线生机，Buoyant 几乎无立足之地。&lt;/p&gt;
&lt;p&gt;回顾2017年和2018年 Buoyant 的表现，笔者的看法是 Buoyant 的问题主要体现在对竞争对手和对自己的认知都不够清晰，导致在产品策略上接连犯错：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在 Istio 出来之前，面对 Envoy，Linkerd 1.× 系列的劣势就很明显，只是 Linkerd 作为市场上第一个 Service Mesh 类产品，光环太盛，遮挡了社区和客户的视线，但是 Buoyant 自己不应该迷失。面对强力竞争对手，未能及时反思并调整布局，这是 Buoyant 犯下的第一个错误。没能意识到自身的不足，导致后面在数据平面上始终被 Envoy 遥遥领先。&lt;/li&gt;
&lt;li&gt;在 Istio 出来之后，在原有数据平面对阵 Envoy 已经存在劣势的前提下，控制平面也出现代差，还有 Google 和 IBM 站台导致原来面对 Envoy 的市场宣传和社区支持的优势也荡然无存。此时 Buoyant 就应该彻底反省并给出全新方案，但是 Buoyant 当时的选择是让 Linkerd 作为数据平面去兼容 Istio，而未能在控制平面上及时发力。&lt;/li&gt;
&lt;li&gt;2017年底，Conduit 的推出本来是一步好棋，2017年年底和2018年年初 Istio 表现糟糕，甚至有些混乱，Conduit 的推出也符合社区希望存在良性竞争的心态。然而 Conduit 的数据平面采用 Rust 语言，虽然性能表现卓越，但是过于小众，导致来自开源社区的 contributor 数量极其稀少，根本无法从社区借力。&lt;/li&gt;
&lt;li&gt;2018年，在推出 Conduit 之后，迟迟不肯放弃 Linkerd 1.×，直到2018年年中才在各种尝试无效之后最终选择放弃 Linkerd 1.×。其实这个决定，本可以在更早的时间点做出。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于 Envoy 在数据平面上的优越表现，和 Buoyant 在产品策略上的接连失误，使得2018年的 Linkerd 1.× 、Conduit 、Linkerd 2.× 一直都 Envoy 的阴影中苦苦追赶，始终无法在控制平面上对 Istio 形成实质性威胁。&lt;/p&gt;
&lt;p&gt;2018年对 Buoyant 及旗下的Linkerd系统的总结是：犹豫太多，决心下的太晚，新产品缺乏吸引力足够大的亮点，前景很不乐观。&lt;/p&gt;
&lt;p&gt;2019年，对 Buoyant 来说，很有可能是生死存亡的一年，用我们熟悉的一句话说：留给 Buoyant 的时间已经不多了。&lt;/p&gt;
&lt;h3 id=&#34;其他产品&#34;&gt;其他产品&lt;/h3&gt;
&lt;p&gt;在前面的内容中，我们用了很多的篇幅来总结 Buoyant 面对 Istio + Envoy 组合的种种应对之策，而这个话题，对于任何希望出现在 Service Mesh 市场的玩家来说，都是一个避无可避的问题。&lt;/p&gt;
&lt;p&gt;接下里我们将列出，在 Istio、Envoy 和 Linkerd系列这些主要竞争者之外，Service Mesh 市场上陆陆续续出现的来自各家公司的参与者：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Nginmesh：来自大名鼎鼎的nginx，在2017年9月nginx对外宣布了这一产品，是一款适配Istio的service mesh方案，使用NGINX作为sidecar替换Envoy。但nginx在Nginmesh上的态度摇摆不定：在2017年下半年发布了3个小版本之后就停止开发。2018年重新启动，接连发了几个小版本，但是在2018年7月发布0.7.1版本之后，再次停止开发。&lt;/p&gt;
&lt;p&gt;总结：Envoy 是座大山，是条鸿沟，在数据平面试图正面挑战 Envoy，需要非常大的努力和投入。这本是一个非常严肃的话题，而 nginmesh 一直摇摆不定没有持续投入，在勤勉的 Envoy 面前不会有机会的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consul Connect：Consul来自HashiCorp公司，主要功能是服务注册和服务发现，基于Golang和Raft协议。在2018年6月26日发布的Consul 1.2版本中，提供了新的Connect功能，能够将现有的Consul集群自动转变为Service Mesh。亮点是可以提供自动的双向TLS加密通信以及基于唯一标识的权限控制。&lt;/p&gt;
&lt;p&gt;总结：Consul 的方案，一直以来社区都没啥反馈。不好评价，让时间说话吧。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;kong：在2017年就有传闻说kong有意service mesh，但一直不见kong的明确动作。在2018年9月，kong宣布1.0发布之后kong将转型为服务控制平台，支持Service Mesh。关于kong到底会不会投身service mesh的悬念也就一直贯穿整个2018年度，直到12月21日，kong 1.0 GA发布时才明确给出：kong可以部署为独立的service mesh proxy，开箱即用的提供service mesh的关键功能，并集成有 Prometheus、Zipkin，支持健康检查，金丝雀发布和蓝绿部署等。&lt;/p&gt;
&lt;p&gt;总结：Kong作为一个从API网关演变而来的 service mesh 产品，背靠成熟的OpenResty，虽然相对 istio + envoy 在功能性上稍显不足，不过胜在简单、可扩展性强，比较适合中小型团队以及以前 kong 的老用户试水 service mesh。考虑到 kong 社区比较活跃，也许能走出一条和 Istio 不同的道路。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;AWS App Mesh：AWS APP Mesh是AWS今年在re:Invent 2018大会上发布的一款新服务，旨在解决在AWS上运行的微服务的监控和控制问题。它主要标准化了微服务之间的通信流程，为用户提供了端到端的可视化界面，并且帮助用户应用实现高可用。App Mesh 使用开源的 Envoy 作为网络代理，这也使得它可以兼容一些开源的微服务监控工具。用户可以在 AWS ECS 和 Amazon EKS 上使用 App Mesh。从官网放出的流程图可以看出，App Mesh 是对标 Istio。目前App Mesh提供公开预览。&lt;/p&gt;
&lt;p&gt;总结：AWS APP Mesh 的选择，和 Buoyant 的 Linkerd 系列完全相反，选择 Envoy 作为数据平面，从而避免和 Istio 在数据平面进行竞争，毕竟 Envoy 珠玉在前，而数据平面又是最为考验技术底蕴和细节完善，费时费力。AWS APP Mesh 可以集中精力主攻控制平面，趁 Istio 还未完全成熟之时，依托AWS 完善的体系力求在 Service Mesh 领域有自己的一席之地。AWS APP Mesh 支持客户在 EC2 和 Kubernetes 环境下同时部署应用并能实现相互访问，一旦成熟，将有可能是一个大卖点。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Aspen Mesh：来自大名鼎鼎的F5 Networks公司，基于Istio构建，定位企业级服务网格，口号是”Service Mesh Made Easy”。Aspen Mesh项目据说启动非常之早，在2017年5月Istio发布0.1版本不久之后就开始组建团队进行开发，但是一直以来都非常低调，外界了解到的信息不多。在2018年9月，Aspen Mesh 1.0发布，基于Istio 1.0。注意这不是一个开源项目，但是可以在Aspen Mesh的官方网站上申请免费试用。&lt;/p&gt;
&lt;p&gt;总结：这代表着 Service Mesh 市场上的另外一种玩法，依托 Istio 进行订制和扩展，提供企业级服务。如果 Istio 能如预期的实现目标，成为新一代微服务，成为连接云和应用的桥梁，则未来很可能会有更多的公司加入这一行列。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SuperGloo：这是由初创公司 solo.io 发起的开源项目，作为一款服务网格编排平台，目前可以管理Consul、Linkerd和Istio，SuperGloo的目标是在降低服务网格的复杂性的同时最大化采纳服务网格的收益，SuperGloo帮助用户快速获得服务网格的经验，接管服务网格中的一些关键功能，统一了Ingress 流量（南北向）和网格流量（东西向）的管理，为自由组合任何服务网格和Ingress打开了大门。&lt;/p&gt;
&lt;p&gt;总结：这是一个令人瞠目结舌的疯狂想法，在服务网格还在努力证明自己能行，我们这些先行者还在努力试图说服更多的人接受这一新鲜事物时，SuperGloo 又往前大大的迈进了一步。服务网格编排，我们暂时无法评论说这是高瞻远瞩，还是脑洞大开，还是留给时间和市场吧，或许2019年我们再次进行年度总结时形势能明朗一些。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从社区的角度，我们希望有更多的参与者进Service Mesh市场，以推动Service Mesh的健康发展。但是实际情况是，在Istio的光辉之下，新晋产品的发展前景都不太客观，是和Istio全面对抗？还是另辟蹊径寻找适合自己的生存空间？是每个产品都要面对的问题。&lt;/p&gt;
&lt;h3 id=&#34;国际篇小结&#34;&gt;国际篇小结&lt;/h3&gt;
&lt;p&gt;Envoy 和 Linkerd 都可以说是目前 Service Mesh 产品的先驱，然而在刚刚过去的2018年中，其处境差距却不啻云泥：Istio借力Envoy，凭借其强大的号召能力和优秀的总体设计，干净利落的将Linkerd打落尘埃。然而Istio在占领Service Mesh的注意力聚焦之后，在整个2018年中，其发布进度表现出令人印象深刻的拖沓。&lt;/p&gt;
&lt;p&gt;Service Mesh这一技术的广阔前景，加上Istio的疲弱表现，吸引了更多对此技术具有强烈需求或相关技术储备的竞争者出现，除了 AWS 、 F5这样的公有云方案，以及Consul、Kong等同类软件解决方案，还出现了Solo.io这样的更加激进的跨云方案加入战团。&lt;/p&gt;
&lt;p&gt;Service Mesh技术的浪潮已将业界席卷其中，然而这一年来，角逐者有增无减，2019年里，Istio仍是关键——除非Istio能够做出符合顶尖项目的水准，否则，Service Mesh技术很可能会以多极化、市场细分的形式落地。&lt;/p&gt;
&lt;h2 id=&#34;国内篇&#34;&gt;国内篇&lt;/h2&gt;
&lt;p&gt;2018年，国内在Service Mesh方面也投入了很大的力量，包括蚂蚁金服、腾讯、阿里、华为、微博等都研发了自己的Service Mesh产品。这里简单介绍一下它们的技术选型及在2018年所做的工作。&lt;/p&gt;
&lt;h3 id=&#34;蚂蚁金服-sofameshsofamosn&#34;&gt;蚂蚁金服 SOFAMesh+SOFAMosn&lt;/h3&gt;
&lt;p&gt;蚂蚁金服是目前国内 Service Mesh 领域的领头羊，高度认可 Service Mesh 的前景，脚踏实地的在准备 Service Mesh 的大规模落地，决心和投入都非常大。&lt;/p&gt;
&lt;p&gt;蚂蚁金服的Service Mesh解决方案目前主要有两个产品组成：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://github.com/alipay/sofa-mesh&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;SOFAMesh&lt;/a&gt;项目：蚂蚁金服 Service Mesh 的控制平面，跟随社区，Fork 自 Istio，保持同步更新。在Istio体系和框架内进行功能补充/扩展/增强/改进，立足于探索并解决 Istio 生产落地，尤其是大规模落地中遇到的实际问题，包括对各种RPC通讯协议的支持，对单进程多服务的传统SOA服务的支持。为了满足公有云上对客户提供 Service Mesh 托管服务，还提供了多租户的支持。&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://github.com/alipay/sofa-mosn&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;SOFAMosn&lt;/a&gt;项目：蚂蚁金服新型基础设施和中间件的底层网络通用解决方案，可以有多种产品形态，2017年底启动，基于Golang开发。在蚂蚁金服 Service Mesh 中承担数据平面的角色，和 SOFAMesh 项目配合使用，兼容 Istio 体系。此外 SOFAMosn 还将用于 Ingress / API Gateway / Serverless Function Gateway 等场景，以及Message Mesh等其他形态的Mesh，成为蚂蚁金服未来Mesh网络的核心组件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以上两个产品都已经于2018年7月在 GitHub 开源。&lt;/p&gt;
&lt;p&gt;经过2018年的开发和小规模落地使用，目前 SOFAMosn 和 SOFAMesh 项目都已经基本成型，2019年即将在蚂蚁金服大规模落地，支撑蚂蚁金服上云的战略目标。其中SOFAMesh还将在蚂蚁金融云上以 Service Mesh 托管服务的形式为客户提供支持，充分结合云和Service Mesh的优势。&lt;/p&gt;
&lt;h3 id=&#34;新浪微博weibomesh&#34;&gt;新浪微博WeiboMesh&lt;/h3&gt;
&lt;p&gt;WeiboMesh 是微博内部跨语言服务化解决方案，目前已经在微博多条业务线上得到广泛使用，这其中不乏热搜、话题等核心项目。 2018 年 WeiboMesh 核心方向是从内部场景提炼实际业务需求，推动大规模业务低成本接入 Mesh 体系，其主要工作包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;强化了管理端口，提供了基于不同维度的 Mesh 管理方式（维护调试、服务管理/Mesh 注册中心等）&lt;/li&gt;
&lt;li&gt;优化，并丰富了 Mesh 控制平面的功能，提供了 Tracing、熔断，限流等功能&lt;/li&gt;
&lt;li&gt;提供 HTTPMesh 方案，支持 HTTP 与 RPC 服务之间的交互，进一步降低接入门槛&lt;/li&gt;
&lt;li&gt;支持了基于 MC 协议的 CacheService，在资源服务化方面迈出重要一步&lt;/li&gt;
&lt;li&gt;提供了 Python、C++ 语言的支持&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;华为mesher与asm&#34;&gt;华为Mesher与ASM&lt;/h3&gt;
&lt;p&gt;Mesher基于华为开源的ServiceComb，ServiceComb是一个java与go语言的微服务编程框架， 在2017年底加入的Mesher补充完善了微服务解决方案。&lt;/p&gt;
&lt;p&gt;在生产中得到了验证后， 华为在8月份开源了Mesher，以完善ServiceComb开源生态。从发展目标来看，Mesher并不只支持Kubernetes， 而是支持任意的基础设施，包括容器，虚拟机等。并且让ServiceComb支持异构的注册中心管理，可以统一的在一个service center中发现不同基础设施，不同数据中心的微服务，以此来更好的支持混合云场景。&lt;/p&gt;
&lt;p&gt;华为云 Istio 团队在 Istio 生态上投入了很大力量，并基于 Istio 发布了自己的ASM（Application Service Mesh），ASM深度集成华为云容器服务CCE(Cloud Container Engine)，提供非侵入的智能流量治理解决方案，包括负载均衡、熔端、限流等多种治理能力。内置金丝雀、蓝绿等多种灰度发布流程，提供一站式自动化的发布管理。基于无侵入的监控数据采集，整合华为云APM能力，提供实时流量拓扑、调用链等服务性能监控和运行诊断，构建全景的服务运行视图。ASM于2018年8月对外公测。&lt;/p&gt;
&lt;h3 id=&#34;阿里dubbo-mesh&#34;&gt;阿里Dubbo Mesh&lt;/h3&gt;
&lt;p&gt;Dubbo Mesh为阿里自研的服务化框架Dubbo的Service Mesh组件，其技术选型为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数据平面选型Envoy。Envoy所定义的、被广泛接受的xDS协议能够很好地体现了Dubbo对Service Mesh具有“规范化”作用的理解。&lt;/li&gt;
&lt;li&gt;控制平面选型Istio的Pilot组件。以Istio目前的架构设计和结合阿里巴巴集团已有软件资产的现状，其整体并不足以承载起对Service Mesh的要求。然而，其中的Pilot组件的平台抽象设计、对Envoy xDS协议的实现能很好地加速Service Mesh在阿里巴巴集团生产环境的落地。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;接下来，Dubbo Mesh将进一步组合阿里巴巴集团已开源出来的各种组件去增强其监管控能力。比如，通过将Sentinel的能力纳入到Dubbo Mesh，能很好地补全限流、降级和熔断的能力。&lt;/p&gt;
&lt;h3 id=&#34;腾讯tencent-service-mesh&#34;&gt;腾讯Tencent Service Mesh&lt;/h3&gt;
&lt;p&gt;腾讯service mesh属于腾讯内部的下一代微服务技术中台，在腾讯内部业务如广告平台等得到充分的验证，并随腾讯云微服务平台（TSF）于2018年6月上线内测，随后在9月集成了Istio 1.0并发布了里程碑版本，产品将于2019年1月全面公测。&lt;/p&gt;
&lt;p&gt;产品技术选型上，控制面选用了集百家之长的istio，数据面则选用了成熟稳定的高性能边缘代理envoy。&lt;/p&gt;
&lt;p&gt;在开源之上，腾讯云根据业务现状及客户诉求做了以下扩展及改造：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;支持多计算平台集成。能支持虚拟机，物理机的服务自动接入Service Mesh&lt;/li&gt;
&lt;li&gt;支持多服务框架互通。能同时支持SpringCloud与Service Mesh业务进行互通&lt;/li&gt;
&lt;li&gt;支持分布式服务寻址。业务可以通过服务名直接接入Service Mesh框架&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;service-mesh衍生产品&#34;&gt;Service Mesh衍生产品&lt;/h3&gt;
&lt;p&gt;除了完整的Service Mesh产品之外，国内也出现了一些基于Istio的外围项目，如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Naftis：小米武汉研发中心推出的管理Istio任务的Dashboard，用Istio治理服务时须通过istioctl或kubectl，这种方式可能存在一些问题。Naftis通过任务模板的方式来帮助用户更轻松地执行Istio任务。用户可以在 Naftis中定义自己的任务模板，并通过填充变量来构造单个或多个任务实例，从而完成各种服务治理功能。&lt;/li&gt;
&lt;li&gt;Istio-ui：Istio的简易UI，它是jukylin的个人项目，其初衷是线上几百个istio配置文件管理会很麻烦，而官方和社区并没有给出解决方案。在此基础上，结合当前服务环境，增加了校验，注入，模板等功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;国内篇小结&#34;&gt;国内篇小结&lt;/h3&gt;
&lt;p&gt;从上面的介绍可以看到，国内在 Service Mesh 领域上和国际靠的很近。&lt;/p&gt;
&lt;p&gt;技术社区方面，在Service Mesh诞生不久，国内就出现了 Service Mesh 的爱好者、交流社区、布道师，诞生了 &lt;a href=&#34;http://www.servicemesher.com&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;ServiceMesher&lt;/a&gt; 这样专业而专注的垂直技术社区，极大的促进了 Service Mesh 技术在国内技术社区的普及和发展。以InfoQ为代表的技术媒体也对 Service Mesh 这一新兴技术给予了高度关注，在 QCon/ArchSummit 等国内顶级技术峰会上经常可以看到 Service Mesh 相关的演讲主题。&lt;/p&gt;
&lt;p&gt;在产品方面，以蚂蚁金服、新浪微博、华为、阿里、腾讯等公司为代表的国内互联网公司，以多种方式给出了符合自身特点的 Service Mesh 产品，思路和打法各有不同。&lt;/p&gt;
&lt;p&gt;具体说，在数据平面上有三种流派：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;选择 Envoy，如腾讯Tencent Service Mesh、阿里Dubbo Mesh&lt;/li&gt;
&lt;li&gt;自行开发，如新浪微博WeiboMesh、华为Mesher&lt;/li&gt;
&lt;li&gt;也是自行开发，但是和 Envoy 或者说 Istio 兼容，如蚂蚁金服SOFAMosn&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;其中，自行开发的数据平面，无一例外的选择了Golang语言，这一点上倒是容易理解：c/c++直接用Envoy；Java、Scala等由于JVM的原因，在资源消耗上不太适合，Linkerd前车之鉴；Rust之类又实在太小众，同样Conduit前车之鉴。&lt;/p&gt;
&lt;p&gt;Golang在各方面比较均衡，成为c/c++之外数据平面的最佳编程语言选择。只是，如前所述，Envoy 的优越表现使得 Service Mesh 数据平面的竞争过早的偏向 Envoy，而 Buoyant 在数据平面编程语言的选择上，先有过于保守的Scala，后是过于激进的Rust，错失各方均衡的Golang，令人叹息。&lt;/p&gt;
&lt;p&gt;在控制平面上，也是三种流派：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;自行开发，如新浪微博WeiboMesh、华为Mesher&lt;/li&gt;
&lt;li&gt;依托Istio进行扩展和订制，如蚂蚁金服SOFAMesh，华为ASM&lt;/li&gt;
&lt;li&gt;只重用 Istio 的 Pilot 组件，将 Pilot 从 Istio 中剥离出来配合 Envoy 使用，弃用 Mixer 和 Citadel。如腾讯Tencent Service Mesh、阿里Dubbo Mesh。这个选项的存在，一方面和国内 Kubernetes 普及程度不高而 Istio 目前基本绑定 Kubernetes 平台有关，另一方面也是对 Istio 中 Mixer、Citadel 两大组件的质疑。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;2018年国内 Service Mesh 的发展情况，总体上说是多方参与，各种落地和探索，技术社区反应热烈，对于一个新兴技术而言已经是非常理想的状态。当然受限于 Service Mesh 的发展阶段，目前还远没有达到全面普及的程度，还有待于当前 Service Mesh 产品的进一步成熟与完善。&lt;/p&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;Service Mesh 在2018年虽未能如预期的全面走向成熟，未能如Service Mesh 爱好者们所期待的成为 &amp;ldquo;the year of  Service Mesh&amp;rdquo; ，但是整体上 Service Mesh 的发展势头还算不错：Envoy、Istio日渐成熟，Linkerd 2.× 也在推进，而国内也出现了多个产品，其中蚂蚁金服、华为等的投入还非常可观。对 Service Mesh 来说，2018年是蓄势待发的一年。&lt;/p&gt;
&lt;p&gt;回顾2017年的年度总结，在结尾处展望2018年 Service Mesh 的发展时，这样写到：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;2018年对Service Mesh而言，必然不是一帆风顺，必然是充满荆棘和坎坷的。如何实现从技术理念到产品落地，如何实实在在地解决实践中遇到的各种问题，将会是这一年中至关重要的事情。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;今天，我们回顾2018年的 Service Mesh，会发现的确如去年预期的，2018年 Service Mesh 市场上的几个主要产品，都还在产品落地和生产实践上努力探索。只是这个过程，比我们预期的要慢一些，遇到的问题也比预期的要多一些，以至于在2018年结束时，我们未能看到一个梦寐以求的完美答案，而不得不将对 Service Mesh 的美好期许，留待2019。&lt;/p&gt;
&lt;p&gt;2019年的Service Mesh，将会继续充满艰辛和痛苦，将需要更多的努力与执着。落地，落地，落地，将会是2019年 Service Mesh 的主旋律。我们满怀希望，我们拭目以待！&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>蚂蚁金服Service Mesh渐进式迁移方案</title>
      <link>https://skyao.net/talk/201811-service-mesh-step-by-step/</link>
      <pubDate>Sun, 25 Nov 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/201811-service-mesh-step-by-step/</guid>
      <description>&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt1_hue456acfdaddafb1385f95ce4a549aaf6_116094_576f744f25a7a6271d647f97caaaf7dc.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt1_hue456acfdaddafb1385f95ce4a549aaf6_116094_41c3f412125edbfef30e3814331c469a.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt1_hue456acfdaddafb1385f95ce4a549aaf6_116094_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt1_hue456acfdaddafb1385f95ce4a549aaf6_116094_576f744f25a7a6271d647f97caaaf7dc.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;大家好，今天给大家带来的演讲主题是“蚂蚁金服Service Mesh渐进式迁移方案”，给大家介绍一下我们蚂蚁金服主站的Service Mesh迁移方案，在稍后的内容中我会给大家解释什么是“渐进式”。今天的演讲方式有些特殊，将会是两位讲师合作。我是敖小剑，来自蚂蚁金服中间件团队，另外一位讲师 龙轼 ，来自 UC 基础研发部。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt2_hu7ab77b092fc88ab9f63b76bed9674582_123571_20fc15866abbd1f1abc41e76c718f78b.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt2_hu7ab77b092fc88ab9f63b76bed9674582_123571_75f28788e51da1d87d230389b6835c5b.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt2_hu7ab77b092fc88ab9f63b76bed9674582_123571_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt2_hu7ab77b092fc88ab9f63b76bed9674582_123571_20fc15866abbd1f1abc41e76c718f78b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;今天的内容将会有四块主要内容：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Service Mesh演进路线：介绍蚂蚁金服计划在主站落地Service Mesh的方案，由于涉及到大量的存量应用和超大规模，又要保证迁移过程的平滑，因此我们的落地方案相比社区方案要复杂的多。&lt;/li&gt;
&lt;li&gt;实现平滑迁移的关键：介绍在整个迁移方案中，为了实现平滑迁移的几个关键做法，然后今天我们将详细展开其他的一个关键点：DNS寻址方案。&lt;/li&gt;
&lt;li&gt;DNS寻址方案的演进：详细介绍Kubernetes/Istio/SOFAMesh一路演进过来的DNS寻址方式&lt;/li&gt;
&lt;li&gt;DNS寻址方案的后续规划：介绍我们在DNS寻址方案上的后续规划&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;前两块内容将由我来为大家介绍，后两块内容将由我的同事 龙轼 为大家介绍。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt3_hue7e8645e848648af87981eee7125935f_243241_277fcd77301012f8435d243586715057.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt3_hue7e8645e848648af87981eee7125935f_243241_6321aab0edc65e8629c03c78cf668ebf.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt3_hue7e8645e848648af87981eee7125935f_243241_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt3_hue7e8645e848648af87981eee7125935f_243241_277fcd77301012f8435d243586715057.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在展开内容之前，先看一下背景，Service Mesh在蚂蚁金服主站落地的背景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;目标：需要满足我们对长期目标的认可，具体指服务间通讯走Service Mesh，而且是Istio这种带完整的控制平面的Service Mesh形态，基础设施要构建在k8s之上，而应用的形态要向微服务靠拢。&lt;/li&gt;
&lt;li&gt;现状：而现实是存在很多挑战，首先还有很多应用没有实现微服务化，而且我们的k8s普及程度也不够，还有非常多的应用没有运行在kubernets之上。Istio的成熟程度也稍显不足，不够稳定，更大的挑战的是Istio目前无法原生支持我们蚂蚁金服的规模，我们还在试图对Istio进行改进和扩展。最后，在落地时必须考虑的非常现实的一点：现有系统中为数众多的应用不可能一夜之间全部迁移。&lt;/li&gt;
&lt;li&gt;关键需求：因此在落地实施时，非常重要的需求是：要实现平滑迁移。简单说，微服务 + Service Mesh + kubernetes 是我们的目标，但是如何从现有体系出发，向目标平稳和坚实的迈进，必须给出可行的实践指导。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;今天演讲的内容，要给大家介绍的就是，在这样的背景下，我们蚂蚁金服选择的Service Mesh主站落地演进方案。这个方案预期会在2019年初全面铺开。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt4_huf4148982f59f39dcf6d66c71b34d6e7d_78605_45d56dce874348bf6cb4b8806b4ecfac.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt4_huf4148982f59f39dcf6d66c71b34d6e7d_78605_413d25a5ffd7ed7bd5937b46882e70be.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt4_huf4148982f59f39dcf6d66c71b34d6e7d_78605_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt4_huf4148982f59f39dcf6d66c71b34d6e7d_78605_45d56dce874348bf6cb4b8806b4ecfac.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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;/ul&gt;
&lt;p&gt;在接下来的演进路线中，大家将会体会到这三个原则在实际落地时的指导作用。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt5_hu495a8787ea0a972200feb97725ca54f7_86384_7040241671534f907e7c4b200dc12a5d.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt5_hu495a8787ea0a972200feb97725ca54f7_86384_1f6c4d1e13e41a8bc6d4062674b69b2e.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt5_hu495a8787ea0a972200feb97725ca54f7_86384_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt5_hu495a8787ea0a972200feb97725ca54f7_86384_7040241671534f907e7c4b200dc12a5d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这个图的信息量有点大，描述的是 Service Mesh 和 k8s 落地可能的多种演进路线。&lt;/p&gt;
&lt;p&gt;我们先从最下面开始看，这是当前蚂蚁金服主站大多数应用的现状：即应用&amp;quot;部署在非k8s上&amp;quot;，应用也&amp;quot;不是Service Mesh形态&amp;quot;。 然后看最上面，这是我们期望的蚂蚁金服主站未来的应用终极形态：应用&amp;quot;部署在k8s上&amp;quot;，应用也迁移到了&amp;quot;Service Mesh形态&amp;quot;。&lt;/p&gt;
&lt;p&gt;这里有个特别的地方，我们将Service Mesh形态细分为两种模式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Sidecar模式：只有Sidecar，没有控制平面，和外部系统的各种集成都是在Sidecar中直接进行。这是第一代的Service Mesh，Linkerd/Envoy都是如此，华为基于ServiceComb演进而来的mesher，新浪微博的Mesh，包括我们蚂蚁金服基于MOSN开发的用于取代多语言客户端的Mesh方案。&lt;/li&gt;
&lt;li&gt;Istio模式：有完善的控制平面，可以提供强大的控制能力，而且从数据平面分离，这是第二代的Service Mesh，典型如Istio和Conkduit/Linkerd 2.0。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;之所以将Service Mesh形态细分，是因为我们有着这样一个特殊背景：目前的原生Istio无法支撑我们蚂蚁金服的规模，因此在改进完善Istio之前，我们不得不暂时在Sidecar模式下短暂停留。另外一个原因就是考虑到存量应用的迁移，多一个Sidecar模式作为中间缓冲，会让整个迁移过程平滑很多。&lt;/p&gt;
&lt;p&gt;现在我们来介绍图中展示的四条演进路线：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;左边的路线1，思路是先将应用迁移k8s部署，再迁移到Service Mesh形态。这条路线的最大好处，是过程中每个阶段的绝大多数投资都将最终得以保留，因为符合k8s+service mesh的远期目标&lt;/li&gt;
&lt;li&gt;右边的路线2，思路是跳过k8s，先迁移到Service Mesh形态，一路演进到Istio模式，然后最后迁移到k8s。&lt;/li&gt;
&lt;li&gt;中间的路线3，直接一步到位，这个路线是Istio默认的方式，或者说Istio根本没有考虑过迁移的问题，默认客户已经有完善的k8s，然后将改造好的应用直接部署在Istio上。这个路线对于蚂蚁金服主站的复杂场景，当然是不现实的。（补充：只是对蚂蚁金服主站不合适，对于大多数公司，规模不是那么巨大，也没有历史负担，也有k8s基础，完全可行。）&lt;/li&gt;
&lt;li&gt;还有一条特别的路线4，走位飘忽，先和路线2一样迁移到Sidecar模式，然后走回路线1，上k8s，再在有k8s支持的情况下继续演进到Istio模式。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;下面我们来详细分析各条演进路线的优劣和实施条件。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt6_hud50c809145b20e7eeaf69f5d43c4864f_92260_6c279f93c8fbbc7fac4cc0119014d591.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt6_hud50c809145b20e7eeaf69f5d43c4864f_92260_ad64981fa021f987f7f345823c1b26c2.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt6_hud50c809145b20e7eeaf69f5d43c4864f_92260_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt6_hud50c809145b20e7eeaf69f5d43c4864f_92260_6c279f93c8fbbc7fac4cc0119014d591.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;演进路线2，和路线1的核心差别，在于：是先上k8s，还是先上Service Mesh。而且路线2是在非k8s条件下一路演进Service Mesh到我们期望的终极形态Istio模式，这意味着过程中和最终目标有非常大的偏移。&lt;/p&gt;
&lt;p&gt;演进路线2的好处，在于第一步非常的自然：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;没有k8s的限制，因此不依赖基础设施，实施方便。毕竟，k8s普及度是个大问题&lt;/li&gt;
&lt;li&gt;在原有的侵入式框架的客户端SDK基础上，通过包裹一个proxy，重用原有SDK的能力，可以非常快速的得到一个基本可用的Sidecar&lt;/li&gt;
&lt;li&gt;除了多一个proxy外，没有引入太多的新概念和新思想，符合现有开发人员/运维人员的心智，容易接受&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，路线2特别容易落地，可以快速达成短期目标，直接拿到Service Mesh的部分红利，如：多语言支持，方便类库升级等。&lt;/p&gt;
&lt;p&gt;但是，这个路线的问题在于再往后走，开始完善Service Mesh的功能以向Istio模式靠拢时，由于没有k8s的底层支持，因此不得不做大量的工作来提供类k8s的功能。尤其是Istio的非k8s支持，官方方案基本上只是一个demo，完全不具备生产可用性，要完善好，工作量很大。而关键点在于，这些投入，在迁移到k8s时，又因为和k8s提供的功能重复而被放弃。&lt;/p&gt;
&lt;p&gt;因此，结合我们前面的原则（符合远期规划，不浪费投资），路线2对蚂蚁金服主站落地是不合适的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt7_hu04fd63bbd833291e9aa7ee11c2dabde5_75698_f5af5027a39f388c81c0f630bba203c3.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt7_hu04fd63bbd833291e9aa7ee11c2dabde5_75698_9fe8499d19590f67bc77ab63cf8a0946.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt7_hu04fd63bbd833291e9aa7ee11c2dabde5_75698_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt7_hu04fd63bbd833291e9aa7ee11c2dabde5_75698_f5af5027a39f388c81c0f630bba203c3.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;演进路线4是一个非常特殊的路线，可以理解为路线1（先上k8s再上Service Mesh）的短期妥协版本。因为路线1的前提条件是要先大规模铺开k8s，将现有应用迁移到k8s之后再继续往Service Mesh演进，这对于还没有普及k8s的公司来说是一个非常高的门槛，很容易因此受阻而无法启动。&lt;/p&gt;
&lt;p&gt;因此，如果暂时不具备k8s条件， 又不想就此止步，那么选择路线2是唯一的出路。而上面我们分析过，路线2虽然能够在第一步快速拿到短期红利，但是由于偏离长期目标后续发展会有问题。怎么办？&lt;/p&gt;
&lt;p&gt;路线4可以是这种场景下的一个折衷选择：在k8s没有铺开之前，第一步沿路线2走，先吃下非k8s下Sidecar模式快速落地的红利。然后第二步避开非k8s下继续演进到Istio模式的大坑，切换到路线1，回归长期目标。&lt;/p&gt;
&lt;p&gt;好处非常明显：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在k8s未铺开前，先往前迈进一步，避免就此卡壳&lt;/li&gt;
&lt;li&gt;和路线2一样，第一步可以快速的拿到短期红利&lt;/li&gt;
&lt;li&gt;后续转为路线1后，因为符合远期规划，因此后续演进不存在投资浪费的问题&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;缺点就是存在少量的投资浪费，毕竟非k8s下的Sidecar模式还是有些工作内容在迁移到k8s之后会有改动。不过，这个改动不会太大，和拿到的红利相比还是值得的。&lt;/p&gt;
&lt;p&gt;路线4在操作时，存在一个变数：现有应用在向Sidecar模式的Service Mesh迁移，是需要一定时间的。有一种可能，就是在迁移过程中，k8s的普及开始了。这个变数的发生，取决于Sidecar模式的Service Mesh普及快，还是k8s的普及快。&lt;/p&gt;
&lt;p&gt;对路线4的分析结果：这是（k8s没有普及的）特殊时期的选择。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt8_huefeff6c3d14fcf81012ea80d87f3a49b_75102_5662723e25d578e7057d85043a16f40b.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt8_huefeff6c3d14fcf81012ea80d87f3a49b_75102_3b6487acd345906a50268b1e1f6f8dbf.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt8_huefeff6c3d14fcf81012ea80d87f3a49b_75102_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt8_huefeff6c3d14fcf81012ea80d87f3a49b_75102_5662723e25d578e7057d85043a16f40b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在对四条可能的演进路线分析完成之后，我们来具体介绍蚂蚁金服的最终选择。&lt;/p&gt;
&lt;p&gt;坦言说，在过去半年中，我们的演进路线有几次摇摆和修订，今天我们公布的路线，和过去几个月中我们通过 meetup/技术大会/博客文章 等方式透露出来的方式会有一些变化。主要原因是在过去的这半年中，一方面我们对Sercice Mesh的认知更加深入，另一方面是蚂蚁金服的k8s背景也在变化。&lt;/p&gt;
&lt;p&gt;首先，在今年年初，我们确认Service Mesh大方向时，k8s还没有在蚂蚁金服普及，而且也没有明确的时间表。因此，我们在一番调研之后，选择了两条腿走路的方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在非k8s环境下，以Sidecar模式先进行少量落地，主要是替换掉原有的多语言客户端 （拿短期红利）&lt;/li&gt;
&lt;li&gt;开发SOFAMesh，集成MOSN到Istio，增加对多种RPC协议的支持，增加对RPC服务模式的兼容（为最终目标做准备 ）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在今年6月底的杭州第一届Service Mesh 线下 meetup 中，我们公布了 SOFAMesh 项目，我当时做了一个演讲 &lt;a href=&#34;https://skyao.net/publication/201806-service-mesh-explore/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;大规模微服务架构下的Service Mesh探索之路&lt;/a&gt; ，有兴趣的同学可以去回顾一下我们当时的背景/需求/设计方案。&lt;/p&gt;
&lt;p&gt;大概在今年九月，我们完成了对非k8s下运行istio的深入调研，得出的结论是要实现这个模式需要非常多的工作。而且，我们对Service Mesh的认知也更加深刻，明确了通过Service Mesh将传统中间件能力向以k8s为代表的基础设施层下沉的战略方向。期间，内部也明确了k8s普及的大方向，因此，综合这两个重要输入，我们选择放弃继续在路线2上继续演进（即 istio on 非k8s）的想法。关于这一点，有兴趣的同学可以去阅读我在10月份QCon大会上的演讲内容 &lt;a href=&#34;https://skyao.net/publication/201810-ant-finance-service-mesh-practice/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;长路漫漫踏歌而行：蚂蚁金服Service Mesh实践探索&lt;/a&gt; 。&lt;/p&gt;
&lt;p&gt;最近，k8s普及的时间表再一次明确提前，蚂蚁金服将会在短时间内开启k8s的大面积普及。因此，我们的演进路线再一次发生变化。目前最新的演进路线将会是这样：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;当前还没有开始迁移的应用（处于演进路线图最下方），将按照路线1的方式进行迁移：先迁移到k8s，再迁移到Sidecar模式的Service Mesh&lt;/li&gt;
&lt;li&gt;目前部分已经迁移的应用（路线2/4的第一步，非k8s部署的 Sidecar 模式），将沿路线4迁移，和路线1会师&lt;/li&gt;
&lt;li&gt;由于应用众多，因此预计到 k8s + Sidecar模式 的迁移工作会持续比较长时间，在此期间，我们会同步完善Istio，和Istio官方一起合作来实现Istio对超大规模部署的支持&lt;/li&gt;
&lt;li&gt;最后一步，迁移到最终目标（当然这一步的方案依然有很多待定内容，继续努力）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;需要强调的是：这个演进路线针对的是蚂蚁金服主站的特殊场景，并不具体普适性。大家可以在理解我们演进路线背后的思路和权衡方式之后，再结合自身的实际情况进行决策。比如，我们在UC落地时，由于UC有完善的k8s支持，而且目前落地的规模没那么夸张，因此是直接从&amp;quot;部署在k8s上&amp;quot; + &amp;ldquo;不是Service Mesh形态&amp;rdquo;，直接迁移到终态的。预计在金融云落实时，也会是如此，因为客户也不会有如此规模。&lt;/p&gt;
&lt;p&gt;总结：前面我们介绍了当应用程序向Service Mesh和K8s迁移时的几种可能的演进路线，分析了各条路线的利弊。并以蚂蚁金服主站为例，介绍了我们迁移的背景和演进路线的选择思路，希望能够帮助大家更好的理解Service Mesh的落地实践，以便在未来设计自家的落地方案时能有所参考。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt9_hu524605e40120b4fcfaf78890c5914f01_124510_71cb94c27b4031e051468860bddee260.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt9_hu524605e40120b4fcfaf78890c5914f01_124510_a8fbbdb2bc2d5416d1782dfdd49a6c9f.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt9_hu524605e40120b4fcfaf78890c5914f01_124510_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt9_hu524605e40120b4fcfaf78890c5914f01_124510_71cb94c27b4031e051468860bddee260.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;前面给大家介绍了蚂蚁金服主站的Service Mesh演进路线，期间谈到要实现现有应用的平滑迁移。今天的第二个内容，将给大家介绍平滑迁移实现中的几个关键做法。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt10_hufee9a2ec14bb702db8b5166977dde210_47719_022a9abc18462dbe4644ed351c0711d3.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt10_hufee9a2ec14bb702db8b5166977dde210_47719_b2aee7f436d05941e57e3642fa301bcd.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt10_hufee9a2ec14bb702db8b5166977dde210_47719_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt10_hufee9a2ec14bb702db8b5166977dde210_47719_022a9abc18462dbe4644ed351c0711d3.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;首先，第一个关键是尽量保证迁移前后服务间网络互通。&lt;/p&gt;
&lt;p&gt;以向k8s迁移为例，在非k8s环境，典型的服务间访问方式是这样：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个服务向注册中心注册&lt;/li&gt;
&lt;li&gt;客户端发起访问前，通过注册中心得到目标服务的实例列表信息，如IP地址/端口等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在向k8s迁移的过程中，我们的做法是保证k8s内外网络打通，即服务的IP地址（在k8s中是pod ip）是可以相互直接访问的。基于这个前提，服务在迁移到k8s的过程中，原有的服务注册/服务发现/发起请求等逻辑都无需修改，是不是在k8s内，是不是pod ip，对原有服务化体系完全是透明的。&lt;/p&gt;
&lt;p&gt;因此，向k8s的迁移可以做到对业务应用非常的平滑，基本感知。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt11_hu7556a886abb971a4739c4edaffe0135d_83979_83f964c0202d042d74f5baac1b8c6b74.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt11_hu7556a886abb971a4739c4edaffe0135d_83979_14314c7554257aa0b9dd9fdb4c7d21d5.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt11_hu7556a886abb971a4739c4edaffe0135d_83979_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt11_hu7556a886abb971a4739c4edaffe0135d_83979_83f964c0202d042d74f5baac1b8c6b74.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;透明拦截在迁移过程中，可以起到非常关键的作用。&lt;/p&gt;
&lt;p&gt;以Service-A要访问Service-B，在应用向Sidecar模式的Service Mesh迁移前后，会有有四种排列组合场景：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Service-A和Service-B都没有迁移到Serive Mesh：此时请求会直接从Service-A发送到Service-B，称为直连，这是应用在开始迁移到Service Mesh之前的标准工作方式&lt;/li&gt;
&lt;li&gt;Service-A已经迁移到Service Mesh，Service-B还没有：此时Service-A发出来的请求，会被劫持，然后发送到和Service-A一起部署的Sidecar（称为Outbound Sidecar），此时链路中只有一个Sidecar，称为（客户端）单跳&lt;/li&gt;
&lt;li&gt;Service-B已经迁移到Service Mesh，Service-A还没有：此时Service-A发出来的请求，在到达Service-B时，会被劫持到和Service-B一起部署的Sidecar（称为Inbound Sidecar），此时链路中也只有一个Sidecar，称为（服务器端）单跳&lt;/li&gt;
&lt;li&gt;Service-A和Service-B都迁移到Serive Mesh：此时Service-A发出来的请求，会被两次劫持，分别进入Outbound Sidecar和Inbound Sidecar，此时链路中有两个Sidecar，称为双跳。这是Istio的标准工作模式，也是我们迁移完成之后的最终工作模式。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在这四种场景中，所有的网络请求，请求报文都是完全一致的，即不管是否被劫持到Sidecar，对请求报文都没有影响，也就是对发出请求报文的客户端和接受请求报文的客户端都是透明的，完全无感之。&lt;/p&gt;
&lt;p&gt;因此，在迁移过程中，可以单个服务逐个迁移，甚至服务的单个实例逐个迁移，而无需修改应用本身。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt12_hu7e3a6ac69184b46b53ee4b0ecb8a5f85_71252_4b447c5c0aa9bda395d10d885ed3425c.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt12_hu7e3a6ac69184b46b53ee4b0ecb8a5f85_71252_b3ccf694c1077162c228f007d460f783.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt12_hu7e3a6ac69184b46b53ee4b0ecb8a5f85_71252_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt12_hu7e3a6ac69184b46b53ee4b0ecb8a5f85_71252_4b447c5c0aa9bda395d10d885ed3425c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在展开第三个关键点之前，我们来探讨一下：在Service Mesh时代，理想的客户端应该是什么样子？&lt;/p&gt;
&lt;p&gt;图中我们列举了一个传统的侵入式框架的客户端所包含的功能，在侵入式框架中，大部分的功能都是由客户端实现，因此会包含非常多的功能，如服务发现、负载均衡等基本功能，加密、认证、路由等高级功能。在应用迁移到Service Mesh之后，这些功能都下沉到Service Mesh中。因此，Service Mesh下的客户端可以进行大幅度的简化，成为一个新的轻量级客户端。&lt;/p&gt;
&lt;p&gt;对于这个轻量级客户端，我们希望可以尽可能的做的轻薄通用：实现简单，不管哪个编程语言都可以做到轻松实现，因此跨语言就方便了。而且越简单之后升级的可能性就会越少，以避免升级客户端。&lt;/p&gt;
&lt;p&gt;那我们来继续看，这个轻量级客户端里面最后还能剩下什么内容？&lt;/p&gt;
&lt;p&gt;图中列出了三个，其中最重要的，也是必不可少的是目标服务的标识，即无论如何简化，最低限度应该告之要访问谁吧？然后是序列化，对于RPC类肯定需要提供编解码功能，不过对于HTTP/REST类很多语言直接内置了标准实现。然后链路追踪，需要做一点工作来传递诸如SpanID之类的参数，同样这块也有可能通过自动埋点来实现。因此，最理想最单薄的客户端，可能只保留最后一个信息：目标服务的标示。&lt;/p&gt;
&lt;p&gt;在侵入式框架下，目标服务的标示是和服务注册/服务发现是直接关联的，这个标示通常都是服务名，通过服务发现机制实现了一个服务名到服务实例的寻址方式。在Service Mesh机制下，由于服务发现机制被下沉到Service Mesh中，因此只要底层Service Mesh能支持，这个目标服务的标示可以不必拘泥于服务名。&lt;/p&gt;
&lt;p&gt;那么，问题来了，对客户端来说：最简单，最通用，支持最广泛的寻址方式是什么？是DNS！&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt13_hue916a94f3dfd80f2df1356f3b182b4a0_59856_bcfd4873549d287336aebfe578b02ec3.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt13_hue916a94f3dfd80f2df1356f3b182b4a0_59856_8a1ad2792c56a59f1d9f6e701353b91b.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt13_hue916a94f3dfd80f2df1356f3b182b4a0_59856_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt13_hue916a94f3dfd80f2df1356f3b182b4a0_59856_bcfd4873549d287336aebfe578b02ec3.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在我们的迁移方案中，我们考虑引入DNS寻址方式。除了前面说的DNS是支持度最好，使用最普遍的寻址方式，在所有的编程语言和平台上都可以支持之外，我们还希望将DNS寻址方式作为未来产品的长期方向：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在SOFAMesh和SOFAMosn中，我们已经基于名为x-protocol的方式实现了DNS通用寻址方式，用来解决Dubbo/HSF/SOFA等传统SOA服务模型在Service Mesh下的访问问题 （备注: 具体内容请见我的博客文章 &lt;a href=&#34;https://skyao.net/post/201809-xprotocol-common-address-solution/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;SOFAMesh中的多协议通用解决方案x-protocol介绍系列(1)-DNS通用寻址方案&lt;/a&gt; )&lt;/li&gt;
&lt;li&gt;未来在我们的serverless产品中，我们希望可以为运行其上的Function提供DNS寻址支持&lt;/li&gt;
&lt;li&gt;可能还会有其他更加广泛的使用场景。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，在我们的演进过程中，对于客户端SDK，我们有这样一个思路：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一方面简化原有的SDK，去除和Sidecar重复的内容（满足短期需求）&lt;/li&gt;
&lt;li&gt;另一方面，考虑到必然有一次客户端SDK的更换过程，那么我们希望在简化的同时引入基于DNS的通用寻址方式，以便在未来的后续迁移和功能扩展中可以依托这个机制来实现 （符合长期目标）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt14_hub3a6bb960025fe8b7335572d7f19aa40_68558_e675af773f1add7ee211068a341b5d1b.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt14_hub3a6bb960025fe8b7335572d7f19aa40_68558_76a16418400f80986e535bcf1542de4b.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt14_hub3a6bb960025fe8b7335572d7f19aa40_68558_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt14_hub3a6bb960025fe8b7335572d7f19aa40_68558_e675af773f1add7ee211068a341b5d1b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;图中描述的是在Service Mesh下，客户端通过域名来指定要访问的目标服务，然后通过DNS解析机制来串联底层的服务注册/DNS记录更新/透明劫持传递原始信息/Sidecar查找路由目标等详细实现机制。&lt;/p&gt;
&lt;p&gt;这里仅做简单示意，我就不详细展开了。在接下来的内容中，我的同事，来自UC基础研发部的 龙轼 同学，将为大家详细的展开DNS寻址方案的细节实现。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt15_hud470c33c47515ae6105b67d8bfd23b88_124241_7c9ea60184f30e50897c161ef7b67f60.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt15_hud470c33c47515ae6105b67d8bfd23b88_124241_1fefa0266e14092faec4369e3666cc88.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt15_hud470c33c47515ae6105b67d8bfd23b88_124241_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt15_hud470c33c47515ae6105b67d8bfd23b88_124241_7c9ea60184f30e50897c161ef7b67f60.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;大家好，我是来自UC基础研发部的龙轼。 感谢小剑老师给我们介绍了蚂蚁和UC共建的Service Mesh的演进路线和实现平滑迁移的关键。&lt;/p&gt;
&lt;p&gt;接下来由我来向大家分享下实现平滑迁移的关键中的DNS寻址方案的演进。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt16_hud82207c1075584b0aceb8a88afe2aecd_71464_572b5a0da66c2344906090cd29add598.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt16_hud82207c1075584b0aceb8a88afe2aecd_71464_7c100dbc201fb19cf9bf4b65165e11b5.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt16_hud82207c1075584b0aceb8a88afe2aecd_71464_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt16_hud82207c1075584b0aceb8a88afe2aecd_71464_572b5a0da66c2344906090cd29add598.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;大家可以看上面的所示的DNS寻址方案的演进，我们先了解下各个服务寻址方案的背景。&lt;/p&gt;
&lt;p&gt;从 SOA 的寻址，到 Kubernetes 的寻址，然后再到 Istio 的寻址，最后是我们的 SOFAMesh 的DNS寻址方案。&lt;/p&gt;
&lt;p&gt;它们的寻址方案有什么不同，我们将一一分析它们的细节和总体寻址方案的演进路线。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt17_hu62b437b550cd3e4080f2e6cd342c3606_51731_2856d54ba4a7b39bff2634dd56ac1e64.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt17_hu62b437b550cd3e4080f2e6cd342c3606_51731_0385b870409b8d80027042b6847350d3.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt17_hu62b437b550cd3e4080f2e6cd342c3606_51731_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt17_hu62b437b550cd3e4080f2e6cd342c3606_51731_2856d54ba4a7b39bff2634dd56ac1e64.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;现在大家可以先来看下 SOA 架构下基于服务注册和服务发现的寻址。&lt;/p&gt;
&lt;p&gt;我们可以看到图中的 SOA 其实是单进程多接口的，依赖于 SOA 的服务注册与服务发现的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt18_huf29c3a7c78837f118fe598cd892ab795_53900_f9c56129d0ec98a671a8e7000023d061.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt18_huf29c3a7c78837f118fe598cd892ab795_53900_4e49944bb644274eab0a7474babcd587.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt18_huf29c3a7c78837f118fe598cd892ab795_53900_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt18_huf29c3a7c78837f118fe598cd892ab795_53900_f9c56129d0ec98a671a8e7000023d061.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;接下来我们看下 Kubernetes 的 DNS 寻址方式，它的寻址方式其实是通过DNS 的。&lt;/p&gt;
&lt;p&gt;从图中我们可以看到部署到K8S 上面的userservice 服务会生成一条DNS记录指向K8S 的ClusterIP。&lt;/p&gt;
&lt;p&gt;我们在 Pod 里面发起请求时通过 DNS 的 SearchDomain 域名补全规则就会从 DNS 里面查询得到ClusterIP，我们可以看出 Kubernetes 的寻址方案是单进程单接口的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt19_huade3a2fd9dba856ea2d57c55721265f8_59858_95af15deae43380d33329342899cf547.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt19_huade3a2fd9dba856ea2d57c55721265f8_59858_2a0fa68f44cb7eb080bbc2d4352175d8.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt19_huade3a2fd9dba856ea2d57c55721265f8_59858_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt19_huade3a2fd9dba856ea2d57c55721265f8_59858_95af15deae43380d33329342899cf547.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;看完 Kubernetes 的服务发现之后我们继续来看 Istio 的服务发现。&lt;/p&gt;
&lt;p&gt;从图中我们可以看出之前的流程都和 K8S 一脉相承，不同的地方在于 Istio 里面有个 SideCar 它把ClusterIP 拿到之后根据 ClusterIP 从 VirtualHost 里面匹配到 Rule 规则 转发给目标的 Pod 地址。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt20_hu4c613ddf7eb67e930104256cff925770_47104_e1d8d4dac05818b72e37013132f6803d.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt20_hu4c613ddf7eb67e930104256cff925770_47104_13f32588e6df93ba5901e35ecc4395a2.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt20_hu4c613ddf7eb67e930104256cff925770_47104_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt20_hu4c613ddf7eb67e930104256cff925770_47104_e1d8d4dac05818b72e37013132f6803d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最后我们来看下 SOFAMesh 的 DNS 通用寻址方案。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;根据我们之前分析的 SOA 寻址方案和 Kubernetes 寻址方案，我们可以看出如果我们的微服务不经过拆分和改造想上 Service Mesh 的话我们需要支持SOA之前的那种单个Pod 多个接口的。&lt;/li&gt;
&lt;li&gt;从图中看就是我们需要支持 &lt;code&gt;com.alipay.userservice.interface1&lt;/code&gt;, &lt;code&gt;com.alipay.userservice.interface2&lt;/code&gt; 这些接口解析到 ClusterIP, 我们知道k8s 中的service 是不支持的。&lt;/li&gt;
&lt;li&gt;那该如何是好，我们只能在DNS 上做文章修改DNS的记录来实现这一功能。确定了这一方案之后我们来看下我们设计的DNS寻址方案实现细节。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt21_hu0b4bc899343d83b2ac9bafa3a9687ba0_47859_2c8fc4e306e093cf7611b785d8fb5d2f.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt21_hu0b4bc899343d83b2ac9bafa3a9687ba0_47859_177d830411319caa06ba525f279b6326.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt21_hu0b4bc899343d83b2ac9bafa3a9687ba0_47859_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt21_hu0b4bc899343d83b2ac9bafa3a9687ba0_47859_2c8fc4e306e093cf7611b785d8fb5d2f.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;大家看这张图:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;我们用 CRD 定义了一个 RPCService 和之前的 Service 有同样的 selector 的标签。&lt;/li&gt;
&lt;li&gt;然后用 RPC Service Controller 对 RPCService 做 Watch，当 RPCService 有更新的时候我们就把接口就是上述的 &lt;code&gt;com.alipay.userservice.interface1&lt;/code&gt; 的记录写入 CoreDNS 里面&lt;/li&gt;
&lt;li&gt;而 interface 是通过 Pod 里面的 Register Agent 来获取 Dubbo 里面暴露的。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt22_hu6c4402dae2f39b22bef771ffcc4f3ea0_35751_8b61322476a733d5b3f00b4c8d396b49.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt22_hu6c4402dae2f39b22bef771ffcc4f3ea0_35751_3284f86dc8ffe4a33d982be3144dbea3.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt22_hu6c4402dae2f39b22bef771ffcc4f3ea0_35751_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt22_hu6c4402dae2f39b22bef771ffcc4f3ea0_35751_8b61322476a733d5b3f00b4c8d396b49.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;好的，说完这个方案的细节之后。我们可以看出其实其他的问题都不大，但是要更新DNS的这个我们需要支持。&lt;/p&gt;
&lt;p&gt;一开始我们 K8S 集群里面是用 Kube-DNS 来做 DNS 寻址的，但我们看这张 Kube-DNS 的架构图。&lt;/p&gt;
&lt;p&gt;可以看出修改它成本是比较大的，而且所有的DNS 都在同一个域里面，这个风险系数很高。 如果一旦修改错误势必会影响到之前的 k8s 的 service，导致线上的故障。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt23_huf59721f4eeaa84fb2e8f7e4e3b0b6ef3_98051_1d9ed0b000b7499de9371bd7cd572578.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt23_huf59721f4eeaa84fb2e8f7e4e3b0b6ef3_98051_0ae3b886a62db39708c10ada51ad064f.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt23_huf59721f4eeaa84fb2e8f7e4e3b0b6ef3_98051_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt23_huf59721f4eeaa84fb2e8f7e4e3b0b6ef3_98051_1d9ed0b000b7499de9371bd7cd572578.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;这个时候我们跟踪到社区的 CoreDNS 项目，我们来看下 CoreDNS 的具体的架构。  它采用作为 Web 服务器 Caddy 的服务器框架，延用了Caddy 中的插件机制，大大的增加了 CoreDNS 的灵活性。&lt;/li&gt;
&lt;li&gt;它的插件机制也特别简单，把所有的插件注册进一个Map里面来，在调用的时候从Map拿出他们有共同接口的函数。有兴趣的同学可以看下 Caddy 的插件代码实现。&lt;/li&gt;
&lt;li&gt;它的 DNS 协议库采用是由 Google 工程师 Meikg 开发的 DNS 库，他同时也是 SkyDNS 的开发者。&lt;/li&gt;
&lt;li&gt;后端可以采用 UDP/TCP、TLS 或者 gRPC 作为后端数据查询。上面有个Google工程师用 gRPC 做了一个 CoreDNS 插件的后端数据查询例子，有兴趣的同学可以看下。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt24_hu10985cbc7795d88daf3c0abe3ea1cbb5_153002_0a32ae39bd6b48da525699e6b96964b7.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt24_hu10985cbc7795d88daf3c0abe3ea1cbb5_153002_689c941e89aa50f5eca47d89d5683065.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt24_hu10985cbc7795d88daf3c0abe3ea1cbb5_153002_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt24_hu10985cbc7795d88daf3c0abe3ea1cbb5_153002_0a32ae39bd6b48da525699e6b96964b7.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;OK，既然 CoreDNS 的 Plugins 这么强大，我们可不可以用它来实现我们刚才说到的 Renew DNS的机制。 答案很显然是可以。&lt;/p&gt;
&lt;p&gt;我们看下上面的图，实现CoreDNS 的插件很简单，只需要继承上面的接口就可以了。 CoreDNS 官网有具体的教程在教我们怎么写一个插件。这个就不具体的展开了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt25_hu57ba450a0e317e904d50dc8b95ee378c_61579_21c6f0dd11ee8d6efa56c3206d25470c.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt25_hu57ba450a0e317e904d50dc8b95ee378c_61579_f0c5738ac3ae4f4c5f9b95cdc4b029a3.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt25_hu57ba450a0e317e904d50dc8b95ee378c_61579_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt25_hu57ba450a0e317e904d50dc8b95ee378c_61579_21c6f0dd11ee8d6efa56c3206d25470c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;到了我们最关键的点了：我们应该怎么更新我们的DNS。其实这点 CoreDNS 社区里面已经有人提出需求用 REST API 的形式提供更新 DNS 的接口。&lt;/li&gt;
&lt;li&gt;互联网任务工程小组也早在 rfc2136 定义了标准的 DNS UPDATE。 Google Cloud 和AWS 都有相应的实现。&lt;/li&gt;
&lt;li&gt;CoreDNS 社区其实已经把接口实现了，但是后端存储是基于file 的，数据没有落地。 蚂蚁和UC 这边扩展了 ETCD 插件的接口，把对应 DNS UPDATE 接口给实现了，实现 DNS 数据写入ETCD 里面。&lt;/li&gt;
&lt;li&gt;从图中我们可以看到 &lt;code&gt;rpc.cluster.local&lt;/code&gt; 这个域 和 k8s 域 cluster.local 是在不同的插件链上的。
这样在k8s域中没有 dynapirest 插件，我们就不能对k8s域中的DNS进行更新，这样就把之前Kube-DNS改造之后会对k8s域里面造成影响给去除了，更加的安全。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt26_hub59f88a5845a196f5a463a9b0fcc5aa4_231132_7ae086eb4af7c95b727b21ca68cd3553.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt26_hub59f88a5845a196f5a463a9b0fcc5aa4_231132_f55ec8eff8243e169aeba87c547675fc.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt26_hub59f88a5845a196f5a463a9b0fcc5aa4_231132_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt26_hub59f88a5845a196f5a463a9b0fcc5aa4_231132_7ae086eb4af7c95b727b21ca68cd3553.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们可以看下 CoreDNS 后端存储的接口，其实和我们之前对数据操作的接口是没有什么差别的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt27_hu979e3f675c0d1b4824edea11acd4fca6_104921_c562c143f97764ef856edc0754f37369.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt27_hu979e3f675c0d1b4824edea11acd4fca6_104921_6e4d442d1ed3a2e9ed51ae4591dd4f8d.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt27_hu979e3f675c0d1b4824edea11acd4fca6_104921_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt27_hu979e3f675c0d1b4824edea11acd4fca6_104921_c562c143f97764ef856edc0754f37369.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;目前 CoreDNS 的 DynAPI 还在主库代码没合并的状态。之后 DynAPI 这个项目会独立成一个插件项目。我们可以看下 CoreDNS 社区的 DynAPI 插件进展。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt28_hue0e862615f6c09b2c5cdf226edffe85d_126981_70e170893b4eb4c88016f4f9c0662f0d.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt28_hue0e862615f6c09b2c5cdf226edffe85d_126981_b4fa7309c80cf74fba42b24ffec4082f.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt28_hue0e862615f6c09b2c5cdf226edffe85d_126981_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt28_hue0e862615f6c09b2c5cdf226edffe85d_126981_70e170893b4eb4c88016f4f9c0662f0d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;OK，我们来看下我们的DynAPI 实现DNS 更新的一个效果。从图中我们可以看出 record.json 里面的一个域名的更新。通过 DynAPI 我们成功把 record.json 的DNS 记录给更新进去并且dns正常工作了。到现在我们通过CoreDNS 的插件就把DNS 更新的需求给解决了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt29_huaf00b3350f9360d8e197a1b30f22364d_60195_3f24822c14e3fa1a93925d7c0d7b5e2a.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt29_huaf00b3350f9360d8e197a1b30f22364d_60195_722ebc61d9e66a4374ce50c86feb17b7.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt29_huaf00b3350f9360d8e197a1b30f22364d_60195_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt29_huaf00b3350f9360d8e197a1b30f22364d_60195_3f24822c14e3fa1a93925d7c0d7b5e2a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;其实CoreDNS 官网还有许多有趣的插件，可以丰富 CoreDNS 的功能和提升 CoreDNS 的性能。 大家可以看下中间的 autopath 插件，他把我们多次的在 searchdomain 拼凑的 DNS 记录的查询在在服务器上给实现了。 避免了多次的 Client 端和 Server 端的数据交互。有兴趣的同学可以看下 [A-Deep-Dive-into-CoreDNS-2018] (&lt;a href=&#34;https://github.com/coredns/presentations/blob/master/A-Deep-Dive-into-CoreDNS-2018.pdf&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/coredns/presentations/blob/master/A-Deep-Dive-into-CoreDNS-2018.pdf&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt30_huc20336f9e777f9f6515adbc9c99f4146_56099_6470c115515f9a8250c60acba6fb6d7e.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt30_huc20336f9e777f9f6515adbc9c99f4146_56099_f5f3d188a46215b7d1e6acd6eb7ec681.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt30_huc20336f9e777f9f6515adbc9c99f4146_56099_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt30_huc20336f9e777f9f6515adbc9c99f4146_56099_6470c115515f9a8250c60acba6fb6d7e.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们把 CoreDNS 的功能开发完了，上线的话很多人关注它的性能。 我们这边做了一个简单的性能测试，可以看出 CoreDNS 和 Bind DNS 这种现在比较通用的DNS的性能还是有点差距的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt31_hu9fe943c105e12b9e14ec24ca69a9103c_245619_c028b317e04bc4f9dfc4c9cdbcc0d9fb.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt31_hu9fe943c105e12b9e14ec24ca69a9103c_245619_02a49bd5e3edc87b5d00bf652504f156.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt31_hu9fe943c105e12b9e14ec24ca69a9103c_245619_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt31_hu9fe943c105e12b9e14ec24ca69a9103c_245619_c028b317e04bc4f9dfc4c9cdbcc0d9fb.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;但是,我们通过上面的图可以看到在一定的QPS 下，CoreDNS 的延时是很低的。 我们可以看到所有的延时都落在4ms 之内。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt32_hued6fb6c99353e2685d64a0ad9dfa825d_78120_8d2c5e2d6aee48a3053949011878d059.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt32_hued6fb6c99353e2685d64a0ad9dfa825d_78120_c4939340e93a8ba25aa8c16590aefcc4.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt32_hued6fb6c99353e2685d64a0ad9dfa825d_78120_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt32_hued6fb6c99353e2685d64a0ad9dfa825d_78120_8d2c5e2d6aee48a3053949011878d059.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;为了解决QPS的问题，我们通过 Kubernetes 的 HPA 给 CoreDNS 进行横向的扩展。&lt;/p&gt;
&lt;p&gt;一开始我们只是通过CPU的维度给 CoreDNS 扩展，但发现波动有点大。 之后我们切换成通过QPS的维度来进行扩容。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt33_hue848a0345f9897f84479e9a448aa22e9_37351_95ca2610f108345e09203cfa46967105.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt33_hue848a0345f9897f84479e9a448aa22e9_37351_526e81167ae348a1a483919ab727fbb6.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt33_hue848a0345f9897f84479e9a448aa22e9_37351_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt33_hue848a0345f9897f84479e9a448aa22e9_37351_95ca2610f108345e09203cfa46967105.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;CoreDNS 将会在Kubernetes 1.13 之后成为 Kubernetes 的默认的DNS服务。我们将会紧跟社区实施我们的方案并且反馈给社区。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt34_huc1479c55041df496034ff380a94f6a7a_123724_9f586e4ac80df99997d108e44da67745.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt34_huc1479c55041df496034ff380a94f6a7a_123724_782772a64cac4ebcec728e34e8956c80.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt34_huc1479c55041df496034ff380a94f6a7a_123724_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt34_huc1479c55041df496034ff380a94f6a7a_123724_9f586e4ac80df99997d108e44da67745.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们再来看下我们后续的一些规划。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt35_hu1b860e785360ba484c11ba90c9f16b75_62710_9aafaed255e787ecde98fd07676cbc6c.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt35_hu1b860e785360ba484c11ba90c9f16b75_62710_f8ea08cf71a680273046b3297f4085e3.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt35_hu1b860e785360ba484c11ba90c9f16b75_62710_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt35_hu1b860e785360ba484c11ba90c9f16b75_62710_9aafaed255e787ecde98fd07676cbc6c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;可以看到我们的 DynAPI 其实在安全上还是有欠缺的。我们后续会把 HTTP 加强成 HTTPS 协议来增强 DynAPI 的安全性。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt36_hu5351b28216fb9260387eb39d140820e3_111055_9c0cd3a0e6b36a6347f8722c19112661.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt36_hu5351b28216fb9260387eb39d140820e3_111055_58aeb90018fec5489996084274c1e4a3.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt36_hu5351b28216fb9260387eb39d140820e3_111055_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt36_hu5351b28216fb9260387eb39d140820e3_111055_9c0cd3a0e6b36a6347f8722c19112661.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;还有如果我们 CoreDNS 的后端变化的更新的 Watch 由于 Watch的范围过大的话，会返回过多的数据。这样会影响到 Watch 的性能，CoreOS 在 ETCD3.2 增加了proxy 可以让我们根据不同的 ETCD KeySpace 去Watch,这样大大的提高了Watch的性能。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt37_hu45e37938a52ab4391622193d77c61bd3_46451_2096bc429abba86f2e0c4b0f9e4c0bf5.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt37_hu45e37938a52ab4391622193d77c61bd3_46451_25c36aff32cf43f4dc13e9830c97d255.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt37_hu45e37938a52ab4391622193d77c61bd3_46451_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt37_hu45e37938a52ab4391622193d77c61bd3_46451_2096bc429abba86f2e0c4b0f9e4c0bf5.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最后一个，我们建议在创建 Kubernetes 集群的时候把 idc 的信息给带进Kubernetes的后缀域名中。这样我们之后可以通过 kubernetai 插件把不同的 Kubernetes 集群的域名进行整合通过本 IDC 缓存提高跨 IDC DNS 的访问速度。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt38_hud0d144dfcd32198c1aca188e0de20250_123871_9a6bef3cfbb09cdb21c1ea2a6751d174.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt38_hud0d144dfcd32198c1aca188e0de20250_123871_a650f5f366c718a2ac4319f9e3da998e.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt38_hud0d144dfcd32198c1aca188e0de20250_123871_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt38_hud0d144dfcd32198c1aca188e0de20250_123871_9a6bef3cfbb09cdb21c1ea2a6751d174.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-service-mesh-step-by-step/images/ppt39_hu09330c52a93d620f5bf7c9bf927a4820_74215_7867e28de265fd7751a080e17fc675e9.webp 400w,
               /talk/201811-service-mesh-step-by-step/images/ppt39_hu09330c52a93d620f5bf7c9bf927a4820_74215_b4161d89d2e1d3a1a05894c87aded4cf.webp 760w,
               /talk/201811-service-mesh-step-by-step/images/ppt39_hu09330c52a93d620f5bf7c9bf927a4820_74215_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-service-mesh-step-by-step/images/ppt39_hu09330c52a93d620f5bf7c9bf927a4820_74215_7867e28de265fd7751a080e17fc675e9.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最后我们总结下，总体方面小剑老师给我们讲了蚂蚁金服主站 Service Mesh 的渐进式演进路线和实现平滑迁移的几个关键。 具体细节方面我们通过CoreDNS 的单点突破解决了 SOFAMesh 的 DNS 寻址的问题。&lt;/p&gt;
&lt;p&gt;感谢大家，希望这次演讲能让大家有所收获。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Knative: 重新定义Serverless</title>
      <link>https://skyao.net/talk/201811-knative-redefine-serverless/</link>
      <pubDate>Sat, 24 Nov 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/201811-knative-redefine-serverless/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt1_hud5e27f22917738697b23de14ca5ba564_90293_769375a43b5e4ad379eca4fceafd9fec.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt1_hud5e27f22917738697b23de14ca5ba564_90293_ada006a86bbfd05a1686e582e57b1cc1.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt1_hud5e27f22917738697b23de14ca5ba564_90293_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt1_hud5e27f22917738697b23de14ca5ba564_90293_769375a43b5e4ad379eca4fceafd9fec.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;大家好，今天给大家来的演讲专题是“Knative：重新定义Serverless”, 我是来自蚂蚁金服中间件的敖小剑。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt2_hu33fccdfd961625f7b2badeeb9ce237f9_204217_020b9045941ce47cc055d8ea9f4ebe7c.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt2_hu33fccdfd961625f7b2badeeb9ce237f9_204217_946667629033634dcef3a988099e84dc.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt2_hu33fccdfd961625f7b2badeeb9ce237f9_204217_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt2_hu33fccdfd961625f7b2badeeb9ce237f9_204217_020b9045941ce47cc055d8ea9f4ebe7c.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是我的个人资料，有兴趣的同学可以关注的我的个人技术博客网站 &lt;a href=&#34;https://skyao.net&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt3_hub658d45dd3f4007e9de58937ac24b9ff_90320_eabcc9a12004b9b669b6abd1b31db802.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt3_hub658d45dd3f4007e9de58937ac24b9ff_90320_aecc60d8881594e517bf42619f3e3909.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt3_hub658d45dd3f4007e9de58937ac24b9ff_90320_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt3_hub658d45dd3f4007e9de58937ac24b9ff_90320_eabcc9a12004b9b669b6abd1b31db802.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这次演讲的内容将会有这些，首先给大家介绍一下knative是什么，然后是knative的主要组件，让大家对knative有一个基本的了解。之后我会简单的对knative做一些分析和探讨，以及介绍一下knative后续的发展。希望本次的内容让大家能够对knative有一个基本的认知。&lt;/p&gt;
&lt;h2 id=&#34;什么是knative&#34;&gt;什么是knative？&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt4_hu3249e3ff9830517ff75ade1e84466611_33529_46b2e20f67dc0226ea015e4e1b2c4e1a.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt4_hu3249e3ff9830517ff75ade1e84466611_33529_a8c589082bac0e35850bfcdce5f4ca16.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt4_hu3249e3ff9830517ff75ade1e84466611_33529_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt4_hu3249e3ff9830517ff75ade1e84466611_33529_46b2e20f67dc0226ea015e4e1b2c4e1a.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Knative是Google牵头发起的 serverless 项目。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt5_hu81b002ec20612c749aad4c03a3ef673e_69692_e3c6c48d6cf3a0666f00f1cf416b73c2.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt5_hu81b002ec20612c749aad4c03a3ef673e_69692_74331cecd10f0c5e1a2d9bf736f7318b.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt5_hu81b002ec20612c749aad4c03a3ef673e_69692_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt5_hu81b002ec20612c749aad4c03a3ef673e_69692_e3c6c48d6cf3a0666f00f1cf416b73c2.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是Knative的项目定义，注意这句话里面几个关键字：kubernetes，serverless，workload。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt6_hu69d5f65ff9dd464f3ee56d346061aec7_65268_f52c819165535f5fa4171e8f9366a8dc.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt6_hu69d5f65ff9dd464f3ee56d346061aec7_65268_8c7676edc1dcd7b482837b54556c3142.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt6_hu69d5f65ff9dd464f3ee56d346061aec7_65268_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt6_hu69d5f65ff9dd464f3ee56d346061aec7_65268_f52c819165535f5fa4171e8f9366a8dc.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是最近几年 Google 做大型项目的常态：产品刚出来，阵营就已经很强大了，所谓先声夺人。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt7_hue1ba5865e62b2fe43bc63d7b6b20f379_30733_8e322d8b3e6d6fdb9bf84c1db369067f.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt7_hue1ba5865e62b2fe43bc63d7b6b20f379_30733_1e2d84b4a4ec23564e8dbd4e626d0094.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt7_hue1ba5865e62b2fe43bc63d7b6b20f379_30733_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt7_hue1ba5865e62b2fe43bc63d7b6b20f379_30733_8e322d8b3e6d6fdb9bf84c1db369067f.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是目前Knative项目的进展，可以看到这是一个非常新的项目，刚刚起步。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：这是截至2018-11-24演讲当天的情况，到2018年12月底，knative已经发布了v0.2.2和v0.2.3两个bugfix版本。但也还只是 0.2 &amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt8_hue94a5a9e9c1f30ae4548565c76e1fe3a_33168_a459c0dcbe648dfbf8bc057d1736c024.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt8_hue94a5a9e9c1f30ae4548565c76e1fe3a_33168_aae3bc36222bbc255f2aaba770550a8a.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt8_hue94a5a9e9c1f30ae4548565c76e1fe3a_33168_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt8_hue94a5a9e9c1f30ae4548565c76e1fe3a_33168_a459c0dcbe648dfbf8bc057d1736c024.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们来看一下，在knative出来前， serverless 领域已有的实现，包括云端提供的产品和各种开源项目。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt9_hu62d6bc2faf69270269a323411f081408_278605_f490a46f041076d9e12094477dd15864.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt9_hu62d6bc2faf69270269a323411f081408_278605_facd1048c8d3fc74d95a38eeb723d503.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt9_hu62d6bc2faf69270269a323411f081408_278605_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt9_hu62d6bc2faf69270269a323411f081408_278605_f490a46f041076d9e12094477dd15864.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这幅图片摘自The New Stack的一个serverless 调查，我们忽略调查内容，仅仅看看这里列出来的serverless产品的数量——感受是什么？好多serverless项目，好多选择！&lt;/p&gt;
&lt;p&gt;那问题来了：到底该怎么选？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt10_huccd0c0303abc817de439dea7ab440c0a_93240_e1a6516f76582dd83f3841cc8da2e163.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt10_huccd0c0303abc817de439dea7ab440c0a_93240_dadb121b9e06e11d134ea8999f650118.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt10_huccd0c0303abc817de439dea7ab440c0a_93240_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt10_huccd0c0303abc817de439dea7ab440c0a_93240_e1a6516f76582dd83f3841cc8da2e163.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这就是目前 serverless 的问题：由于缺乏标准，市场呈现碎片化。不同厂商，不同项目，各不相同，因此无论怎么选择，都面临一个风险：供应商绑定！&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt11_hu5ff35aae7e266432f51aa80f34ffc76f_37831_12f3184a6e3526c3406cf6a9e57ba0f9.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt11_hu5ff35aae7e266432f51aa80f34ffc76f_37831_cb4b23325dd8cf0166dfa96c2ed03a24.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt11_hu5ff35aae7e266432f51aa80f34ffc76f_37831_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt11_hu5ff35aae7e266432f51aa80f34ffc76f_37831_12f3184a6e3526c3406cf6a9e57ba0f9.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这段话来自 knative 的官方介绍，google 推出 knative 的理由和动机。其中第一条和第二条针对的是当前 serverless 市场碎片的现状。而第四条多云战略，则是针对供应商绑定的风险。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt12_huea54707d8a6a224ddecf737653772547_66591_2bea1d891e9e47c00ab9124ab22517fe.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt12_huea54707d8a6a224ddecf737653772547_66591_2be343207b790824326d51d561c5e233.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt12_huea54707d8a6a224ddecf737653772547_66591_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt12_huea54707d8a6a224ddecf737653772547_66591_2bea1d891e9e47c00ab9124ab22517fe.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;google描述knative的动机之一，是将云原生中三个领域的最佳实践结合起来。&lt;/p&gt;
&lt;p&gt;小结：&lt;/p&gt;
&lt;p&gt;当前 serverless 市场产品众多导致碎片化严重，存在厂商绑定风险，而 google 推出 knative ，希望能提供一套简单易用的 serverless 方案，实现 serverless 的标准化和规范化。&lt;/p&gt;
&lt;h2 id=&#34;knative的主要组件&#34;&gt;Knative的主要组件&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt13_huea4256810d07992124e736755e361c35_91025_66506908939088e16f579ee3067e535b.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt13_huea4256810d07992124e736755e361c35_91025_31c3d3eff85a5c15bda24e19829bc970.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt13_huea4256810d07992124e736755e361c35_91025_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt13_huea4256810d07992124e736755e361c35_91025_66506908939088e16f579ee3067e535b.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第二部分，来介绍一下knative的主要组件。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt14_hu40bdc740882e5f645b2c9e58de34562b_67101_7ab52c53085d4ca3e272f728640708f7.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt14_hu40bdc740882e5f645b2c9e58de34562b_67101_621a262c9d5e98a2be660e41aad4a85c.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt14_hu40bdc740882e5f645b2c9e58de34562b_67101_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt14_hu40bdc740882e5f645b2c9e58de34562b_67101_7ab52c53085d4ca3e272f728640708f7.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;前面提到，google 推出 knative ，试图将云原生中三个领域的最佳实践结合起来。反应到 knative 产品中，就是这三大主要组件：Build，Serving，Eventing。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt15_hu1fe2f546077a2403375c05f07dea52d7_41166_65b46dbeb4c48fce852cd05ebdfd097f.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt15_hu1fe2f546077a2403375c05f07dea52d7_41166_34cc147bd83d7b8d753e84021414637b.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt15_hu1fe2f546077a2403375c05f07dea52d7_41166_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt15_hu1fe2f546077a2403375c05f07dea52d7_41166_65b46dbeb4c48fce852cd05ebdfd097f.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Knative Build 组件，实现从代码到容器的目标。为什么不直接使用 dockfile 来完成这个事情？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt16_hu833baec127c4848fd145d10e228729da_60108_c5c7c85b92e8c08a2b84fd075f28af28.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt16_hu833baec127c4848fd145d10e228729da_60108_404a0ca7172f487c2e6d68c95fab5f9f.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt16_hu833baec127c4848fd145d10e228729da_60108_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt16_hu833baec127c4848fd145d10e228729da_60108_c5c7c85b92e8c08a2b84fd075f28af28.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Knative Build 在实现时，是表现为 kubernetes 的 CRD，通过 yaml 文件来定义构建过程。这里引入了很多概念如：build，builder，step，template，source等。另外支持用 service account 做身份验证。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt17_huefd2f46a92d88d005a0cf7cf69bc9b6d_49336_df79df99fdf0ef8d6af3f6ccfbe4a340.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt17_huefd2f46a92d88d005a0cf7cf69bc9b6d_49336_f9a5445a3652afda38ee366292a77ff4.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt17_huefd2f46a92d88d005a0cf7cf69bc9b6d_49336_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt17_huefd2f46a92d88d005a0cf7cf69bc9b6d_49336_df79df99fdf0ef8d6af3f6ccfbe4a340.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Knative Serving组件的职责是运行应用以对外提供服务，即提供服务、函数的运行时支撑。&lt;/p&gt;
&lt;p&gt;注意定义中的三个关键：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;kubernetes-based：基于k8s，也仅支持k8s，好处是可以充分利用k8s平台的能力&lt;/li&gt;
&lt;li&gt;scale-to-zero：serverless 最重要的卖点之一，当然要强调&lt;/li&gt;
&lt;li&gt;request-driven compute：请求驱动的计算&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;值得注意的是，除了k8s之外，还有另外一个重要基础：istio！后面会详细聊这个。&lt;/p&gt;
&lt;p&gt;Knative Serving项目同样也提供了自己的中间件原语，以支持如图所示的几个重要特性。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt18_hu9d7fa6307fef20f1393ce57bb57515aa_64729_ea253d6b19ecadc83ea39643f5ac0cca.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt18_hu9d7fa6307fef20f1393ce57bb57515aa_64729_5b8b822e44acf7c25e782c7c6e681489.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt18_hu9d7fa6307fef20f1393ce57bb57515aa_64729_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt18_hu9d7fa6307fef20f1393ce57bb57515aa_64729_ea253d6b19ecadc83ea39643f5ac0cca.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;knative中有大量的概念抽象，而在这之后的背景，说起来有些意思：knative 觉得 kubernetes 和 istio 本身的概念非常多，多到难于理解和管理，因此 knative 决定要自己提供更高一层的抽象。至于这个做法，会是釜底抽薪解决问题，还是雪上加霜让问题更麻烦&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;knative的这些抽象都是基于 kubernetes 的 CRD 来实现，具体抽象概念有：Service、Route、Configuration 和 Revision。特别提醒的是，右边图中的 Service 是 knative 中的 service 概念，&lt;code&gt;service.serving.knative.dev&lt;/code&gt;，而不是大家通常最熟悉的 k8s 的 service。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt19_hu1cffbdde6f13a3b53f0ed8ded41c1af8_58789_7c110299997fd2ddfee9e1937cac775d.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt19_hu1cffbdde6f13a3b53f0ed8ded41c1af8_58789_7ae531fca33ef514dcddf0398282f6e6.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt19_hu1cffbdde6f13a3b53f0ed8ded41c1af8_58789_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt19_hu1cffbdde6f13a3b53f0ed8ded41c1af8_58789_7c110299997fd2ddfee9e1937cac775d.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对于Knative Serving 组件，最重要的特性就是自动伸缩的能力。目前伸缩边界支持从0到无限，容许通过配置设置。&lt;/p&gt;
&lt;p&gt;Knative 目前是自己实现的 autoscaler ，原来比较简单：Revision 对应的pod由 k8s deployment 管理，pod上的工作负载上报 metrics，汇总到 autoscaler 分析判断做决策，在需要时修改 replicas 数量来实现自动伸缩（后面会再讲这块存在的问题）。&lt;/p&gt;
&lt;p&gt;当收缩到0，或者从0扩展到1时，情况会特别一些。knative在这里提供了名为 Activator 的设计，如图所示：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Istio Route 控制流量走向，正常情况下规则设置为将流量切到工作负载所在的pod&lt;/li&gt;
&lt;li&gt;当没有流量，需要收缩到0时，规则修改为将流量切到 Activator ，如果一直没有流量，则什么都不发生。此时autoscaler 通过 deployment 将 replicas 设置为0。&lt;/li&gt;
&lt;li&gt;当新的流量到来时，流量被 Activator 接收，Activator 随即拉起 pod，在 pod 和工作负载准备好之后，再将流量转发过去&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt20_hu8c5025719f2e901e3d91742f4e6e7d37_39937_b723869dd15f9ca9a0a363eca1f59dcb.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt20_hu8c5025719f2e901e3d91742f4e6e7d37_39937_f5cb97747750e7c564f4eaa90b84abf2.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt20_hu8c5025719f2e901e3d91742f4e6e7d37_39937_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt20_hu8c5025719f2e901e3d91742f4e6e7d37_39937_b723869dd15f9ca9a0a363eca1f59dcb.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Knative Eventing 组件负责事件绑定和发送，同样提供多个抽象概念：Flow，Source，Bus，以帮助开发人员摆脱概念太多的负担（关于这一点，我保留意见）。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt21_hu58bf2f6343ab2cad967312aa914b9dac_44079_9d08af83339308b18e7bde3953f0e55d.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt21_hu58bf2f6343ab2cad967312aa914b9dac_44079_0ab78609ea7e130aad2fab6b87de51c5.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt21_hu58bf2f6343ab2cad967312aa914b9dac_44079_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt21_hu58bf2f6343ab2cad967312aa914b9dac_44079_9d08af83339308b18e7bde3953f0e55d.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Bus 是对消息总线的抽象。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt22_hu998acf88b62a147b2287d17eefb5c0df_41448_5e4b438145acb1d4557832e74b97511a.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt22_hu998acf88b62a147b2287d17eefb5c0df_41448_e7c68a8bd727c496306327ff7c2bc999.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt22_hu998acf88b62a147b2287d17eefb5c0df_41448_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt22_hu998acf88b62a147b2287d17eefb5c0df_41448_5e4b438145acb1d4557832e74b97511a.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Source 是事件数据源的抽象。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt23_hu9542fa584e78349988e2cd655d24a520_52961_5888b41496e40df0fa5ec8566599a56c.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt23_hu9542fa584e78349988e2cd655d24a520_52961_e7dc1a12979f38c3b025a1c81be86aec.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt23_hu9542fa584e78349988e2cd655d24a520_52961_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt23_hu9542fa584e78349988e2cd655d24a520_52961_5888b41496e40df0fa5ec8566599a56c.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Knative 在事件定义方面遵循了 cloudevents 规范。&lt;/p&gt;
&lt;p&gt;小结：&lt;/p&gt;
&lt;p&gt;简单介绍了一下 knative 中的三大组件，让大家对 knative 的大体架构和功能有个基本的认知。这次就不再继续深入 knative 的实现细节，以后有机会再展开。&lt;/p&gt;
&lt;h2 id=&#34;knative分析和探讨&#34;&gt;Knative分析和探讨&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt24_hu90e7bdae7ff46e47858f53acc8b18b3c_91134_2592442b529e0c238590477e8b506530.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt24_hu90e7bdae7ff46e47858f53acc8b18b3c_91134_2a963350f6be054e5aa0034d40edc0ad.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt24_hu90e7bdae7ff46e47858f53acc8b18b3c_91134_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt24_hu90e7bdae7ff46e47858f53acc8b18b3c_91134_2592442b529e0c238590477e8b506530.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在第三部分，我们来分析探讨一下 knative 的产品定位，顺便也聊一下为什么我们会看好 knative。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt25_hu39cd794092f2ea3e715a779ab3f71bc5_35875_a751f161f84e10430ebeaf62fda05750.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt25_hu39cd794092f2ea3e715a779ab3f71bc5_35875_79ae8e9d3ca0b0c98205a3923d5c7419.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt25_hu39cd794092f2ea3e715a779ab3f71bc5_35875_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt25_hu39cd794092f2ea3e715a779ab3f71bc5_35875_a751f161f84e10430ebeaf62fda05750.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;首先，最重要的一点是：knative &lt;strong&gt;不是&lt;/strong&gt;一个 Serverless 实现，而是一个 Serviceless 平台。&lt;/p&gt;
&lt;p&gt;也就是说，knative 不是在现有市场上的20多个 serverless 产品和开源项目的基础上简单再增加一个新的竞争者，而是通过建立一个标准而规范的 serverless 平台，容许其他 serverless 产品在 knative 上运行。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt26_huca71f408709afc5318a33a6550abb15a_46986_d9e650ed4406415e439547f549a5c3c9.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt26_huca71f408709afc5318a33a6550abb15a_46986_a070909568d35258d18867ad2b92d800.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt26_huca71f408709afc5318a33a6550abb15a_46986_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt26_huca71f408709afc5318a33a6550abb15a_46986_d9e650ed4406415e439547f549a5c3c9.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Knative 在产品规划和设计理念上也带来了新的东西，和传统 serverless 不同。工作负载和平台支撑是 knative 最吸引我们的地方。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt27_hu97fae923b056b60371f5013aadc2106d_35039_71b03c440c312b4a4b702809683b7dd5.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt27_hu97fae923b056b60371f5013aadc2106d_35039_4241c727b3449c77b9b15ea4f11980af.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt27_hu97fae923b056b60371f5013aadc2106d_35039_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt27_hu97fae923b056b60371f5013aadc2106d_35039_71b03c440c312b4a4b702809683b7dd5.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;要不要Istio？这是 knative 一出来就被人诟病和挑战的点：因为 Istio 的确是复杂度有点高。而 k8s 的复杂度，还有 knative 自身的复杂度都不低，再加上 Istio&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;关于这一点，个人的建议是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果原有系统中没有规划 Istio/Service mesh 的位置，那么为了 knative 而引入 Istio 的确是代价偏高。可以考虑用其他方式替代，最新版本的 knative 已经实现了对 Istio 的解耦，容许替换。&lt;/li&gt;
&lt;li&gt;如果本来就有规划使用 Istio/Service mesh ，比如像我们蚂蚁这种，那么 knative 对 Istio 的依赖就不是问题了，反而可以组合使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而 kubernetes + servicemesh + serverless 的组合，我们非常看好。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt28_hu39ae86871f16e63002726624323ea78b_37592_150c0464ec68584e4a87a3bf5243fdce.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt28_hu39ae86871f16e63002726624323ea78b_37592_1cc5179fd018ee6589affe1406b314dc.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt28_hu39ae86871f16e63002726624323ea78b_37592_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt28_hu39ae86871f16e63002726624323ea78b_37592_150c0464ec68584e4a87a3bf5243fdce.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;当然，knative 体系的复杂度问题是无法回避的：kubernetes，istio，knative 三者都是复杂度很高的产品， 加在一起整体复杂度就非常可观了，挑战非常大。&lt;/p&gt;
&lt;h2 id=&#34;knative后续发展&#34;&gt;Knative后续发展&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt29_hu5f496a759c74944d8c089b1194e72463_90702_ef718be003d12d3d367259615c9a716f.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt29_hu5f496a759c74944d8c089b1194e72463_90702_2091a22073c28143c16de111248cc7d4.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt29_hu5f496a759c74944d8c089b1194e72463_90702_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt29_hu5f496a759c74944d8c089b1194e72463_90702_ef718be003d12d3d367259615c9a716f.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第四个部分，我们来展望一下 knative 的后续发展，包括如何解决一些现有问题。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt30_hude7c67c528221d7d7beabc541f594d90_35716_8a9a3837868bcd430f2ae14a0448e051.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt30_hude7c67c528221d7d7beabc541f594d90_35716_4aa6060b3523ef0ea0dfe1678bd84f6b.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt30_hude7c67c528221d7d7beabc541f594d90_35716_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt30_hude7c67c528221d7d7beabc541f594d90_35716_8a9a3837868bcd430f2ae14a0448e051.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第一个问题就是性能问题。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt31_hu0a975a40130e6b18644c8d5b3f659c2b_37584_c258a72fb10cbaae67ea90465ece82b6.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt31_hu0a975a40130e6b18644c8d5b3f659c2b_37584_874bcd680401594900919b37e11ac47d.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt31_hu0a975a40130e6b18644c8d5b3f659c2b_37584_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt31_hu0a975a40130e6b18644c8d5b3f659c2b_37584_c258a72fb10cbaae67ea90465ece82b6.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Queue Proxy也是一个现存的需要替换的模块。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt32_hu9d9816707fa24a0bf42337e68d663076_44888_02cd66287cd0c68c39560971904a2814.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt32_hu9d9816707fa24a0bf42337e68d663076_44888_b85bb99d3df1ff1fd108407eb3182004.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt32_hu9d9816707fa24a0bf42337e68d663076_44888_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt32_hu9d9816707fa24a0bf42337e68d663076_44888_02cd66287cd0c68c39560971904a2814.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;前面讲过 knative 的 Autoscaler 是自行实现的，而 k8s 目前已经有比较健全原生能力： HPA 和 Custom Metrics。目前 knative 已经有计划要转而使用 k8s 的原生能力。这也符合 Cloud Native 的玩法：将基础能力下沉到 k8s 这样的基础设施，上层减负。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt33_hu6a3aa2c724406e7e7fabe2f8c9d4f7f0_33829_6f5464b7ccec09ec1b3b238b0fbf7ec9.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt33_hu6a3aa2c724406e7e7fabe2f8c9d4f7f0_33829_5099c076bb59c3c30b5f4f98b992e89e.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt33_hu6a3aa2c724406e7e7fabe2f8c9d4f7f0_33829_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt33_hu6a3aa2c724406e7e7fabe2f8c9d4f7f0_33829_6f5464b7ccec09ec1b3b238b0fbf7ec9.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;除了下沉到 k8s 之外，autoscaler还有很多细节需要在后续版本中完善。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt34_hu02fa60b6bebbe6be58407fd868564ed7_34751_e193edc26dae1e10b9f925da827f2b33.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt34_hu02fa60b6bebbe6be58407fd868564ed7_34751_21ec9edfe11a772f92b9922e2885d8a3.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt34_hu02fa60b6bebbe6be58407fd868564ed7_34751_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt34_hu02fa60b6bebbe6be58407fd868564ed7_34751_e193edc26dae1e10b9f925da827f2b33.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对事件源和消息系统的支持也远不够完善，当然考虑到目前才 0.2.0 版本，可以理解。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt35_hu5f5a506bacd5e2ac90bd6a91bcbd4920_80976_4d8d4e01b65f040e3edcd33374990b8f.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt35_hu5f5a506bacd5e2ac90bd6a91bcbd4920_80976_df6ba6167ea9c6e55bb48c2dda60b591.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt35_hu5f5a506bacd5e2ac90bd6a91bcbd4920_80976_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt35_hu5f5a506bacd5e2ac90bd6a91bcbd4920_80976_4d8d4e01b65f040e3edcd33374990b8f.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;目前 knative 还没有规划 workflow 类的产品。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt36_hu2ddb93c22420f3212a21dc31520d1fa0_46260_8ed1003be122ccf7d1732f3ecd54d41c.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt36_hu2ddb93c22420f3212a21dc31520d1fa0_46260_e441ff0f062a716a5c7ff769b3a83e82.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt36_hu2ddb93c22420f3212a21dc31520d1fa0_46260_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt36_hu2ddb93c22420f3212a21dc31520d1fa0_46260_8ed1003be122ccf7d1732f3ecd54d41c.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在网络路由能力方面也有很多欠缺，上面是 knative 在文档中列出来的需求列表。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt37_hua49f3c2f37806eec823c752d7e30e4e3_82722_15aa4f92c6d2fe9d4b9034f5ffac921c.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt37_hua49f3c2f37806eec823c752d7e30e4e3_82722_f6963f612b98db97aae79848a25fd7a5.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt37_hua49f3c2f37806eec823c752d7e30e4e3_82722_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt37_hua49f3c2f37806eec823c752d7e30e4e3_82722_15aa4f92c6d2fe9d4b9034f5ffac921c.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最后聊聊 knative 的可拔插设计，这是 knative 在架构设计上的一个基本原则：顶层松耦合，底层可拔插。&lt;/p&gt;
&lt;p&gt;最顶层是 Build / Serving / Eventing 三大组件，中间是各种能力，通过 k8s 的 CRD 方式来进行声明，然后底层是各种实现，按照 CRD 的要求进行具体的实现。&lt;/p&gt;
&lt;p&gt;在这个体系中，用户接触的是 Build / Serving / Eventing 通用组件，通过通过标准的 CRD 进行行为控制，而和底层具体的实现解耦。理论上，之后在实现层做适配，knative 就可以运行在不同的底层 serverless 实现上。从而实现 knative 的战略目标：提供 serverless 的通用平台，实现 serverless 的标准化和规范化。&lt;/p&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt38_hu708e7843578c81befcfc745c62e99f0a_90762_fb71c4592875a788a37a7a45b31dc44d.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt38_hu708e7843578c81befcfc745c62e99f0a_90762_88adb1560d4f594175155764dcdc2d83.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt38_hu708e7843578c81befcfc745c62e99f0a_90762_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt38_hu708e7843578c81befcfc745c62e99f0a_90762_fb71c4592875a788a37a7a45b31dc44d.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最后，我们对 knative 做一个简单总结。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt39_hu49022b4d4dda65e675b00ce2065255f9_42971_f3de1c8466740a0dcad25ad2219eb0f8.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt39_hu49022b4d4dda65e675b00ce2065255f9_42971_a9e57152c3be566c8a9f38d2752dcf2e.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt39_hu49022b4d4dda65e675b00ce2065255f9_42971_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt39_hu49022b4d4dda65e675b00ce2065255f9_42971_f3de1c8466740a0dcad25ad2219eb0f8.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;先谈一下 knative 的优势，首先是 knative 自身的几点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;产品定位准确：针对市场现状，不做竞争者而是做平台&lt;/li&gt;
&lt;li&gt;技术方向明确：基于 k8s，走 cloud native 方向&lt;/li&gt;
&lt;li&gt;推出时机精准：k8s 大势已成，istio 接近成熟&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然后，再次强调：kubernetes + service mesh + serverless 的组合，在用好的前提下，应该威力不凡。&lt;/p&gt;
&lt;p&gt;此外，knative 在负载的支撑上，不拘泥于传统的FaaS，可以支持 BaaS 和传统应用，在落地时适用性会更好，使用场景会更广泛。（备注：在这里我个人有个猜测，knative 名字中 native 可能指的是 native workload，即在 k8s 和 cloud native 语义下的原生工作负载，如果是这样，那么 google 和 knative 的这盘棋就下的有点大了。）&lt;/p&gt;
&lt;p&gt;最后，考虑到目前 serverless 的市场现状，对 serverless 做标准化和规范化，出现一个 serverless 平台，似乎也是一个不错的选择。再考虑到 google 拉拢大佬和社区一起干的一贯风格，携 k8s 和 cloud native 的大势很有可能实现这个目标。&lt;/p&gt;
&lt;p&gt;当然，knative 目前存在的问题也很明显，细节不说，整体上个人感觉有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;成熟度：目前才 0.2 版本，实在太早期，太多东西还在开发甚至规划中。希望随着时间的推移和版本演进，knative 能尽快走向成熟。&lt;/li&gt;
&lt;li&gt;复杂度：成熟度的问题还好说，总能一步一步改善的，无非是时间问题。但是 knative 的系统复杂度过高的问题，目前看来几乎是不可避免的。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后，对 knative 的总结，就一句话：&lt;strong&gt;前途不可限量，但是成长需要时间&lt;/strong&gt;。让我们拭目以待。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201811-knative-redefine-serverless/images/ppt40_hue8bcc01b08173f099bc47c4e931f0002_58730_70af25cdfd03f6793a5a417458fde3d7.webp 400w,
               /talk/201811-knative-redefine-serverless/images/ppt40_hue8bcc01b08173f099bc47c4e931f0002_58730_a12dac0eb29ab882da544ec17d512f82.webp 760w,
               /talk/201811-knative-redefine-serverless/images/ppt40_hue8bcc01b08173f099bc47c4e931f0002_58730_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201811-knative-redefine-serverless/images/ppt40_hue8bcc01b08173f099bc47c4e931f0002_58730_70af25cdfd03f6793a5a417458fde3d7.webp&#34;
               width=&#34;720&#34;
               height=&#34;540&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;广告时间，欢迎大家加入 servicemesher 社区，也可以通过关注 servicemesher 微信公众号来及时了解 service mesh 技术的最新动态。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>长路漫漫踏歌而行：蚂蚁金服Service Mesh实践探索</title>
      <link>https://skyao.net/talk/201810-ant-finance-service-mesh-practice/</link>
      <pubDate>Tue, 23 Oct 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/201810-ant-finance-service-mesh-practice/</guid>
      <description>&lt;p&gt;后记：被评选为QCon上海2018的明星讲师，感谢各方朋友的厚爱！&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/star_hu983d82b1261a136286e01c7105a0ee52_535477_54c458a8814f04235ab04297cf6f2eba.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/star_hu983d82b1261a136286e01c7105a0ee52_535477_163679082378dd93ddc27f391ff48e92.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/star_hu983d82b1261a136286e01c7105a0ee52_535477_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/star_hu983d82b1261a136286e01c7105a0ee52_535477_54c458a8814f04235ab04297cf6f2eba.webp&#34;
               width=&#34;760&#34;
               height=&#34;237&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-1_hu0176e78aef0117a1c7752ce69822354a_36854_d36d2be00f9023029ba6c5d1ff0d3c81.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-1_hu0176e78aef0117a1c7752ce69822354a_36854_1c7ae6063f4074e3968ff02499476e47.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-1_hu0176e78aef0117a1c7752ce69822354a_36854_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-1_hu0176e78aef0117a1c7752ce69822354a_36854_d36d2be00f9023029ba6c5d1ff0d3c81.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;大家好，我是来自蚂蚁金服中间件团队的敖小剑，目前是蚂蚁金服 Service Mesh 项目的PD。我同时也是 &lt;a href=&#34;http://www.servicemesher.com&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Servicemesher中国技术社区&lt;/a&gt; 的创始人，是 Service Mesh 技术在国内最早的布道师。我今天给大家带来的主题是&amp;quot;长路漫漫踏歌而行：蚂蚁金服Service Mesh实践探索&amp;quot;。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-2_hu646b717498418971c18901263490984f_29165_4696810188db5018a82538b3b3e6e2a7.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-2_hu646b717498418971c18901263490984f_29165_da5a6a19975cace182f50febc64dc281.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-2_hu646b717498418971c18901263490984f_29165_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-2_hu646b717498418971c18901263490984f_29165_4696810188db5018a82538b3b3e6e2a7.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在去年的QCon上海，我曾经做过一个名为 &lt;a href=&#34;https://skyao.net/publication/201710-service-mesh-next-generation-microservice/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;Service Mesh：下一代微服务&amp;rdquo;&lt;/a&gt; 的演讲，不知道今天现场是否有当时听过去年这场演讲的同学？（备注：现场调查的结果，大概十几位听众听过去年的演讲。）&lt;/p&gt;
&lt;p&gt;当然，今天我们的内容不是继续做 Service Mesh 的布道，按秀涛的要求，今年要好好讲一讲实践。所以今天我不会像去年那样给大家详细解释 Service Mesh 是什么，能做什么，有什么优势。而是结合过去一年中蚂蚁金服的实践经验，结合蚂蚁金服的 SOFAMesh 产品，帮助大家更深刻的理解 Service Mesh 技术。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-3_hu2e569158c9c73213213add150b2add6c_108239_65e99f58a8396774118c799db02b48e5.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-3_hu2e569158c9c73213213add150b2add6c_108239_d71f63fca51ff0514acdfaa43e26cc0b.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-3_hu2e569158c9c73213213add150b2add6c_108239_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-3_hu2e569158c9c73213213add150b2add6c_108239_65e99f58a8396774118c799db02b48e5.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在开始今天的内容分享之前，我们先来热个身，温习一下去年的内容。去年我是来QCon布道的，而布道的核心内容就是告诉大家：Service Mesh 是什么？&lt;/p&gt;
&lt;p&gt;为了帮忙大家回答，我给出一个提示图片，了解 Service Mesh 的同学对这张图片应该不会陌生。&lt;/p&gt;
&lt;p&gt;这里我们一起回顾一下Service Mesh 的正式定义：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Service Mesh是一个&lt;strong&gt;基础设施层&lt;/strong&gt;，用于处理服务间通讯。现代云原生应用有着复杂的服务拓扑，服务网格负责在这些拓扑中&lt;strong&gt;实现请求的可靠传递&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在实践中，服务网格通常实现为一组&lt;strong&gt;轻量级网络代理&lt;/strong&gt;，它们与应用程序部署在一起，而&lt;strong&gt;对应用程序透明&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;黑色加粗部分是重点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基础设施层：这是 Service Mesh 的定位，今天内容的最后一个部分我会和大家详细展开这个话题&lt;/li&gt;
&lt;li&gt;服务间通讯：这是 Service Mesh 的功能和范围&lt;/li&gt;
&lt;li&gt;实现请求的可靠传递：是 Service Mesh 的目标&lt;/li&gt;
&lt;li&gt;轻量级网络代理：是 Service Mesh 的部署方式&lt;/li&gt;
&lt;li&gt;对应用程序透明：是 Service Mesh 的重要特性，零侵入，Service Mesh 的最大优势之一。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-4_hu8d903926a17ce555e286454253b8145e_139060_44d0f4013c108e05ac326fb2ab889811.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-4_hu8d903926a17ce555e286454253b8145e_139060_acaa595083ef3988c4101cf138802de8.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-4_hu8d903926a17ce555e286454253b8145e_139060_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-4_hu8d903926a17ce555e286454253b8145e_139060_44d0f4013c108e05ac326fb2ab889811.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;今天的内容会有这些：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先给大家快速介绍一下我们的 SOFAMesh 项目，让大家对故事的背景有个大致的了解&lt;/li&gt;
&lt;li&gt;然后给大家介绍一下为什么我们选择了用 Golang 语言来实现数据平面，这个是过去一年中各方对我们产品方案最大的疑惑&lt;/li&gt;
&lt;li&gt;再继续给大家分享一下过去一年中我们在 Service Mesh 落地中遇到的典型问题和解决方案，给大家一些比较实际感受&lt;/li&gt;
&lt;li&gt;然后我们将探索一下服务间通讯的范围，看看 Service Mesh 可以在哪些领域得到应用&lt;/li&gt;
&lt;li&gt;再接下来，给大家介绍一下在这一年实践中的最大感悟，和大家聊聊基础设施对服务网格的意义，这也是今年最想和大家分享的内容。&lt;/li&gt;
&lt;li&gt;最后，总结一下今天的内容，分享一些信息&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;OK，让我们开始今天的第一个部分，给大家快速介绍一下 SOFAMesh，目标在展开我们的各种实践和探索之前，让大家了解一下背景。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-5_hu878ff45cd7bf6e219f3e27f88fee243e_162148_03fb31d7dfc8db291ae43f74cd041fae.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-5_hu878ff45cd7bf6e219f3e27f88fee243e_162148_4a6a60a5230dce6a856fe7d2154249ab.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-5_hu878ff45cd7bf6e219f3e27f88fee243e_162148_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-5_hu878ff45cd7bf6e219f3e27f88fee243e_162148_03fb31d7dfc8db291ae43f74cd041fae.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;SOFAMesh 是蚂蚁金服推出的 Service Mesh 开源产品，大家可以简单的理解为是 Istio 的落地增强版本。我们有两个原则：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;跟随社区&lt;/p&gt;
&lt;p&gt;体现在 SOFAMesh 是 fork 自 Istio，而且紧跟 Istio 的最新版本，确保和上游保持同步。&lt;/p&gt;
&lt;p&gt;我们在 Istio 上的改动都在 SOFAMesh 项目中开源出来，而且在验证完成后我们也会联系 Istio，反哺回上游。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;实践检验&lt;/p&gt;
&lt;p&gt;一切从实践出发，不空谈，在实际生产落地中，发现问题，解决问题。在解决问题的过程中，不将就，不凑合，努力挖掘问题本质，然后追求以技术创新的方式来解决问题。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;原则上：Istio 做好的地方，我们简单遵循，保持一致；Istio 做的不好或者疏漏的地方，我们努力改进和弥补。&lt;/p&gt;
&lt;p&gt;所有这一切，以&lt;strong&gt;实际落地&lt;/strong&gt;为出发点，同时满足未来的技术大方向。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-6_hu7295dd60902993db9085ff0fc49f86c2_48044_01b47b093d45532b9c0394336ee262f1.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-6_hu7295dd60902993db9085ff0fc49f86c2_48044_5381fa7ae06ed6d2df692043985907fa.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-6_hu7295dd60902993db9085ff0fc49f86c2_48044_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-6_hu7295dd60902993db9085ff0fc49f86c2_48044_01b47b093d45532b9c0394336ee262f1.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;SOFAMesh 的产品规划，这是目前正在进行的第一阶段。架构继续延续 Istio 的数据平面和控制平面分离的方式，主要工作内容是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;用 Golang 开发 Sidecar，也就是我们的 SOFAMosn 项目，替代 Envoy。&lt;/li&gt;
&lt;li&gt;集成 Istio 和 SOFAMosn，同时针对落地时的需求和问题进行扩展和补充，这是我们的 SOFAMesh 项目&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在这个架构中，和 Istio 原版最大的不同在于我们没有选择 Istio 默认集成的 Envoy，而是自己用 Golang 开发了一个名为 SOFAMosn 的 Sidecar 来替代 Envoy。&lt;/p&gt;
&lt;p&gt;为什么？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-7_hu1fb56133ec64508483abc6a2a4323b22_139854_f16d00f3672cac08678fb5fff64dd2d5.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-7_hu1fb56133ec64508483abc6a2a4323b22_139854_93908533eb9b7ec4d26c35d4bd846ccf.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-7_hu1fb56133ec64508483abc6a2a4323b22_139854_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-7_hu1fb56133ec64508483abc6a2a4323b22_139854_f16d00f3672cac08678fb5fff64dd2d5.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们的第二部分内容将给大家解答这个问题。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-8_hud6651532a64ba7c00b227915aa51fdc3_62295_93a9bd0647d028d7b00f47afefe24df5.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-8_hud6651532a64ba7c00b227915aa51fdc3_62295_83e95f754b172bc47c1134ebcc6c5fc2.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-8_hud6651532a64ba7c00b227915aa51fdc3_62295_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-8_hud6651532a64ba7c00b227915aa51fdc3_62295_93a9bd0647d028d7b00f47afefe24df5.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;MOSN 的全称是 &amp;ldquo;Modular Observable Smart Network&amp;rdquo;，正如其名所示，这是一个模块化可观察的智能网络。这个项目有非常宏大的蓝图，由蚂蚁金服的系统部门和中间件部门联手UC大文娱基础架构部门推出，准备将原有的网络和中间件方面的各种能力在 Golang 上重新沉淀，打造成为未来新一代架构的底层平台，承载各种服务通讯的职责。&lt;/p&gt;
&lt;p&gt;Sidecar 模式是 MOSN 目前的主要形式之一，参照 Envoy 项目的定位。我们实现了 Envoy 的 xDS API，和 Istio 保持兼容。&lt;/p&gt;
&lt;p&gt;在 Istio 和 Envoy 中，对通讯协议的支持，主要体现在 HTTP/1.1 和 HTTP/2 上，这两个是 Istio / Envoy 中的一等公民。而基于 HTTP/1.1 的 REST 和基于 HTTP/2 的 gRPC，一个是目前社区最主流的通讯协议，一个是未来的主流，Google 的宠儿，CNCF 御用的 RPC 方案，这两个组成了目前 Istio 和 Envoy（乃至 CNCF 所有项目）的黄金组合。&lt;/p&gt;
&lt;p&gt;而我们 SOFAMesh，在第一时间就遇到和 Istio/Envoy 不同的情况，我们需要支持 REST 和 gRPC 之外的众多协议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SOFARPC：这是蚂蚁金服大量使用的 RPC 协议(已开源)&lt;/li&gt;
&lt;li&gt;HSF RPC：这是阿里集团内部大量使用的 RPC 协议(未开源)&lt;/li&gt;
&lt;li&gt;Dubbo RPC: 这是社区广泛使用的 RPC 协议(已开源)&lt;/li&gt;
&lt;li&gt;其他私有协议：在过去几个月间，我们收到需求，期望在 SOFAMesh 上运行其他 TCP 协议，大部分是私有协议&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为此，我们需要考虑在 SOFAMesh 和 SOFAMosn 中增加这些通讯协议的支持，尤其是要可以让我们的客户非常方便的扩展支持各种私有TCP协议。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-9_huadee123e0c9d945fe1ed82870d440f75_131447_c9c8bd87b6916dae5acb5ab7b36fb307.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-9_huadee123e0c9d945fe1ed82870d440f75_131447_40d45a031aabfeb5981d059e4b2a39c0.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-9_huadee123e0c9d945fe1ed82870d440f75_131447_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-9_huadee123e0c9d945fe1ed82870d440f75_131447_c9c8bd87b6916dae5acb5ab7b36fb307.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;为什么不直接使用 Envoy？&lt;/p&gt;
&lt;p&gt;几乎所有了解 SOFAMesh 产品的同学，都会问到这个问题，也是 SOFAMesh 被质疑和非议最多的地方。因为目前 Envoy 的表现的确是性能优越，功能丰富，成熟稳定。&lt;/p&gt;
&lt;p&gt;我们在技术选型时也是重点研究过 Envoy，可以说 Envoy 非常符合我们的需求，除了一个地方：&lt;strong&gt;Envoy是c++&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-10_hu920c25b67cec0a4e81cbc9c6ea0e2fa3_117681_fe191b4343d650436548a9aea2d35f51.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-10_hu920c25b67cec0a4e81cbc9c6ea0e2fa3_117681_6bd10a0968af50f0694b8568e3f66a57.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-10_hu920c25b67cec0a4e81cbc9c6ea0e2fa3_117681_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-10_hu920c25b67cec0a4e81cbc9c6ea0e2fa3_117681_fe191b4343d650436548a9aea2d35f51.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里有个选择的问题，就是数据平面应该选择什么样的编程语言？&lt;/p&gt;
&lt;p&gt;图中列出了目前市场上主要的几个 Service Mesh 类产品在数据平面上的编程语言选择。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首先，基于 Java 和 Scala 的第一时间排除，实践证明，JDK/JVM/字节码这些方式在部署和运行时都显得太重，不适合作为 Sidecar&lt;/li&gt;
&lt;li&gt;Nginmesh 的做法有些独特，通过 Golang 的 agent 得到信息然后生成配置文件塞给 nginx，实在不是一个正统的做法&lt;/li&gt;
&lt;li&gt;Conduit（后更名为Linkerd2.0）选择的 Rust 是个剑走偏锋的路子，Rust 本身极其适合做数据平面，但是 Rust 语言的普及程度和社区大小是个极大的欠缺，选择 Rust 意味着基本上无法从社区借力&lt;/li&gt;
&lt;li&gt;Envoy 选择的 c++&lt;/li&gt;
&lt;li&gt;国内华为和新浪微博选择了 Golang&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们在选择之前，内部做过深入讨论，焦点在于：未来的新一代架构的底层平台，编程语言栈应该是什么？最终一致觉得应该是 Golang，配合部分 Java。&lt;/p&gt;
&lt;p&gt;对于 Sidecar 这样一个典型场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;要求高性能，低资源消耗，有大量的并发和网络编程&lt;/li&gt;
&lt;li&gt;要能被团队快速掌握，尤其新人可以快速上手&lt;/li&gt;
&lt;li&gt;要和底层的 k8s 等基础设施频繁交互，未来有 Cloud Native 的大背景&lt;/li&gt;
&lt;li&gt;非常重要的：要能被社区和未来的潜在客户接受和快速掌握，不至于在语言层面上有过高的门槛&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不考虑其他因素，满足 Sidecar 场景的最理想的编程语言，自然是非 Golang 莫属。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-11_hu56252d292a4357d596b9812d3658b805_105738_7d8e6cab7c0cf61a40fd39ee0e5101a4.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-11_hu56252d292a4357d596b9812d3658b805_105738_e1b4f2824a331e18d81cf48a7ec91bfc.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-11_hu56252d292a4357d596b9812d3658b805_105738_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-11_hu56252d292a4357d596b9812d3658b805_105738_7d8e6cab7c0cf61a40fd39ee0e5101a4.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;但是到具体的技术选型时，面对要不要使用 Envoy，决策依然是非常艰难：关键在于，c++有 Envoy 这样成熟的产品存在，可以直接拿来用；而 Golang 没有可以和 Envoy 分庭抗礼的产品可以选择，需要白手起家。&lt;/p&gt;
&lt;p&gt;两个选择各有优劣，短期看：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;直接使用 Envoy，优势在于这是一个成熟项目，表现稳定，而且也是 Isto 默认的 Sidecar，本身速度快，资源消耗低。可以直接拿来用，上手超简单，投入少而收益快&lt;/li&gt;
&lt;li&gt;开发自己的 Golang 版本的 Sidecar，全是劣势：这是一个全新项目，工作量非常大，而且技术上很有挑战，还有需要自行完成和 Istio 集成的额外工作量以及维护成本，最大的挑战还在于 Envoy 丰富甚至繁多的功能，要向 Envoy 对齐需要非常大的努力&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可以说，短期内看，选择 Envoy 远比自行开发 Golang 版本要现实而明智。&lt;/p&gt;
&lt;p&gt;但是，前面我们有说到，对于 MOSN 项目，我们有非常宏大的蓝图：准备将原有的网络和中间件方面的各种能力重新沉淀和打磨，打造成为未来新一代架构的底层平台，承载各种服务通讯的职责。这是一个需要一两年时间打造，满足未来三五年乃至十年需求的长期规划项目，我们如果选择以 Envoy 为基础，短期内自然一切OK，快速获得各种红利，迅速站稳脚跟。&lt;/p&gt;
&lt;p&gt;但是：后果是什么？Envoy 是C++的，选择 Envoy 意味着我们后面沉淀和打磨的未来通讯层核心是c++的，我们的语言栈将不得不为此修改为以c++为主，这将严重偏离既定的 Golang + Java 的语言栈规划。&lt;/p&gt;
&lt;p&gt;而一旦将时间放到三五年乃至十年八年这个长度时，选择Envoy的劣势就出来了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;C++ 带来的开发和维护成本时远超 Golang，时间越长，改动越多，参与人数越多，使用场景越多，差别越明显&lt;/li&gt;
&lt;li&gt;从目前的需求上看，对 Envoy 的扩展会非常多，包括通讯协议和功能。考虑到未来控制平面上可能出现的各种创新，必然需要数据平面做配合，改动会长期存在&lt;/li&gt;
&lt;li&gt;Golang 还是更适合云原生时代，选择 Golang，除了做 Sidecar，锻炼出来的团队还可以用 Golang 去完成其他各种产品。当然选择 Envoy 也可以这么干，但是这样一来以后系统中就真的都是c++的产品了。&lt;/li&gt;
&lt;li&gt;另外 Envoy 目前的官方定位只有 Sidecar 一种模式，而我们规划中的 MSON 项目覆盖了各种服务通讯的场景&lt;/li&gt;
&lt;li&gt;日后如何和 Envoy 协调是个大难题。尤其我们后续会有非常多的创新想法，也会容许快速试错以鼓励创新，选择  Envoy 在这方面会有很多限制。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，最后我们的选择是：先难后易，着眼未来。忍痛（真的很痛）舍弃 Envoy，选择用 Golang 努力打造我们的SOFAMosn 项目。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-12_hu189a90d027271ffd95b8058701930e2d_946782_caee5dafa011e1c050baaed46a40f218.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-12_hu189a90d027271ffd95b8058701930e2d_946782_57e818f744faa38e465c5ce594e9b64a.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-12_hu189a90d027271ffd95b8058701930e2d_946782_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-12_hu189a90d027271ffd95b8058701930e2d_946782_caee5dafa011e1c050baaed46a40f218.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对于同样面临要不要选择 Envoy 的同学，我给出的建议是：Envoy 是否适合，取决于是不是想“动”它。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果只是简单的使用，或者少量的扩展，那么其实你接触到的只是 Envoy 在冰山上的这一小部分，这种情况下建议你直接选择 Envoy&lt;/li&gt;
&lt;li&gt;如果你和我们一样，将 Service Mesh 作为未来架构的核心，预期会有大量的改动和扩展，同时你又不愿意让自己的主流编程语言技术栈中 c++ 占据主流，那么可以参考我们的选择&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当然，对于原本就是以 c/c++ 为主要编程语言栈的同学来说，不存在这个问题。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-13_hubb79ebe3ed999212dc556da3c7dca788_140042_db3b6e734f8ac426e078ddc320567f97.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-13_hubb79ebe3ed999212dc556da3c7dca788_140042_aa5f77519d4660486784effff3811de7.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-13_hubb79ebe3ed999212dc556da3c7dca788_140042_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-13_hubb79ebe3ed999212dc556da3c7dca788_140042_db3b6e734f8ac426e078ddc320567f97.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;今天的第三部分，给大家介绍一下 SOFAMesh 在落地期间遇到的典型问题。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-14_hu9221f817ed705ccd52a523ecaba80089_57470_cc9d5f345a73d1369a59b92abc6b6b87.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-14_hu9221f817ed705ccd52a523ecaba80089_57470_b2256c862b97e7b26969b1a4ad06d5a4.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-14_hu9221f817ed705ccd52a523ecaba80089_57470_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-14_hu9221f817ed705ccd52a523ecaba80089_57470_cc9d5f345a73d1369a59b92abc6b6b87.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里给大家列出了三个主要问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;通讯协议扩展&lt;/p&gt;
&lt;p&gt;前面也刚谈到过，就是我们会需要支持非常多的TCP协议，包括各种私有协议。当然这个其实更应该归为需求，后面详细展开。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;平滑迁移传统架构&lt;/p&gt;
&lt;p&gt;所谓传统架构指的是传统的 SOA 架构，如基于 Dubbo 的很多现有应用，我们希望它们能够在 Service Mesh 中直接跑起来，而不必一定要先进行微服务改造。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;适配异构体系&lt;/p&gt;
&lt;p&gt;异构体系指的是，当我们进行 Service Mesh 落地时，会存在新旧两条体系，比如说新的应用是基于 Service Mesh 开发的，而旧的应用是基于传统框架比如说 Dubbo 或者是 Spring Cloud。&lt;/p&gt;
&lt;p&gt;当我们做应用迁移的时候，考虑到原来的存量应用会有很多的，比如上千个应用，这些应用肯定不可能说一个晚上全部切过去。中间必然会有一个过渡阶段，在这个过渡阶段新旧体系中的应用应该怎么通讯，如何才能做到最理想。&lt;/p&gt;
&lt;p&gt;我们现在正在做方案，就是现在POC中。我们现在给自己设定的目标，就是希望给出一套方案，可以让现有应用不做代码改动，然后可以在新旧两边随便切，以保证平滑迁移。&lt;/p&gt;
&lt;p&gt;当然这套方案现在正在做POC，方案还未最终定型，所以今天我们不会包含这一块的细节。大家如果有兴趣的话可以稍后关注我们的这个方案。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;今天给大家主要分享前面两个部分，我们详细展开。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-15_hueddbd860cccc1b1d85a1ab193b563605_66662_c6aede0172943dd9d442f0ec4ed535eb.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-15_hueddbd860cccc1b1d85a1ab193b563605_66662_70080eae236ab96050b4ebfcb62b77da.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-15_hueddbd860cccc1b1d85a1ab193b563605_66662_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-15_hueddbd860cccc1b1d85a1ab193b563605_66662_c6aede0172943dd9d442f0ec4ed535eb.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第一个要解决的问题是如何快速的扩展支持一个新的通讯协议。&lt;/p&gt;
&lt;p&gt;这个问题主要源于现在 Istio 的设计，按照 Istio 现在的方式，如果要添加一个新的通讯协议，是有几大块工作要做的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;添加协议的 Encoder 和 Decoder&lt;/p&gt;
&lt;p&gt;也就是协议的编解码，这个没得说，肯定要加的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;修改 Pilot 下发 Virtual Host 等配置&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;修改 Sidecar 如 Envoy，MOSN 去实现请求匹配&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;后两者是大量重复的，就技术实现而言，需要修改的内容和现有的东西差不多，但是必须要再改出一份新的来。因为我们协议比较多，由此带来的改动量非常大。根据我们之前的实践，以这样的方式加一个新的通讯协议可能需要几天的工作量，而且每次改动都重复大量代码。&lt;/p&gt;
&lt;p&gt;在这里我们最后给出了一个名为 &lt;strong&gt;x-protocol&lt;/strong&gt; 的通用解决方案，细节我们这里不展开，只给大家看个结果。根据我们最新的验证情况，如果我们要添加一个新的通讯协议，大概就是一两百行代码，一两个小时就能完成。即使加上测试，基本上也可以控制在一天之内，我们就能够为 SOFOMesh 新增一个通讯协议的支持。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-16_hu6f426493e8ed48a204371a007bb25557_176663_3888a063440ddcbd730355be491e828e.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-16_hu6f426493e8ed48a204371a007bb25557_176663_a8d12478a0cea73c21bba71942a5235c.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-16_hu6f426493e8ed48a204371a007bb25557_176663_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-16_hu6f426493e8ed48a204371a007bb25557_176663_3888a063440ddcbd730355be491e828e.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第二个要解决的问题就是让传统架构的存量应用上 Service Mesh 的问题。&lt;/p&gt;
&lt;p&gt;就是刚才说的现有大量的基于 SOA 框架的程序，这些应用以传统的 SOA 方式开发，如果直接挪到 Service Mesh 下，如Istio，会遇到问题：因为 Istio 用的服务注册是通过 k8s 来进行，而 k8s 的服务注册模型和原有的 SOA 模型是不匹配的。&lt;/p&gt;
&lt;p&gt;SOA 框架当中，通常是以接口为单位来做服务注册，也就是一个应用里面部署多个接口的，在运行时是一个进程里面有多个接口（或者说多个服务）。实际上是以接口为粒度，服务注册和服务发现，包括服务的调用都是以接口为粒度。但是有个问题，部署到 Istio 中后，Istio 做服务注册是以服务为粒度来做服务注册，这个时候不管是注册模型，还是按接口调用的方式都不一致，就是说通过 Interface 调用是调不通的。&lt;/p&gt;
&lt;p&gt;左边的代码实例，大家可以看得到，一般情况下 Dubbo 程序是按照 Interface 来注册和发现，调用时也是通过 Interface 来调用。另外，在这个地方，除了通过接口调用之外，还有另外一个问题：服务注册和服务发现的模型，从原来的一对N，也就是一个进程N个接口，变成了要一对一，一个进程一个服务。&lt;/p&gt;
&lt;p&gt;怎么解决这个问题？最正统的做法是，是先进行&lt;strong&gt;微服务改造&lt;/strong&gt;：把原有的 SOA 的架构改成微服务的架构，把现有应用拆分为多个微服务应用，每个应用里面一个服务（或者说接口），这样应用和服务的关系就会变成一对一，服务注册模型就可以匹配。&lt;/p&gt;
&lt;p&gt;但是在执行时会有难处，因为微服务改造是一个比较耗时间的过程。我们遇到的实际的需求是：能不能先不做微服务改造，而先上 Service Mesh ？因为 Service Mesh 的功能非常有吸引力，如流量控制，安全加密。那能不能先把应用搬迁到 Service Mesh 上来，先让应用跑起来，后面再慢慢的来做微服务改造。&lt;/p&gt;
&lt;p&gt;这就是我们实际遇到的场景，我们需要找到方案来解决问题：注册模型不匹配，原有用接口调用的代码调不通。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-17_hu78b777641971f5bcb3b558021ee9c396_189176_58beb191181168961da8096b23f8e39a.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-17_hu78b777641971f5bcb3b558021ee9c396_189176_ac690aa10e676e8a1998654aabd63052.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-17_hu78b777641971f5bcb3b558021ee9c396_189176_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-17_hu78b777641971f5bcb3b558021ee9c396_189176_58beb191181168961da8096b23f8e39a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们设计了一个名为 &lt;strong&gt;DNS通用选址方案&lt;/strong&gt; 的解决方案，用来支持 Dubbo 等SOA框架，容许通过接口名来调用服务。&lt;/p&gt;
&lt;p&gt;细节不太适合展开，给大家介绍最基本的一点，就是说我们会在 DNS 中增加记录，如图上左下角所示标红的三个接口名，我们会在DNS中把这个三个接口指向当前服务的 Cluster IP。k8s 的 Cluster IP 通常是一个非常固定的一个IP，每个服务在k8s部署时都会分配。&lt;/p&gt;
&lt;p&gt;在增加完DNS记录之后，再通过 Interface 的方式去调用，中间在我们的 Service Mesh 里面，我们会基于 Cluster IP 信息完成实际的寻址，并跑通 Istio 的所有功能，和用服务名调用等同。&lt;/p&gt;
&lt;p&gt;这个功能在现有的 SOFAMesh 中已经完全实现，大家可以去试用。稍后我们会将这个方案提交给 k8s 或者 Istio 社区，看看他们是否愿意接受这样一个更通用的寻址方式。&lt;/p&gt;
&lt;p&gt;在这里我们提出这样一个设想：&lt;strong&gt;先上车后补票&lt;/strong&gt;。所谓&amp;quot;先上车&amp;quot;是指说先上 Service Mesh 的车，&amp;ldquo;后补票&amp;quot;是指后面再去补微服务拆分的票。好处是在微服务拆分这个巨大的工作量完成之前，提前受益于 Service Mesh 提供的强大功能；同时也可以让部署变得舒服，因为不需要强制先全部完成微服务拆分才能上 Service Mesh 。有了这个方案，就可以在应用不做微服务拆分的情况下运行在 Service Mesh 上，然后再从容的继续进行微服务拆分的工作，这是我们提出这个解决方案的最大初衷。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-18_huef35af9c4ca0b1f83a2f83884d0c57e5_90426_380ec94fa0484a73f25fe243f0b271b5.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-18_huef35af9c4ca0b1f83a2f83884d0c57e5_90426_f387d84e32c30385461e0ef57abefa76.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-18_huef35af9c4ca0b1f83a2f83884d0c57e5_90426_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-18_huef35af9c4ca0b1f83a2f83884d0c57e5_90426_380ec94fa0484a73f25fe243f0b271b5.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;当然，这里面有比较多的技术实现细节，里面有很多细节的东西实在是不适合在这里一一展开。同时也涉及到比较多的 k8s 和 Istio 底层技术细节，需要大家对 k8s kubeproxy 网络转发方案和 Istio 的实现有比较深的认知才能完全理解。这里给出了几篇文章，大家如果对这几个技术有兴趣，可以通过这些文章来了解里面的技术细节，今天就不在这里继续展开了。&lt;/p&gt;
&lt;p&gt;MOSN 和 x-protocol 介绍：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.servicemesher.com/blog/sofa-mosn-deep-dive/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Service Mesh数据平面SOFAMosn深层揭秘&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.servicemesher.com/blog/sofa-mosn-performance-report-0.1.0/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;蚂蚁金服开源Go语言版Service Mesh数据平面SOFAMosn性能报告&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.servicemesher.com/blog/ant-financial-sofamesh-common-protocol-extension/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;蚂蚁金服开源的 SOFAMesh 的通用协议扩展解析&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://www.servicemesher.com/blog/dubbo-on-x-protocol-in-sofa-mesh/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dubbo on x-protocol——SOFAMesh中的x-protocol示例演示&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;X-protocol 特性的详细讲解：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://skyao.net/post/201809-xprotocol-common-address-solution/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;SOFAMesh中的多协议通用解决方案x-protocol介绍系列(1)-DNS通用寻址方案&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skyao.net/post/201809-xprotocol-rapid-decode-forward/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;SOFAMesh中的多协议通用解决方案x-protocol介绍系列(2)-快速解码转发&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skyao.net/post/201809-xprotocol-tcp-protocol-extension/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;SOFAMesh中的多协议通用解决方案x-protocol介绍系列(3)-TCP协议扩展&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总结一下，我们解决了如下几个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;可以快速的用几个小时就在 SOFAMesh 中添加一个新的通讯协议&lt;/li&gt;
&lt;li&gt;可以让 SOA 应用在 SOFAMesh 上继续通过接口进行调用，不需要改代码&lt;/li&gt;
&lt;li&gt;可以实现不做 SOA 程序的微服务改造，就直接搬迁到 SOFAMesh，提前受益&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-19_hucce2e3edc348da2eb3e8a30e85fc9b68_202329_26a329917c498254e08265baad76d61a.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-19_hucce2e3edc348da2eb3e8a30e85fc9b68_202329_5d793d6ac12bcc2a13aaee5b43ea0be5.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-19_hucce2e3edc348da2eb3e8a30e85fc9b68_202329_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-19_hucce2e3edc348da2eb3e8a30e85fc9b68_202329_26a329917c498254e08265baad76d61a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第四块，涉及到流量劫持的方案。&lt;/p&gt;
&lt;p&gt;Service Mesh 有一个很重要的特性，就是无侵入，而无侵入通常是通过流量劫持来实现的。通过劫持流量，在客户端服务器端无感知的情况下，可以将 Service Mesh 的功能插进去。通常特别适合于类似安全加密等和现有应用的业务逻辑完全分离的场合。&lt;/p&gt;
&lt;p&gt;但 Istio 的流量劫持方案做的还不够好，目前 Istio 只给了一个方案就是 iptables。这个方案有比较多的问题，所以我们有几个思路：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;优化 iptables&lt;/p&gt;
&lt;p&gt;优化 iptables 主要是为了减少对Host主机的影响。&lt;/p&gt;
&lt;p&gt;用 iptables 有两种思路：一个是 pod only，就是说在pod里面做 iptables，这个Istio的官方做法，但是这样需要ROOT权限以便修改iptables配置；还有一种思路用Host主机上的 iptables，这个话可以不用ROOT权限。我们对比之后，还是觉得放在pod里面更好一点，因为性能损耗比较小一些，所以暂时我们用的是在pod中方案，但我们会进行优化，比如把 iptables 的模块简化到最小。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;调研IPVS方案&lt;/p&gt;
&lt;p&gt;我们现在正在调研IPVS方案。主要是 iptables 方案存在部署问题，就是 iptables 这个模块经常被限制使用。现场有没有做运维的同学？你们的机器上开启了 iptables 吗？我能告诉大家的是，到目前为止，蚂蚁金服内部的机器上，iptables不仅仅是禁用，而是整个 iptables 模块都被卸载。原因是性能、安全、维护等大家周知的原因，总之我们蚂蚁金服内部是没有这个模块的。&lt;/p&gt;
&lt;p&gt;为了解决这个问题，我们现在正在调研IPVS的方案，准备用IPVS来替换 iptables。这块工作正在进行，目前方案已经验证，但是还有一些细节没有完善，后面有更多的消息也给大家继续介绍。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;轻量级客户端的实践&lt;/p&gt;
&lt;p&gt;另外还有一个实践是考虑不做流量劫持。比如说，最典型的RPC方案，因为RPC通常来说总是会有一个客户端的。在上 Service Mesh 之后，可以将原来的客户端的一些功能如服务发现、负载均衡、限流等精简，形成一个新的轻量级客户端，但此时终究还是有一个客户端在的。&lt;/p&gt;
&lt;p&gt;这个时候，如果能知道 Sidecar 的访问地址，是可以不进行流量劫持的，由客户端直接将请求发给 Sidecar 就好了。所以，最基本的想法就是通过环境变量或者配置给出 Sidecar 的地址，告诉客户端 Sidecar 就在 localhost 的8080端口。然后客户端SDK简单读取一下，接下来直接将请求发过去就好了。这个方案可以轻松的绕开流量劫持的问题。&lt;/p&gt;
&lt;p&gt;这个方案我们内部也实践过，早期用来替代多语言客户端的版本用的是这个方案。当然，实践中发现流量劫持还是有必要的，这是另外一个话题，后面有机会再详细解释。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;但上面这三个都不是今天的重点，今天的重点是下面这个 Cilium + eBPF 的思路，这是我们目前最密切关注的一个方案。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-20_hu2f9e6bda80b88a9592de2ad586e7d9a8_283011_1a733e0b2eaabd7b9d0e4e72869d3666.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-20_hu2f9e6bda80b88a9592de2ad586e7d9a8_283011_408990a7b783124fe520ac7430323040.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-20_hu2f9e6bda80b88a9592de2ad586e7d9a8_283011_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-20_hu2f9e6bda80b88a9592de2ad586e7d9a8_283011_1a733e0b2eaabd7b9d0e4e72869d3666.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Cilium是一个很新的项目，Cilium的思路中会涉及到底层通讯中TCP堆栈的问题。&lt;/p&gt;
&lt;p&gt;这里的图片显示了用 iptables 和轻量级客户端方案的网络调用细节，左边是客户端 Service 和它的 Sidecar 之间的调用过程，可以看到它走了两次的TCP堆栈。然后还有 iptables 的拦截。轻量级客户端方案和流量劫持方案的差别在于减少一次iptables，避开了iptables的性能消耗。但是即使没有 iptables，最终还是要走整个调用流程，虽然 Loopback 环回地址比network 网络通讯快很多，但是它终究还是走了两次TCP堆栈，两次TCP堆栈这里是有性能消耗的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-21_hu1466b20c38da655bdfb975f8a6a3427c_157276_3f8bba899de84139f8f5d6eb1e6037c8.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-21_hu1466b20c38da655bdfb975f8a6a3427c_157276_74403dfefc81631ea7618e85e5d7cdb3.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-21_hu1466b20c38da655bdfb975f8a6a3427c_157276_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-21_hu1466b20c38da655bdfb975f8a6a3427c_157276_3f8bba899de84139f8f5d6eb1e6037c8.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而Cilium则给出了一个很好的思路：想办法绕开TCP堆栈。&lt;/p&gt;
&lt;p&gt;Cilium方案的好处，就在于在 socket 这个层面就完成了请求的转发，通过 sockmap 技术实现 redirect，当然这个技术细节咱们就不在这里展开。今天主要是讲一下这个思路的好处和价值。Cilium 方案最大的好处，是可以绕开两次TCP堆栈，绕开两次TCP堆栈的好处，则会带来一个出乎意外甚至违背常识的结果：Cilium 劫持可以比轻量级客户端不劫持更快！这可能颠覆大家的观念。&lt;/p&gt;
&lt;p&gt;我们来体会一下。流量劫持，如 iptables，是要在原来的调用链当中插入一段，增加消耗导致性能下降，对吧？这是流量劫持最容易给人的留下的负面印象，就是流量劫持是有消耗的，所以优化的思路通常都在于减少这个消耗，或者选择不做劫持从而避开这个消耗。那 Cilium 的做法则是给出另外一种解决流量劫持问题的思路：通过绕开两次TCP堆栈和其他底层细节，更快的将请求转发给 Sidecar！&lt;/p&gt;
&lt;p&gt;Cilium的这个思路是我们非常赞赏的，通过这样的方式减少服务和 Sidecar 之间的性能损失，可以解决 Service Mesh 中至关重要的一个问题：&lt;strong&gt;性能与架构的取舍&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;熟悉 Service Mesh 技术的同学，应该多少都有这样的认知： Service Mesh 是一门中庸的艺术。在性能与架构之间， Service Mesh 选择牺牲性能来换取架构。在传统的侵入式框架中，客户端业务代码和框架代码之间是通过函数来进行调用的，速度非常快完全可以忽略。而 Service Mesh 是强行把框架和类库剥离出来，将上述的方法调用变成一个远程调用，以牺牲了一次远程调用的开销为代价来换取整个架构的优化空间。这是 Service Mesh 技术和传统侵入式框架的一个本质差异，也是 Service Mesh 技术和传统侵入式框架所有差异的源头。&lt;/p&gt;
&lt;p&gt;这是 Service Mesh 技术最为重要的一次取舍：舍弃一次远程调用的开销，换取更富有弹性的架构和更丰富的功能。&lt;/p&gt;
&lt;p&gt;Service Mesh 技术的发展，也由此出现两个大方向：一方面是继续在架构上获取好处，更多的功能，更丰富的使用场景，各种创新，竭尽可能的获取红利；另一方面，是在舍字上下功夫，尽可能的将性能损失降到最低，以求得到前面的最大好处而将付出的代价降到最低。&lt;/p&gt;
&lt;p&gt;我们在前面列出的这四个实践，都可以说是在这条贪心的路上一步一步的探索和尝试，希望可以将 Service Mesh 架构上的舍弃的部分再尽可能多的要回一部分。&lt;/p&gt;
&lt;p&gt;当然，Cilium 在实际落地的时候还是会有一些问题，比如说现在最大的问题是 Cilium 对 Linux 内核的版本要求特别高，最低要求是4.9推荐4.10，然后里面的部分特性要求是4.14。Linux 内核4.14是2017年底才发布的，而目前 Linux 内核最新版本才4.18。Cilium 要求的 Linux 内核的版本实在太新了，部署时很难满足。另外就是 Cilium 还是存在一些安全问题，主要是 eBPF 是将代码直接注入到内核运行，效率好是好，但是肯定会存在安全隐患。&lt;/p&gt;
&lt;p&gt;我们接下来会重点跟踪 Cilium 技术，也有可能会给出其它的类似方案，有兴趣的同学可以关注我们的进展。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-22_hu7a6ed95c3650b4af1683c66766ffd020_139925_dd65a188774c6fa73f00a7089842263c.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-22_hu7a6ed95c3650b4af1683c66766ffd020_139925_b86675e17557ef40100a4435a1329c5b.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-22_hu7a6ed95c3650b4af1683c66766ffd020_139925_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-22_hu7a6ed95c3650b4af1683c66766ffd020_139925_dd65a188774c6fa73f00a7089842263c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;继续给大家介绍今天的第四部分内容，对服务间通讯范围的探索。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-23_hu5c2465a00b473e6a40542b6c4670bcba_235795_f420e9e29f409f39344abbb93c62d12e.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-23_hu5c2465a00b473e6a40542b6c4670bcba_235795_fb9daa55e22c328cba5903c72d29bf93.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-23_hu5c2465a00b473e6a40542b6c4670bcba_235795_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-23_hu5c2465a00b473e6a40542b6c4670bcba_235795_f420e9e29f409f39344abbb93c62d12e.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Service Mesh 起初关注的是东西向通讯，即系统内部各个服务之间的通讯，而这通常都是同步的，走REST或者RPC协议。&lt;/p&gt;
&lt;p&gt;在Service Mesh的实践过程中，我们发现，Service Mesh 可以提供的功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;请求转发：如服务发现，负载均衡等&lt;/li&gt;
&lt;li&gt;路由能力：如强大的 Content Based Routing 和 Version Based Routing&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;可以适用于 Service Mesh 之外的其他领域，也就是说我们可以在其他领域引入并重用这些能力，实现比单纯的东西向通讯更广泛的服务间通讯。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-24_hu8d472dccd489053e7e12e4823011db3e_81139_17bb00f7a5ba6c7326972af4764c9177.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-24_hu8d472dccd489053e7e12e4823011db3e_81139_3e8895ad142eba01242cb9835facc2ee.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-24_hu8d472dccd489053e7e12e4823011db3e_81139_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-24_hu8d472dccd489053e7e12e4823011db3e_81139_17bb00f7a5ba6c7326972af4764c9177.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第一个探索的方向是 API Gateway，和东西向通讯直接对应的南北向通讯。&lt;/p&gt;
&lt;p&gt;主要原因是南北向通讯和东西向通讯在功能上高度重叠，如服务发现，负载均衡，路由，灰度，安全，认证，加密，限流，熔断&amp;hellip;&amp;hellip;因此，重用东西向通讯的这些能力就成为自然而然的想法。&lt;/p&gt;
&lt;p&gt;传统侵入式框架下，重用这些能力的方式是基于类库方式，也就是在 API Gateway 的实现中，典型如 Zuul，引入东西向通讯中的类库。而 Service Mesh下，思路有所不同，重用的不再是类库，而是 Sidecar：通过将 Sidecar 用于南北向通讯，重用 Sidecar 的请求转发和服务治理功能。&lt;/p&gt;
&lt;p&gt;将 Service Mesh 引入 API Gateway 的优势在于:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;统一微服务和 API Gateway 两套体系&lt;/li&gt;
&lt;li&gt;大量节约学习/开发/维护的成本&lt;/li&gt;
&lt;li&gt;可以在南北向通讯中获得 Service Mesh 的各种特性&lt;/li&gt;
&lt;li&gt;可以通过 Service Mesh 的控制平面加强对南北向通讯的控制力&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个方向上，业界也有一些探索：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ambassador: Kubernetes-native microservices API gateway，基于Envoy构建，开源项目&lt;/li&gt;
&lt;li&gt;Gloo: The Function Gateway built on top of Envoy，同样是基于Envoy，不过这个不仅仅用于传统的微服务API Gateway，也可以用于Serverless架构的Function&lt;/li&gt;
&lt;li&gt;Kong：在最近宣布，即将发布的1.0版本，kong将不再是单纯的 API Gateway，而是转型为服务控制平台。可谓是一个反向的探索案例：从 API Gateway 向 Service Mesh 切。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而我们的思路也非常明确：在 SOFAMesh 和 SOFAMosn 的基础上，打造新的 API Gateway 产品，以此来统一东西向通讯和南北向通讯。目前该项目已经启动，后续也会作为开源项目公布出来，对这个话题有兴趣的同学可以保持关注。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-25_hue835b22ead3c1720a370c3271d224591_100722_859ee242051ca6888a9bb2028ce3100a.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-25_hue835b22ead3c1720a370c3271d224591_100722_6b603525ff3c19ca698c723f5c27c8a2.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-25_hue835b22ead3c1720a370c3271d224591_100722_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-25_hue835b22ead3c1720a370c3271d224591_100722_859ee242051ca6888a9bb2028ce3100a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;前段时间我们在考虑 Serverless 方向时，刚好看到 Google 新推出了它的 Serverless 新项目 Knative，时间点非常的巧。和其他 Serverless 项目不同的是，Knative 项目关注的是 Serverless 平台的标准化和规范化。&lt;/p&gt;
&lt;p&gt;Knative 项目是基于 kubernetes 和 Istio 的，在 Knative 中 Istio 用于实现部分组件之间的通讯。在 Knative 项目中，对于是否应该引入 Istio 存在很大争议，因为觉得 Istio 太重了，为了少量需求引入 Istio 有些兴师动众。不过这个问题对于本来就已经在用 Istio 的我们来说不是问题。&lt;/p&gt;
&lt;p&gt;目前在 Serverless，尤其 Knative 方面，我们还在探索，目前的初步想法是这样：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Serverless 很重要&lt;/p&gt;
&lt;p&gt;尤其 Knative 的出现，昭示着 Serverless 领域新的玩法出现，Serverless 平台出现标准化和统一化的契机&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Kubernetes + Serverless + Service Mesh（尤其是扩展范围之后的 Service Mesh）是一个很好的组合&lt;/p&gt;
&lt;p&gt;从下向上，从底层基础设施到服务间通讯再到 Function，在应用和系统之间形成了一套完整的支撑体系。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;后续我们的产品策略，会继续深入调研 knative，一边POC一边规划产品，当然结合实际业务需要以落地为目标依然是基本要求。然后，非常自然的，我们会将标准版本的 Istio 替换为我们的 SOFAMesh 和 SOFAMosn。&lt;/p&gt;
&lt;p&gt;举例，目前我们在计划尝试使用 Serverless 的典型场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;小程序&lt;/li&gt;
&lt;li&gt;AI：Serverless AI Layer，一站式机器学习平台&lt;/li&gt;
&lt;li&gt;Databus： 大数据处理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-26_hu41d512c407a9c9e953da5461831340f0_93104_344aa717fcce3e230484560859414af1.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-26_hu41d512c407a9c9e953da5461831340f0_93104_0b60dff605f1ead74d854beead23292c.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-26_hu41d512c407a9c9e953da5461831340f0_93104_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-26_hu41d512c407a9c9e953da5461831340f0_93104_344aa717fcce3e230484560859414af1.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是我们目前探索和规划中的服务间通讯的完整蓝图：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Service Mesh&lt;/p&gt;
&lt;p&gt;负责东西向通讯，实践中就是我们的 SOFAMesh 产品，基于 Istio 的扩展增强版&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;API Gateway&lt;/p&gt;
&lt;p&gt;负责南北向通讯，还在探索中，我们在尝试基于 SOFAMosn 和 SOFAMesh 开发新的 API Gateway 产品&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Serverless&lt;/p&gt;
&lt;p&gt;负责异步通讯，事件驱动模型，粒度也从服务级别细化到Function级别，目前在积极探索和实践 knative&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这里给出一个我们的预测：在云原生的时代，服务间通讯的未来都会是  Service Mesh 这种方式，将服务间通讯的职责剥离并下沉。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-27_hudf417965f6d7a94767195403c8c4da37_139927_1e515c366ca2848df5ca25914744f157.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-27_hudf417965f6d7a94767195403c8c4da37_139927_d5dc8f209657c769c8701226657eae3e.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-27_hudf417965f6d7a94767195403c8c4da37_139927_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-27_hudf417965f6d7a94767195403c8c4da37_139927_1e515c366ca2848df5ca25914744f157.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是今天的最后内容。前面四个部分的内容基本上都是给大家介绍我们的产品实践，落地遇到的问题，以及我们正在做的一些探索，比较偏实际。第五部分会特殊一点，可能就有点&lt;strong&gt;务虚&lt;/strong&gt;了。这块要讲是在过去一年当中，在项目落地的过程中的特别感受，其中最关键的一点就是基础设施和服务网格之间的关系，或者说基础设施对服务网格的意义。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-28_hu0088abf4fcf4984eb3a822de4a604c88_73828_8a789807672d9a93a17e4eb7bcf3bffe.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-28_hu0088abf4fcf4984eb3a822de4a604c88_73828_e6fff94877b7bf8bebad1b46c8f785ff.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-28_hu0088abf4fcf4984eb3a822de4a604c88_73828_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-28_hu0088abf4fcf4984eb3a822de4a604c88_73828_8a789807672d9a93a17e4eb7bcf3bffe.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;里面有一个时代背景：Cloud Native，云原生。而在今年6月，CNCF 技术监督委员会通过了 Cloud Native 的定义，中文翻译如上。&lt;/p&gt;
&lt;p&gt;这里我们将关注点放在标红的这一句来：云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式API。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-29_hu47482d8413d4eac1dec6b82722a5145b_84292_b0082ab4ca6314fea468e2bc845fa41c.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-29_hu47482d8413d4eac1dec6b82722a5145b_84292_227aafdada9d991c771e75bf519b2f6a.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-29_hu47482d8413d4eac1dec6b82722a5145b_84292_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-29_hu47482d8413d4eac1dec6b82722a5145b_84292_b0082ab4ca6314fea468e2bc845fa41c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对于云原生架构，蚂蚁金服的策略是：积极拥抱! 我们未来的架构也会往这个方向演进。&lt;/p&gt;
&lt;p&gt;对于前面列举的云原生代表技术：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;容器：大阿里在容器技术上有非常深度的积累，实践多年，而新版本的 Sigma3.* 版本也将基于 k8s。&lt;/li&gt;
&lt;li&gt;微服务：微服务的前身，SOA 服务化，在大阿里也是实践多年， Dubbo / HSF / SOFA 可谓名满江湖，目前也在陆陆续续的微服务改造中。&lt;/li&gt;
&lt;li&gt;不可变基础设施和声明式API：也是高度认可和长期实践的技术。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-30_hu1d07dc703c9d139809dc30ded14ac07f_46300_e0576c4f27449e7a1bd786d452010a6a.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-30_hu1d07dc703c9d139809dc30ded14ac07f_46300_ee7959857ff8bd77b96c610406254805.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-30_hu1d07dc703c9d139809dc30ded14ac07f_46300_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-30_hu1d07dc703c9d139809dc30ded14ac07f_46300_e0576c4f27449e7a1bd786d452010a6a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对于Service Mesh的定位，我们是这样理解的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Service Mesh 是承上启下的重要一环&lt;/li&gt;
&lt;li&gt;一方面充分利用底层系统能力&lt;/li&gt;
&lt;li&gt;一方面为上层应用提供坚实的底座&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-31_hu3dceabea7a9723a039f6dd606b208029_164594_cf61f9cfb724e682f7ef2d1dc6e3e727.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-31_hu3dceabea7a9723a039f6dd606b208029_164594_1a4da68b8eca019cd3e2d2ef96339d82.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-31_hu3dceabea7a9723a039f6dd606b208029_164594_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-31_hu3dceabea7a9723a039f6dd606b208029_164594_cf61f9cfb724e682f7ef2d1dc6e3e727.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对于 Service Mesh，我们有一个重要判断，这也是今天最想和大家分享的一点：Service Mesh 的归宿，或者说最终的形态，是下沉到基础设施！&lt;/p&gt;
&lt;p&gt;从 Service Mesh 的发展看，从简单的 Proxy，到功能完善的Sidecar（如Linkerd和Envoy），再到以 Istio 为代表的第二代Service Mesh，演进的方式如上图：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;第一步：从应用剥离&lt;/p&gt;
&lt;p&gt;通过将原有的方法调用改为远程调用，将类库的功能套上 Proxy 的壳子，Service Mesh 成功的将服务间通讯从程序中剥离出来，从此服务间通讯不再是应用程序的一部分。&lt;/p&gt;
&lt;p&gt;这一点是大家最容易接受的，对吧？这一步也是最容易实现的，只要搭起来一个 Sidecar 或者说 Proxy，将原有类库的功能塞进去就好了。&lt;/p&gt;
&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;li&gt;
&lt;p&gt;第三步：融入基础设施&lt;/p&gt;
&lt;p&gt;继续下沉，和底层基础设施密切联系，进而融为一体，成为平台系统的一部分，典型就是和 kubernetes 结合。&lt;/p&gt;
&lt;p&gt;Istio在这方面做了一个非常大的创新，Istio的创新，不仅仅在于增加控制平面，也在于和 kubernetes 的结合。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果大家有在去年QCon听过我的演讲，会发现我在去年的时候对 Service Mesh 的理解和现在不太一样。在去年的这个时候，我认为 Istio 最大的创新是增加了控制平面。但是，今年我觉得还再加一个关键点，除了控制平面的增加之外，Istio很重要的一点是开始跟k8s融合，充分利用 k8s 的能力。k8s 代表的是底层基础设施，所有的各种能力在k8s上沉淀。在Istio上，已经能够看到这样一个非常明显的趋势： Service Mesh 已经开始和底层基础设施密切联系，融为一体，成为整个平台系统的一部分。&lt;/p&gt;
&lt;p&gt;大家注意体会这中间的细微差异，第一步和第二步，将服务间通讯的能力抽取出来沉淀成一个抽象层，而如果止步于第二步的话，这个抽象层和底层基础设施是没有任何关系的。注意，比如说 Linkerd 或者 Envoy，在部署的时候，不管是物理机、虚拟机或者容器，都没有任何关系，本身也不利用底层的任何能力，可谓泾渭分明。但是一旦演进到了Istio，包括现在的Linkerd 2.0，就会发现转为第三步的这种形态。&lt;/p&gt;
&lt;p&gt;今天想跟大家说的是，&lt;strong&gt;Service Mesh 的未来，是将服务间通讯的能力下沉到基础设施&lt;/strong&gt;，然后充分利用底层基础设施的能力来架构整个体系。而不再将底层基础设施抽象成为就是一个简单的操作系统抽象：给我cpu，给我内存，给我网络，给我IO，其他的事情和底层没有任何关系，我自己上面全部搞定。这个思路在 Service Mesh 的未来发展中是不合适的， Service Mesh 未来一定是通过和基础设施融合的方式来实现。&lt;/p&gt;
&lt;p&gt;注意这个方式跟传统方式的差异，不仅仅在于技术，而是这个方式会混淆两个传统的部门：一个叫做中间件，就像我所在的部门，或者有些公司叫做基础架构部门；还有一个部门通常是运维部门或者叫做系统部门，负责维护底层基础设施。大部分公司一般这两个部门在组织架构上是分离的。做k8s的同学，和做微服务框架比如 Dubbo，Spring Cloud 的同学，通常是两个不同的组织架构，彼此泾渭分明。第三步要走通的话，就会要求中间件部门和基础设施部门关系要协调的特别好，要密切的合作，才能将事情做好。&lt;/p&gt;
&lt;p&gt;这是在过去这一年当中，我们在实践中得到的最大的一个感受，也是今天整个演讲中最希望给大家分享的内容。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-32_hu13a66e43f13ea30413b05b16a0fb4871_30431_1cee307d0b722ef9cf4bbe1b4295d1b0.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-32_hu13a66e43f13ea30413b05b16a0fb4871_30431_a548175c34d1c69e9aba376ec525300a.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-32_hu13a66e43f13ea30413b05b16a0fb4871_30431_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-32_hu13a66e43f13ea30413b05b16a0fb4871_30431_1cee307d0b722ef9cf4bbe1b4295d1b0.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里抛出一个问题，和传统的 Spring Cloud，Dubbo等侵入式框架相比：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Service Mesh的本质差异在哪里？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果去年的我来回答这个问题，那我会告诉你：下移，沉淀，形成一个通讯层。而今天，我会告诉大家，除了这点之外，还有第二点：充分利用底层基础设施。这是Dubbo，Spring Cloud从来没有做到的！&lt;/p&gt;
&lt;p&gt;这是今天最想和大家分享的观点，也是过去一年实践中最大的感悟：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Service Mesh 和 Spring Cloud / Dubbo 的本质差异，不仅仅在于将服务间通讯从应用程序中剥离出来，更在于一路下沉到基础设施层并充分利用底层基础设施的能力。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-33_hu38dfa5a1ad6c67dceca1d890fcdc66b1_140320_d4ed54d40c4b338c959903732fe448ee.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-33_hu38dfa5a1ad6c67dceca1d890fcdc66b1_140320_d92bef24fa79772efee274e23325e9f8.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-33_hu38dfa5a1ad6c67dceca1d890fcdc66b1_140320_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-33_hu38dfa5a1ad6c67dceca1d890fcdc66b1_140320_d4ed54d40c4b338c959903732fe448ee.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最后，我们总结一下今天的内容：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;给大家介绍了一下我们的 SOFAMesh 项目，如果大家有计划应用  Service Mesh 技术，想上 Istio，可以尝试了解一下我们的这个项目，会让大家落地更舒服一些&lt;/li&gt;
&lt;li&gt;其次给大家介绍了选择 Golang 的原因，主要是因为语言栈的长期选择。如果有正在进行 Service Mesh 技术选择的同学，可以作为参考。如果和我们一样，更愿意在未来保持 Golang 和 Java 为主要语言栈，则可以参考我们的方案，当然我们更希望你们可以和我们一起来共建 SOFAMesh 这个开源项目&lt;/li&gt;
&lt;li&gt;然后给大家分享了我们遇到的几个典型问题，如何快速的支持更多通讯协议，如何让传统的SOA架构的应用程序在不进行代码修改的情况下也能从 Service Mesh 中受益，实现系统的平滑迁移。对于准备实际落地的同学会有帮助，由于时间所限未能将细节展开，大家可以会后查看资料或者直接找我们交流&lt;/li&gt;
&lt;li&gt;对服务间通讯的范围进行了探讨，从原有的东西向通讯，扩展到南北向通讯，还有在 serverless 项目中的使用。希望能够让大家了解到 Service Mesh 技术可以应用的更多场景。&lt;/li&gt;
&lt;li&gt;最后谈了一下切身感受：Service Mesh 技术要想完全发挥作用，需要和底层基础设施融合，以充分发挥基础设施的能力。这块的认知，会影响到 Service Mesh 的技术选型，产品方案，甚至影响组织关系。可谓至关重要，希望每位有志于此的同学能认认真真的审视这个问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-34_hub3999adc7bd370f2f32c3895f5eb7191_1186787_0a4f3f79bad28a8962f0b4047b808915.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-34_hub3999adc7bd370f2f32c3895f5eb7191_1186787_5c582e5da88519345df56056daf950b5.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-34_hub3999adc7bd370f2f32c3895f5eb7191_1186787_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-34_hub3999adc7bd370f2f32c3895f5eb7191_1186787_0a4f3f79bad28a8962f0b4047b808915.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Service Mesh 是一个新生事物，新事物在刚出现时总是会遇到各种挑战和质疑，尤其在它自身还不够完全成熟的时候。而Service Mesh 背后的Cloud Native，更是一场前所未有的巨大变革。&lt;/p&gt;
&lt;p&gt;我们心怀美好愿景，憧憬未来的 Cloud Native 架构，那里有我们的 Service Mesh，有k8s，有微服务&amp;hellip;&amp;hellip;而新的架构，新的技术，从来都不是能一蹴而就的，更不存在一帆风顺之类的美好而天真的想法。&lt;/p&gt;
&lt;p&gt;道路从来都是人走出来的，或者说，趟出来的。作为国内 Service Mesh 技术的先驱者，我们坦言 Service Mesh 技术还不够成熟，还有很多问题等待解决，还有非常多的挑战在前面等着我们。但我们有信心相信，我们的方向是正确的，我们今天的每一份努力，每一份付出，都在让我们离目标更近一步。&lt;/p&gt;
&lt;p&gt;鲁迅先生说：地上本没有路，走的人多了，也便成了路。在 Service Mesh 的这个方向，相信会出现越来越多努力探索的身影。这条路，我们终究会努力趟出来！&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;长路漫漫，吾辈当踏歌而行！&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-35_hu7748589be1eac94b6fa1b94f2d11c00a_85367_0f3fc290ba38b5ef462ccb8fb521f447.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-35_hu7748589be1eac94b6fa1b94f2d11c00a_85367_86ceb0b721ad12df09b71e137b6b2f66.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-35_hu7748589be1eac94b6fa1b94f2d11c00a_85367_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-35_hu7748589be1eac94b6fa1b94f2d11c00a_85367_0f3fc290ba38b5ef462ccb8fb521f447.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;目前 SOFAMesh 和 SOFAMosn 项目都已经在 github 开源，地址如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;sofa-mesh: &lt;a href=&#34;https://github.com/alipay/sofa-mesh&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/alipay/sofa-mesh&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;sofa-mosn: &lt;a href=&#34;https://github.com/alipay/sofa-mosn&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://github.com/alipay/sofa-mosn&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;欢迎大家关注这两个项目的进展，如果能star一下表示支持就更好了，感激不尽！&lt;/p&gt;
&lt;p&gt;更希望可以一起来参与这两个项目的建设，期待Issue，期待PR！&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-36_hu572c930ca6bd894ee65a868e4a6b4446_66988_32d56c9a3cfcba1a99760cc116400de6.webp 400w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-36_hu572c930ca6bd894ee65a868e4a6b4446_66988_3a1c68f3ed733be6f8025f52db86f719.webp 760w,
               /talk/201810-ant-finance-service-mesh-practice/images/ppt-36_hu572c930ca6bd894ee65a868e4a6b4446_66988_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201810-ant-finance-service-mesh-practice/images/ppt-36_hu572c930ca6bd894ee65a868e4a6b4446_66988_32d56c9a3cfcba1a99760cc116400de6.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对 Service Mesh 技术感兴趣的同学，可以关注servicemesher社区，这是一个中立的纯技术社区，汇集了当前国内大部分 Service Mesh 的技术人员。我本人也是 servicemesher 社区的创始人之一，这个社区的使命是传播 Service Mesh 技术，加强行业内部交流，促进开源文化构建，推动 Service Mesh 在企业落地。&lt;/p&gt;
&lt;p&gt;可以通过访问社区网站 &lt;a href=&#34;http://www.servicemesher.com&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;http://www.servicemesher.com&lt;/a&gt; 获取各种技术资讯和社区活动信息，可以关注 servicemesher 社区的微信公众号得到及时的信息推动。我们拥有一个庞大的翻译组，除了翻译各种  Service Mesh  相关的技术博客和新闻，还负责 Envoy 和 Istio 两个项目官方文档的日常维护。&lt;/p&gt;
&lt;p&gt;也欢迎大家加入 servicemesher 社区的微信交流群，请按照 servicemesher.com 网站的 &amp;ldquo;联系我们&amp;rdquo; 页面的要求加入微信交流群。&lt;/p&gt;
&lt;p&gt;最后，厚颜推荐一下我自己的个人技术博客 &lt;a href=&#34;https://skyao.net&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.net&lt;/a&gt; ，欢迎浏览和交流。&lt;/p&gt;
&lt;p&gt;今天的内容到此结束，非常感谢大家的聆听，有缘下次再会！谢谢大家！&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>SOFAMesh中的多协议通用解决方案x-protocol介绍系列(3)-TCP协议扩展</title>
      <link>https://skyao.net/post/201809-xprotocol-tcp-protocol-extension/</link>
      <pubDate>Thu, 20 Sep 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201809-xprotocol-tcp-protocol-extension/</guid>
      <description>&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;在Istio和Envoy中，对通讯协议的支持，主要体现在HTTP/1.1和HTTP/2上，这两个是Istio/Envoy中的一等公民。而基于HTTP/1.1的REST和基于HTTP/2的gRPC，一个是目前社区最主流的通讯协议，一个是未来的主流，google的宠儿，CNCF御用的RPC方案，这两个组成了目前Istio和Envoy（乃至CNCF所有项目）的黄金组合。&lt;/p&gt;
&lt;p&gt;而我们SOFAMesh，在第一时间就遇到和Istio/Envoy不同的情况，我们需要支持REST和gRPC之外的众多协议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SOFARPC：这是蚂蚁金服大量使用的RPC协议(已开源)&lt;/li&gt;
&lt;li&gt;HSF RPC：这是阿里集团内部大量使用的RPC协议(未开源)&lt;/li&gt;
&lt;li&gt;Dubbo RPC: 这是社区广泛使用的RPC协议(已开源)&lt;/li&gt;
&lt;li&gt;其他私有协议：在过去几个月间，我们收到需求，期望在SOFAMesh上运行其他TCP协议，部分是私有协议&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为此，我们需要考虑在SOFAMesh和SOFAMosn中增加这些通讯协议的支持，尤其是要可以让我们的客户非常方便的扩展支持各种私有TCP协议：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-tcp-protocol-extension/images/supported-protocol_hu4b5d390c7844cf8ce6c3b61c782fb02f_53835_8a70d11d7d8b313cd37543fb5f5e4fc8.webp 400w,
               /post/201809-xprotocol-tcp-protocol-extension/images/supported-protocol_hu4b5d390c7844cf8ce6c3b61c782fb02f_53835_09c83a47e8048fd830e355014133ddd4.webp 760w,
               /post/201809-xprotocol-tcp-protocol-extension/images/supported-protocol_hu4b5d390c7844cf8ce6c3b61c782fb02f_53835_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-tcp-protocol-extension/images/supported-protocol_hu4b5d390c7844cf8ce6c3b61c782fb02f_53835_8a70d11d7d8b313cd37543fb5f5e4fc8.webp&#34;
               width=&#34;594&#34;
               height=&#34;485&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;实现分析&#34;&gt;实现分析&lt;/h2&gt;
&lt;p&gt;我们来大体看一下，在SOFAMesh/Istio中要新增一个通讯协议需要有哪些工作：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-tcp-protocol-extension/images/tbd_hu7d50621cc2c2d0cbfb0d52e5292ba5ed_74747_91c1f6e3bc5833fd7aaf3bae4d9384d9.webp 400w,
               /post/201809-xprotocol-tcp-protocol-extension/images/tbd_hu7d50621cc2c2d0cbfb0d52e5292ba5ed_74747_a1c0f5d4894dc50da6bfe23093380393.webp 760w,
               /post/201809-xprotocol-tcp-protocol-extension/images/tbd_hu7d50621cc2c2d0cbfb0d52e5292ba5ed_74747_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-tcp-protocol-extension/images/tbd_hu7d50621cc2c2d0cbfb0d52e5292ba5ed_74747_91c1f6e3bc5833fd7aaf3bae4d9384d9.webp&#34;
               width=&#34;760&#34;
               height=&#34;327&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;protocol decoder：负责解析协议，读取协议字段&lt;/li&gt;
&lt;li&gt;protocol encoder：负责生成请求报文，注意通常会有改动，比如修改某些header&lt;/li&gt;
&lt;li&gt;在pilot中需要为新协议生成 Virtual Host 等配置，有 inbound 和 outbound 两份，分别下发到Sidecar&lt;/li&gt;
&lt;li&gt;在Sidecar中，根据下发的 Virtual Host 等配置，进行请求匹配，以决定请求该转发到何处&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：实际下发的配置不止 Virtual Host 配置，为了简单期间，我们仅以 Virtual Host 为例做讲解&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;其中，protocol encoder和protocol decoder是容易理解的，对于新的通讯协议肯定需要有协议编解码层面的工作必须要完成，这块有工作量是很自然的。&lt;/p&gt;
&lt;p&gt;我们来看看第三块的工作量是什么，inbound 和 outbound 的Virtual Host配置示例如下：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-tcp-protocol-extension/images/outbound_hud9b9c178eae581b5514140397bcba88a_138013_333329872b9f4bf7a0cace7d3626ebca.webp 400w,
               /post/201809-xprotocol-tcp-protocol-extension/images/outbound_hud9b9c178eae581b5514140397bcba88a_138013_e4c82177a2056561ba70c6d22b7c7de7.webp 760w,
               /post/201809-xprotocol-tcp-protocol-extension/images/outbound_hud9b9c178eae581b5514140397bcba88a_138013_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-tcp-protocol-extension/images/outbound_hud9b9c178eae581b5514140397bcba88a_138013_333329872b9f4bf7a0cace7d3626ebca.webp&#34;
               width=&#34;760&#34;
               height=&#34;593&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;outbound 配置中，注意 domains 字段是各种域名和ClusterIP，而 routes 中，match是通过prefix来匹配。我们结合HTTP/1.1，domains字段是用来和请求的Host header进行域名匹配的，比如 &lt;code&gt;Host: istio-telemetry&lt;/code&gt;，这决定了哪些请求是要转发到 istio-telemetry 这个服务的。routes的match用来进行路由匹配的，通过HTTP请求的path进行匹配。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-tcp-protocol-extension/images/inbound_hu16ee50cfe930c8b969e366dc6e9e5cd3_83832_fd833d751707a136e336c652bced9f12.webp 400w,
               /post/201809-xprotocol-tcp-protocol-extension/images/inbound_hu16ee50cfe930c8b969e366dc6e9e5cd3_83832_0b8c3475c5b03b455b660df2267f5498.webp 760w,
               /post/201809-xprotocol-tcp-protocol-extension/images/inbound_hu16ee50cfe930c8b969e366dc6e9e5cd3_83832_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-tcp-protocol-extension/images/inbound_hu16ee50cfe930c8b969e366dc6e9e5cd3_83832_fd833d751707a136e336c652bced9f12.webp&#34;
               width=&#34;760&#34;
               height=&#34;526&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;inbound 配置类似，只是inbound更简单，domains匹配&lt;code&gt;*&lt;/code&gt;就可以。&lt;/p&gt;
&lt;p&gt;从上面的例子中可以看到，Istio和Envoy的设计有非常浓重的HTTP协议的味道，各种语义都是和HTTP直接相关。而当我们进行TCP协议的转发时，就需要将请求的协议字段进行映射，映射到HTTP的相应语义。&lt;/p&gt;
&lt;p&gt;比如，最基本的Destination，原始语义是请求的目的地，在前面的文章中我们指出过这是请求转发最关键的字段。在HTTP协议中，通常是通过Host header和Path表示，对于REST而言还有重要的Method字段。&lt;/p&gt;
&lt;p&gt;下面的格式是其他各种协议对这个Destination原始语义的实际实现方式：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&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;原始语义&lt;/td&gt;
&lt;td&gt;请求的目的地(Destination)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP/1.1&lt;/td&gt;
&lt;td&gt;Host header，Method，Path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP/2&lt;/td&gt;
&lt;td&gt;Header帧中的伪header &lt;code&gt;:authority&lt;/code&gt;，&lt;code&gt; :path&lt;/code&gt;和&lt;code&gt; :method&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bolt协议&lt;/td&gt;
&lt;td&gt;header map中key为&amp;quot;service&amp;quot;的字段&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HSF协议&lt;/td&gt;
&lt;td&gt;协议头中的服务接口名和服务方法名&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dubbo协议&lt;/td&gt;
&lt;td&gt;data字段（payload）中的path/method&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这些通讯协议在下发规则和进行请求匹配时，就需要进行协调：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;定义好 Virtual Host 配置中的 domains 字段和 route 中的 match 用到的字段在当前通讯协议中的实际语义&lt;/li&gt;
&lt;li&gt;在 protocol encoder 中读取请求的协议字段，和上面的字段对应&lt;/li&gt;
&lt;li&gt;然后进行请求路由规则匹配（参照HTTP/1.1中的domain和route match的匹配）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而这些都是需要以代码的方式进行实现，以满足新通讯协议的要求。正规的做法，是每次新增一个通讯协议就将上述的工作内容重复一遍。这会直接导致大量的高度类似的重复代码。&lt;/p&gt;
&lt;h2 id=&#34;x-protocol的实现&#34;&gt;x-protocol的实现&lt;/h2&gt;
&lt;p&gt;在上述需要在协议扩展时修改的四个内容中，有一块是特别的：生成 Virtual Host 配置的工作是在Pilot中实现的，而其他三个是在Sidecar （Envoy或MOSN）中。考虑到 protocol encoder 和 protocol decoder 的工作是必不可少的，必然会修改Sidecar来增加实现代码，因此简化开发的第一个想法就是：能不能做到不修改Pilot？&lt;/p&gt;
&lt;p&gt;基本思路就是固定好原始语义，避免每个通讯协议都映射一遍。从前面我们列出来的各个协议的映射情况看，对于RPC协议而言，一般目的地信息都是服务名(有些是接口名)+方法名居多，因此可以考虑直接将服务名和方法名固定下来：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RPC协议在 Virtual Host 配置中就固定为服务名对应 domains 字段，方法名对应 route 中的 match 用到的字段，这样只要修改一次然后各个RPC协议公用此配置，以后就不用再重复修改Pilot。&lt;/li&gt;
&lt;li&gt;protocol encoder 在解析通讯协议完成之后，就直接将协议中对应服务名和方法名的字段提取出来，后面的匹配处理过程就可以公用一套通用实现，这样路由匹配这块也可以不用在重复开发。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，在x-protocol中，如果需要引入一个新的通讯协议，需要的工作内容只有必不可少的protocol encoder 和 protocol decoder，和实现以下几个接口：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-tcp-protocol-extension/images/xprotocol-interfaces_hubd616638a7c4cda2e92c6e1356d3dc05_121697_ec605172cacbbbe62b60fe091e1c8c72.webp 400w,
               /post/201809-xprotocol-tcp-protocol-extension/images/xprotocol-interfaces_hubd616638a7c4cda2e92c6e1356d3dc05_121697_ae51cc30cce48e4f24d3c278ae1fe7f9.webp 760w,
               /post/201809-xprotocol-tcp-protocol-extension/images/xprotocol-interfaces_hubd616638a7c4cda2e92c6e1356d3dc05_121697_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-tcp-protocol-extension/images/xprotocol-interfaces_hubd616638a7c4cda2e92c6e1356d3dc05_121697_ec605172cacbbbe62b60fe091e1c8c72.webp&#34;
               width=&#34;503&#34;
               height=&#34;517&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;X-protocol 在支持新通讯协议上的做法并无新奇之处，只是由于需求特殊有众多通讯协议需要支持，在开发时发现大量重复工作，因此我们选择了一条可以让后面更舒服一点的道路。&lt;/p&gt;
&lt;p&gt;目前这个方案在SOFAMesh中采用，我们将进一步检验实际效果，也会和合作的小伙伴时验证，看他们在自行扩展新协议时是否足够理想。这个方案理论上应该可以同样适用于Istio、Envoy体系，随着社区对Istio的接受程度的提高，在Istio上支持各种TCP通讯协议的需求会越来越多，有理由相信Istio后续可能也会出现类似的方案。毕竟，每次都改一大堆类似的东西，不是一个好做法。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>SOFAMesh中的多协议通用解决方案x-protocol介绍系列(2)-快速解码转发</title>
      <link>https://skyao.net/post/201809-xprotocol-rapid-decode-forward/</link>
      <pubDate>Wed, 19 Sep 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201809-xprotocol-rapid-decode-forward/</guid>
      <description>&lt;h2 id=&#34;背景介绍&#34;&gt;背景介绍&lt;/h2&gt;
&lt;p&gt;在Istio和Envoy中，对通讯协议的支持，主要体现在HTTP/1.1和HTTP/2上，而我们SOFAMesh，则需要支持以下几个RPC协议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SOFARPC：这是蚂蚁金服大量使用的RPC协议(已开源)&lt;/li&gt;
&lt;li&gt;HSF RPC：这是阿里集团内部大量使用的RPC协议(未开源)&lt;/li&gt;
&lt;li&gt;Dubbo RPC: 这是社区广泛使用的RPC协议(已开源)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;更适合的平衡点性能和功能&#34;&gt;更适合的平衡点：性能和功能&lt;/h3&gt;
&lt;p&gt;对于服务间通讯解决方案，性能永远是一个值得关注的点。而SOFAMesh在项目启动时就明确要求在性能上要有更高的追求，为此，我们不得不在Istio标准实现之外寻求可以获取更高性能的方式，比如支持各种RPC协议。&lt;/p&gt;
&lt;p&gt;期间有两个发现：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Istio在处理所有的请求转发如REST/gRPC时，会解码整个请求的header信息，拿到各种数据，提取为Attribute，然后以此为基础，提供各种丰富的功能，典型如&lt;strong&gt;Content Based Routing&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;而在测试中，我们发现：解码请求协议的header部分，对CPU消耗较大，直接影响性能。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此，我们有了一个很简单的想法：是不是可以在转发时，不开启部分功能，以此换取转发过程中的更少更快的解码消耗？毕竟，不是每个服务都需要用到&lt;strong&gt;Content Based Routing&lt;/strong&gt;这样的高级特性，大部分服务只使用 &lt;strong&gt;Version Based Routing&lt;/strong&gt;，尤其是使用RPC通讯协议的服务，没有HTTP那么表现力丰富的header，对Content Based Routing的需求要低很多。&lt;/p&gt;
&lt;p&gt;此外，对于部分对性能有极高追求的服务，不开启高级特性而换取更高的性能，也是一种满足性能要求的折中方案。考虑到系统中总存在个别服务对性能非常敏感，我们觉得ServiceMesh提供一种性能可以接近直连的方案会是一个有益的补充。为了满足这些特例而不至于因此整体否决Servicemesh方案，我们需要在Servicemesh的大框架下提供一个折中方案。&lt;/p&gt;
&lt;h2 id=&#34;请求转发&#34;&gt;请求转发&lt;/h2&gt;
&lt;p&gt;在我们进一步深入前，我们先来探讨一下实现请求转发的技术细节。&lt;/p&gt;
&lt;p&gt;有一个关键问题：当Envoy/MOSN这样的代理程序，接收到来自客户端的TCP请求时，需要获得哪些信息，才可以正确的转发请求到上游的服务器端？&lt;/p&gt;
&lt;h3 id=&#34;最关键的信息destination&#34;&gt;最关键的信息：destination&lt;/h3&gt;
&lt;p&gt;首先，毫无疑问的，必须拿到destination/目的地，也就是客户端请求必须通过某种方式明确的告之代理该请求的destination，这样代理程序才能根据这个destionation去找到正确的目标服务器，然后才有后续的连接目标服务器和转发请求等操作。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-rapid-decode-forward/images/destination-in-forward_huc74cba576099f95e33fb1e1f0446ff63_67884_28491e0e1c00bc9758509e2c4137a727.webp 400w,
               /post/201809-xprotocol-rapid-decode-forward/images/destination-in-forward_huc74cba576099f95e33fb1e1f0446ff63_67884_09dcd8347b8827c96a735c4ca0829333.webp 760w,
               /post/201809-xprotocol-rapid-decode-forward/images/destination-in-forward_huc74cba576099f95e33fb1e1f0446ff63_67884_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-rapid-decode-forward/images/destination-in-forward_huc74cba576099f95e33fb1e1f0446ff63_67884_28491e0e1c00bc9758509e2c4137a727.webp&#34;
               width=&#34;760&#34;
               height=&#34;314&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Destination信息的表述形式可能有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;IP地址&lt;/p&gt;
&lt;p&gt;可能是服务器端实例实际工作的IP地址和端口，也可能是某种转发机制，如Nginx/HAProxy等反向代理的地址，或者k8s中的ClusterIP。&lt;/p&gt;
&lt;p&gt;举例：&amp;ldquo;192.168.1.1:8080&amp;quot;是实际IP地址和端口，&amp;ldquo;10.2.0.100:80&amp;quot;是ngxin反向代理地址，&amp;ldquo;172.168.1.105:80&amp;quot;是k8s的ClusterIP。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;目标服务的标识符&lt;/p&gt;
&lt;p&gt;可用于名字查找，如服务名，可能带有各种前缀后缀。然后通过名字查找/服务发现等方式，得到地址列表（通常是IP地址+端口形式）。&lt;/p&gt;
&lt;p&gt;举例：&amp;ldquo;userservice&amp;quot;是标准服务名， &amp;ldquo;com.alipay/userservice&amp;quot;是加了域名前缀的服务名， &amp;ldquo;service.default.svc.cluster.local&amp;quot;是k8s下完整的全限定名。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Destination信息在请求报文中的携带方式有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;通过通讯协议传递&lt;/p&gt;
&lt;p&gt;这是最常见的形式，标准做法是通过header头，典型如HTTP/1.1下一般使用 host header，举例如&amp;quot;Host: userservice&amp;rdquo;。HTTP/2下，类似的使用&amp;rdquo;:authority&amp;rdquo; header。&lt;/p&gt;
&lt;p&gt;对于非HTTP协议，通常也会有类似的设计，通过协议中某些字段来承载目标地址信息，只是不同协议中这个字段的名字各有不同。如SOFARPC，HSF等。&lt;/p&gt;
&lt;p&gt;有些通讯协议，可能会将这个信息存放在payload中，比如后面我们会介绍到的dubbo协议，导致需要反序列化payload之后才能拿到这个重要信息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过TCP协议传递&lt;/p&gt;
&lt;p&gt;这是一种非常特殊的方式，通过在TCP option传递，上一节中我们介绍Istio DNS寻址时已经详细介绍过了。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;tcp拆包&#34;&gt;TCP拆包&lt;/h3&gt;
&lt;p&gt;如何从请求的通讯协议中获取destination？这涉及到具体通讯协议的解码，其中第一个要解决的问题就是如何在连续的TCP报文中将每个请求内容拆分开，这里就涉及到经典的TCP沾包、拆包问题。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-rapid-decode-forward/images/tcp-packge_hu2a1927aa31c8cd3f96cce7e92e6162a3_42140_9d684dbb6e229948cc93b0afcde22f39.webp 400w,
               /post/201809-xprotocol-rapid-decode-forward/images/tcp-packge_hu2a1927aa31c8cd3f96cce7e92e6162a3_42140_1d5a0758892ae5c396b17943fb0a624b.webp 760w,
               /post/201809-xprotocol-rapid-decode-forward/images/tcp-packge_hu2a1927aa31c8cd3f96cce7e92e6162a3_42140_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-rapid-decode-forward/images/tcp-packge_hu2a1927aa31c8cd3f96cce7e92e6162a3_42140_9d684dbb6e229948cc93b0afcde22f39.webp&#34;
               width=&#34;760&#34;
               height=&#34;261&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;转发请求时，由于涉及到负载均衡，我们需要将请求发送给多个服务器端实例。因此，有一个非常明确的要求：就是必须以单个请求为单位进行转发。即单个请求必须完整的转发给某台服务器端实例，负载均衡需要以请求为单位，不能将一个请求的多个报文包分别转发到不同的服务器端实例。所以，拆包是请求转发的必备基础。&lt;/p&gt;
&lt;p&gt;由于篇幅和主题限制，我们不在这里展开TCP沾包、拆包的原理。后面针对每个具体的通讯协议进行分析时再具体看各个协议的解决方案。&lt;/p&gt;
&lt;h3 id=&#34;多路复用的关键参数requestid&#34;&gt;多路复用的关键参数：RequestId&lt;/h3&gt;
&lt;p&gt;RequestId用来关联request和对应的response，请求报文中携带一个唯一的id值，应答报文中原值返回，以便在处理response时可以找到对应的request。当然在不同协议中，这个参数的名字可能不同（如streamid等）。&lt;/p&gt;
&lt;p&gt;严格说，RequestId对于请求转发是可选的，也有很多通讯协议不提供支持，比如经典的HTTP1.1就没有支持。但是如果有这个参数，则可以实现多路复用，从而可以大幅度提高TCP连接的使用效率，避免出现大量连接。稍微新一点的通讯协议，基本都会原生支持这个特性，比如SOFARPC，Dubbo，HSF，还有HTTP/2就直接內建了多路复用的支持。&lt;/p&gt;
&lt;p&gt;HTTP/1.1不支持多路复用(http1.1有提过支持幂等方法的pipeline机制但是未能普及)，用的是经典的ping-pong模式：在请求发送之后，必须独占当前连接，等待服务器端给出这个请求的应答，然后才能释放连接。因此HTTP/1.1下，并发多个请求就必须采用多连接，为了提升性能通常会使用长连接+连接池的设计。而如果有了requestid和多路复用的支持，客户端和Mesh之间理论上就可以只用一条连接(实践中可能会选择建立多条)来支持并发请求：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-rapid-decode-forward/images/requestid-1_hubb9d4bd1d60f13de3016f93a5d4786c8_104126_e1be16a2ebfe387f872803e8b8909a63.webp 400w,
               /post/201809-xprotocol-rapid-decode-forward/images/requestid-1_hubb9d4bd1d60f13de3016f93a5d4786c8_104126_d6709a6ec13ae3592c19c9b7d3f7ca0d.webp 760w,
               /post/201809-xprotocol-rapid-decode-forward/images/requestid-1_hubb9d4bd1d60f13de3016f93a5d4786c8_104126_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-rapid-decode-forward/images/requestid-1_hubb9d4bd1d60f13de3016f93a5d4786c8_104126_e1be16a2ebfe387f872803e8b8909a63.webp&#34;
               width=&#34;760&#34;
               height=&#34;265&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而Mesh与服务器（也可能是对端的Mesh）之间，也同样可以受益于多路复用技术，来自不同客户端而去往同一个目的地的请求可以混杂在同一条连接上发送。通过RequestId的关联，Mesh可以正确将reponse发送到请求来自的客户端。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-rapid-decode-forward/images/requestid-2_hud53701a3834d99b940665847c8d920e1_93313_443dbb78b06abecf143c5e04751338cd.webp 400w,
               /post/201809-xprotocol-rapid-decode-forward/images/requestid-2_hud53701a3834d99b940665847c8d920e1_93313_203a53e622c4930f6dc169b2db52a432.webp 760w,
               /post/201809-xprotocol-rapid-decode-forward/images/requestid-2_hud53701a3834d99b940665847c8d920e1_93313_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-rapid-decode-forward/images/requestid-2_hud53701a3834d99b940665847c8d920e1_93313_443dbb78b06abecf143c5e04751338cd.webp&#34;
               width=&#34;760&#34;
               height=&#34;289&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;由于篇幅和主题限制，我们不在这里展开多路复用的原理。后面针对每个具体的通讯协议进行分析时再具体看各个协议的支持情况。&lt;/p&gt;
&lt;h3 id=&#34;请求转发参数总结&#34;&gt;请求转发参数总结&lt;/h3&gt;
&lt;p&gt;上面的分析中，我们可以总结到，对于Sidecar，要正确转发请求：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;必须获取到destination信息，得到转发的目的地，才能进行服务发现类的寻址&lt;/li&gt;
&lt;li&gt;必须要能够正确的拆包，然后以请求为单位进行转发，这是负载均衡的基础&lt;/li&gt;
&lt;li&gt;可选的RequestId，这是开启多路复用的基础&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此，这里我们的第一个优化思路就出来了：&lt;strong&gt;尽量只解码获取这三个信息&lt;/strong&gt;，满足转发的基本要求。其他信息如果有性能开销则跳过解码，所谓&amp;quot;快速解码转发&amp;rdquo;。基本原理就是牺牲信息完整性追求性能最大化。&lt;/p&gt;
&lt;p&gt;而结合上一节中我们引入的DNS通用寻址方案，我们是可以从请求的TCP options中得到ClusterIP，从而实现寻址。这个方式可以实现不解码请求报文，尤其是header部分解码destination信息开销大时。这是我们的第二个优化思路：&lt;strong&gt;跳过解码destination信息&lt;/strong&gt;，直接通过ClusterIP进行寻址。&lt;/p&gt;
&lt;p&gt;具体的实现则需要结合特定通讯协议的实际情况进行。&lt;/p&gt;
&lt;h2 id=&#34;主流通讯协议&#34;&gt;主流通讯协议&lt;/h2&gt;
&lt;p&gt;现在我们开始，以Proxy、Sidecar、Service Mesh的角度来看看目前主流的通讯协议和我们前面列举的需要在SOFAMesh中支持的几个协议。&lt;/p&gt;
&lt;h3 id=&#34;sofarpcbolt协议&#34;&gt;SOFARPC/bolt协议&lt;/h3&gt;
&lt;p&gt;SOFARPC 是一款基于 Java 实现的 RPC 服务框架，详细资料可以查阅 &lt;a href=&#34;http://www.sofastack.tech/sofa-rpc/docs/Home&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;官方文档&lt;/a&gt;。SOFARPC 支持 &lt;a href=&#34;https://github.com/alipay/sofa-bolt&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;bolt&lt;/a&gt;，rest，dubbo 协议进行通信。REST、dubbo后面单独展开，这里我们关注bolt协议。&lt;/p&gt;
&lt;p&gt;bolt 是蚂蚁金融服务集团开放的基于 Netty 开发的网络通信框架，其协议格式是变长，即协议头+payload。具体格式定义如下，以request为例（response类似）：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-rapid-decode-forward/images/bolt-protocol-request_hu75c589c7047a5ea4162277c6a3215669_38607_b5c74b5112f2015a82f92a3f48d01d62.webp 400w,
               /post/201809-xprotocol-rapid-decode-forward/images/bolt-protocol-request_hu75c589c7047a5ea4162277c6a3215669_38607_6ca43a4b1fe7d94189add1d0b45f5d59.webp 760w,
               /post/201809-xprotocol-rapid-decode-forward/images/bolt-protocol-request_hu75c589c7047a5ea4162277c6a3215669_38607_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-rapid-decode-forward/images/bolt-protocol-request_hu75c589c7047a5ea4162277c6a3215669_38607_b5c74b5112f2015a82f92a3f48d01d62.webp&#34;
               width=&#34;760&#34;
               height=&#34;160&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们只关注和请求转发直接相关的字段：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;TCP拆包&lt;/p&gt;
&lt;p&gt;botl协议是定长+变长的复合结构，前面22个字节长度固定，每个字节和协议字段的对应如图所示。其中classLen，headerLen和contentLen三个字段指出后面三个变长字段className，header，content的实际长度。和通常的变长方案相比只是变长字段有三个。拆包时思路简单明了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;先读取前22个字节，解出各个协议字段的实际值，包括classLen，headerLen和contentLen&lt;/li&gt;
&lt;li&gt;按照classLen，headerLen和contentLen的大小，继续读取className，header，content&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Destination&lt;/p&gt;
&lt;p&gt;Bolt协议中的header字段是一个map，其中有一个key为&amp;quot;service&amp;quot;的字段，传递的是接口名/服务名。读取稍微麻烦一点点，需要先解码整个header字段，这里对性能有影响。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;RequestId&lt;/p&gt;
&lt;p&gt;Blot协议固定字段中的&lt;code&gt;requestID&lt;/code&gt;字段，可以直接读取。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SOFARPC中的bolt协议，设计的比较符合请求转发的需要，TCP拆包，读取RequestID，都没有性能问题。只是Destination的获取需要解码整个header，性能开销稍大。&lt;/p&gt;
&lt;p&gt;总结：适合配合DNS通用解码方案，跳过对整个header部分的解码，从而提升性能。当然由于这个header本身也不算大，优化的空间有限，具体提升需要等对比测试的结果出来。&lt;/p&gt;
&lt;h3 id=&#34;hsf协议&#34;&gt;HSF协议&lt;/h3&gt;
&lt;p&gt;HSF协议是经过精心设计工作在4层的私有协议，由于该协议没有开源，因此不便直接暴露具体格式和字段详细定义。&lt;/p&gt;
&lt;p&gt;不过基本的设计和bolt非常类似：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;采用变长格式，即协议头+payload&lt;/li&gt;
&lt;li&gt;在协议头中可以直接拿到服务接口名和服务方法名作为Destination&lt;/li&gt;
&lt;li&gt;有RequestID字段&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;基本和bolt一致，考虑到Destination可以直接读取，比bolt还要方便一些，HSF协议可以说是对请求转发最完美的协议。&lt;/p&gt;
&lt;p&gt;总结：目前的实现方案也只解码了这三个关键字段，速度足够快，不需要继续优化。&lt;/p&gt;
&lt;h3 id=&#34;dubbo协议&#34;&gt;Dubbo协议&lt;/h3&gt;
&lt;p&gt;Dubbo协议也是类似的协议头+payload的变长结构，其协议格式如下：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-rapid-decode-forward/images/dubbo-protocol_hu0d1cc537c116970b49402ff023a6bd80_15515_bb20fea89779262fbf64847a2bacdfd5.webp 400w,
               /post/201809-xprotocol-rapid-decode-forward/images/dubbo-protocol_hu0d1cc537c116970b49402ff023a6bd80_15515_b014a68b46678f464631ea6b670471c1.webp 760w,
               /post/201809-xprotocol-rapid-decode-forward/images/dubbo-protocol_hu0d1cc537c116970b49402ff023a6bd80_15515_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-rapid-decode-forward/images/dubbo-protocol_hu0d1cc537c116970b49402ff023a6bd80_15515_bb20fea89779262fbf64847a2bacdfd5.webp&#34;
               width=&#34;760&#34;
               height=&#34;107&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;其中long类型的&lt;code&gt;id&lt;/code&gt;字段用来把请求request和返回的response对应上，即我们所说的&lt;code&gt;RequestId&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这样TCP拆包和多路复用都轻松实现，稍微麻烦一点的是：Destination在哪里？Dubbo在这里的设计有点不够理想，在协议头中没有字段可以直接读取到Destination，需要去读取data字段，也就是payload，里面的path字段通常用来保存服务名或者接口名。method字段用来表示方法名。&lt;/p&gt;
&lt;p&gt;从设计上看，path字段和method字段被存放在payload中有些美中不足。庆幸的是，读取这两个字段的时候不需要完整的解开整个payload，好险，不然，那性能会没法接受的。&lt;/p&gt;
&lt;p&gt;以hession2为例，data字段的组合是：dubbo version + path + interface version + method + ParameterTypes + Arguments + Attachments。每个字段都是一个byte的长度+字段值的UTF bytes。因此读取时并不复杂，速度也足够快。&lt;/p&gt;
&lt;p&gt;基本和HSF一致，就是Destination的读取稍微麻烦一点，放在payload中的设计让人吓了一跳，好在有惊无险。整体说还是很适合转发的。&lt;/p&gt;
&lt;p&gt;总结：同HSF，不需要继续优化。&lt;/p&gt;
&lt;h3 id=&#34;http11&#34;&gt;HTTP/1.1&lt;/h3&gt;
&lt;p&gt;HTTP/1.1的格式应该大家都熟悉，而在这里，不得不指出，HTTP/1.1协议对请求转发是非常不友好的（甚至可以说是恶劣！）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;HTTP请求在拆包时，需要先按照HTTP header的格式，一行一行读取，直到出现空行表示header结束&lt;/li&gt;
&lt;li&gt;然后必须将整个header的内容全部解析出来，才能取出&lt;code&gt;Content-Length header&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;通过&lt;code&gt;Content-Length&lt;/code&gt; 值，才能完成对body内容的读取，实现正确拆包&lt;/li&gt;
&lt;li&gt;如果是chunked方式，则更复杂一些&lt;/li&gt;
&lt;li&gt;Destination通常从&lt;code&gt;Host&lt;/code&gt; header中获取&lt;/li&gt;
&lt;li&gt;没有RequestId，完全无法实现多路复用&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这意味着，为了完成最基本的TCP拆包，必须完整的解析全部的HTTP header信息，没有任何可以优化的空间。对比上面几个RPC协议，轻松自如的快速获取几个关键信息，HTTP无疑要重很多。这也造成了在ServiceMesh下，HTTP/1.1和REST协议的性能总是和其他RPC方案存在巨大差异。&lt;/p&gt;
&lt;p&gt;对于注定要解码整个header部分，完全没有优化空间可言的HTTP/1.1协议来说，Content Based Routing 的解码开销是必须付出的，无论是否使用 Content Based Routing 。因此，快速解码的构想，对HTTP/1.1无效。&lt;/p&gt;
&lt;p&gt;总结：受HTTP/1.1协议格式限制，上述两个优化思路都无法操作。&lt;/p&gt;
&lt;h3 id=&#34;http2和grpc&#34;&gt;HTTP/2和gRPC&lt;/h3&gt;
&lt;p&gt;作为HTTP/1.1的接班人，HTTP/2则表现的要好很多。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：当然HTTP/2的协议格式复杂多了，由于篇幅和主题的限制，这里不详细介绍HTTP/2的格式。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;首先HTTP/2是以帧的方式组织报文的，所有的帧都是变长，固定的9个字节+可变的payload，Length字段指定payload的大小：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-rapid-decode-forward/images/http2-frame_hudb7f3de91e06269f29bba5c18d3c5767_80550_bc552cac7b2ccfbc0fad68f3f8f9a45c.webp 400w,
               /post/201809-xprotocol-rapid-decode-forward/images/http2-frame_hudb7f3de91e06269f29bba5c18d3c5767_80550_756f3199ffb80f52dbbc7321a3642a15.webp 760w,
               /post/201809-xprotocol-rapid-decode-forward/images/http2-frame_hudb7f3de91e06269f29bba5c18d3c5767_80550_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-rapid-decode-forward/images/http2-frame_hudb7f3de91e06269f29bba5c18d3c5767_80550_bc552cac7b2ccfbc0fad68f3f8f9a45c.webp&#34;
               width=&#34;700&#34;
               height=&#34;221&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;HTTP2的请求和应答，也被称为Message，是由多个帧构成，在去除控制帧之外，Message通常由Header帧开始，后面接CONTINUATION帧和Data帧（也可能没有，如GET请求）。每个帧都可以通过头部的Flags字段来设置END_STREAM标志，表示请求或者应答的结束。即TCP拆包的问题在HTTP/2下是有非常标准而统一的方式完成，完全和HTTP/2上承载的协议无关。&lt;/p&gt;
&lt;p&gt;HTTP/2通过Stream內建多路复用，这里的&lt;code&gt;Stream Identifier&lt;/code&gt; 扮演了类似前面的&lt;code&gt;RequestId&lt;/code&gt;的角色。&lt;/p&gt;
&lt;p&gt;而Destination信息则通过Header帧中的伪header &lt;code&gt;:authority&lt;/code&gt; 来传递，类似HTTP/1.1中的&lt;code&gt;Host&lt;/code&gt; header。不过HTTP/2下header会进行压缩，读取时稍微复杂一点，也存在需要解压缩整个header帧的性能开销。考虑到拆包和获取RequestId都不需要解包（只需读取协议头，即HTTP/2帧的固定字段），速度足够快，因此存在很大的优化空间：不解码header帧，直接通过DNS通用寻址方案，这样性能开销大为减少，有望获得极高的转发速度。&lt;/p&gt;
&lt;p&gt;总结：HTTP/2的帧设计，在请求转发时表现的非常友好。唯独Destination信息放在header中，会造成必须解码header帧。好在DNS通用寻址方案可以弥补，实现快速解码和转发。&lt;/p&gt;
&lt;h2 id=&#34;servicemesh时代的rpc理想方案&#34;&gt;Servicemesh时代的RPC理想方案&lt;/h2&gt;
&lt;p&gt;在文章的最后，我们总结并探讨一下，对于Servicemesh而言，什么样的RPC方案是最理想的？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;必须可以方便做TCP拆包，最好在协议头中就简单搞定，标准方式如固定协议头+length字段+可变payload。HSF协议, bolt协议和dubbo协议表现完美，HTTP/2采用帧的方式，配合END_STREAM标志，方式独特但有效。HTTP/1.1则是反面典型。&lt;/li&gt;
&lt;li&gt;必须可以方便的获取destination字段，同样最好在协议头中就简单搞定。HSF协议表现完美，dubbo协议藏payload中但终究还是可以快速解码有惊无险的过关，bolt协议和HTTP/2协议就很遗憾必须解码header才能拿到，好在DNS通用寻址方案可以弥补，但终究丢失了服务名和方法名信息。HTTP/1.1依然是反面典型。&lt;/li&gt;
&lt;li&gt;最好有RequestId字段，同样最好在协议头中就简单搞定。这方面HSF协议，dubbo协议，bolt协议表现完美，HTTP/2协议更是直接內建支持。HTTP/1.1继续反面典型。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此，仅以方便用最佳性能进行转发，对ServiceMesh、sidecar友好而言，最理想的RPC方案是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;传统的变长协议&lt;/p&gt;
&lt;p&gt;固定协议头+length字段+可变payload，然后在固定协议头中直接提供RequestId和destination。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;基于帧的协议&lt;/p&gt;
&lt;p&gt;以HTTP/2为基础，除了请求结束的标志位和RequestId外，还需要通过帧的固定字段来提供destination信息。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;或许，在未来，在Servicemesh普及之后，对Servicemesh友好成为RPC协议的特别优化方向，我们会看到表现完美更适合Servicemesh时代的新型RPC方案。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>SOFAMesh中的多协议通用解决方案x-protocol介绍系列(1)-DNS通用寻址方案</title>
      <link>https://skyao.net/post/201809-xprotocol-common-address-solution/</link>
      <pubDate>Thu, 13 Sep 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201809-xprotocol-common-address-solution/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;在2018年上半年，蚂蚁金服决定基于 Istio 订制自己的 ServiceMesh 解决方案，在6月底对外公布了 SOFAMesh，详情请见之前的文章: &lt;a href=&#34;../../publication/service-mesh-explore/&#34;&gt;大规模微服务架构下的Service Mesh探索之路&lt;/a&gt; 。&lt;/p&gt;
&lt;p&gt;在 SOFAMesh 的开发过程中，针对遇到的实际问题，我们给出了一套名为 x-protocol 的解决方案，定位是云原生、高性能、低侵入性的通用 Service Mesh 落地方案，依托 Kubernetes 基座，利用其原生的服务注册和服务发现机制，支持各种私有 RPC 协议低成本、易扩展的接入，快速享受 Service Mesh 所带来的红利。&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;兼容现有SOA体系，提供通过接口进行访问的方式，实现不修改业务代码也能顺利接入 Service Mesh&lt;/li&gt;
&lt;li&gt;支持单进程多服务的传统SOA程序，可以在微服务改造之前，先受益于 Service Mesh 带来的强大功能&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在本系列文章中，我们将对此进行详细的讲解，首先是“DNS通用寻址方案”。&lt;/p&gt;
&lt;h2 id=&#34;背景和需求&#34;&gt;背景和需求&lt;/h2&gt;
&lt;h3 id=&#34;soa的服务模型&#34;&gt;SOA的服务模型&lt;/h3&gt;
&lt;p&gt;在SOFAMesh计划支持的RPC框架中，SOFARPC、HSF、Dubbo都是一脉相承的SOA体系，也都支持经典的SOA服务模型，通常称为&amp;quot;单进程多服务&amp;quot;，或者叫做&amp;quot;单进程多接口&amp;quot;。（备注：由于服务一词使用过于频繁，下文都统一称为接口以便区分）&lt;/p&gt;
&lt;p&gt;SOA标准的服务注册，服务发现和调用流程如下：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-common-address-solution/images/soa-standard-process_hu63f0355497bb1f76ad37b271ee3d46b2_126871_e1b256536aa52f20548f1ffdf936943c.webp 400w,
               /post/201809-xprotocol-common-address-solution/images/soa-standard-process_hu63f0355497bb1f76ad37b271ee3d46b2_126871_555aec4fe01ccf448bc72062c80d2354.webp 760w,
               /post/201809-xprotocol-common-address-solution/images/soa-standard-process_hu63f0355497bb1f76ad37b271ee3d46b2_126871_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-common-address-solution/images/soa-standard-process_hu63f0355497bb1f76ad37b271ee3d46b2_126871_e1b256536aa52f20548f1ffdf936943c.webp&#34;
               width=&#34;760&#34;
               height=&#34;354&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在单个SOA应用进程内，存在多个接口&lt;/li&gt;
&lt;li&gt;服务注册时，以接口为单位进行多次独立的服务注册&lt;/li&gt;
&lt;li&gt;当客户端进行调用时，按照接口进行服务发现，然后发起调用&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;当我们试图将这些SOA架构的应用搬迁到ServiceMesh时，就会遇到服务模型的问题：微服务是单服务模型，也就是一个进程里面只承载一个服务。以k8s的服务注册为例，在单进程单服务的模型下，服务名和应用名可以视为一体，k8s的自动服务注册会将应用名作为服务注册的标示。&lt;/p&gt;
&lt;p&gt;这就直接导致了SOA模型和微服务模型的不匹配问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SOA以接口为单位做服务注册和服务发现，而微服务下是服务名&lt;/li&gt;
&lt;li&gt;SOA是&amp;quot;单进程多接口&amp;quot;，而微服务是&amp;quot;单进程单服务&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;一步接一步的需求&#34;&gt;一步接一步的需求&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;先上车后补票&lt;/p&gt;
&lt;p&gt;最理想的做法当然是先进行微服务改造，实现微服务拆分。但是考虑到现有应用数量众多，我们可能更愿意在大规模微服务改造之前，先想办法让这些应用可以运行在ServiceMesh下，提前受益于Service Mesh带来的强大功能。因此，我们需要找到一个合适的方案，让ServiceMesh支持没有做微服务改造依然是&amp;quot;单进程多接口&amp;quot;形式的传统SOA应用，所谓&amp;quot;先上车后补票&amp;quot;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;不修改代码&lt;/p&gt;
&lt;p&gt;考虑到原有的SOA应用，相互之间错综复杂的调用关系，最好不要修改代码，即保持客户端依然通过接口名来访问的方式。当然，SOA架构的客户端SDK可能要进行改动，将原有的通过接口名进行服务发现再自行负载均衡进行远程调用的方式，精简为标准的Servicemesh调用（即走Sidecar），因此修改SDK依赖包和重新打包应用是不可避免。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;支持带特殊字符的接口名&lt;/p&gt;
&lt;p&gt;k8s的服务注册，Service名是不能携带&amp;quot;.&amp;ldquo;号的。而SOA架构下，接口名有时出于管理方便，有可能是加了域名前缀，如&amp;quot;com.alipay.demo.interface-2&amp;rdquo;。为了实现不修改原有代码，就只能想办法支持这种带特殊字符的接口名。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;参考kubernetes和istio&#34;&gt;参考Kubernetes和Istio&lt;/h2&gt;
&lt;p&gt;在进一步讨论解决方案之前，我们先来看一下kubernetes和istio中的标准请求寻址方式。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：过程稍显复杂，涉及到k8s/istio的一些底层细节。但是了解这个过程对后续的理解非常重要，也可以帮助大家了解k8s和k8s的工作原理，强烈推荐阅读。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;k8s下的dns寻址方式&#34;&gt;k8s下的DNS寻址方式&lt;/h3&gt;
&lt;p&gt;在k8s下，如图所示，假定我们部署了一个名为userservice的应用，有三个实例，分别在三个pod中。则应用部署之后，k8s会为这个应用分配ClusterIP和域名，并在DNS中生成一条DNS记录，将域名映射到ClusterIP：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-common-address-solution/images/k8s-process_hu801a5835c7910c15e8bf2111581616cb_213097_fc176da897283ec78d97a3554bc2e8d2.webp 400w,
               /post/201809-xprotocol-common-address-solution/images/k8s-process_hu801a5835c7910c15e8bf2111581616cb_213097_8156501fb56cfcf042a3fdf4125d13e6.webp 760w,
               /post/201809-xprotocol-common-address-solution/images/k8s-process_hu801a5835c7910c15e8bf2111581616cb_213097_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-common-address-solution/images/k8s-process_hu801a5835c7910c15e8bf2111581616cb_213097_fc176da897283ec78d97a3554bc2e8d2.webp&#34;
               width=&#34;760&#34;
               height=&#34;289&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;当部署在k8s下的某个充当客户端的应用发起请求时，如图中的HTTP GET请求，目标URL地址为 &amp;ldquo;http://userservice/id/1000221&amp;rdquo;。请求的寻址方式和过程如下：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;首先进行域名解析，分别尝试解析&amp;quot;userservice&amp;quot;/&amp;ldquo;userservie.default.svc.cluster.local&amp;quot;等域名，得到ClusterIP&lt;/li&gt;
&lt;li&gt;然后客户端发出请求的报文，目标地址为ClusterIP，源地址为当前客户端所在的pod IP（简单起见，端口先忽略）&lt;/li&gt;
&lt;li&gt;请求报文随即被kube-proxy拦截，kube-proxy根据ClusterIP，拿到ClusterIP对应的多个实际服务实例所在的pod ip，取其中一个，修改目标地址为这个pod IP&lt;/li&gt;
&lt;li&gt;请求报文最终就被发送到服务实例所在的pod IP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;应答回来的方式类似，userservice发出的应答报文会被kube-proxy拦截并修改为发送到客户端所在的pod IP。&lt;/p&gt;
&lt;p&gt;我们详细看一下请求和应答全称的四个请求包的具体内容（简单起见继续忽略端口）：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-common-address-solution/images/k8s-process-2_hu21ee4609601f87c8853278ef436177b3_194819_4b9df385fcbbc51ea4edc3aaaeedbb7d.webp 400w,
               /post/201809-xprotocol-common-address-solution/images/k8s-process-2_hu21ee4609601f87c8853278ef436177b3_194819_57d72567c4db2b9d652ea627cf13e5de.webp 760w,
               /post/201809-xprotocol-common-address-solution/images/k8s-process-2_hu21ee4609601f87c8853278ef436177b3_194819_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-common-address-solution/images/k8s-process-2_hu21ee4609601f87c8853278ef436177b3_194819_4b9df385fcbbc51ea4edc3aaaeedbb7d.webp&#34;
               width=&#34;760&#34;
               height=&#34;269&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;重点关注请求和应答报文的源地址和目标地址：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;客户端发出的请求，为&amp;quot;客户端到ClusterIP&amp;rdquo;&lt;/li&gt;
&lt;li&gt;kube-proxy拦截到请求后，将请求修改为&amp;quot;客户端到服务器端&amp;quot;&lt;/li&gt;
&lt;li&gt;服务器端收到请求时，表现为&amp;quot;客户端到服务器端&amp;quot;，ClusterIP被kube-proxy屏蔽&lt;/li&gt;
&lt;li&gt;服务器端发送应答，因为收到的请求看似来自客户端，因此应答报文为&amp;quot;服务器端到客户端&amp;quot;&lt;/li&gt;
&lt;li&gt;应答报文被kube-proxy拦截，将应答修改为&amp;quot;ClusterIP到服务器端&amp;quot;&lt;/li&gt;
&lt;li&gt;客户端收到应答，表现为&amp;quot;ClusterIP到服务器端&amp;quot;，服务器端IP被kube-proxy屏蔽&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;kube-proxy在客户端和服务器端之间拦截并修改请求和应答的报文，联通两者，但各自屏蔽了一些信息：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在客户端看来它是在和ClusterIP交互，userservice的具体服务器端实例对客户端是无感知的&lt;/li&gt;
&lt;li&gt;在服务器端看来，客户端是直接在和它交互，ClusterIP的存在对服务器端是无感知的&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;更深入一步，看kube-proxy在两个拦截和修改报文中的逻辑处理关系，即kube-proxy是如何在收到应答时正确的找回原有的ClusterIP：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-common-address-solution/images/k8s-process-3_hu51059952c54808701ecc8ab544974ba1_138308_9fb7ec41f284cbfaf3044452470ca6d6.webp 400w,
               /post/201809-xprotocol-common-address-solution/images/k8s-process-3_hu51059952c54808701ecc8ab544974ba1_138308_a490c6ba8fe5c7242e1942538af1ead4.webp 760w,
               /post/201809-xprotocol-common-address-solution/images/k8s-process-3_hu51059952c54808701ecc8ab544974ba1_138308_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-common-address-solution/images/k8s-process-3_hu51059952c54808701ecc8ab544974ba1_138308_9fb7ec41f284cbfaf3044452470ca6d6.webp&#34;
               width=&#34;760&#34;
               height=&#34;205&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在拦截并修改请求报文之后，kube-proxy会保存报文修改的5元组对应关系（5元组指源IP地址，源端口，协议，目的地IP地址，目的地端口）&lt;/li&gt;
&lt;li&gt;在收到应答报文后，根据应答报文中的5元组，在保存的5元组对应关系中，找到对应信息，得到原有的ClusterIP和端口，然后修改应答报文&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;总结，通过上述k8s下的寻址方式，客户端只需发送带简单寻址信息的请求（如 &amp;ldquo;http://userservice/id/1000221&amp;rdquo; 中的&amp;quot;userservice&amp;quot; ），就可以寻址到正确的服务器端。这期间有两个关注点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;通过DNS，建立了域名和ClusterIP的关系。&lt;/p&gt;
&lt;p&gt;对于客户端，这是它能看到的内容，非常的简单，域名、DNS是非常容易使用的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;而通过kube-proxy的拦截和转发，又打通了ClusterIP和服务器端实际的Pod IP&lt;/p&gt;
&lt;p&gt;对于客户端，这些是看不到的内容，不管有多复杂，都是k8s在底层完成，对客户端，或者说使用者透明。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;以客户端的视角看来，这个DNS寻址方式非常的简单直白：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-common-address-solution/images/k8s-process-4_huedd76544b60a24ecf42eba8f3c2d1e1c_19435_2a7271718e22d84e951e7e2326176956.webp 400w,
               /post/201809-xprotocol-common-address-solution/images/k8s-process-4_huedd76544b60a24ecf42eba8f3c2d1e1c_19435_dae43ee6c3f3501b1f3b502b2bd2833d.webp 760w,
               /post/201809-xprotocol-common-address-solution/images/k8s-process-4_huedd76544b60a24ecf42eba8f3c2d1e1c_19435_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-common-address-solution/images/k8s-process-4_huedd76544b60a24ecf42eba8f3c2d1e1c_19435_2a7271718e22d84e951e7e2326176956.webp&#34;
               width=&#34;760&#34;
               height=&#34;103&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;istio的dns寻址方式&#34;&gt;Istio的DNS寻址方式&lt;/h2&gt;
&lt;p&gt;Istio的请求寻址方式和普通kubernetes非常相似，原理相同，只是kube-proxy被sidecar取代，然后sidecar的部署方式是在pod内部署，而且客户端和服务器端各有一个sidecar。其他基本一致，除了图中红色文本的部分：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-common-address-solution/images/istio-process_huc9f5ff9df76bf0d1db383e3bf65c06a2_262512_263bd91b8204c90457f9320b2acef449.webp 400w,
               /post/201809-xprotocol-common-address-solution/images/istio-process_huc9f5ff9df76bf0d1db383e3bf65c06a2_262512_8b7108adc4de11484dd712ee7b5511a3.webp 760w,
               /post/201809-xprotocol-common-address-solution/images/istio-process_huc9f5ff9df76bf0d1db383e3bf65c06a2_262512_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-common-address-solution/images/istio-process_huc9f5ff9df76bf0d1db383e3bf65c06a2_262512_263bd91b8204c90457f9320b2acef449.webp&#34;
               width=&#34;760&#34;
               height=&#34;297&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;iptables在劫持流量时，除了将请求转发到localhost的Sidecar处外，还额外的在请求报文的TCP options 中将 ClusterIP 保存为 original dest。&lt;/li&gt;
&lt;li&gt;在 Sidecar （Istio默认是Envoy）中，从请求报文 TCP  options 的 original dest 处获取 ClusterIP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;通过TCP  options 的 original dest，iptables就实现了在劫持流量到Sidecar的过程中，额外传递了 ClusterIP 这个重要参数。Istio为什么要如此费力的传递这个 ClusterIP 呢？&lt;/p&gt;
&lt;p&gt;看下图就知道了，这是一个 Virtual Host 的示例， Istio 通过 Pilot 将这个规则发送给 Sidecar/Envoy ，依靠这个信息来匹配路由请求找到处理请求的cluster：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-common-address-solution/images/virtualhost-clusterip_hu0074fdf531058dac65d1e2d8b9e903be_145045_be8e75fc8a1f23a5d49860e497d2485b.webp 400w,
               /post/201809-xprotocol-common-address-solution/images/virtualhost-clusterip_hu0074fdf531058dac65d1e2d8b9e903be_145045_76491d8116452dd9e158c84e9a57bd5f.webp 760w,
               /post/201809-xprotocol-common-address-solution/images/virtualhost-clusterip_hu0074fdf531058dac65d1e2d8b9e903be_145045_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-common-address-solution/images/virtualhost-clusterip_hu0074fdf531058dac65d1e2d8b9e903be_145045_be8e75fc8a1f23a5d49860e497d2485b.webp&#34;
               width=&#34;760&#34;
               height=&#34;593&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;domains中，除了列出域名外，还有一个特殊的IP地址，这个就是k8s服务的 ClusterIP！因此，Sidecar可以通过前面传递过来的 ClusterIP 在这里进行路由匹配（当然也可以从报文中获取destination然后通过域名匹配）。&lt;/p&gt;
&lt;p&gt;总结，Istio延续了k8s的寻址方式，客户端同样只需发送带简单寻址信息的请求，就可以寻址到正确的服务器端。这期间同样有两个关注点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;通过DNS，建立了域名和ClusterIP的关系。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;通过 ClusterIP 和 Pilot 下发给  Virtual Host 的配置，Sidecar  可以完成路由匹配，将ClusterIP和目标服务器关联起来&lt;/p&gt;
&lt;p&gt;同样，对于客户端，这些是看不到的内容。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;因此，以客户端的视角看来，Isito的这个DNS寻址方式同样的简单直白！&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-common-address-solution/images/k8s-process-4_huedd76544b60a24ecf42eba8f3c2d1e1c_19435_2a7271718e22d84e951e7e2326176956.webp 400w,
               /post/201809-xprotocol-common-address-solution/images/k8s-process-4_huedd76544b60a24ecf42eba8f3c2d1e1c_19435_dae43ee6c3f3501b1f3b502b2bd2833d.webp 760w,
               /post/201809-xprotocol-common-address-solution/images/k8s-process-4_huedd76544b60a24ecf42eba8f3c2d1e1c_19435_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-common-address-solution/images/k8s-process-4_huedd76544b60a24ecf42eba8f3c2d1e1c_19435_2a7271718e22d84e951e7e2326176956.webp&#34;
               width=&#34;760&#34;
               height=&#34;103&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;dns通用寻址方案&#34;&gt;DNS通用寻址方案&lt;/h2&gt;
&lt;h3 id=&#34;解决问题的思路&#34;&gt;解决问题的思路&lt;/h3&gt;
&lt;p&gt;在详细讲述了k8s和istio的DNS寻址方案之后，我们继续回到我们的主题，我们要解决的问题：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如何在不修改代码，继续使用接口的情况下，实现在Service Mesh上运行现有的Dubbo/HSF/SOFA等传统SOA应用？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-common-address-solution/images/soa-standard-process_hu63f0355497bb1f76ad37b271ee3d46b2_126871_e1b256536aa52f20548f1ffdf936943c.webp 400w,
               /post/201809-xprotocol-common-address-solution/images/soa-standard-process_hu63f0355497bb1f76ad37b271ee3d46b2_126871_555aec4fe01ccf448bc72062c80d2354.webp 760w,
               /post/201809-xprotocol-common-address-solution/images/soa-standard-process_hu63f0355497bb1f76ad37b271ee3d46b2_126871_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-common-address-solution/images/soa-standard-process_hu63f0355497bb1f76ad37b271ee3d46b2_126871_e1b256536aa52f20548f1ffdf936943c.webp&#34;
               width=&#34;760&#34;
               height=&#34;354&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里有一个关键点：k8s的服务注册是以基于Service或者说基于应用(app name)，而我们的客户端代码是基于接口的。因此，在 Virtual Host 进行路由匹配时，是不能通过域名匹配的。当然，这里理论上还有一个思路，就是将接口注册为k8s Service。但是，还记得要支持接口特殊字符的需求吗？带点号的接口名，k8s是不能接受它作为Service Name的，直接堵死了将接口名注册到k8s Service的道路。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-common-address-solution/images/virtualhost-clusterip_hu0074fdf531058dac65d1e2d8b9e903be_145045_be8e75fc8a1f23a5d49860e497d2485b.webp 400w,
               /post/201809-xprotocol-common-address-solution/images/virtualhost-clusterip_hu0074fdf531058dac65d1e2d8b9e903be_145045_76491d8116452dd9e158c84e9a57bd5f.webp 760w,
               /post/201809-xprotocol-common-address-solution/images/virtualhost-clusterip_hu0074fdf531058dac65d1e2d8b9e903be_145045_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-common-address-solution/images/virtualhost-clusterip_hu0074fdf531058dac65d1e2d8b9e903be_145045_be8e75fc8a1f23a5d49860e497d2485b.webp&#34;
               width=&#34;760&#34;
               height=&#34;593&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这样，我们就只有一条路可以走了：效仿istio的做法，通过 ClusterIP 匹配！&lt;/p&gt;
&lt;p&gt;而要将接口名（如&amp;quot;com.alipay.demo.interface-1&amp;quot;）和 ClusterIP 关联，最简单直接的方式就是&lt;strong&gt;打通DNS&lt;/strong&gt; ：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-common-address-solution/images/xprotocol-dns_hu259b5e2bf8c4fdad0b460a164d3d25b7_221762_35559139fe25744c05e0f341066b2c2f.webp 400w,
               /post/201809-xprotocol-common-address-solution/images/xprotocol-dns_hu259b5e2bf8c4fdad0b460a164d3d25b7_221762_2ca1f900838a2c77abf9ec9bd0038fb7.webp 760w,
               /post/201809-xprotocol-common-address-solution/images/xprotocol-dns_hu259b5e2bf8c4fdad0b460a164d3d25b7_221762_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-common-address-solution/images/xprotocol-dns_hu259b5e2bf8c4fdad0b460a164d3d25b7_221762_35559139fe25744c05e0f341066b2c2f.webp&#34;
               width=&#34;760&#34;
               height=&#34;227&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;只需要在DNS记录中，增加接口到 ClusterIP 的映射，然后就可以完全延续Istio的标准做法！其他的步骤，如域名解析到ClusterIP，iptables拦截并传递ClusterIP，sidecar读取ClusterIP并匹配路由，都完全可以重用原有方案。&lt;/p&gt;
&lt;h3 id=&#34;具体实现方案&#34;&gt;具体实现方案&lt;/h3&gt;
&lt;p&gt;实现时，我们选择了使用 CoreDNS 作为k8s的DNS解决方案，然后通过 Service Controller 操作 CoreDNS 的记录来实现DNS解析。&lt;/p&gt;
&lt;p&gt;为了收集到SOA应用的接口信息，我们还提供了一个 Register Agent 给 Service Controller 收集信息。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201809-xprotocol-common-address-solution/images/xprotocol-impl_huc08202174ace84beaa7f5ecae520da47_52034_43f207b3fafece8266fc0848c5de4206.webp 400w,
               /post/201809-xprotocol-common-address-solution/images/xprotocol-impl_huc08202174ace84beaa7f5ecae520da47_52034_7c47199f981b1f6ec52b94cecfd5b972.webp 760w,
               /post/201809-xprotocol-common-address-solution/images/xprotocol-impl_huc08202174ace84beaa7f5ecae520da47_52034_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201809-xprotocol-common-address-solution/images/xprotocol-impl_huc08202174ace84beaa7f5ecae520da47_52034_43f207b3fafece8266fc0848c5de4206.webp&#34;
               width=&#34;760&#34;
               height=&#34;476&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;详细的实现方案，不在本文中重复讲述，请参阅我们之前的分享文章 &lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzUzMzU5Mjc1Nw==&amp;amp;mid=2247484175&amp;amp;idx=1&amp;amp;sn=5cb26b1afe615ac7e06b2ccbee6235b3&amp;amp;chksm=faa0ecd5cdd765c3f285bcb3b23f4f1f3e27f6e99021ad4659480ccc47f9bf25a05107f4fee2&amp;amp;mpshare=1&amp;amp;scene=1&amp;amp;srcid=0828t5isWXmyeWhTeoAoeogw&amp;amp;pass_ticket=DqnjSkiuBZW9Oe68Fjiq%2Bqa6fFCyysQTR7Qgd8%2BX9FfooybAg7NXVAQdLmfG6gRX#rd&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;SOFAMesh 的通用协议扩展&lt;/a&gt; 中的DNS寻址方案一节。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：暂时修改 CoreDNS 记录的方式是直接修改 CoreDNS 的底层数据，不够优雅。未来将修改为通过 CoreDNS 的 Dynamic updates API 接口进行，不过 CoreDNS 的这个API还在开发中，需要等待完成。详情见&lt;a href=&#34;https://github.com/coredns/coredns/pull/1822&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;这里&lt;/a&gt; 。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;单进程多接口问题的解决&#34;&gt;单进程多接口问题的解决&lt;/h3&gt;
&lt;p&gt;上面的解决方案，在解决通过接口实现访问的同时，也将&amp;quot;单进程多接口&amp;quot;的问题一起解决了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;原SOA应用上k8s时，可以注册为标准的k8s Service，获取ClusterIP。此时使用应用名注册，和接口无关。&lt;/li&gt;
&lt;li&gt;通过操作 CoreDNS，我们将该SOA应用的各个接口都添加为 DNS 记录，指向该应用的ClusterIP&lt;/li&gt;
&lt;li&gt;当客户端代码使用不同的接口名访问时，DNS解析出来的都是同一个ClusterIP，后续步骤就和接口名无关了&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;欠缺微服务改造带来的限制&#34;&gt;欠缺微服务改造带来的限制&lt;/h3&gt;
&lt;p&gt;需要特别指出的是，DNS通用寻址方案虽然可以解决使用接口名访问和支持单进程多接口的问题，但是这种方案只是完成了“寻址”，也就是打通端到端的访问通道。由于应用没有进行微服务改造，部署上是依然一个应用（体现为一个进程，在k8s上体现为一个Service）中包含多个接口，本质上：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务注册依然是以应用名为基础，对应的k8s service和service上的label也是应用级别&lt;/li&gt;
&lt;li&gt;因此提供的服务治理功能，也是以k8s的Service为基本单位，包括灰度，蓝绿，版本拆分等所有的Vesion Based Routing功能&lt;/li&gt;
&lt;li&gt;这意味着，只能进行&lt;strong&gt;应用级别&lt;/strong&gt;的服务治理，而不能继续细分到&lt;strong&gt;接口级别&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个限制来源于应用没有进行微服务改造，没有按照接口将应用拆分为多个独立的微服务，因此无法得到更小的服务治理粒度。这也就是我们前面说的“先上车后补票”的含义：在微服务改造前，先获得Service Mesh的服务治理的绝大部分功能，再慢慢进行微服务改造。&lt;/p&gt;
&lt;h2 id=&#34;dns通用寻址方案-1&#34;&gt;DNS通用寻址方案&lt;/h2&gt;
&lt;p&gt;我们将这个方案称为&amp;quot;DNS通用寻址方案&amp;quot;，是因为这个方案真的非常的通用，体现在以下几个方面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;对使用者来说，通过域名和DNS解析的方式来访问，是非常简单直白而易于接受的，同时也是广泛使用的，适用于各种语言、平台、框架。&lt;/li&gt;
&lt;li&gt;这个方案延续了k8s和istio的做法，保持了一致的方式方式，对用户提供了相同的体验&lt;/li&gt;
&lt;li&gt;这个寻址方案，不仅仅可以用于Dubbo、SOFA、HSF等RPC框架往Service Mesh的迁移，也可以适用于基于HTTP/REST协议的SOA应用，甚至最传统的web应用（例如tomcat下部署多个war包）迁移到Service Mesh&lt;/li&gt;
&lt;li&gt;我们也在考虑在未来的Serverless项目中，将Function的寻址也统一到这套方案中，而无需要求每个Function都进行一次服务注册&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;概括的说，有了这套DNS通用寻址方案，不管需要寻址的实体是什么形态，只要它部署在Service Mesh上，满足以下条件：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;有正常注册为k8s Service，分配有ClusterIP&lt;/li&gt;
&lt;li&gt;为实体（或者更细分的子实体）分配域名或子域名，然后添加到DNS，解析到ClusterIP&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;那么我们的DNS通用寻址方案，就可以工作，从而将请求正确的转发到目的地。而在此基础上，Service Mesh 所有的强大功能都可以为这些实体所用，实现我们前面的目标：在不修改代码不做微服务改造的情况下，也能提前受益于Service Mesh带来的强大服务治理功能。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Mixer Cache: Istio的阿克琉斯之踵?微信讨论实录</title>
      <link>https://skyao.net/post/201807-istio-achilles-heel-wechat/</link>
      <pubDate>Thu, 19 Jul 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201807-istio-achilles-heel-wechat/</guid>
      <description>&lt;h2 id=&#34;前情回顾&#34;&gt;前情回顾&lt;/h2&gt;
&lt;p&gt;在Service Mesh技术社区的微信群中，针对Istio Mixer Cache设计中缓存存放和逻辑分离的潜在分险，进行了深入探讨。以下为截屏实录，确保原汁原味。&lt;/p&gt;
&lt;h2 id=&#34;讨论实录&#34;&gt;讨论实录&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/1_hu25a85ddb9f93cab0fa55e93b5333dc37_82492_890d19d3faf15d44ad969ed1b03deb2a.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/1_hu25a85ddb9f93cab0fa55e93b5333dc37_82492_88d7566d7a103be766f097143e4a4e51.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/1_hu25a85ddb9f93cab0fa55e93b5333dc37_82492_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/1_hu25a85ddb9f93cab0fa55e93b5333dc37_82492_890d19d3faf15d44ad969ed1b03deb2a.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/2_hu9bbb01bbfb11a783445e757d421db0fb_70290_cf1ecea0e1f7f05c4680c86845e41f5c.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/2_hu9bbb01bbfb11a783445e757d421db0fb_70290_a78cb98812ddc8518bbfdcdb10e95129.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/2_hu9bbb01bbfb11a783445e757d421db0fb_70290_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/2_hu9bbb01bbfb11a783445e757d421db0fb_70290_cf1ecea0e1f7f05c4680c86845e41f5c.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/3_huf362fb82ba93b788f9578a8e57b94d4f_77297_1bf14142851cb6e8ad251c4076b8d1be.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/3_huf362fb82ba93b788f9578a8e57b94d4f_77297_7a5de17df8888b44b4db0fd7fcad23e4.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/3_huf362fb82ba93b788f9578a8e57b94d4f_77297_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/3_huf362fb82ba93b788f9578a8e57b94d4f_77297_1bf14142851cb6e8ad251c4076b8d1be.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/4_hub2914b8d9a69ec90c277d467916fb1ab_104818_d6fec846e6ab92f8b93ce0a83b18f0fc.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/4_hub2914b8d9a69ec90c277d467916fb1ab_104818_b28dfbf97efe3f01fdea5025676ea9d0.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/4_hub2914b8d9a69ec90c277d467916fb1ab_104818_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/4_hub2914b8d9a69ec90c277d467916fb1ab_104818_d6fec846e6ab92f8b93ce0a83b18f0fc.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/5_hufa45d10d3e6713f5608e1775230925b8_94847_e55a3124bf81144b97ce19cb15d9ef7d.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/5_hufa45d10d3e6713f5608e1775230925b8_94847_fb74a857b259d53478df781a01a300d3.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/5_hufa45d10d3e6713f5608e1775230925b8_94847_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/5_hufa45d10d3e6713f5608e1775230925b8_94847_e55a3124bf81144b97ce19cb15d9ef7d.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/6_hu5ee6288bfd1f342436cc48f2251c0c3d_92384_4e08694d14e50d9dfe8a5e69d22f6a8b.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/6_hu5ee6288bfd1f342436cc48f2251c0c3d_92384_7ae1ba213e6c81a1d885972842b33c08.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/6_hu5ee6288bfd1f342436cc48f2251c0c3d_92384_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/6_hu5ee6288bfd1f342436cc48f2251c0c3d_92384_4e08694d14e50d9dfe8a5e69d22f6a8b.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/7_hu1a81d4db0ba8c75cf9866953d20b3ae4_88579_3c2d3a6f476dacc3aea29b17fadedcc0.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/7_hu1a81d4db0ba8c75cf9866953d20b3ae4_88579_acf9ce51cba1002b1b58fcf38cc153b8.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/7_hu1a81d4db0ba8c75cf9866953d20b3ae4_88579_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/7_hu1a81d4db0ba8c75cf9866953d20b3ae4_88579_3c2d3a6f476dacc3aea29b17fadedcc0.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/8_hu6185d541ba70f359b7a4776cd7dc6c85_539890_0d45516836ec4455092bf05626bb560b.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/8_hu6185d541ba70f359b7a4776cd7dc6c85_539890_9065ed0812ad06a7617eeaba261028c2.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/8_hu6185d541ba70f359b7a4776cd7dc6c85_539890_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/8_hu6185d541ba70f359b7a4776cd7dc6c85_539890_0d45516836ec4455092bf05626bb560b.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/9_hue7aaebf2c7f416b4cd6cb523baca8604_625346_7fa4d4d85e85d072f1bc0de221ecd193.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/9_hue7aaebf2c7f416b4cd6cb523baca8604_625346_ba03d5559fe571b6faf79daf78b529b0.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/9_hue7aaebf2c7f416b4cd6cb523baca8604_625346_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/9_hue7aaebf2c7f416b4cd6cb523baca8604_625346_7fa4d4d85e85d072f1bc0de221ecd193.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/10_hu29d3167748a58dda721e61c9def7d380_607269_4d0640954fe0b5fd577b3ed06ff55468.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/10_hu29d3167748a58dda721e61c9def7d380_607269_c2837dacab46b34588089a88c4a2bdcd.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/10_hu29d3167748a58dda721e61c9def7d380_607269_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/10_hu29d3167748a58dda721e61c9def7d380_607269_4d0640954fe0b5fd577b3ed06ff55468.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/11_hu995a3b395ca3c1f40028870ba07b0cf8_619997_65ca40cbd8bd6045aa3162bebe98a765.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/11_hu995a3b395ca3c1f40028870ba07b0cf8_619997_4c1cf3f9cb4a2feba949d72d93a818a3.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/11_hu995a3b395ca3c1f40028870ba07b0cf8_619997_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/11_hu995a3b395ca3c1f40028870ba07b0cf8_619997_65ca40cbd8bd6045aa3162bebe98a765.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/13_hu10f61aa599db5864f9fedfe95a66ba49_594931_19b904b0be868f1d370f4a20f0b4325e.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/13_hu10f61aa599db5864f9fedfe95a66ba49_594931_547949dc4b4961c87343e6c26b3292bc.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/13_hu10f61aa599db5864f9fedfe95a66ba49_594931_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/13_hu10f61aa599db5864f9fedfe95a66ba49_594931_19b904b0be868f1d370f4a20f0b4325e.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/14_hu1b1a503b89155b9511fffd12476a4a29_690354_6bd60f86467555658747a59b80888a1f.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/14_hu1b1a503b89155b9511fffd12476a4a29_690354_ce69d93b4f39ffd5de4b33e7faf3666b.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/14_hu1b1a503b89155b9511fffd12476a4a29_690354_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/14_hu1b1a503b89155b9511fffd12476a4a29_690354_6bd60f86467555658747a59b80888a1f.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/15_huf398b5a18d57405e772c957add532e79_601593_63d7e438cad66ead3afb07c81c807881.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/15_huf398b5a18d57405e772c957add532e79_601593_cb760f0ba95b7812244a13066def0aea.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/15_huf398b5a18d57405e772c957add532e79_601593_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/15_huf398b5a18d57405e772c957add532e79_601593_63d7e438cad66ead3afb07c81c807881.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/16_hu44b927dd30b24476d4f5594329064213_591903_9b989eaeb639207a25da577ff2340b06.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/16_hu44b927dd30b24476d4f5594329064213_591903_e85575368356168776967bece7546e9e.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/16_hu44b927dd30b24476d4f5594329064213_591903_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/16_hu44b927dd30b24476d4f5594329064213_591903_9b989eaeb639207a25da577ff2340b06.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/17_hu09a5b3e2cbeb0ad5d36e7e9dc337f32d_637428_fb0725b3789018eb3f16e3f8144543ef.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/17_hu09a5b3e2cbeb0ad5d36e7e9dc337f32d_637428_ebd42eeee6270f568af4873cb8bb0b99.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/17_hu09a5b3e2cbeb0ad5d36e7e9dc337f32d_637428_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/17_hu09a5b3e2cbeb0ad5d36e7e9dc337f32d_637428_fb0725b3789018eb3f16e3f8144543ef.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201807-istio-achilles-heel-wechat/images/18_huf79cb9b6d3d83dbe87c2b8d8451b7ea6_562911_e068f48179ee14d4e805432e0bf31422.webp 400w,
               /post/201807-istio-achilles-heel-wechat/images/18_huf79cb9b6d3d83dbe87c2b8d8451b7ea6_562911_a232294ff0d8106f6cccbc87fe81daad.webp 760w,
               /post/201807-istio-achilles-heel-wechat/images/18_huf79cb9b6d3d83dbe87c2b8d8451b7ea6_562911_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201807-istio-achilles-heel-wechat/images/18_huf79cb9b6d3d83dbe87c2b8d8451b7ea6_562911_e068f48179ee14d4e805432e0bf31422.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;鸣谢几位积极参与讨论的朋友！&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>大规模微服务架构下的Service Mesh探索之路</title>
      <link>https://skyao.net/talk/201806-service-mesh-explore/</link>
      <pubDate>Sat, 30 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/201806-service-mesh-explore/</guid>
      <description>&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-1_hu1a683fdb66d2cbd27fc3212f5996f43c_43381_0a3a84199bcd44e4b293ffc70dccd466.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-1_hu1a683fdb66d2cbd27fc3212f5996f43c_43381_5146f121807c383c714f1c4ba166b0ee.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-1_hu1a683fdb66d2cbd27fc3212f5996f43c_43381_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-1_hu1a683fdb66d2cbd27fc3212f5996f43c_43381_0a3a84199bcd44e4b293ffc70dccd466.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;今天给大家带来的内容叫做Service Mesh探索之路，但是在前面加了一个定语：大规模微服务架构下。之所以加上这个词，是因为我们这个体系是在蚂蚁金服这样一个大的架构下进行的，蚂蚁金服的体量大家可以想象，所以这个探索会带有一个非常隆重的色彩：对性能/规模/高可用等方面的思考。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-2_hub519295d1a38c2bc49ff3ad92ef6ba5b_60842_b6aa866e587820ca4627957414b62f17.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-2_hub519295d1a38c2bc49ff3ad92ef6ba5b_60842_2819106ccae8d41b2fcde5b5f62ce1ee.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-2_hub519295d1a38c2bc49ff3ad92ef6ba5b_60842_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-2_hub519295d1a38c2bc49ff3ad92ef6ba5b_60842_b6aa866e587820ca4627957414b62f17.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;今年6月初，在深圳的GIAC大会，我们同事披露了这个正在开发中的Service Mesh产品，我们现在暂时命名为Sofa Mesh。我们目前的产品都在Sofa品牌下，比如Sofa RPC，Sofa Boot等。今天我们详细介绍Sofa Mesh这个单独产品，上次大会只是简单披露，也就是给大家介绍说我们有这样一个产品，而我今天的内容是把这个产品详细展开。&lt;/p&gt;
&lt;p&gt;主要是三个内容：一是Sofa Mesh的技术选型，二是它的架构设计，以及在最后跟大家聊一下，蚂蚁金服在Sofa Mesh上的开源策略。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-3_hu1a683fdb66d2cbd27fc3212f5996f43c_25773_545337233a79d26a0efe75294067a21c.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-3_hu1a683fdb66d2cbd27fc3212f5996f43c_25773_1030c7a6523a67c25abba51f71b7041e.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-3_hu1a683fdb66d2cbd27fc3212f5996f43c_25773_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-3_hu1a683fdb66d2cbd27fc3212f5996f43c_25773_545337233a79d26a0efe75294067a21c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第一个是技术选型。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-4_hu8ffc6519f93a342b548fb119614cf509_107168_5ebca50a3b9e6e36f0c1b855c6769a04.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-4_hu8ffc6519f93a342b548fb119614cf509_107168_058dd250ef93077705cd34ec8365ee48.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-4_hu8ffc6519f93a342b548fb119614cf509_107168_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-4_hu8ffc6519f93a342b548fb119614cf509_107168_5ebca50a3b9e6e36f0c1b855c6769a04.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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;p&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;部署上会要求这三个场合都能使用。&lt;/p&gt;
&lt;p&gt;部署环境也会有多种，刚才我们调查到，有部分同学相对比较前沿一些，现在就已经上k8s了。有部分同学还是停留在以前的虚拟机以及物理机这种状态，也有一部分自己上了容器，还有部分同学可能会使用不同的公有云和私有云。这几种不同的环境，我们都是需要满足的。&lt;/p&gt;
&lt;p&gt;第三点可能要特殊一些，需要满足各种体系。刚才我们在调查的时候了解到，有部分同学是在做旧有系统改造，那在改造的时候就会遇到一个问题：除了Service Mesh之外，还需要跟原来的体系，比如说Sofa，或者社区主流框架如Dubbo，Spring Cloud，相互之间打通和过渡。怎么在技术转型期间平滑的让业务做变更，是我们在整个技术选型之前提出的实际要求。整个技术选型是在这样一个背景下进行的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-5_huc9e5623942587225b668e674f9a57bc4_158466_8bbe72a97f2aa66eb9bb1c3bc7e78c9c.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-5_huc9e5623942587225b668e674f9a57bc4_158466_118c763189afc9207e9afac4c18317da.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-5_huc9e5623942587225b668e674f9a57bc4_158466_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-5_huc9e5623942587225b668e674f9a57bc4_158466_8bbe72a97f2aa66eb9bb1c3bc7e78c9c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们做技术选型的时候，有两大方向：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;一个选择是在开源产品上做&lt;/p&gt;
&lt;p&gt;我们先看右边的路线，起点是找一个开源产品，fork出来，做增强/扩展/定制，和内部集成。因为开源产品还在继续往前走，所以我们会持续做版本更新，也可以从社区拿到最新版本。相当于是从开源社区做&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;/li&gt;
&lt;li&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;p&gt;这条路线会遇到一个问题，因为长期上看我们也是希望开源的，而开源就意味着不能将自己内部太多的定制化的东西直接做进去，所以在架构上需要考虑可扩展性，可以定制化。因为开源出去的应该是一个标准产品，这样的产品才可以得到社区和客户的认可。客户希望看到一个干净的东西，也需要做扩展，整个体系在设计上会有所不同。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两条路线的终点，从图上看，我们有两个目标：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;第一个目标是内部落地&lt;/p&gt;
&lt;p&gt;前面提到的，我们需要在蚂蚁金服主站这样的一个巨大规模的场景下落地，这是蚂蚁金服自身的需求。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;第二个目标是技术输出&lt;/p&gt;
&lt;p&gt;因为蚂蚁金服在公司策略上有科技输出的内容，不仅仅我们自己用，我们还需要给出去。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;现在我们来看这个问题：目标在这里，然后有左右两条路线，我们该怎么选择？在做的技术选型的时候，这是一个非常大的分歧点，到底是从左边走，还是从右边走？&lt;/p&gt;
&lt;p&gt;在公布结果之前，我们先来看一下有什么可选方案。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-6_hu471bac4b8141fa6f48a176eb7f7f7681_98789_e62531facb6ec94eb0dbd123c21211c8.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-6_hu471bac4b8141fa6f48a176eb7f7f7681_98789_c0c87ccecb7b3b017ab7cc4fc30fd64b.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-6_hu471bac4b8141fa6f48a176eb7f7f7681_98789_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-6_hu471bac4b8141fa6f48a176eb7f7f7681_98789_e62531facb6ec94eb0dbd123c21211c8.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是开源方案的选择，第一代的Service Mesh。&lt;/p&gt;
&lt;p&gt;左边的Linkerd，这个基本上，目前看，大家都已经有点嫌弃了。因为它没有控制平面，用Scala写的，基于JVM，资源消耗比较大。它的可扩展性比较有限的，相对于Envoy的扩展性。然后它里面有个dtab，有接触到的同学就会有认识：dtab的语法，非常的不人性，很难理解，使用不太方便。另外它的功能是远远不够的，对于蚂蚁金服来说。另外这个产品本身的发展前景已经很暗淡了，所以这个选项就被淘汰了。&lt;/p&gt;
&lt;p&gt;Envoy是非常不错的，做了一些令我们意外的事情：安心的去做好数据平面，没有往上面做很多的东西，而是创造性的提出了XDS API。整个设计是非常优秀的，性能和稳定性也表现得非常好，甚至看到业界有一个趋势，有一部分的公司开始把他们的nginx替换了，不再用nginx了，而是用envoy。也就是说，现在它的稳定性和性能达到和nginx一个级别，nginx大家应该都有听说过，envoy已经是这样一个工业成熟度。&lt;/p&gt;
&lt;p&gt;我们当时选型时是比较头疼的，因为它是c++写的，c++14。和我们技术栈的差异会比较大，因为蚂蚁的技术栈是以Java为主，长期的话，我们可能部分转到Golang上去。在这种情况下，C++的技术栈，会让我们比较尴尬，也不是说我们找不到会c++的同学，而是说，长期上会和我们的方向不一致，我们要在Java和Golang的技术栈之外再加一个c++，这就比较难受。&lt;/p&gt;
&lt;p&gt;然后我们内部会有大量扩展和定制化的需求。因为我们内部有我们自己的产品，我们自己的需求，我们的通讯方案，我们内部的追踪，监控，日志方案，所以工作量非常大。&lt;/p&gt;
&lt;p&gt;总结说，我们觉得Envoy很好，但是我们不能简单用。但是它在数据平面上的表现我们是非常认可的，Envoy在这点做得非常好。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-7_hu471bac4b8141fa6f48a176eb7f7f7681_85487_51f194ce55c884a5dcc359408fbad24b.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-7_hu471bac4b8141fa6f48a176eb7f7f7681_85487_457f5d16fb0da4d21503c5f18159ef4a.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-7_hu471bac4b8141fa6f48a176eb7f7f7681_85487_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-7_hu471bac4b8141fa6f48a176eb7f7f7681_85487_51f194ce55c884a5dcc359408fbad24b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;开源方案里面的第二代，istio是我们当时的第一选择，重点关注对象。Istio现在最大的问题在于它迟迟不能发布生产可用版本，大家如果对istio有了解的话，会知道istio刚刚发布了0.8版本，第一个长期支持版本，但是这个版本也不是生产可用。不出意外的话，按照目前的进度，istio应该会在7月份发布它的1.0版本，但是从我们目前的感受上看，1.0估计可能还是不能工业级的使用。所以需要等，而我们没法等，但是Istio的理念和方向我们非常认可。大家看一看，我们这个技术选型有多纠结。&lt;/p&gt;
&lt;p&gt;右边的Conduit，现在Conduit的最大限制是它只支持k8s。而现在蚂蚁金服还没有普及k8s，我们现在还有很多系统是跑在非k8s上的。第二是它的数据平面是Rust编写的，这个语言更加小众了，在座的同学有没有人了解Rust这门语言？或者听过。（备注：现场大概十几个人举手）大概10%左右的同学听过。好，Rust语言排名大概在50名左右。这个语言本身还是蛮认可的，我还很喜欢这个语言，它的一些特性还是非常有道理，如果掌握好还是可以写出非常好的产品，但是它的入门台阶会比较高一点。这个地方比较讨厌的事情是说，因为这个语言本身比较小众，所以基本上是没办法从社区借力的。这里可以举个例子，大家可以看一下Conduit的committer的人数，大概是25个左右，还包括像我这种只提交了几行代码的。Conduit从12月份开源到现在已经有半年时间，半年时间只有这么多的committer，其中真正有贡献大概9到10个人，基本上都是他自己的员工。也就说这个产品基本上没办法从社区借力，一个产品，如果大家一起来帮忙，其实很多的细节是可以完善的，但是Conduit就卡在Rust语言上。&lt;/p&gt;
&lt;p&gt;然后还是同样有技术栈的问题，因为这个原因，基本上Conduit我们也没法用了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-8_hu0dcc9a1d4e9d324b0d6964497cf4cfef_102932_6e0c28473bad6a14bc32539fd00a006f.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-8_hu0dcc9a1d4e9d324b0d6964497cf4cfef_102932_04afd8d4f0561d0a89d32c768780d36b.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-8_hu0dcc9a1d4e9d324b0d6964497cf4cfef_102932_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-8_hu0dcc9a1d4e9d324b0d6964497cf4cfef_102932_6e0c28473bad6a14bc32539fd00a006f.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们再看一下国内的在Service Mesh领域，其他的一些比较前卫的同学，他们的选择会是什么？&lt;/p&gt;
&lt;p&gt;首先是华为，华为自己做了一套Golang版本，名字叫做Mesher。这是由他们之前的一套类库演进而来。它走的路线是，先有类库和框架，然后加proxy，proxy打通了之后再慢慢的开始添加控制平面。这是一条非常非常标准的路线，我这边给一个词叫做&lt;strong&gt;老成持重&lt;/strong&gt;，因为这条路是最安全的：每一步都是基于现有的产品，很快就可以到下一个里程碑，然后每个里程碑都可以解决一些实际问题，可以直接得到一些红利，这个方案是比较比较稳妥的。比如说第一步是把proxy做进去，有了这个切入口之后，就在第一时间获取跨语言的红利，还有技术栈下沉的好处。然后控制平面的创新，可以在这个基础上慢慢往前做。&lt;/p&gt;
&lt;p&gt;在对接Istio这一条上，现在华为的策略，我们现在从公开途径了解到的是：部分对接istio，也就是有一部分的API兼容Istio。但是细节上还不太清楚，因为它的开源还没出来，目前得到的消息是，会在7月份开源。&lt;/p&gt;
&lt;p&gt;第二个是新浪微博的Motan Mesh，他们也是Golang的，但他不太一样，是全新实现。他们用Go语言重新写了一把，主要原因是因为它没有golang类库，Motan是基于Java的。&lt;/p&gt;
&lt;p&gt;刚才看到的这两个产品，他们的思路大体上是相同的，差异在哪里？就是启动的时候是用已有的类库还是重新写？这两个选择之间最大的麻烦在于编程语言，华为原来有go的类库，所以继续用golang包装一下就好了。但是新浪的类库用的是Java，而sidecar选择的是go语言，所以只能重新做了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-9_hu0dcc9a1d4e9d324b0d6964497cf4cfef_61244_26cb444a08ca425373569bd1b4215062.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-9_hu0dcc9a1d4e9d324b0d6964497cf4cfef_61244_492cfa07d412e513ce1372f1ff55b24e.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-9_hu0dcc9a1d4e9d324b0d6964497cf4cfef_61244_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-9_hu0dcc9a1d4e9d324b0d6964497cf4cfef_61244_26cb444a08ca425373569bd1b4215062.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们再看腾讯，最近看到他们有类似的产品出来。我们看看他们的资料：在数据平台上继续选择Envoy，因为它比较成熟。腾讯的话大家比较熟悉，尤其是腾讯有非常深厚的c++背景，所以Envoy对他们来说，技术栈是非常OK的。而且之前内部其他领域Envoy也是在用的，所以底层非常自然的选择了Envoy。然后控制平面上，据传是&amp;quot;挣扎了一下&amp;quot;。这个词是我抄过的，&amp;ldquo;他们挣扎了一下&amp;rdquo;，最后还是选了Istio。然后自己做定制和扩展，然后注意到他们也解耦了k8s。这也是其中一个关键的点：要不要绑定k8s？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-10_hu0dcc9a1d4e9d324b0d6964497cf4cfef_56010_2c696c84093f76f3f4d1c97056da1511.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-10_hu0dcc9a1d4e9d324b0d6964497cf4cfef_56010_ccba9bbe643eab50b9e1da3cac72c7e7.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-10_hu0dcc9a1d4e9d324b0d6964497cf4cfef_56010_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-10_hu0dcc9a1d4e9d324b0d6964497cf4cfef_56010_2c696c84093f76f3f4d1c97056da1511.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里还有UCloud的一个很有意思的做法，另辟蹊径啊。他的方案很有意思，是一个轻量级的实践：从Istio里面，将Envoy和Pilot单独剥离出来。就是说不用Istio整体，把Mixer和Auth的模块去掉，只要最重要的Envoy，然后把Pilot剥离出来。然后这个Pilot还是个定制版，把其他的adapter干掉了。Pilot主要是做服务发现，它底层用ETCD，做了一个ETCD的adapter，把其他的adapter从Pilot中去掉。做完这几个事情之后，整个体系就可以脱离k8s了，这是一个比较有意思的实践。&lt;/p&gt;
&lt;p&gt;总结：在讲我们技术决策过程之前，我们过了一下目前市场上的主要产品，以及一部分实践者的做法。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-11_hu21b97ba1cf8d442905025c90daefe20a_89876_d4ea473371be3b0e4219edb5302d2d7e.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-11_hu21b97ba1cf8d442905025c90daefe20a_89876_e04d062c3273b11b881a04edd2cb98ed.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-11_hu21b97ba1cf8d442905025c90daefe20a_89876_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-11_hu21b97ba1cf8d442905025c90daefe20a_89876_d4ea473371be3b0e4219edb5302d2d7e.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们现在来详细讲一下，Sofa Mesh在技术选型上的考虑。&lt;/p&gt;
&lt;p&gt;首先第一个，数据平台上Envoy是最符合我们要求的，Envoy确实好。第二个事情是Envoy提出的XDS API设计是非常令人称道的，我们现在对这个的评价是非常高的。它实际上是一套通用的API，由于时间的缘故，我今天就不在现场展开API的细节。只能说XDS API基本上已经成为数据平面和控制平面之间的一个事实标准。&lt;/p&gt;
&lt;p&gt;在这种情况下，我们其实是想用Envoy的，但是刚才提到我们有个技术栈选择的问题：我们不愿意将c++纳入到我们主流的技术栈。然后我们本身有太多的扩展和定制，逼得我们不得不去改Envoy，我们不能简单的拿过去用，我们需要做很多扩展的。&lt;/p&gt;
&lt;p&gt;另外一个事情是，我们这个proxy不仅仅是用于Mesh，我们有可能把它引入到API Gateway里头，以及后面会提到的名为Edge Sidecar的模块。因为这个原因，所以，怎么说呢，想用，但是不合适用。&lt;/p&gt;
&lt;p&gt;第二就是在Istio上，控制平面这一块Istio可以说是做的最好的。基本上，到目前为止，在控制平面上，暂时我们还没有看到做的比Istio更好的产品，或者说思路。目前Istio整个设计理念，包括它的产品方向，也是我们非常认可的。&lt;/p&gt;
&lt;p&gt;但是Istio的性能是目前最大的问题，而我们有一个重要的前提：大规模应用。要用在蚂蚁金服主站这样一个场景下，性能和稳定性对我们非常非常的重要。第二个问题是它对非k8s的支持不够理想，因为我们还涉及到一个k8s没有完全上线的问题。第三个是和侵入式框架互通的问题，我们内部用的是SOFA，对外推出的时候我们的客户用的可能是Dubbo或者Spring Cloud，Mesh上去之后，两个系统现在走不通，这是大问题。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-12_hu68224e9b777abf187d541c28db9dad60_83182_3c13b0ee53ad6b37101347b9f3b4ab85.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-12_hu68224e9b777abf187d541c28db9dad60_83182_25371897c8e7c6b6e1c257a9d98e7b50.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-12_hu68224e9b777abf187d541c28db9dad60_83182_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-12_hu68224e9b777abf187d541c28db9dad60_83182_3c13b0ee53ad6b37101347b9f3b4ab85.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最终我们的策略是这样的，这是我们Sofa Mesh的技术选型：左边是Istio现有的架构，Envoy/Pilot/Mixer/Auth，右边是我们Sofa Mesh的架构。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;最重要的第一点：我们用Golang开发的Sidecar替换Envoy，用Golang重写整个数据平面。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;第二点是我们会合并一部分的Mixer内容进到Sidecar，也就是Mixer的一部分功能会直接做进Sidecar。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;第三点是我们的Pilot和Auth会做扩展和增强。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这是我们整个的技术选型方案，实际上是Istio的一个增强和扩展版本，我们会在整个Istio的大框架下去做这个事情，但是会做一些调整。&lt;/p&gt;
&lt;p&gt;这是今天的第一部分内容，Sofa Mesh的技术选型。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-13_hu1a683fdb66d2cbd27fc3212f5996f43c_26804_2fd7b97f4366ea5084aee5ec2b4ad9dc.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-13_hu1a683fdb66d2cbd27fc3212f5996f43c_26804_67ece895f4879f7faf799904ca80a3fa.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-13_hu1a683fdb66d2cbd27fc3212f5996f43c_26804_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-13_hu1a683fdb66d2cbd27fc3212f5996f43c_26804_2fd7b97f4366ea5084aee5ec2b4ad9dc.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;然后我们来详细介绍一下在这个技术选型上我们怎么去做实现。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-14_hue9aaf981b4f02ca01fb9165d06a40301_69798_8b075203c3d348477ff21c34c8f3eab2.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-14_hue9aaf981b4f02ca01fb9165d06a40301_69798_c21e9dff89cc516c40953ee4fbe0dc79.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-14_hue9aaf981b4f02ca01fb9165d06a40301_69798_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-14_hue9aaf981b4f02ca01fb9165d06a40301_69798_8b075203c3d348477ff21c34c8f3eab2.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;首先是Golang版本的Sidecar，我们会参考Envoy，非常明确的实现XDS API。因为XDS API是目前的事实标准，所以我们选择遵循，然后我们会让它兼容Istio。&lt;/p&gt;
&lt;p&gt;在协议支持上，我们会支持标准的HTTP/1.1和HTTP/2，也就是大家常见的REST和gRPC协议。然后我们会增加一些特殊的协议扩展，包括Sofa协议，Dubbo协议，HSF协议。我们现在正在做这几个协议的扩展，然后XDS API我们支持，mixer service我们没有改动，遵循现有实现。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-15_hua2953c4f4adf8c2b85912174e831e610_82218_37d3c02f62ef765ea4ab51bc67e75032.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-15_hua2953c4f4adf8c2b85912174e831e610_82218_cac263f466f8b23ec7825673202de4e4.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-15_hua2953c4f4adf8c2b85912174e831e610_82218_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-15_hua2953c4f4adf8c2b85912174e831e610_82218_37d3c02f62ef765ea4ab51bc67e75032.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最大的变化在Mixer，其实刚才的Sidecar虽然是全新编写，但是说白了是做Envoy的替换，在架构上没有什么变化。但是第二步的变化就非常大，我们会合并一部分的Mixer功能。&lt;/p&gt;
&lt;p&gt;Mixer的三大功能：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;check。也叫precondition，前置条件检查，比如说黑白名单，权限。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;quota。比如说访问次数之类。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;report。比如说日志，度量等。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;三大功能里面，注意到，前两个功能是同步阻塞的，就是一定要检查通过，或者是说quota验证OK，才能往下走。如果结果没回来只能等，因为这是业务逻辑，必须要等。而Report是可以通过异步和批量的方式来做的。&lt;/p&gt;
&lt;p&gt;在这里，我们现在的决策是：我们会将其中的两个部分(check和quota)合并进来，原有report部分我们会继续保留在mixer里面。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-16_hu81039307c2489c9becdc1f7d9f780742_91752_21f3191121466fee95f61670f53fc0a7.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-16_hu81039307c2489c9becdc1f7d9f780742_91752_bcdef08afc5227f2bb055cdf1f1d9f81.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-16_hu81039307c2489c9becdc1f7d9f780742_91752_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-16_hu81039307c2489c9becdc1f7d9f780742_91752_21f3191121466fee95f61670f53fc0a7.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;可能大家会问：为什么我们要选择用这个方案，而不是遵循Istio的标准做法？我们之前聊到，我们会尽量去和Istio做兼容，跟随Istio的设计理念和产品方向，但是我们在它的架构上做了一个重大的调整。为什么？&lt;/p&gt;
&lt;p&gt;最大的问题就是&lt;strong&gt;对性能的影响&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;给大家解释一下，看右边这个图，Envoy在每次请求进来的时候，要去做两次调用：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;第一次在请求转发之前要做一次check，这个check里面包含了quota。Check完成通过，才能把请求转发过去。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;请求转发完成之后，再调用report，报告一下响应时间，日志，度量等信息&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;每次traffic都会有两次调用：一次check，一次report。而这是远程调用，因为这两个模块是两个进程，Mixer是单独部署的。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;同步阻塞&lt;/strong&gt;意味着必须要等，&lt;strong&gt;远程调用&lt;/strong&gt;意味着有开销而且有延迟。这个事情是发生在&lt;strong&gt;每一次&lt;/strong&gt;请求里面，意味着整个的性能一定会受影响。而考虑到我们蚂蚁金服这样一个体量，其实我们是很难承受。所以我们有自己的观点：我们不是太认可这样的一个方式，我们的想法是说我们要把它拆分出来想一想：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;如果是需要请求做同步阻塞的功能，比如说黑白名单的验证，可能要检查IP地址，可能检查quota。这些逼请求一定要做同步阻塞等待结果的功能，就&lt;strong&gt;不应该放在Mixer中&lt;/strong&gt;去完成去远程调用，而应该在Sidecar中完成。&lt;/p&gt;
&lt;p&gt;这是我们的观点，原因就是远程调用带来的系统开销，这个代价实在是太高了！&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后其他的功能，比如说可以优化为异步的，或者可以以批量方式来提交的，最典型的就是Report。Report其实是可以异步提交，可以把十个请求打包到一个report同时提交，这些都是OK的。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这是我们的基本想法。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-17_hube816503136c85ca82359efb45075eae_93134_8e2a82fc9322c2726feb8f8280ebe108.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-17_hube816503136c85ca82359efb45075eae_93134_11694e03bdbd9e998f53d0072a335d61.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-17_hube816503136c85ca82359efb45075eae_93134_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-17_hube816503136c85ca82359efb45075eae_93134_8e2a82fc9322c2726feb8f8280ebe108.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这个问题其实在Istio里面是给了一个解决方案的。最早的时候，Istio 0.1版本中，一出来就发现这个问题。从去年5月份开始到现在，13个月的时间里，他只给了一个解决方案，就是在Mixer上的这个位置加了一个Cache。这个的Cache的想法是：把这些结果缓存在Envoy的内存里面，如果下次的检查参数是相同的，那我们可以根据这样一个缓冲的设计，拿到已经缓存的结果，就可以避免远程调用。这个方式是很理想的，对吧？只要缓存能够命中，那就可以避免这一次远程调用。&lt;/p&gt;
&lt;p&gt;然后第二个优化是report，现在的report是通过异步模式完成的，而且是批量。&lt;/p&gt;
&lt;p&gt;理论上说，如果这两个事情做到足够理想，Mixer应该就不是瓶颈。对吧？&lt;/p&gt;
&lt;p&gt;问题在于：这个Cache真的搞得定吗？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-18_hub09093d87fe202c789304c4ddb2f8aa4_76366_30a8a63416a745bd167649a4194edb7c.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-18_hub09093d87fe202c789304c4ddb2f8aa4_76366_f7872479973bebbc9a2b1f617128a816.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-18_hub09093d87fe202c789304c4ddb2f8aa4_76366_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-18_hub09093d87fe202c789304c4ddb2f8aa4_76366_30a8a63416a745bd167649a4194edb7c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们给一个简单的例子，我现在假设Mixer有三个adapter。然后它的输入值是不同的属性，属性是istio的概念，理解为若干个输入值。假设，需要三个adapter分别检查A/B/C。如果这三个属性A/B/C，他们只有100个取值范围，每个都是从0到100，我们假设这种最简单的场景。&lt;/p&gt;
&lt;p&gt;如果这三个adapter分别做缓存的话，需要多少个缓存项？很容易计算吧？100个a，100个b，100个c，非常容易计算，这种情况下，其实就是a+b+c等于300嘛。理解一下：有三个输入，每个输入只有一百个取值范围，我们要把他们缓存起来。这些缓存大小，就是允许的范围，然后加起来。只要有300个key，就都可以缓存起来。&lt;/p&gt;
&lt;p&gt;但是，这个方法中，缓存是做在mixer这边，每个adapter单独缓存。但是，在Istio中，缓存是做在Envoy这端的，因为做在mixer这端是没有用的，还是要远程调用过去。它做缓存的很重要的目标是要在客户端避免远程调用。所以，这种情况下，把缓存放到这里（备注，图中绿色方块）。&lt;/p&gt;
&lt;p&gt;大家现在想一想，现在这里只有一个缓存，只有一个key/value。现在还有刚才的这个场景，A/B/C各自的取值范围都是一百。但是现在缓存放在这边的话，实际上的这个key要考虑三个值了，A/B/C的组合。这种情况下，它的最大缓存个数是多少？&lt;/p&gt;
&lt;p&gt;（备注：现场回答，a 乘 b 乘 c）&lt;/p&gt;
&lt;p&gt;a * b * c？还能 a + b + c吗？做不到了，对不对？现在是 a * b * c，从300变成这么大的数了。为什么？因为缓存是在这个地方做的，根本没有办法像这样分开做，所以这里就变成了一个笛卡尔乘积。&lt;/p&gt;
&lt;p&gt;这个笛卡尔乘积有一个很大的麻烦，也就是说，如果adapter检查的某个属性，它的取值范围比较大，比如说要检查客户端的IP地址？你想想，这个IP地址有多少个取值范围？数以几十万几百万计，对吧？这种情况，哪怕在前面再乘以特别小的值，哪怕只是十，二十，如果是加20根本没所谓的，加200，加2000都没所谓的，那乘个200，乘个2000试一下？瞬间就被干掉。IP地址可能只是百万级别，再在前面乘个100，乘个1000，瞬间就疯掉了。这个key值基本上已经是大到不能接受：要么就全放内存，内存爆掉；要不然限制缓存大小，就放1万个，缓存的命中率会非常低，整个缓存相当于失效了。&lt;/p&gt;
&lt;p&gt;这个细节，因为时间原因，不在这里详细讲了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-19_hu7d071f95fcfd0e59d7cf850c84fb7504_88846_20cc3a25129485b15dd6638decabe18d.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-19_hu7d071f95fcfd0e59d7cf850c84fb7504_88846_abc4ac0af8194077c196fbca00922bcc.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-19_hu7d071f95fcfd0e59d7cf850c84fb7504_88846_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-19_hu7d071f95fcfd0e59d7cf850c84fb7504_88846_20cc3a25129485b15dd6638decabe18d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里讲第二点，我们的反省：隔离怎么做？&lt;/p&gt;
&lt;p&gt;Mixer有一个基本的设计目标，就是希望提供一个统一的抽象（就是这个adapter的概念），用它来隔离基础设施后端和Istio的其他部分。但是在这个点上我们的反思是：我们认可这样一个隔离。大家理解基础设施后端的概念吧？举个例子，日志处理如prometheus，各种后端监控系统。这些系统和应用之间，我们认为这种情况下的确应该做隔离，没必要每个应用都去和基础设施后端产生直接的联系。这个观点是我们是赞许的。&lt;/p&gt;
&lt;p&gt;但是我们现在的意见是，我们把这条线(备注：连接应用和基础设施后端的标记有红叉的线)从应用里面拿下来之后，我们把它下沉。下沉到Sidecar，够不够？Istio的做法是，它觉得这个地方应该再往前走一步，到Mixer里面。由Mixer去完成和基础设施后端的连接，走这根线（备注：图中连接Mixer和基础设施后端的线）。但是多了这样一个隔离之后的代价，就是在中间的这根红线上，会多一次远程调用。&lt;/p&gt;
&lt;p&gt;现在只有两个选择：和基础设施怎么连？这条线（备注：最左边的）大家都认为没必要，这两条线（备注：中间和右边的线）之间选，两条线的差异，就是要付出一次远程调用的代价。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-20_hud9f93057f395628ea5aca41bc2279fe6_110861_3882715b43825e37897de897406c30fa.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-20_hud9f93057f395628ea5aca41bc2279fe6_110861_1d0d0fe1f8bdc6f464f531436ef5454d.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-20_hud9f93057f395628ea5aca41bc2279fe6_110861_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-20_hud9f93057f395628ea5aca41bc2279fe6_110861_3882715b43825e37897de897406c30fa.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;继续反省：什么是基础设施后端？&lt;/p&gt;
&lt;p&gt;这里我们做一个列表，整个Istio现有的adapter，大家可以看到，大概是这些。前面这两个部分是实现check和quota的adapter，后面这些adapter是实现report功能。&lt;/p&gt;
&lt;p&gt;在这里，我们的反省是：这些功能，比如说黑白名单，比如说基于内存的quota，或者基于外部redis的quota。我们认为这些功能不太应该视为后端基础设施，因为这些功能更应该是说是体系内置的基本能力，应该直接把它们做成Mesh的内置产品，或者说可以做标准化，然后和外部系统集成。这些我认为应该是Mesh的最基础的功能，比如说我们Sofa Mesh可以提供基于Redis的quota方案，直接就把这个功能给出来了。我不认为应该再去跟外界的一个所谓的基础设施后端发生联系。&lt;/p&gt;
&lt;p&gt;但是下面这些我们是觉得OK的。这些adapter大家有概念吧，prometheus大家应该都接触过的。剩下的这些在国内可能用的不多，是各种日志和metric相关的功能。把这些视为基础设施后端，我们是非常理解的。包括我们内部，我们蚂蚁也有很多这样的系统，相信各位自家的监控方案也是不一样的。&lt;/p&gt;
&lt;p&gt;这些视为基础设施，和系统隔离开，我们认为这是非常有必要，可以理解，可以接受。&lt;/p&gt;
&lt;p&gt;这是我们在这一点（备注：何为基础设施后端）上和istio的差异。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-21_hud66bf237853100ba1c81e3fc45c8ffcc_123117_9b1d6809183e35daa53722969148de9e.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-21_hud66bf237853100ba1c81e3fc45c8ffcc_123117_5c22272777029e698b95124425d41101.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-21_hud66bf237853100ba1c81e3fc45c8ffcc_123117_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-21_hud66bf237853100ba1c81e3fc45c8ffcc_123117_9b1d6809183e35daa53722969148de9e.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;因为时间原因，我们就不再深入去讲，这里我给了一些我博客上的文章。前段时间，我们在做技术选型，在做前面整个架构设计时，在这一点上有些讨论。以及我们最重要的决策：为什么要把Mixer合并进去。细节都在这几篇文章里面，大家如果有兴趣，可以去详细了解。&lt;/p&gt;
&lt;p&gt;备注链接地址：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://skyao.net/post/201804-servicemesh-architecture-introspection/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Service Mesh架构反思：数据平面和控制平面的界线该如何划定？&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://skyao.net/post/201804-istio-achilles-heel/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Mixer Cache: Istio的阿克琉斯之踵&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://skyao.net/post/201804-istio-mixer-cache-concepts/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Istio Mixer Cache工作原理与源码分析(1)－基本概念&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://skyao.net/post/201806-istio-mixer-cache-principle/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Istio Mixer Cache工作原理与源码分析(2)－工作原理&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://skyao.net/post/201806-istio-mixer-cache-main/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Istio Mixer Cache工作原理与源码分析(3)－主流程&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&#34;https://skyao.net/post/201806-istio-mixer-cache-signature/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Istio Mixer Cache工作原理与源码分析(4)－签名&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-22_hu06e42dbe8a24ad2b8c12b87cf1d40e81_89012_8d8de321511f9664f1338bc262c0bb7b.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-22_hu06e42dbe8a24ad2b8c12b87cf1d40e81_89012_931c988777397524e643dfca63f7f511.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-22_hu06e42dbe8a24ad2b8c12b87cf1d40e81_89012_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-22_hu06e42dbe8a24ad2b8c12b87cf1d40e81_89012_8d8de321511f9664f1338bc262c0bb7b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们还有一部分现在没有合并进来的adapter和mixer，report的这部分。但是这块不是说完全没有问题，我们现在有一个担心，report这块可能会存在一个叫做&lt;strong&gt;网络集中&lt;/strong&gt;的问题。比如说，大家会注意到，应用和Sidecar是一对一部署的，有一万个应用，就有一万个Sidecar。基础设施后端也是多机部署的。而现在的方式，流量会先打到Mixer来，Mixer也是高可用的，也是会部署多台。但是这个数量肯定不是一万这个级别，跟这个肯定会有很大的差异。这样流量会先集中，通道会突然间收缩一下。总的流量没变，但是通道的口径要小很多。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-23_hu06e42dbe8a24ad2b8c12b87cf1d40e81_89977_035e540857af32841f3867306d437bf6.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-23_hu06e42dbe8a24ad2b8c12b87cf1d40e81_89977_88e609438e7885e782c9e3dd745dd913.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-23_hu06e42dbe8a24ad2b8c12b87cf1d40e81_89977_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-23_hu06e42dbe8a24ad2b8c12b87cf1d40e81_89977_035e540857af32841f3867306d437bf6.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对网络吞吐量也会有影响。&lt;/p&gt;
&lt;p&gt;比如最简单的，如果应用直连，走交换机直接就过去了。&lt;/p&gt;
&lt;p&gt;如果是Sidecar模式，是在这个位置上（备注：应用和sidecar之间的绿色连线）加一个远程调用，但是应用和Sidecar之间走的是localhost，localhost根本就不走网卡，直接环回地址就走了。对性能不会有什么影响，对网络流量的影响就为零了。所以这两个方案相比，吞吐量不会有变化。&lt;/p&gt;
&lt;p&gt;但是，如果在Sidecar和Backend之间再加一个Mixer，这意味着要走两次网络，这样的话会有一个流量翻倍的问题。&lt;/p&gt;
&lt;p&gt;所以这个地方可能会带来一些问题，但暂时我们现在还没做决策，我们现在还不是很确定这个问题会不会导致质的影响。所以我们现在暂时还是把它放在这里，就是说我们后面会做验证，如果在我们的网络方案下，这个方式有问题的话，我们可能再合进去。但是如果没问题的话，我们认为分开之后架构确实会更理想一些，所以我们现在暂时先不合并。&lt;/p&gt;
&lt;p&gt;给大家一些参考，目前Conduit最新版本已经把report的功能合并进来，然后check的功能，会在后续的计划中合并。我们在国内做一些技术交流，华为新浪微博他们现在通通都是选择在Sidecar里面实现功能，不走mixer。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-24_hua5580187c26246ee96581808e31f2fd9_128170_e4a09db94ac0974bbaaf84d5dafa14a0.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-24_hua5580187c26246ee96581808e31f2fd9_128170_44d44e726a00431e679765fdd3199842.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-24_hua5580187c26246ee96581808e31f2fd9_128170_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-24_hua5580187c26246ee96581808e31f2fd9_128170_e4a09db94ac0974bbaaf84d5dafa14a0.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是我们称之为梦幻级别的服务注册和治理中心，我们对他的要求是比较多的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;我们需要他支持跨集群，比如说我们现在有多个注册中心，多个注册中心之间可以相互同步信息，然后可以做跨注册中心的调用&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;还有支持异构，注册中心可能是不一样的东西。能理解吧，有些是Service Mesh的注册中心，比如Istio的，有些是Spring Cloud的注册中心，比如Consul。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后终极形态，我们希望在两种场景都可以支持。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;右边的这个图，是我们构想中的比较理想化的注册中心的架构，我们会有各种adapter实现，会有一个抽象的模型，把他们抽象起来，然后有一些接口。后来，在我们实现的时候发现，Istio的路线跟我们有点像，Istio本身也是做了跨平台的Adapter，也做了一层抽象，然后它也提出了一些API。所以我们最终的决策是：往Pilot靠。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-25_hu3038eed0e703d35ca7ff57293a29239c_88211_c82666e8ad281a29f7303f3cc4b759dd.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-25_hu3038eed0e703d35ca7ff57293a29239c_88211_38fbad838ab152c4eb8a231405769243.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-25_hu3038eed0e703d35ca7ff57293a29239c_88211_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-25_hu3038eed0e703d35ca7ff57293a29239c_88211_c82666e8ad281a29f7303f3cc4b759dd.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们以Istio的Pilot模块为基础去做扩展和增强：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;增加Sofa Registry的Adapter，Sofa Registry是我们内部的服务注册中心，提供超大规模的服务注册和服务发现的解决方案。所谓超大规模，大家能理解吧？服务数以万计。&lt;/li&gt;
&lt;li&gt;再加一个数据同步的模块，来实现多个服务注册中心之间的数据交换。&lt;/li&gt;
&lt;li&gt;然后第三点就是希望加一个Open Service Registry API，增加服务注册，因为现在Istio的方案只有服务发现，它的服务注册是走k8s的，用的是k8s的自动服务注册。如果想脱离k8s环境，就要提供服务注册的方案。在服务发现和服务模型已经标准化的情况下，我们希望服务注册的API也能标准化。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-26_hu99089294e867d6fc7d22712c515c43e6_107498_4fc321015d2eba82bdf353510f8c860f.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-26_hu99089294e867d6fc7d22712c515c43e6_107498_257c11fa88b695ff61e807201d427ac8.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-26_hu99089294e867d6fc7d22712c515c43e6_107498_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-26_hu99089294e867d6fc7d22712c515c43e6_107498_4fc321015d2eba82bdf353510f8c860f.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里还有一个比较特殊的产品，因为时间限制，给大家简单了解一下。&lt;/p&gt;
&lt;p&gt;我们计划的Edge Sidecar这个产品，它是东西向服务间通讯的一个特殊桥梁。所谓东西向，大家能理解吧？东西向指服务间通讯，也就是A服务调用B服务。对应的还有南北向，南北向通常是指从外部网络进来调用服务，如走API Gateway调用服务。在东西向通讯中，我们有时会需要一个比较特殊的途径，比如说在这个图中，我们有两个集群，两个集群各有各自的服务注册中心。我们通过增强Pilot的方式打通两个注册中心，可以知道对方有什么服务。&lt;/p&gt;
&lt;p&gt;当A服务发出一个请求去调用B服务的时候，由于两个集群是隔离的，网络无法相通，肯定直接调用不到的。这时local sidecar会发现，服务B不在本集群，而在右边这个集群里，Local Sidecar就会将请求转发给Edge Sidecar，然后由Edge Sidecar接力完成后续的工作。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-27_huc9271213878cca5e33ce21c7d8564486_85781_af4d55c111f3edfb0643e1189ddb827f.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-27_huc9271213878cca5e33ce21c7d8564486_85781_758dfaaa3de30bde3841986dbd7912cb.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-27_huc9271213878cca5e33ce21c7d8564486_85781_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-27_huc9271213878cca5e33ce21c7d8564486_85781_af4d55c111f3edfb0643e1189ddb827f.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这个模块的功能会比较特殊一点，因为时间限制，在今天的过程当中，Pilot和Edge Sidecar就不再详细展开。&lt;/p&gt;
&lt;p&gt;下个月在北京的meetup上，我们这边负责这一块工作的专家，俊雄同学，会给大家详细展开。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-28_hu1a683fdb66d2cbd27fc3212f5996f43c_27457_1ba7559d05f063f4e60939f8e97ff2af.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-28_hu1a683fdb66d2cbd27fc3212f5996f43c_27457_ea7ac1eb4844f452adceb35b6d26f258.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-28_hu1a683fdb66d2cbd27fc3212f5996f43c_27457_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-28_hu1a683fdb66d2cbd27fc3212f5996f43c_27457_1ba7559d05f063f4e60939f8e97ff2af.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;现在讲第三部分，大家更关心的一部分，开源策略。&lt;/p&gt;
&lt;p&gt;Sofa Mesh的开源策略，可能会和大家之前接触到的一些开源产品，有质的差异，非常的不一样。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-29_huad6bded9b65c82abdcab0fcea0128752_121754_4376a7045314d762b74fad0bbf67aba8.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-29_huad6bded9b65c82abdcab0fcea0128752_121754_f9f4d18f9bc806e54c5992d317d1cd49.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-29_huad6bded9b65c82abdcab0fcea0128752_121754_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-29_huad6bded9b65c82abdcab0fcea0128752_121754_4376a7045314d762b74fad0bbf67aba8.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;备注：这块就不整理了，直接看图中文字。&lt;/p&gt;
&lt;p&gt;这是整个大的愿景。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-30_hu9c6514c9d0320ffb115b56a0608ff34a_111650_c551f9488d15e461c75c74a1ebfbd31c.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-30_hu9c6514c9d0320ffb115b56a0608ff34a_111650_77b57faff3517cc64c5eaadcb75d0836.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-30_hu9c6514c9d0320ffb115b56a0608ff34a_111650_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-30_hu9c6514c9d0320ffb115b56a0608ff34a_111650_c551f9488d15e461c75c74a1ebfbd31c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Sofa Mesh的开源态度，其实我写左边这些的时候是有很大压力的。用官方话语说，不针对任何人和任何项目，我们不影射任何人。&lt;/p&gt;
&lt;p&gt;但是，大家如果经常用各种开源产品的话，会发现一些问题。比如说，开源的时机。大家接触的开源产品，尤其是国内的，不管是多大的公司，通常都是产品完成之后，甚至是使用好多年。好处是相对稳，缺点是什么？（备注：现场回答，老）对，技术可能已经很老了，十年前的！还有可能是它都已经放弃了，开源出来时自己不再使用。或者说是一个很新的产品，真的很新，他自己不用，说就是做出来给你用的。（备注：现场哄笑）自己不用的产品给你用，你的第一反应是什么？小白鼠是吗？你愿意做小白鼠吗？你敢把公司的这个产品放上面吗？&lt;/p&gt;
&lt;p&gt;Sofa Mesh这次比较特殊，非常非常特殊。我们这个产品，会在非常早的时间点上开源给大家。我甚至可以跟大家说，其实在这个点上，我们更重要的是摆明态度：我们要开源，我们要把这个产品开源给大家，甚至早到我们自己都不认为这是一个完整的产品。为什么？&lt;/p&gt;
&lt;p&gt;有几个事情，这几点大家认可吧？业界最新的技术，Mesh是最新技术大家都已经达成共识了吧？业界最好的架构，当然这个我们还在努力中，尽量做好。然后我们会给大家一个承诺，大家不用担心做小白鼠，你能拿到的产品，我们已经趟过一遍了。&lt;/p&gt;
&lt;p&gt;开源动机，这个地方我们也不说大话，就是我们希望能吸引整个社区，谋求这样一个合作，走开源共建的方式。这是为什么我们会选择在现在这个时间点上开源出来。&lt;/p&gt;
&lt;p&gt;整个产品的维护，什么样的产品会让你有信心，不用担心中间断掉？最重要的一点是我们自己在用。想想，如果支付宝在用，你担心这个项目死掉吗？对不对？如果这个产品本身是蚂蚁金服这样级别的公司，在它的线上将会使用的产品，而且是同样一个核心的版本。相信在这种情况下，大家就放心了吧？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-31_hudaecd611259eff5a09c76944f3b5008a_105337_1087313eb8e9bafd9a0b8e711d879d9d.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-31_hudaecd611259eff5a09c76944f3b5008a_105337_74d8c5633f8ae20c53d50c129be6e81e.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-31_hudaecd611259eff5a09c76944f3b5008a_105337_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-31_hudaecd611259eff5a09c76944f3b5008a_105337_1087313eb8e9bafd9a0b8e711d879d9d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Sofa Mesh的合作模式，我称之为&amp;quot;多层次全方位开放&amp;quot;。&lt;/p&gt;
&lt;p&gt;中间这幅图，最底下的是&lt;strong&gt;基础类库&lt;/strong&gt;，实现各种功能。我们希望有这样一套基础类库，类比Netflix的OSS套件。因为Golang的类库做的不是很好，没有Java沉淀的那么好。目标是希望在这个产品做完之后，能给整个社区沉淀出一套Golang的微服务基础类库。最重要的一点，是希望最好能大家合力，在这个点上做出一套成熟稳定性能足够好的产品。这是在类库层面。&lt;/p&gt;
&lt;p&gt;在类库之上，功能模块层面，比如说Golang版本的Sidecar，我们希望它能替换Envoy的功能。在原来使用Envoy的情况下可以使用这个Sidecar来替代。体现在什么层次？就是说，如果想用Envoy，也很喜欢它，但是可能又受限于C++语言栈，更希望是Golang语言栈的时候，可以选择我们这一套。或者如果我们抱有同样的想法，比如想把Mixer合进来，可以在Sidecar这个层面上来重用我们的产品，跟我们做合作。或者我们刚才提到的这个产品，增强版本的Pilot，大家有印象吧？我们会实现一个非常强大的，跨各种集群，各种异构的服务注册机制。然后是Edge Sidecar，在两个不同的区域之间，比如两个不同的机房，IP地址不通的情况下，帮你打通服务间调用。这些功能模块，会以单独的产品和项目出现，你可以在某一个产品上跟我们合作。&lt;/p&gt;
&lt;p&gt;第三点就是完整的产品，如果你需要一个完整的Service Mesh的产品，把这些所有的功能都包括进来，没问题，Sofa Mesh可以拿来用。&lt;/p&gt;
&lt;p&gt;有些同学可能会需要更完整的解决方案，我们的金融云会提供Sofa Mesh的支持，这是我们的目标。你可以将你的系统，架构在金融云之上。&lt;/p&gt;
&lt;p&gt;今天的几位讲师来自不同的公司，我们非常欢迎业界参与。如果大家有意在Service Mesh领域做一些事情，大家可以相互之间做技术的沟通，技术的交流，在社区合作上做一些事情。&lt;/p&gt;
&lt;p&gt;有些同学说，我只是用一下，好像没法做什么贡献。其实，&amp;ldquo;用&amp;quot;是一个很重要的合作，你能够用，你就会遇到问题，有你的诉求，遇到什么样的bug，有什么样需求没有满足。这些对我们来说，是非常重要的输入。在这一点上，欢迎和我们保持合作。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-32_hu51c8805856738fe626f1202d52a6ef2e_68163_fa414cf2b872510929d152d4622326ae.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-32_hu51c8805856738fe626f1202d52a6ef2e_68163_be182e350aa597eba7af63e1a450fc42.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-32_hu51c8805856738fe626f1202d52a6ef2e_68163_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-32_hu51c8805856738fe626f1202d52a6ef2e_68163_fa414cf2b872510929d152d4622326ae.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Sofa Mesh的开源宣言，写的比较狗血。但是在这一点上，我觉得这一次Sofa Mesh在开源上还是做的比较有诚意。&lt;/p&gt;
&lt;p&gt;首先我们认可这个大方向，我们看好Service Mesh的前景。体现在什么上呢？我们现在规划，未来整个蚂蚁金服内部的大部分应用都会逐渐的往Service Mesh上落。这个内部已经达成一致了，会往这个方向走。&lt;/p&gt;
&lt;p&gt;第二是说，&amp;ldquo;勇敢探索&amp;rdquo;，&amp;ldquo;耐心填坑&amp;rdquo;，有在1.0版本之前用过大型开源产品的同学，对这两个词都应该有深刻体验，对吧？包括前两年用0.*版本和1.1/1.2版本的k8s的同学。任何一个新的技术，一个大的方案出来，前期的时候，这些事情是一定会遇到的。但是我们觉得还是要去趟这个事情。&lt;/p&gt;
&lt;p&gt;我们要继续推进这样一个技术进步，包括Service Mesh技术社区的推广。大家如果有注意的话说，Service Mesh技术社区已经重新启动了，我们在跟很多的公司，包括甚至我们一些竞争对手合作。从技术进步的角度说，我们欢迎大家在一个公平的基础上做技术交流。&lt;/p&gt;
&lt;p&gt;然后我们是愿意做分享的，整个产品，我们接下来所有能开源的东西都会开源出来。除了一些内部定制化的东西，内部没有开源的产品的集成。基本上，你们能看到的东西，也就是我们内部用的东西。&lt;/p&gt;
&lt;p&gt;我们寻求和大家的合作，包括刚才讲过的各个层面的合作，哪怕是简单的使用，发现问题给我们提交一些bug，也是非常好的合作契机。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-33_hu60c9509fbe237d6767e89a66990ee06d_70340_0d3024e4ee74537fa2de4561608bd38b.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-33_hu60c9509fbe237d6767e89a66990ee06d_70340_fe39422d648afa46a4edeb2f51095883.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-33_hu60c9509fbe237d6767e89a66990ee06d_70340_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-33_hu60c9509fbe237d6767e89a66990ee06d_70340_0d3024e4ee74537fa2de4561608bd38b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里我喊一个口号，这个口号有点大，&amp;ldquo;集结中国力量，共建开源精品&amp;rdquo;。这里面有个词，比较大一点，我也斟酌了一下，中国这两个字敢不敢用。最后我觉得还是用吧，至少到目前为止，Service Mesh这个技术领域，在全世界目前都还没有成熟的场景落地的情况下，我们目前在这方面的探索，已经是走在最前面的了。&lt;/p&gt;
&lt;p&gt;在这一点上，我们是希望能联合国内在这个领域做探索的同学，我们一起来做这个事情。我们开源的一个重要目的，是说不管大家在商业上有什么样的竞争，至少在技术领域上，包括刚才说的可以在类库层面，产品层面，或者社区合作方面，开展合作。我们希望能够尽可能的联合国内的合作伙伴，包括竞争对手一起来营造整个技术氛围，把整个Service Mesh技术体系的基本水准提升上来。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-34_hu5298bf0b5b6fb7070c2cff2f08b1e91a_28686_f13d1a3a1a14b3e19340c181407985a9.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-34_hu5298bf0b5b6fb7070c2cff2f08b1e91a_28686_7feaa6db6d791d6c1ad56358b11ad485.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-34_hu5298bf0b5b6fb7070c2cff2f08b1e91a_28686_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-34_hu5298bf0b5b6fb7070c2cff2f08b1e91a_28686_f13d1a3a1a14b3e19340c181407985a9.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这一点应该是大家比较关注的，什么时候开源? 我们只能告诉大家说，on the way，正在路上。&lt;/p&gt;
&lt;p&gt;本来这一页的写法应该是贴个地址给大家的，但是因为进度的原因还没有实现，有可能会在一到两个星期之后，在7月份的时候开源给大家。&lt;/p&gt;
&lt;p&gt;需要澄清的一点，大家的期望值不要太高，因为我们开源出来的第一个版本，主要是释放姿态，把我们的开源共建的姿态释放出来。我们的第一个版本，肯定不是一个完善的版本。（备注：现场有同学问，有在用吗？）内部有用一部分，Sidecar内部已经在用了，但是第二部分的内容，比如说XDS API的集成，我们现在正在做。我们不希望等把产品做完善了，比如说两年之后非常成熟的情况下再来开源。我们希望尽可能早的开源。&lt;/p&gt;
&lt;p&gt;（备注：现场提问，7月份的版本，不一定是生产环境可用？）对，是的。有一部分功能是生产可用的，有一部分功能不是，因为我们是迭代上去的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-35_hue8151775305e17661c5e3402ae3f782d_74258_2a605c36c514b37555eebee215306119.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-35_hue8151775305e17661c5e3402ae3f782d_74258_44f762ec26ec52c1751d21ad5f317fc0.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-35_hue8151775305e17661c5e3402ae3f782d_74258_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-35_hue8151775305e17661c5e3402ae3f782d_74258_2a605c36c514b37555eebee215306119.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是我们刚刚开通的Service Mesh技术社区的官方网站。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-36_hu9e9b339a552f645b13863fed8cf39fe9_78464_093c759df88a8265bb0279f6e743eb08.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-36_hu9e9b339a552f645b13863fed8cf39fe9_78464_cf07a53a85c206d7af60570c27f028c6.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-36_hu9e9b339a552f645b13863fed8cf39fe9_78464_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-36_hu9e9b339a552f645b13863fed8cf39fe9_78464_093c759df88a8265bb0279f6e743eb08.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这个是我们的微信公众号和微信交流群，欢迎关注，欢迎交流。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201806-service-mesh-explore/images/ppt-37_hu51661e0f756b9d3138ea612a8422b121_18140_69c66257a746339c6ec514c06426c1fa.webp 400w,
               /talk/201806-service-mesh-explore/images/ppt-37_hu51661e0f756b9d3138ea612a8422b121_18140_ee4973f4d8b56e1890fa2a161c5e8f95.webp 760w,
               /talk/201806-service-mesh-explore/images/ppt-37_hu51661e0f756b9d3138ea612a8422b121_18140_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201806-service-mesh-explore/images/ppt-37_hu51661e0f756b9d3138ea612a8422b121_18140_69c66257a746339c6ec514c06426c1fa.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;谢谢大家！&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Istio Mixer Cache工作原理与源码分析(4)－签名</title>
      <link>https://skyao.net/post/201806-istio-mixer-cache-signature/</link>
      <pubDate>Fri, 08 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201806-istio-mixer-cache-signature/</guid>
      <description>&lt;p&gt;接前文，继续分析Mixer Check Cache的源码，这次的重点是签名算法，也就是Referenced::Signature()方法。&lt;/p&gt;
&lt;p&gt;前情回顾：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Referenced保存的是mixer adapter使用的引用属性的一个组合，也就是前面例子中的 &lt;code&gt;“a,b,c”或者“a,b,c不存在”&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Referenced中有两个数据结构： &lt;code&gt;std::vector&amp;lt;AttributeRef&amp;gt; absence_keys_&lt;/code&gt; 和 &lt;code&gt;std::vector&amp;lt;AttributeRef&amp;gt; exact_keys_&lt;/code&gt;，exact_keys_保存的是一定要出现的属性， absence_keys_中保存的是没有出现的属性&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;基本流程&#34;&gt;基本流程&lt;/h2&gt;
&lt;p&gt;我们来看详细源代码，具体在文件&lt;code&gt;src/istio/mixerclient/referenced.cc&lt;/code&gt;中，代码的基本流程非常清晰：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Referenced&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Signature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Attributes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                           &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extra_key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                           &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;signature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// 第一步，先检查输入是否匹配保存的引用属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 必须同时满足absent key和exact key的要求
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CheckAbsentKeys&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CheckExactKeys&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// 发现匹配之后，才开始计算签名
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;CalculateSignature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;extra_key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;signature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;切记：请更新到 &lt;code&gt;istio/proxy&lt;/code&gt; 仓库的最新代码，在master分支上才能看到这个版本。&lt;/p&gt;
&lt;p&gt;这里的代码在此之前是存在性能问题的，我为此提交了一个改进方案，由于0.8版本发布前锁了master分支，因此这个fix的代码是在0.8版本发布之后才进的master分支。&lt;/p&gt;
&lt;p&gt;详情请见：https://github.com/istio/proxy/issues/1531&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;引用属性匹配&#34;&gt;引用属性匹配&lt;/h2&gt;
&lt;p&gt;先检查absent key，这里要求请求中的属性，不能出现 absence_keys_ 保存的属性，否则就是不匹配：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Referenced&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CheckAbsentKeys&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Attributes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes_map&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;absence_keys_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 检查每个absence_key
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;absence_keys_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes_map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes_map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;c1&#34;&gt;// 如果在输入的属性中没有找到，就继续下一个
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 如果找到了，则直接返回不匹配
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 实际代码中还有特别的 StringMap 类型的属性需要额外处理，简单起见我们忽略它
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// 只有absence_key都没有在输入的属性中出现，才表示匹配
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;再检查exact keys，这里要求exact keys中保存的每一个属性，必须在请求中出现，否则就是不匹配：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;bool&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Referenced&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CheckExactKeys&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Attributes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes_map&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;exact_keys_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 检查每个exact_key
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;exact_keys_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes_map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 如果没有在请求中出现就返回不匹配
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes_map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;// 实际代码中还有特别的 StringMap 类型的属性需要额外处理，简单起见我们忽略它
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// 只有exact_key都在输入的属性中出现，才表示匹配
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;简单说，引用属性匹配的要求就是：exact key都必须出现，absence key都不能出现。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;输入&lt;/th&gt;
&lt;th&gt;exact=&amp;ldquo;a,b,c&amp;rdquo;,absent=&amp;quot;&amp;quot;&lt;/th&gt;
&lt;th&gt;exact=&amp;ldquo;a,b&amp;rdquo;,absent=&amp;ldquo;c&amp;rdquo;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;ldquo;a=1,b=2,c=3,e=4,f=5&amp;rdquo;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;ldquo;a=1,b=2,e=4,f=5&amp;rdquo;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;计算签名&#34;&gt;计算签名&lt;/h2&gt;
&lt;p&gt;在exact key和absent key检查通过之后，就意味着请求中的属性满足当前Referenced的匹配要求。&lt;/p&gt;
&lt;p&gt;下一步就可以进行签名计算了，CalculateSignature()方法的参数中attributes是输入的所有属性，extra_key这个参数目前没有使用，忽略即可：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Referenced&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CalculateSignature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Attributes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extra_key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                    &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;signature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes_map&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;utils&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;MD5&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hasher&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// 游历exact_keys_ 中的每个属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;i&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;exact_keys_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;exact_keys_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;i&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 在输入的属性中通过属性名找到包含值的属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes_map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;hasher&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;it&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;first&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;hasher&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kDelimiter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kDelimiterLength&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 根据属性值的不同类型，调用hasher.Update()方法进行计算
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Attributes_AttributeValue&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;second&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value_case&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Attributes_AttributeValue&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;kStringValue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;hasher&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string_value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;......&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// 忽略其他类型的处理代码
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;      &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Attributes_AttributeValue&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;VALUE_NOT_SET&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;hasher&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;kDelimiter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;kDelimiterLength&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;hasher&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;extra_key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// 完成签名计算的最后一步，得到签名
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;signature&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hasher&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Digest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;即CalculateSignature()方法会将exact_keys_ 指定的请求属性进行签名，注意只对 exact_keys_ 的属性进行签名，absent key反正没有出现自然无需也无法对它们进行计算。&lt;/p&gt;
&lt;p&gt;形象起见，以我们前面介绍基础概念和工作原理时的例子做讲解，假设 referenced_map 保存的引用属性组合为 &lt;code&gt;{“k1”: “a,b,c”, “k2”: “a,b,c不存在” }&lt;/code&gt; ，&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;请求&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;&amp;ldquo;a=1,b=2,c=3,e=4,f=5&amp;rdquo;&lt;/td&gt;
&lt;td&gt;exact=&amp;ldquo;a,b,c&amp;rdquo;, absent=&amp;quot;&amp;quot;&lt;/td&gt;
&lt;td&gt;a=1,b=2,c=3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;ldquo;a=1,b=2,e=4,f=5&amp;rdquo;&lt;/td&gt;
&lt;td&gt;exact=&amp;ldquo;a,b&amp;rdquo;, absent=&amp;ldquo;c&amp;rdquo;&lt;/td&gt;
&lt;td&gt;a=1,b=2&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;签名算法的关键在于需要先匹配exact key和absent key，然后再计算。和主流程代码一样，只要理解了引用属性和absent key的概念，就容易理解了。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Istio Mixer Cache工作原理与源码分析(3)－主流程</title>
      <link>https://skyao.net/post/201806-istio-mixer-cache-main/</link>
      <pubDate>Thu, 07 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201806-istio-mixer-cache-main/</guid>
      <description>&lt;p&gt;经过前面基本概念和实现原理的介绍，大家对mixer check cache应该有了基本的了解，下面我们开始展开源代码来细细研读。&lt;/p&gt;
&lt;h2 id=&#34;check-cache的主要流程&#34;&gt;Check Cache的主要流程&lt;/h2&gt;
&lt;h3 id=&#34;check-cache的调用入口&#34;&gt;Check Cache的调用入口&lt;/h3&gt;
&lt;p&gt;对mixer cache的调用在代码 &lt;code&gt;proxy/src/istio/mixerclient/client_impl.cc&lt;/code&gt; 中的方法Check()中，此处跳过quota cache的内容：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nx&#34;&gt;CancelFunc&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;MixerClientImpl&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Check&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Attributes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;vector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;istio&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;quota_config&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Requirement&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;quotas&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;TransportCheckFunc&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;transport&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;CheckDoneFunc&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;on_done&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;o&#34;&gt;++&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;total_check_calls_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;unique_ptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;CheckCache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;CheckResult&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;check_result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;CheckCache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;CheckResult&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 在这里调用了CheckCache.Check()方法，进行检查
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;nx&#34;&gt;check_cache_&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;Check&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;check_result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;CheckResponseInfo&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;check_response_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;check_response_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;is_check_cache_hit&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;check_result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;IsCacheHit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;check_response_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;response_status&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;check_result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 如果check cache命中，并且结果不OK，则直接结束处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;check_result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;IsCacheHit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;check_result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;ok&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;on_done&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;check_response_info&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;nullptr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nx&#34;&gt;CheckCache&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;CheckResult&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;raw_check_result&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;check_result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;release&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 如果check cache没有命中，则需要发起请求到mixer得到response
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 然后将response加入check cache中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;transport&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;nx&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;request_copy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;raw_check_result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;raw_quota_result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       &lt;span class=&#34;nx&#34;&gt;on_done&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;](&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nx&#34;&gt;raw_check_result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;SetResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;request_copy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;o&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;});&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们先来看看缓存的保存方式，再返回来看Check()方法的具体实现，这样方便理解。&lt;/p&gt;
&lt;p&gt;这里的transport是一个TransportCheckFunc，具体定义在&lt;code&gt;include/istio/mixerclient/environment.h&lt;/code&gt; 头文件中：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Defines a function prototype to make an asynchronous Check call
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;TransportCheckFunc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CancelFunc&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;istio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mixer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CheckRequest&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;istio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mixer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CheckResponse&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;DoneFunc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;on_done&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中DoneFunc的定义如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Defines a function prototype used when an asynchronous transport call
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// is completed.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// Uses UNAVAILABLE status code to indicate network failure.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;DoneFunc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;google&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;protobuf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;util&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Status&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;总结说，Check()方法会通过TransportCheckFunc对mixer发起请求，在得到response之后，再调用DoneFunc。&lt;/p&gt;
&lt;p&gt;在这个匿名的DoneFunc中，最关键的代码是：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;raw_check_result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SetResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request_copy&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里的 raw_check_result 类型是 CheckCache::CheckResult。&lt;/p&gt;
&lt;h2 id=&#34;保存check结果&#34;&gt;保存Check结果&lt;/h2&gt;
&lt;p&gt;CheckResult.SetResponse()方法的源代码在 istio/proxy 项目， &lt;code&gt;src/istio/mixerclient/check_cache.h&lt;/code&gt; 文件中&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;SetResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;google&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;protobuf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;util&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Status&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;istio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mixer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Attributes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                 &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;istio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mixer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CheckResponse&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;on_response_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 调用on_response_这个Func
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;status_&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;on_response_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// The function to set check response.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;OnResponseFunc&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;function&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;google&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;protobuf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;util&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;google&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;protobuf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;util&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Status&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;istio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mixer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Attributes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;istio&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;mixer&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;v1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CheckResponse&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;OnResponseFunc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;on_response_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// on_response_在此定义
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;on_response_这个OnResponseFunc的设定在 &lt;code&gt;src/istio/mixerclient/check_cache.cc&lt;/code&gt; 文件中的 CheckCache::Check() 方法中设置：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;result&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;on_response_&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;](&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Status&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Attributes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                              &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CheckResponse&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Status&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ok&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// status表示对mixer的远程调用的结果
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// 如果调用都没有成功，则没有check结果可言，自然不必缓存
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;options_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;network_fail_open&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;c1&#34;&gt;// 注意这里有个选项，如果打开，则在mixer调用没有成功时视为check成功
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;            &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Status&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;OK&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;            &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 如果对mixer调用成功，拿到了response，则进行缓存
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;CacheResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;system_clock&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;下面是保存缓存的关键代码了，CacheResponse() 方法，清晰起见，忽略分支处理和错误处理代码，日志打印等：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Status&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CheckCache&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CacheResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Attributes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                                 &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CheckResponse&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Tick&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;time_now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// 类Referenced用来保存引用属性，也就是哪些属性被mixer adapter使用了
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 记得前面讲述实现原理时的例子吗？这里的Referenced就是&amp;#34;a,b,c&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;Referenced&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;referenced&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// Fill()方法解析response的precondition的referenced_attributes并填充到referenced
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;referenced&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Fill&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;                       &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;precondition&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;().&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;referenced_attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;signature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// 调用Signature()方法进行签名
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;referenced&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Signature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;signature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;p&#34;&gt;......&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// 进行第一层缓存的保存
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// referenced_map用于保存各种引用属性的组合
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 在实现原理中的例子，就是&amp;#34;a,b,c&amp;#34;和带absence key的&amp;#34;a,b&amp;#34;,&amp;#34;a,c&amp;#34;等
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hash&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;referenced&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Hash&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// 计算当前引用属性的hash值，比如&amp;#34;a,b,c&amp;#34;的hash值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 然后保存进referenced_map
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;referenced_map_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hash&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;referenced_map_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;end&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;referenced_map_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;hash&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;referenced&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// 进行第二层缓存的保存
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 用计算而来的签名来在第二层缓存中查找
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;CheckLRUCache&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ScopedLookup&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lookup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cache_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;signature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lookup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Found&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 如果已经存在则更新CacheElem
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;n&#34;&gt;lookup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SetResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;time_now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lookup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// 如果不存在则插入新的CacheElem
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;n&#34;&gt;CacheElem&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cache_elem&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CacheElem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;this&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;response&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;time_now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;cache_&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Insert&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;signature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cache_elem&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cache_elem&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;缓存的结构和保存方式&#34;&gt;缓存的结构和保存方式&lt;/h3&gt;
&lt;p&gt;我们现在可以结合代码来详细的展开缓存的结构和保存方式了：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 第一层缓存，用于保存引用属性
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 这个map中，value是Referenced对象，key是Referenced的hash值
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unordered_map&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Referenced&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;referenced_map_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 第二层缓存，用于保存check的结果
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// 这是一个 LRU Cache，key是请求的签名，value是check的结果，封装为CacheElem
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CheckLRUCache&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;utils&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SimpleLRUCache&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CacheElem&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unique_ptr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CheckLRUCache&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cache_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Referenced 中保存使用的属性，包括absence的属性：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// The keys should be absence.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AttributeRef&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;absence_keys_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// The keys should match exactly.
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;vector&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;AttributeRef&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;exact_keys_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;以前面的例子为例，&amp;ldquo;a,b,c不存在&amp;quot;这种引用属性组合，在保存时就是a/b保存在exact_keys中，而c保存在absence_keys中。&lt;/p&gt;
&lt;p&gt;CacheElem中保存的是检查结果：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;google&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;protobuf&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;util&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Status&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;status_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chrono&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;time_point&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;chrono&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;system_clock&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;expire_time_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;use_count_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中status字段是结果，而expire_time和use_count是这个缓存项的过期时间和使用次数，这个细节后面再展开。&lt;/p&gt;
&lt;p&gt;两层缓存key值的计算，会比较有意思，我们会在下一节中详细展开，这一节我们先关注在缓存的主要流程。我们继续看缓存的check()方法是如何实现的，即怎么匹配请求和缓存。&lt;/p&gt;
&lt;h2 id=&#34;匹配请求和缓存&#34;&gt;匹配请求和缓存&lt;/h2&gt;
&lt;p&gt;每一个请求，都要和 mixer check cache 匹配一下，看是否可以命中缓存从而避免对mixer的远程调用。有了前面的铺垫，再来看缓存是如何匹配就简单了：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;check_cache_&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Check&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;check_result&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;源代码在 &lt;code&gt;src/istio/mixerclient/check_cache.cc&lt;/code&gt; 中，去除错误处理和细节处理代码之外，主要代码为：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;Status&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CheckCache&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Check&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Attributes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Tick&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;time_now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 游历第一层缓存,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// referenced_map中保存的是所有保存的引用属性组合中
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 在我们前面的例子中，这里保存有 {“k1”: “a,b,c”, “k2”: “a,b,c不存在” } 等
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;auto&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;nl&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;referenced_map_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Referenced&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;reference&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;second&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;signature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 在所有保存的引用属性组合中，逐个匹配看请求是否具备保存的引用属性结合
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// 如果引用属性和请求中的属性匹配，则计算签名
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;reference&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Signature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;signature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;c1&#34;&gt;// 进行第二层缓存的查找
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;c1&#34;&gt;// 第二层缓存的key是签名，因此简单通过key查找就OK
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;        &lt;span class=&#34;n&#34;&gt;CheckLRUCache&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ScopedLookup&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lookup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;cache_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;get&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(),&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;signature&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;lookup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Found&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;n&#34;&gt;CacheElem&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;elem&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;lookup&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;elem&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;c1&#34;&gt;// 如果游历完第一层缓存，也没能找到匹配的引用属性,则只能返回NOT_FOUND
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;Status&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Code&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;NOT_FOUND&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;注意在Signature()方法中实际做了两个事情：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在referenced_map查找看是否有匹配的引用属性组合&lt;/li&gt;
&lt;li&gt;如果有，则计算签名，以便通过签名来进行第二层缓存的查找&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这个Signature()方法的实现是整个mixer check cache的重中之重，核心所在。&lt;/p&gt;
&lt;p&gt;篇幅原因，我们将在下一节中详细展开Signature()方法实现的源代码解析。&lt;/p&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;Mixer Check Cache的主流程代码，在了解了基本概念和工作原理之后，理解起来并不困难。代码本身并没有特别费解的地方，麻烦之处在于对 Referenced Attribute / 引用属性这个概念的理解。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Istio Mixer Cache工作原理与源码分析(2)－工作原理</title>
      <link>https://skyao.net/post/201806-istio-mixer-cache-principle/</link>
      <pubDate>Tue, 05 Jun 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201806-istio-mixer-cache-principle/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;经过前面的基础概念的介绍，我们现在已经可以勾勒出一个mixer cache的实现轮廓，当然实际代码实现时会有很多细节。但是为了方便理解，我们在深入细节之前，先给出一个简化版本，让大家快速了解mixer cache的实现原理。后面的章节我们再逐渐深入。&lt;/p&gt;
&lt;p&gt;Mixer Cache分为两个部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;check cache&lt;/li&gt;
&lt;li&gt;quota cache&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;简单起见，我们先关注check cache，在check cache讲述清楚之后，我们再继续看quota cache。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：istio一直在持续更新，以下代码来源于istio 0.8版本。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;mixer-check-cache的构造&#34;&gt;Mixer Check Cache的构造&lt;/h2&gt;
&lt;p&gt;Mixer Cache在实现时，在envoy的内存中，保存有两个数据结构：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c++&#34; data-lang=&#34;c++&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;CheckCache&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unordered_map&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Referenced&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;referenced_map_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;using&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CheckLRUCache&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;utils&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;SimpleLRUCache&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;CacheElem&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;std&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;unique_ptr&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CheckLRUCache&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;cache_&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;blockquote&gt;
&lt;p&gt;具体代码: 见istio/proxy项目，文件&lt;code&gt;src/istio/mixerclient/check_cache.h&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;referenced_map：保存的是引用属性&lt;/li&gt;
&lt;li&gt;cache：保存的是check的结果&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这里和一般缓存不一样，有两个map，也就是存在两套key/value两层缓存，为什么要这样设计？&lt;/p&gt;
&lt;h2 id=&#34;mixer-check-cache的核心设计&#34;&gt;Mixer Check Cache的核心设计&lt;/h2&gt;
&lt;p&gt;缓存在设计上，最核心的内容就是如何设计缓存的key，这个问题在mixer check cache中尤其突出。&lt;/p&gt;
&lt;h3 id=&#34;为什么要有两层map&#34;&gt;为什么要有两层Map？&lt;/h3&gt;
&lt;p&gt;我们继续以这个最基本的场景为例：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;../201804-istio-mixer-cache-concepts/images/referenced-attributes.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;注意这个场景下属性的使用情况是这样的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;envoy提交的请求中有5个属性，”a=1,b=2,c=3,e=0,f=0”&lt;/li&gt;
&lt;li&gt;mixer中有三个adapter，每个adapter只使用提交属性中的一个属性a/b/c&lt;/li&gt;
&lt;li&gt;在CheckResponse中返回referencedAttributes字段的内容为”a,b,c”&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;要怎么设计这个Mixer check cache？先分析缓存的逻辑语义：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;返回的referencedAttributes字段的内容为”a,b,c”，说明这三个属性被使用&lt;/li&gt;
&lt;li&gt;结合输入的”a=1,b=2,c=3,e=0,f=0”，就可以得知&amp;quot;a=1,b=2,c=3&amp;quot;这个属性和属性的值的组合，代表一个输入，结果是固定而可以缓存的&lt;/li&gt;
&lt;li&gt;如果下一个请求，同样提供”a,b,c”三个属性，并且三个属性的值是&amp;quot;a=1,b=2,c=3&amp;quot;，则可以直接使用这个缓存的结果&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;注意：由于哪些属性可能会被使用是取决于运行时实际部署的adapter，因此mixer check cache的key计算时是无法直接指定要计算哪些属性的，也就无法简单的对输入属性做简单计算得到key。这是mixer cache和一般场景下的缓存的关键差异。&lt;/p&gt;
&lt;p&gt;mixer check cache在工作时，如果要命中缓存，就必须带有两层匹配逻辑：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;请求中是否携带有匹配的属性，在上面的例子中，就是要有”a,b,c”三个属性&lt;/li&gt;
&lt;li&gt;这些属性是否具备匹配的值，在上面的例子中，就是要”a=1,b=2,c=3”&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在具体实现上：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;referenced_map 是第一层缓存，用来保存引用属性的组合，注意只有属性名，这里不保存属性值&lt;/li&gt;
&lt;li&gt;cache 是第二层缓存，用来保存输入的签名（根据引用属性的值计算而来）/value （check的检查结果）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;两层cache是如何工作的&#34;&gt;两层cache是如何工作的？&lt;/h3&gt;
&lt;p&gt;为了避免陷入代码细节，我们先不看代码具体实现（这是下一章的内容），先只看工作原理：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;referenced_map 用来保存哪些属性组合已经被缓存，比如 &lt;code&gt;{&amp;quot;k1&amp;quot;: &amp;quot;a,b,c&amp;quot;}&lt;/code&gt; 这样表示当前只有一个属性组合&amp;quot;a,b,c&amp;quot;被保存，为了简单我们先忽略key的计算方式。&lt;/li&gt;
&lt;li&gt;cache用来保存输入的签名(简单理解为有效输入内容”a=1,b=2,c=3”的hash结果)和check 结果（简化为true/false表示是否通过），比如 &lt;code&gt;{ &amp;quot;a=1,b=2,c=3&amp;quot;: &amp;quot;true&amp;quot; }&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们来看各种场景下的请求和缓存的匹配请求，先看最理想的缓存命中的场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;请求为：”a=1,b=2,c=3,e=0,f=0”&lt;/p&gt;
&lt;p&gt;这个请求和被缓存的请求是一模一样的，我们期待可以命中缓存。&lt;/p&gt;
&lt;p&gt;匹配时，先进行第一层匹配：输入的”a=1,b=2,c=3,e=0,f=0”和 referenced_map {&amp;ldquo;k1&amp;rdquo;: &amp;ldquo;a,b,c&amp;rdquo;} 进行检查，发现输入的”a=1,b=2,c=3,e=0,f=0”可以和保存的&amp;quot;a,b,c&amp;quot;属性组合匹配。&lt;/p&gt;
&lt;p&gt;然后继续，第二层缓存就可以简单通过key来匹配了。注意在对输入进行签名时，只需要计算引用属性的hash值，即只需要计算&amp;quot;a=1,b=2,c=3&amp;quot;，再通过这个签名在cache中找到缓存结果。&lt;/p&gt;
&lt;p&gt;这便是标准的mixer check cache的匹配姿势。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;请求为：”a=1,b=2,c=3,e=1,f=2”&lt;/p&gt;
&lt;p&gt;差异在于e/f属性的值有所不同，考虑到e/f两个属性没有adapter使用，和”a=1,b=2,c=3,e=0,f=0”等效，我们期待可以命中缓存。&lt;/p&gt;
&lt;p&gt;第一层匹配，输入的”a=1,b=2,c=3,e=1,f=2”和{&amp;ldquo;k1&amp;rdquo;: &amp;ldquo;a,b,c&amp;rdquo;} 命中，由于属性组合是&amp;quot;a,b,c&amp;quot;，因此计算签名时还是计算&amp;quot;a=1,b=2,c=3&amp;quot;，因此可以命中第二层缓存。&lt;/p&gt;
&lt;p&gt;通过这种在签名时忽略未被adapter使用的属性的方式，mixer check cache 做到了只检查被adapter使用的属性，而其他属性的值不会影响。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们再来看缓存不命中的典型场景，此时会多一个保存新结果到缓存的过程：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;新请求：”a=1,b=2,c=10,e=0,f=0”&lt;/p&gt;
&lt;p&gt;不同在于c的取值有变化，这是一个新的有效输入，和已经缓存的&amp;quot;a=1,b=2,c=3&amp;quot;不同，应该无法命中。&lt;/p&gt;
&lt;p&gt;匹配时，第一层匹配命中，计算签名时计算的输入是&amp;quot;a=1,b=2,c=10&amp;quot;，得到的签名结果自然和缓存的&amp;quot;a=1,b=2,c=3&amp;quot;的签名不同，因此第二层缓存没有命中。&lt;/p&gt;
&lt;p&gt;这是典型的属性组合匹配但是属性具体值不匹配的场景，我们看mixer check cache的后续处理。&lt;/p&gt;
&lt;p&gt;缓存不命中，就需要向mixer发起远程，得到应答，应答中给出adapter使用的属性情况，此时依然是&amp;quot;a,b,c&amp;quot;，和检查的结果，我们假定这次是false。即此时我们得到了一个新的输入和结果的对应关系，我们将这个结果保存起来：referenced_map 中现有的值是 {&amp;ldquo;k1&amp;rdquo;: &amp;ldquo;a,b,c&amp;rdquo;}，无需改变。cache 从 { &amp;ldquo;a=1,b=2,c=3&amp;rdquo;: &amp;ldquo;true&amp;rdquo; } 增加新结果，变为  { &amp;ldquo;a=1,b=2,c=3&amp;rdquo;: &amp;ldquo;true&amp;rdquo;, &amp;ldquo;a=1,b=2,c=10&amp;rdquo;: &amp;ldquo;false&amp;rdquo;}&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;继续发送请求：”a=1,b=2,c=10,e=0,f=0”/”a=1,b=2,c=3,e=0,f=0”&lt;/p&gt;
&lt;p&gt;如果继续有这样的请求进来，则继续命中。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;新请求：”a=1,b=20,c=10,e=0,f=0”&lt;/p&gt;
&lt;p&gt;如果属性a/b/c的值继续变化，则继续重复前面的不命中后更新缓存的步骤。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;absence-key&#34;&gt;absence key&lt;/h3&gt;
&lt;p&gt;通过上面稍显枯燥的描述，我想大家基本可以了解 mixer check cache 的工作原理，但是注意这个是经过简化的最简单版本，我们现在来加上 &lt;code&gt;absence key&lt;/code&gt; 这个极其重要的概念。&lt;/p&gt;
&lt;p&gt;什么叫做 absence key ？我们需要继续看回这个图片，注意mixer adapter使用的属性是a/b/c三个：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;../201804-istio-mixer-cache-concepts/images/referenced-attributes.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;前面我们列出来的所有场景中，每个输入中都包含有a/b/c三个属性，考虑到其他不使用的属性在匹配过程中会被忽略而不影响，我们来将关注点放在a/b/c三个属性上。需要考虑这种可能：如果a/b/c三个属性不是每次都同时提供，而是少一个或者多个，结果会怎么样？&lt;/p&gt;
&lt;p&gt;此时两层缓存的数据为：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;referenced_map = {&amp;ldquo;k1&amp;rdquo;: &amp;ldquo;a,b,c&amp;rdquo;}&lt;/li&gt;
&lt;li&gt;cache = { &amp;ldquo;a=1,b=2,c=3&amp;rdquo;: &amp;ldquo;true&amp;rdquo;, &amp;ldquo;a=1,b=2,c=10&amp;rdquo;: &amp;ldquo;false&amp;rdquo;}&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果我们有一个输入 ”a=1,b=2,c不存在,e=0,f=0” ，注意在这个输入中 c没有出现的。此时肯定缓存无法匹配，需要发送请求到mixer，我们再假设mixer adapter的处理逻辑在输入为&amp;quot;a=1,b=2,c不存在&amp;quot;的结果为&amp;quot;false&amp;quot;(这样可以和输入为&amp;quot;a=1,b=2,c=3&amp;quot;的结果&amp;quot;true&amp;quot;区分开)。&lt;/p&gt;
&lt;p&gt;设计上有个问题：mixer该怎么返回引用属性来让mixer check cache可以正确的保存这个结果并用于后续的请求？&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;输入&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;”a=1,b=2,c=3,e=0,f=0”&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;td&gt;&amp;ldquo;a,b,c&amp;rdquo;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;”a=1,b=2,c不存在,e=0,f=0”&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;td&gt;&amp;ldquo;a,b&amp;quot;还是&amp;quot;a,b,c&amp;rdquo;？&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;关键点：当输入中c不存在时，mixer的response中 referenced attribute 应该返回 &amp;ldquo;a,b&amp;rdquo; 还是 &amp;ldquo;a,b,c&amp;rdquo;？&lt;/p&gt;
&lt;p&gt;先回顾一下 referenced attribute 的概念：按照我们之前介绍的逻辑，referenced attribute 返回的是 mixer adapter 使用到的属性。换句话说，这些属性之外的其他属性，是不会影响mixer adapter处理结果的，因此在缓存保存和匹配时都可以忽略。&lt;/p&gt;
&lt;p&gt;首先来看，如果返回 &amp;ldquo;a,b&amp;rdquo; 会如何？这表示 c/e/f 属性可以被忽略，也就是不管c取值如何，是否出现，都不影响check的结果。即如果”a=1,b=2,c不存在,e=0,f=0”的结果为false，按照引用属性为&amp;quot;a,b&amp;quot;进行缓存，后面的”a=1,b=2,c=3,e=0,f=0”的请求，会被忽略c属性而命中”a=1,b=2&amp;quot;的缓存结果，导致返回false。&lt;/p&gt;
&lt;p&gt;因此 mixer check cache 在设计中，引入了 &lt;code&gt;absence key&lt;/code&gt; 的概念，mixer 的reponse里面，会明确指出：在输入为”a=1,b=2,c不存在,e=0,f=0”，输出为false这个场景下，referenced attribute 不仅仅包括出现在输入中的 a/b 两个属性，还有 c 这个虽然在输入中没有出现但是 mixer adapter 实际也使用了的属性的（属性c没有出现可以视为属性c的一个特别值）。这个没出现的属性c 被称为 &lt;code&gt;absence key&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;此时mixer check cache 在做缓存时，要处理 &amp;ldquo;a/b/c不存在&amp;rdquo; 这种特别的属性组合，具体步骤为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;第一层缓存 referenced_map = {&amp;ldquo;k1&amp;rdquo;: &amp;ldquo;a,b,c&amp;rdquo;} 和输入”a=1,b=2,c不存在,e=0,f=0” 因为c的缺席而无法匹配&lt;/li&gt;
&lt;li&gt;发起对mixer的请求，获取新的应答，结果为false，引用属性为&amp;quot;a,b&amp;quot;和absence key c，我们简写为&amp;quot;a,b,c不存在&amp;quot;。&lt;/li&gt;
&lt;li&gt;保存结果到第一层缓存 referenced_map 更新为 {&amp;ldquo;k1&amp;rdquo;: &amp;ldquo;a,b,c&amp;rdquo;, &amp;ldquo;k2&amp;rdquo;: &amp;ldquo;a,b,c不存在&amp;rdquo; }&lt;/li&gt;
&lt;li&gt;保存结果到第二层缓存 cache 更新为 &amp;ldquo;a=1,b=2,c=3&amp;rdquo;: &amp;ldquo;true&amp;rdquo;, &amp;ldquo;a=1,b=2,c=10&amp;rdquo;: &amp;ldquo;false&amp;rdquo;, &amp;ldquo;a=1,b=2&amp;rdquo;: &amp;ldquo;false&amp;rdquo;}&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;之后的请求匹配缓存的过程，会稍有不同，体现在第一层缓存的匹配上，注意此时有两个属性组合 {&amp;ldquo;k1&amp;rdquo;: &amp;ldquo;a,b,c&amp;rdquo;, &amp;ldquo;k2&amp;rdquo;: &amp;ldquo;a,b,c不存在&amp;rdquo; }：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果是 ”a=1,b=2,c=3,e=0,f=0” 这种a/b/c三个属性都提供的输入，则会匹配到 &amp;ldquo;k1&amp;rdquo;: &amp;ldquo;a,b,c&amp;rdquo;&lt;/li&gt;
&lt;li&gt;如果是 ”a=1,b=2,c不存在,e=0,f=0” 这种提供了a/b属性而c没有提供的输入，则会匹配到 &amp;ldquo;k2&amp;rdquo;: &amp;ldquo;a,b,c不存在&amp;rdquo;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;第二层缓存的匹配方式没有变化，注意由于属性c不存在，因此在计算”a=1,b=2,c不存在,e=0,f=0”这个输入的签名时，只需要计算”a=1,b=2”。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;需要额外指出的是，当有多个属性被 mixer adapter 使用，而出现某个或者某几个属性不存在的场景，是可能有多种的，以上面&amp;quot;a,b,c&amp;quot;三个属性为例，会有&amp;quot;a,b&amp;quot;/&amp;ldquo;a,c&amp;rdquo;/&amp;ldquo;b,c&amp;rdquo;/&amp;ldquo;a&amp;rdquo;/&amp;ldquo;b&amp;rdquo;/&amp;ldquo;c&amp;rdquo;/&amp;quot;&amp;quot;(即abc都不存在)7种情况，加上&amp;quot;a,b,c&amp;quot;都出现的情况，referenced_map 中会需要保存最多8种属性组合。而且，mixer adapter使用的属性越多，这个数量还会急剧增加。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：这个地方istio有一个bug，在研读代码时发现的，后来提交fix给了istio，后面我会结合代码给大家讲解。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;Mixer check Cache的设计，由于受限于无法得知mixer adaper会使用哪些属性，因此在设计上和普通缓存差异极大，必须明确引用属性和absence key的概念，才能正确理解mixer check cache。&lt;/p&gt;
&lt;p&gt;下一节，我们终于可以展开源码了。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Service Mesh：重塑微服务市场</title>
      <link>https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/</link>
      <pubDate>Sun, 20 May 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/</guid>
      <description>&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-01_hu24b41bb6a4430f59d455e8d07f1beaca_135501_efc5ba0668be683acebf67bd8f99942b.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-01_hu24b41bb6a4430f59d455e8d07f1beaca_135501_ee176d51031ad61d39295a4f486d1adc.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-01_hu24b41bb6a4430f59d455e8d07f1beaca_135501_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-01_hu24b41bb6a4430f59d455e8d07f1beaca_135501_efc5ba0668be683acebf67bd8f99942b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;大家好，我是敖小剑，今天给大家带来的这个主题叫做 “Service Mesh：重塑微服务市场”。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-02_hu24b41bb6a4430f59d455e8d07f1beaca_252130_a2fc1c0751743ca7275535d37a6e99b9.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-02_hu24b41bb6a4430f59d455e8d07f1beaca_252130_00f63d1f3826e970fd766820e2571244.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-02_hu24b41bb6a4430f59d455e8d07f1beaca_252130_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-02_hu24b41bb6a4430f59d455e8d07f1beaca_252130_a2fc1c0751743ca7275535d37a6e99b9.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;刚才主持人张亮提到说，过去一年Service Mesh成为一个热词。基本上，在国内的话，我差不多是Service Mesh最早的布道师。可能如果大家之前有看相关的资料的话，应该会看到一些我的资料。我先后做过几场的演讲，做过一些技术的分享，也写过很多文章。但在此之前，这些内容可能更多的都是集中在技术领域。那今天我们会特殊一点，我们今天不谈详细的技术，不谈具体的架构，我们也不谈具体的产品。后面的这些名词，Istio/Conduit/Envoy/Linkerd/Nginmesh，这些词可能听过，可能没听过，但没问题，今天这些我们统统都不讲。我们今天要讲另外一个东西：我们会聊一聊在未来一两年之内，Service Mesh技术会在微服务相关的市场带来什么样的变化？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-03_hu24b41bb6a4430f59d455e8d07f1beaca_129251_184cb6d2a8b112ea50408eb388f170de.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-03_hu24b41bb6a4430f59d455e8d07f1beaca_129251_39d2e22b1d30e4a8211def57cf8e4899.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-03_hu24b41bb6a4430f59d455e8d07f1beaca_129251_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-03_hu24b41bb6a4430f59d455e8d07f1beaca_129251_184cb6d2a8b112ea50408eb388f170de.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;主要内容会是三大块：首先我们会看一下目前微服务的市场的一些现状，然后接下来我们会探讨一下它的商业模式，在第三块，我们会重点讲一下Service Mesh对PaaS的意义。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-04_hu24b41bb6a4430f59d455e8d07f1beaca_87090_4402712f233312b1bb29811b1a1639cc.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-04_hu24b41bb6a4430f59d455e8d07f1beaca_87090_6803565d0b97fce2b09622e9450ec4a2.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-04_hu24b41bb6a4430f59d455e8d07f1beaca_87090_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-04_hu24b41bb6a4430f59d455e8d07f1beaca_87090_4402712f233312b1bb29811b1a1639cc.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;OK，第一块，微服务的现状。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-05_hu7f1aa2dca4ffc4cbebe1336848081843_229905_978823f1440e228bd572c21ebdfb4bb8.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-05_hu7f1aa2dca4ffc4cbebe1336848081843_229905_c0860e9447926d6f6204e5ca7f5e6be9.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-05_hu7f1aa2dca4ffc4cbebe1336848081843_229905_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-05_hu7f1aa2dca4ffc4cbebe1336848081843_229905_978823f1440e228bd572c21ebdfb4bb8.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们快速过一下。&lt;/p&gt;
&lt;p&gt;目前微服务的背景是这样，首先目前在市场上是有这么一个潮流：传统企业会慢慢向互联网技术转型，其中微服务和容器是这个技术转型的核心。这个市场比较大，大家也都看好这样一个方向，这是大的时代背景。&lt;/p&gt;
&lt;p&gt;简单回顾一下，微服务在国内，基本上是在2015年开始兴起。2016/2017这两年在国内的基本上就是大热了。我们能看到的是，未来这一两年之内，这个热潮应该继续延续。主要还是因为微服务这个技术是用于解决实际问题的，另外它也同样适用于各种企业。这样的大背景之下，我们来看现在使用微服务的客户现状。&lt;/p&gt;
&lt;p&gt;实际上，我们之前在谈到Service Mesh技术为什么演进的时候，我们有提到，在Service Mesh之前，第一代的侵入式微服务框架，它的门槛相对稍微高一点，典型的代表的是Dubbo，Spring Cloud。对于传统企业来说，传统企业其实缺乏一些互联网的技术基因，这些包括技术，人才，经验，还有开发流程。在实际的市场当中，我们可以看到，大多数企业，虽然他们试图在微服务方面有一些转变，但实际上，在落地的时候还是会遇到一些问题。目前第二代的Service Mesh技术其实主要是冲着解决这个问题来的。他的思路在于要想办法用Service Mesh这样一个技术来降低微服务落地的门槛，最后帮助传统企业完成整个技术转型。这是目前大的背景和现状，我们下面来详细聊一下在这个背景当中一些具体的东西。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-06_hu7f1aa2dca4ffc4cbebe1336848081843_218813_2daac959d2b16bb99c6468afa5ed171b.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-06_hu7f1aa2dca4ffc4cbebe1336848081843_218813_a93def27d3b6adf7aba08eba7508a719.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-06_hu7f1aa2dca4ffc4cbebe1336848081843_218813_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-06_hu7f1aa2dca4ffc4cbebe1336848081843_218813_2daac959d2b16bb99c6468afa5ed171b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;微服务的一个痛点：落地很难。&lt;/p&gt;
&lt;p&gt;在这个地方我放了一个冰山图，左边的有一个坐标，就是说要实现好一个微服务，技术要求大概是一个什么样子，我这边简单的画了一下。&lt;/p&gt;
&lt;p&gt;实际上我们可以看到，就是说如果以60分为及格线的话，那很遗憾的是，虽然这个冰山我们看它的体积非常的巨大，这个市场规模是非常大的，但实际上到目前真正能够落地的，能够浮在水面上的，其实并不多。这个问题在哪里？&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;因为它落地太难了&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-07_hu7f1aa2dca4ffc4cbebe1336848081843_326073_0a5d2c2f8afcde2ea262376e7b3d7bd6.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-07_hu7f1aa2dca4ffc4cbebe1336848081843_326073_8bda2c2860b5ce31961024509a11ea70.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-07_hu7f1aa2dca4ffc4cbebe1336848081843_326073_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-07_hu7f1aa2dca4ffc4cbebe1336848081843_326073_0a5d2c2f8afcde2ea262376e7b3d7bd6.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;落地难的原因是门槛比较高。我们简单的罗列了一下，比如说典型的Spring Cloud，他的技术栈，我们看到的这些特性的列表。大家可以看到非常多的东西，左边这个地方Spring  Cloud的各个组件。大家如果用过Spring Cloud的都会比较熟悉。当然两边并不是严格对称，这只是一个示意。&lt;/p&gt;
&lt;p&gt;实际上在这样的一个巨大的特性列表和组件列表当中，比较头疼的是：如果你是一个新人的话，你要第一时间掌握的东西其实是非常多的。Hello Would都很简单，但是你真的要掌握，这些东西是要一个一个吃透的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-08_hu7f1aa2dca4ffc4cbebe1336848081843_333115_6325827669f1f2892f83c33f1a41c5e4.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-08_hu7f1aa2dca4ffc4cbebe1336848081843_333115_beac43e0d2239520ec2366e437dc8340.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-08_hu7f1aa2dca4ffc4cbebe1336848081843_333115_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-08_hu7f1aa2dca4ffc4cbebe1336848081843_333115_6325827669f1f2892f83c33f1a41c5e4.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;为什么这个门槛会这么高？在这里面要指出一点，就是说：解决问题的思路有点不太对。&lt;/p&gt;
&lt;p&gt;我们先看左边这个图，我们现在如果是想要一辆汽车，那OK，可以像左边这个图一样。我们看到一辆汽车分解之后是会有多少个零件？我们现在通过类库的方式，实际去组装辆汽车，我可以给你不同的组件，不同的类库，然后告诉你这个是发动机，这个是轮胎，这个是刹车&amp;hellip;&amp;hellip;这确实会比自己从头到尾，从每一个螺丝钉开始制造，去组装整车要轻松的多，比如说至少有个成熟的发动机，至少方向盘可以不用自己做了。但是实际上，对用户而言，必须要对整体有非常深的认识：你知道每个组件能做什么，选择合适的组件，并把他们并拢起来。这样对一个系统的了解是需要比较深的。&lt;/p&gt;
&lt;p&gt;我们再看看右边：你组装出来的东西是什么样子？最上面这个跑车可能是所有人的梦想，对吧？但实际当中，不同的用户，他的能力是不一样的，他的投入也不一样。那他最终得到产出品，很有可能不是上面的这个让大家心动的跑车。很可能只是一个普通的大众，只能只一个QQ，甚至，其实最后一张图非常凄惨：不知道出来的会是什么，很可能是接近无法使用的产品。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-09_hu7f1aa2dca4ffc4cbebe1336848081843_316067_d7d6a5e08e4dc8c83e05d4dc490bae1c.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-09_hu7f1aa2dca4ffc4cbebe1336848081843_316067_b4c43b3bdd6f4dfc4f341a53a4431b98.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-09_hu7f1aa2dca4ffc4cbebe1336848081843_316067_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-09_hu7f1aa2dca4ffc4cbebe1336848081843_316067_d7d6a5e08e4dc8c83e05d4dc490bae1c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在下一代的Service Mesh当中，会用其他的方式来完成这个事情。&lt;/p&gt;
&lt;p&gt;首先通过智能代理的方式，屏蔽掉大家对底层各个组件的认知。Service Mesh会通过直接使用Sidecar的方式来完成这些功能。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-10_hu7f1aa2dca4ffc4cbebe1336848081843_265739_bea63728a35b2bb3cac2b4256da1003b.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-10_hu7f1aa2dca4ffc4cbebe1336848081843_265739_c80cb9cc9f23318e394728120c9c9ee5.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-10_hu7f1aa2dca4ffc4cbebe1336848081843_265739_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-10_hu7f1aa2dca4ffc4cbebe1336848081843_265739_bea63728a35b2bb3cac2b4256da1003b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;从思路上说，在这个时候，最大的事情是&lt;strong&gt;调整战略&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;我们回到需求：客户用这些东西的需求是什么？它的目标是把这个车造出来，但造出这个车的下一步，是开着它上路，去该去的地方。造车，并不是他的最终的目标，对吧？我们回到现实的例子，大家学习Spring Cloud的目标是仅仅掌握Spring Cloud吗？我们说到，做微服务的实现，是把我们体系架构在微服务之上，然后让整个体系可以更快更好的运转。所以呢，客户真正的需求是用微服务做开发，做应用开发，应用是它的核心价值。这种情况下，对于微服务系统本身的掌握，要求其实不应该那么高。&lt;/p&gt;
&lt;p&gt;比如说我随便举个例子，我相信在座的各位，很多同学开过车对吧？你可能开车的驾驶技术很高，但是如果我们现在，举个例子说：我给你一堆组件给你组，你能不能组装成一辆车？我相信在坐的同学应该没有几个能办得到。&lt;/p&gt;
&lt;p&gt;所以，在这个地方，在Service Mesh里面，最重要的是：我们会做一个思路的转变。我们不再以组件的方式给客户提供服务，而且直接给客户成品，而且是精心打磨的成品。这个大家梦想中的跑车，开箱即用，直接呈现在客户面前。它非常的方便，可以非常快速地使用它。他的品质是经过打磨好之后的，然后客户只需要知道该怎么驾驶就好了。&lt;/p&gt;
&lt;p&gt;这是整个Mesh的思路。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-11_hu7f1aa2dca4ffc4cbebe1336848081843_239221_87f934fada74c6978a965eaa90530e27.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-11_hu7f1aa2dca4ffc4cbebe1336848081843_239221_dccf06e438f68bb6e019d4ff3ad07a0f.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-11_hu7f1aa2dca4ffc4cbebe1336848081843_239221_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-11_hu7f1aa2dca4ffc4cbebe1336848081843_239221_87f934fada74c6978a965eaa90530e27.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在这个思路背后，代表了一个重要的核心理念。我们会看到，第一代的微服务将当时微服务开发的门槛降低了，在第一代微服务之前，你需要一切从零开始，你需要从每一行代码开始。换句话说，在你造整车的时候，你需要从每个螺丝钉开始，这必然是很难的。&lt;/p&gt;
&lt;p&gt;第一代微服务至少提供了一些成熟的组件，比如说发动机OK啦，这个门槛它降低了一部分。第二代微服务，我们是希望在这个基础上，将门槛进一步降低。60分不再是及格线，我们希望将它降成30分。这个目标如果能够达成，对于期望用微服务来做技术革新的企业来说，他这个时候可以更容易地落地。大家可以想象，一场考试，及格线是60分和及格线是30分，这个时候及格率会发生质的变化，这个时候能释放出来的市场规模也会远远大于前者。&lt;/p&gt;
&lt;p&gt;OK，这个第一阶段我们讲好。&lt;/p&gt;
&lt;p&gt;嗯，在这个地方，我想问大家一个问题：在座的各位，有没有哪一位所在的企业是真正的将微服务落地在一线生产上的？张亮兄？OK，你这个没问题。还有没有哪一位？OK？好，这个属于冰山水面上的部分。后面还有没有其他同学？有没有同学做过尝试的？就是在你们的实际的生产当中，实际落地微服务的架构，OK，这边有些同学。&lt;/p&gt;
&lt;p&gt;好，实际上调查的和我们预期的还是有点像的。真正的大家能够把微服务落地的，就是冰山上面露出来的一小部分。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-12_hu24b41bb6a4430f59d455e8d07f1beaca_91074_071b9e644753a0038c024b7b814b6ab9.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-12_hu24b41bb6a4430f59d455e8d07f1beaca_91074_2a379e48c51cb3e4a34184bab1998a13.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-12_hu24b41bb6a4430f59d455e8d07f1beaca_91074_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-12_hu24b41bb6a4430f59d455e8d07f1beaca_91074_071b9e644753a0038c024b7b814b6ab9.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;OK，我们进行第二个探讨：Service Mesh和微服务市场模式的探讨。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-13_hu7f1aa2dca4ffc4cbebe1336848081843_123195_63853da14d06c486936dc0190a07dd4b.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-13_hu7f1aa2dca4ffc4cbebe1336848081843_123195_642110b509bca3d77208e2685c7b6f24.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-13_hu7f1aa2dca4ffc4cbebe1336848081843_123195_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-13_hu7f1aa2dca4ffc4cbebe1336848081843_123195_63853da14d06c486936dc0190a07dd4b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我先抛出一个问题：假设现在有一个公司，他要推微服务，但它确实之前没有这样的经验，它可能也缺乏这样的人才，所以在技术能力上它会有些欠缺。那这个时候怎么办？&lt;/p&gt;
&lt;p&gt;哪位同学能给我想一个办法？或者说如果现在你的领导和你说：我们要上微服务了，有什么办法？这个很现实的，领导明天就你定方案，然后你发现你的团队好像大家都没玩过，也都不会。请你告诉我怎么办？有没有哪个同学给我一个想法？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：现场互动，有同学回答说，需要领导重视。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;嗯，非常重视，我们明天就上！&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：现场互动，有同学继续说，招人，外包。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;恩，招人和外包，还有别的吗？OK，好，这位同学至少已经找到了明天早上开始推行微服务的一些方案了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-14_hu7f1aa2dca4ffc4cbebe1336848081843_163184_67f7fc360526707c55c0c17c082e1cd9.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-14_hu7f1aa2dca4ffc4cbebe1336848081843_163184_fa38fde473e5533db9cc7db10ca34c3f.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-14_hu7f1aa2dca4ffc4cbebe1336848081843_163184_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-14_hu7f1aa2dca4ffc4cbebe1336848081843_163184_67f7fc360526707c55c0c17c082e1cd9.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;OK，我们简单过一下，刚才这个同学这里有一个比较有意思的地方：招人。这个有个比较有意思的东西给大家轻松一下。&lt;/p&gt;
&lt;p&gt;这个是我个人的玩笑，用于区分互联网企业的一个简单方式：当发现有些事情自己不会做，也没有合适的人手，没能力的时候怎么办？一般互联网公司的习惯都是：挖！没人是吧，看一下业界谁会，挖！挖不过来是吧，薪水乘2？OK，互联网公司一般习惯这么干。但是传统企业一般不喜欢这么干，这里还包括伪装成互联网，大家应该懂这个意思吧？嗯，他的业务有可能是互联网业务，但他的工作方式，整个运作可能是传统企业的方式。但它的业务模式可能是互联网产品。这种企业的通常情况下它的习惯是买！拿钱去买，但他能买到什么？&lt;/p&gt;
&lt;p&gt;当然这是个玩笑，但是有时候还是挺准确的，大家可以私底下去验证一下。&lt;/p&gt;
&lt;p&gt;那我们现在说说，能买什么？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-15_hu7f1aa2dca4ffc4cbebe1336848081843_154605_8a482a7b68d5041d5802ecb8fdcd8049.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-15_hu7f1aa2dca4ffc4cbebe1336848081843_154605_24c70356c7916179867e0adf21372122.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-15_hu7f1aa2dca4ffc4cbebe1336848081843_154605_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-15_hu7f1aa2dca4ffc4cbebe1336848081843_154605_8a482a7b68d5041d5802ecb8fdcd8049.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在这个市场，能为微服务的开发提供什么样的产品，什么样的服务吗？刚才同学说了一个：外包。是的，这个很正常。确实有非常之多的外包，但还有两个，一个是咨询，教你怎么做；一个是培训，包括出书也是一种培训，现场培训是另一种。还有一种就是卖产品，微服务相关的各种产品。整个市场会提供这些产品，但我们会注意到：前三者是不一样的。咨询、培训、外包本质上是要提升客户的能力，就是让你的能力更强。如果大家记得前面的那条线的话，现在就是在你考试的时候，让你的考试能力更强。产品是帮你稍微降低一下门槛。比如我告诉你，第五道题的答案是B，你填上就好了。最终达到大家及格的目标，至少起码及格。&lt;/p&gt;
&lt;p&gt;整个市场提供的产品，大概是这个样子。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-16_hu7f1aa2dca4ffc4cbebe1336848081843_226169_cad1f589b28604029eb8cbef31336858.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-16_hu7f1aa2dca4ffc4cbebe1336848081843_226169_55c826c157c17aa35febcd5fb524d1c9.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-16_hu7f1aa2dca4ffc4cbebe1336848081843_226169_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-16_hu7f1aa2dca4ffc4cbebe1336848081843_226169_cad1f589b28604029eb8cbef31336858.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们聊另外一个话题，可能更有意思：为什么大家想用微服务？尤其在参加技术大会之后。平时大家苦日子过习惯了，后来某人参加了某个技术大会之后，回来就觉得：平时这苦日子过得有点惨。旁边的这个是麦粒，不知道大家有没有吃过？晒干之后脱皮直接煮着可以吃的，甚至也可以生吃。然后是非常难吃的，很难下咽，但古代，我们的祖先原来就是这么吃下来的。后来发现参加了一场大会之后，发现这个受不了，为什么呢？发现别人吃的是右边的东西。&lt;/p&gt;
&lt;p&gt;这个叫什么？不患贫而患不均，对吧？左边这个其实也不是过不下去，但是当你看到右边之后，通常一般人都受不了了。别人告诉你说要去皮，你要磨成粉，之后你要和面，发酵，蒸，然后就有这个吃了。大家一看，开完大会之后就发现，对啊，左边这个麦粒确实没必要这么吃，对不对？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-17_hu7f1aa2dca4ffc4cbebe1336848081843_227980_7a3ae8bedeccce57ce85204263ea9ca6.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-17_hu7f1aa2dca4ffc4cbebe1336848081843_227980_464a5d53e439e931d3da25bc67562a27.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-17_hu7f1aa2dca4ffc4cbebe1336848081843_227980_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-17_hu7f1aa2dca4ffc4cbebe1336848081843_227980_7a3ae8bedeccce57ce85204263ea9ca6.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们现在回到刚才的这个话题：咨询、培训、外包的本质是什么？&lt;/p&gt;
&lt;p&gt;咨询是告诉你，看个例子，咨询告诉你什么品种的小麦口感好，或者说告诉你微服务12要素。嗯，然后告诉你，Spring Cloud是个不错的选择。&lt;/p&gt;
&lt;p&gt;培训是什么？告诉你，这个小麦怎么种，这个馒头要怎么蒸，对吧？接下来告诉你，什么三个星期或者三天快速掌握Spring Cloud。&lt;/p&gt;
&lt;p&gt;外包是什么？就是这些东西，做咨询了，给方案了，也做了一些培训了，但是还是搞不定。可能技术不够，也可能人力不足。那怎么办？上门帮你。对吧？我直接帮你蒸一屉馒头，客户就会问了：今天搞定了，明天怎么办，是吧？这个问题肯定是现成的，今年的这个目标搞定了，但是馒头明天还是想吃，不想明天再搞回去的，是吧？OK，好开心的告诉客户，二期合同，签二期合同，轻松帮你搞定。&lt;/p&gt;
&lt;p&gt;那我们可以看到说：这三个本质是什么？是客户变得更强大，对吧？咨询、培训是让你变得更强大的；外包，让你变得假装更强大：其实没这个能力，但是在别人帮助的情况下，可以在短时间之内达到这个能力。&lt;/p&gt;
&lt;p&gt;但是别忘了：整个事情还是在客户这边的，这个还是自己的事情，如果能力不够，明天的事情还是做不好。今天让别人帮忙蒸好了馒头，明天没人蒸的话，还是得回去啃麦粒。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-18_hu7f1aa2dca4ffc4cbebe1336848081843_233028_6e97d37621072395b4346dc31440350a.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-18_hu7f1aa2dca4ffc4cbebe1336848081843_233028_1ab655e41309cd4762512ffd842add79.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-18_hu7f1aa2dca4ffc4cbebe1336848081843_233028_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-18_hu7f1aa2dca4ffc4cbebe1336848081843_233028_6e97d37621072395b4346dc31440350a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;然后我们可以看到，买到的产品也是不同层次的。&lt;/p&gt;
&lt;p&gt;我们做个简单的类比，初级产品是提供一些原材料，不能直接达到目标。但是不管如何，它会给你基石。至少在有小麦的情况下，还有机会煮一煮，对吧？类比各种类库，给一些基本的类库，至少还有机会不要从零开始。当肚子饿的时候，你说我没有吃的，我现在今天开始种地，对吧？等到半年之后，开始有收成，这不现实。所以，不管如何，初期产品至少让你有一个比较好的起点。&lt;/p&gt;
&lt;p&gt;再往后，中级的产品，比如说面粉，这个时候离馒头已经不是很遥远了。但是你还是需要一些比较重要的工具，类比就是各种的框架。基本上有面粉之后，起码不会饿死对吧？不管做的有多难吃。但是呢，有多好吃就是另外一回事，后面还有很多工序需要自己去完成。&lt;/p&gt;
&lt;p&gt;相比之下，大部分同学可能还会选择：这个自己做的不太好，我们还是选最高级，开箱即用。直接下单，那边马上给你端上一笼馒头，马上就搞定。这肯定是比前面自己种地或者买面粉要快的多，类比的话就是Service Mesh。在这里我加了一个问号，后面大家会了解这个问号是什么。&lt;/p&gt;
&lt;p&gt;实际上，在市场上能买到的产品，是不同层次的。市场的规律通常是这样，在满足需求的前提之下，最初期的产品都会在第一时间出现，然后逐渐的开始演变，开始向高级产品来演变。对于微服务市场来说，现在的高级产品就是Service Mesh。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-19_hu7f1aa2dca4ffc4cbebe1336848081843_201559_2a7f4be85da78f2ebf6b055ecbe95684.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-19_hu7f1aa2dca4ffc4cbebe1336848081843_201559_a120e25968debd05dd6a74be67ca5d36.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-19_hu7f1aa2dca4ffc4cbebe1336848081843_201559_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-19_hu7f1aa2dca4ffc4cbebe1336848081843_201559_2a7f4be85da78f2ebf6b055ecbe95684.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们回到第二个痛点。前面我们说微服务落地的重点在哪里，第一个是门槛，微服务的门槛高实在是有点高。这里我们看第二个痛点：微服务的市场模式是不太对的。&lt;/p&gt;
&lt;p&gt;我们现在细细看，就是说，咨询、培训、外包，对于市场来说，有能力提供微服务相关服务的这些公司，大多数是技术型的公司。不管是创业公司，还是大一点像阿里腾讯这种比较大的。这些公司有个问题：它其实不是太擅长咨询培训外包的，毕竟这个不是它的主业。同样在这几个领域当中，市场存在大量的竞争对手，比如咨询公司，大家熟悉的，培训公司，还有各种外包。这些对于做技术型的公司来说通常不擅长，而且即使他可以来做，也会占用大量的人手。一旦占用人手的话，就没有能力去开发产品。&lt;/p&gt;
&lt;p&gt;我们看第四个，会发现：这个产品麻烦了。客户的资金，他的预算，一般来说是有固定的。当他的预算大部分投入到咨询、培训和外包之后，还有多少钱来买产品？他不买产品，技术公司就没有办法得到利润，没有利润，就没有足够的财力去开发更好的产品。&lt;/p&gt;
&lt;p&gt;没有更好的产品，就不能靠产品解决问题。&lt;/p&gt;
&lt;p&gt;那客户就要回答说：产品不能解决我的问题，我就继续回到咨询、培训、外包的这个主流上来。这个地方形成一个很要命的恶性循坏。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-20_hu7f1aa2dca4ffc4cbebe1336848081843_215494_f5b342787f7987bbb7c5edf5205157e5.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-20_hu7f1aa2dca4ffc4cbebe1336848081843_215494_5b76d0ffcf13c00fb0c32b0a3d727e29.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-20_hu7f1aa2dca4ffc4cbebe1336848081843_215494_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-20_hu7f1aa2dca4ffc4cbebe1336848081843_215494_f5b342787f7987bbb7c5edf5205157e5.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在我之前的经历当中，我是在这个市场的乙方公司做过事情。我们当时其实是面临一个比较难受的事情，就是说：如何在产品和项目之间平衡。我相信这对于所有在微服务市场提供服务的乙方公司来说，都是一个非常非常现实的话题。&lt;/p&gt;
&lt;p&gt;产品是个什么概念？大家最熟悉的，左边这个图，office系列，或者说它背后的windows操作系统。差不多是过去十几年，软件行业我感觉应该是最成功的所谓&amp;quot;产品&amp;quot;。产品的概念：难度非常大。你看windows、office出了这么多年，有谁超过了？然后它的周期非常长，开发一个产品，好几年。几千个人，甚至更多的人堆在上面。它的风险非常大，一次投资就是几亿几十亿。然后来钱其实挺慢的，因为他要慢慢铺开。这个产品铺上去可能几年之后陆陆续续回本。但是，有个极大的优点：非常低成本的大规模复制。Office 2019，它的第一份拷贝成本可能高到几十亿美元，但它的第二份拷贝的成本是多少？第两千份拷贝的成本是多少？第1000万份，它的成本又是多少？&lt;/p&gt;
&lt;p&gt;所以我们就发现针对于技术公司而言，对于大部分技术公司而言，其实最理想的是做产品，对吧？产品做好了，然后再卖给更多的客户。&lt;/p&gt;
&lt;p&gt;但是很多时候，事情往往没这么简单。很多时候我们遇到一个事情：会有一个“项目”的概念。有个客户，他有一大堆的东西，这些东西无法形成一个通用的需求，也没办法由简单的产品去覆盖它。然后可能就会用咨询、培训加外包的方式帮他搞定。OK，好处是说有一单是一单，客户的需求是摆在面前的，风险很小，基本上技术上肯定可以搞定，半年一年之后就能把这个项目的钱结回来。但是它的缺点是：陷入卖人头的境地。因为项目的可重复性是比较差的，当你接到第二个项目的时候，你会发现它其实需要重头来过，很难把两个项目之间的东西去积累成产品。&lt;/p&gt;
&lt;p&gt;我相信在座的如果有做乙方的，包括做内部乙方的，给其他人提供服务、产品来解决问题时，应该都会遇到这两个问题。这个平衡是相当麻烦。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-21_hu5c95a73d8952dc829c1e2d60a6a77d66_230949_75dfe1198d5c7e1f931348818e14ec3a.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-21_hu5c95a73d8952dc829c1e2d60a6a77d66_230949_5b696ff2ffa98437117bcc48b1a1bd37.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-21_hu5c95a73d8952dc829c1e2d60a6a77d66_230949_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-21_hu5c95a73d8952dc829c1e2d60a6a77d66_230949_75dfe1198d5c7e1f931348818e14ec3a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;路在哪里？Service Mesh给出几个答案。&lt;/p&gt;
&lt;p&gt;左边这个是在之前曾经做过的分享，从技术上来说，因为我们今天没讲技术，所以没有提过。从技术上说，Service Mesh提供了一个方案，就是说将整个服务间通讯的解决方式，整个技术栈全部下移。从应用当中下移到底层的基础设施，通过加强基础设施的方式提供一个统一的解决方案，这是从技术的角度。&lt;/p&gt;
&lt;p&gt;在前面我们提到，从理念的角度上说，Service Mesh是希望将微服务市场的门槛降低，然后形成整个市场的规模增大。&lt;/p&gt;
&lt;p&gt;我们在前面也提供了一个产品的思路：解决问题的思路要发生变化。要实现产品的升级，不能卖初级产品，要想办法提供最终的成型的成熟的产品。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-22_hu7f1aa2dca4ffc4cbebe1336848081843_170244_2f54dba5d070b5e1898d55c17fbdc26b.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-22_hu7f1aa2dca4ffc4cbebe1336848081843_170244_05b6403fdb2edfd1f81ad4fd718e8aeb.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-22_hu7f1aa2dca4ffc4cbebe1336848081843_170244_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-22_hu7f1aa2dca4ffc4cbebe1336848081843_170244_2f54dba5d070b5e1898d55c17fbdc26b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;OK，这是Service Mesh在这个时候非常重要的一件事情，就是：可以重建微服务市场的市场模式。&lt;/p&gt;
&lt;p&gt;将整个模式牵回到一个正统的&lt;strong&gt;重产品重技术&lt;/strong&gt;的途径，也就是说，我们会通过提供更好的产品，然后这个产品可以更多的更普遍地满足客户的需求，从而降低客户的门槛。当客户入门的门槛降低的时候，他对于咨询、培训、外包的需求就会降低。那他会有更多的资金预算投到产品的采购当中，这样会让提供产品的技术公司有更多的利润，然后继续加强产品，形成这样一个良性的循环。这是Service Mesh在整个微服务市场当中非常非常重要的一环，必须要让原来的恶性循环的场景开始向现在这样一个良性循环做转变。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-23_hu7f1aa2dca4ffc4cbebe1336848081843_215997_be03ffa86430569f7ef87ec99558c2e6.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-23_hu7f1aa2dca4ffc4cbebe1336848081843_215997_cf8650b8b19140db86b907af2aca4c9e.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-23_hu7f1aa2dca4ffc4cbebe1336848081843_215997_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-23_hu7f1aa2dca4ffc4cbebe1336848081843_215997_be03ffa86430569f7ef87ec99558c2e6.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们来详细的过一下，Service Mesh对于微服务市场的核心价值，主要是四块：&lt;/p&gt;
&lt;p&gt;第一是对使用者更加的友好，体现在技术栈下移，降低了整个微服务入门的门槛。最终达到扩大市场规模的目标，这主要是体现它的易用性上。&lt;/p&gt;
&lt;p&gt;然后，第二个核心价值体现在标准。从类库，到框架，再到平台，整个生态是越来越大的。&lt;/p&gt;
&lt;p&gt;而一旦到了Service Mesh这个领域，就不会拘泥于细节，而是通盘考虑，考虑生态如何做。整个体系，所有组件，这些组件之间的交互是什么？这有个好处，它会自然而然的去统一，去集中化这些模块，然后在上面再制定一个标准。&lt;/p&gt;
&lt;p&gt;第三个价值在于Service Mesh提供专业化的解决方案。大家常说的，“专业的人做专业的事情”。在这个领域，微服务之间的通讯，这是一个专业度非常高的领域，这个领域应该出现工业级成熟度的制成品。而不应该让每一家公司都以小作坊的方式去各自完成。我们期待的是一个工业级的产品，它应该有非常非常高的完成度，功能齐全，以此来提升业界的整体水准。随便举个例子，今天大家能拿到的任何一个哪怕微不足道的小螺丝钉。你就想想，如果用人工的方式去做，他们开发成本会有多大？工业制成品的概念就是在这个地方，通过大量的标准化，通过工业制造，可以做到非常好的精度，同时成本降到极低。&lt;/p&gt;
&lt;p&gt;这在整个市场上体现为规模效应。为什么？如果一天的时间只做一个螺丝，这个成本非常的高，如果开一台机器，一天制造了100万个螺丝，成本在哪里？所以，在这个点上有个非常重要的事情，就是：一定要可以低成本的大面积的使用。&lt;/p&gt;
&lt;p&gt;如果你的螺丝不标准，你在某个地方一定要需要一个特殊的螺丝，这个螺丝的规格跟其他都不相同，一定要手工制作。那这种情况下，你是没有办法去降低成本。你只有通过前面的易用性，标准，专业来实现。这些事情最终的目标，都是让这个产品最终实现可以低成本的大面积使用。这个时候可以做到一个事情，就是说你最终总的利润可以增加，但是你的单价是降低的。&lt;/p&gt;
&lt;p&gt;Service Mesh这样的一个技术，对于市场有一个比较好的事情，是说它适合&lt;strong&gt;把规模做大&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-24_hu24b41bb6a4430f59d455e8d07f1beaca_93570_77450ed18683d2650f11af004ddf6cc4.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-24_hu24b41bb6a4430f59d455e8d07f1beaca_93570_eb299d7043cdb012c794780fc693caf6.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-24_hu24b41bb6a4430f59d455e8d07f1beaca_93570_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-24_hu24b41bb6a4430f59d455e8d07f1beaca_93570_77450ed18683d2650f11af004ddf6cc4.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;OK，我们探讨了service mesh对微服务市场模式的重新塑造。我们现在进入第三段，Service Mesh对于PaaS平台的价值和意义。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-25_hu7f1aa2dca4ffc4cbebe1336848081843_234898_9fe29e48c9aa8768cf068f3d29f4a213.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-25_hu7f1aa2dca4ffc4cbebe1336848081843_234898_8e6cd60d02665c838380371b43876484.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-25_hu7f1aa2dca4ffc4cbebe1336848081843_234898_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-25_hu7f1aa2dca4ffc4cbebe1336848081843_234898_9fe29e48c9aa8768cf068f3d29f4a213.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在开始这个话题之前，我们先简单过一下，PaaS的核心价值是什么？它跟Service Mesh又有什么相通的地方？大家记得前面列了四个东西，第一个是易用，对使用者友好，大家会发现PaaS提供的价值也是如此，PaaS也是让大家可以更轻易的更简单的实现整个平台。标准，这个不用说了。专业，大家会发现，其实现在PaaS平台会慢慢的向少数的解决方案集中。基本上已经很少有小公司自己再去做一个自己的PaaS平台了。大规模，大家都有联系到，目前PaaS市场上比较大的一些公有云，会发现这个规模其实是非常可怕。&lt;/p&gt;
&lt;p&gt;大部分公有云，如果体积规模发展比较迅速的话，每年乘2是很正常的。我们发现PaaS其实和我们之前谈到的Service Mesh，几乎是一脉相承。为什么？殊路而同归。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-26_hu7f1aa2dca4ffc4cbebe1336848081843_251641_9baf03e30a14fcb65d16ad4d1498dce8.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-26_hu7f1aa2dca4ffc4cbebe1336848081843_251641_e40f4efa2862672d835ca062c4aa93cf.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-26_hu7f1aa2dca4ffc4cbebe1336848081843_251641_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-26_hu7f1aa2dca4ffc4cbebe1336848081843_251641_9baf03e30a14fcb65d16ad4d1498dce8.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;PaaS和Service Mesh成功的基础，其实就是在这几个关键的点上。&lt;/p&gt;
&lt;p&gt;一个是一定要简单易用。这个轮子大家有没有印象，有小朋友的就会知道，这个是自行车后轮的平衡轮。有这个平衡轮之后，没有任何基础的小朋友也可以骑上自行车了，就叫易用性：非常非常简单，让你的入门门槛瞬间降低，客户做的事情及其简单。&lt;/p&gt;
&lt;p&gt;第二个事情是一定要有规模效应，产品要好，价格要低，怎么做到？只能把规模做大。要把规模做大，还有一个事情，就是一定要想办法把蛋糕做大。因为就算你把市场百分百占了，如果这个市场本身不大，那这种情况下其实就算占了百分百，也就一小块。所以接下来一个事情就是一定要去把这个蛋糕做大。&lt;/p&gt;
&lt;p&gt;整个PaaS和Service Mesh的生存之道（大家如果有留意到，我们一路下来这个脉络）是说它做了一个重要的事情，就是它实际上是在帮客户做事情：这些事情是客户必须要做的，但是他又不太容易做好。我们的生存之道是帮助客户从这些细节里面解脱出来。客户大多数情况下是业务驱动的，我们要做的就是把所有的他要做又不好做的这些事情都下沉下来，我们帮他做好。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-27_hu7f1aa2dca4ffc4cbebe1336848081843_265840_664fa4ad91d0a7d92f3152891758a4ee.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-27_hu7f1aa2dca4ffc4cbebe1336848081843_265840_cc495fde3845dfd26f303715e267e274.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-27_hu7f1aa2dca4ffc4cbebe1336848081843_265840_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-27_hu7f1aa2dca4ffc4cbebe1336848081843_265840_664fa4ad91d0a7d92f3152891758a4ee.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Service Mesh和PaaS在理念上是相通的，Service Mesh对PaaS的价值体现在下面的几个方面：&lt;/p&gt;
&lt;p&gt;第一个是标准化和规模化，那这个我们讲的挺多。&lt;/p&gt;
&lt;p&gt;第二个，会涉及到跟技术相关的一些内容，它可以让开发和运维分离。Service Mesh会接管整个应用的部署、运维和对应用的管理，它独立于应用的开发和业务实现。这样的好处是可以将大家熟悉的一些比如说服务治理的各种功能，让它独立应用的开发之外，而这些功能通过Service Mesh来实现。当Service Mesh变成PaaS的一部分之后，PaaS和业务之间的这个界限会变得特别的清晰。应用集中在业务语义，而剩下的所有的部署、运维、管理、监控通通放在PaaS，这样两者之间的界限清晰。&lt;/p&gt;
&lt;p&gt;另外一个就是提高竞争力，因为Service Mesh代表着技术先进性，提供了一些非常强大的功能，同时它会降低客户的门槛和客户易于使用，这个对于客户而言吸引力是非常高的。&lt;/p&gt;
&lt;p&gt;然后可以帮助PaaS平台更好的去整合资源，因为PaaS天生是提供各种能力的。这些能力，原来是以单个单个的方式提供给客户，大家如果有注意到的话，所有PaaS平台都卖各种产品各种能力，然后可以自己选择去用。Mesh有个好处是说它本身就可以天然地把这些能力组合起来，变成一个统一的全套方案，直接覆盖监控、告警、故障排查，变成整个基础能力的一部分，变成PaaS平台的一部分，通过这样的方式来发挥PaaS平台的威力。&lt;/p&gt;
&lt;p&gt;另外就是引入了可控性。因为Service Mesh的控制平面，是可以对整个服务间通讯、对服务治理做到集中式的管理。这些控制的能力，如果为PaaS所用，那PaaS就会平添一种能力，去对整个应用做统一的控制。在此之前PaaS平台对应用的控制更多是集中在非常粗的层面，比如说启动、关闭，但是内部其实没办法干预。可以给它分配资源，但是你实际上没有办法去管控，比如说一些服务治理的功能。那通过整合Service Mesh之后，PaaS就开始有能力对服务进行管控，而且这个能力会变得非常强大。而强大的服务治理功能，会变成PaaS平台的重要的卖点。&lt;/p&gt;
&lt;p&gt;这是整个Service Mesh对于PaaS的帮助。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-28_hu7f1aa2dca4ffc4cbebe1336848081843_116328_cf1d579fac3a070d5c5cbae31d5de759.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-28_hu7f1aa2dca4ffc4cbebe1336848081843_116328_36ed553578ff386e59883140f1140bf0.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-28_hu7f1aa2dca4ffc4cbebe1336848081843_116328_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-28_hu7f1aa2dca4ffc4cbebe1336848081843_116328_cf1d579fac3a070d5c5cbae31d5de759.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们简单总结一下：Service Mesh技术为PaaS平台提供了一个非常好的应用落地方案。&lt;/p&gt;
&lt;p&gt;底层是PaaS，PaaS如果直接接业务的话，通常是比较累的。客户选择用微服务之后，就会选择Spring Cloud之类的东西，还是要自己做一层比较厚的框架层。有Service Mesh技术之后PaaS会更好的对接微服务，对接业务。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-29_hu7f1aa2dca4ffc4cbebe1336848081843_157248_1c838602ef18d0504174f5be8ae8da5b.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-29_hu7f1aa2dca4ffc4cbebe1336848081843_157248_bfa92c31c0be1269dfa76e7b705576e3.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-29_hu7f1aa2dca4ffc4cbebe1336848081843_157248_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-29_hu7f1aa2dca4ffc4cbebe1336848081843_157248_1c838602ef18d0504174f5be8ae8da5b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最后我们会提到，Service Mesh和PaaS，我们称之为&lt;strong&gt;绝配&lt;/strong&gt;。所谓绝配，是说这样一个搭档相互之间是非常的舒服：让彼此的能力互补，然后增强对方的优点。&lt;/p&gt;
&lt;p&gt;在最早的微服务时代，微服务和容器被认为是一对绝配。应该说这两个技术的互补性是非常强的。微服务已经进展到Service Mesh阶段了，而容器经过市场淘汰已经开始向K8S靠拢了。接下来，在这样一个基础上如果能再走一步，当k8s逐步向PaaS平台靠拢，也就说PaaS实际上是一个基于K8S的PaaS。那它和Service Mesh之间的搭档会成为一个新的市场主流，成为一个更好的客户基础。当然现在还没有实现，目前市场上暂时还没有这样的产品，但我相信在未来一两年中这会成为市场的主流。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-30_hu7f1aa2dca4ffc4cbebe1336848081843_64436_1b952186d153c5fa4f41d9d0612afb11.webp 400w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-30_hu7f1aa2dca4ffc4cbebe1336848081843_64436_74b6935343a6c117e2fbb1b4539ee140.webp 760w,
               /talk/201805-service-mesh-rebuild-microservice-market/images/ppt-30_hu7f1aa2dca4ffc4cbebe1336848081843_64436_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201805-service-mesh-rebuild-microservice-market/images/ppt-30_hu7f1aa2dca4ffc4cbebe1336848081843_64436_1b952186d153c5fa4f41d9d0612afb11.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;OK，我们今天的内容到这里结束，非常感谢大家，谢谢。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Istio Mixer Cache工作原理与源码分析(1)－基本概念</title>
      <link>https://skyao.net/post/201804-istio-mixer-cache-concepts/</link>
      <pubDate>Sat, 28 Apr 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201804-istio-mixer-cache-concepts/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;本系列文章将详细介绍Istio中Mixer Cache的工作原理，为了避免空谈，将引入广大程序员同学喜闻乐见的源码分析环节，并结合Mixer的接口API，详细展现Mixer Cache的各种细节。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;预警：Mixer Cache系列文章除了本文讲述概念比较简单外，其它文章会包含大量复杂和繁琐的细节，包括设计／实现／API等，适合追求深度的同学。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;阅读本系列文章前，请确保对Service Mesh和Istio有基本的认知，临时上车的同学请自觉补课：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;../../publication/service-mesh-next-generation-microservice/&#34;&gt;Service Mesh：下一代微服务&lt;/a&gt;: Service Mesh介绍&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;../../publication/istio-introduction/&#34;&gt;服务网格新生代-Istio&lt;/a&gt;：Istio介绍&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外如果对Mixer职责和设计不熟悉的同学，请先阅读下文（本文可以理解为是此文的番外篇）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;../201804-servicemesh-architecture-introspection/&#34;&gt;Service Mesh架构反思：数据平面和控制平面的界线该如何划定？&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在这篇文章中，出于对Istio性能的担忧和疑虑，我们探讨了Mixer的架构设计，工作原理，并猜测了Mixer的设计初衷。期间，我们介绍到，为了保证运行时性能，避免每次请求都远程访问Mixer，Istio特意为Mixer增加了缓存。当时出于篇幅考虑，我们没有深入到缓存的细节，现在将在这个系列文章中就这一点深入展开。&lt;/p&gt;
&lt;p&gt;在展开代码实现细节之前，我们先介绍和Mixer Cache相关的基本概念。&lt;/p&gt;
&lt;h2 id=&#34;属性&#34;&gt;属性&lt;/h2&gt;
&lt;p&gt;属性（Attuibute）是Istio中非常一个关键设计，对于Mixer更是特别重要，可以说Mixer的所有功能都是建立在属性这个核心概念之上。&lt;/p&gt;
&lt;p&gt;搬运一段官方文档的介绍：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Istio使用 &lt;em&gt;属性&lt;/em&gt; 来控制在服务网格中运行的服务的运行时行为。属性是具有名称和类型的元数据片段，用以描述入口和出口流量，以及这些流量所属的环境。Istio属性携带特定信息片段，例如API请求的错误代码，API请求的延迟或TCP连接的原始IP地址。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;属性的形式如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;request.path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;xyz&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;abc&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request.size&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;234&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request.time&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;12&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;34&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;56.789&lt;/span&gt; &lt;span class=&#34;mo&#34;&gt;04&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;17&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;/&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2017&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;source.ip&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;192.168.0.1&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;target.service&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;example&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id=&#34;属性词汇&#34;&gt;属性词汇&lt;/h2&gt;
&lt;p&gt;需要特别强调的是：&lt;strong&gt;Istio中可以使用的属性是固定的&lt;/strong&gt;，而不是随意设定的，在这一点上，和一般系统中的类似设计有根本性的差异。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;每个给定的Istio部署有固定的能够理解的属性词汇。这个特定的词汇由当前部署中正在使用的属性生产者集合决定。Istio中首要的属性生产者是Envoy，然后特定的Mixer适配器和服务也会产生属性。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这些将被Istio使用的属性集合，被称为属性词汇，总数大概是50个，详细列表可以参看文档：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://istio.io/docs/reference/config/mixer/attribute-vocabulary.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Attribute Vocabulary&lt;/a&gt;: 来自Istio官方文档中的Reference&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://istio.doczh.cn/docs/reference/config/mixer/attribute-vocabulary.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;属性词汇&lt;/a&gt;：此文档的中文文档翻译，来自istio.doczh.cn&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;引用属性&#34;&gt;引用属性&lt;/h2&gt;
&lt;p&gt;引用属性（Referenced Attributes）是在Mixer Cache的设计和实现中引入的一个非常特别的概念。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;特别提醒：要理解Mixer Cache，必须深刻理解Referenced Attritutes。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;什么是引用属性&#34;&gt;什么是引用属性？&lt;/h3&gt;
&lt;p&gt;这个需要从Envoy和Mixer之间的Check方法说起：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-protobuf&#34; data-lang=&#34;protobuf&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;rpc&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Check&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CheckRequest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;returns&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;CheckResponse&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;在CheckRequest中，Envoy会提交所有的Attribute，而在CheckResponse的应答中，PreconditionResult 表示前置条件检查的结果：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;字段&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;status&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;#google.rpc.Status&#34;&gt;google.rpc.Status&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;状态码OK表示所有前置条件均满足。任何其它状态码表示不是所有的前置条件都满足，并且在detail中描述为什么。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;validDuration&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#duration&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;google.protobuf.Duration&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;时间量，在此期间这个结果可以认为是有效的&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;validUseCount&lt;/td&gt;
&lt;td&gt;int32&lt;/td&gt;
&lt;td&gt;可使用的次数，在此期间这个结果可以认为是有效的&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;attributes&lt;/td&gt;
&lt;td&gt;CompressedAttributes&lt;/td&gt;
&lt;td&gt;mixer返回的属性。&lt;br&gt;返回的切确属性集合由mixer配置的adapter决定。这些属性用于传送新属性，这些新属性是Mixer根据输入的属性集合和它的配置派生的。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;referencedAttributes&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;ReferencedAttributes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;在匹配条件并生成结果的过程中使用到的全部属性集合。&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;“在匹配条件并生成结果的过程中使用到的全部属性集合”是什么意思呢？我们给个例子：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;假定envoy提交的请求中有5个属性，&amp;ldquo;a=1,b=2,c=3,e=0,f=0&amp;rdquo;&lt;/li&gt;
&lt;li&gt;假定mixer中有三个adapter，每个adapter只使用提交属性中的一个属性a/b/c&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如下图所示，mixer会在CheckResponse中返回referencedAttributes字段，内容为&amp;quot;a,b,c&amp;quot;，以此表明这三个属性是mixer的adapter在实际的处理过程中使用到的属性：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;./images/referenced-attributes.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;envoy在收到CheckResponse时，就可以从referencedAttributes字段的值中得知： 原来提交上去的&amp;quot;a=1,b=2,c=3,e=0,f=0&amp;quot;这样一个5个属性的集合，实际adapter使用到的只有&amp;quot;a,b,c&amp;quot;。&lt;/p&gt;
&lt;h3 id=&#34;引用属性的作用&#34;&gt;引用属性的作用&lt;/h3&gt;
&lt;p&gt;为什么envoy要这么关心哪些属性被adapter使用了？以至于需要在交互的过程中，特意让mixer收集这些使用过的属性并明确在CheckResponse中返回给Envoy？&lt;/p&gt;
&lt;p&gt;这是因为Mixer Cache的需要。为了缓存Mixer的结果，避免每次请求都发起一次envoy对mixer的调用，istio在envoy中增加了mixer cache。而要让缓存工作，则必须在每次请求中想办法得到一个有效的key，将调用结果作为value存放起来。&lt;/p&gt;
&lt;p&gt;现在关键点就来了：key要如何设计？&lt;/p&gt;
&lt;p&gt;最简单的方式，自然是将请求中所有的属性都作为key的组成部分，直接做一个简单的hash，得到的值作为key。但是这个方案不可行的地方在于，请求中可能提交的属性大概有二十个上下，有些属性的值变化非常频繁，取值范围也很大，典型如request.id这样每次请求都会给出一个全局唯一值。如果直接将所有属性都作为key的组成部分，那么很可能每次算出来的key都是一个唯一值，这样缓存也就失去意义了。&lt;/p&gt;
&lt;p&gt;因此，不能将全部属性都作为key，那么，挑选部分属性如何？只计算部分我们判断为有必要被adapter使用的属性来计算key。但是，等等，我们会立马反应出来：这违背了mixer adapter的设计原则。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;adapter是独立于envoy&lt;/li&gt;
&lt;li&gt;envoy不应该知道有哪些adapter的存在&lt;/li&gt;
&lt;li&gt;更不应该知道这些adapter使用了哪些属性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，在envoy试图计算key时，就面临两难的境地：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;envoy无法预计哪些属性是adapter需要的&lt;/li&gt;
&lt;li&gt;envoy也不能将所有的属性都作为key&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;那怎么办，mixer cache可是必须要加的。只能见招拆招了，思路倒是直白，容易理解：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;谁可以切确的知道哪些属性被adapter使用过？&lt;/p&gt;
&lt;p&gt;当然是被调用过的adapter自己了，每个adapter在执行完成后，都可以给出自己使用属性集合，mixer只要做一个简单收集就可以拿到这个信息。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;mixer知道了，怎么告之envoy？&lt;/p&gt;
&lt;p&gt;不是有个现成的response嘛，将前面收集到的属性集合通过response传递回envoy就是了。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;搞定！现在再重新看回前面给出的这个图片，就很容易理解了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;./images/referenced-attributes.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;下一步&#34;&gt;下一步&lt;/h2&gt;
&lt;p&gt;在介绍完基本概念之后，我们将在下一篇文章中开始讲解mixer cache的工作原理，然后在更后面的章节中深入实现细节。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Mixer Cache: Istio的阿克琉斯之踵?</title>
      <link>https://skyao.net/post/201804-istio-achilles-heel/</link>
      <pubDate>Fri, 27 Apr 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201804-istio-achilles-heel/</guid>
      <description>&lt;h2 id=&#34;前情回顾&#34;&gt;前情回顾&lt;/h2&gt;
&lt;p&gt;在我的上一个博客文章中，出于对性能的担心，我和大家探讨并反思了Service Mesh的架构。关注的焦点在于mixer的职责和设计的初衷，以及由此带来的问题：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;../201804-servicemesh-architecture-introspection/&#34;&gt;Service Mesh架构反思：数据平面和控制平面的界线该如何划定？&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：如果对Mixer不太了解，推荐在阅读本文之前先阅读上面这个文章。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;期间，对于Mixer Cache我存在几个质疑，由于官方文档和网上资料都几乎找不到任何相关的详细信息。因此，我不得不通过阅读源代码的方式来深入了解细节。&lt;/p&gt;
&lt;p&gt;而从目前分析的情况看，Istio的这个mixer cache实现有些复杂，设计倒是挺精巧的。只是发现，&lt;strong&gt;在特定场景可能会失效&lt;/strong&gt;。为了确认这个问题是否真实存在，我决定将问题消息描述出来，希望和大家一起分析和推断。&lt;/p&gt;
&lt;p&gt;事情有一点复杂，让我们从mixer的工作原理，缓存的设计开始本文。&lt;/p&gt;
&lt;h2 id=&#34;mixer缓存工作原理&#34;&gt;Mixer缓存工作原理&lt;/h2&gt;
&lt;p&gt;我们先看看mixer是如何工作的， 简单的说，是envoy从每次请求中获取信息，然后发起两次对mixer的请求：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在转发请求之前：这时需要做前提条件检查和配额管理，只有满足条件的请求才会做转发&lt;/li&gt;
&lt;li&gt;在转发请求之后：这时要上报日志等，术语上称为遥感信息，&lt;strong&gt;Telemetry&lt;/strong&gt;，或者&lt;strong&gt;Reporting&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;check方法介绍&#34;&gt;Check方法介绍&lt;/h3&gt;
&lt;p&gt;我们的焦点落在转发之前的这次请求，称为Check方法，方法如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-properties&#34; data-lang=&#34;properties&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;rpc&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Check(CheckRequest) returns (CheckResponse)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;请求 &lt;code&gt;CheckRequest&lt;/code&gt; 的内容如下（其他字段暂时忽略）：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;字段&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;attributes&lt;/td&gt;
&lt;td&gt;CompressedAttribute&lt;/td&gt;
&lt;td&gt;用于此次请求的属性。&lt;br&gt; mixer的配置决定这些属性将被如何使用以创建在应答中返回的结果。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;attributes 属性是envoy从请求中提取出来的，其内容类似如下：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-properties&#34; data-lang=&#34;properties&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;request.path&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;xyz/abc&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;request.size&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;234&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;request.time&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;12:34:56.789 04/17/2017&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;source.ip&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;192.168.0.1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;na&#34;&gt;target.service&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;example&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Mixer中的Adapter将根据这些 attributes 属性来进行判断和处理，比如进行前置条件检查。然后将结果发送回envoy。简单起见，我们只看前置条件检查相关的内容。应答返回名为precondition的字段，表示前置条件检查的结果，具体如下(忽略其他字段)：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;字段&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;status&lt;/td&gt;
&lt;td&gt;&lt;a href=&#34;#google.rpc.Status&#34;&gt;google.rpc.Status&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;状态码OK表示所有前置条件均满足。任何其它状态码表示不是所有的前置条件都满足，并且在detail中描述为什么。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;referencedAttributes&lt;/td&gt;
&lt;td&gt;ReferencedAttributes&lt;/td&gt;
&lt;td&gt;在匹配条件并生成结果的过程中使用到的全部属性集合。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;从Check方法的输入输出，我们可以看到：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;前置条件检查输入主要是attributes字段，这是envoy提取的属性列表，注意此时envoy是没有办法得知mixer中的adapter到底会关心哪些属性，因此envoy只能选择将所有属性都发送给mixer&lt;/li&gt;
&lt;li&gt;前置条件检查的输出中，status代表检查结果，referencedAttributes则有些费解，而这个referencedAttributes的设计，则是本次讨论的焦点。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;referencedattributes的特殊设计&#34;&gt;referencedAttributes的特殊设计&lt;/h3&gt;
&lt;p&gt;referencedAttributes是mixer中的adapter在做条件匹配并生成结果的过程中使用到的全部属性集合。&lt;/p&gt;
&lt;p&gt;为什么要有这么一个设计呢？我们来看mixer请求过程中输入情况：我们假定当前mixer中有三个生效的adapter，其中每个adapter的逻辑都和特定的属性相关。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201804-istio-achilles-heel/images/referencedAttributes_hu377a931b69ea3cea13d10aeeddc2f034_72000_ff8e36d64dcc619e43ed98f5f700c1c2.webp 400w,
               /post/201804-istio-achilles-heel/images/referencedAttributes_hu377a931b69ea3cea13d10aeeddc2f034_72000_ff91d9228e3d1d5db15c79910e6e0542.webp 760w,
               /post/201804-istio-achilles-heel/images/referencedAttributes_hu377a931b69ea3cea13d10aeeddc2f034_72000_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201804-istio-achilles-heel/images/referencedAttributes_hu377a931b69ea3cea13d10aeeddc2f034_72000_ff8e36d64dcc619e43ed98f5f700c1c2.webp&#34;
               width=&#34;760&#34;
               height=&#34;268&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;再假设envoy在处理traffic请求时，从请求中提取出5个属性，这五个属性中a/b/c是三个adapter分别使用到的属性，然后e/f两个属性当前没有adapter使用（实际情况属性会远比这个复杂，提取的属性有十几二十，其中有更多的属性不被adapter使用）。&lt;/p&gt;
&lt;p&gt;在这个请求应答模型中，注意envoy是不能提前知道adapter要哪些属性的，因此只能选择全部属性提交。按照通常的缓存设计思路，我们应该将输入作为key，输出作为value。但是，如果我们将“a=1,b=2,c=3,e=0,f=0”作为key时，我们会发现，当e/f两个属性发生变化时，产生的新key “a=1,b=2,c=3,e=1,f=1”/“a=1,b=2,c=3,e=3,f=4”/“a=1,b=2,c=3,e=10,f=30” 对应的value会大量的重复，而这些属性值的变化对于adapter来说完全没有意义：e/f两个属性根本不被adapter使用。&lt;/p&gt;
&lt;p&gt;因此，Istio在设计mixer cache时，选择了一个特殊方式来处理缓存的key：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在mixer的response中，返回adapter使用到的属性名，在这个例子中就是&amp;quot;a/b/c&amp;quot;。&lt;/li&gt;
&lt;li&gt;envoy在收到response之后，检查这个使用的属性列表，发现只有&amp;quot;a/b/c&amp;quot;三个属性被adapter使用&lt;/li&gt;
&lt;li&gt;envoy在缓存这个应答结果时，会选择将属性列表简化为只有adapter使用的属性，如“a=1,b=2,c=3”&lt;/li&gt;
&lt;li&gt;因此mixer在构建缓存项时，可以就针对简化后的属性进行hash计算，mixer中将此称为签名&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;这些被adapter使用的属性在Check 方法的response中以 referencedAttributes 字段表示。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这样缓存的key的数量就大为减少，否则每次提交的key有十几二十个，有些属性的值还每次都变化如request.id。如果不进行这样的优化，则缓存根本无从谈起。&lt;/p&gt;
&lt;h3 id=&#34;缓存的保存和查找方式&#34;&gt;缓存的保存和查找方式&lt;/h3&gt;
&lt;p&gt;经过 referencedAttributes 字段的优化之后，输入的属性就被简化为“a=1,b=2,c=3”，然后envoy将保存这个输入到缓存中：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;envoy将记录mixer关注&amp;quot;a/b/c&amp;quot;这样一组属性组合（注意会不止一组）&lt;/li&gt;
&lt;li&gt;envoy将“a=1,b=2,c=3”这个实际被使用的属性值进行签名（理解为某种hash算法）得到缓存的key&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;缓存保存之后，envoy在处理后面的请求，如“a=1,b=2,c=3,e=1,f=1”/“a=1,b=2,c=3,e=3,f=4”/“a=1,b=2,c=3,e=10,f=30” 这三个请求时，就会尝试从缓存中查找：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;envoy会先根据保存的被关注属性组合，看请求是否命中，比如这里的&amp;quot;a/b/c&amp;quot;属性组合就可以匹配这三个请求。&lt;/li&gt;
&lt;li&gt;然后根据&amp;quot;a/b/c&amp;quot;组合简化请求的属性为“a=1,b=2,c=3”，再进行签名计算&lt;/li&gt;
&lt;li&gt;然后再以计算得到的签名为key在缓存中查找。&lt;/li&gt;
&lt;li&gt;如果找到，返回缓存结果。如果没有找到，继续发送请求到mixer，然后保存得到的response到缓存中&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这就是mixer cache的工作原理，而实际上，mixer cache的实现细节远比这里描述的复杂，有很多细节如absence key，有效时间，有效使用次数，匹配方式的优化。理论上说，有了这么一个明显是精心设计的mixer cache的加持，Istio中mixer和sidecar分离造成的性能问题得以解决，而mixer从sidecar拆分出来带来的架构优势就更加明显。&lt;/p&gt;
&lt;p&gt;就如图中，英勇无敌的阿克琉斯，手持盾牌，就不惧箭雨。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201804-istio-achilles-heel/images/achilles_huce0c918345268ec1d6a2f59ee54a4850_228915_4176e35b22478a51dddc061ac2b1683b.webp 400w,
               /post/201804-istio-achilles-heel/images/achilles_huce0c918345268ec1d6a2f59ee54a4850_228915_459af1f450514609ed76a0dc233d0c42.webp 760w,
               /post/201804-istio-achilles-heel/images/achilles_huce0c918345268ec1d6a2f59ee54a4850_228915_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201804-istio-achilles-heel/images/achilles_huce0c918345268ec1d6a2f59ee54a4850_228915_4176e35b22478a51dddc061ac2b1683b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：后面会单独出一个系列文章，详细介绍mixer cache的工作机制，外加源码分析。在本文中我尽量简化以便聚焦我们的关注点。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;mixer缓存的问题&#34;&gt;Mixer缓存的问题&lt;/h2&gt;
&lt;p&gt;有了这个知识作为背景，我们开始本文的正题：这个mixer缓存的问题在哪里？&lt;/p&gt;
&lt;p&gt;我们将关注点放在这里：“a=1,b=2,c=3”。这是经过简化之后的实际被adapter使用的属性名和属性值的表示，表示这里有三个属性以及他们的当前值。&lt;/p&gt;
&lt;h3 id=&#34;缓存总数的计算&#34;&gt;缓存总数的计算&lt;/h3&gt;
&lt;p&gt;我们给出一个简单的场景：如果a/b/c三个属性的取值范围都固定为100个，那么，envoy中的mixer cache理论上最多有多少缓存项？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201804-istio-achilles-heel/images/cache-account_hu10b23d26b2fa1e4d1db922dfd6ca0478_91962_78197f8183c108a2df77e9b84cfc73b6.webp 400w,
               /post/201804-istio-achilles-heel/images/cache-account_hu10b23d26b2fa1e4d1db922dfd6ca0478_91962_f06bdb3427ab2cf61b1e863911670327.webp 760w,
               /post/201804-istio-achilles-heel/images/cache-account_hu10b23d26b2fa1e4d1db922dfd6ca0478_91962_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201804-istio-achilles-heel/images/cache-account_hu10b23d26b2fa1e4d1db922dfd6ca0478_91962_78197f8183c108a2df77e9b84cfc73b6.webp&#34;
               width=&#34;760&#34;
               height=&#34;231&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;相信这么简单的问题难不倒大家，我们很容易的得到答案：Mixer Cache的数量=属性a的取值数量 * 属性b的取值数量 * 属性c的取值数量 = 100 * 100 * 100 = 100万。从数学的角度说，是每个取值范围的笛卡尔乘积。&lt;/p&gt;
&lt;p&gt;有没有发现这个缓存数量总数有点夸张？明明是3个属性的取值范围都只有100这么小，为何直接膨胀变成100万？&lt;/p&gt;
&lt;p&gt;我们对比一下，如果缓存不是存放在envoy一侧，而是存放在Mixer中，让每个adapter各自缓存自家的处理结果。那得到的缓存总数会是如何？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201804-istio-achilles-heel/images/cache-account2_hudfb5a0b9a9158f9be41f7a9e4a10ac71_95744_49a9ae41dfa4a4834707ffeb28718f6e.webp 400w,
               /post/201804-istio-achilles-heel/images/cache-account2_hudfb5a0b9a9158f9be41f7a9e4a10ac71_95744_431870e966e313f269c385d2f8b650d9.webp 760w,
               /post/201804-istio-achilles-heel/images/cache-account2_hudfb5a0b9a9158f9be41f7a9e4a10ac71_95744_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201804-istio-achilles-heel/images/cache-account2_hudfb5a0b9a9158f9be41f7a9e4a10ac71_95744_49a9ae41dfa4a4834707ffeb28718f6e.webp&#34;
               width=&#34;760&#34;
               height=&#34;266&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是小学二年级的数学题了，总数=100+100+100=300，和前面的100万差异巨大。&lt;/p&gt;
&lt;p&gt;为什么会有这么大的差异？根据在于计算方式，当缓存在Mixer一侧时，缓存总数是各个adapter缓存的总数，也就是每个属性数量的简单相加。而当缓存在Mixer一侧时，缓存总数是每个属性取值数量的笛卡尔乘积。&lt;/p&gt;
&lt;h3 id=&#34;为何不能把缓存放mixer&#34;&gt;为何不能把缓存放Mixer？&lt;/h3&gt;
&lt;p&gt;从上面的计算我们可以看到，当缓存在mixer一侧时，缓存数量是简单相加，只要不出现单个缓存数量过大，总和就不会离谱。多几个属性，如果取值范围只是几个，几十，甚至几百，几千也不会对结果有任何实质性的影响。&lt;/p&gt;
&lt;p&gt;而当缓存放在envoy一侧时，由于算法从各项和变成了各项的笛卡尔乘积，导致数量急剧增加，甚至有些本来取值范围非常小的属性，哪怕只是个位数，也会因为乘法的原因，*2 *3 *10 *100 导致最终总数量爆炸性膨胀。&lt;/p&gt;
&lt;p&gt;两相对比，将缓存放在mixer一侧，从缓存的角度上说毫无疑问是更好的选择。但是，在Istio的架构设计中，明确的要求Mixer和Envoy划分开，将Envoy归为数据平面，而Mixer归为控制平面。在具体实现上，Envoy是重用原有项目，Mixer是全新编写。在编程语言上，Envoy是c++，而Mixer是Golang。&lt;/p&gt;
&lt;p&gt;以上种种，一步一步演进，终于造就了我们目前不得不面对的尴尬局面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;要明确划分数据平面和控制平面的界限，Mixer就必须独立于Envoy&lt;/li&gt;
&lt;li&gt;Mixer和Envoy之间就变成了远程访问，存在性能瓶颈&lt;/li&gt;
&lt;li&gt;为了解决性能问题，避免远程访问，就需要将cache加在envoy一侧&lt;/li&gt;
&lt;li&gt;然后就不得不面对缓存总数呈现笛卡尔乘积的威胁&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;或者说，只要Istio不重新规划数据平面和控制平面的界限，不将Mixer的功能移到sidecar，此问题，貌似就无解？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TBD: 这个结论暂时只是我的个人理解，需要等待大家讨论和分析，给出权威的结论之后根据讨论情况更新。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;问题严重程度&#34;&gt;问题严重程度&lt;/h2&gt;
&lt;p&gt;然而，并非所有的问题都一定需要解决，如果问题不造成不可接受的影响，也未尝不能接受。&lt;/p&gt;
&lt;h3 id=&#34;缓存数量的影响&#34;&gt;缓存数量的影响&lt;/h3&gt;
&lt;p&gt;我们重新回到问题所在，让我们来评估一下，在实际的使用中，这个缓存数量是否真有膨胀到不可忍受的地步。计算公式：&lt;/p&gt;
&lt;p&gt;&lt;u&gt;Mixer Cache的数量=各个引用属性取值数量的笛卡尔乘积&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;要控制缓存总数，有两个思路：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;控制引用属性的个数：也就是别开启太多的adapter，或者别开启那些使用多个属性的adapter。这条路很难行得通，因为开启哪些adapter是由功能需求决定的，如果担心缓存数量太多就不开启，未免有些&amp;hellip;&amp;hellip;&lt;/li&gt;
&lt;li&gt;控制引用属性的取值范围：尽量不要用取值范围较大的属性，绝对要躲开那些危险的属性比如每次都变化的 &lt;code&gt;request.id&lt;/code&gt;，这条路同样不容易，要对adapter和它使用的属性有明确的了解和控制&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;也就是说，从此之后，在使用mixer的adapter时，最好检查一下这些adapter使用了哪些属性，这些属性的可能取值范围，大致评估一下缓存的理论最大总量。如果自己开发adapter，那么在使用属性时也要特别谨慎。&lt;/p&gt;
&lt;h3 id=&#34;lru的帮助&#34;&gt;LRU的帮助&lt;/h3&gt;
&lt;p&gt;Mixer Cache的实现，是基于LRU算法。所以，对于单个属性，如果取值范围非常大，但是分布集中，则LRU算法可以帮助我们，缓存大部分经常使用的项，少数偶尔出现的项无法命中对全局的影响也不止于太大。&lt;/p&gt;
&lt;p&gt;Mixer的缓存可以通过在构造cache时传递的option对象来设置最大缓存数量，配合LRU算法来平衡缓存数量和命中率。&lt;/p&gt;
&lt;p&gt;不过这里也有个限制，因为mixer的缓存key是需要计算所有被使用的属性的。因此，即便有一个分布很集中的理想属性，但是如果还有其他值域变化的属性参与签名计算，则计算结果将无法再保持分布集中。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;鸣谢Hu Yusuo同学在讨论中针对此处给出的说明。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;缓存其他设置的影响&#34;&gt;缓存其他设置的影响&lt;/h3&gt;
&lt;p&gt;Mixer缓存还有有效时间和有效使用次数的设置，这会进一步削弱缓存的使用效果。如果强调加强缓存减少对mixer的调用，则需要修改这两个的配置。&lt;/p&gt;
&lt;h3 id=&#34;属性的风险系数分析&#34;&gt;属性的风险系数分析&lt;/h3&gt;
&lt;p&gt;简单分析了一下现有属性词汇中各个属性的危险程度：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;属性名&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;source.user&lt;/td&gt;
&lt;td&gt;请求的直接发送者的身份，由mTLS验证&lt;/td&gt;
&lt;td&gt;取决于user的数量，会让总数*N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;destination.ip&lt;/td&gt;
&lt;td&gt;服务器IP地址&lt;/td&gt;
&lt;td&gt;如果目标服务有很多实例，那么这里的取值范围就会变大，比如几十上百&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;request.headers&lt;/td&gt;
&lt;td&gt;HTTP 请求 headers. 对于 gRPC, 则是它的 metadata.&lt;/td&gt;
&lt;td&gt;取决于具体的header名称，会让总数*N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;request.id&lt;/td&gt;
&lt;td&gt;请求的ID，具有统计上较低的碰撞概率。&lt;/td&gt;
&lt;td&gt;绝对不能使用！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;request.path&lt;/td&gt;
&lt;td&gt;HTTP URL 路径，包括 query string&lt;/td&gt;
&lt;td&gt;非常危险，尤其query string包含参数时&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;request.host&lt;/td&gt;
&lt;td&gt;HTTP/1.x host header 或者 HTTP/2 authority header.&lt;/td&gt;
&lt;td&gt;取决于服务器端实例的个数，会让总数*N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;request.method&lt;/td&gt;
&lt;td&gt;HTTP method.&lt;/td&gt;
&lt;td&gt;数量不多，但也会让总数*N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;request.referer&lt;/td&gt;
&lt;td&gt;HTTP referer header.&lt;/td&gt;
&lt;td&gt;非常危险，尤其客户从外部地址直接进入时，可能会有非常多的取值可能性&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;request.scheme&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;数量不多，但也会让总数*N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;request.size&lt;/td&gt;
&lt;td&gt;以字节计算的请求大小。对于HTTP请求，等同于Content-Length header.&lt;/td&gt;
&lt;td&gt;非常危险，除非请求的大小非常固定&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;request.time&lt;/td&gt;
&lt;td&gt;目的地接收到请求的时间戳。这等同于Firebase &amp;ldquo;now&amp;rdquo;.&lt;/td&gt;
&lt;td&gt;绝对不能使用！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;request.useragent&lt;/td&gt;
&lt;td&gt;HTTP User-Agent header.&lt;/td&gt;
&lt;td&gt;数量不多，但也可能有多个值，也会让总数*N&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;connection.id&lt;/td&gt;
&lt;td&gt;对于一条连接，在最后一次Report()之后，目的地服务在此连接上接收到的字节数量&lt;/td&gt;
&lt;td&gt;绝对不能使用！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;connection.received.bytes_total&lt;/td&gt;
&lt;td&gt;在连接的生命周期中，目的地服务接收到的全部字节数量&lt;/td&gt;
&lt;td&gt;绝对不能使用！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;connection.sent.bytes&lt;/td&gt;
&lt;td&gt;对于一条连接，在最后一次Report()之后，目的地服务在此连接上发送的字节数量&lt;/td&gt;
&lt;td&gt;绝对不能使用！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;connection.sent.bytes_total&lt;/td&gt;
&lt;td&gt;在连接的生命周期中，目的地服务发送的全部字节数量&lt;/td&gt;
&lt;td&gt;绝对不能使用！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;connection.duration&lt;/td&gt;
&lt;td&gt;连接打开的时间总数量&lt;/td&gt;
&lt;td&gt;绝对不能使用！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;context.time&lt;/td&gt;
&lt;td&gt;Mixer 操作的时间戳.&lt;/td&gt;
&lt;td&gt;绝对不能使用！&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;api.operation&lt;/td&gt;
&lt;td&gt;用于辨别操作的唯一字符串。在特定的&lt;code&gt;&amp;lt;service, version&amp;gt;&lt;/code&gt; 描述的所有操作中，这个ID是唯一的。&lt;/td&gt;
&lt;td&gt;取决于操作的数量，会让总数*N&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;adapter的风险系数分析&#34;&gt;Adapter的风险系数分析&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;TBD：稍后更新，需要逐个检查现有的adapter，看看会使用哪些属性，以及这些属性可能的取值数量。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;对于istio，在使用时，需要留意adapter使用的属性，以避免mixer cache数量过大的风险。&lt;/p&gt;
&lt;p&gt;对于每个adapter，每个使用到的属性，以及这些属性的每一个可能的取值，都会让笛卡尔乘积的结果放大。而上面列出来的被标注为“绝对不能使用！”的属性，则是一个一个的致命点，务必小心谨慎。&lt;/p&gt;
&lt;h2 id=&#34;讨论和反馈&#34;&gt;讨论和反馈&lt;/h2&gt;
&lt;p&gt;TBD：等收集后整理更新&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;在前几日偶然间发现这个问题存在的可能性之后，我便有些为难，因为我无法确认这个问题的严重程度，也许只是皮肉之痒忍忍就过去了，也许真是致命弱点。而如前面推断的，如果问题成立，则矛头直指Istio的架构设计，这是一个非常严肃的质疑，以至于我在写下此文之后，深感压力。&lt;/p&gt;
&lt;p&gt;郑重申明：我保留因为才疏学浅能力不足造成错误判断从而修改/撤回本文的一切权力。此文只求为进一步深入讨论提供一个基础，可以描述清楚问题和可能的疑虑，欢迎参与技术讨论。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Service Mesh架构反思：数据平面和控制平面的界线该如何划定？</title>
      <link>https://skyao.net/post/201804-servicemesh-architecture-introspection/</link>
      <pubDate>Fri, 20 Apr 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201804-servicemesh-architecture-introspection/</guid>
      <description>&lt;p&gt;苦等一年，始终不见Istio的性能有实质性提升，失望之余，开始反思Istio而至Service Mesh的架构。焦点所在：proxy到底该做哪些事情？架构的优美和性能的实际表现该如何平衡？&lt;/p&gt;
&lt;h2 id=&#34;问题所在&#34;&gt;问题所在&lt;/h2&gt;
&lt;p&gt;Istio的性能，从去年5月问世以来，就是一块心病。&lt;/p&gt;
&lt;p&gt;前段时间Istio 0.7.1版本发布，不久我们得到了这个一个&amp;quot;喜讯&amp;quot;：Istio的性能在0.7.1版本中得到了大幅提升！&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201804-servicemesh-architecture-introspection/images/istio-performance-result_huafc1c78dd63586ad66d7bc4f105146aa_34185_07999e3ca9ca568dd37830b6d089f5b4.webp 400w,
               /post/201804-servicemesh-architecture-introspection/images/istio-performance-result_huafc1c78dd63586ad66d7bc4f105146aa_34185_14d8e08f40f9d0accc37a6b5c9e3fae5.webp 760w,
               /post/201804-servicemesh-architecture-introspection/images/istio-performance-result_huafc1c78dd63586ad66d7bc4f105146aa_34185_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201804-servicemesh-architecture-introspection/images/istio-performance-result_huafc1c78dd63586ad66d7bc4f105146aa_34185_07999e3ca9ca568dd37830b6d089f5b4.webp&#34;
               width=&#34;731&#34;
               height=&#34;256&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最大QPS从0.5.1的700，到0.6.0的1000，再到0.7.1的1700，纵向比较Istio最近的性能提升的确不错，都2.5倍性能了。&lt;/p&gt;
&lt;p&gt;但是，注意，QPS &lt;strong&gt;700/1000/1700&lt;/strong&gt;。是的，没错，你没有看错，没有漏掉一个零或者两个零。&lt;/p&gt;
&lt;p&gt;稍微回顾一下近年中有自己有实际感受的例子：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;几个月之前写了一个基于netty4.1的HTTP转发的demo，没做任何优化和调教，轻松10万+的QPS&lt;/li&gt;
&lt;li&gt;两年前写的dolphin框架，gRPC直连，15万QPS轻松做到&lt;/li&gt;
&lt;li&gt;然后，白衣和隔壁老王两位同学轻描淡写的好像说过，OSP极致性能过了20万QPS了（背景补充：OSP是唯品会的服务化框架，sidecar模式，它的Proxy是被大家诟病以慢著称的Java）。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;当然Istio测试场景稍微复杂一些，毕竟不是空请求，但是如论如何，从QPS十几二十万这个级别，直落到QPS一两千，中间有几乎100倍的差距。这个差距未免有些太大，从实用性上说，2000级别的QPS，低了点。&lt;/p&gt;
&lt;p&gt;反思的第一个怀疑对象是proxy转发性能，但是随即否决：多了proxy肯定会有影响，但是远不至于此。而且，唯品会的OSP，还有华为的Service Mesher的性能表现也说明了问题不是出在proxy转发上。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：关于proxy可能带来的性能开销，在之前的文章 &lt;a href=&#34;../201802-dreammesh-brainstorm-cost/&#34;&gt;DreamMesh抛砖引玉(6)-性能开销&lt;/a&gt; 一文中曾经有过详细的分析，可以参考。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;背景回顾&#34;&gt;背景回顾&lt;/h2&gt;
&lt;p&gt;Istio的性能问题其实由来已久，很早就暴露，官方也为此做了改进，我们现在看到的 700/1000/1700 已经是改进之后的结果。&lt;/p&gt;
&lt;p&gt;今天来好好聊下这个问题，这涉及到Istio的架构设计，甚至涉及到Service Mesh的演进过程。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注：关于Service Mesh的演进过程，在之前的演讲 &lt;a href=&#34;../../publication/service-mesh-next-generation-microservice/&#34;&gt;DreamMesh抛砖引玉(6)-性能开销&lt;/a&gt; 。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Service Mesh刚出现时，以Linkerd/Envoy为代表:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201804-servicemesh-architecture-introspection/images/ppt-26_huc5c50923cd72b19afdd4a735657820ea_97718_7981c6a5ff97ff757601e30a227ea003.webp 400w,
               /post/201804-servicemesh-architecture-introspection/images/ppt-26_huc5c50923cd72b19afdd4a735657820ea_97718_d573f8195366c18df990a44f6980e445.webp 760w,
               /post/201804-servicemesh-architecture-introspection/images/ppt-26_huc5c50923cd72b19afdd4a735657820ea_97718_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201804-servicemesh-architecture-introspection/images/ppt-26_huc5c50923cd72b19afdd4a735657820ea_97718_7981c6a5ff97ff757601e30a227ea003.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这时的service mesh，主要是以proxy/sidecar的形式出现，功能基本都在sidecar中（linkerd有个named的模块分出了部分功能）。请求通过sidecar转发，期间发生的各种检查/判断/操作，都是在sidecar中进行。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201804-servicemesh-architecture-introspection/images/ppt-8_hu1103fbddc50cb88e27d058eae70a6adb_108719_5bddaac61a546e978302b8eb0c4fc716.webp 400w,
               /post/201804-servicemesh-architecture-introspection/images/ppt-8_hu1103fbddc50cb88e27d058eae70a6adb_108719_7cc25a1e7d20b1ee40be204d300aa367.webp 760w,
               /post/201804-servicemesh-architecture-introspection/images/ppt-8_hu1103fbddc50cb88e27d058eae70a6adb_108719_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201804-servicemesh-architecture-introspection/images/ppt-8_hu1103fbddc50cb88e27d058eae70a6adb_108719_5bddaac61a546e978302b8eb0c4fc716.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;因此，从性能上说，与客户端/服务器端直接连接相比，做的事情基本一致，只是多了proxy转发的开销。而这个开销，与服务器端业务处理的开销相比，非常小，大多数情况下是可以忽略的。&lt;/p&gt;
&lt;p&gt;然后Service Mesh演进到了第二代，Istio出现，和后面紧跟的Conduit。这个时候，在第一代的基础上，Service Mesh开始在对系统的掌控上发力，控制平面由此诞生：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201804-servicemesh-architecture-introspection/images/ppt-29_huddfd1b56a9efab2b964e97dfde815108_160654_61c3075a5ea0ad90ab869b2c4385633b.webp 400w,
               /post/201804-servicemesh-architecture-introspection/images/ppt-29_huddfd1b56a9efab2b964e97dfde815108_160654_61b8e3c48bd86d03ffb8d096532f44e3.webp 760w,
               /post/201804-servicemesh-architecture-introspection/images/ppt-29_huddfd1b56a9efab2b964e97dfde815108_160654_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201804-servicemesh-architecture-introspection/images/ppt-29_huddfd1b56a9efab2b964e97dfde815108_160654_61c3075a5ea0ad90ab869b2c4385633b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;控制平面的加入，是一个非常令人兴奋的事情，因为带来了太多的实用型的功能，istio因此备受关注和推崇，随后紧跟Istio脚步的Conduit也沿用了这套架构体系：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201804-servicemesh-architecture-introspection/images/ppt-31_huc5a436dd846bdf1d5aec0eb89381d4eb_164904_ea41ea39ac909a470b0f41b981da6f6f.webp 400w,
               /post/201804-servicemesh-architecture-introspection/images/ppt-31_huc5a436dd846bdf1d5aec0eb89381d4eb_164904_de87cbe135f3da8546c7754577a716c4.webp 760w,
               /post/201804-servicemesh-architecture-introspection/images/ppt-31_huc5a436dd846bdf1d5aec0eb89381d4eb_164904_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201804-servicemesh-architecture-introspection/images/ppt-31_huc5a436dd846bdf1d5aec0eb89381d4eb_164904_ea41ea39ac909a470b0f41b981da6f6f.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在这个架构当中，控制平面的三大模块，其中的Pilot和Auth都不直接参与到traffic的处理流程，因此他们不会对运行时性能产生直接影响。&lt;/p&gt;
&lt;p&gt;需要审视的是，需要参与到traffic流程的Mixer模块，请注意上图中，从envoy到mixer的两个箭头，这代表着两次调用，而且是两次远程调用。下面这个图，可以看的更清楚一些：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201804-servicemesh-architecture-introspection/images/arch_hue9e188093afc6c678dc6c9276be33bbf_96018_c95a771e47ef2b4b845e98134784e9b9.webp 400w,
               /post/201804-servicemesh-architecture-introspection/images/arch_hue9e188093afc6c678dc6c9276be33bbf_96018_9eb313e2f2b2471ae51a111e5bfa8a11.webp 760w,
               /post/201804-servicemesh-architecture-introspection/images/arch_hue9e188093afc6c678dc6c9276be33bbf_96018_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201804-servicemesh-architecture-introspection/images/arch_hue9e188093afc6c678dc6c9276be33bbf_96018_c95a771e47ef2b4b845e98134784e9b9.webp&#34;
               width=&#34;760&#34;
               height=&#34;425&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;mixer的职责&#34;&gt;Mixer的职责&lt;/h2&gt;
&lt;p&gt;我们直接搬出mixer官方文档对mixer的介绍：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://istio.io/docs/concepts/policy-and-control/mixer.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://istio.io/docs/concepts/policy-and-control/mixer.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Mixer 提供三个核心功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;前提条件检查&lt;/strong&gt;。在响应来自服务调用者的传入请求之前，使得调用者能够验证许多前提条件。允许服务在响应来自服务消费者的传入请求之前验证一些前提条件。前提条件可以包括服务使用者是否被正确认证，是否在服务的白名单上，是否通过ACL检查等等。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配额管理&lt;/strong&gt;。 使服务能够在多个维度上分配和释放配额，当服务消费者对有限的资源发生抢占时，配额就成了一种有效的资源管理工具，它为服务之间的资源抢占提供相对的公平。频率控制就是配额的一个实例。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;遥测报告&lt;/strong&gt;。使服务能够上报日志和监控。在未来，它还将启用针对服务运营商以及服务消费者的跟踪和计费流。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然后，最关键的的是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;这些机制的应用是基于一组&lt;a href=&#34;http://istio.doczh.cn/docs/concepts/policy-and-control/attributes.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;属性&lt;/a&gt;的，每个请求都会将这些属性呈现给Mixer。在Istio中，这些属性是由对Sidecar代理（一般是Envoy）的每一次请求产生的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;也就是说，为了让mixer能够工作，就需要envoy从每次请求中获取信息，然后发起两次对mixer的请求：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在转发请求之前：这时需要做前提条件检查和配额管理，只有满足条件的请求才会做转发&lt;/li&gt;
&lt;li&gt;在转发请求之后：这时要上报日志等，术语上称为遥感信息，&lt;strong&gt;Telemetry&lt;/strong&gt;，或者&lt;strong&gt;Reporting&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;设计初衷&#34;&gt;设计初衷&lt;/h2&gt;
&lt;p&gt;继续搬运官方文档：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;后端基础服务为构建的服务提供各种支持功能。这些功能包括访问控制系统、计量收集捕获系统、配额执行系统、计费系统等。传统服务会直接和这些后端系统打交道，与后端紧密耦合，并集成其中的个性化语义和用法。&lt;/p&gt;
&lt;p&gt;Mixer在应用程序代码和基础架构后端之间提供通用中介层。它的设计将策略决策移出应用层，用运维人员能够控制的配置取而代之。应用程序代码不再将应用程序代码与特定后端集成在一起，而是与Mixer进行相当简单的集成，然后Mixer负责与后端系统连接。&lt;/p&gt;
&lt;p&gt;Mixer的设计目的是改变层次之间的边界，以此来降低总体的复杂性。从服务代码中剔除策略逻辑，改由运维人员进行控制。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;非常优秀的设计，从系统架构上没得说，解开应用和后端基础设施的耦合，好处多多，这也是我们爱Istio的重要理由。&lt;/p&gt;
&lt;p&gt;但是，注意，这段文字解释的是：为什么要将这些功能从应用里面搬出来放进去service mesh和mixer。这点我举双手赞成，而我的疑问在于：这些逻辑从应用中移动到service mesh之后，为什么要放mixer中，而不是proxy？&lt;/p&gt;
&lt;p&gt;这就涉及到第二代service mesh的核心设计了：原有的sidecar被归结为data plane，然后在data plane上增加control plane。那么，最最重要的设计问题就来了，在这个架构中，从职责分工和部署上：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;data plane和control plane的界限在哪里？&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;istio的选择&#34;&gt;Istio的选择&lt;/h2&gt;
&lt;p&gt;当前，istio在这个问题上，选择的是非常理想化的划分方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;data plane 只负责转发，其中部分数据来自Pilot和Auth。&lt;/li&gt;
&lt;li&gt;和后端基础设施相关的功能放置在mixer中，通过各种adapter实现&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个方式架构清晰，职责分明，在不考虑性能时，无可挑剔。&lt;/p&gt;
&lt;p&gt;再考虑到Istio的背景，Istio项目启动时:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;envoy已经基本成熟。这样istio的data plane直接有现成的一个基础，在这个基础上新加control plane，合乎情理。&lt;/li&gt;
&lt;li&gt;新写的control plane用golang编写，也是符合情理，毕竟中间件用go是个潮流，加上是google自己的产品。&lt;/li&gt;
&lt;li&gt;同时envoy是基于c++的，写各种很具体很繁琐的外围功能未免有些难受，比如mixer中和各种后端打交道的adapter。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所有，在我看来，istio当时选择现在这样一个架构，合乎情理，也比较自然。&lt;/p&gt;
&lt;p&gt;只是，选择这个方式之后，有些问题就无可回避：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为了在请求处理过程中调用到mixer，就只得在转发前后发起两次对mixer的调用&lt;/li&gt;
&lt;li&gt;由于envoy是c++，新的mixer是go，独立部署&lt;/li&gt;
&lt;li&gt;导致，这两次调用， 都是远程调用，而且也不是localhost的本地调用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这样一来，性能开销就无可避免。Istio去年5月出来之后，就被发现性能非常糟糕，比现在的QPS 700/1000/1700 还要糟糕很多。&lt;/p&gt;
&lt;p&gt;##Istio的改进&lt;/p&gt;
&lt;p&gt;之后，Istio给出了一个改良的方案：在envoy中增加mixer filter。这个Filter和控制面的Mixer组件进行通讯，完成策略控制和遥测数据收集功能。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201804-servicemesh-architecture-introspection/images/mixer-filter_hu46896fb870bc20327badea56a97dcee0_120924_dc3af9357266283a0706a13dee2bf112.webp 400w,
               /post/201804-servicemesh-architecture-introspection/images/mixer-filter_hu46896fb870bc20327badea56a97dcee0_120924_dcbbee58a0e0840bd5dabf9c2155f49a.webp 760w,
               /post/201804-servicemesh-architecture-introspection/images/mixer-filter_hu46896fb870bc20327badea56a97dcee0_120924_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201804-servicemesh-architecture-introspection/images/mixer-filter_hu46896fb870bc20327badea56a97dcee0_120924_dc3af9357266283a0706a13dee2bf112.webp&#34;
               width=&#34;760&#34;
               height=&#34;528&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;关键之处，在于增加了缓存：&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Mixer Filter中保存有策略判断所需的数据缓存，因此大部分策略判断在Envoy中就处理了，不需要发送请求到Mixer。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;另外Envoy收集到的遥测数据会先保存在Envoy的缓存中，每隔一段时间再通过批量的方式上报到Mixer。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;从官方博客  &lt;a href=&#34;https://istio.io/blog/2017/mixer-spof-myth.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Mixer and the SPOF Myth&lt;/a&gt; 给出的信息看，这里的缓存实现还做的很周到，甚至实现了两级缓存：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34;
           src=&#34;https://skyao.net/post/201804-servicemesh-architecture-introspection/images/mixer-spof-myth-2.svg&#34;
           loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;缓存的工作方式如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Sidecar 中包含本地缓存，一大部分的前置检查可以通过缓存来进行。&lt;/li&gt;
&lt;li&gt;另外，sidercar 会把待发送的指标数据进行缓冲，这样可能在几千次请求之后才调用一次 Mixer。&lt;/li&gt;
&lt;li&gt;前置检查和请求处理是同步的&lt;/li&gt;
&lt;li&gt;指标数据上送是使用 fire-and-forget 模式异步完成的。&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;从描述上看非常令人满意，如果这个方式实现了，那么Mixer带来的性能瓶颈应该可以解决。但是，对照一下时间，这个博客发表于2017年12月，在这之后的小半年，istio的性能还是徘徊在 QPS 700/1000/1700 的水准。&lt;/p&gt;
&lt;p&gt;这里，个人存在几个质疑：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&amp;ldquo;一大部分的前置检查可以通过缓存来进行&amp;rdquo;，大部分？可是只要有一个前置检查不能缓存，就必须去mixer里面请求&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;没有看到任何关于quota的说明。到底quato怎么办？配额按说是没法缓存的，否则配额就不准确了。而一旦需要执行配额管理，还是必须发起请求到mixer&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;envoy中要执行前置检查，不仅仅需要缓存前置检查的各种配置信息，也必须要求envoy有执行前置检查的能力，即原来在mixer中实现前置检查的所有逻辑代码必须在envoy里面再实现一次。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;其中的第三条，会带来一个悖论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果envoy没有把所有的前置检查的代码逻辑都实现一遍，那么走缓存就会造成执行结果和走mixer不一致，这不是一个严谨的做法；&lt;/li&gt;
&lt;li&gt;如果envoy做的足够严谨，保证了envoy的前置检查可以100%覆盖mixer里面的实现，那何苦再保留mixer的前置检查逻辑，去掉就好了，否则维持同一个代码逻辑的两套实现版本&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;TBD: 这几个疑问貌似误解，只能去翻代码了。稍后更新这块内容。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;另一个选择&#34;&gt;另一个选择&lt;/h2&gt;
&lt;p&gt;Istio的选择出发点，我理解是让data plane保持简单，尽可能将其它功能移出来。然而遇到性能问题，终究还是要做妥协，比如cache的出现。&lt;/p&gt;
&lt;p&gt;如果我们放弃proxy最简化的想法，不再将系统架构优美放在第一位，而是将性能放在首位，那么，我们就可以有另外一种选择。&lt;/p&gt;
&lt;p&gt;我们再次审视mixer的三大功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;前置条件检查&lt;/strong&gt;。这个是必须在请求的traffi处理流程中完成的，因为traffic必须等待检查结果来决定下一步的行为，是拒绝请求还是继续转发，必须有明确答案。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;配额管理&lt;/strong&gt;。 同上，必须同步等待结果才能继续。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;遥测报告&lt;/strong&gt;。这个可以优化，两个方式，可以异步提交，可以批量提交，当时实际代码实现时会选择异步＋批量。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;因此，优化的方向很明显，前置条件检查和配额管理都是同步操作，应该移回proxy。遥测可以通过异步＋批量的方式减少对mixer请求的数量级来进行优化。&lt;/p&gt;
&lt;p&gt;但是，对于遥测报告，还有一个重要的考量点：遥测报告涉及到日志等数据提交，如果都集中式的先行提交给mixer，然后mixer再连接后端基础设施，则数据量（尤其批量之后）会集中在mixer这个单点。因此，从性能考虑，遥测报告最好也是proxy直接提交合适。&lt;/p&gt;
&lt;p&gt;按照这个思路，mixer几乎被全部合并回proxy。Istio的架构需要做巨大的调整：control plane只留下Pilot和Auth，在envoy中重新实现一份mixer。&lt;/p&gt;
&lt;p&gt;我不知道Istio会不会有这么大的决心。&lt;/p&gt;
&lt;p&gt;然而，快一年了，istio的性能始终徘徊在一个低的离谱的地步，总该找到某种方式来解决问题，对吧？&lt;/p&gt;
&lt;h2 id=&#34;conduit的选择&#34;&gt;Conduit的选择&lt;/h2&gt;
&lt;p&gt;作为linkerd惨遭istio阻击之后的绝地反击，conduit从出生开始就带有悲剧色彩，强大的对手，小小的团队，不翻盘就等死的处境。&lt;/p&gt;
&lt;p&gt;这种情况下的conduit，在架构上选择了直接吸收istio的优点，因此，istio提出的控制面板conduit几乎照样来了一份。也因此，istio mixer遇到的问题，conduit也没躲过。从这个角度说，istio把自己和conduit都带进坑了。&lt;/p&gt;
&lt;p&gt;本周，带着前面的疑问和担忧，跑去conduit的slack上，简单做了一下交流。得到的答复如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;kl [1:49 AM]
@Sky Ao/敖小剑 thanks for the suggestions! totally agree that the policy stuff should be pushed out asynchronously. and in 0.4.0 we moved telemetry to a setup where prometheus scrapes stat data directly from the proxies themselves, separate from the request path, and no longer reliant on the controller&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;william [4:03 AM]
@Sky Ao/敖小剑 we&amp;rsquo;re looking at ways to push policy into the proxies, rather than polling the controller per requet (and caching). but it&amp;rsquo;s still early. like Kevin says, telemetry is no longer pushed from the proxy in 0.4.0 already&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;也就是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在新发布的0.4.0版本中，遥测报告已经从控制平面移出，现在是从proxy直接走&lt;/li&gt;
&lt;li&gt;未来将会继续将policy的部分移到proxy中（只是现在还没有动）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;可以说，conduit已经意识到坑的存在了，现在一条腿已经拔出来，另外一条腿要拔出来的话还需要一点时间。&lt;/p&gt;
&lt;p&gt;颇感欣慰。&lt;/p&gt;
&lt;h2 id=&#34;其它人的选择&#34;&gt;其它人的选择&lt;/h2&gt;
&lt;p&gt;很早之前，和白衣同学深入讨论这个话题，当时白衣就对mixer的做法有异议，因为性能问题是明摆着的。唯品会的OSP框架，选择的是将功能都在proxy中完成，性能还是有足够的保障。&lt;/p&gt;
&lt;p&gt;近日在群内讨论时，了解到华为的兄弟们从一开始就绕开了这个坑，直接在proxy中实现功能。&lt;/p&gt;
&lt;p&gt;更新：联系到新浪微博的同学，确认motan mesh的做法也是直接做进去proxy的。&lt;/p&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;好多年前，某位同学（依稀是白衣）曾经打过一个比喻，非常生动，大意如下：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;架构师就是艺术家，精心雕刻了一个精美绝伦的花瓶，然后，为了某些考虑，又不得不在花瓶的底下垫了一块板砖&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Service Mesh中数据平面和控制平面的关系，到了该重新认真审视和反思的时候了：花瓶虽美，但是那块板砖，是不是该考虑垫上去了 :)&lt;/p&gt;
&lt;p&gt;未来的一段时间，我们不妨关注istio和conduit对此的选择。&lt;/p&gt;
&lt;h2 id=&#34;脑洞时间&#34;&gt;脑洞时间&lt;/h2&gt;
&lt;p&gt;最后，脑洞一下：如果用go重写proxy，替代envoy，那么mixer里面的功能要搬过来就是轻松自如。&lt;/p&gt;
&lt;p&gt;做这个事情的前提: 是能提供一个go版本的proxy，做到足够好，以便替代envoy的位置。&lt;/p&gt;
&lt;p&gt;感叹一下：如果当年envoy不是用c++，而是用go，事情就完全不一样了。然后，conduit的proxy是rust写的，rust用来实现proxy倒是神器，但是用来写各种adapter，想必也为难。也许，未来我们会见到一个纯go版本的service mesh？&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>DreamMesh服务注册(2)-多集群的难点</title>
      <link>https://skyao.net/post/201804-dreammesh-registry-difficulty/</link>
      <pubDate>Thu, 19 Apr 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201804-dreammesh-registry-difficulty/</guid>
      <description>&lt;p&gt;如果有多集群/多机房的支持需求，该如何解决？&lt;/p&gt;
&lt;p&gt;这个问题和前面列出的service mesh体系和非service mesh的并存问题，可能叠加：如何在多集群/多机房要求下实现service mesh体系和非service mesh的并存。&lt;/p&gt;
&lt;h2 id=&#34;需求&#34;&gt;需求&lt;/h2&gt;
&lt;p&gt;首先看看需求来自哪里：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Service Mesh体系和非Service Mesh体系并存/过渡的需要&lt;/p&gt;
&lt;p&gt;见前文 &lt;a href=&#34;../201802-dreammesh-brainstorm-transition/&#34;&gt;DreamMesh抛砖引玉(3)-艰难的过渡&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;技术栈差异&lt;/p&gt;
&lt;p&gt;不同时期使用的技术栈不同，可能造成有多套集群，比如原有dubbo，现在要转向spring cloud，这样在过渡期间会有两套系统。前面列的第一条可以视为是本条的特例。&lt;/p&gt;
&lt;p&gt;如果公司较大，也会出现不同组织采用不同的技术栈导致出现多个集群。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;测试运维需要&lt;/p&gt;
&lt;p&gt;可能希望在生产环境之外搭建stagging，test等集群，通常是独立运作，但是偶尔会有想法，希望开个口子以便打通若干个服务或者某个实例，来做测试和验证。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;场景&#34;&gt;场景&lt;/h2&gt;
&lt;p&gt;我们要打通的多个微服务集群，情况很复杂，可能是以下多种场景混杂：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;集群可能是Service Mesh体系和非Service Mesh体系&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果是Service Mesh，可能是Istio/Conduit&lt;/li&gt;
&lt;li&gt;如果是非Service Mesh体系，可能是SpringCloud/Dubbo/Motan等&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;网络不同，可能在虚拟网络中如k8s&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;li&gt;
&lt;p&gt;集群可能用于不同的产品部署阶段&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;prod&lt;/li&gt;
&lt;li&gt;stagging&lt;/li&gt;
&lt;li&gt;test&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;难点&#34;&gt;难点&lt;/h2&gt;
&lt;p&gt;需求告诉我们：这个事情有做的价值；而场景则提醒我们：这个事情不简单。&lt;/p&gt;
&lt;p&gt;我们来罗列一下实现中的难点所在：&lt;/p&gt;
&lt;h3 id=&#34;服务注册与服务发现&#34;&gt;服务注册与服务发现&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;备注1：由于篇幅所限，下面列出的只是提纲，详细内容会在后续文章中阐述
备注2：实际上是内容展开之后发现篇幅收不住，内容太长不适合阅读，决定拆开&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;要调用服务，自然需要知道服务在哪里，这涉及到服务注册与服务发现。本集群内只需要知道目标服务实例的IP地址和端口即可，而要跨集群调用服务，事情要变的复杂的多：&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;ul&gt;
&lt;li&gt;要不要支持跨集群的负载均衡?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后，最关键的一点：&lt;strong&gt;各个集群的服务注册模型必须一致或者可以转换为一致&lt;/strong&gt;，这样才能在一个集群中&amp;quot;理解&amp;quot;另一个集群的服务注册信息。&lt;/p&gt;
&lt;h3 id=&#34;sdk必须有能力转发跨集群的请求&#34;&gt;SDK必须有能力转发跨集群的请求&lt;/h3&gt;
&lt;p&gt;在获取目标服务的地址之后，如果发现是远程集群，那就需要解决如何将请求转发到另一个集群的问题。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果网络互通，直接连接就好了&lt;/li&gt;
&lt;li&gt;如果网络不通，那么需要引入特殊机制，来跨集群转发请求，类似反向代理/API Gateway&lt;/li&gt;
&lt;li&gt;SDK要能识别服务实例所在的zone，以及获取配置，看是否需要执行&amp;quot;就近访问&amp;quot;&lt;/li&gt;
&lt;li&gt;如果服务跨多个集群部署+需要跨集群负载均衡，SDK的实现要复杂的多&lt;/li&gt;
&lt;li&gt;如果一个服务在两个集群中采用不同的通讯协议，则还有一个协议转换的过程&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;服务治理必须跨集群通用&#34;&gt;服务治理必须跨集群通用&lt;/h3&gt;
&lt;p&gt;在服务注册机制+SDK的配合之下，现在我们可以做到：&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;/p&gt;
&lt;p&gt;要在各个集群中贯彻一致的服务治理意图，需要解决两个难题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;服务治理的实现不同：有各自的SDK实现&lt;/li&gt;
&lt;li&gt;服务治理的信息不统一：有各自的配置方式，或者设置方法&lt;/li&gt;
&lt;/ol&gt;
</description>
    </item>
    
    <item>
      <title>DreamMesh服务注册(1)-统一模型</title>
      <link>https://skyao.net/post/201804-dreammesh-registry-model/</link>
      <pubDate>Wed, 18 Apr 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201804-dreammesh-registry-model/</guid>
      <description>&lt;p&gt;在前面的讨论中，我们探索了打通多个服务注册中心的思路。另外在服务治理中心的构想，也是希望能提供统一的方式对各家微服务体系进行服务治理。&lt;/p&gt;
&lt;p&gt;而要做到这两点，服务注册模型的统一势在必行。&lt;/p&gt;
&lt;h2 id=&#34;背景回顾&#34;&gt;背景回顾&lt;/h2&gt;
&lt;p&gt;首先回顾一下，需求来自哪里：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Service Mesh体系和非Service Mesh体系并存/过渡的需要&lt;/p&gt;
&lt;p&gt;见前文 &lt;a href=&#34;../201802-dreammesh-brainstorm-transition/&#34;&gt;DreamMesh抛砖引玉(3)-艰难的过渡&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;多集群部署的需要&lt;/p&gt;
&lt;p&gt;见前文 &lt;a href=&#34;../201804-dreammesh-brainstorm-mutiple-cluster/&#34;&gt;DreamMesh抛砖引玉(10)-多集群&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这两个需要迫使我们要想办法打通多个服务注册体系，使得他们可以相互交换数据，从而实现服务跨集群的彼此感知。&lt;/p&gt;
&lt;p&gt;要实现这个想法，需要做到几点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;能够跨集群的交换服务注册数据&lt;/li&gt;
&lt;li&gt;能够理解交换而来的服务注册数据&lt;/li&gt;
&lt;li&gt;SDK有能力根据服务注册数据实现跨集群的请求发送&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我们先来关注第二点：如何让多个服务注册体系彼此理解对方的服务注册数据？&lt;/p&gt;
&lt;h2 id=&#34;模型是关键&#34;&gt;模型是关键&lt;/h2&gt;
&lt;p&gt;每个服务注册体系，都会有自己的服务注册模型，记录服务注册时提交的信息，以便在服务发现时返回。简单的信息如IP，端口告知客户端&amp;quot;我在哪&amp;quot;，复杂一点的则典型如k8s中引入的label，可以实现基于lable的过滤。&lt;/p&gt;
&lt;p&gt;服务注册模型通常都不会太过复杂，尤其是常见的基本信息大体上各家实现上大同小异。&lt;/p&gt;
&lt;p&gt;但是，基本上，每家都是各自设计自己的一套模型，起码目前看不到有任何规范或者协同的迹象。因此，当今天我们试图打通多个服务注册体系时，面临的第一个事情，就是如何统一这些服务注册模型。&lt;/p&gt;
&lt;h3 id=&#34;理想化的模型&#34;&gt;理想化的模型&lt;/h3&gt;
&lt;p&gt;先看看最理想的状态，如果我们能够提炼出一个统一的服务注册模型，然后让自家的服务注册产品都遵循这个统一模型。那我们就能得到一个非常理想的架构：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201804-dreammesh-registry-model/images/unified-model_hu8cbe224c717b9ee7c822a08c33067648_50689_0f598a2986975fbfe9f19afe364a5871.webp 400w,
               /post/201804-dreammesh-registry-model/images/unified-model_hu8cbe224c717b9ee7c822a08c33067648_50689_58e61265a45f9aad7f3041466139a79c.webp 760w,
               /post/201804-dreammesh-registry-model/images/unified-model_hu8cbe224c717b9ee7c822a08c33067648_50689_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201804-dreammesh-registry-model/images/unified-model_hu8cbe224c717b9ee7c822a08c33067648_50689_0f598a2986975fbfe9f19afe364a5871.webp&#34;
               width=&#34;760&#34;
               height=&#34;288&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;当然，自家的底层实现是可以完全不同的，各自发挥，但是最终对外都表现为一个统一的模型。类似于代码里面的interface和类实现，这里就是一个规范模型+各种具体实现。&lt;/p&gt;
&lt;h3 id=&#34;基于统一模型的体系&#34;&gt;基于统一模型的体系&lt;/h3&gt;
&lt;p&gt;有了统一的服务注册模型，上层的注册中心服务，就可以依托于这个统一模型而建立起独立于底层模型和存储实现的服务注册逻辑实现。以及注册中心服务之上的服务治理中心，则可以由此提供实现统一的服务治理功能。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201804-dreammesh-registry-model/images/unified-registry_hue07b6b48d12256bf02f9ddfa3115285e_74975_97bd077c3cadc4b201886d3ebe5320d5.webp 400w,
               /post/201804-dreammesh-registry-model/images/unified-registry_hue07b6b48d12256bf02f9ddfa3115285e_74975_4f9999bdee9892c94b227821955c1b4e.webp 760w,
               /post/201804-dreammesh-registry-model/images/unified-registry_hue07b6b48d12256bf02f9ddfa3115285e_74975_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201804-dreammesh-registry-model/images/unified-registry_hue07b6b48d12256bf02f9ddfa3115285e_74975_97bd077c3cadc4b201886d3ebe5320d5.webp&#34;
               width=&#34;760&#34;
               height=&#34;591&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在这个理想化的体系中，上层服务和UI是独立于底层实现的，通过中间的抽象模型来实现对接。因此，在这个体系中可以自由的选择/替换底层实现。而如果这个抽象的服务注册模型能够成为业界标准，则不同厂商可以分别提供不同组件，客户任意组合依然可以得到一个可工作的系统。&lt;/p&gt;
&lt;p&gt;这是理想化的场景，一切很美好的样子，现在让我们回到现实。&lt;/p&gt;
&lt;h2 id=&#34;模型适配&#34;&gt;模型适配&lt;/h2&gt;
&lt;p&gt;现实中，这个理想化的被大家一致认可并且严格遵循的统一的服务注册模型，是不存在的。&lt;/p&gt;
&lt;p&gt;而且，很残酷的是，即使现在我们能找到并提出一个足够优秀的服务注册模型，业界也未必愿意接受，而说服现在的厂商和开源实现来修改代码适配这个模型，则无异于痴人说梦。&lt;/p&gt;
&lt;p&gt;但是，这并不意味着事情就此打住，无以为继。因为，我们还有一个大杀器，虽然原理简单，虽然了无新意，虽然已经用的烂大街，但是，依然可以解决问题：适配器！&lt;/p&gt;
&lt;p&gt;相信设计模式中Adapter的概念大家都是烂熟于胸的，随便抄一段适配器模式的定义：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;适配器模式将某个类的接口转换成客户端期望的另一个接口表示，主要目的是&lt;strong&gt;兼容性&lt;/strong&gt;，让原本因接口不匹配不能一起工作的两个类可以协同工作。其别名为包装器(Wrapper)。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;dream-registry的构思&#34;&gt;Dream Registry的构思&lt;/h3&gt;
&lt;p&gt;在Dream Mesh体系中，我们的服务注册子项目（项目名  &lt;a href=&#34;https://github.com/dreamfly-io/dream-registry&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dream Registry&lt;/a&gt;）将提供三个原生实现和多种适配器：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201804-dreammesh-registry-model/images/adapters_hu27ac5132796fcfcc1047fec24be50ed0_112447_3c454cf410f532ec21f5bd4162fae256.webp 400w,
               /post/201804-dreammesh-registry-model/images/adapters_hu27ac5132796fcfcc1047fec24be50ed0_112447_4690cd43bc2b38b1d98da8e6e776a71d.webp 760w,
               /post/201804-dreammesh-registry-model/images/adapters_hu27ac5132796fcfcc1047fec24be50ed0_112447_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201804-dreammesh-registry-model/images/adapters_hu27ac5132796fcfcc1047fec24be50ed0_112447_3c454cf410f532ec21f5bd4162fae256.webp&#34;
               width=&#34;760&#34;
               height=&#34;438&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;其中，spring cloud adapter和dubbo adapter将适配到spring cloud和dubbo的服务注册发现，当然这两个框架的服务注册也是支持多种实现，我们将通过访问他们提供的抽象接口如spring cloud的discovery client来实现。&lt;/p&gt;
&lt;p&gt;为了支持主流的service mesh，我们将提供Istio和Conduit的adapter，通过访问Istio的Polit和Conduit的Destination来实现。&lt;/p&gt;
&lt;h3 id=&#34;参考实现&#34;&gt;参考实现&lt;/h3&gt;
&lt;p&gt;坦白说，上述Dream Registry的设计，本身并无过人之处，业界也有很多类似的实现。&lt;/p&gt;
&lt;p&gt;比如Istio的Pilot，其中的Abstract Model和Platform Adapter的设计，就如出一辙：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34;
           src=&#34;https://skyao.net/post/201804-dreammesh-registry-model/images/PilotAdapters.svg&#34;
           loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Spring Cloud和更久远的Dubbo，设计也是类似的方案。&lt;/p&gt;
&lt;h2 id=&#34;优势何在&#34;&gt;优势何在&lt;/h2&gt;
&lt;p&gt;设计上的雷同，一方面说明我们Dream Registry的设计是合乎常理，中规中矩的，可行性没有问题，这是好事；另一方面则是质疑和挑战：我们在今天掏出一个和别人三五年前（甚至dubbo已经是六七年前）的设计雷同的东西，价值何在？&lt;/p&gt;
&lt;p&gt;这是一个无法回避的问题，我对此的回答是：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;更先进的模型&lt;/p&gt;
&lt;p&gt;Dubbo和Spring Cloud提出的服务注册模型，实在是太老了，尤其Spring Cloud，在2015年提出，给出的discovery client定义，却简陋到令人发指！&lt;/p&gt;
&lt;p&gt;Dream Registry的服务注册模型，会向k8s的服务模型靠拢，诸如label和lable filter这样的特性会在Dream Registry中发挥的淋漓尽致。具体实现中，我会尽量参考Istio pilot的Abstract Model，并结合Conduit Destination的设计，给出一个起码令我个人最为满意的服务注册模型（所谓Dream！）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;更广泛的用途&lt;/p&gt;
&lt;p&gt;和Istio pilot的Abstract Model相比，在功能和模型细节可以高度类似的情况下，我更希望将这样一个优秀的服务注册模型用于更加广泛的用途：不限于istio，不限于service mesh，而是在所有需要用到服务注册与发现的场合，甚至有改造spring cloud和dubbo的想法。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;更高的社区认可度&lt;/p&gt;
&lt;p&gt;有一个大胆的想法，由来已久，在Dream Mesh中，我希望能摸索出一条路，证明：一个优秀而统一的服务注册模型，可以帮助我们统一和规范服务注册的行为，并由此规范基于服务注册的各种服务治理功能。&lt;/p&gt;
&lt;p&gt;关于这个思路，曾经和多方讨论，基本上大家觉得还是可行的，虽然在能否统一社区想法和让社区接受上大家觉得难度颇大。但是，本着事在人为的想法，我觉得不妨努力试试。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;篇幅所限，后续很多的细节将在接下来的文章中继续阐述。下一章，我们将聚焦这个服务注册模型的定义。&lt;/p&gt;
&lt;h2 id=&#34;讨论和反馈&#34;&gt;讨论和反馈&lt;/h2&gt;
&lt;p&gt;TBD：等收集后整理更新&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;有兴趣的朋友，请联系我的微信，加入Dream Mesh内部讨论群。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>DreamMesh架构设计(3)-主要模块</title>
      <link>https://skyao.net/post/201804-dreammesh-architecture-module/</link>
      <pubDate>Sun, 15 Apr 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201804-dreammesh-architecture-module/</guid>
      <description>&lt;p&gt;本文将列出规划中的Dream Mesh主要功能模块，给出蓝图，并定好优先级和开发顺序。&lt;/p&gt;
&lt;h2 id=&#34;核心模块&#34;&gt;核心模块&lt;/h2&gt;
&lt;p&gt;在前文 &lt;a href=&#34;../201804-dreammesh-architecture-core/&#34;&gt;DreamMesh架构设计(1)-系统核心&lt;/a&gt; 中，列出了最核心的三个模块。&lt;/p&gt;
&lt;h3 id=&#34;配置中心&#34;&gt;配置中心&lt;/h3&gt;
&lt;p&gt;配置中心包含三大块的内容：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;服务配置（优先级：高）&lt;/li&gt;
&lt;li&gt;业务配置（优先级：中）&lt;/li&gt;
&lt;li&gt;资源配置（优先级：低）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;../201804-dreammesh-architecture-core/images/config-center.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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;定义通用的配置数据访问接口（优先级：高）&lt;/li&gt;
&lt;li&gt;基于ETCD V3的第一个实现版本（优先级：高）&lt;/li&gt;
&lt;li&gt;桥接到其他的配置中心实现（优先级：低）&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;
&lt;p&gt;配置中心服务&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;实现配置中心的业务逻辑（优先级：高）&lt;/li&gt;
&lt;li&gt;对外暴露服务的协议实现
&lt;ul&gt;
&lt;li&gt;gRPC协议（优先级：高）&lt;/li&gt;
&lt;li&gt;REST协议（优先级：低）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;提供的服务接口
&lt;ul&gt;
&lt;li&gt;标准的CRUD接口（优先级：高）&lt;/li&gt;
&lt;li&gt;给应用特别定制的专用接口（优先级：高）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;通过配置数据通用接口访问底层数据（优先级：高）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;控制台/Console&lt;/p&gt;
&lt;ul&gt;
&lt;li&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;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;注册中心&#34;&gt;注册中心&lt;/h3&gt;
&lt;p&gt;注册中心包含两大块：服务注册和服务配置。其中服务配置的实现包含在配置中心的开发中，这里只需要重用代码即可。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;../201804-dreammesh-architecture-core/images/registry-center.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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;定义通用的服务注册数据访问接口（优先级：高）&lt;/li&gt;
&lt;li&gt;基于ETCD V3的实现版本（优先级：高）&lt;/li&gt;
&lt;li&gt;基于k8s 服务注册的实现版本（优先级：中）&lt;/li&gt;
&lt;li&gt;桥接到其他的服务注册的实现
&lt;ul&gt;
&lt;li&gt;spring cloud的discoveryClient（优先级：中）&lt;/li&gt;
&lt;li&gt;consul（优先级：低）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start=&#34;2&#34;&gt;
&lt;li&gt;
&lt;p&gt;注册中心服务&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;实现注册中心的业务逻辑（优先级：高）&lt;/li&gt;
&lt;li&gt;对外暴露服务的协议实现
&lt;ul&gt;
&lt;li&gt;gRPC协议（优先级：高）&lt;/li&gt;
&lt;li&gt;REST协议（优先级：低）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;提供的服务接口
&lt;ul&gt;
&lt;li&gt;标准的注册/注销/发现接口（优先级：高）&lt;/li&gt;
&lt;li&gt;给应用特别定制的专用接口（优先级：高）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;通过服务注册数据通用接口访问底层数据（优先级：高）&lt;/li&gt;
&lt;li&gt;支持连接其他注册中心交换数据（优先级：中）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;服务治理中心&#34;&gt;服务治理中心&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;基本的服务注册管理（优先级：高）&lt;/li&gt;
&lt;li&gt;基本的服务配置管理（优先级：高）&lt;/li&gt;
&lt;li&gt;基于label的简单服务路由（优先级：中）&lt;/li&gt;
&lt;li&gt;访问注册中心服务和服务配置服务的接口（优先级：高）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;最基本的sdk&#34;&gt;最基本的SDK&lt;/h3&gt;
&lt;p&gt;核心模块中的SDK暂时只实现一个最基本的基于gRPC的简单实现，功能只是简单的：&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=&#34;目标&#34;&gt;目标&lt;/h3&gt;
&lt;p&gt;上述的四个模块实现之后，就可以得到一个最小范围的微服务体系，功能不多，但是端到端的流程已经可以跑起来。此时的应用，在配置中心/注册中心/SDK的配合下，已经具体基本的服务间通讯功能，同时通过服务治理中心能实现一些简单的服务治理功能：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;../201804-dreammesh-architecture-core/images/application.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;当然，这只是基石，在此之上，我们将进一步完善体系。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;注： 后面的模块就不详细展开了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;引入service-mesh&#34;&gt;引入Service Mesh&lt;/h2&gt;
&lt;p&gt;首先申明：Dream Mesh暂时不会选择自己重新实现一套Service Mesh，除非未来Istio和Conduit两个产品都出现令人无法满意的极端情况。&lt;/p&gt;
&lt;p&gt;Dream Mesh选择在Istio和Conduit的基础上做进一步的完善和扩展。&lt;/p&gt;
&lt;h3 id=&#34;打通service-mesh和非service-mesh&#34;&gt;打通Service Mesh和非Service Mesh&lt;/h3&gt;
&lt;p&gt;第一件事情，就是完成前文   &lt;a href=&#34;../201802-dreammesh-brainstorm-transition/&#34;&gt;DreamMesh抛砖引玉(3)-艰难的过渡&lt;/a&gt; 讨论的过渡方案，打通Service Mesh和非Service Mesh。&lt;/p&gt;
&lt;p&gt;此时需要的完成的事情：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;可以兼容Istio和Conduit的服务注册实现&lt;/li&gt;
&lt;li&gt;可以连接Service Mesh和非Service Mesh下的服务注册&lt;/li&gt;
&lt;li&gt;可以将请求在Service Mesh和非Service Mesh之间转发&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;引入spring-cloud&#34;&gt;引入spring cloud&lt;/h2&gt;
&lt;h3 id=&#34;spring-cloud集成&#34;&gt;spring cloud集成&lt;/h3&gt;
&lt;p&gt;将前面实现的配置中心和服务注册集成到spring cloud，这样普通spring cloud程序也可以使用Dream Mesh体系的配置中心/注册中心，然后可以通过服务治理中心进行基本的服务治理。&lt;/p&gt;
&lt;h3 id=&#34;spring-cloud-on-service-mesh&#34;&gt;spring cloud on service mesh&lt;/h3&gt;
&lt;p&gt;帮助将已有的spring cloud应用迁移到service mesh上，尽量减少代码的修改量，做到可以比较平滑的迁移。&lt;/p&gt;
&lt;h3 id=&#34;spring-boot-on-service-mesh&#34;&gt;spring boot on service mesh&lt;/h3&gt;
&lt;p&gt;个人推崇的比较干净的应用开发模式，spring boot + service mesh，彻底抛弃spring cloud。&lt;/p&gt;
&lt;h2 id=&#34;基于service-mesh的扩展&#34;&gt;基于Service Mesh的扩展&lt;/h2&gt;
&lt;h3 id=&#34;基于service-mesh的api-gateway&#34;&gt;基于Service Mesh的API Gateway&lt;/h3&gt;
&lt;p&gt;实现前文 &lt;a href=&#34;../201803-dreammesh-brainstorm-gateway/&#34;&gt;DreamMesh抛砖引玉(9)-API Gateway&lt;/a&gt; 设想的基于Service Mesh的API Gateway。&lt;/p&gt;
&lt;h3 id=&#34;削峰填谷&#34;&gt;削峰填谷&lt;/h3&gt;
&lt;p&gt;为应用提供&amp;quot;削峰填谷&amp;quot;的功能，结合Service Mesh，可以做到对应用透明。&lt;/p&gt;
&lt;h2 id=&#34;讨论和反馈&#34;&gt;讨论和反馈&lt;/h2&gt;
&lt;p&gt;TBD：等收集后整理更新&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;有兴趣的朋友，请联系我的微信，加入Dream Mesh内部讨论群。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>DreamMesh架构设计(2)-设计原则</title>
      <link>https://skyao.net/post/201804-dreammesh-architecture-principle/</link>
      <pubDate>Sat, 14 Apr 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201804-dreammesh-architecture-principle/</guid>
      <description>&lt;p&gt;在展开详细的架构设计之前，先罗列一下Dream Mesh将在之后遵循的一些基本原则，以及这些原则背后的原因和期望的目标。&lt;/p&gt;
&lt;p&gt;不敢立论说这些原则一定是对的，或者是最好的选择，只是从个人的感悟上出发，我更倾向于在这些原则的基础上架构整个Dream Mesh的体系。&lt;/p&gt;
&lt;h2 id=&#34;原则要服务不要类库&#34;&gt;原则：要服务不要类库&lt;/h2&gt;
&lt;p&gt;以注册中心和配置中心为例，通常的做法，是引入诸如zookeeper/consul/etcd等分布式一致性方案，然后编写代码调用其客户端API来操作数据。然后将编写的代码打包为类库，分发给使用者。典型如Java中就是提供一个依赖，然后可以导入一个或者若干个Jar。&lt;/p&gt;
&lt;p&gt;这个方式非常的正统，由于是以类库的方式嵌入到应用中，实际运行时应用时直接和zookeeper/consul/etcd等服务器连接和访问。好处是设计上简单直白容易理解，执行效率较高。&lt;/p&gt;
&lt;p&gt;但是，也存在一些问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;升级困难&lt;/p&gt;
&lt;p&gt;即任何情况下需要升级类库，就必须重新分发，然后所有使用者都要重新打包上线。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;引入大量依赖包&lt;/p&gt;
&lt;p&gt;由于是类库模式，需要引入依赖和递归依赖，导致应用的依赖数量大增，增加版本冲突等的可能性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;严重依赖客户端API&lt;/p&gt;
&lt;p&gt;类库是建立在客户端API上的，因此客户端API能做什么，有什么限制，有什么不足，都直接反应在类库上。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;举例，在2016年我们开发Dolphin微服务框架时，当时选择consol，它的监听机制是基于HTTP long pull的，客户端引入了一大堆依赖，然后还非常不稳定，客户端版本升级也特别频繁。大受折磨，最后换etcd v3才得以解脱。&lt;/p&gt;
&lt;p&gt;在Dream Mesh中，所有的功能模块都将以服务的方式提供，包括注册中心自己：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;../201804-dreammesh-architecture-core/images/registry-center.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;配置中心：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;../201804-dreammesh-architecture-core/images/config-center.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;应用在运行时，就不再依赖各种类库了，转而直接调用服务提供的接口：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;../201804-dreammesh-architecture-core/images/application.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;原则万物皆服务服务皆注册&#34;&gt;原则：万物皆服务，服务皆注册&lt;/h2&gt;
&lt;p&gt;在Dream Mesh体系内，各个功能模块，都抽象为服务，然后在注册中心注册。&lt;/p&gt;
&lt;p&gt;在使用时，也是尽量依赖服务发现机制。&lt;/p&gt;
&lt;p&gt;好处是，所有模块都在注册中心有注册，则我们通过注册中心，就可以掌控整个体系。至少，有什么东西，部署在哪里就可以有一个统一而完备的记录。&lt;/p&gt;
&lt;p&gt;这应该算是一个目前比较主流的做法，只是Dream Mesh中会做的比较彻底，比较绝。&lt;/p&gt;
&lt;h2 id=&#34;原则内部通讯走grpc&#34;&gt;原则：内部通讯走gRPC&lt;/h2&gt;
&lt;p&gt;Dream Mesh体系中的内部通讯，尽可能的选择使用gRPC作为通讯机制。&lt;/p&gt;
&lt;p&gt;主要理由如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;gRPC有完备的跨语言/跨平台的支持，也已经坐稳了下一代RPC的位置，日渐主流&lt;/li&gt;
&lt;li&gt;gRPC基于HTTP/2，可以提供远比HTTP/1.1强大的特性，最关键的，监听实现起来舒服多了&lt;/li&gt;
&lt;li&gt;gRPC提供的双向stream，在后面的设计中会大量使用，成为很多模块的主要工作模式&lt;/li&gt;
&lt;li&gt;gRPC单连接的工作模式，不需要连接池，简化了客户端实现。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;和用在服务间通讯时，需要权衡REST和gRPC相比，在内部通讯中，有些常见的制约和不足不再明显：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;开发和使用方式：内部通讯都是直接提供客户端依赖（注：这个客户端已经简化到只是完成访问服务接口），使用者完全不涉及到gRPC的开发和直接使用，对使用者其实是透明的。&lt;/li&gt;
&lt;li&gt;不是文本模式：对于内部通讯，基本不存在需要抓包看报文类的操作，我们会通过收发请求前后的日志来提供足够的debug信息。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;原则优先提供直接语义的专用接口&#34;&gt;原则：优先提供直接语义的专用接口&lt;/h2&gt;
&lt;p&gt;所谓&amp;quot;直接语义&amp;quot;，指不需要考虑通用性，直接针对某个意图特别明确的操作，提供和这个操作的意图明确匹配的业务语义。&lt;/p&gt;
&lt;p&gt;典型如服务发现，正统的接口设计，会提供若干个查询接口，然后组合监听/通知的接口，一起为客户端提供完备而有弹性的选择。&lt;/p&gt;
&lt;p&gt;但是对于大多数情况的客户端，其业务语义往往非常的直白而集中：我要做服务B的服务发现，现在给我服务B的实例列表，然后如果有变动请及时通知我。中间我们要保持网络连接，发心跳包，顺便实现简单的健康检查。&lt;/p&gt;
&lt;p&gt;在有gRPC的双向stream支持的情况下，我们可以将类似的场景直接封装为一个&amp;quot;直接语义&amp;quot;的接口，一次性的解决客户端的各种需求。&lt;/p&gt;
&lt;p&gt;当然，这个&amp;quot;直接语义&amp;quot;的接口是额外提供的，虽然我们推荐尽量使用这个接口，但是普通的接口也是会一并提供。&lt;/p&gt;
&lt;p&gt;在后面注册中心和配置中心的设计中，我们将广泛应用这个原则。&lt;/p&gt;
&lt;h2 id=&#34;讨论和反馈&#34;&gt;讨论和反馈&lt;/h2&gt;
&lt;p&gt;TBD：等收集后整理更新&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;有兴趣的朋友，请联系我的微信，加入Dream Mesh内部讨论群。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>DreamMesh架构设计(1)-系统核心</title>
      <link>https://skyao.net/post/201804-dreammesh-architecture-core/</link>
      <pubDate>Fri, 13 Apr 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201804-dreammesh-architecture-core/</guid>
      <description>&lt;p&gt;对于一个微服务系统，无论是传统的侵入式，还是新兴的Service Mesh，其核心骨干，主要是三大模块：服务注册，配置，SDK。&lt;/p&gt;
&lt;p&gt;这是我自己经过这些年的探索与实践，总结下来的对微服务体系本质的一个个人感悟。而这个思路，会贯彻在接下来的Dream Mesh的架构设计中。&lt;/p&gt;
&lt;h2 id=&#34;服务注册&#34;&gt;服务注册&lt;/h2&gt;
&lt;p&gt;包含服务注册与服务发现，终极目标：解决服务间感知的问题。&lt;/p&gt;
&lt;p&gt;即，当我们希望实现服务A到服务B的调用时，我们必然需要获知服务B的所在。考虑到分布式系统，服务B存在多个实例，因此在调用时需要得知服务B的所有实例信息。由于存在诸如就近访问等优化需求，因此有时也需要提供作为调用发起者A的实例信息。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;./images/registry-essence.jpg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;服务注册的终极三连问：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;我是谁？(答：调用的发起者服务A)&lt;/li&gt;
&lt;li&gt;我要访问谁？(答：服务B)&lt;/li&gt;
&lt;li&gt;它在哪里? (答：服务B的实例列表)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;事情开始总是简单，然后慢慢变的复杂：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;由于服务实例是动态变化的，因此需要一个存储机制来保存服务实例以便查询
&lt;ul&gt;
&lt;li&gt;为了保证服务信息的一致性，因此通常会引入分布式一致性方案如zookeeper/consul/etcd等&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;我们需要设计服务注册的模型，然后转换为一个数据结构来保存
&lt;ul&gt;
&lt;li&gt;最开始的时候，信息只包含基本的内容，如ID，IP地址，端口等&lt;/li&gt;
&lt;li&gt;为了支持多版本，将服务版本加入到注册信息，然后基于版本信息做版本过滤和隔离，或者实现语义化版本&lt;/li&gt;
&lt;li&gt;为了支持多机房和就近访问，加入region/zone等信息&lt;/li&gt;
&lt;li&gt;为了实现灵活的实例刷选，加入label信息，然后实现基于label的过滤
&lt;ul&gt;
&lt;li&gt;我们便有了很多强大的服务路由功能，实现诸如灰度等特性&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;为了方便的携带其他非label信息，加入annotation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;我们开始考虑把事情做的更好
&lt;ul&gt;
&lt;li&gt;为了保存实例信息的有效性，需要对服务实例做健康检查&lt;/li&gt;
&lt;li&gt;为了及时通知服务实例的动态变化，需要实现监听和通知&lt;/li&gt;
&lt;li&gt;&amp;hellip;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;一步一步的，我们就得到了一个完善的服务注册实现，然后我们将代码打包进SDK，分发下去。当系统中所有的服务都实现了服务注册时，那么我们就可以通过服务发现来查找所有我们需要调用的服务。就这样，服务间感知的使命得以完成。&lt;/p&gt;
&lt;p&gt;后面在服务发现（项目名：&lt;a href=&#34;https://github.com/dreamfly-io/dream-registry&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Dream Registry&lt;/a&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;我们需要将service mesh和非service mesh连接起来&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;h2 id=&#34;配置&#34;&gt;配置&lt;/h2&gt;
&lt;p&gt;服务注册完成了服务间的感知，现在我们的服务A知道了服务B的所在，我们可以发起请求。&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;li&gt;要不要做灰度？要不要做路由？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所有这些配置，都和服务间通讯有关，有些和服务注册非常紧密，有些和后面要谈到的SDK非常紧密。总而言之，在服务A调用服务B的过程中，有一些操作细节是可以定制和修改的。我将这些内容称为&amp;quot;服务配置&amp;quot;。&lt;/p&gt;
&lt;p&gt;之所以要在配置前面加上&amp;quot;服务&amp;quot;二字，是因为通常大家理解的配置，往往是另外一种：和服务间通讯无关，而与应用的业务逻辑和实现细节有关。这一类配置我称为&amp;quot;业务配置&amp;quot;。&lt;/p&gt;
&lt;p&gt;在这两者之外，还有一种常见配置：对各种资源的配置，比如数据库访问信息，连接池设置，Redis/Mongo等外部资源配置。这些配置即和服务间通讯无关，也和业务逻辑无关，因此我将它们单独出来称为&amp;quot;资源配置&amp;quot;。&lt;/p&gt;
&lt;p&gt;这里有一个非常微妙的关系：服务配置从代码实现上说是配置的一种，但是服务配置和服务注册的关系又特别的紧密，完全是注册中心不可分割的一部分。因此，注册中心和配置中心该如何划分界限，就成为一个需要权衡的问题：服务配置，究竟应该放在注册中心，还是应该放在配置中心？还是干脆单独拉出来？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;./images/config-category.jpg&#34; alt=&#34;config-category&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;曾经在某个汇集国内诸多家服务化框架核心开发者的微信群中讨论过这个问题，最后大家达成的一致如上图所示：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;实现层面上，服务配置应该重用配置中心的代码&lt;/li&gt;
&lt;li&gt;管理层面上，服务配置应该归属注册中心&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在Dream Mesh的设计中，我们遵循这个做法，Dream Mesh的服务注册/服务配置/服务治理中心的关系如下：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;./images/registry-center.jpg&#34; alt=&#34;config-category&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;配置中心实现如下：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;./images/config-center.jpg&#34; alt=&#34;config-category&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;应用和注册中心/配置中心的关系如下：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;./images/application.jpg&#34; alt=&#34;config-category&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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;/ul&gt;
&lt;h2 id=&#34;sdk&#34;&gt;SDK&lt;/h2&gt;
&lt;p&gt;有了服务注册和服务配置，我们服务A对服务B的调用，就基本准备好了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务A已经通过服务发现机制感知到了服务B的所在&lt;/li&gt;
&lt;li&gt;服务A已经通过服务配置获取了访问过程中的行为方式&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;现在该发起实质性的调用了，将请求从服务A发送到服务B：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;以什么样的形式体现请求的内容？是发送一段内存，还是发送一个消息？&lt;/li&gt;
&lt;li&gt;如果是消息，选择何种方案做序列化的编解码？&lt;/li&gt;
&lt;li&gt;网络请求协议如何选择？TCP/UDP? HTTP/1.1，HTTP/2，自定义TCP？&lt;/li&gt;
&lt;li&gt;客户端使用什么编程语言，选用何种类库/框架？&lt;/li&gt;
&lt;li&gt;NIO/AIO等的时候&lt;/li&gt;
&lt;li&gt;负载均衡的实现，熔断的实现，重试的实现，还有路由，灰度，认证，加密等&amp;hellip;&amp;hellip;&lt;/li&gt;
&lt;li&gt;以及前面提到的，对服务注册的使用，和对服务配置的遵守&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所有这些的实现，我都统称为SDK。在这里，我们可以选择简单的方案如httpclient发送json，可以选择成熟的RPC方案如thrift，可以直接采用各种框架如dubbo/spring cloud，甚至我们念念叨叨的service mesh也可以理解为一种特别的SDK。&lt;/p&gt;
&lt;p&gt;无论选择何种SDK方案，最终，我们的目标都是通过SDK，将我们的请求从服务A发送到服务B。&lt;/p&gt;
&lt;p&gt;SDK在微服务体系中的核心价值也就清晰了：完成请求发送的具体过程。&lt;/p&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;服务注册/配置/SDK，三者配合，就形成了微服务体系的骨架。&lt;/p&gt;
&lt;p&gt;Dream Mesh在接下来的设计和实现中，都将围绕这三个核心模块来完成。当然这里SDK的内容会比较多，平常大家的关注点也会更多的聚焦于SDK的实现，对于服务注册和配置的重要性往往认识不足。&lt;/p&gt;
&lt;p&gt;从个人的感悟上说，也是在摸爬滚打这些年，在重新认真的审视服务注册和配置之后，才体会到他们的重要。&lt;/p&gt;
&lt;h2 id=&#34;讨论和反馈&#34;&gt;讨论和反馈&lt;/h2&gt;
&lt;p&gt;TBD：等收集后整理更新&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;有兴趣的朋友，请联系我的微信，加入Dream Mesh内部讨论群。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>DreamMesh抛砖引玉(10)-多集群</title>
      <link>https://skyao.net/post/201804-dreammesh-brainstorm-mutiple-cluster/</link>
      <pubDate>Thu, 12 Apr 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201804-dreammesh-brainstorm-mutiple-cluster/</guid>
      <description>&lt;p&gt;如果有多集群/多机房的支持需求，该如何解决？&lt;/p&gt;
&lt;p&gt;这个问题和前面列出的service mesh体系和非service mesh的并存问题，可能叠加：如何在多集群/多机房要求下实现service mesh体系和非service mesh的并存。&lt;/p&gt;
&lt;h2 id=&#34;需求&#34;&gt;需求&lt;/h2&gt;
&lt;p&gt;首先看看需求来自哪里：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Service Mesh体系和非Service Mesh体系并存/过渡的需要&lt;/p&gt;
&lt;p&gt;见前文 &lt;a href=&#34;../201802-dreammesh-brainstorm-transition/&#34;&gt;DreamMesh抛砖引玉(3)-艰难的过渡&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;技术栈差异&lt;/p&gt;
&lt;p&gt;不同时期使用的技术栈不同，可能造成有多套集群，比如原有dubbo，现在要转向spring cloud，这样在过渡期间会有两套系统。前面列的第一条可以视为是本条的特例。&lt;/p&gt;
&lt;p&gt;如果公司较大，也会出现不同组织采用不同的技术栈导致出现多个集群。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;测试运维需要&lt;/p&gt;
&lt;p&gt;可能希望在生产环境之外搭建stagging，test等集群，通常是独立运作，但是偶尔会有想法，希望开个口子以便打通若干个服务或者某个实例，来做测试和验证。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;场景&#34;&gt;场景&lt;/h2&gt;
&lt;p&gt;我们要打通的多个微服务集群，情况很复杂，可能是以下多种场景混杂：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;集群可能是Service Mesh体系和非Service Mesh体系&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果是Service Mesh，可能是Istio/Conduit&lt;/li&gt;
&lt;li&gt;如果是非Service Mesh体系，可能是SpringCloud/Dubbo/Motan等&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;网络不同，可能在虚拟网络中如k8s&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;li&gt;
&lt;p&gt;集群可能用于不同的产品部署阶段&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;prod&lt;/li&gt;
&lt;li&gt;stagging&lt;/li&gt;
&lt;li&gt;test&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;难点&#34;&gt;难点&lt;/h2&gt;
&lt;p&gt;需求告诉我们：这个事情有做的价值；而场景则提醒我们：这个事情不简单。&lt;/p&gt;
&lt;p&gt;我们来罗列一下实现中的难点所在：&lt;/p&gt;
&lt;h3 id=&#34;服务注册与服务发现&#34;&gt;服务注册与服务发现&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;备注1：由于篇幅所限，下面列出的只是提纲，详细内容会在后续文章中阐述
备注2：实际上是内容展开之后发现篇幅收不住，内容太长不适合阅读，决定拆开&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;要调用服务，自然需要知道服务在哪里，这涉及到服务注册与服务发现。本集群内只需要知道目标服务实例的IP地址和端口即可，而要跨集群调用服务，事情要变的复杂的多：&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;ul&gt;
&lt;li&gt;要不要支持跨集群的负载均衡?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最后，最关键的一点：&lt;strong&gt;各个集群的服务注册模型必须一致或者可以转换为一致&lt;/strong&gt;，这样才能在一个集群中&amp;quot;理解&amp;quot;另一个集群的服务注册信息。&lt;/p&gt;
&lt;h3 id=&#34;sdk必须有能力转发跨集群的请求&#34;&gt;SDK必须有能力转发跨集群的请求&lt;/h3&gt;
&lt;p&gt;在获取目标服务的地址之后，如果发现是远程集群，那就需要解决如何将请求转发到另一个集群的问题。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果网络互通，直接连接就好了&lt;/li&gt;
&lt;li&gt;如果网络不通，那么需要引入特殊机制，来跨集群转发请求，类似反向代理/API Gateway&lt;/li&gt;
&lt;li&gt;SDK要能识别服务实例所在的zone，以及获取配置，看是否需要执行&amp;quot;就近访问&amp;quot;&lt;/li&gt;
&lt;li&gt;如果服务跨多个集群部署+需要跨集群负载均衡，SDK的实现要复杂的多&lt;/li&gt;
&lt;li&gt;如果一个服务在两个集群中采用不同的通讯协议，则还有一个协议转换的过程&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;服务治理必须跨集群通用&#34;&gt;服务治理必须跨集群通用&lt;/h3&gt;
&lt;p&gt;在服务注册机制+SDK的配合之下，现在我们可以做到：&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;/p&gt;
&lt;p&gt;要在各个集群中贯彻一致的服务治理意图，需要解决两个难题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;服务治理的实现不同：有各自的SDK实现&lt;/li&gt;
&lt;li&gt;服务治理的信息不统一：有各自的配置方式，或者设置方法&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;讨论和反馈&#34;&gt;讨论和反馈&lt;/h2&gt;
&lt;p&gt;TBD：等收集后整理更新&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;Dream Mesh抛砖引玉系列的文章到此完结，后续将展开Dream Mesh的概要设计，和针对各个功能子模块的详细设计。&lt;/p&gt;
&lt;p&gt;鸣谢在此期间参与讨论，给出意见和反馈的朋友们，感谢你们的支持和帮忙。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>DreamMesh抛砖引玉(9)-API Gateway</title>
      <link>https://skyao.net/post/201803-dreammesh-brainstorm-gateway/</link>
      <pubDate>Thu, 22 Mar 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201803-dreammesh-brainstorm-gateway/</guid>
      <description>&lt;p&gt;service mesh解决的是东西向服务间通讯的问题，我们来审视一下API gateway到微服务之间的南北向通讯： 服务发现，负载均衡，路由，灰度，安全，认证，加密，限流，熔断……几乎大部分的主要功能，在这两个方向上都高度重叠。&lt;/p&gt;
&lt;p&gt;因此，是否该考虑提供一个统一的解决方案来处理？&lt;/p&gt;
&lt;h2 id=&#34;在service-mesh之前&#34;&gt;在Service Mesh之前&lt;/h2&gt;
&lt;p&gt;在Service Mesh出来之前，这个问题就已经存在，而且也已经有了解决方案。&lt;/p&gt;
&lt;p&gt;对于API Gateway的产品，有两种不同的实现方式：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;基于微服务体系&lt;/p&gt;
&lt;p&gt;典型如Zuul/Spring Cloud Gateway，这类API Gateway的产品和微服务体系一脉相承，在实现将请求转发到内部服务时，API Gateway等同于一个普通的微服务客户端。&lt;/p&gt;
&lt;p&gt;因此，可以复用微服务体系客户端的几乎所有功能，比如Zuul/Spring Cloud Gateway都是和Spring Cloud的普通客户端一样，用Feign做client，Ribbon做负载均衡，用Eureka或者其他ServiceDiscovery实现做服务发现，Hystrix做熔断&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-1_hu8db9845740bd15d389dc67f63082b958_44780_78799cd1ff5d8c988e5f6539e791ec74.webp 400w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-1_hu8db9845740bd15d389dc67f63082b958_44780_f1310d2b41322a4c259f9c16069dc909.webp 760w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-1_hu8db9845740bd15d389dc67f63082b958_44780_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201803-dreammesh-brainstorm-gateway/images/gateway-1_hu8db9845740bd15d389dc67f63082b958_44780_78799cd1ff5d8c988e5f6539e791ec74.webp&#34;
               width=&#34;760&#34;
               height=&#34;583&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;独立于微服务体系&lt;/p&gt;
&lt;p&gt;对于独立的API Gateway产品，典型如kong，因为和微服务体系不是一体，因此无法直接复用微服务体系的客户端，需要自行通过其他方式解决。&lt;/p&gt;
&lt;p&gt;最基本的，是需要解决服务发现的问题。&lt;/p&gt;
&lt;p&gt;请教了一下熟悉kong的朋友，kong是通过DNS的方式来进行服务发现的。也就是说，需要实现DNS和服务注册机制的协同，典型的做法是使用consul这种支持DNS的服务注册机制。也可以通过插件的方式实现服务发现的客户端。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-2_hua6547528b5dfa582efe039847447fd49_47922_c63bcad6e3d47029483f4ac920191f12.webp 400w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-2_hua6547528b5dfa582efe039847447fd49_47922_4b631c7c8e9ec41f9105ffe5337fa347.webp 760w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-2_hua6547528b5dfa582efe039847447fd49_47922_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201803-dreammesh-brainstorm-gateway/images/gateway-2_hua6547528b5dfa582efe039847447fd49_47922_c63bcad6e3d47029483f4ac920191f12.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;两种实现方式的根本差别：在于能否&lt;strong&gt;复用&lt;/strong&gt;微服务体系的客户端机制。&lt;/p&gt;
&lt;h2 id=&#34;在service-mesh之后&#34;&gt;在Service Mesh之后&lt;/h2&gt;
&lt;p&gt;当我们将侵入式的微服务框架替换为Service Mesh，这个问题会发生一些微妙的变化，因为：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Service Mesh是基于Sidecar的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;而Sidecar的特点是：独立进程，运行于客户端进程之外；通过远程访问来接收和转发请求。&lt;/p&gt;
&lt;p&gt;按照上面的思路，我们需要考虑如何在API Gateway中复用Service Mesh体系的客户端机制，也就是复用sidecar。有个简单而直白的方案，就是将sidecar&amp;quot;竖&amp;quot;起来，添加到南北向的流量中，如图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-3_huaaa2b3ba21e6d5a7ca4341a31f198aac_69220_6c1a975affd0049d9fecb438fc83b64c.webp 400w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-3_huaaa2b3ba21e6d5a7ca4341a31f198aac_69220_4b35054fa5597d31e424418da5f9a25c.webp 760w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-3_huaaa2b3ba21e6d5a7ca4341a31f198aac_69220_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201803-dreammesh-brainstorm-gateway/images/gateway-3_huaaa2b3ba21e6d5a7ca4341a31f198aac_69220_6c1a975affd0049d9fecb438fc83b64c.webp&#34;
               width=&#34;760&#34;
               height=&#34;507&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;优势分析&#34;&gt;优势分析&lt;/h2&gt;
&lt;p&gt;上述方案如果成功实现，则带来以下好处：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;统一了微服务和API Gateway两套体系，大量节约学习/开发/维护的成本&lt;/li&gt;
&lt;li&gt;API Gateway体系可以从Service Mesh方案中得到同样的各种好处，可以使用各种高级特性&lt;/li&gt;
&lt;li&gt;通过Service Mesh的控制平面，可以控制的范围从微服务体系扩展到了API Gateway体系&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;非常美好的想法，那关键来了：该如何实现？&lt;/p&gt;
&lt;h2 id=&#34;实现方式&#34;&gt;实现方式&lt;/h2&gt;
&lt;p&gt;宏观上看，实现应该不难，起码思路很清晰：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;将API Gateway纳入Service Mesh体系&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;理由：要让API Gateway可以使用sidecar，要让这个和API Gateway一起部署的siecar可以工作于Service Mesh体系，那么最简单的办法，就是将API Gateway连同它的sidecar，一起融入Service Mesh体系：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-4_hua89d7b6e5f4128b724dda44ee60b9968_47456_7982502f6f26f48a12a40a985798f067.webp 400w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-4_hua89d7b6e5f4128b724dda44ee60b9968_47456_128f570ec9f276b591c7e9d8e4469445.webp 760w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-4_hua89d7b6e5f4128b724dda44ee60b9968_47456_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201803-dreammesh-brainstorm-gateway/images/gateway-4_hua89d7b6e5f4128b724dda44ee60b9968_47456_7982502f6f26f48a12a40a985798f067.webp&#34;
               width=&#34;760&#34;
               height=&#34;532&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;此时，API Gateway扮演一个普通服务的角色，运行于Service Mesh体系内，自然可以复用Service Mesh的所有功能。&lt;/p&gt;
&lt;h3 id=&#34;k8s带来的影响&#34;&gt;k8s带来的影响&lt;/h3&gt;
&lt;p&gt;考虑到如果Service Mesh是运行在k8s上时，典型如Istio/Conduit，那么事情会稍微复杂一点：因为k8s下会有个外部流量如何进入k8s的问题。我们需要为此引入类似Ingress的组件：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-5_hua0b4b878a6fc2a73e78eb261a335949a_53020_b6a9347a6284d80f2d9d2eace5e39ba6.webp 400w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-5_hua0b4b878a6fc2a73e78eb261a335949a_53020_382e5fc58f59ffe173dfd5d3299e6d28.webp 760w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-5_hua0b4b878a6fc2a73e78eb261a335949a_53020_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201803-dreammesh-brainstorm-gateway/images/gateway-5_hua0b4b878a6fc2a73e78eb261a335949a_53020_b6a9347a6284d80f2d9d2eace5e39ba6.webp&#34;
               width=&#34;760&#34;
               height=&#34;538&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;k8s下的另类方式&#34;&gt;k8s下的另类方式&lt;/h3&gt;
&lt;p&gt;仔细想了一下，理论上还存在另外一种的方式，貌似有些另类：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;API Gateway体系继续独立于Service Mesh体系之外&lt;/li&gt;
&lt;li&gt;在Service Mesh体系内为API Gateway部署特殊的sidecar，专门用于转发南北向流量&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-6_huf3875207f15630f1849985d277d4c690_48209_ba156a4498024cd8854eb72666289f39.webp 400w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-6_huf3875207f15630f1849985d277d4c690_48209_213022cb603e117154139e684b7effa3.webp 760w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-6_huf3875207f15630f1849985d277d4c690_48209_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201803-dreammesh-brainstorm-gateway/images/gateway-6_huf3875207f15630f1849985d277d4c690_48209_ba156a4498024cd8854eb72666289f39.webp&#34;
               width=&#34;760&#34;
               height=&#34;539&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;此时的sidecar，不再和使用者在一起，也就是不是&amp;quot;local&amp;quot;。部署模型上和正规的sidecar差别很大。&lt;/p&gt;
&lt;h3 id=&#34;追求极致性能的方式&#34;&gt;追求极致性能的方式&lt;/h3&gt;
&lt;p&gt;如果特别介意Sidecar引入之后造成的性能下降，也可以考虑下面的方式：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-7_hu590fdb4678d196f44e79b31d28050516_51813_5d429ab9c8d41e39ccba9fdc2439c8bf.webp 400w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-7_hu590fdb4678d196f44e79b31d28050516_51813_5969131bd4b3ce385e24e3dd632bc2c6.webp 760w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-7_hu590fdb4678d196f44e79b31d28050516_51813_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201803-dreammesh-brainstorm-gateway/images/gateway-7_hu590fdb4678d196f44e79b31d28050516_51813_5d429ab9c8d41e39ccba9fdc2439c8bf.webp&#34;
               width=&#34;760&#34;
               height=&#34;539&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;直接在Sidecar的基础上做开发和扩展&lt;/li&gt;
&lt;li&gt;目标是将Gateway的功能和Sidecar的功能合二为一&lt;/li&gt;
&lt;li&gt;这样可以减少一次gateway和sidecar之间的远程调用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个方式个人不建议，因为基本又退回侵入式框架的模式，除非对性能有非常高甚至堪称极致的需求（比如单机超过10万/20万QPS），否则感觉没有必要。&lt;/p&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结&lt;/h2&gt;
&lt;p&gt;权衡各个方案，个人意见，下面这个方案比较均衡：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-5_hua0b4b878a6fc2a73e78eb261a335949a_53020_b6a9347a6284d80f2d9d2eace5e39ba6.webp 400w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-5_hua0b4b878a6fc2a73e78eb261a335949a_53020_382e5fc58f59ffe173dfd5d3299e6d28.webp 760w,
               /post/201803-dreammesh-brainstorm-gateway/images/gateway-5_hua0b4b878a6fc2a73e78eb261a335949a_53020_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201803-dreammesh-brainstorm-gateway/images/gateway-5_hua0b4b878a6fc2a73e78eb261a335949a_53020_b6a9347a6284d80f2d9d2eace5e39ba6.webp&#34;
               width=&#34;760&#34;
               height=&#34;538&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;主要考虑如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;可以直接重用sidecar&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;开发工作量少很多&lt;/li&gt;
&lt;li&gt;Gateway职责清晰&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;编程语言的考虑&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;目前Istio中的sidecar是Envoy，基于c++，Conduit中的是Rust语言&lt;/li&gt;
&lt;li&gt;这两个语言开发难度，尤其是客户二次开发或者扩展的难度都非常大&lt;/li&gt;
&lt;li&gt;gateway最好还是用Golang或者Java开发会比较合适&lt;/li&gt;
&lt;li&gt;尤其是Java，普通用户的接受度应该会更高&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这个gateway可以全新编写，或者找个现成的gateway产品修改。考虑到gateway的工作模式主要是请求转发，最适合响应式编程，这里有很多发挥的空间。&lt;/p&gt;
&lt;h2 id=&#34;讨论和反馈&#34;&gt;讨论和反馈&lt;/h2&gt;
&lt;p&gt;TBD：等收集后整理更新&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;有兴趣的朋友，请联系我的微信，加入DreamMesh内部讨论群。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>DreamMesh抛砖引玉(8)-SpringCloud迁移</title>
      <link>https://skyao.net/post/201802-dreammesh-brainstorm-springcloud/</link>
      <pubDate>Sun, 25 Feb 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201802-dreammesh-brainstorm-springcloud/</guid>
      <description>&lt;p&gt;虽然Service Mesh号称下一代微服务，取代以Spring Cloud为典型代表的传统侵入式开发框架是Service Mesh与生俱来的天然目标之一。&lt;/p&gt;
&lt;p&gt;但是以目前市场形式，Spring Cloud在未来很长一段时间之内都会是市场主流和很多公司的第一选择。如何在迁移到Service Mesh之前加强Spring Cloud，并为将来转入Service Mesh铺路，是一个艰难而极具价值的话题。&lt;/p&gt;
&lt;h2 id=&#34;长期共存的大背景&#34;&gt;长期共存的大背景&lt;/h2&gt;
&lt;p&gt;首先我们将目标限定在准备进行互联网技术转型的传统企业用户，和部分技术能力还没有达到大型互联网企业水准的中小型互联网企业用户，这些企业有一个比较共性的地方：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;暂时还没有把微服务和容器等新兴技术玩转&lt;/li&gt;
&lt;li&gt;又有强烈的意愿往新技术方向做技术转型&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;在本系列前面的 &lt;a href=&#34;201802-dreammesh-brainstorm-cloudnative/&#34;&gt;DreamMesh抛砖引玉(2)-CloudNative&lt;/a&gt; 一文中我们对此有深入探讨。&lt;/p&gt;
&lt;p&gt;其次，目前Service Mesh处于青黄不接的尴尬时期，暂时Istio和Conduit这两个寄予厚望的产品都还没有production ready，考虑到即使1.0发布，社区和用户也还有一个逐步接触，掌握的过程。而且很多公司出于谨慎也可能采取观望的姿态，Service Mesh的普及必然会需要时间。&lt;/p&gt;
&lt;p&gt;可以参考微服务这几年的发展历程：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2014年出来微服务的概念&lt;/li&gt;
&lt;li&gt;2015年国内开始热烈讨论微服务，少数公司在尝试&lt;/li&gt;
&lt;li&gt;2016/2017年很多公司陆陆续续在实践&lt;/li&gt;
&lt;li&gt;2018年，还有很多公司没有上微服务，聚焦在传统企业，则可以说是大部分公司还出于初级阶段&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;类比之下，今天Service Mesh的在社区的知名度方面和2015年时微服务的状态类似。但是，有一个很大不同在于：微服务在2015年时在实践方面已经有很多公司已经实践并积累了足够的经验，包括类库，典型如Netflix和OSS套件，但是Service Mesh，尤其是以Istio和Conduit为代表的具备强大管理能力的Service Mesh，至今还没有落地实践可以参考。&lt;/p&gt;
&lt;p&gt;因此，未来一段时间，必然会存在侵入式开发框架如Spring Cloud和Service Mesh并存的局面，也必然会有很多致力于微服务迁移的公司继续选择使用Spring Cloud。期间会有很长一段时间，Service Mesh和Spring Cloud并存。&lt;/p&gt;
&lt;h3 id=&#34;springcloud的不足之处&#34;&gt;SpringCloud的不足之处&lt;/h3&gt;
&lt;p&gt;虽然Spring Cloud近两年风光无限，但是SpringCloud的不足还是非常明显，尤其服务治理功能太过薄弱。对比Istio的功能集合，Spring Cloud差距明显。&lt;/p&gt;
&lt;p&gt;另外Spring Cloud的设计是封装一套通用接口，然后理论上可以有多种实现，典型如服务发现的DiscoveryClient，可以有Eureka/zookeeper/consul等诸多实现。但是，Spring Cloud的封装过于简化，几乎是只支持最小功能集合，缺乏大量实用功能。&lt;/p&gt;
&lt;p&gt;以DiscoveryClient接口为例，这是接口定义，方法屈指可数：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-java&#34; data-lang=&#34;java&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;interface&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;DiscoveryClient&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * 实现可读的描述，用于HealthIndicator
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;description&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * 获取和指定serviceId关联的所有服务实例
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;List&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;ServiceInstance&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;getInstances&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;serviceId&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;);&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;cm&#34;&gt;/**
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     * 返回所有已知的服务id。（注意只是id）
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;     */&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;List&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;String&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;getServices&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最关键的&lt;code&gt;getInstances(String serviceId);&lt;/code&gt;，入口参数只有一个serviceId。再看
ServiceInstance的定义：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;参数&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;serviceId&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;service id，由DiscoveryClient设置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;host&lt;/td&gt;
&lt;td&gt;String&lt;/td&gt;
&lt;td&gt;主机名&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;port&lt;/td&gt;
&lt;td&gt;int&lt;/td&gt;
&lt;td&gt;端口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;secure&lt;/td&gt;
&lt;td&gt;boolean&lt;/td&gt;
&lt;td&gt;是否加密，简单说就是是否https&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;metadata&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Map&amp;lt;String, String&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;元数据&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;和成熟的服务注册机制（如原生的Euraka/Consul）相比，缺少诸多功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;没有version参数，所以无法实现语义化版本。&lt;/li&gt;
&lt;li&gt;没有group或者namespace参数，所以无法为服务分组，当服务数量多时管理困难。&lt;/li&gt;
&lt;li&gt;没有zone/datacenter参数，所以无法实现多机房部署&lt;/li&gt;
&lt;li&gt;服务没有status参数，无法支持特殊状态例如consul的&amp;quot;maintainance&amp;quot;。注：ServiceRegistry接口上又有setStatus()。&lt;/li&gt;
&lt;li&gt;接口上也没有定义监听方法，只能交给具体实现。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：好在还有一个metadata参数，总算留了一个口子，可以自行扩展以实现部分功能。但是需要自己实现。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;除了服务注册和服务发现外，Spring Cloud目前严重依赖Ribbon来实现客户端负载均衡，而Ribbon是不支持权重的，因此类似&amp;quot;切1%的流量去某个实例&amp;quot;这样的典型灰度需求在Spring Cloud下是一筹莫展。&lt;/p&gt;
&lt;h2 id=&#34;改进方向&#34;&gt;改进方向&lt;/h2&gt;
&lt;p&gt;当然，我们今天不是来声讨Spring Cloud的，而是希望在未来一段时间，可以增强Spring Cloud，在现有基础上尽可能的加入更多服务治理功能，使其向Service Mesh方向靠拢。&lt;/p&gt;
&lt;p&gt;个人对Spring Cloud的一些改进想法：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;加强服务注册和服务发现：
&lt;ul&gt;
&lt;li&gt;支持语义化版本&lt;/li&gt;
&lt;li&gt;支持分组/namespace&lt;/li&gt;
&lt;li&gt;支持多机房部署&lt;/li&gt;
&lt;li&gt;支持类似k8s的label和对应的label过滤功能&lt;/li&gt;
&lt;li&gt;支持多协议/多个端口&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;支持类似consul的维护模式：停止请求，但是保留服务实例现场，以便debug&lt;/li&gt;
&lt;li&gt;增加基本的灰度功能&lt;/li&gt;
&lt;li&gt;增加对grpc的支持&lt;/li&gt;
&lt;li&gt;改进配置，最好集成一个足够强大的配置中心&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;li&gt;服务治理，服务治理，服务治理！&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;为未来铺路&#34;&gt;为未来铺路&lt;/h2&gt;
&lt;p&gt;在之前的文章 &lt;a href=&#34;./201802-dreammesh-brainstorm-transition/&#34;&gt;DreamMesh抛砖引玉(3)-艰难的过渡&lt;/a&gt; 中曾经探讨过侵入式框架向Service Mesh架构过渡时会遇到的问题，Spring Cloud自然也会遇到类似问题。&lt;/p&gt;
&lt;p&gt;因此，必须找到一个可行的方案，可以解决过渡期Spring Cloud体系和Service Mesh体系间服务间通讯问题。不然现有上Spring Cloud的用户，届时会遇到很大麻烦，而如果不能从容的完成迁移，那么必然会拖累Service Mesh的普及。&lt;/p&gt;
&lt;p&gt;今天的Service Mesh和Spring Cloud，几乎没有相通的东西，对用户而言是两种截然不同的开发体验。我很难想象，目前正在向Spring Cloud迁移的用户，在历尽辛苦完成迁移之后，发现又需要再次迁移到Service Mesh时，会是何种心情？&lt;/p&gt;
&lt;p&gt;在加强Spring Cloud各个功能（如上所列）期间，是否可以找到合适的方式，至少在编码/管理/配置的层面上，让一些Spring Cloud和Service Mesh下相同的功能对外呈现相同之处？比如，以同样的方式配置负载均衡算法，配置灰度，实现服务路由。&lt;/p&gt;
&lt;p&gt;目前，Service Mesh和Spring Cloud都有一种各行其是无视对方存在的感觉。我们无意指责任何一方，只是作为一个负责任的引路人，我们在告诉客户，“你们先上Spring Cloud，等Service Mesh成熟后再换Service Mesh”的同时，是否有责任将这条路趟平一点？或者更进一步，将路铺好？&lt;/p&gt;
&lt;h2 id=&#34;路在何方&#34;&gt;路在何方&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-dreammesh-brainstorm-springcloud/images/road_hu137b0165f047229c75da155858da365a_250376_afe619649a657db917dee43c6c1fbb30.webp 400w,
               /post/201802-dreammesh-brainstorm-springcloud/images/road_hu137b0165f047229c75da155858da365a_250376_93647b02776f62e95f74f290909ad26d.webp 760w,
               /post/201802-dreammesh-brainstorm-springcloud/images/road_hu137b0165f047229c75da155858da365a_250376_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-dreammesh-brainstorm-springcloud/images/road_hu137b0165f047229c75da155858da365a_250376_afe619649a657db917dee43c6c1fbb30.webp&#34;
               width=&#34;760&#34;
               height=&#34;439&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对于自成一家的体系，通常是现有侵入式开发框架，再以此为基础在原有SDK上继而搭建出来service mesh，此时的侵入式开发框架和自家的service mesh底层共用代码，要实现共存和平滑过渡难度并不大。比如他们有相同的服务注册，相同的负载均衡/路由/认证&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;但是对于Spring Cloud和以istio/conduit为代表的service mesh，代码实现上没有任何共通之处，要强行铺路谈何容易。反倒是Spring Boot + Service Mesh全新开始轻松上路要舒坦的多。&lt;/p&gt;
&lt;p&gt;在后续的文章中，将就此深入展开，暂时先只列出当前的一些想法，容我稍后细细道来：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;增强型的服务感知和访问
&lt;ul&gt;
&lt;li&gt;必须统一服务注册的模型，或者退一步，可以将现有服务注册模型和这个统一模型进行相互转换/桥接&lt;/li&gt;
&lt;li&gt;要能打通多个服务的注册中心，做到跨注册中心的服务感知&lt;/li&gt;
&lt;li&gt;客户端SDK要有能力将请求发送到跨注册中心的目标服务&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;配置方式
&lt;ul&gt;
&lt;li&gt;业务型的配置倒是简单，只要使用同一个配置中心即可&lt;/li&gt;
&lt;li&gt;但是对于服务治理类型的配置，则需要更多工作，甚至可能只能在管理界面一层统一而底层实现大相径庭，比如spring cloud下更多的是将配置传递给调用sdk的代码，而istio/conduit下则是通过yaml文件来更改行为。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;服务治理
&lt;ul&gt;
&lt;li&gt;Spring Cloud欠债太多，这块要填的坑很大&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;讨论和反馈&#34;&gt;讨论和反馈&lt;/h2&gt;
&lt;p&gt;TBD: 待讨论后更新。&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;有兴趣的朋友，请联系我的微信，加入DreamMesh内部讨论群。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>DreamMesh抛砖引玉(7)-绕不开的Spring</title>
      <link>https://skyao.net/post/201802-dreammesh-brainstorm-spring/</link>
      <pubDate>Fri, 23 Feb 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201802-dreammesh-brainstorm-spring/</guid>
      <description>&lt;p&gt;对于Java企业应用，spring是无论如何绕不开的。然而目前我们没有看到Spring社区对Service Mesh的任何回应。因此，如何以正确的姿势在service mesh时代使用Spring，需要自己探索。&lt;/p&gt;
&lt;h2 id=&#34;定位&#34;&gt;定位&lt;/h2&gt;
&lt;p&gt;Service Mesh的定位在于微服务，在于&amp;quot;&lt;strong&gt;服务间通讯&lt;/strong&gt;&amp;quot;，在于管理和监控微服务，也就是一般说的&amp;quot;服务治理&amp;quot;。&lt;/p&gt;
&lt;p&gt;而Spring是一个巨大的生态体系，模块众多，这些模块除了Spring Cloud作为微服务框架和Service Mesh关系特殊（这个我们将会在下一章中单独谈），其他模块和Service Mesh都不冲突，定位都是完全可以互补的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spring Context作为Spring生态最早的模块和系统核心，定位于&lt;strong&gt;依赖注入和Bean管理&lt;/strong&gt;，这是目前Java社区的事实标准。&lt;/li&gt;
&lt;li&gt;Spring Boot作为产品级别的&amp;quot;&lt;strong&gt;微框架&lt;/strong&gt;&amp;quot;（注意不是微服务框架），过去几年间也可谓大获成功。&lt;/li&gt;
&lt;li&gt;Spring MVC是目前主流的web和Rest开发框架&lt;/li&gt;
&lt;li&gt;Spring Data定于为数据访问&lt;/li&gt;
&lt;li&gt;其他模块都不一一列举&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们可以看到，除Spring Cloud之外的Spring生态体系和Service Mesh在定位上都不冲突。&lt;/p&gt;
&lt;p&gt;从打造一个完整应用的角度看，我们使用Service Mesh只是解决了微服务之间彼此通讯的问题，对于服务本身，并不涉及：Service Mesh和业务实现无关，和数据库无关，和微服务拆分无关，和cache/session无关。&lt;/p&gt;
&lt;p&gt;这也就意味着，不管有没有Service Mesh，应用本身该如何开发和实现，理论上不受影响。&lt;/p&gt;
&lt;h2 id=&#34;现状&#34;&gt;现状&lt;/h2&gt;
&lt;p&gt;让我们回到Spring，在过往的十几年间，对于Java社区，Spring是一道美丽的风景。可以说，Java在企业开发市场的成功，Spring的功不可没。&lt;/p&gt;
&lt;p&gt;而令人惊喜的是，Spring至今依然保持良好的发展态势，继续在引领Java社区的技术进步。2018年对Spring的使用者和爱好者来说，会是一个很有惊喜和挑战的年份：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;基于Java8的Spring5于2017年9月发布&lt;/li&gt;
&lt;li&gt;同样基于Java8和Spring5的Spring Boot2即将在2月底发布1.0 RELEASE版本&lt;/li&gt;
&lt;li&gt;不出意外基于Spring5/Spring Boot2的Spring Cloud2也会在今年发布&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-dreammesh-brainstorm-spring/images/spring5_hu33a2a32dd642b521999bffeac4faec9c_35458_068d4d995199b807db324762ec170099.webp 400w,
               /post/201802-dreammesh-brainstorm-spring/images/spring5_hu33a2a32dd642b521999bffeac4faec9c_35458_056b96c5f183fe5c7cdc3b08f855e3bb.webp 760w,
               /post/201802-dreammesh-brainstorm-spring/images/spring5_hu33a2a32dd642b521999bffeac4faec9c_35458_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-dreammesh-brainstorm-spring/images/spring5_hu33a2a32dd642b521999bffeac4faec9c_35458_068d4d995199b807db324762ec170099.webp&#34;
               width=&#34;702&#34;
               height=&#34;336&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Spring 5/Spring Boot 2终于开始支持Java8特性，带来响应式编程，函数式web框架，Kotlin支持，JUnit 5支持等。其中，响应式编程的全面引入意义深远。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-dreammesh-brainstorm-spring/images/springboot2_hu8a6fd7e850e29df216abcb24a1a089bf_8881_b13f0676c3ee349418aeb825a2fe89f7.webp 400w,
               /post/201802-dreammesh-brainstorm-spring/images/springboot2_hu8a6fd7e850e29df216abcb24a1a089bf_8881_df03a717f263c8d70baf903ffb9ab330.webp 760w,
               /post/201802-dreammesh-brainstorm-spring/images/springboot2_hu8a6fd7e850e29df216abcb24a1a089bf_8881_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-dreammesh-brainstorm-spring/images/springboot2_hu8a6fd7e850e29df216abcb24a1a089bf_8881_b13f0676c3ee349418aeb825a2fe89f7.webp&#34;
               width=&#34;432&#34;
               height=&#34;116&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;从目前发布情况看， Spring 5/Spring Boot 2继续保持了Spring一贯的品质和作风，值得拥有，不容错过。&lt;/p&gt;
&lt;h2 id=&#34;清爽搭配&#34;&gt;清爽搭配&lt;/h2&gt;
&lt;p&gt;最近这几年，微服务和容器这两个新兴技术，堪称绝配。而在微服务领域，我个人非常看好这样一个的搭配：&lt;strong&gt;Spring Boot + Service Mesh&lt;/strong&gt;。之前我甚至连口号都准备了一个：&amp;ldquo;Spring On Service Mesh&amp;rdquo;，简称&amp;quot;Spring Mesh&amp;quot;。&lt;/p&gt;
&lt;p&gt;在Service Mesh搞定服务间通讯的诸多复杂度之后，带来的好处就是让应用可以回归业务：开发人员的关注点可以更多的聚焦于业务逻辑实现和应用自身的管理。而如何实现单机模式的业务应用，这正是Spring Boot最擅长的领域。&lt;/p&gt;
&lt;p&gt;Spring Boot + Service Mesh这对组合的清爽之处在于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Spring Boot大幅简化了应用本身开发的工作，发力于应用之&amp;quot;内&amp;quot;&lt;/li&gt;
&lt;li&gt;Service Mesh大幅简化了服务间通讯开发的工作，发力于应用之&amp;quot;外&amp;quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;两者结合，就是&amp;quot;内外兼修&amp;quot;，可以相互支撑而又能互不越界。同时，两者的处世哲学都是尽可能的在底层默默的把事情做好，留给上层一个简单清晰的使用方式，而各种强大功能悄无声息的就绪，堪称&amp;quot;低调的奢华&amp;quot;。&lt;/p&gt;
&lt;p&gt;这正是我喜欢的风格。&lt;/p&gt;
&lt;h2 id=&#34;实践&#34;&gt;实践&lt;/h2&gt;
&lt;p&gt;目前&amp;quot;Spring Boot + Service Mesh&amp;quot;对我而言还停留在一个纸上谈兵的阶段，我暂时还未能在实际的工程项目中真实的落地这样一个搭档。因此，如果有朋友有类似的想法，愿意尝试，可以联系我一起做深入研究。&lt;/p&gt;
&lt;p&gt;目前构思中的Dream Mesh开源项目，有一块重要内容就是如何让Spring体系和Service Mesh技术更加融洽的结合。我的初步想法就是：如果Spring和Service Mesh做的足够好，那么我们就只是提炼出来最佳实践，给出一个成熟方案供大家参考或者直接拿来用，类似于SpringSide项目于Spring；如果有某些地方有所欠缺或者不足，我们就在Dream Mesh中做好补充和完善，类似于OpenShift项目于K8s。&lt;/p&gt;
&lt;p&gt;实践出真知，只有在实践中检验过的东西才能经得起考验。非常期待有机会实践的朋友给予来自一线的知识分享，请微信联系我，不吝赐教。&lt;/p&gt;
&lt;h2 id=&#34;讨论和反馈&#34;&gt;讨论和反馈&lt;/h2&gt;
&lt;p&gt;TBD: 待讨论后更新。&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;有兴趣的朋友，请联系我的微信，加入DreamMesh内部讨论群。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>DreamMesh抛砖引玉(6)-性能开销</title>
      <link>https://skyao.net/post/201802-dreammesh-brainstorm-cost/</link>
      <pubDate>Thu, 22 Feb 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201802-dreammesh-brainstorm-cost/</guid>
      <description>&lt;p&gt;之前我们反复谈到，Service Mesh的核心在于将原有以类库方式提供的功能拆分到独立的sidecar进程中，以远程调用的方式来强行解耦&lt;strong&gt;服务间通讯的业务语义&lt;/strong&gt;和&lt;strong&gt;服务间通讯的具体实现&lt;/strong&gt;。这带来了诸多的好处，我们这里不再累述，而是来看看这对性能会有什么影响。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TBD: 暂时处于纸上谈兵状态，后续我们需要找到实际测试数据来验证我们的分析和猜想。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在上一节中我们看到，在引入Service Mesh之后，客户端和服务器端之间不再直接连接，而是走了mesh转发。这必然会带来额外的资源消耗，肯定会对性能有所影响。但是具体会到什么地步？这些影响会有多大？什么情况下可能会导致不适合使用Service Mesh。让我们来深入探讨这个话题。&lt;/p&gt;
&lt;h2 id=&#34;序列化性能&#34;&gt;序列化性能&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-dreammesh-brainstorm-cost/images/conmunicate_huab4e269acba9c80a415d55b13620ba90_102545_2e2881d83991b93ca9c45e67f5e04727.webp 400w,
               /post/201802-dreammesh-brainstorm-cost/images/conmunicate_huab4e269acba9c80a415d55b13620ba90_102545_22668270a385d2ce1b5abdf2711cc3d9.webp 760w,
               /post/201802-dreammesh-brainstorm-cost/images/conmunicate_huab4e269acba9c80a415d55b13620ba90_102545_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-dreammesh-brainstorm-cost/images/conmunicate_huab4e269acba9c80a415d55b13620ba90_102545_2e2881d83991b93ca9c45e67f5e04727.webp&#34;
               width=&#34;760&#34;
               height=&#34;433&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;从图中可以看到，虽然加入Mesh（有可能是两个，如Istio/Conduit都是客户端服务器各一个），但是在Mesh内只读取（也可能做一些必要的修改）header，没有对Payload进行处理。&lt;/p&gt;
&lt;p&gt;因此，全程下来，和侵入式开发框架相比，以HTTP协议为例，对比如下：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;模式&lt;/th&gt;
&lt;th&gt;Payload序列化&lt;/th&gt;
&lt;th&gt;Payload反序列化&lt;/th&gt;
&lt;th&gt;HTTP协议解析&lt;/th&gt;
&lt;th&gt;HTTP协议组装&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;侵入式框架&lt;/td&gt;
&lt;td&gt;1次&lt;/td&gt;
&lt;td&gt;1次&lt;/td&gt;
&lt;td&gt;1次&lt;/td&gt;
&lt;td&gt;1次&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service Mesh&lt;/td&gt;
&lt;td&gt;1次&lt;/td&gt;
&lt;td&gt;1次&lt;/td&gt;
&lt;td&gt;3次&lt;/td&gt;
&lt;td&gt;3次&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;因此，全程下来，和侵入式开发框架相比：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在Payload序列化方面的开销相同&lt;/p&gt;
&lt;p&gt;都只是一次序列化和反序列化，而且都没有发生在Mesh内部。因此引入Service Mesh之后，完全不必担心Payload序列化和反序列化的性能。原来是什么性能现在还是如此，不增不减。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;多了两次HTTP协议的解析和组装&lt;/p&gt;
&lt;p&gt;假定HTTP协议处理的资源消耗为1，我们来看当Payload不同时的性能对比：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;消耗&lt;/th&gt;
&lt;th&gt;Payload很重&lt;/th&gt;
&lt;th&gt;Payload稍重&lt;/th&gt;
&lt;th&gt;Payload很轻&lt;/th&gt;
&lt;th&gt;Payload为空&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Payload序列化&lt;/td&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;侵入式开发框架协议处理     |&lt;/td&gt;
&lt;td&gt;2    |&lt;/td&gt;
&lt;td&gt;2    |&lt;/td&gt;
&lt;td&gt;2 |&lt;/td&gt;
&lt;td&gt;2 |&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service Mesh协议处理&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;侵入式开发框架总额     |&lt;/td&gt;
&lt;td&gt;10002    |&lt;/td&gt;
&lt;td&gt;102    |&lt;/td&gt;
&lt;td&gt;12 |&lt;/td&gt;
&lt;td&gt;2 |&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service Mesh总额&lt;/td&gt;
&lt;td&gt;10006&lt;/td&gt;
&lt;td&gt;106&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;消耗对比     |&lt;/td&gt;
&lt;td&gt;增加4/10000    |&lt;/td&gt;
&lt;td&gt;增加4%    |&lt;/td&gt;
&lt;td&gt;增加33% |&lt;/td&gt;
&lt;td&gt;增加200% |&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;结论就是：payload越重，Service Mesh增加的消耗就越不起眼。但是对于Payload很轻的情况，尤其对于HTTP GET这种没有payload的请求，Service Mesh消耗增加的就会变的很夸张：增加200%！&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;考虑服务器端处理请求的消耗大小&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;消耗&lt;/th&gt;
&lt;th&gt;消耗很大的请求&lt;/th&gt;
&lt;th&gt;一般请求&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;服务器端处理请求的消耗&lt;/td&gt;
&lt;td&gt;1000000&lt;/td&gt;
&lt;td&gt;10000&lt;/td&gt;
&lt;td&gt;100&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;侵入式开发框架     |&lt;/td&gt;
&lt;td&gt;10002    |&lt;/td&gt;
&lt;td&gt;102    |&lt;/td&gt;
&lt;td&gt;12 |&lt;/td&gt;
&lt;td&gt;2 |&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service Mesh&lt;/td&gt;
&lt;td&gt;10006&lt;/td&gt;
&lt;td&gt;106&lt;/td&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;侵入式开发框架总额&lt;/td&gt;
&lt;td&gt;1010002&lt;/td&gt;
&lt;td&gt;10102&lt;/td&gt;
&lt;td&gt;112&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Service Mesh总额&lt;/td&gt;
&lt;td&gt;1010006&lt;/td&gt;
&lt;td&gt;10106&lt;/td&gt;
&lt;td&gt;116&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;消耗对比     |&lt;/td&gt;
&lt;td&gt;增加少到可忽略    |&lt;/td&gt;
&lt;td&gt;增加4/10000    |&lt;/td&gt;
&lt;td&gt;增加3% |&lt;/td&gt;
&lt;td&gt;增加200% |&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;分析的结果，我们大体可以给出如下推断：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;对于普通请求，有payload而且服务器端需要处理时，多增加的4次HTTP协议处理带来的消耗不大，大部分情况下几乎可以忽略。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;对于特别轻量级的请求，比如没有payload而且服务器端处理简单（不做请求，或者足够简单如命中缓存）而且应答简单，则多增加的4次HTTP协议处理会带来非常明显的性能损失&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;TBD： 此处有待实际验证，需要跑性能测试进行对比。有测试数据的同学请联系我。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;网络传输开销&#34;&gt;网络传输开销&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-dreammesh-brainstorm-cost/images/remotecall_huad7c9da56dd523cfb97c852397f170dd_21599_4cce90093db2292c9602cb89262a73e8.webp 400w,
               /post/201802-dreammesh-brainstorm-cost/images/remotecall_huad7c9da56dd523cfb97c852397f170dd_21599_991ff067c22cf9f2374b012e58552a6d.webp 760w,
               /post/201802-dreammesh-brainstorm-cost/images/remotecall_huad7c9da56dd523cfb97c852397f170dd_21599_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-dreammesh-brainstorm-cost/images/remotecall_huad7c9da56dd523cfb97c852397f170dd_21599_4cce90093db2292c9602cb89262a73e8.webp&#34;
               width=&#34;760&#34;
               height=&#34;200&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如图所示，Service Mesh下，多了两次远程调用：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;client发送请求给和client一起部署的Mesh&lt;/li&gt;
&lt;li&gt;服务器端部署Mesh将收到的请求转发给Server&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;但是需要指出的是，这两次远程调用都发在在本地，也就是&amp;quot;localhost/127.0.0.1&amp;quot;，走loopback/环回地址。而loopback可以绕开TCP/IP协议栈的下层，也就是会跳过链路层，物理层之类，不会真的经过网卡走网络，而是直接在IP层就处理了。如果优化得当还可以用Unix Socket之类的进一步提升性能，因此这两个我标记为&amp;quot;local&amp;quot;的调用，实际可以理解为是在内存里面兜了一圈，而不是真的走网络。&lt;/p&gt;
&lt;p&gt;而两个标记为&amp;quot;remote&amp;quot;的调用，从网络条件来说可以认为是完全一致的，都是从client所在机器到server所在机器，中间的线路/速率/延迟/转发等都相同。&lt;/p&gt;
&lt;p&gt;这样一来，在网络传输开销方面，Service Mesh增加的开销只在于两次loopback的网络调用。这个开销和client/server之间真实的网络线路相比可以认为是非常小的，无论是网络流量还是网络延迟。&lt;/p&gt;
&lt;p&gt;推断：网络传输开销的增加基本上不大。&lt;/p&gt;
&lt;h2 id=&#34;内存开销&#34;&gt;内存开销&lt;/h2&gt;
&lt;p&gt;这里有两方面的内存开销增加：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Sidecar进程额外占用的内存&lt;/p&gt;
&lt;p&gt;和原有client/server进程相比，现在多了Sidecar的进程，必然会多出一些内存占用。&lt;/p&gt;
&lt;p&gt;首当其冲的就是以Java为典型代表的基于JVM的语言，由他们编写的sidecar天然就要额外占用很多内存。其次，通过GC机制来自动回收内存，内存占用也会多一些。因此，基于Scala语言的Linkerd在这方面就吃亏比较大，和基于C++的Envoy相比差距明显。所以后来Bueyant重新开发Conduit时干脆选择用Rust。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;请求转发过程中占用的内存&lt;/p&gt;
&lt;p&gt;请求在一路转发的过程中，sidecar肯定要占用内存的：毕竟一边接收请求，一边转发，期间要解析协议格式把Header读取出来。&lt;/p&gt;
&lt;p&gt;此时，sidecar代码实现中&amp;quot;zero copy&amp;quot;是最基本的要求，必须做到。&lt;/p&gt;
&lt;p&gt;遇到需要改动请求的情况就麻烦了，比如需要添加一个header(如http_x_forwarded_host)，需要去除某个header(抹掉某些敏感信息)，或者改写某个header的值(如Host)。在无法只读的情况下简单的&amp;quot;zero copy&amp;quot;肯定不可行，但是如果实现的足够好，起码Payload部分还是可以继续实现&amp;quot;zero copy&amp;quot;的。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TBD: 需要去读一下Envoy和Conduit的代码，看看他们具体如何实现。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在这一点上，HTTP/2（还有基于HTTP/2的gRPC）有天然优势：HTTP/2协议是基于帧的，Header帧和Data帧是分别发送的，因此对Header帧的修改完全不会影响到Data帧的处理，在编码实现上要比Header/Body一起传输的HTTP1.1简单的多。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;有一点应该比较明朗：Service Mesh不适合大文件传输。毕竟中间多了两次sidecar转发，对内存开销和后面提到的CPU开销都会有负面影响。&lt;/p&gt;
&lt;h3 id=&#34;sidecar的部署模型&#34;&gt;sidecar的部署模型&lt;/h3&gt;
&lt;p&gt;额外的话题：sidecar的部署模型，是否一定要和服务实例一对一？&lt;/p&gt;
&lt;p&gt;这是目前Istio/Conduit的标准部署模型，部署服务实例都会插入一个sidecar。考虑引入Docker之后，同一台物理机器上，容器的部署数量会大为增加，反映在服务实例上就是会有大量的服务实例部署在同一个物理机器上。此时是否应该考虑共享sidecar以减少sidecar的部署数量？这样可以大幅度的节约内存。&lt;/p&gt;
&lt;h2 id=&#34;cpu开销&#34;&gt;cpu开销&lt;/h2&gt;
&lt;p&gt;继续看回这个图片，多了两次sidecar的转发：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-dreammesh-brainstorm-cost/images/conmunicate_huab4e269acba9c80a415d55b13620ba90_102545_2e2881d83991b93ca9c45e67f5e04727.webp 400w,
               /post/201802-dreammesh-brainstorm-cost/images/conmunicate_huab4e269acba9c80a415d55b13620ba90_102545_22668270a385d2ce1b5abdf2711cc3d9.webp 760w,
               /post/201802-dreammesh-brainstorm-cost/images/conmunicate_huab4e269acba9c80a415d55b13620ba90_102545_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-dreammesh-brainstorm-cost/images/conmunicate_huab4e269acba9c80a415d55b13620ba90_102545_2e2881d83991b93ca9c45e67f5e04727.webp&#34;
               width=&#34;760&#34;
               height=&#34;433&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;必然会有CPU开销的增加：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;两次sidecar转发请求，无论是接收请求还是发送请求，都涉及到网络IO&lt;/li&gt;
&lt;li&gt;接收请求之后，必须解析协议，读取header&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;但是和前面序列化的分析类似，只有当请求足够简单并且服务器端处理请求的负载足够低导致QPS非常高时，才会对性能有明显影响。对于大多数情况，影响应该不大。&lt;/p&gt;
&lt;h2 id=&#34;讨论和反馈&#34;&gt;讨论和反馈&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;敖小剑：昨晚写好的，反思了一下sm的性能问题。你们有测试过吗？直连和走两次sidecar对性能有多大影响？&lt;/li&gt;
&lt;li&gt;田晓亮：影响不大，如果不是简单的helloworld，比如你的业务代码只往标准输出打印一行字符串，可以忽略。我觉得还是贴近真实来看性能损耗，因为真实世界没有helloworld&lt;/li&gt;
&lt;li&gt;敖小剑：如果是呢？我推演的是，简单请求加服务器端空实现，要除于3的。&lt;/li&gt;
&lt;li&gt;田晓亮：恩，空实现确实，下降40%吧。&lt;/li&gt;
&lt;li&gt;敖小剑：我们要备着一种情况，就是服务器端做了缓存，在缓存命中的情况下，服务器端接近空实现。&lt;/li&gt;
&lt;li&gt;田晓亮：对。但是一般性能瓶颈都在业务，性能下降可以忽略。其实我认为一般的业务tps真不高，尤其我面对的还有动态语言。&lt;/li&gt;
&lt;li&gt;崔秀龙：我是做了一段时间的优化工作之后，就再也不管啥性能问题了。&lt;/li&gt;
&lt;li&gt;田晓亮：恩，可以忽略，我的客户也没关心这个问题，不敏感。看到那么多能力后，估计觉得性能就不是事了。&lt;/li&gt;
&lt;li&gt;崔秀龙：我遇到的绝大多数性能问题是 debug/review 范畴，轮不到拔尖优化。&lt;/li&gt;
&lt;li&gt;敖小剑：嗯，我主要是担心有人较真，从推演上说空实现的极致性能会有超过50%的下降。这样你们以前说的30万qps估计应该保不住了。&lt;/li&gt;
&lt;li&gt;崔秀龙：我所见过的企业用户的计算资源不是不足，是多得愁人。&lt;/li&gt;
&lt;li&gt;田晓亮：还真是。&lt;/li&gt;
&lt;li&gt;李乘胜：一般大多数内部的企业系统，资源利用率都很低。&lt;/li&gt;
&lt;li&gt;敖小剑：我还在想着如果服务qps不高，每个服务实例一个sidecar是不是太浪费了？istio支持在单个节点上只部署一个envoy给多个pod里面的服务共用吗？&lt;/li&gt;
&lt;li&gt;崔秀龙：没这法子吧？不合理啊，如果说一个业务应用，跟envoy是同体量的，是不是太“微”了？qps 都不高了，多个envoy又不会怀孕。&lt;/li&gt;
&lt;li&gt;敖小剑：可是一个节点上跑几十个docker实例时，就起几十个envoy，好浪费啊。&lt;/li&gt;
&lt;li&gt;李大伟：我们以前也考虑过sidecar是不是太浪费了，没选sidecar模式，生产运营半年多后发现计算资源根本用不了，上层应用的qps一点都不给力。&lt;/li&gt;
&lt;li&gt;田晓亮：Sidecar肯定是最佳实践，只要内存控制住。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;有兴趣的朋友，请联系我的微信，加入DreamMesh内部讨论群。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>DreamMesh抛砖引玉(5)-网络通讯</title>
      <link>https://skyao.net/post/201802-dreammesh-brainstorm-communicate/</link>
      <pubDate>Mon, 19 Feb 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201802-dreammesh-brainstorm-communicate/</guid>
      <description>&lt;p&gt;在微服务时代，由于原有的单体系统被拆分为多个微服务，服务间通讯的数量大为增加。因此，选择什么样的远程通讯方案变得至为重要。&lt;/p&gt;
&lt;h2 id=&#34;背景&#34;&gt;背景&lt;/h2&gt;
&lt;p&gt;在深入讨论之前，先简单交代一下背景。对于远程通讯来说，有两个重点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;序列化协议&lt;/p&gt;
&lt;p&gt;序列化和反序列化方式，主要是两大派系：1. 文本格式，主流是REST（或者说JSON），XML。2. 二进制格式,主流如Thrift，Protocol Buffer, Hessian，还有某些框架特有的格式如Dubbo，另外Java社区还有以慢著称的Java序列化。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;远程调用方式&lt;/p&gt;
&lt;p&gt;主要是REST和RPC两个流派的竞争。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;传统侵入式开发框架&#34;&gt;传统侵入式开发框架&lt;/h2&gt;
&lt;p&gt;对于传统侵入式开发框架，远程通讯是其SDK的核心内容。客户端能选择什么样的通讯方案，取决于SDK可以支持哪些。&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;开发框架&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;Spring Cloud&lt;/td&gt;
&lt;td&gt;REST(或者说HTTP+JSON)&lt;/td&gt;
&lt;td&gt;明确拒绝二进制和RPC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;阿里Dubbo&lt;/td&gt;
&lt;td&gt;主要是RPC方案如Dubbo/Hessian/Rmi/WebService&lt;/td&gt;
&lt;td&gt;DubboX增加了对REST的支持&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;微博Motan&lt;/td&gt;
&lt;td&gt;Hessian/Json/Motan&lt;/td&gt;
&lt;td&gt;Agent方案支持gRPC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;唯品会OSP&lt;/td&gt;
&lt;td&gt;改进版本的Thrift&lt;/td&gt;
&lt;td&gt;只用了thrift的序列化，网络通讯重新改写&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dolphin&lt;/td&gt;
&lt;td&gt;gRPC&lt;/td&gt;
&lt;td&gt;我在2016年开发的微服务框架&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;TBD：需要更多调研。&lt;/p&gt;
&lt;p&gt;总体上说，REST和RPC两个方案都有，早期的部分框架还会保留诸如Hessian/Rmi/WebService&lt;/p&gt;
&lt;h2 id=&#34;service-mesh方式&#34;&gt;Service Mesh方式&lt;/h2&gt;
&lt;p&gt;我们进入正题，谈谈Service Mesh下的情况。&lt;/p&gt;
&lt;p&gt;首先我们来看看侵入式开发框架和Service Mesh的差异(仅以请求为例，应答是同理)：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-dreammesh-brainstorm-communicate/images/conmunicate_huab4e269acba9c80a415d55b13620ba90_102545_2e2881d83991b93ca9c45e67f5e04727.webp 400w,
               /post/201802-dreammesh-brainstorm-communicate/images/conmunicate_huab4e269acba9c80a415d55b13620ba90_102545_22668270a385d2ce1b5abdf2711cc3d9.webp 760w,
               /post/201802-dreammesh-brainstorm-communicate/images/conmunicate_huab4e269acba9c80a415d55b13620ba90_102545_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-dreammesh-brainstorm-communicate/images/conmunicate_huab4e269acba9c80a415d55b13620ba90_102545_2e2881d83991b93ca9c45e67f5e04727.webp&#34;
               width=&#34;760&#34;
               height=&#34;433&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;侵入式开发框架下，客户端和服务器端直接通讯，客户端做一次序列化，服务器端做一次反序列化&lt;/li&gt;
&lt;li&gt;Service Mesh就要复杂的多，在客户端和服务器端部署有一个或者两个Mesh，用于转发请求。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;首先，我们可以看到，&lt;strong&gt;Service Mesh下服务间通讯的方式是基于网络层&lt;/strong&gt;。在整个过程中，Mesh只需要能支持通讯协议，比如最常见的HTTP1.1/HTTP2，能做到接收请求并转发即可。原则上，Mesh接受到请求之后，只是读取Header获得必要信息，然后透传Payload。&lt;/p&gt;
&lt;p&gt;因此，对于选择什么样的序列化方案和远程访问方案并无限制：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;原则上Payload是透传的，Mesh并不关心其实质内容。&lt;/li&gt;
&lt;li&gt;Mesh收到的是网络请求，不关心这个请求客户端是如何发出来的，也就是说REST和PRC与否和Mesh无关。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;理论上说，&lt;strong&gt;传统侵入式开发框架可以选择的方案在Service Mesh下都是可以继续沿用的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;但是需要额外特别指出的是，在Service Mesh下，跨语言和跨平台是必须满足的基本需求。因此，任何语言和平台有关的序列化协议和远程调用方式都不适合，比如Java序列化，EJB之类。当然，目前主流的侵入式开发框架也基本都在遵循这个原则，只是Service Mesh下会做的更加的坚决。&lt;/p&gt;
&lt;h2 id=&#34;轻量级-vs-微服务&#34;&gt;轻量级 VS 微服务&lt;/h2&gt;
&lt;p&gt;按照Martin Fowler老爷子给出的微服务经典定义：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;微服务架构风格是一种将一个单一应用程序开发为一组小型服务的方法，每个服务运行在自己的进程中，&lt;strong&gt;服务间通信采用轻量级通信机制&lt;/strong&gt;(通常用HTTP Resource API)。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;服务间通信采用轻量级通信机制，这是微服务的美好愿景。但是，事情往往不是想象中那么完美。&lt;/p&gt;
&lt;h3 id=&#34;侵入式客户端窘境&#34;&gt;侵入式客户端窘境&lt;/h3&gt;
&lt;p&gt;以REST为例，虽然REST一直标榜轻量级，要发出一个REST请求对于任何语言都不是难事。但是一旦和微服务结合，就立马变得臃肿不堪，以Spring Cloud为例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;为了实现服务发现需要引入Eureka&lt;/li&gt;
&lt;li&gt;为了客户端的负载均衡需要引入Ribbon&lt;/li&gt;
&lt;li&gt;为了熔断需要引入Hystrix&lt;/li&gt;
&lt;li&gt;为了分布式追踪引入zipkin&lt;/li&gt;
&lt;li&gt;&amp;hellip;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了让各个类库协调工作，中间还有大量的集成工作，连自成一家的netflix OSS套件，在Spring Cloud集成中工作量也没少到哪里去。对于普通用户，无论刚开始的REST类库有多简单，只要开始了微服务之路，就不得不一个一个的功能坐上去：服务注册和服务发现是必须的，负载均衡也是必须的，熔断没有未免不够安全，没有APM debug时很不方便，有些还要考虑高级一点的功能如智能路由，还要考虑安全，比如认证/加密&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;因此，采用REST实现微服务，要不直接用Spring Cloud，要不就一路做下来做出一套类似Spring Cloud的系统。类似的，采用RPC方案来实现微服务，最终成型的系统也无外如是。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;侵入式开发框架，最终都会成为一个庞然大物&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这一路做下来，最开始起步时到底是不是轻量级已经无关轻重。此时作为这个庞然大物的核心和入口，客户端类库已经捆绑了太多的东西，重也是无可奈何。&lt;/p&gt;
&lt;p&gt;而太重也就意味着断无可能随意更换。开发框架的SDK集成了什么样的类库，那么用户的客户端就只能选择什么。&lt;/p&gt;
&lt;h3 id=&#34;源于service-mesh的自由&#34;&gt;源于Service Mesh的自由&lt;/h3&gt;
&lt;p&gt;在Service Mesh之下，有一个特别的地方：相比侵入式开发框架，客户端大为简化，只需要将生成请求并发送出去即可。上面列出的服务发现，负载均衡等各种功能由Service Mesh接管。客户端功能的极大简化，体现在开发的技术选型上，就是：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;可以自由的选择客户端类库&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;Service Mesh下的REST，才真的有了轻量级的感觉。采用REST开发，可以选择的类库和方式也就可以天马行空任意发挥了。对于RPC，由于不再需要在RPC中捆绑微服务框架的诸多功能，同样也是大为简化。&lt;/p&gt;
&lt;h4 id=&#34;service-mesh协议支持&#34;&gt;Service Mesh协议支持&lt;/h4&gt;
&lt;p&gt;对于HTTP1.1/HTTP2这样的有明确Header，格式通用的协议，Service Mesh都可以很轻松的提供支持。目前市面上主流的Servic Mesh实现都提供了对HTTP1.1的支持，而且基本也都提供HTTP2的支持。&lt;/p&gt;
&lt;p&gt;对于TCP协议的支持要稍微麻烦一些，但是只要格式清晰，有类似的Header/Payload结构，Service Mesh也还是有办法以类似的方式提供支持。麻烦只是在于需要为每个具体的TCP协议提供特定的扩展，无法像HTTP1.1/HTTP2可以通用。&lt;/p&gt;
&lt;p&gt;无论如何，&lt;strong&gt;Payload只透传不处理是基本原则&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;基于这个原则，序列化方式对Service Mesh来说就可以完全无关：无论是文本还是二进制，无论消息体结构如何，对Service Mesh而言都只是一段byte数组。&lt;/p&gt;
&lt;p&gt;至此，在Service Mesh加持下，服务间网络通讯的解决方案可以选择的余地就大了：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;可以自由选择HTTP1.1/HTTP2&lt;/li&gt;
&lt;li&gt;可以自由选择文本格式或者二进制格式，JSON/xml/thrift/protocol buffer随意&lt;/li&gt;
&lt;li&gt;可以自由选择REST/RPC&lt;/li&gt;
&lt;li&gt;可以自由选择相关的类库，不再需要各种集成&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;自由之下的烦恼&#34;&gt;自由之下的烦恼&lt;/h2&gt;
&lt;p&gt;自由的好处是我们可以任意选择各种方案，但是自由带来的一个烦恼就是没有一个足够好的方案可以简单借鉴，没有一个足够好的模式可以严格遵循。&lt;/p&gt;
&lt;p&gt;在微服务体系的各种功能之外，我们在开发时，还会遇到很多实际工作：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;REST开发时，到底该先定义好API，然后生成代码？还是先写代码，通过注解等方式来定义API？&lt;/li&gt;
&lt;li&gt;RPC开发时，schema该如何定义才更合理？&lt;/li&gt;
&lt;li&gt;接口的API文档要如何编写？&lt;/li&gt;
&lt;li&gt;错误码的定义，错误信息的传递&lt;/li&gt;
&lt;li&gt;集成测试时如何方便的mock依赖的微服务？&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;能否以最佳实践的方式给出适合service mesh时代的网络通讯方案？&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TBD： 需要继续调研/讨论。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;有兴趣的朋友，请联系我的微信，加入DreamMesh内部讨论群。&lt;/p&gt;
&lt;h2 id=&#34;讨论和反馈&#34;&gt;讨论和反馈&lt;/h2&gt;
&lt;p&gt;稍后补充。&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>DreamMesh抛砖引玉(4)-零侵入的代价</title>
      <link>https://skyao.net/post/201802-dreammesh-brainstorm-invasion/</link>
      <pubDate>Mon, 12 Feb 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201802-dreammesh-brainstorm-invasion/</guid>
      <description>&lt;p&gt;在介绍Service Mesh优点时，通常会特别突出一点：对应用侵入度低。&lt;/p&gt;
&lt;p&gt;侵入度低的根源于Service Mesh的架构，在将各种功能以Sidecar方式从客户端拆出来之后，客户端现在的功能可以说被缩减到就剩下最后一个功能了：将请求发送给Sidecar。&lt;/p&gt;
&lt;p&gt;也是Service Mesh方案相对于传统基于SDK的侵入式开发框架的本质差异之一。这个侵入性最低能低到什么地步？如果我们能让客户端代码只管把请求发出去，连发到哪都不用管，就可以实现所谓”零侵入”了。&lt;/p&gt;
&lt;h2 id=&#34;导流方式&#34;&gt;导流方式&lt;/h2&gt;
&lt;p&gt;因为客户端现在剩下的就一个功能：把请求发出去。请求是什么内容，以何种方式生成，这是应用需要自己完成的工作，同样如何发出去也是要自己完成，比如用HTTP client发出普通HTTP请求，或者用RestTemplate发送Rest请求，用gRPC客户端发出gRPC请求。&lt;/p&gt;
&lt;p&gt;但是发去哪里，这里还是有一点文章可以做的。&lt;/p&gt;
&lt;p&gt;为了让客户端发出的请求进入到Sidecar，有以下几种引导流量的方式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;手工设置&lt;/p&gt;
&lt;p&gt;直接在客户端代码中明确给出发送的目标Sidecar地址，比如&amp;quot;127.0.0.1:8080&amp;quot;。或者灵活一点，将这个sidecar地址写入到配置文件中。&lt;/p&gt;
&lt;p&gt;这个工作可以说毫无难度简直不费吃灰之力，但是不管怎么说也是要改动代码的，因此不能算是零侵入。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;proxy代理&lt;/p&gt;
&lt;p&gt;通过设置代理，可以是在代码中直接指定http proxy，也可以通过设置HTTP_PROXY这样的环境变量，或者&amp;quot;-Dhttp-proxy=&amp;ldquo;等方式来进行。实际操作中，考虑到几乎所有的HTTP客户端都支持环境变量或者系统参数来设置代理，因此通常都不会采用代码设置proxy的方式（不然这和上面那条手工设置目标地址的咸鱼有什么差异）。&lt;/p&gt;
&lt;p&gt;虽然这个方式也挺简单，但是和手工设置相比，有质的飞跃：不用改动代码，实现了零侵入。对于新应用开发而言意义不大，但是对于老系统迁移来说，非常有意义：这意味着不用修改代码，不用重新打包。&lt;/p&gt;
&lt;p&gt;但是这个方案有个限制，就是要求客户端代码能够支持proxy，如果遇到类库不支持时就没辙了。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;iptables劫持&lt;/p&gt;
&lt;p&gt;如果在linux上，iptables就可以用来解决这个问题。实现方式和proxy类似，只是proxy比较温和，和iptables要暴力的多：iptables实际是劫持流量，而且是在操作系统层面劫持，和应用的类库语言无关。&lt;/p&gt;
&lt;p&gt;这个方案的限制在在于操作系统：iptables需要linux。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;各家支持&#34;&gt;各家支持&lt;/h2&gt;
&lt;p&gt;在容器时代，由于容器是基于linux的，因此iptables劫持方案很自然就成为主流做法。&lt;/p&gt;
&lt;p&gt;Service Mesh中，Istio和Conduit都是非常明确的采用iptables劫持的方式。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TBD: istio据说是支持VM的，不确认在VM上运行的Istio是否也是采用iptables劫持。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Linkerd出现比较早，早期也没有专门针对容器环境做特别设计，因此Linkerd比较灵活，上述三种方式都支持。&lt;/p&gt;
&lt;h2 id=&#34;零侵入的代价&#34;&gt;零侵入的代价&lt;/h2&gt;
&lt;p&gt;然而，没有任何事情是可以十全十美的，零侵入虽好，也还有一些弊端的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;iptables一刀切的方案有滥用嫌疑&lt;/p&gt;
&lt;p&gt;我个人始终觉得只为指定一个请求目标地址就动用iptables这种大杀器有种杀鸡用牛刀的感觉。虽然确实是方便&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;为了不劫持某些网络访问又不得不想办法绕开&lt;/p&gt;
&lt;p&gt;如果客户端除了发送请求给服务之外，还有其他的网络访问，那么这个一刀切的方案就尴尬了：会劫持到不应该的请求，比如访问数据库，访问redis，访问外部系统等。&lt;/p&gt;
&lt;p&gt;为此，又不得不想办法避免错误劫持。&lt;/p&gt;
&lt;p&gt;比如Istio中，需要使用Egress规则来容许访问外部服务，对于非HTTP(s)请求，还不得不使用&lt;code&gt;--includeIPRanges&lt;/code&gt;的方式来绕开Sidecar代理。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;担心太多的iptables rules会影响性能或者造成系统不稳定&lt;/p&gt;
&lt;p&gt;这块暂时只是担心，并非有实际案例。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;TBD： 请大家补充或者纠正&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;多一个选择&#34;&gt;多一个选择？&lt;/h2&gt;
&lt;p&gt;目前Istio和Conduit都是直接iptables劫持，考虑到大多数场景其实没这必要，是否考虑补充一个低侵入的方案？通过配置项（如果sidecar的端口是固定的）或者环境变量向应用注入sidecar地址，应用代码当中只要简单（几行代码）使用这个地址即可。&lt;/p&gt;
&lt;p&gt;对于新开发或者容许改动的应用，这个工作量小到可以忽略，但是就可以不用iptables劫持，也无需再担心错误的劫持到了其他流量。&lt;/p&gt;
&lt;p&gt;当然，对于不想修改代码就直接上Service Mesh的场景，iptables劫持方案还是很合适的。&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;有兴趣的朋友，请联系我的微信，加入DreamMesh内部讨论群。&lt;/p&gt;
&lt;h2 id=&#34;讨论和反馈&#34;&gt;讨论和反馈&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：iptables有谁熟悉啊？Istio和Conduit这样用iptables做流量劫持，我总觉得不是很正道，但又说不出大道理来&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;宋净超：k8s也是这么搞的，其实都是这么弄的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;崔秀龙：很主流。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：你们没啥意见吗？我个人有点喜欢多个选择，提供一个超轻量级的客户端，把请求以普通方式发给mesh，而不是非的走劫持&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;张琦：你说的那个就是我们的mesher提供的方式，因为要走iptables的话很有可能跟容器网络或者虚拟机网络产生耦合和影响&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：晓亮说Mesher是用的http proxy的方式来引导流量，遇到不想被劫持的流量时，就设置&lt;code&gt;no_proxy&lt;/code&gt;，这个方式和iptables劫持和设置egress穿透是一回事&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：这篇写的不是太好，原因在于我不是很有底气。我对零侵入和iptables劫持的反对和犹豫不是因为我觉得这个有多不好，而是我性格中觉得这么点事犯不着用这么决绝的手段。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;崔秀龙： 下午讨论这玩意的时候，我也提醒了朋友一句性能问题，他比我更随意的反应了一句——我没准备把我们的垃圾应用写到交换机里面。马丁也有过一句类似的话，透明就是个巨大的好处&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;林静：应用直接发sidecar目标地址，那sidecar怎么知道实际目标服务的地址？如果这样 应用payload里还得有信息告诉sidecar去解析相关内容，并转化为tcp 目标ip和端口吧。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：非常好的问题，稍后调研一下细节。按照我的经验，一般还是需要携带一个服务信息，一般是HTTP header比如Host。TBD：后续再更新&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;孙寅：可以默认iptables，但不应该没有其它选择。工业上使用，iptables最大的问题是带来的网络性能损耗&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>DreamMesh抛砖引玉(3)-艰难的过渡</title>
      <link>https://skyao.net/post/201802-dreammesh-brainstorm-transition/</link>
      <pubDate>Sun, 11 Feb 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201802-dreammesh-brainstorm-transition/</guid>
      <description>&lt;p&gt;在上一篇中，我们讨论的话题是：如果没有做好Cloud Native的准备，该怎么上Service Mesh。本章继续讨论，假定Cloud Native已经准备好，看看Service Mesh的道路是否就一帆风顺。&lt;/p&gt;
&lt;h2 id=&#34;问题所在&#34;&gt;问题所在&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;如何从非Service Mesh体系过渡到Service Mesh？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;我们需要考虑的是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;即使一切准备就绪，对于一个有存量应用的系统而言，绝无可能将所有应用都一起改为Service Mesh，然后一夜之间上线。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;必然会有一个中间过渡状态，一部分应用开始搬迁到Service Mesh，一部分还停留在原有体系。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;那么，在过渡阶段，Service Mesh内的服务和Service Mesh外的服务在通讯时会遇到哪些问题？&lt;/p&gt;
&lt;h2 id=&#34;场景分析&#34;&gt;场景分析&lt;/h2&gt;
&lt;p&gt;我们来看一个具体的例子，有三个服务，调用关系分别是A-&amp;gt;B-&amp;gt;C，然后在最前面架设API Gateway。非常典型的微服务体系：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-dreammesh-brainstorm-transition/images/original_huf079826d03815469e35c11a261d79682_30797_527d0e0ec92862abd9487357288ae226.webp 400w,
               /post/201802-dreammesh-brainstorm-transition/images/original_huf079826d03815469e35c11a261d79682_30797_dce1785cec5ac32519d557dbba66734f.webp 760w,
               /post/201802-dreammesh-brainstorm-transition/images/original_huf079826d03815469e35c11a261d79682_30797_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-dreammesh-brainstorm-transition/images/original_huf079826d03815469e35c11a261d79682_30797_527d0e0ec92862abd9487357288ae226.webp&#34;
               width=&#34;358&#34;
               height=&#34;474&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里可以是spring cloud/dubbo/motan等各种侵入式微服务架构，左边的注册中心/registry的实现也可以有多种，服务间通讯的方式也不尽相同。但是，都不影响我们的讨论。&lt;/p&gt;
&lt;p&gt;上图可以看到，在标准的微服务框架中，处理这样一个请求，调用方式是清晰明了的。&lt;/p&gt;
&lt;p&gt;如果开始转向Service Mesh体系，无论是Istio/Conduit，都会引入一个新的k8s体系。为了充分演示，我们选择将服务B转移到Service Mesh。调用关系就一下变成复杂：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-dreammesh-brainstorm-transition/images/service-b-moved_hu6537fab2552a6c7d698dc8d2411a0e38_63985_d280e5a8eba8747fc7df318c8750931b.webp 400w,
               /post/201802-dreammesh-brainstorm-transition/images/service-b-moved_hu6537fab2552a6c7d698dc8d2411a0e38_63985_22759a3055e862fa17d052c7eac96507.webp 760w,
               /post/201802-dreammesh-brainstorm-transition/images/service-b-moved_hu6537fab2552a6c7d698dc8d2411a0e38_63985_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-dreammesh-brainstorm-transition/images/service-b-moved_hu6537fab2552a6c7d698dc8d2411a0e38_63985_d280e5a8eba8747fc7df318c8750931b.webp&#34;
               width=&#34;760&#34;
               height=&#34;477&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里我们引入两个术语（TBD：应该是业界通用术语吧？待确认）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;东西向通讯：指微服务间相互调用&lt;/li&gt;
&lt;li&gt;南北向通讯：指外界访问微服务体系，通常是通过API Gateway&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;当B被迁移后，B原有的上游调用（A调用B）和下游调用（B调用C），虽然业务语意上依然还是东西向通讯，但是由于跨了体系导致原有的调用方式被打破。只能另想办法，目前看通常的做法都是改走南北向通讯。&lt;/p&gt;
&lt;h2 id=&#34;影响&#34;&gt;影响&lt;/h2&gt;
&lt;p&gt;而这个改变会带来巨大的工作量：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;B的所有上游服务都要修改&lt;/p&gt;
&lt;p&gt;原有的标准服务间通讯（通过sdk进行服务发现/负载均衡等）都废弃，需要改为对k8s体系入口如Ingress的调用。然后在Ingress这边也要做好对服务B的配置。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;B对所有下游服务的调用方式都要修改&lt;/p&gt;
&lt;p&gt;同样，原有的标准服务间通讯都废弃，需要改为对API Gateway的调用。然后在API Gateway这边也要做好对下游服务的配置。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;而通讯机制改变带来的工作量不是唯一的问题，还有一个内部服务对外暴露的问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在原有体系中，服务B和服务C都是内部服务，完全可以不对外暴露，API Gateway访问的只是服务A&lt;/li&gt;
&lt;li&gt;迁移之后，为了让服务B的上游服务能够访问到服务B，就不得不将服务B暴露出来。&lt;/li&gt;
&lt;li&gt;同样，为了让服务B能够访问它的下游服务，就不得不将服务C暴露出来&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;原体系中只有服务A对外暴露，现在服务B和服务C也不得不暴露。而对外暴露服务，就意味着必然还会有一堆相关的工作需要完成：&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;&amp;hellip;&amp;hellip;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而这些都意味着：工作量/复杂度/更多的开发测试上线。&lt;/p&gt;
&lt;h2 id=&#34;后续影响&#34;&gt;后续影响&lt;/h2&gt;
&lt;p&gt;随着应用往Service Mesh体系的逐渐迁移，我们开始迁移服务C和服务A。&lt;/p&gt;
&lt;p&gt;先看服务C迁移到来的变化：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-dreammesh-brainstorm-transition/images/service-c-moved_hu916dcdb2bfa8564b574ae1907412efdd_63273_01c5dd2fece1e1fa26dee36b64deb038.webp 400w,
               /post/201802-dreammesh-brainstorm-transition/images/service-c-moved_hu916dcdb2bfa8564b574ae1907412efdd_63273_0cf9aa80f2e3790d9d96c9ed113cd811.webp 760w,
               /post/201802-dreammesh-brainstorm-transition/images/service-c-moved_hu916dcdb2bfa8564b574ae1907412efdd_63273_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-dreammesh-brainstorm-transition/images/service-c-moved_hu916dcdb2bfa8564b574ae1907412efdd_63273_01c5dd2fece1e1fa26dee36b64deb038.webp&#34;
               width=&#34;760&#34;
               height=&#34;490&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;此时服务B到服务C的调用从原来的走API Gateway改变为Service Mesh体系内的服务间调用。然后API Gateway不再需要调用服务C，可以去除和服务C相关的内容。&lt;/p&gt;
&lt;p&gt;再看服务A的迁移：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-dreammesh-brainstorm-transition/images/service-a-moved_hu216c924f14d8f641ab95c1d510cdb8b1_59057_bc729c12a20248a8477939e61f05b6c1.webp 400w,
               /post/201802-dreammesh-brainstorm-transition/images/service-a-moved_hu216c924f14d8f641ab95c1d510cdb8b1_59057_f446ed0c84755404a562c84cdbbcf439.webp 760w,
               /post/201802-dreammesh-brainstorm-transition/images/service-a-moved_hu216c924f14d8f641ab95c1d510cdb8b1_59057_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-dreammesh-brainstorm-transition/images/service-a-moved_hu216c924f14d8f641ab95c1d510cdb8b1_59057_bc729c12a20248a8477939e61f05b6c1.webp&#34;
               width=&#34;760&#34;
               height=&#34;476&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;此时服务B不再需要暴露，而服务A的暴露方式发生变化，另外服务A调用服务B的方式也有改变。&lt;/p&gt;
&lt;p&gt;我们抛开细节，只看整体：在服务A/B/C迁移到Service Mesh体系的过程中，&lt;strong&gt;服务间调用方式和对外暴露方式的变化&lt;/strong&gt;，带来了一系列的工作量。而耗费这些工作量的中间环节，在整体迁移完成之后都会消失。换言之，都是迫不得已的临时投入，对最后的系统不产生增益。&lt;/p&gt;
&lt;p&gt;直白一点：在过渡阶段的这诸多折腾，只是完成了服务迁移，而不能带来任何收益。这一点，无疑是令人沮丧的。&lt;/p&gt;
&lt;h2 id=&#34;问题本质&#34;&gt;问题本质&lt;/h2&gt;
&lt;p&gt;反思一下：为何服务只是体系间迁移一下，就需要增加这么多不带来实际收益的工作量和复杂度？到底我们上面这些折腾是在做什么？&lt;/p&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;p&gt;迁移过程中，服务A/B/C之间的通讯在业务语意上虽然依然属于东西向的服务间通讯机制，但是在实现上，却不得不临时转为南北向的网关到服务的通讯机制。&lt;/p&gt;
&lt;p&gt;这个转变是无奈的，两个体系之间存在以下问题导致无法继续走东西向服务间通讯机制：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;没有共同的registry，因此无法相互感知&lt;/li&gt;
&lt;li&gt;没有可以直接连通的网络通道，原有的服务间通讯被迫走公开的API Gateway和Ingress通道&lt;/li&gt;
&lt;li&gt;两个体系的服务间通讯机制也可能不同，导致迁移之后不得不重新实现服务间通讯机制&lt;/li&gt;
&lt;li&gt;API Gateway和Ingress对于服务暴露的方式也不尽相同，各种特性如认证/加密/服务路由等方式也很可能完全不同。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这就如同江河中的淡水鱼，如果要随波汇入大海，就必须要能适应海水。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-dreammesh-brainstorm-transition/images/sea_hu3ccdfae7365c5a974b895da08b682462_78698_4ca916219e246864d4ad47388761ec68.webp 400w,
               /post/201802-dreammesh-brainstorm-transition/images/sea_hu3ccdfae7365c5a974b895da08b682462_78698_0af18d366a704d2cf18356cd6b49d7d3.webp 760w,
               /post/201802-dreammesh-brainstorm-transition/images/sea_hu3ccdfae7365c5a974b895da08b682462_78698_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-dreammesh-brainstorm-transition/images/sea_hu3ccdfae7365c5a974b895da08b682462_78698_4ca916219e246864d4ad47388761ec68.webp&#34;
               width=&#34;720&#34;
               height=&#34;405&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;然后我们的问题在于，在过渡阶段，不得不花费大量投入来的完成被两个体系分割的服务间通讯，增加了大量额外的工作。&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;有没有办法解决这个问题，或者部分减轻工作量，为将来的Service Mesh转型做好准备？&lt;/p&gt;
&lt;p&gt;后续章节会深入探讨这个话题，给出部分解决方案，也欢迎大家给出意见或者参与讨论。&lt;/p&gt;
&lt;p&gt;有兴趣的朋友，请联系我的微信，加入DreamMesh内部讨论群。&lt;/p&gt;
&lt;h2 id=&#34;讨论和反馈&#34;&gt;讨论和反馈&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;冉启春：任何两个架构体系的迁移都是痛苦的&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;于文涛：运维团队负责容器化和k8s,基础架构部负责数据库拆分和分库分表以及底层中间件，业务平台部门参与微服务业务改造，其实路径没有统一的，得看不同团队的执行结果和如何协调了。谁强势先突破可能会有主导权。不过一般的路径是先底层后业务层。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>DreamMesh抛砖引玉(2)-CloudNative</title>
      <link>https://skyao.net/post/201802-dreammesh-brainstorm-cloudnative/</link>
      <pubDate>Sat, 10 Feb 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201802-dreammesh-brainstorm-cloudnative/</guid>
      <description>&lt;p&gt;我对Service Mesh的第一个担忧，来自 &lt;strong&gt;Cloud Native&lt;/strong&gt;。&lt;/p&gt;
&lt;h2 id=&#34;are-you-ready&#34;&gt;Are You Ready？&lt;/h2&gt;
&lt;p&gt;作为Cloud Native的忠实拥护者，我从不怀疑Cloud Native的价值和前景。可以说，微服务/容器这些技术天然就适合走Cloud Native的道路。&lt;/p&gt;
&lt;p&gt;但是，我担心的是：准备上Service Mesh的各位，是否都已经做到了Ready for Cloud Native？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-dreammesh-brainstorm-cloudnative/images/are-you-ready_hu7ade1b7c798ff77c498ba689660fa521_51337_b9c26dfeff8c68166e2b939a5a1cb1b0.webp 400w,
               /post/201802-dreammesh-brainstorm-cloudnative/images/are-you-ready_hu7ade1b7c798ff77c498ba689660fa521_51337_f4de98a12facb8940c5eb44464160ded.webp 760w,
               /post/201802-dreammesh-brainstorm-cloudnative/images/are-you-ready_hu7ade1b7c798ff77c498ba689660fa521_51337_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-dreammesh-brainstorm-cloudnative/images/are-you-ready_hu7ade1b7c798ff77c498ba689660fa521_51337_b9c26dfeff8c68166e2b939a5a1cb1b0.webp&#34;
               width=&#34;400&#34;
               height=&#34;264&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这真是一个尴尬的问题。&lt;/p&gt;
&lt;p&gt;现实摆在眼前，根据我最近几个月跑过的企业客户（大大小小接近二十家）的实际情况看，可以说：情况非常不乐观。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注： 这里只讨论普通企业用户，对于技术和管理都比较先进的互联网大公司来说，Cloud Native的普及情况要好很多。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这就引出了下面这个问题：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;如果没有Cloud Native基础，那还能不能用Service Mesh？&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;发展路径&#34;&gt;发展路径&lt;/h2&gt;
&lt;p&gt;这里有三条发展路径可选：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;先Cloud Native，再Service Mesh&lt;/p&gt;
&lt;p&gt;理论上说，这是最合理的：先把底层基础设施铺好，再在其上构建上层业务应用。&lt;/p&gt;
&lt;p&gt;具体说，就是先上云/容器/k8s，应用暂时维持原状。不管是单体应用，还是基于Dubbo/Spring Cloud等侵入式开发框架的微服务应用，先上云再说。更直白一点，上k8s。&lt;/p&gt;
&lt;p&gt;等待Istio/Conduit成熟之后，再迁移到Service Mesh方案。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;先Service Mesh，再Cloud Native&lt;/p&gt;
&lt;p&gt;这个方案理论上也是可行的：先用Service Mesh方案完成微服务体系建设，之后再迁移到k8s平台。&lt;/p&gt;
&lt;p&gt;之所以说&lt;strong&gt;理论上&lt;/strong&gt;没有问题，是指Service Mesh从设计理念上，对底层是不是容器并没有特别要求。无论是容器/虚拟机/物理机，Service Mesh都是可行的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;同时上Service Mesh加Cloud Native&lt;/p&gt;
&lt;p&gt;通常来说我们不赞成同时进行这两个技术变革，因为涉及到的内容实在太多，集中在一起，指望一口气吃成大胖子，容易被噎住。&lt;/p&gt;
&lt;p&gt;但是不管怎么样这条路终究还是存在的，而且如果决心够大+愿意投入+高人护航，也不失是一个一次性彻底解决问题的方案，先列在这里。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;何去何从&#34;&gt;何去何从&lt;/h2&gt;
&lt;p&gt;路径1和路径2，在讨论该如何选择之前，还有一个问题：就是路径2是不是真的可行？&lt;/p&gt;
&lt;h3 id=&#34;青黄不接的尴尬&#34;&gt;青黄不接的尴尬&lt;/h3&gt;
&lt;p&gt;我们前面说道路径2理论上是可行的，但是目前的实际情况是真要选择就会发现：难。这要从目前市面上的Service Mesh产品谈起，按照我的划分方式，我将目前主流的四个Service Mesh产品划分为两代：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;第一代Service Mesh，包括Linkerd和Envoy。&lt;/p&gt;
&lt;p&gt;这两个产品目前都是production ready，而且都和平台无关，对物理机/虚拟机/容器都可以支持。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;第二代Service Mesh，包括Istio和Conduit&lt;/p&gt;
&lt;p&gt;这两个产品目前都还在发展中，暂时都未能达到production ready。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果要在当前时刻进行Service Mesh的技术选型，我们就会发现这样一个尴尬的局面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Istio和Conduit还没有production ready，上线不适合，只能继续等待。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Linkerd和Envoy倒是可用，但是，在了解Istio和Conduit之后，又有多少人愿意在现在选择上Linkerd和Envoy？49年入国军？&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所谓&lt;strong&gt;青黄不接&lt;/strong&gt;，便是如此。&lt;/p&gt;
&lt;p&gt;在接下来的讨论中，我们假定大家都是在等待Istio和Conduit。&lt;/p&gt;
&lt;p&gt;我们回到前面的话题，限定Istio和Conduit，如果选择路径2(先Service Mesh，再Cloud Native)，会如何？&lt;/p&gt;
&lt;h3 id=&#34;对平台的要求&#34;&gt;对平台的要求&lt;/h3&gt;
&lt;h4 id=&#34;conduit&#34;&gt;Conduit&lt;/h4&gt;
&lt;p&gt;首先Conduit非常坚定执着的&amp;quot;Say No&amp;quot;了，官网非常清晰的表述：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Conduit is a next-generation ultralight service mesh for Kubernetes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;私底下和William就此简单聊过，他给出来的回答很委婉也很实在：conduit总要从某个地方起步，k8s是目前最好选择。以后可以支持，但是肯定先k8s再说。考虑到Conduit和Buoyant公司的处境，尤其全公司才二十，我们不能要求太多。&lt;/p&gt;
&lt;p&gt;可以明确的说，短期之内，起码2018年，Conduit官方不会有对k8s之外的支持。&lt;/p&gt;
&lt;h4 id=&#34;istio&#34;&gt;Istio&lt;/h4&gt;
&lt;p&gt;Isito最早版本是只支持k8s的，后来陆续提供了对其他非k8s环境的支持，比如Docker+Consul/Eureka的方案，还有计划中但是还没有完成的Cloud Fountry和Mesos集成。&lt;/p&gt;
&lt;p&gt;对于VM，istio有提供一个VM解决方案，具体看见官方文档：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://istio.io/docs/guides/integrating-vms.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Integrating Virtual Machines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://istio.doczh.cn/docs/guides/integrating-vms.html&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;集成虚拟机&lt;/a&gt;: 中文翻译版本&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从文档上看是可以支持部分服务在k8s之外：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;http://istio.doczh.cn/docs/img/mesh-expansion.svg&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;TBD： 需要继续调研看istio是否可以在纯粹的VM环境下运行，即完全脱离k8s和容器。&lt;/p&gt;
&lt;h3 id=&#34;平台要求总结&#34;&gt;平台要求总结&lt;/h3&gt;
&lt;p&gt;Conduit和Istio（还有待最后确认）对容器/K8s/Cloud Native都有要求，导致目前路径2（先Service Mesh，再Cloud Native）几乎没有无法实现，至少在不改动Conduit和Istio的情况下。&lt;/p&gt;
&lt;p&gt;这就意味着，只能走路径1（先Cloud Native，再Service Mesh），也就回到了最早的问题： 做好了Cloud Native的准备吗？&lt;/p&gt;
&lt;h2 id=&#34;后记&#34;&gt;后记&lt;/h2&gt;
&lt;p&gt;需要做一个市场调查，要有足够多的样本：&lt;/p&gt;
&lt;p&gt;企业客户对微服务和容器，是打算先上容器/k8s再上微服务，还是希望可以直接在虚拟机/物理机上做微服务，后面再迁移到k8s？&lt;/p&gt;
&lt;p&gt;有兴趣的朋友，请联系我的微信，加入DreamMesh讨论群就此话题展开讨论。&lt;/p&gt;
&lt;h2 id=&#34;讨论和反馈&#34;&gt;讨论和反馈&lt;/h2&gt;
&lt;p&gt;在这篇博客文章编写前一天晚上，和来自Google Istio开发团队的Hu同学有过一次长时间的讨论。&lt;/p&gt;
&lt;p&gt;在征得同意之后我将讨论内容整理如下。特别鸣谢Hu同学的指点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Hu: 你好，这么晚还在工作？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：正在整理思路。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hu: 文章写的很好。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：您客气了，还是你们产品做的好，istio我是报以厚望。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hu：希望不要让大家失望，能够解决一些实际问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：一起努力吧，就算有小的不足，也还是有机会改进的，istio的大方向我是非常认可的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hu：恩，现在是一个新时代的开始，cloud native是大势所趋，后面我们会看到更多有趣的技术出来。有什么想法和建议，也欢迎在istio的工作组里提。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：我现在是一边等istio的production ready版本，一边着手准备，为落地可能遇到的问题或者需求预先研究一下。&lt;/p&gt;
&lt;p&gt;国内可能情况和美国不太一样，目前国内企业，尤其传统形的企业，他们的技术基础非常糟糕，离cloud native差距很远。&lt;/p&gt;
&lt;p&gt;但是他们又有强烈的意愿上微服务。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hu：对，但这也是机遇。国内的企业软件市场还有很大空间。美国公司喜欢新技术，跟的比较紧。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：我选择istio这种service mesh方案来推微服务落地，本意是降低微服务普及的门槛。&lt;/p&gt;
&lt;p&gt;这样普通企业用户才有机会玩转微服务，毕竟这些公司连spring cloud都玩的很吃力。&lt;/p&gt;
&lt;p&gt;现在的问题是，istio比较强调cloud native，而这些企业用户基本都没有准备好cloud native。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hu：呵呵，我觉得你的想法很好，不过可能有点超前。据我所知，即使在很多互联网大企业, service mesh也没有完全落地。第一步可能还是docker化和普及kubernetes。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：我刚才还在看如何在非k8s，非docker环境下跑istio。嗯，你的思路是先准备好路，再让istio这辆车上路？我的思路有点倾向于让service mesh这个车在没路的情况下也能跑起来。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hu：我的意思是要看条件，可以把非K8S方案作为一个过渡。最终还是要迁移到kube和云上。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：嗯，对的，我想增加一个过渡阶段。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hu：都可以的，就看企业的自身条件了。Google这边是提供不同解决方案的，但最终目标还是希望客户迁移到云上。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：cloud native条件不成熟的情况下，先过渡一下，把应用迁移到非docker条件下的istio，先完成微服务化。&lt;/p&gt;
&lt;p&gt;两条路，一条先cloud native再service mesh，一条先service mesh再cloud native。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hu：恩，我觉得都是可行的。如果是重IT的公司，建议直接cloudnative。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：不同企业可能演进的速度和步骤不一样。微服务化更多是业务团队推动，cloud native通常是运维和基础架构团队。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hu：我对国内情况不了解，只是个人看法，呵呵。其实可能最重要的还是普及devops的模式，人的问题解决了，别的都好办。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：嗯，我个人的感觉是技术导向的互联网公司容易做到cloud native，他们走你说的路线比较合理。但是普通企业用户可能会选择先微服务化。&lt;/p&gt;
&lt;p&gt;当然这个我还要继续调研和确认，比较我现在接触的样本也不够多。所以，多讨论多沟通，确认好实际需要再说。&lt;/p&gt;
&lt;p&gt;我这段时间会陆陆续续把想法写出来，然后提交大家讨论。希望你多给意见。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Hu：好的。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在这篇博客文章发表收集到的讨论和评论反馈：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;张琦：我们的经验，必定要走你说的路径2，servicemesh甚至要充当从传统应用到Cloudnative之间的桥梁。例如在逐渐微服务化的过程中 用mesh来接入原来的单体应用 然后再一点一点去拆；或者用mesh接入其他协议的遗留应用来做一下协议转换，我记得微博也有这种用法&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;崔秀龙：posta那篇微服务改造的文章还是很可以参考的&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;肖晟：没错，企业随着IT架构的演进，上面提到的遗留应用并不在少数。需要解决协议适配等问题，又不想受限于服务总线类流量中心的瓶颈，mesh是一种理想的解决之道；而想要上mesh，又可能推动其上cloudnative。所以从企业总体来说，这个演变很可能是混合的，不过从单应用来说会是分步的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;肖晟：另外在思考的一个问题是，在一个企业IT架构下，由于不同技术标准或安全需求等因素的影响，有没有可能同时存在两套或多套servicemesh。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注： 这个话题后面会有专门的章节&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;崔秀龙：我觉得是两个必须：必须容器云，必须打SC。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;宋净超：理想很丰满，现实很骨感啊。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;崔秀龙：我个人的感觉是有了SM之后，微服务的定义就很清晰了。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;宋净超：同意。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;孟樊亮：迁移到k8s，感觉是服务注册/发现/互通只是第一步，后续的治理和运维才是无尽大坑。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;于文涛：我们公司应该是偏第一种方案，先走容器化，k8s后微服务化。不过微服务和也其实在同时推进。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>DreamMesh抛砖引玉(1)-序言</title>
      <link>https://skyao.net/post/201802-dreammesh-brainstorm-preface/</link>
      <pubDate>Fri, 09 Feb 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201802-dreammesh-brainstorm-preface/</guid>
      <description>&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;相信能看到这篇博客的同学，大体都知道过去几个月间，我在努力的研究Service Mesh并致力于在国内拓荒和布道。&lt;/p&gt;
&lt;p&gt;坦言说：Service Mesh的发展进程，当前还处于前景虽然一致看好，但是脚下的路还是需要一步一步走的早期艰难阶段。由于istio和conduit的尚未成熟，造成目前Service Mesh青黄不接的尴尬局面。&lt;/p&gt;
&lt;p&gt;近期在和很多朋友交流，也都谈到这个话题，着实有些无奈，只能静静的等待istio和conduit的发展。好在这两个产品也很争气，近期都快速发出了新版本。&lt;/p&gt;
&lt;p&gt;然而Service Mesh的现状，它的不够成熟，终究还是引发了猜疑，不安和观望。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-dreammesh-brainstorm-preface/images/doubt-kills-dreams_huf493f29d8a5c872e31b18e53c88e1cd0_100668_8d6ada1031c4ef2c01957b72cbdb4009.webp 400w,
               /post/201802-dreammesh-brainstorm-preface/images/doubt-kills-dreams_huf493f29d8a5c872e31b18e53c88e1cd0_100668_f918379cb54941c33b7a192c6c1bfbd7.webp 760w,
               /post/201802-dreammesh-brainstorm-preface/images/doubt-kills-dreams_huf493f29d8a5c872e31b18e53c88e1cd0_100668_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-dreammesh-brainstorm-preface/images/doubt-kills-dreams_huf493f29d8a5c872e31b18e53c88e1cd0_100668_8d6ada1031c4ef2c01957b72cbdb4009.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Doubt kills more dreams than failure ever has&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;在猎鹰升空，马斯克封神的本周，我更能深刻体会这句话的内涵。&lt;/p&gt;
&lt;h2 id=&#34;正视问题&#34;&gt;正视问题&lt;/h2&gt;
&lt;p&gt;过去的一个月间，我一直在认真的思考这样一个问题：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Service Mesh真的能完美解决问题吗？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这里我们抛开前面所说的istio或者conduit暂未成熟的情况，毕竟在不远的未来即将可以（至少有很大希望）被解决，不出意外会在2018年年中或者年底。&lt;/p&gt;
&lt;p&gt;让我们设想：如果明天Istio或者conduit发布出Production Ready的版本，是不是我们就可以欢欣鼓舞的直接将系统搬迁到service mesh上？&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;p&gt;Ready for Cloud Native?&lt;/p&gt;
&lt;p&gt;我对Service Mesh的第一个担忧，来自 &lt;strong&gt;Cloud Native&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;作为Cloud Native的忠实拥护者，我不怀疑Cloud Native的价值和前景。但是，我担心的是：准备上service mesh的各位，是否都已经做到了ready for Cloud Native？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如何从非Service Mesh体系过渡到Service Mesh？&lt;/p&gt;
&lt;p&gt;即使一切都ready，对于一个有存量应用的系统而言，绝无可能在一夜之间就将所有应用都改为Service Mesh，然后一起上线。&lt;/p&gt;
&lt;p&gt;必然会有一个中间过渡状态，一部分应用开始搬迁到Service Mesh，大部分还停留在原有体系。那么，如何在过渡阶段让Service Mesh内的服务和Service Mesh外的服务相互通讯？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;零侵入的代价&lt;/p&gt;
&lt;p&gt;Service Mesh的一个突出优点就是对应用的侵入度非常低，低到可以&amp;quot;零侵入&amp;quot;。&lt;/p&gt;
&lt;p&gt;然而，没有任何事情是可以十全十美的，零侵入带来的弊端：iptables一刀切的方案有滥用嫌疑，为了不劫持某些网络访问又不得不增加配置去绕开。&lt;/p&gt;
&lt;p&gt;是否考虑补充一个低侵入的方案？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;网络通讯方案&lt;/p&gt;
&lt;p&gt;Service Mesh解决服务间通讯的方式是基于网络层，HTTP1.1/HTTP2和可能的TCP，对于选择什么样的序列化方案和远程访问方案并未限制。&lt;/p&gt;
&lt;p&gt;好处是我们可以自由的选择各种方案，坏处就是自由意味着自己做。&lt;/p&gt;
&lt;p&gt;能否以类库或者最佳实践的方式给出适合service mesh时代的网络通讯方案？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;性能开销&lt;/p&gt;
&lt;p&gt;我们反复谈到，Service Mesh的核心在于将原有以类库方式提供的功能拆分到独立的sidecar进程中，以远程调用的方式来强行解耦服务间通讯的业务语义和服务间通讯的具体实现。这带来了诸多的好处，但是这对性能会有什么影响？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;绕不开的spring&lt;/p&gt;
&lt;p&gt;对于Java企业应用，spring是无论如何绕不开的。然而目前我们没有看到spring社区对service mesh的任何回应。因此，如何以正确的姿势在service mesh时代使用spring，需要自己探索。&lt;/p&gt;
&lt;p&gt;理论上说，springboot on service mesh有可能成为一个清爽的解决方案。然后路终究是要走一遍才知道是不是那么美好。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;spring cloud迁移之路&lt;/p&gt;
&lt;p&gt;虽然service mesh号称下一代微服务，取代spring cloud是service mesh与生俱来的天然目标之一。&lt;/p&gt;
&lt;p&gt;但是以目前市场形式，spring cloud在未来很长一段时间之内都会是市场主流和很多公司的第一选择。如何在迁移到service mesh之前加强spring cloud，并为将来转入service mesh铺路，是一个艰难而极具价值的话题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;API gateway&lt;/p&gt;
&lt;p&gt;service mesh解决的是东西向服务间通讯的问题，我们来审视一下API gateway到微服务之间的南北向通讯： 服务发现，负载均衡，路由，灰度，安全，认证，加密，限流，熔断&amp;hellip;&amp;hellip;几乎大部分的主要功能，在这两个方向上都高度重叠。&lt;/p&gt;
&lt;p&gt;因此，是否该考虑提供一个统一的解决方案来处理？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;多集群/多机房的支持&lt;/p&gt;
&lt;p&gt;如果有多集群/多机房的支持需求，该如何解决？&lt;/p&gt;
&lt;p&gt;这个问题和前面列出的service mesh体系和非service mesh的并存问题，可能叠加：如何在多集群/多机房要求下实现service mesh体系和非service mesh的并存。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;TBD：更多想法将稍后逐步列出，也欢迎补充，请直接微信联系我。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;dream-mesh&#34;&gt;Dream Mesh&lt;/h2&gt;
&lt;p&gt;在经过一个月的冥思苦想和深度思考之后，我对上面列出的问题大致有了一些初步的想法和思路。&lt;/p&gt;
&lt;p&gt;我个人心中理想的Service Mesh解决方案，希望是可以在istio或者conduit的基础上，进一步的扩展和完善，解决或者规避上述问题。&lt;/p&gt;
&lt;p&gt;终极目标：让Service Mesh能够更加平稳的在普通企业落地。&lt;/p&gt;
&lt;p&gt;这个美好的愿景，目前还只停留在我的脑海中，如梦境一般虚幻，又如梦境一般令人向往。&lt;/p&gt;
&lt;p&gt;所以我将这个思路和解决方案，统称为&amp;quot;&lt;strong&gt;Dream Mesh&lt;/strong&gt;&amp;quot;。&lt;/p&gt;
&lt;p&gt;坦言说：Dream Mesh想法比较超前，规划也有点庞大，兼具高层架构和底层实现，极富挑战。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-dreammesh-brainstorm-preface/images/doubt-kills-dreams_huf493f29d8a5c872e31b18e53c88e1cd0_100668_8d6ada1031c4ef2c01957b72cbdb4009.webp 400w,
               /post/201802-dreammesh-brainstorm-preface/images/doubt-kills-dreams_huf493f29d8a5c872e31b18e53c88e1cd0_100668_f918379cb54941c33b7a192c6c1bfbd7.webp 760w,
               /post/201802-dreammesh-brainstorm-preface/images/doubt-kills-dreams_huf493f29d8a5c872e31b18e53c88e1cd0_100668_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-dreammesh-brainstorm-preface/images/doubt-kills-dreams_huf493f29d8a5c872e31b18e53c88e1cd0_100668_8d6ada1031c4ef2c01957b72cbdb4009.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;再一次用这张图片为自己打气，同时感谢太平洋对岸的埃隆·马斯克在本周这个关键的时间点上给了我更多的勇气。&lt;/p&gt;
&lt;h2 id=&#34;诚邀&#34;&gt;诚邀&lt;/h2&gt;
&lt;p&gt;在将Dream Mesh的规划和架构正式呈现出来之前，在春节期间，我会陆续将我目前的所思所想以文字的形式发表在我的博客上，然后年后会发起几轮内部讨论。之后修订/补充/完善，希望在四五月份的时候能给出一个成型的方案。&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;p&gt;十分期待。&lt;/p&gt;
&lt;h2 id=&#34;写作背景&#34;&gt;写作背景&lt;/h2&gt;
&lt;p&gt;补充交代一下写作背景，这个Dream Mesh系列的博客文章，很有可能会非常长，因为涉及到的内容实在有点多。不是三言两语可以交代的清楚，也不是一两次讨论就足够，另外为了避免空对空，我希望在讨论之前先给出部分资料和信息，这样让讨论可以建立在一个相对比较坚实的基础上，而且有足够的高度，以期望可以得到一个高质量的讨论成果。&lt;/p&gt;
&lt;p&gt;在开始这个系列文章之前，我曾经有多次和不同的朋友就其中的个别话题有过单独的交流，当时就曾经萌发想法说我可能需要先输出一部分内容，交代好背景，给出我的想法（哪怕并不是足够清晰）和思路（哪怕并不是足够合理）。&lt;/p&gt;
&lt;p&gt;后来非常凑巧的，华为的几位兄弟找到我，他们对此也有一些深度思考，在交流的过程中，我感觉真的非常有必要把这些内容好好深入和广泛的探讨一下，因此前面想的准备资料撰写内容就变得非常紧迫了。&lt;/p&gt;
&lt;p&gt;于是在当天，我开始了本文，也是本系列的第一篇文章。同时拉了一个新的微信群，为这次讨论做好准备。&lt;/p&gt;
&lt;h2 id=&#34;讨论和反馈&#34;&gt;讨论和反馈&lt;/h2&gt;
&lt;p&gt;以下讨论内容是在本文开始之前，和华为的孟樊亮兄弟的长篇讨论，直接促成了本系列文章的提前问世。特别鸣谢孟樊亮兄弟，以下为讨论内容：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;备注：基本上是原文，只是修改了个别拼写错误，补充标点符号等，可以说是原汁原味。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul&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;li&gt;
&lt;p&gt;林志南：侵入式指的是开发框架，如当前的java-chassis、springcloud等。非侵入式指的是service mesh。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：明白，你们不是两套同时提供了嘛:)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;孟樊亮：主要是当前侵入式框架怎么平滑过度到service mesh的理念。现在是两套都提供，而且还是个单选题。对于已有系统到service mesh的演化，其实还有个转化的坑。&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;li&gt;
&lt;p&gt;敖小剑：那我先把一些想法抛出来吧，有很多，实话说还没有想好，我本来想慢慢梳理的。抛砖引玉吧，看看有多少人对这个有想法，自然会加入进来。我这个周末组织一下，然后大家一起来讨论讨论。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;孟樊亮：我们主要还是纠结在控制面的数据上。个人的想法，无论现在的微服务还是servicemesh各种治理、路由等本质 协调中心还是在服务的控制数据。有的在etcd，有的在zk，有的自己实现。&lt;/p&gt;
&lt;p&gt;实际上的迁移的本质，大部分就落在了服务的控制信息里面。所以现在的点，就是这个控制面数据处理问题了。&lt;/p&gt;
&lt;p&gt;当然后续感觉还是有很多胶水性质的东西要做。&lt;/p&gt;
&lt;p&gt;你的切入点是什么层面？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：我前段时间在反复思考一个问题：一个服务化体系，它的核心是什么？什么是这个系统最核心的所在？&lt;/p&gt;
&lt;p&gt;答案是：&lt;strong&gt;信息和控制&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;p&gt;和服务相关的各种配置定义好服务间该如何交互，比如负载均衡用轮训还是随机。&lt;/p&gt;
&lt;p&gt;然后，我们现在有了信息，我们期望的行为该如何来发生？系统中必然需要有各种我们可控制的组件来实现我们的意图，比如SDK。&lt;/p&gt;
&lt;p&gt;我们给个java版本的sdk，按照要求开发好客户端服务器端，sdk会帮助客户完成服务注册发现，负载等全套操作。&lt;/p&gt;
&lt;p&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;敖小剑：service mesh，甚至nginx这种存在已久的传统反向代理，也可以理解为sdk的扩展和延伸。&lt;/p&gt;
&lt;p&gt;终极目标：根据系统内的信息完成我们期待的操作。&lt;/p&gt;
&lt;p&gt;是否侵入，是不是service mesh，在不在k8s中，都是这个思想的各种实际落地行为。&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;li&gt;
&lt;p&gt;敖小剑：最近因为某些不可抗力，做的太少，而想的太多，堆积了一堆内容在脑海里面。sorry，我知道这样有点装逼，但是请原谅，估计等我把东西写出来你们才会理解我。因为还没有想透彻，所以一直没落笔写下来。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;孟樊亮：其实我觉得还真不是装逼，至少我个人也是围绕着从信息的匹配出发，到反映到微服务各个维度的控制。&lt;/p&gt;
&lt;p&gt;毕竟现在的实际情况就是：各种微服务的信息格式存在差异，实际造成的结果就是&lt;strong&gt;平台绑定&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;li&gt;
&lt;p&gt;敖小剑：任意两个微服务体系，都是独立和隔离的，没法打通。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;孟樊亮：其实也是走到这一步的必然。&lt;/p&gt;
&lt;p&gt;嗯，走到当下这个时间窗，恰恰产生了打通的需求。或者说类似打通的需求。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：service mesh和普通服务化框架的打通？比如springcloud？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;孟樊亮：对，打通。当然首先是是否值得打通。&lt;/p&gt;
&lt;p&gt;是否值得打通，或者抛下是否打通这个问题，换种方法。&lt;/p&gt;
&lt;p&gt;客户现在springcloud或者其他微服务框架中，如果要切换到其他的框架，那么原来的服务怎么办？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;敖小剑：我思考过这个问题，取决于客户到底有没有真的cloud native。&lt;/p&gt;
&lt;p&gt;按照理想状态，根本没有打通的需求，所以服务都在同一个k8s和istio中。&lt;/p&gt;
&lt;p&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;敖小剑：别说用户什么时候切到cloud native，就算是真要切，那么多服务总不可能一夜之间都cloud native了&lt;/p&gt;
&lt;p&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;敖小剑：还有，即使cloud native加service mesh都实现了，还有多中心问题，难道都走api gateway？&lt;/p&gt;
&lt;p&gt;我甚至见过同一个服务集群内堆api gateway的做法 :)&lt;/p&gt;
&lt;p&gt;还别说，现在大家解决问题的方法都是无脑堆api gateway。&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;li&gt;
&lt;p&gt;孟樊亮：好啊，也是想多跟大家交流。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;以下内容是本文发表之后微信群内的讨论和微信上的留言，整理之后以供参考：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;汪照辉：有时间可以看下ca,axway,apigee等api管理产品，对这块会有帮助&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;孟樊亮：刚刚看了你的文章，真的也都是我们现在比较纠结的&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;魏清刚：看了你的博客，思考的不错。我们就该想services mesh如果产品ready, 对于企业用户来讲，如何考虑落地。&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;
</description>
    </item>
    
    <item>
      <title>十年一觉扬州梦，赢得青楼薄幸名</title>
      <link>https://skyao.net/post/201802-getting-started/</link>
      <pubDate>Tue, 06 Feb 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/post/201802-getting-started/</guid>
      <description>&lt;p&gt;自从两年前停止更新博客之后，一直以gitbook的方式写各种学习笔记。&lt;/p&gt;
&lt;p&gt;今天，重启博客网站。&lt;/p&gt;
&lt;p&gt;借此机会回顾一下过去十三年间的个人技术博客的历程。&lt;/p&gt;
&lt;h2 id=&#34;遥远的2005年&#34;&gt;遥远的2005年&lt;/h2&gt;
&lt;p&gt;直到今天翻自家的blog历史记录，才意外的发现：我的第一个技术博客，居然是在CSDN！&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://blog.csdn.net/aoxiaojian&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;http://blog.csdn.net/aoxiaojian&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;当时我才刚加入亚信，做第一个项目，给邮箱系统增加即时通讯功能。&lt;/p&gt;
&lt;p&gt;当时选择的是Jabber，然后没啥中文资料，我就只能用我那蹩脚的英文能力啃英文资料！&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-getting-started/images/csdn_hub0679eab085391c551fc7312b219bf8e_43380_08a545f5be0a2e4c17e9cd0e07062577.webp 400w,
               /post/201802-getting-started/images/csdn_hub0679eab085391c551fc7312b219bf8e_43380_0d939e00d4405d9985204936ea1943eb.webp 760w,
               /post/201802-getting-started/images/csdn_hub0679eab085391c551fc7312b219bf8e_43380_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-getting-started/images/csdn_hub0679eab085391c551fc7312b219bf8e_43380_08a545f5be0a2e4c17e9cd0e07062577.webp&#34;
               width=&#34;760&#34;
               height=&#34;587&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;十几年后回想，当时亚信的AIMC邮箱团队，阵容是何其的强大！这十几年职业生涯见过的最强大的团队莫过于此。&lt;/p&gt;
&lt;p&gt;然而当时我只是一个才毕业两三年的毛头小伙，还不知道身边的那些貌不惊人的年轻人日后会成为高山仰止的对象。&lt;/p&gt;
&lt;p&gt;人生如梦！&lt;/p&gt;
&lt;h2 id=&#34;从2006-07到2013-02blogjava&#34;&gt;从2006-07到2013-02：blogjava&lt;/h2&gt;
&lt;p&gt;好像当时csdn的访问速度有些问题，我就将blog搬到了当时流行的blogjava网站。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.blogjava.net/aoxj&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;http://www.blogjava.net/aoxj&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;陆陆续续写了这么多：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-getting-started/images/blogjava-3_hu44b0e1da8ad710f6c3986d4c8898f5fb_8520_c533e3e39607c02017cd5bfdfc09f89a.webp 400w,
               /post/201802-getting-started/images/blogjava-3_hu44b0e1da8ad710f6c3986d4c8898f5fb_8520_fa18fed8c8fd4d59cc8553c4c0b16d60.webp 760w,
               /post/201802-getting-started/images/blogjava-3_hu44b0e1da8ad710f6c3986d4c8898f5fb_8520_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-getting-started/images/blogjava-3_hu44b0e1da8ad710f6c3986d4c8898f5fb_8520_c533e3e39607c02017cd5bfdfc09f89a.webp&#34;
               width=&#34;391&#34;
               height=&#34;176&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;当时blogjava很是热闹，博客一发出去，就可以看到阅读数蹭蹭就上去了，很有成就感。&lt;/p&gt;
&lt;p&gt;然后就记得blogjava首页有一个阅读数排行版，我当时很努力的发文章，后来终于杀进100名进入首页，再慢慢一点点的往前爬。想想也真是闲的蛋疼。&lt;/p&gt;
&lt;p&gt;今天特意去首页看了一眼，都停止更新长达五年了，sky ao还在排在前50名：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-getting-started/images/blogjava_hu6eccc0055d9c52c09b357c5090bff686_24226_e81b2a399d1832a72ae94d23a0d300a5.webp 400w,
               /post/201802-getting-started/images/blogjava_hu6eccc0055d9c52c09b357c5090bff686_24226_ef629e227cb392a33809b5d49717d10b.webp 760w,
               /post/201802-getting-started/images/blogjava_hu6eccc0055d9c52c09b357c5090bff686_24226_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-getting-started/images/blogjava_hu6eccc0055d9c52c09b357c5090bff686_24226_e81b2a399d1832a72ae94d23a0d300a5.webp&#34;
               width=&#34;379&#34;
               height=&#34;338&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;顺便瞅了一眼，江南白衣还排在23名，最后一次更新在2011年。&lt;/p&gt;
&lt;p&gt;可见今天的blogjava有多败落。&lt;/p&gt;
&lt;p&gt;关于这个排行版，有个小插曲：当年就是在blogjava的排行榜中认识的白衣，所以后来某人在爱立信第一次亮相时做自我介绍的场景就成为经典：大家好，我叫肖桦（一片沉默：谁啊，不认识）&amp;hellip;&amp;hellip; 网名叫做江南白衣（掌声四起：啊，原来是你啊，久仰久仰）&lt;/p&gt;
&lt;p&gt;看看当时都在写些啥：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-getting-started/images/blogjava-2_hubc342e6f33de8b154a4bac00e4fdf460_41057_6f7c13e255f2c4534d8222b4968fcffc.webp 400w,
               /post/201802-getting-started/images/blogjava-2_hubc342e6f33de8b154a4bac00e4fdf460_41057_8cc22acddfb6e505372f91f0d71f0456.webp 760w,
               /post/201802-getting-started/images/blogjava-2_hubc342e6f33de8b154a4bac00e4fdf460_41057_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-getting-started/images/blogjava-2_hubc342e6f33de8b154a4bac00e4fdf460_41057_6f7c13e255f2c4534d8222b4968fcffc.webp&#34;
               width=&#34;384&#34;
               height=&#34;381&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里比较搞笑的是第一篇，2009年初学maven时写的总结，用来打包应用到zip包然后解压即可运行。2016年我在做dolphin框架时，忘了怎么打包了，一顿百度/google，最后找出来的比较靠谱的文章居然还是自己写的这篇。——可见没事总结一下还是有意义的，天知道若干年后会不会有需要。&lt;/p&gt;
&lt;p&gt;dbcp文档中文翻译那个，貌似从那个时候起我就喜欢翻译文档，不过早期翻译水平很烂，经常被人在评论里面说还不如看英文。无地自容的感觉，当然现在水平也没好到哪里去。但是，我经常安慰自己的是：贵在坚持。&lt;/p&gt;
&lt;p&gt;最后一个更是搞笑，文章写于2009年，当时就上了8g内存。现在2018年，整整九年过去了，我现在用来敲这个文档的笔记本也才16g内存，十年间几乎没啥变化。摩尔定律失效的典型下场。&lt;/p&gt;
&lt;h2 id=&#34;从2006-07到2013-02javaeye&#34;&gt;从2006-07到2013-02：javaeye&lt;/h2&gt;
&lt;p&gt;当时还叫javaeye，某人还叫肉饼，当时还盛行ror。&lt;/p&gt;
&lt;p&gt;Javaeye的博客推出之后，因为可以导入blogjava的博客，我就同时使用blogjava和javaeye的博客，互为备份。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://skydream.iteye.com/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;http://skydream.iteye.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;庆幸的是，十余年后这两个网站都还幸存，我的博客内容也都还健在。只是javaeye改名iteye，物是人非。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-getting-started/images/javaeye_hu3021a28ac2a335cd2af53176a9600c3e_23360_363e658566df63dba2b4cdec7b878f34.webp 400w,
               /post/201802-getting-started/images/javaeye_hu3021a28ac2a335cd2af53176a9600c3e_23360_f59e9bc44e0c1607aadbcd2298c09f8e.webp 760w,
               /post/201802-getting-started/images/javaeye_hu3021a28ac2a335cd2af53176a9600c3e_23360_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-getting-started/images/javaeye_hu3021a28ac2a335cd2af53176a9600c3e_23360_363e658566df63dba2b4cdec7b878f34.webp&#34;
               width=&#34;429&#34;
               height=&#34;528&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;当年一起泡javaeye的朋友们，一向可好？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-getting-started/images/javaeye-2_hu32071b261140709a38c12bbe3ffceaae_20630_07120f7fad35b33ae91b93e9271b3d85.webp 400w,
               /post/201802-getting-started/images/javaeye-2_hu32071b261140709a38c12bbe3ffceaae_20630_c207f48362f0e210f630a6217a4ce5cc.webp 760w,
               /post/201802-getting-started/images/javaeye-2_hu32071b261140709a38c12bbe3ffceaae_20630_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-getting-started/images/javaeye-2_hu32071b261140709a38c12bbe3ffceaae_20630_07120f7fad35b33ae91b93e9271b3d85.webp&#34;
               width=&#34;760&#34;
               height=&#34;207&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;2009/2010年间备受EJB/weblogic困扰的我，当时的想法就是一定要找个方法解决掉&lt;strong&gt;系统太大模块太多复杂度太高维护太难&lt;/strong&gt;的问题，于是深入研究了一把当时火热的OSGI技术。后来，放弃&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-getting-started/images/javaeye-3_hu4ff2b134ed255409b2cb64f115053664_33659_fbdd26ac5957afc2b2aee51b85ae5a51.webp 400w,
               /post/201802-getting-started/images/javaeye-3_hu4ff2b134ed255409b2cb64f115053664_33659_4000fe860732ea957caa1dc1ab3fe8ea.webp 760w,
               /post/201802-getting-started/images/javaeye-3_hu4ff2b134ed255409b2cb64f115053664_33659_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-getting-started/images/javaeye-3_hu4ff2b134ed255409b2cb64f115053664_33659_fbdd26ac5957afc2b2aee51b85ae5a51.webp&#34;
               width=&#34;760&#34;
               height=&#34;186&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;时隔五年，直到2014年底/2015年初，在深入了解微服务之后，终于找到满意的结果。&lt;/p&gt;
&lt;p&gt;额外补充一个：当年也是在blogjava的排行版上认识的BlueDavy，受他影响了解到osgi。不过据说BlueDavy后来自己也从osgi的坑中跳出来了，这是后话。&lt;/p&gt;
&lt;p&gt;所以说：技术选型有风险，防火防盗防跟风。&lt;/p&gt;
&lt;h2 id=&#34;从2014-04到2016-01github-page&#34;&gt;从2014-04到2016-01：github page&lt;/h2&gt;
&lt;p&gt;2014年的时候想法改变，博客更多的是想写给自己，作为自己思考和记录的一种工具，学习工具。&lt;/p&gt;
&lt;p&gt;有没有访客倒不再重要，也不再关注阅读数和评论。&lt;/p&gt;
&lt;p&gt;当时博客好像也有些寂寥，blogjava和已经更名的iteye也找不回最初的热闹感觉。&lt;/p&gt;
&lt;p&gt;于是，将博客搬到了github，利用hexo + github page搭建了基本上没啥人看的博客。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://skyao.github.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;http://skyao.github.io/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /post/201802-getting-started/images/github_hu261a87a795366fae0b43ec85eedcf4d5_26369_bf307c87d97b781fb0fc4a0d345bf9cc.webp 400w,
               /post/201802-getting-started/images/github_hu261a87a795366fae0b43ec85eedcf4d5_26369_c220d83558ef8644ed50c2d587e700e2.webp 760w,
               /post/201802-getting-started/images/github_hu261a87a795366fae0b43ec85eedcf4d5_26369_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/post/201802-getting-started/images/github_hu261a87a795366fae0b43ec85eedcf4d5_26369_bf307c87d97b781fb0fc4a0d345bf9cc.webp&#34;
               width=&#34;760&#34;
               height=&#34;192&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&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;h2 id=&#34;从2016-01到2018-01gitbook&#34;&gt;从2016-01到2018-01：gitbook&lt;/h2&gt;
&lt;p&gt;当博客内容越来越多之后，发现以博客的方式来组织学习类的资料是一件非常不方便的事情，尤其有很多琐碎内容分散在几十个知识体系时。&lt;/p&gt;
&lt;p&gt;后来偶尔接触到gitbook，发现以gitbook的方式来组织同一个知识体系是一件非常便利的事情，我称之为学习笔记。&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://www.gitbook.com/@skyao&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://www.gitbook.com/@skyao&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;陆陆续续建立了接近40个学习笔记，有些内容还算充实，有些只有聊聊几句，有些甚至空白来不及开始学习。&lt;/p&gt;
&lt;p&gt;好在只是写给自己，除了偶尔分享给同事朋友，也懒得推。&lt;/p&gt;
&lt;p&gt;意外的是，在github上各个笔记都很少有人star，反倒是gitbook上的star比较多，陆陆续续也攒了估计六七百个star，小小的安慰一下自己。&lt;/p&gt;
&lt;h2 id=&#34;从2018-01开始skyaoio&#34;&gt;从2018-01开始：skyao.io&lt;/h2&gt;
&lt;p&gt;gitbook虽好，奈何速度总是不够快，2017年年中之后更是经常被墙导致无法访问。&lt;/p&gt;
&lt;p&gt;最大的麻烦在于doczh.cn上的文档翻译，当时和service mesh社区的一帮人一起辛辛苦苦翻译的istio/conduit文档，放在gitbook上经常被告之无法访问，怒。&lt;/p&gt;
&lt;p&gt;忍无可忍，于是在2017年年底的时候，掏钱在腾讯云买了一个最便宜的主机，然后把这堆翻译资料扔腾讯云上，访问速度飞快。&lt;/p&gt;
&lt;p&gt;2018年，被&lt;a href=&#34;https://jimmysong.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;宋净超&lt;/a&gt;同学&amp;quot;勾搭&amp;quot;，发现hugo是个好东西：编译内容到静态文件的速度超快，十倍于gitbook。当时正在苦于gitbook本地生成速度的我发现这似乎是一个不错的选择。&lt;/p&gt;
&lt;p&gt;适逢其会，2017年年底因为推service mesh，发了一些文章和分享，演讲实录。都是发在公司或者infoq等的微信公众号里面，非常散乱，而且夹杂着大量广告也不便阅读。期间偶尔还被朋友们索要资料，ppt/视频等，想想干脆自己整理起来好了，要给的时候也方便，避免到处找。&lt;/p&gt;
&lt;p&gt;简单研究了一下，发现hugo貌似做这个事情不错。于是在hugo的一堆theme中找到了今天正在使用的这个&lt;a href=&#34;https://sourcethemes.com/academic/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Academic theme&lt;/a&gt;，感觉挺适合作为个人网站兼博客。&lt;/p&gt;
&lt;p&gt;顺便赶个时髦，申请了io域名，在高人指点下顺便搞定了https，于是有了下面这个个人网站：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://skyao.io/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;https://skyao.io/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;前段时间，将之前两年的几个觉得不错的分享整理出来放在网站上，也算是给自己留一个备份吧。&lt;/p&gt;
&lt;p&gt;此外，有些内容不适合以学习笔记的方式存放在gitbook中的内容，以后会慢慢以博客的形式发在这里，比如说本文。&lt;/p&gt;
&lt;p&gt;废话说了一大筐，其实就一个意思：&lt;strong&gt;以后继续写个人技术博客&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;2025年6月4日-更换域名为-skyaonet&#34;&gt;2025年6月4日 更换域名为 skyao.net&lt;/h2&gt;
&lt;p&gt;将网站从香港搬回国内, 为了备案, 放弃 skyao.io 域名(备注:io域名无法备案), 启用 skyao.net 作为个人技术分享网站的域名, 将网站名从&amp;quot;敖小剑的博客&amp;quot;修改为&amp;quot;敖小剑的技术分享&amp;quot;(备注:博客是敏感词不能使用否则无法备案).&lt;/p&gt;
&lt;p&gt;博客已经不怎么更新了, 写作的内容基本都在各种学习笔记里面,大大小小攒了一百多个,内容五花八门, 我也不做宣传, 访客一般都是来自搜索引擎.&lt;/p&gt;
&lt;h2 id=&#34;结束语&#34;&gt;结束语&lt;/h2&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;p&gt;&lt;strong&gt;少说，多做&lt;/strong&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Service Mesh年度总结：群雄逐鹿烽烟起</title>
      <link>https://skyao.net/publication/201801-service-mesh-2017-summary/</link>
      <pubDate>Sat, 06 Jan 2018 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/publication/201801-service-mesh-2017-summary/</guid>
      <description>&lt;p&gt;在过去的2016年和2017年，微服务技术得以迅猛普及，和容器技术一起成为这两年中最吸引眼球的技术热点。而以Spring Cloud为代表的传统侵入式开发框架，占据着微服务市场的主流地位，它甚至一度成为微服务的代名词。&lt;/p&gt;
&lt;p&gt;直到2017年底，当非侵入式的Service Mesh技术终于从萌芽到走向了成熟，当Istio/Conduit横空出世，人们才惊觉：微服务并非只有侵入式一种玩法，更不是Spring Cloud的独角戏！&lt;/p&gt;
&lt;p&gt;这一次的新生力量，完全不按照常理出牌，出场就霸道地掀翻桌子，直接摆出新的玩法：Service Mesh，下一代微服务！这一场大战，在 2017 年的最后一个月，终于上演到白热化，被摆上了台面，受到越来越多人关注。往日霸主 Spring Cloud，此时只能沦为看客。&lt;/p&gt;
&lt;p&gt;2017年的Service Mesh历程，在平淡中开始，如戏剧般结束，留给我们一个充满想象和憧憬的2018。让我们一起来回顾这堪称精彩的一年。&lt;/p&gt;
&lt;h2 id=&#34;service-mesh的萌芽期&#34;&gt;Service Mesh的萌芽期&lt;/h2&gt;
&lt;p&gt;在我们正式开始2017年回顾之前，我们将时间稍微放前一点，回到2016年：有些故事背景需要预交交代一下。&lt;/p&gt;
&lt;p&gt;虽然直到2017年底，Service Mesh才开始较大规模被世人了解，这场微服务市场之争也才显现，但是其实Service Mesh这股微服务的新势力，早在 2016年初就开始萌芽：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2016年1月15日，离开twitter的基础设施工程师William Morgan和Oliver Gould，在github上发布了linkerd 0.0.7版本，他们同时组建了一个创业小公司Buoyant，业界第一个Service Mesh项目诞生。&lt;/li&gt;
&lt;li&gt;2016年，Matt Klein在Lyft默默的进行Envoy的开发。Envoy诞生的时间其实要比Linkerd更早一些，只是在Lyft内部不为人所知。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在2016年初，service mesh还只是Buoyant公司的内部词汇，而之后，它开始逐步走向社区：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2016年9月29日在SF Microservices上，“Service Mesh”这个词汇第一次在公开场合被使用。这标志着“Service Mesh”这个词，从Buoyant公司走向社区。&lt;/li&gt;
&lt;li&gt;2016年10月，Alex Leong开始在buoyant公司的官方Blog中开始&amp;quot;A Service Mesh for Kubernetes&amp;quot;系列博客的连载。随着&amp;quot;The services must mesh&amp;quot;口号的喊出，buoyant和Linkerd开始service mesh概念的布道。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在这一年中，第一代的Service Mesh产品在稳步推进：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2016年9月13日，Matt Klein宣布Envoy在github开源，直接发布1.0.0版本&lt;/li&gt;
&lt;li&gt;2016年下半年，Linkerd陆续发布了0.8和0.9版本，开始支持HTTP/2 和gRPC，1.0发布在即；同时，借助Service Mesh在社区的认可度，Linkerd在年底开始申请加入CNCF。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;而在这个世界的另外一个角落，Google和IBM两位巨人，握手开始合作，他们联合Lyft，启动了Istio项目。这样，在第一代Service Mesh还未走向市场主流时，以Istio为代表的第二代Service Mesh就迫不及待地上路。&lt;/p&gt;
&lt;p&gt;现在我们可以进入主题，开始2017年Service Mesh发展历程的回顾。&lt;/p&gt;
&lt;h2 id=&#34;急转而下的linkerd&#34;&gt;急转而下的Linkerd&lt;/h2&gt;
&lt;p&gt;2017年，Linkerd迎来了一个梦幻般的开局，喜讯连连：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2017年1月23日，Linkerd加入CNCF&lt;/li&gt;
&lt;li&gt;2017年3月7日，Linkerd宣布完成千亿次产品请求&lt;/li&gt;
&lt;li&gt;2017年4月25日，Linkerd 1.0版本发布&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可谓各条战线都进展顺利：产品完成1.0 release，达成最重要的里程碑；被客户接受并在生产线上成功大规模应用，这代表着市场的认可；进入CNCF更是意义重大，是对Linkerd的极大认可，也使得Linkerd声名大噪。一时风光无量，可谓&amp;quot;春风得意马蹄疾，一日看尽长安花&amp;quot;。&lt;/p&gt;
&lt;p&gt;需要特别指出的是，Linkerd加入CNCF，对于Service Mesh技术是一个非常重要的历史事件：这代表着社区对Service Mesh理念的认同和赞赏，Service Mesh也因此得到社区更大范围的关注。&lt;/p&gt;
&lt;p&gt;趁热打铁，就在Linkerd 1.0版本发布的同一天，创作者继续Service Mesh的布道：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2017年4月25日，William Morgan发布博文&amp;quot;What’s a service mesh? And why do I need one?&amp;quot;。正式给Service Mesh做了一个权威定义。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然而现实总是那么残酷，这个美好的开局，未能延续多久就被击碎：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2017年5月24日，Istio 0.1 release版本发布，google和IBM高调宣讲，社区反响热烈，很多公司在这时就纷纷站队表示支持Istio。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Linkerd的风光瞬间被盖过，从意气风发的少年一夜之间变成过气网红。当然，从产品成熟度上来说，linkerd作为业界仅有的两个生产级Service Mesh实现之一，暂时还可以在Istio成熟前继续保持市场。但是，随着Istio的稳步推进和日益成熟，外加第二代Service Mesh的天然优势，Istio取代第一代的Linkerd只是个时间问题。&lt;/p&gt;
&lt;p&gt;面对google和IBM加持的Istio，linkerd实在难有胜算：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Istio作为第二代Service Mesh，通过控制平面带来了前所未有的控制力，远超linkerd。&lt;/li&gt;
&lt;li&gt;Istio通过收编和linkerd同为第一代Service Mesh的envoy，直接拥有了一个功能和稳定性与linkerd在一个水准的数据平面（也就是作为 sidecar 模式部署的 proxy）。&lt;/li&gt;
&lt;li&gt;基于c++的envoy在性能和资源消耗上本来就强过基于Scala/Jvm的Linkerd&lt;/li&gt;
&lt;li&gt;Google和IBM组合在人力，资源和社区影响力方面远非Buoyant公司这样的小公司可以比拟&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Linkerd的发展态势顿时急转而下，未来陷入一片黑暗。出路在哪里？&lt;/p&gt;
&lt;p&gt;在一个多月后，Linkerd给出一个答案：和Istio集成，成为Istio的数据面板。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2017年7月11日，Linkerd发布版本1.1.1，宣布和Istio项目集成。Buoyant发表博文&amp;quot;Linkerd and Istio: like peanut butter and jelly&amp;quot;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这个方案在意料之中，毕竟面对Google和IBM的联手威胁，选择低头和妥协是可以理解的。只是存在两个疑问：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;和Envoy相比，Linkerd并没有特别优势。考虑编程语言的天生劣势，Linkerd想替代Envoy难度非常之大。&lt;/li&gt;
&lt;li&gt;即使替代成功，在Istio的架构下，只是作为一个数据平面存在的Linkerd，可以发挥的空间有限。这种境地的Linkerd，是远远无法承载起Buoyant的未来的。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Linkerd的这个谜团，直到2017年即将结束的12月，在Conduit发布之后才被解开。&lt;/p&gt;
&lt;h2 id=&#34;波澜不惊的envoy&#34;&gt;波澜不惊的Envoy&lt;/h2&gt;
&lt;p&gt;自从在2016年决定委身于Istio之后，envoy就开始了一条波澜不惊的平稳发展之路，和Linkerd的跌宕起伏完全不同。&lt;/p&gt;
&lt;p&gt;在功能方面，由于定位在数据平面，因此Envoy无需考虑太多，很多工作在Istio的控制平面完成就好，Envoy从此专心于将数据平面做好，完善各种细节。在市场方面，Envoy和Linkerd性质不同，不存在生存和发展的战略选择，也没有正面对抗生死大敌的巨大压力。Envoy在2017年有条不紊地陆续发布了1.2、1.3、1.4和1.5版本，稳步地完善自身，表现非常稳健。&lt;/p&gt;
&lt;p&gt;稳打稳扎的Envoy在2017年一方面继续收获独立客户，一方面伴随Istio一起成长。作为业界仅有的两个生产级Service Mesh实现之一，Envoy随后收获了属于它的殊荣：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2017年9月14日，Envoy加入CNCF，成为CNCF的第二个Service Mesh项目&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;可谓名至实归，水到渠成。作为一个无需承载一家公司未来的开源项目，Envoy在2017年的表现，无可挑剔。&lt;/p&gt;
&lt;h2 id=&#34;背负使命的istio&#34;&gt;背负使命的Istio&lt;/h2&gt;
&lt;p&gt;从Google和IBM联手决定推出Istio开始，Istio就注定永远处于风头浪尖，无论成败。&lt;/p&gt;
&lt;p&gt;Istio背负了太多的使命：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;建立Google和IBM在微服务市场的统治地位&lt;/li&gt;
&lt;li&gt;为Google和IBM的公有云打造杀手锏级特性&lt;/li&gt;
&lt;li&gt;在k8s的基础上，延续Google的战略布局&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Google在企业市场的战略布局，是从底层开始，一步一步向上，一步一步靠近应用。刚刚大获全胜的K8s为Istio准备了一个非常好的基石，而Istio的历史使命，就是继k8s拿下容器之后，更进一步，&lt;strong&gt;拿下微服务&lt;/strong&gt;！&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /publication/201801-service-mesh-2017-summary/images/strategy_hu76e5c1194a2ef5098184a76e4fdbbd15_34367_1e9a82710659d2d0658ca500d4a8e071.webp 400w,
               /publication/201801-service-mesh-2017-summary/images/strategy_hu76e5c1194a2ef5098184a76e4fdbbd15_34367_284460aabd1104db9a5ae1f6d3f6e0b1.webp 760w,
               /publication/201801-service-mesh-2017-summary/images/strategy_hu76e5c1194a2ef5098184a76e4fdbbd15_34367_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/publication/201801-service-mesh-2017-summary/images/strategy_hu76e5c1194a2ef5098184a76e4fdbbd15_34367_1e9a82710659d2d0658ca500d4a8e071.webp&#34;
               width=&#34;629&#34;
               height=&#34;650&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;2017年，Istio稳步向前，先后发布四个版本：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2017年5月24日，Istio 0.1 release版本发布&lt;/li&gt;
&lt;li&gt;2017年10月4日，Istio 0.2 release版本发布&lt;/li&gt;
&lt;li&gt;2017年11月30日，Istio 0.3 release版本发布&lt;/li&gt;
&lt;li&gt;2017年12月15日，Istio 0.4 release版本发布&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在社区方面，Istio借助Google和IBM的大旗，外加自身过硬的实力、先进的理念，很快获得了社区的积极响应和广泛支持。包括Oracle和Red Hat在内的业界大佬都明确表示对支持Istio。&lt;/p&gt;
&lt;p&gt;在平台支持方面，Istio的初期版本只支持k8s平台，从0.3版本开始提供对非k8s平台的支持。从策略上说，Istio借助了k8s，但是没有强行绑定在k8s上。&lt;/p&gt;
&lt;p&gt;Istio面世之后，赞誉不断，尤其是Service Mesh技术的爱好者，可以说是为之一振：以新一代Service Mesh之名横空出世的Istio，对比Linkerd，优势明显。同时产品路线图上有一大堆令人眼花缭乱的功能。假以时日，如果Istio能顺利地完成开发，稳定可靠，那么这会是一个非常美好、值得憧憬的大事件，它的意义重大：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;重新定义微服务开发方式，让Service Mesh成为主流技术&lt;/li&gt;
&lt;li&gt;大幅降低微服务开发的入门门槛，让更多的企业和开发人员可以落地微服务&lt;/li&gt;
&lt;li&gt;统一微服务的开发流程，标准化开发/运维方式&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;奈何，事情的发展总是不会这么简单地如人所愿。Istio发布之后，试用中就被发现问题较多，0.1版本时还比较容易被接受，但是接下来的0.2、0.3和0.4，Istio在可用性上并没有明显的改观，导致迄今在全球范围内都几乎没有听到Istio上生产的案例，各家公司都将其停留在简单试用阶段。&lt;/p&gt;
&lt;p&gt;此时再看Istio琳琅满目的各种功能，不禁让人疑惑Istio的产品策略：为什么一开场就将摊子铺的如此之大？以至于开发时间长达一年 (注意，虽然开源才半年多，但是开源前已经在开发)，却无法得到一个稳定可用的版本。&lt;/p&gt;
&lt;p&gt;这有悖于互联网产品的开发理念。下边这个经典图片相信大家并不陌生：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /publication/201801-service-mesh-2017-summary/images/production_hu3c9f27909ddbe486f88a28b5053fa11a_66403_fdbb3a3ffddff1b1a8b6052399be66e1.webp 400w,
               /publication/201801-service-mesh-2017-summary/images/production_hu3c9f27909ddbe486f88a28b5053fa11a_66403_a63d16f7a23766ba333def4a5d12e59c.webp 760w,
               /publication/201801-service-mesh-2017-summary/images/production_hu3c9f27909ddbe486f88a28b5053fa11a_66403_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/publication/201801-service-mesh-2017-summary/images/production_hu3c9f27909ddbe486f88a28b5053fa11a_66403_fdbb3a3ffddff1b1a8b6052399be66e1.webp&#34;
               width=&#34;760&#34;
               height=&#34;415&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;从目前情景看，Istio已经在图上“不应该”的产品迭代路径上走了一年。从5月份0.1版本发布开始，我们就满心期待，却陷入“过尽千帆皆不是”的尴尬境地：每一次新版本试用后的结果，都不理想。&lt;/p&gt;
&lt;p&gt;身处局外，无法了解Istio项目开发的背景和真实情况，也自然无法得知为何会如此，我们只能由衷地希望，Istio能在2018年尽快完成计划中的产品开发，实现生产可用。个人意见：哪怕推迟某些特性的实现，也希望能做到主体部分尽快完善。&lt;/p&gt;
&lt;p&gt;2018年Service Mesh的整体走势，很大程度取决于Istio：如果Istio能在2018年上半年实现生产可用，哪怕是牺牲部分高级特性，也足以推动整个Service Mesh向前大步迈进。反之如果进展不顺，市场会呈现观望和等待的态势，也会给竞争对手机会，比如说，下面将要出场的Conduit。&lt;/p&gt;
&lt;h2 id=&#34;背水一战的conduit&#34;&gt;背水一战的Conduit&lt;/h2&gt;
&lt;p&gt;2017年底的KubeConf，在Service Mesh成为大会热点、Istio备受瞩目时，Buoyant公司出人意料地给了踌躇满志又稍显拖沓的Istio重重一击：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2017年12月5日，Conduit 0.1.0版本发布，Istio的强力竞争对手亮相KubeConf。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Conduit的整体架构和Istio一致，借鉴了Istio数据平面+控制平面的设计，同时别出心裁地选择了Rust编程语言来实现数据平面，以达成Conduit 宣称的更轻、更快和超低资源占用。&lt;/p&gt;
&lt;p&gt;继Isito之后，业界第二款第二代Service Mesh产品就此诞生。话说得有些拗口，但是一场大战就此浮出水面。Buoyant在Linkerd不敌Istio的恶劣情况下，绝地反击，祭出全新设计的Conduit作为对抗Istio的武器。&lt;/p&gt;
&lt;p&gt;需要额外指出的是，作为一家初创型企业，在第一款主力产品Linkerd被Istio强力阻击之后，Buoyant已经身陷绝境，到了生死存亡之秋，作为背负公司期望，担负和Istio正面抗衡职责的Conduit，可谓压力巨大。&lt;/p&gt;
&lt;p&gt;从目前得到的信息分析，Conduit明显是有备而来，针对Istio当前状况，针锋相对的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;编程语言&lt;/strong&gt;：为了达成更轻、更快和更低资源消耗的目标，考虑到Istio的数据面板用的是基于C++语言的Envoy，Conduit跳过了Golang，直接选择了Rust，颇有些剑走偏锋的意味。不过，单纯以编程语言而言，在能够完全掌握的前提下，Rust的确是做proxy的最佳选择。考虑到Envoy在性能方面的良好表现，Conduit要想更进一步，选择Rust也是可以理解。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;架构设计&lt;/strong&gt;：在借鉴Istio整体架构的同时，Conduit做了一些改进。首先Conduit控制平面的各个组件是以服务的方式提供功能的，极富弹性。另外，控制平面特意为定制化需求进行了可扩展设计，可以通过编写gPRC插件来扩展Conduit的功能而无需直接修改Conduit，这对于有定制化需求的客户是非常便利的。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;产品演进&lt;/strong&gt;：这是最重要的一点！Conduit完全吸取了Istio的教训，因此它的产品迭代路径会是我们最期待的方式。在本文撰写期间，笔者特意和 Conduit的CEO William深入探讨过这个话题，得到了一个非常令人欣慰的答复：++Minimal feature set，prod ready as quickly as possible++。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然而，要抗衡Istio和其身后的Google与IBM，谈何容易。Conduit2018年的发展道路，注定是充满挑战的，艰难险阻可想而知。但是，不得不佩服Buoyant公司，以及以CEO William为首的那支充满挑战精神的团队，有理想、有追求、有魄力、有勇气！期待他们在2018年的表现。&lt;/p&gt;
&lt;p&gt;让我们回到Istio和Conduit的竞争格局。从目前局面看，Istio先天优势明显，但是产品策略上的选择给了Conduit一个难得的机会。接下来的2018年，在Conduit的威胁和刺激下，希望Istio能打起精神，给出一份令大家满意的答卷。期待Istio和Conduit能在2018年形成良性竞争，共同引领Service Mesh的大潮。&lt;/p&gt;
&lt;p&gt;就在本文撰写之时，在2017年的最后几天，大名鼎鼎的F5 Networks公司突然放出了他们的Service Mesh类产品“Aspen Mesh”，基于Istio构建，目标“企业服务网格”。需要特别强调的是，F5在Service Mesh上的坚定决心：砍掉原有传统产品思路的项目，以内部孵化项目的方式组建独立自治团队，并在新方向上重新开始。而且在Istio才0.1版本的时候F5就做好战略决策，之后默默耕耘，其决策者的胆识令人敬佩。F5在Service Mesh这个新兴技术领域表现出积极进取的姿态，立足Istio完善企业级特性，这也是一条值得探索的路线，期待2018年Aspen Mesh的进展。&lt;/p&gt;
&lt;h2 id=&#34;低调的参与者&#34;&gt;低调的参与者&lt;/h2&gt;
&lt;p&gt;2017年的Service Mesh，除了业界先驱Linkerd/Envoy，和后起之秀Istio/Conduit，还有一些其它的竞争者进入这个市场，只是它们都非常低调。&lt;/p&gt;
&lt;p&gt;首先是nginmesh，来自大名鼎鼎的Nginx：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2017年9月，在美国波特兰举行的nginx.conf大会上，nginx宣布了nginmesh。随即在github上发布了0.1.6版本。&lt;/li&gt;
&lt;li&gt;2017年12月6日，nginmesh 0.2.12版本发布&lt;/li&gt;
&lt;li&gt;2017年12月25日，nginmesh 0.3.0版本发布&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;nginmesh的定位是作为Istio的服务代理，也就是替代Envoy，思路和Linkerd之前和Istio集成很相似。Nginmesh在发布后的两个多月，github上提交非常少，直到最近突然发力，先后发布了0.2和0.3版本。不过Nginmesh极度低调，github上的star也只有不到100。&lt;/p&gt;
&lt;p&gt;然后是Kong，但是这个比默默无闻的nginmesh还要更加低调，只是曾经有传闻kong有意service mesh，但是后来又没有下文。不过kong的github项目介绍里面，悄悄的加上了Service Mesh的字样：&amp;ldquo;Kong is a ××× Microservice Abstraction Layer (also known as an API Gateway, API Middleware or in some cases Service Mesh).&amp;rdquo;&lt;/p&gt;
&lt;p&gt;在2017年，这些低调的参与者，几乎没有引起外界任何的注意，也无法预期他们在2018年会如何表现。从社区的角度，还是希望有更多的参与者进Service Mesh市场，以推动整个市场的健康发展。&lt;/p&gt;
&lt;h2 id=&#34;快速升温的国内&#34;&gt;快速升温的国内&lt;/h2&gt;
&lt;p&gt;2017年，随着Servic Mesh的发展，国内技术社区也开始通过新闻报道/技术文章等开始接触Service Mesh，但是传播范围和影响力都非常有限。直到年底才剧烈升温，开始被国内技术社区关注：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2017年10月16日，在2017 QCon上海大会上，我做了一个&amp;quot;Service Mesh：下一代微服务&amp;quot;的演讲，成为Service Mesh技术在国内大型技术峰会上的第一次亮相。&lt;/li&gt;
&lt;li&gt;2017年11月，国内第一个Service Mesh的技术社区&lt;a href=&#34;http://servicemesh.cn&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;&amp;ldquo;Service Mesh中文网&amp;rdquo;&lt;/a&gt; 成立。&lt;/li&gt;
&lt;li&gt;2017年12月，在全球架构师峰会（ArchSummit）2017北京站上，来自华为的田晓亮做了名为&amp;quot;Service Mesh在华为云的实践&amp;quot;的分享。&lt;/li&gt;
&lt;li&gt;2017年12月16日，来自新浪微博的周晶做了名为&amp;quot;微博Service Mesh实践&amp;quot;的演讲，分享了Service Mesh在微博的落地情况。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外，作为Servic Mesh国内最早的开发和实践者的华为和新浪微博，都积极参与开源。其中新浪微博Service Mesh的核心实现，跨语言通信和服务治理已经在Motan系列项目中提供，而华为也将稍后开源他们基于Golang的Service Mesh代码实现。&lt;/p&gt;
&lt;p&gt;特别要指出的是，华为目前已经在公有云上将Service Mesh作为公共服务提供，这在国内公有云中是第一家。预计随着Service Mesh的落地和普及，公有云提供生产级别的Service Mesh服务将成为标配。在国外Google/IBM/Amazon等公有云都有提供Service Mesh的计划，相信国内公有云也会陆续跟进。&lt;/p&gt;
&lt;h2 id=&#34;展望2018&#34;&gt;展望2018&lt;/h2&gt;
&lt;p&gt;2017年的Service Mesh市场，从Linkerd的风光无限开始，到Istio的横空出世，最后止于Conduit的绝地反击，可谓一波三折；产品也经历从第一代的Linkerd/Envoy，跨越性的演化出第二代的Istio/Conduit；同时，技术社区的态度也从年初的逐步接受发展到年底的热烈追捧，下面这张KubeConf上的图片非常有代表性地展示了社区的热切期望：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /publication/201801-service-mesh-2017-summary/images/the-year-of-the-service-mesh_hu082d711caa345b74ce88ee62b55512fe_45434_32eda9d2d7f2c6c3e6974b2e32a3f3fb.webp 400w,
               /publication/201801-service-mesh-2017-summary/images/the-year-of-the-service-mesh_hu082d711caa345b74ce88ee62b55512fe_45434_85e0d02229b4461cc4f44256f3e51ee0.webp 760w,
               /publication/201801-service-mesh-2017-summary/images/the-year-of-the-service-mesh_hu082d711caa345b74ce88ee62b55512fe_45434_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/publication/201801-service-mesh-2017-summary/images/the-year-of-the-service-mesh_hu082d711caa345b74ce88ee62b55512fe_45434_32eda9d2d7f2c6c3e6974b2e32a3f3fb.webp&#34;
               width=&#34;760&#34;
               height=&#34;570&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;然而Service Mesh终究是一个新兴的技术，尤其作为未来主流的Istio/Conduit迄今还没有实现产品级别可用，因此2018年对Service Mesh而言，必然不是一帆风顺，必然是充满荆棘和坎坷的。如何实现从技术理念到产品落地，如何实实在在地解决实践中遇到的各种问题，将会是这一年中至关重要的事情。&lt;/p&gt;
&lt;p&gt;衷心祝愿Istio和Conduit（也许还有其他的产品）可以在2018年快速成长，实现社区期待的功能和可用性，可以真正地实现降低微服务门槛的目标，让Service Mesh成为名副其实的下一代微服务。&lt;/p&gt;
&lt;p&gt;2018年的Service Mesh，值得期望！&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>山雨欲来风满楼：Service Mesh时代的选边与站队</title>
      <link>https://skyao.net/talk/201712-make-a-choise-for-service-mesh/</link>
      <pubDate>Sat, 16 Dec 2017 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/201712-make-a-choise-for-service-mesh/</guid>
      <description>&lt;h1 id=&#34;山雨欲来风满楼&#34;&gt;山雨欲来风满楼&lt;/h1&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt1_hu87b6d64fedccf770e03c5af6fc948095_74407_686737677777ffb7be18dc44ccd50e05.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt1_hu87b6d64fedccf770e03c5af6fc948095_74407_385969e42dfae0a2c694701b121ed362.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt1_hu87b6d64fedccf770e03c5af6fc948095_74407_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt1_hu87b6d64fedccf770e03c5af6fc948095_74407_686737677777ffb7be18dc44ccd50e05.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;大家好，我是敖小剑，来自数人云。今天给大家带来的专题，相对来说会比较轻松一点。大家前面听到的两位的演讲都是非常有真材实料的，以及在我的下一场，周晶同学会带来一个非常有干货的Service Mesh实战的专题。我的内容会比较轻松一点，也比较好玩，主要是今天的主题比较特殊一点，因为我们选择的是“选边与站队”。OK，我们开始今天的主题。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt2_hu8c01221b1072ae8844c2a194079ef2cb_74980_756f133e4707e0333e5eb224ef5cc373.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt2_hu8c01221b1072ae8844c2a194079ef2cb_74980_0c4ec8dcc08e7c58e2bd88981b753509.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt2_hu8c01221b1072ae8844c2a194079ef2cb_74980_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt2_hu8c01221b1072ae8844c2a194079ef2cb_74980_756f133e4707e0333e5eb224ef5cc373.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在2017年，Servicemesh技术在快速成长。我们看到在年中的时候，Istio非常霸气的登场。如果大家有关注Service Mesh这个技术，就会知道大概10天前，Conduit这个产品突然发布了。实际上在这过去的一年当中，Servicemesh历经了非常多的事情。在经过2017年的酝酿过程后，Service Mesh技术接近一个爆发的状态。而2018年很有可能就是Service Mesh全面爆发的一年，它的目标其实就是一个：&lt;strong&gt;重新塑造整个微服务市场&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;在今年十月份的时候，我在QCon做了一个演讲，叫“Servicemesh——下一代微服务”。这个口号十月份喊出来的时候，还是有蛮多反对的声音。有个挺有意思的事情，我一直当成玩笑来说。当时QCon在转我的演讲实录文章的时候，在我的标题后面，在”Servicemesh:下一代微服务”后面打了一个问号，那个问号是Infoq的编辑加的。我的理解是，小编觉得如果这个标题由他们发出来，可能有Infoq的印号。所以为了避嫌，在后面打了一个问号。&lt;/p&gt;
&lt;p&gt;大概是在一个星期前，KubeConf刚刚召开，Servicemesh非常的火，而这个时候Infoq做了一个事情，把之前QCon的视频处理好了发出来。视频的标题是”Servicemesh:下一代微服务”，后面再也没有问号了。这是很小的插曲，非常深刻的表明过去的几个月当中，ServiceMesh技术快速的变化，以及大家对它认知的变化。&lt;/p&gt;
&lt;p&gt;我们开始今天的主题，站队和选边。上面有一句话叫”新一轮的江湖厮杀又一次开始了”，有个小问题，为什么要说又字？大家觉得上一轮江湖厮杀是什么内容？我们来问一个问题，在大家的认知当中，IT领域的上一轮厮杀是谁对谁。&lt;/p&gt;
&lt;p&gt;（备注： 现场互动，有同学指出，容器，k8s，mesos，swarm）&lt;/p&gt;
&lt;p&gt;这场厮杀的结果如何？K8S笑到了最后。那现在开始，我们来看看新一轮的厮杀是什么样的结果。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt3_hu8c01221b1072ae8844c2a194079ef2cb_32659_c069271423b7aa7274b688e67465df72.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt3_hu8c01221b1072ae8844c2a194079ef2cb_32659_2b1246be09e23bbfbaa2e716ac8c639d.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt3_hu8c01221b1072ae8844c2a194079ef2cb_32659_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt3_hu8c01221b1072ae8844c2a194079ef2cb_32659_c069271423b7aa7274b688e67465df72.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;让我们从 Buoyant 这家小公司开始。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt4_hu0a33fe36f8fbd40cd939887327f27f4d_118953_be9936b91a83e95b054078bfe22ef6a6.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt4_hu0a33fe36f8fbd40cd939887327f27f4d_118953_8386f31f0a9d086f6f0c8cfa07fb92a1.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt4_hu0a33fe36f8fbd40cd939887327f27f4d_118953_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt4_hu0a33fe36f8fbd40cd939887327f27f4d_118953_be9936b91a83e95b054078bfe22ef6a6.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Buoyant是一家名不见经传的小公司，但这家公司是Servicemesh的先驱，是Linkerd的公司，而Linkerd是业界第一个Servicemesh。这家是初创型的小公司，今年七月份刚拿到A轮的一千万美元融资，开发团队不到20人，我在他网站主页数了一下也就17、18个左右的样子。&lt;/p&gt;
&lt;p&gt;创始人是两个前Twitter的基础设施工程师，CEO是William Morgan。因为融资的关系，A轮融了1000万美元，最近也在招兵买马，招了一些高手进来。这里我们单独列了一位大牛，如果大家有印象的话，他曾写了一篇文章叫《模式：Servicemesh》，那篇文章基本上是目前介绍Servicemesh最好的最经典的文章之一。大家可以看到，中间这位同学，William，这个人是它的CEO，Servicemesh全球第一个布道师： 他定义了Service Mesh，开始在全球讲Service Mesh。右图这张图是在2016年九月份第一次使用这个词汇。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt5_hu762cddcaece0772ed3cad7f11147374f_101691_a67b76095ed40c19c146daa46b4397f0.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt5_hu762cddcaece0772ed3cad7f11147374f_101691_fcfc603bc9bba810d27ccfb5523a791c.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt5_hu762cddcaece0772ed3cad7f11147374f_101691_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt5_hu762cddcaece0772ed3cad7f11147374f_101691_a67b76095ed40c19c146daa46b4397f0.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;但是，先驱有个问题：先驱和先烈只差一个字。一个常见的说法是：领先一步是先驱，领先两步，可能就变成先烈了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt6_hu08db2a129dab04f217eb2586f8739bac_62820_15f1b8ed336f01ab109757d83d983f60.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt6_hu08db2a129dab04f217eb2586f8739bac_62820_58c70918d17f1b4a5da99746ea15a52e.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt6_hu08db2a129dab04f217eb2586f8739bac_62820_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt6_hu08db2a129dab04f217eb2586f8739bac_62820_15f1b8ed336f01ab109757d83d983f60.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;就在linkerd和William还在布道的时候，让业界慢慢开始接受Servicemesh这个概念，发现后来，有一堆新人出来了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt7_hu749c5e4e6dfdd4c361268bce60747f12_73047_b8ed63de8d6ab55b4bb92de0113ef73b.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt7_hu749c5e4e6dfdd4c361268bce60747f12_73047_5e51b59ce5d0f3689ae6b7fbe1dedfae.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt7_hu749c5e4e6dfdd4c361268bce60747f12_73047_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt7_hu749c5e4e6dfdd4c361268bce60747f12_73047_b8ed63de8d6ab55b4bb92de0113ef73b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;新的Service mesh，在2017年，蹭蹭蹭的文莱了。第一个，Envoy，这是业界第二个Servicemesh，在今年九月份的时候，同样加入了CNCF。&lt;/p&gt;
&lt;p&gt;Envoy还好，基本上属于同质竞争，就是大家都在一个层次上，至少还有的打。&lt;/p&gt;
&lt;p&gt;但很不幸，istio杀出来了——大家可以看到Istio发布的时间点还是很快的，5月，10月，12月，就0.3了。Isito从架构，从功能上，比linkerd和Envoy是上了一个层次。这个就头疼了，属于下一代打这一代。按照《三体》的说法，这属于降维攻击：只要对手完成，基本上就是等死。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt8_hua6fafb117a054f0cb2848085a43c1dfd_86893_95d4fc3582e8bec93619ac72c6337a9d.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt8_hua6fafb117a054f0cb2848085a43c1dfd_86893_56de0b66609e9c971bc2fb64781c3294.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt8_hua6fafb117a054f0cb2848085a43c1dfd_86893_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt8_hua6fafb117a054f0cb2848085a43c1dfd_86893_95d4fc3582e8bec93619ac72c6337a9d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们来看一下整个的时间表：Linkerd加入CNCF是一月，这是一个很关键点的，当时CNCF在类别上写了一个Servicemesh。当时看到这个词时还不知道Service Mesh是什么概念。但它对Linkerd特别重要，因为业界已经接受了Servicemesh的概念，且又被CNCF认可了。&lt;/p&gt;
&lt;p&gt;而后Linkerd1.0发布不到一个月，Istio就出来了，紧接着Envoy在九月份杀入CNCF。时间点上可以看到非常近，可谓是“江山代有才人出，各领风骚几个月”。整个2017年，Servicemesh的风头就是以一个月一个月的方式在做变化。现在我们可以看到事情有多残酷：前脚还很悠闲的做先驱，做布道，眼看就要变成先烈了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt9_hu30eb432e401b561b3282aa8f0ed82403_59957_2c6c4baf0e06ea07e3d71c867f5a6238.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt9_hu30eb432e401b561b3282aa8f0ed82403_59957_68fd38aa50c19e42a62369cbd6081abe.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt9_hu30eb432e401b561b3282aa8f0ed82403_59957_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt9_hu30eb432e401b561b3282aa8f0ed82403_59957_2c6c4baf0e06ea07e3d71c867f5a6238.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Istio缘何这么强？主要是三位创造Istio的大佬，Google、IBM、另外一位Lyft在前面两位这里算是小的。所以对于Linkerd来说会有种一时瑜亮的感叹：Linkerd刚出来很强，跨了一个时代的感觉，但脚还没站稳，就让人给揍了回来。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt10_hu54b3eeec9302676a638e17f464b4b4c8_90572_feb49266fc2a53be0531081dd077864b.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt10_hu54b3eeec9302676a638e17f464b4b4c8_90572_0d0c32a4cf5da1d54cc16e4f9a1a7680.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt10_hu54b3eeec9302676a638e17f464b4b4c8_90572_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt10_hu54b3eeec9302676a638e17f464b4b4c8_90572_feb49266fc2a53be0531081dd077864b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而Istio这个产品不仅后台过硬，社区支持够强，人也够多，能力也足，最重要的是它还特别努力。Isito在今年2700多个Commits，数量远远超过了Linkerd，可以说在产品上，Istio做的非常努力。而在人手上，整个Linkerd公司才不到20人，Istio的Working Groups的leader就已经23位了，怎么玩？这就有一个很要命的问题：对方不仅强，还很努力。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt11_hu1c2e7552f922f6baa0f64d7f4892444c_78040_f28f50322a4516bc7be1415a96ab8081.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt11_hu1c2e7552f922f6baa0f64d7f4892444c_78040_f802218262d34abc5b9d7d942911f119.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt11_hu1c2e7552f922f6baa0f64d7f4892444c_78040_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt11_hu1c2e7552f922f6baa0f64d7f4892444c_78040_f28f50322a4516bc7be1415a96ab8081.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;刚才提到的问题，上一场战斗刚刚打完，硝烟还未散去，尸骨都还没有寒呢。Mesos这里我们写着山河破碎，为啥呢？Mesos之前曾经占据领先的优势，最早的时候大部分江山是mesos的，而且现在都残留着很大的地盘。Swarm大家也看到了，基本上是宣布俯首称臣了。Kuberentes笑而不语，笑到最后。&lt;/p&gt;
&lt;p&gt;在这场战争结束之后，这场离得非常近，打的非常激烈，可谓殷鉴不远。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt12_hu5744ab7878bf48354ae81d96db8a877c_74976_ee2c623c69bacb165c93abc2e4c79424.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt12_hu5744ab7878bf48354ae81d96db8a877c_74976_5d6fadd5f468f60c9c3dd342efd5d4bc.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt12_hu5744ab7878bf48354ae81d96db8a877c_74976_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt12_hu5744ab7878bf48354ae81d96db8a877c_74976_ee2c623c69bacb165c93abc2e4c79424.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;接下来有一个关键的问题：到底怎么办？&lt;/p&gt;
&lt;p&gt;现在Google带着Istio出来了，还叫上了一堆IBM，Lyft这样的助手，以及社区。对于Linkerd以及它的Servicemesh类的产品，就要面对一个问题：到底是想跪着生？还是站着死？&lt;/p&gt;
&lt;p&gt;如果你有勇气和它对抗，那你站着，但若面对的是这样的竞争对手，胜算在哪里？如果没有勇气直面，接下来该怎么办？出路在哪里？这个问题困扰了我一段时间，因为我也在考虑要不要做一个Servicemesh的产品.这个问题细想起来，真的会很纠结。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt13_hu8c01221b1072ae8844c2a194079ef2cb_29548_5eb81c326c088f4e2ee7921263bdcab0.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt13_hu8c01221b1072ae8844c2a194079ef2cb_29548_0b466c218085c3f851cc5d61607788c4.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt13_hu8c01221b1072ae8844c2a194079ef2cb_29548_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt13_hu8c01221b1072ae8844c2a194079ef2cb_29548_5eb81c326c088f4e2ee7921263bdcab0.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们来看看istio身后的Google。&lt;/p&gt;
&lt;p&gt;Google是我个人是最崇拜的公司，没有之一，它做了很多让我感觉是真的在推动人类文明往前走的事情，比如它前段时间发表的论文。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt14_hu1f17d01744ecb1f1479fb6b1bb6e2901_133108_0d9457779b74734e8a70c5539fbe4302.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt14_hu1f17d01744ecb1f1479fb6b1bb6e2901_133108_05e2134715afa26ad5e3e11f37be5d6e.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt14_hu1f17d01744ecb1f1479fb6b1bb6e2901_133108_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt14_hu1f17d01744ecb1f1479fb6b1bb6e2901_133108_0d9457779b74734e8a70c5539fbe4302.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们回到容器、云的领域，Google非常的强，可以说是“剑在手问天下谁是英雄”。&lt;/p&gt;
&lt;p&gt;左边，Kuberentes，屠龙宝刀已成，现在是“号令天下莫敢不从”，整个领域都没人敢说不。&lt;/p&gt;
&lt;p&gt;右边，Istio，现在还在磨砺，虽然还未成功，但有勇气跟它竞争的人已经不多了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt15_hu197224b07b1c07517720e147b9776a17_107918_9088d9bce12e70f3876e8056dfa7733f.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt15_hu197224b07b1c07517720e147b9776a17_107918_e74e0dd57d94576d3e3df9eaa48b678f.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt15_hu197224b07b1c07517720e147b9776a17_107918_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt15_hu197224b07b1c07517720e147b9776a17_107918_9088d9bce12e70f3876e8056dfa7733f.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是目前我个人的判断，因为个人原因我比较关注这几个点。&lt;/p&gt;
&lt;p&gt;GCP是Google云平台的缩写，下面是四个旗下的产品：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;其中Kuberentes很熟悉了，它已经搞定整个容器，而且是Done的状态，基本上已经是事实标准了。&lt;/li&gt;
&lt;li&gt;Isito按照我的理解是准备出来搞定下一代微服务的，仍在路上，但等成熟稳定后，基本上很难有强劲的竞争对手。&lt;/li&gt;
&lt;li&gt;后面两个可能相对偏门一点，但对我比较特殊，我可能是国内第一批对gRPC进行研究的。如果大家对gRPC这个技术有所了解，可能会知道我的名字。这个东西基本上是搞定下一代的RPC通讯了，大家没有知觉的情况下，下一代的RPC基本上在它那里了。目前这个市场用的不是特别多，仍在培育当中，但也没有强劲的竞争对手。&lt;/li&gt;
&lt;li&gt;而HTTP/2现在已经是W3C的标准，搞定了下一代HTTP：大家还停留在HTTP1.1上争夺的时候，google已经偷偷摸摸的直接把HTTP/2搞定了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这四个产品加在一起的有什么感觉？我的想法是GCP在下一盘很大的棋，若将它们串联在一起，接下来在容器、微服务、通信这个领域，都在Google的范围之内——它已经把路完全铺好了。&lt;/p&gt;
&lt;p&gt;底层操作系统，中间的容器，可能有一部分的PaaS系统，类似GCP这种，都是从Kuberentes这边走，已经搞定。服务间各种通讯，通讯机制如HTTP/2以及gRPC，这两个已经是事实标准了，搞定。现在全力以赴做微服务，Istio，准备继续往上做。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt16_hu2917b5ec328e8abe6bcb591cbb4c900b_59030_ee8a7024d495f549c89fde6834ef2c15.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt16_hu2917b5ec328e8abe6bcb591cbb4c900b_59030_f66c5ecfcf6505d3e791eea986951a36.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt16_hu2917b5ec328e8abe6bcb591cbb4c900b_59030_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt16_hu2917b5ec328e8abe6bcb591cbb4c900b_59030_ee8a7024d495f549c89fde6834ef2c15.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;大家注意这张图，google现在是从底层一步步向上做，趋势非常明显。我们现在回头看这个布局。现在我不敢确定说Google是否真的在下这么一盘棋，但若真的有人在刻意下棋，只能说明这个棋手的能力太强了。现在要跟Google去争，如何去争？直接帮你将后面的东西全部铺好了。&lt;/p&gt;
&lt;p&gt;当然，这里还有一个小小的悬念，如果一两年之内，Istio有能力将微服务这一块完全搞定，那么它的下一个目标会是什么？不出意外的话google会继续往上走，继续往业务上走，但会是什么现在还想不明白。&lt;/p&gt;
&lt;p&gt;这里留一个悬念，两年之后大家再来看这个图，就可以知道这个问好是什么。&lt;/p&gt;
&lt;p&gt;OK，是不是有种阴谋论的感觉？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt17_hu252ca4ce330002c71e93c8f7a8603b5a_79373_d99202456162d347417c944949c0656b.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt17_hu252ca4ce330002c71e93c8f7a8603b5a_79373_d40b761e671b3cf42373ccff2728f57e.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt17_hu252ca4ce330002c71e93c8f7a8603b5a_79373_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt17_hu252ca4ce330002c71e93c8f7a8603b5a_79373_d99202456162d347417c944949c0656b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;回到微服务，在Servicemesh这个领域，Google这一次没有直接自己单干，而是搞了一套Istio，然后这次找了IBM。这里面有一个象征意义的东西，Google其实是标准互联网典型代表，但IBM是传统企业，虽然也一直在往互联网上走，一直往这方面做，但企业形象还是偏重传统。他的目标用户也是偏向传统企业用户，它们的合作象征意义是非常大的。&lt;/p&gt;
&lt;p&gt;上面我一直在推一个概念，我们现在这个世界，这个技术潮流，有一个很重要的趋势是：传统企业用户向互联网技术做转型，大家注意到这个趋势，会非常明显。如果你在互联网工作，是没什么感觉的。但是如果看传统企业用户，会发现他们现在的技术完全是往互联网这边走，往微服务、容器、敏捷走，现在基本上他们都开始陆陆续续放弃weblogic、EJB、ESB，这个趋势非常明显。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt18_hufe791dda534af2d92a3b1958154ac3cc_122396_1985c5786e753a04a86f6bcd27aee902.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt18_hufe791dda534af2d92a3b1958154ac3cc_122396_9c3280d5cd2e4d5e6c2adac2bc5b4671.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt18_hufe791dda534af2d92a3b1958154ac3cc_122396_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt18_hufe791dda534af2d92a3b1958154ac3cc_122396_1985c5786e753a04a86f6bcd27aee902.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这样的一个合作很有意思。&lt;/p&gt;
&lt;p&gt;Google在Istio之前是有一些项目的，当时做了一个Google Service Control，如果熟悉Envoy，会发现这个功能点和现在istio的功能点非常像。实际上当时的一个重要的事情是这样的，IBM的一个VP在istio出来之后发表的一篇文章，意思是说Google和IBM各自在各自的领域做了一些事情，后来他们彼此间了解之后，发现相互之间是可以互补的，而且方向一致。所以做了很重要的一个决策：各自放弃吧，合起来一起做一个。刚好套上Service mesh的概念，就这样一拍即合，搞定。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt19_hu5d7f902e82267ced354425d17e382f84_97699_c84f91a9e1daac9911c87700162a9c31.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt19_hu5d7f902e82267ced354425d17e382f84_97699_2f4e8694adc806e845207e7831705ac7.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt19_hu5d7f902e82267ced354425d17e382f84_97699_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt19_hu5d7f902e82267ced354425d17e382f84_97699_c84f91a9e1daac9911c87700162a9c31.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;可以想象Google和IBM的影响力，一起合作是什么概念？我们可以看到Istio在社区里得到了非常积极的响应。这些东西是在0.1版本的时候就已经开始在响应了，0.1是在今年五月份。&lt;/p&gt;
&lt;p&gt;这里面很重要的一个是Oracle。容器：K8S，这不出意外。微服务直接选Istio，这个有点出乎我意料。Serverless是直接收购了一个FN的项目。这里面很明确的是，他们的微服务就是Istio，这是它的战略决策。&lt;/p&gt;
&lt;p&gt;Redhat就比较好理解，它一直跟Google和Kubernetes跟的很紧，所以它选择Istio完全可以理解。&lt;/p&gt;
&lt;p&gt;反而是最后这一位，Pivotal，它的Cloud foundry非常明确要支持Istio。但是这里面有点古怪的地方是，这家公司本身是好像有点跟Google对着干的感觉。&lt;/p&gt;
&lt;p&gt;后面几家公司相对比较小一点，但是它们各自领域都是比较特殊的。但是这几家公司除了Ambassador时间不确认，剩下五家公司都是在0.1版本出来的，今年五月份出来，就明确要支持。&lt;/p&gt;
&lt;p&gt;这也体现了Google在社区可怕的号召力：一个新的开源产品才发布0.1版本，别人就已经开始站队，这是什么概念。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt20_hu7db3471314108f8e5fd65dd3ff46dbab_74005_50b8f9118e0ef8ad6651c636bde9e3ae.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt20_hu7db3471314108f8e5fd65dd3ff46dbab_74005_56f0ea47ba0f18dfe0da5cbfd2c1889b.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt20_hu7db3471314108f8e5fd65dd3ff46dbab_74005_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt20_hu7db3471314108f8e5fd65dd3ff46dbab_74005_50b8f9118e0ef8ad6651c636bde9e3ae.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;左边这张图，大家应该看过了，前一段时间在网上非常火，因为这个代表今年KubeConf非常标志性的一个东西，就是Servicemesh在这次会议上非常火爆。2018年预测它会全面的爆发，至少这个技术会在大多数的领域会被人关注、使用、探索，不排除落地，如果它的release版本发布足够快。&lt;/p&gt;
&lt;p&gt;Istio应该会在2018年发布，我还顺便问过0.3版本，按照它的说法，是已经接近了Production ready。但是根据我们测试的结果，不行。这里面还有一些小障碍，可能0.4、0.5可能会，但是从目前看，差距不是特别远，但2018年这个产品肯定会发布的，具体是上半年还是下半年不好说。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt21_hu8c01221b1072ae8844c2a194079ef2cb_28618_060fd7b2ebcdcad035f72f41a74ab11a.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt21_hu8c01221b1072ae8844c2a194079ef2cb_28618_fd56328a538853d6c6e5805a437384b7.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt21_hu8c01221b1072ae8844c2a194079ef2cb_28618_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt21_hu8c01221b1072ae8844c2a194079ef2cb_28618_060fd7b2ebcdcad035f72f41a74ab11a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;再来看看IBM。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt22_hu03358f4a7cc68779a7a913cec9a01a09_128250_a3e1f2d8c0be77eb7a3dd832cb9952dc.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt22_hu03358f4a7cc68779a7a913cec9a01a09_128250_631b3afef4b01d03409ae6d7f6205489.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt22_hu03358f4a7cc68779a7a913cec9a01a09_128250_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt22_hu03358f4a7cc68779a7a913cec9a01a09_128250_a3e1f2d8c0be77eb7a3dd832cb9952dc.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;刚才说它有一个产品的，现在非常明确，这个产品已经停止演进。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt23_hu03358f4a7cc68779a7a913cec9a01a09_59326_25c4057ca462bb80d7d67cbc1e3d7036.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt23_hu03358f4a7cc68779a7a913cec9a01a09_59326_c84481c4617cd433f36297f1ce4af6eb.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt23_hu03358f4a7cc68779a7a913cec9a01a09_59326_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt23_hu03358f4a7cc68779a7a913cec9a01a09_59326_25c4057ca462bb80d7d67cbc1e3d7036.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;现在的战略其实非常的明确，它自己的公有云改成基于Kubernetes，接下来会支持Istio，它的云服务商会推广。&lt;/p&gt;
&lt;p&gt;而且听说已经在公有云上上线了，但是没有找到，不过很明显它接下来会直接在公有云上直接支持Istio。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt24_hu2d330940f705875b1aac01ff0462f7bd_120548_d6d8dfc7914eda22e1f8dc9f6eed17e8.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt24_hu2d330940f705875b1aac01ff0462f7bd_120548_5dd169fa3ac43bcfec2fa7d95ba0c46d.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt24_hu2d330940f705875b1aac01ff0462f7bd_120548_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt24_hu2d330940f705875b1aac01ff0462f7bd_120548_d6d8dfc7914eda22e1f8dc9f6eed17e8.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里面有一张图是Istio的Working Group，可以看到这个图上的leader，23位leader，基本上都是IBM和Google的人。而且这里面可以非常明确的看到一点，IBM在这个项目当中是属于深度参与的状态。它基本上和Google一对一了，基本上所有的团队都在，和Google平起平坐。目对于IBM来说也是投入非常大，也是非常重视的一个项目。&lt;/p&gt;
&lt;p&gt;前面说到Istio有三位创始人，这里谈到两位，整个Working Group里只看到这两个公司，lyft哪里去了？lyft一直都没有出现。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt25_hu8c01221b1072ae8844c2a194079ef2cb_26666_c56da1ecc4e07d890d9f592c6b8149e0.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt25_hu8c01221b1072ae8844c2a194079ef2cb_26666_2e43c74f9cba78b97152482da5ae3068.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt25_hu8c01221b1072ae8844c2a194079ef2cb_26666_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt25_hu8c01221b1072ae8844c2a194079ef2cb_26666_c56da1ecc4e07d890d9f592c6b8149e0.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt26_hu58dcfdd7485d279b4179265615ff60c3_84011_9052fe954e5f66fd9db6ee3cab2a1806.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt26_hu58dcfdd7485d279b4179265615ff60c3_84011_021f9f08f780ad7cc590105f4821cfa2.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt26_hu58dcfdd7485d279b4179265615ff60c3_84011_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt26_hu58dcfdd7485d279b4179265615ff60c3_84011_9052fe954e5f66fd9db6ee3cab2a1806.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Lyft的贡献完全在Envoy代理，这张图是很经典的istio架构的图，红色箭头对应的位置是Envoy，它是做底层的数据平面。lyft所有的贡献都是集中在Envoy代理里面。其它的东西是Google和IBM在做，而这个地方是lyft在做。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt27_hu509c5db4424d5b1d280e454c4c3010f1_91810_d2bf84283c899c81a03c8292ab7901e3.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt27_hu509c5db4424d5b1d280e454c4c3010f1_91810_8de84211403abb0cebb70812b861b9a1.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt27_hu509c5db4424d5b1d280e454c4c3010f1_91810_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt27_hu509c5db4424d5b1d280e454c4c3010f1_91810_d2bf84283c899c81a03c8292ab7901e3.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里面有一些比较有意思的东西，有点阴谋论的感觉。&lt;/p&gt;
&lt;p&gt;首先在Envoy这个角色上，它是扮演数据平面的角色。第二个是它的控制平面是通过API来跟数据平面交互，没有绑死，是一个明确的API。底层数据平面的具体实现和核心的控制平面是解耦的，是通过一个定义好的API来做这个约束。所以理论上有一个可能性，只要兼容这个API，Istio可以和任何一个数据平面集成。这是可以替换，当前默认集成是Envoy——这个地方有没有感觉到，似曾相识？&lt;/p&gt;
&lt;p&gt;大家想一下K8S和Docker的关系，还有OCI规范，你会发现好像有这么回事。但是现在默认的是Envoy，但是这里面存在微妙的感觉，就是说它存在替换的可能性。有一些事情只要有可能，就有可能会发生，对不对？那会在什么情况下发生呢？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt28_hu3ec08b084c9b712bcc8937de082a7f99_122071_e1cdb6901d7280def623338eed7a559d.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt28_hu3ec08b084c9b712bcc8937de082a7f99_122071_a2e2b00f0c6571dbdf2a7fdc379158c2.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt28_hu3ec08b084c9b712bcc8937de082a7f99_122071_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt28_hu3ec08b084c9b712bcc8937de082a7f99_122071_e1cdb6901d7280def623338eed7a559d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这个地方很有意思，Istio其实是给其他Service mesh留了一条活路。istio是来换代的，理论上它来了后，其他service mesh就死了，只有它能成，但是它还是留了一条活路。这个考虑，不太清楚，我个人的理解应该是“节约时间快速推出产品”，所以它刚刚出道的时候，选择了没有自己做数据平面而是集成。Istio出来时选择了集成envoy，envoy是c++。按照Google的习惯，做这种底层的东西，肯定是自己都做的。但是它选择集中精力去做控制平面，把数据平面给envoy去做。所以这个地方，原配是Envoy，但是原配是原配，没有说一定要白头偕老。linkerd就发现这个问题，只要努力就有机会，没有挖不动的墙角，只有不努力的小三。Linkerd就干了这个事情，他在1.2、1.3的版本当中，从半年前开始，他就开始做Istio的集成，努力的满足Google的API要求，往那边去走。这个兼容它一直在做，非常努力的在做，被我成为努力的小三。&lt;/p&gt;
&lt;p&gt;有努力的小三，就意味着还有一个不努力的小三——nginmesh。今年大概九月份的时候，nginx突然宣布要搞出一个Servicemesh来。当时我个人很兴奋，当时它写了一篇文章，我就去翻译这些文档。文中说它要和istio集成，当时以为有一场好戏看，两个小三开始打原配了。结果后来发现这个项目开源三个多月，它几乎没提交。非常的不努力，不知道发生了什么事情。&lt;/p&gt;
&lt;p&gt;接下来，在看Istio的核心模块，控制面板上面有三个核心模块，上面这三个模块都是Google自己在做，唯独留了下面Sidecar。四个东西做三个，留一个，大家能想到什么成语吗？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt29_hua0c0c00c34f883c2cb3314131020da74_135062_3db80f0652906100da8271b233b0c9c5.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt29_hua0c0c00c34f883c2cb3314131020da74_135062_c30fb410c5babc8ed0014826d5ef3052.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt29_hua0c0c00c34f883c2cb3314131020da74_135062_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt29_hua0c0c00c34f883c2cb3314131020da74_135062_3db80f0652906100da8271b233b0c9c5.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;围三阙一，又名叫“围师必阙”，这是孙子兵法里的一条，打仗的八个原则之一。它的意思是，如果你要全面合围敌人的话，有可能会让对方的指挥官定下拼死一搏的决心。反而你故意留一个缺口，对方就会在到底是逃跑还是死战之间摇摆不定，同时会使对方的军心和斗志涣散。&lt;/p&gt;
&lt;p&gt;现在有没有这种感觉，四个东西故意留了一个，给其他service mesh一条活路。但是这有点阴谋论，我也不确定它们是不是真的这么玩。如果是真的，只能说Google的心机太可怕了。但是感觉上是这样的，因为对其它的Service mesh而言，这个事情上就有选择。到底要不要跟Istio联手，到底要不要做这个小三。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt30_hu75926c0fafa07b79c2520de8ee02c206_112083_af190be003e627e703fcfd965fb218ce.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt30_hu75926c0fafa07b79c2520de8ee02c206_112083_3537cc8db58ff1b5b5e47248c7c87f9e.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt30_hu75926c0fafa07b79c2520de8ee02c206_112083_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt30_hu75926c0fafa07b79c2520de8ee02c206_112083_af190be003e627e703fcfd965fb218ce.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这种事情因人而异，对不对？&lt;/p&gt;
&lt;p&gt;对于Envoy和lyft来说，好啊好啊，就像图中一样握手。女神说，你要不要来啊，来啊来啊，搞定。所有envoy很开心，lyft也很开心，lyft直接把整个envoy贡献出来了，整个团队干这个事。&lt;/p&gt;
&lt;p&gt;但是有一个问题，对于右边这个图，对于linkerd来说，这是荣幸吗？右边这个图是韩信当年的跨下之辱。同样是跟Istio联手，对于大家的选择是完全不一样的，为什么？你的屁股决定了你的脑袋。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt31_huf8bb89e46f287898c273e5faeebb1eae_79648_b465ab257a0e1bbe807204ab2e49858a.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt31_huf8bb89e46f287898c273e5faeebb1eae_79648_73bd4ccc883fa9ddf75f77f2fe8855c7.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt31_huf8bb89e46f287898c273e5faeebb1eae_79648_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt31_huf8bb89e46f287898c273e5faeebb1eae_79648_b465ab257a0e1bbe807204ab2e49858a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这家公司是一家初创型的公司，现在才十几个人。它是一家技术型的创业公司，它不是lyft。lyft是做租车的，Envoy是它的一个开源项目，它不靠这个挣钱的，它把Envoy白送给Google，它有损失吗？它打车的市场会因为这个原因损失百分之一的份额吗？没有任何问题，所以它很开心，没问题。&lt;/p&gt;
&lt;p&gt;但是对于buoyan这家公司来说，这是命根子，它创业的根基就在这里，它能把自己的根基扔出去吗？所以说，彼之蜜糖，吾之砒霜。Lyft扔可以，lyft可以扔掉envoy，白送都行啊，我还贴个团队给你做，没问题。但是linkerd能这么干吗？linkerd如果只是跟istio做集成，如果它的未来只是做集成，它还是以小三的身份，它都不是原配，那还有什么前途可言。&lt;/p&gt;
&lt;p&gt;所以这个事情，后面一直困扰我，我看到它1.2版本做istio集成之后，我就没想明白这个事。一直到后来……&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt32_hu89bcfc12a9f97ab2cfa3ec45a73f6afa_136180_1278caf48342d4b3aad5203e99096441.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt32_hu89bcfc12a9f97ab2cfa3ec45a73f6afa_136180_cd6c86bf9963aa46ecb8a0f65156849d.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt32_hu89bcfc12a9f97ab2cfa3ec45a73f6afa_136180_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt32_hu89bcfc12a9f97ab2cfa3ec45a73f6afa_136180_1278caf48342d4b3aad5203e99096441.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里有一个很有意思的典故，三国中曹操大军压境，赤壁大战之前，当时孙权犹豫到底是投降还是反抗。鲁肃当时劝孙权，说我们可以投降，没问题，我们投降还是可以继续荣华富贵，将军迎操，欲安所归？你孙权投降曹操，你想怎么样？&lt;/p&gt;
&lt;p&gt;道理是一样的，现在是Istio大军压境，linkerd考虑到底是战还是降。关键是你降了之后你能干什么？所以这个地方一直困扰我，因为我看到linkerd一直在投降，死命的在兼容，死命的做努力的小三，对方还不理你。我看到Istio从来没有提过linkerd，linkerd那边死命的说我要跟Istio集成，标准的热脸贴冷屁股的感觉。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt33_hu5744ab7878bf48354ae81d96db8a877c_99840_f3730d7c1bcc0efd3f772c60701d3ca6.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt33_hu5744ab7878bf48354ae81d96db8a877c_99840_d4dc2fe1f505b193085dcd2e239e9b12.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt33_hu5744ab7878bf48354ae81d96db8a877c_99840_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt33_hu5744ab7878bf48354ae81d96db8a877c_99840_f3730d7c1bcc0efd3f772c60701d3ca6.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;回到刚才那个问题，到底是想跪着生还是想站着死？因为站着真的会死，如果没有这个勇气，出路在哪里。很明显跟Istio做集成，这是一个非常温柔的陷阱，进去了，差不多就死在里面了，仅此而已。能做的空间很有限。它直接把天花板搁在那里了，剩下的东西它都做了，你只能做到这里而已，没有空间可言。&lt;/p&gt;
&lt;p&gt;如果你看到这条死路，你就只能硬挺着跟它干一仗，但胜算在哪里？&lt;/p&gt;
&lt;p&gt;如果没有想好这个问题，如果没有想好有什么机会，千万别跟Istio争了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt34_hu8c01221b1072ae8844c2a194079ef2cb_49637_c357cae83594f6216b7db1ff6784ea84.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt34_hu8c01221b1072ae8844c2a194079ef2cb_49637_0ebbc71ddb3e364d4b2277064bf4a683.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt34_hu8c01221b1072ae8844c2a194079ef2cb_49637_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt34_hu8c01221b1072ae8844c2a194079ef2cb_49637_c357cae83594f6216b7db1ff6784ea84.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;但是很明显，有个家伙想好了，这是非常令人惊讶的。至少对于我而言，当我第一次看到这个产品的时候，感觉突然兴奋了一把：真的有人搞出来了？&lt;/p&gt;
&lt;p&gt;Conduit这个产品，是Buoyant的绝地大反击。在12月5号的时候，它突然发布了这个产品。先看看这个产品是什么？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt35_hu23c07488deaebff3ec8f53fc2e4a5817_101893_8d48034246b75ea31527844d86642411.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt35_hu23c07488deaebff3ec8f53fc2e4a5817_101893_f70cddb138d36eebbe2da1ad7ce83108.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt35_hu23c07488deaebff3ec8f53fc2e4a5817_101893_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt35_hu23c07488deaebff3ec8f53fc2e4a5817_101893_8d48034246b75ea31527844d86642411.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;首先它是从头开始的，除了还是这个公司之外，它跟linkerd没有一毛钱关系。&lt;/p&gt;
&lt;p&gt;然后它的目标是成为最快、最轻、最简单、最安全的Service mesh。最简单不好说，因为大家都刚开始，最安全我也没有测过，但是最轻和最快这两个词是比较容易做体验的。&lt;/p&gt;
&lt;p&gt;它为了达到这两个目标，它使用了Rust这个编程语言。这个语言是很偏门的语言。&lt;/p&gt;
&lt;p&gt;（注：现场互动环节，听过rust同学请举手。只有5个人）&lt;/p&gt;
&lt;p&gt;这个语言是个非常偏门的语言，但是它最大的好处是性能超好，资源占用超级低，蛮梦幻的语言。除了有代码写的方式有点反人类之外，我之前说要学这个rust的时候，他们说告诉我说你小心，反人类哦。这个语言好处是你真的把它吃透了，它应该是目前最适合拿来做proxy的一个语言，资源消耗非常低。&lt;/p&gt;
&lt;p&gt;conduit还有一个很重要的事情，就是它吸收了过去的经验。就是过去18个月，在linkerd上沉淀了各种真实的经验。因为linkerd是生产级的，而且linerd很多企业直接上生产，这一点非常重要。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt36_hu859c5ebb22f43c7e5190d9a3c8ff52fc_118345_3a1956185e36e353b64e3a7e36ceabcc.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt36_hu859c5ebb22f43c7e5190d9a3c8ff52fc_118345_cf7fe1cf43e431dd2c27cd6b027541fd.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt36_hu859c5ebb22f43c7e5190d9a3c8ff52fc_118345_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt36_hu859c5ebb22f43c7e5190d9a3c8ff52fc_118345_3a1956185e36e353b64e3a7e36ceabcc.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;可以看到这个rust的过人之处。&lt;/p&gt;
&lt;p&gt;后面三条数据不直白，但是第一条太明显了，Conduit代理用不到十兆实际内存，P99在分毫秒之内，这个可能不是太敏感，但是十兆应用太敏感了。proxy是跟每一个应用都直接对应启动起来，要启动n份，这个资源消耗其实是蛮大的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt37_hub07a9cf8bf6ce3ebb2a5e190bd51581c_119680_46858717c58f9d79298227672feef60b.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt37_hub07a9cf8bf6ce3ebb2a5e190bd51581c_119680_5749bfa9fc1a22cd8d875be2238d5fd5.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt37_hub07a9cf8bf6ce3ebb2a5e190bd51581c_119680_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt37_hub07a9cf8bf6ce3ebb2a5e190bd51581c_119680_46858717c58f9d79298227672feef60b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这个时候的关键点就在于2018年，2018年Service mesh这个市场几乎是蛮荒时代，除了linkerd和envoy有一小部分企业用户之外。大部分人都在等，等一个足够让大家放心的产品再用，市场基本上是空白的，但是要拿到这个市场有一个非常重要的事情：一定要用自己的实际表现说服大家，让大家觉得Service mesh可以落地，可以做商用，可以上线。&lt;/p&gt;
&lt;p&gt;这点很重要！&lt;/p&gt;
&lt;p&gt;2018年最重要的事情就是：谁能第一个达到这个目标，让大家敢用，敢在生产上用。&lt;/p&gt;
&lt;p&gt;大家如果有注意的话，会注意到，Istio在发自己的release note的时候，都写了一句话：不要用，不要用，不要用&amp;hellip;&amp;hellip;很搞笑的，你能想象吗？他自己发的release note，特别注明不要用它。&lt;/p&gt;
&lt;p&gt;在这里面Istio基本上就算一个贵族了，背景非常深厚，自己能力也很出众，盟友众多。基本上可以看到Istio只要它自己不犯错，它这个地位非常难撼动。现在的唯一的悬念就是说它的1.0或者是它的Production Ready版本什么时候发布，它如果今天马上发布的话，这个市场基本上没有什么悬念可言。它如果拖到明年、后年发布，那就没它什么事了。拖到年底，如果Conduit够快，也很难说。&lt;/p&gt;
&lt;p&gt;所以这里面有非常大的悬念，谁先搞定第一个生产可用的版本。&lt;/p&gt;
&lt;p&gt;Buoyant算是江湖草莽吧，一个小公司但是一身傲骨。之前看它俯低做小伺候Istio的时候感觉还很奇怪，但是突然之间把Conduit拿出来。前面那个行为现在感觉有点变质了，有点像当年勾践卧薪尝胆的感觉，卧薪尝胆，然后突然间憋出一个大招来了。&lt;/p&gt;
&lt;p&gt;Conduit还是有一些优势的，首先这家公司因为linkerd的原因，它一直是摸爬滚打在Service mesh的第一线，它是少有的几个真正在线上跑过的Service mesh，这一点是没人比的过的。它是最懂Servicemesh的，这是它最大的优势。人也不多，但是不多的几个人里面，有几个真的是高手，这也是一个优势。因为人不多，所以只能做简单一点，做的接地气一点，实用一点，基本上是可以预料的。但是现在打一个问号，我是预判的，实际是不是这样，还要看它产品真实表现。&lt;/p&gt;
&lt;p&gt;最近也看到有人给了conduit一个标签，叫做穷人的Servicemesh，因为它的资源消耗非常低，也比较简单，所以有这么一个标签。但是究竟是不是，接下来2018年，我们能看到。&lt;/p&gt;
&lt;p&gt;右边写了一个问号，这么大的一个市场，会不会有新的竞争者进来，这个不好说，说不定哪天就有人蹦进来了。但是跟Istio集成的就不算，没有什么意思，如果进来只是为了做一个小三就没意思了。对于Service mesh是一开局，开局就是红海，左边这两位已经在刀对刀的在拼杀了，所以如果是庸人，只能进来做个小三，打个酱油，基本上可以不用进来了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt38_hu8c01221b1072ae8844c2a194079ef2cb_43923_d6abafed1145525bec5bf4feb6b6fcc3.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt38_hu8c01221b1072ae8844c2a194079ef2cb_43923_7ea1022faed0479fb99964424c3f8fda.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt38_hu8c01221b1072ae8844c2a194079ef2cb_43923_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt38_hu8c01221b1072ae8844c2a194079ef2cb_43923_d6abafed1145525bec5bf4feb6b6fcc3.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们将整个service mesh的大潮，和市场，过了一遍。接下来我们看一下这个大潮下的应对。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt39_hufbda77b8ea70e4e17866254923ee60c2_121333_b2b8db18dc03f2382c42136d44851c45.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt39_hufbda77b8ea70e4e17866254923ee60c2_121333_8ac355ae3854d4ff0855e9cc206a0355.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt39_hufbda77b8ea70e4e17866254923ee60c2_121333_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt39_hufbda77b8ea70e4e17866254923ee60c2_121333_b2b8db18dc03f2382c42136d44851c45.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;首先这个东西是个革命，革命就是两个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;第一谁革命，大家都知道Servicemesh要革命。&lt;/li&gt;
&lt;li&gt;第二个问题是革谁的命，这是比较有意思的。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Service Mesh号称下一代的微服务，下一代的微服务概念是什么，当前的微服务是谁？大家很清楚，当前主流微服务框架是左边Spring Cloud，基本上首选。现在刀架在脖子上，Pivotal这个公司会怎么样，是会顺应潮流，说那也好，我们也搞Service Mesh吧。搞个spring cloud on service mesh,或者干脆砍掉整个Spring Cloud，说觉得Spring Cloud没意思，直接spring on service mesh。&lt;/p&gt;
&lt;p&gt;其实后者我挺喜欢的。Spring Boot是很清爽的东西，觉得它的设计，实现，包括资源消耗是很好的。如果Spring Boot能跑到Service Mesh上，真的是很清爽的搭配。但是，这个毕竟只是我的主意，也许他们不为所动，说不定他们就不玩Service Mesh。&lt;/p&gt;
&lt;p&gt;为什么会有这个想法，因为去年曾经给它们提议，让他们支持RPC，被拒绝了。Spring Cloud说我喜欢rest。就是这么固执，不好说它最后做什么决策，2018年我们可以看，它也许有动作，也许没动作。&lt;/p&gt;
&lt;p&gt;OK，这个地方革命的对象非常明确，就是以新一代微服务的身份，把整个微服务这条路走过去：走别人的路，让别人无路可走。只要它把微服务全部搞定了，自然就没有上一代啥事了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt40_hu19c5163f60859b7a7551559a2cec17ef_108924_ca16f2bc72ad42024a717207333d50e6.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt40_hu19c5163f60859b7a7551559a2cec17ef_108924_d1bf4fbce47389950734cdb950d4ca96.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt40_hu19c5163f60859b7a7551559a2cec17ef_108924_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt40_hu19c5163f60859b7a7551559a2cec17ef_108924_ca16f2bc72ad42024a717207333d50e6.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Service mesh实际上有一些天然的盟友，有一种类型的微服务框架它是比较容易向Service mesh靠拢的，即原来就是Sidecar模式，或者它有比较好的意愿可以快速转成Sidecar。&lt;/p&gt;
&lt;p&gt;可以看到今年的全球架构师峰会上，华为在讲它的那个Mesh。它们原来有一个Golang sdk，最近好像是被我勾引了一把，他们快速堆出了一个Go版的Service mesh出来，现在看还挺成功的。&lt;/p&gt;
&lt;p&gt;还有Motan，这个我就不细说了，一会另外一位讲师周晶同学会做详细的分享。&lt;/p&gt;
&lt;p&gt;多说一下，其实很多企业用户，有没有开源的产品。在某些企业里，也有一些典型的服务化框架，比如说唯品会的OSP框架，它就是一个很典型的。内部一个sidecar模式在跑。对它而言，如果想向Service mesh靠拢是非常简单的，因为本身和Service mesh的方式非常相似。但是这里面有一个小悬念，它现在是基于Java的，那未来是不是还会基于Java还是把Java改掉，这就是一个悬念了。往后面看，看白衣到底是改不改。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt41_huef3a022857a5500369d2a8c1fddf9db5_146574_f3049e22caaf1fad427678e933633c13.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt41_huef3a022857a5500369d2a8c1fddf9db5_146574_382bf240f47cacb4a4e70b8f661d451b.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt41_huef3a022857a5500369d2a8c1fddf9db5_146574_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt41_huef3a022857a5500369d2a8c1fddf9db5_146574_f3049e22caaf1fad427678e933633c13.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;现在来看谁会拥抱Servicemesh？咱们只谈国内，不谈国外。&lt;/p&gt;
&lt;p&gt;在国内有一大批初创企业，典型的就是某某云，包括我们数人云。这些企业大部分是做容器、云、或者大数据。有一个共同点：单只做云这一块东西稍微有点薄，而且离最终的业务应用有点远。所以，向Google看齐，向上做，这是一条出路。其实很多公司都有这样的共识，只是多少的问题，有些人可能选，有些人可能不选。&lt;/p&gt;
&lt;p&gt;但是如果选择向上做，那微服务基本上是一个很自然的选择。业界也是公认的：微服务和容器的搭配非常的合适。但是选微服务是不是选择Service mesh，这是另外的事情。可以选择spring cloud，也可以选择Dubbo，虽然只剩几根骨头了。&lt;/p&gt;
&lt;p&gt;我们数人云算是率先走出第一步的。一方面会继续在Spring Cloud基础上提供稳定的服务，另外一个会积极的落地Service mesh的方案，这是我们接下来会做的事情，我们走了第一步了。现在不知道2018年还会有谁跟进，我们预计肯定会有初创的公司跟我们一起走这条路的。现在的悬念就是说谁是第二个，第三个，会有多少个。&lt;/p&gt;
&lt;p&gt;还有一些就是所谓的公有云的大鳄，它提供公有云的服务。Service mesh对于公有云而言，这是一个神兵利器，这个暂时只有我说这个话，相信时间越久就会有更多的认可。因为一旦Service mesh成熟，它会变成公有云的一个杀手锏的特性，到时候有没有Service mesh的功能，会是公有云非常重要的标识。这一点在2018年或者是2019年会变成一个大概率的事件，大家可以等着来挖坟，万一到时候service mesh没成功，那就打我脸好了。暂时这是我的一个判断。&lt;/p&gt;
&lt;p&gt;我们现在能看到的是，华为的公有云已经抢先出击了，提供了微服务的服务，它们是第一家。现有的公有云里华为现在动作最快，既提供传统架构的ServiceComb，也有基于Servicemesh的CSE mesher的。&lt;/p&gt;
&lt;p&gt;华为第一家出来没问题，问题是后面还有没有跟进，阿里云会不会跟，腾讯会不会跟，这个应该是2018年小小悬念：他们会不会跟？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt42_hucb6b48200f20b78fb0cdf6b0e0cb3e30_82793_ebbcb158af1016aef40e7b7e34be277b.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt42_hucb6b48200f20b78fb0cdf6b0e0cb3e30_82793_8f5a8cf513449237669d81b8fda3905e.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt42_hucb6b48200f20b78fb0cdf6b0e0cb3e30_82793_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt42_hucb6b48200f20b78fb0cdf6b0e0cb3e30_82793_ebbcb158af1016aef40e7b7e34be277b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;然后神仙打架，会殃及池鱼。&lt;/p&gt;
&lt;p&gt;一旦Service mesh成为主流，有一些领域会受到一些冲击，典型的像反向代理如Nginx、HAproxy，还有像API gateway。因为如果Service mesh成主流之后，没必要用反向代理了，直接Service mesh就好。也包括API gateway，有一部分功能其实istio会往上面去做。这两个领域会有一些冲击。&lt;/p&gt;
&lt;p&gt;我们看到Nginx曾经喊着说自己做Service mesh，但是也没有下文。其它的像Zuul、Kong这些，之前了解到有一个朋友说Kong曾经也在想，要不要做Service mesh。但是想了半天，最后没下决心，估计也卡在我刚才说的问题。大家还记得吧？如果要做的话，怎么干掉Google，如果没有信心干掉它的话，做它干什么？&lt;/p&gt;
&lt;p&gt;但是这两个领域，如果有人站出来，也是个好事，可能会多一个选择。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt43_hu8c01221b1072ae8844c2a194079ef2cb_30211_efa680032382a32a6abe8d9171f4ec86.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt43_hu8c01221b1072ae8844c2a194079ef2cb_30211_8e326f43a3feac2e15c422da2e112207.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt43_hu8c01221b1072ae8844c2a194079ef2cb_30211_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt43_hu8c01221b1072ae8844c2a194079ef2cb_30211_efa680032382a32a6abe8d9171f4ec86.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最后聊一下数人云。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt44_hu55a591847ba5b8c6ef2bb4f0907415c3_138060_0a077096fbea23038a8c93bed57c65ed.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt44_hu55a591847ba5b8c6ef2bb4f0907415c3_138060_1b860f480240a9f9808d53ac3c3747e1.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt44_hu55a591847ba5b8c6ef2bb4f0907415c3_138060_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt44_hu55a591847ba5b8c6ef2bb4f0907415c3_138060_0a077096fbea23038a8c93bed57c65ed.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;之前也有人问过问题，为什么数人云会选Service mesh？数人云基本上是国内第一家力推Service mesh的公司，布道师、拓荒牛还是担的起的，为什么？只是为了玩一个概念吗？&lt;/p&gt;
&lt;p&gt;其实这里面有非常大的背景，我们非常看好传统企业互联网技术转型这个市场，在我们看来，一方面这个市场非常巨大，我们的客户有非常多的微服务的需求。&lt;/p&gt;
&lt;p&gt;实不相瞒，我昨天就在上海，见了两家客户，了解需求，都想做微服务，都没有经验。都是传统的企业，他们第一次玩微服务。这里面有一个非常现实的东西：理想是把微服务玩转，把微服务所有的优点搞定，但是现实很有可能是，有这个想法，但是缺人、缺经验，缺技术、也没这个体系，没这个理念。甚至spring cloud也不是说玩就能玩转的，让一支团队几十号人把业务程序转到Spring cloud之后稳定上线，不是三两天能搞定的事情。&lt;/p&gt;
&lt;p&gt;传统的方案就是搞不定就死命搞，就把Spring cloud多学一下，一个月搞不定，三个月搞定；三个月搞不定，一年搞定。但是这样有一个麻烦：人力和物力投入非常大，时间和精力也耗不起，投入和产出比也不太好。所以这种情况下，最终我们选择了一个方案是两条腿走路。&lt;/p&gt;
&lt;p&gt;一方面我们会继续围绕Spring cloud这个体系，因为这个体系非常的成熟，如果客户有需求，会按照这个方案给他们走。这里做一个小广告，我们接下来会提供一个开源的配置中心，对标携程的Appolo。不出意外的话下个月，最晚下下个月会开源。接下来会有一个服务治理中心，解决目前Springcloud最不好的一个地方，就是服务治理太弱的问题，2018年我们会做这两个体系。&lt;/p&gt;
&lt;p&gt;除了Spring cloud体系之外，我们接下来会基于Service mesh探索新的方案，选择拥抱Istio和Conduit。暂时是两个都选择，因为不确定谁是最终最合适的。2018的目标是，希望这两个产品能够实实在在的帮我们解决客户存在的真实的问题，然后真真切切的帮客户落地微服务，把它的产品真正落在微服务上去上线，这是我们2018年的目标。我们要把这条路探索出来，具体到底是用Istio还是conduit不是问题，但是这条路要走通。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt45_hu03358f4a7cc68779a7a913cec9a01a09_48182_d8cda25bde9b69ae366a255fdcad59fc.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt45_hu03358f4a7cc68779a7a913cec9a01a09_48182_bb365723517581dde403d7f96e8abad7.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt45_hu03358f4a7cc68779a7a913cec9a01a09_48182_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt45_hu03358f4a7cc68779a7a913cec9a01a09_48182_d8cda25bde9b69ae366a255fdcad59fc.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最后，“2018, the year of service mesh”，我们期待这样一个时刻的到来。&lt;/p&gt;
&lt;p&gt;今天的演讲到此结束，非常感谢大家。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201712-make-a-choise-for-service-mesh/images/ppt46_hud70afc0b0f7d8a4f84ccf0a45abce0e5_139043_7040f028f9a61b11649efa55ae810231.webp 400w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt46_hud70afc0b0f7d8a4f84ccf0a45abce0e5_139043_65eeb563c281e893bca7c39736f0f1cc.webp 760w,
               /talk/201712-make-a-choise-for-service-mesh/images/ppt46_hud70afc0b0f7d8a4f84ccf0a45abce0e5_139043_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201712-make-a-choise-for-service-mesh/images/ppt46_hud70afc0b0f7d8a4f84ccf0a45abce0e5_139043_7040f028f9a61b11649efa55ae810231.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最后，如果您对service mesh技术感兴趣。请留意这里列出的信息。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://www.servicemesh.cn/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;servie mesh中国技术社区/中文网&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/ServicemeshCN/awesome-servicemesh&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;awesome service mesh资料清单&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://istio.doczh.cn/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;istio官方文档中文版&lt;/a&gt;：由servie mesh中国技术社区组织翻译&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://conduit.doczh.cn/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;conduit官方文档中文版&lt;/a&gt;：由servie mesh中国技术社区组织翻译&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
    <item>
      <title>Service Mesh：下一代微服务</title>
      <link>https://skyao.net/talk/201710-service-mesh-next-generation-microservice/</link>
      <pubDate>Sat, 14 Oct 2017 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/201710-service-mesh-next-generation-microservice/</guid>
      <description>&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-1_hu87b6d64fedccf770e03c5af6fc948095_72614_d46f979fe82d9956367ca98258c6be42.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-1_hu87b6d64fedccf770e03c5af6fc948095_72614_e32915bb3955c36a84ae9af13dfb667c.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-1_hu87b6d64fedccf770e03c5af6fc948095_72614_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-1_hu87b6d64fedccf770e03c5af6fc948095_72614_d46f979fe82d9956367ca98258c6be42.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;敖小剑：首先感谢这么多朋友来听我的演讲，今天我们分享的是Service Mesh，下一代微服务.我是敖小剑，来自数人云的资深架构师。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-2_hu8c01221b1072ae8844c2a194079ef2cb_101652_d2d5ccbdfd7dfaa6345c1406acc247e0.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-2_hu8c01221b1072ae8844c2a194079ef2cb_101652_0d06313c4cf073c656e535feead74764.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-2_hu8c01221b1072ae8844c2a194079ef2cb_101652_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-2_hu8c01221b1072ae8844c2a194079ef2cb_101652_d2d5ccbdfd7dfaa6345c1406acc247e0.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;简单回顾一下过去三年微服务的发展历程。在过去三年当中，微服务成为我们的业界技术热点，我们看到大量的互联网公司都在做微服务架构的落地。也有很多传统企业在做互联网技术转型，基本上还是以微服务和容器为核心。&lt;/p&gt;
&lt;p&gt;在这个技术转型中，我们发现有一个大的趋势，伴随着微服务的大潮，Spring Cloud微服务开发框架非常普及。而今天讲的内容在Spring Cloud之外，我们发现最近新一代的微服务开发技术正在悄然兴起，就是今天要给大家带来的Service Mesh/服务网格。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-3_hu8c01221b1072ae8844c2a194079ef2cb_65336_5c63c331ec26fed9cc05bbc660f4478a.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-3_hu8c01221b1072ae8844c2a194079ef2cb_65336_a2635af3cd130cd83a0f2691390242f4.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-3_hu8c01221b1072ae8844c2a194079ef2cb_65336_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-3_hu8c01221b1072ae8844c2a194079ef2cb_65336_5c63c331ec26fed9cc05bbc660f4478a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我做一个小小的现场调查，今天在座的各位，有没有之前了解过服务网格的，请举手。（备注：调查结果，现场数百人仅有3个人举手）&lt;/p&gt;
&lt;p&gt;既然大家都不了解，那我来给大家介绍。首先，什么是Service  Mesh？然后给大家讲一下Service Mesh的演进历程，以及为什么选择Service Mesh以及为什么我将它称之为&lt;strong&gt;下一代的微服务&lt;/strong&gt;，这是我们今天的内容。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-4_hu8c01221b1072ae8844c2a194079ef2cb_36112_e31c09de58eb6d808ca84f61696d22b2.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-4_hu8c01221b1072ae8844c2a194079ef2cb_36112_dcfbff0257653d3a45e79f72038e0ce0.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-4_hu8c01221b1072ae8844c2a194079ef2cb_36112_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-4_hu8c01221b1072ae8844c2a194079ef2cb_36112_e31c09de58eb6d808ca84f61696d22b2.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-5_hub6d629ceb7905f6a86c0e0905af87d9a_160942_1de2d07cdaa4fb03abcaf74ca66d06ae.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-5_hub6d629ceb7905f6a86c0e0905af87d9a_160942_2efc9c4b624458e9c57bb317656ed890.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-5_hub6d629ceb7905f6a86c0e0905af87d9a_160942_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-5_hub6d629ceb7905f6a86c0e0905af87d9a_160942_1de2d07cdaa4fb03abcaf74ca66d06ae.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们首先说一下Service Mesh这个词，这确实是一个非常非常新的名词，像刚才调查的，大部分的同学都没听过。&lt;/p&gt;
&lt;p&gt;这个词最早使用由开发Linkerd的Buoyant公司提出，并在内部使用。2016年9月29日第一次公开使用这个术语。2017年的时候随着Linkerd的传入，Service  Mesh进入国内技术社区的视野。最早翻译为“服务啮合层”，这个词比较拗口。用了几个月之后改成了服务网格。后面我会给大家介绍为什么叫网格。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-6_hu959f71cabb1666b20fd9db1ff57a5d77_144117_752efa446c2331e5fe9afef0010ba081.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-6_hu959f71cabb1666b20fd9db1ff57a5d77_144117_a46b25e1741376e2dc1bb96e5e378f71.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-6_hu959f71cabb1666b20fd9db1ff57a5d77_144117_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-6_hu959f71cabb1666b20fd9db1ff57a5d77_144117_752efa446c2331e5fe9afef0010ba081.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;先看一下Service Mesh的定义，这个定义是由Linkerd的CEO William给出来的。Linkerd是业界第一个Service Mesh，也是他们创造了Service Mesh这个词汇的，所以这个定义比较官方和权威。&lt;/p&gt;
&lt;p&gt;我们看一下中文翻译，首先服务网格是一个基础设施层，功能在于处理服务间通信，职责是负责实现请求的可靠传递。在实践中，服务网格通常实现为轻量级网络代理，通常与应用程序部署在一起，但是对应用程序透明。&lt;/p&gt;
&lt;p&gt;这个定义直接看文字大家可能会觉得比较空洞，不太容易理解到底是什么。我们来看点具体的东西。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-7_hu7f0096ba1ad04e29cde3faaa37521536_105471_894a39c6ee232bdcc074d2dcae3626b0.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-7_hu7f0096ba1ad04e29cde3faaa37521536_105471_9da3a255def91cd01e683dcf35873d15.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-7_hu7f0096ba1ad04e29cde3faaa37521536_105471_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-7_hu7f0096ba1ad04e29cde3faaa37521536_105471_894a39c6ee232bdcc074d2dcae3626b0.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Service Mesh的部署模型，先看单个的，对于一个简单请求，作为请求发起者的客户端应用实例，会首先用简单方式将请求发送到本地的Service Mesh实例。这是两个独立进程，他们之间是远程调用。&lt;/p&gt;
&lt;p&gt;Service Mesh会完成完整的服务间调用流程，如服务发现负载均衡，最后将请求发送给目标服务。这表现为Sidecar。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-8_hu1103fbddc50cb88e27d058eae70a6adb_108719_5bddaac61a546e978302b8eb0c4fc716.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-8_hu1103fbddc50cb88e27d058eae70a6adb_108719_7cc25a1e7d20b1ee40be204d300aa367.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-8_hu1103fbddc50cb88e27d058eae70a6adb_108719_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-8_hu1103fbddc50cb88e27d058eae70a6adb_108719_5bddaac61a546e978302b8eb0c4fc716.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Sidecar这个词中文翻译为边车，或者车斗，也有一个乡土气息浓重的翻译叫做边三轮。Sidecar这个东西出现的时间挺长的，它在原有的客户端和服务端之间加多了一个代理。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-9_hu7f0096ba1ad04e29cde3faaa37521536_111902_7adb7d98665c5de85a9b94db4ceb6954.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-9_hu7f0096ba1ad04e29cde3faaa37521536_111902_8cab5fe413fcb8b7a4cc22bccdba5880.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-9_hu7f0096ba1ad04e29cde3faaa37521536_111902_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-9_hu7f0096ba1ad04e29cde3faaa37521536_111902_7adb7d98665c5de85a9b94db4ceb6954.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;多个服务调用的情况，在这个图上我们可以看到Service Mesh在所有的服务的下面，这一层被称之为&lt;strong&gt;服务间通讯专用基础设施层&lt;/strong&gt;。Service Mesh会接管整个网络，把所有的请求在服务之间做转发。在这种情况下，我们会看到上面的服务不再负责传递请求的具体逻辑，只负责完成业务处理。服务间通讯的环节就从应用里面剥离出来，呈现出一个抽象层。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-10_hu7f0096ba1ad04e29cde3faaa37521536_126742_00216c64388eeede58fd5b8f90013271.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-10_hu7f0096ba1ad04e29cde3faaa37521536_126742_f6f4840e00577d570b10c1d5795bfa72.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-10_hu7f0096ba1ad04e29cde3faaa37521536_126742_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-10_hu7f0096ba1ad04e29cde3faaa37521536_126742_00216c64388eeede58fd5b8f90013271.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如果有大量的服务，就会表现出来网格。图中左边绿色方格是应用，右边蓝色的方框是Service Mesh，蓝色之间的线条是表示服务之间的调用关系。Sidecar之间的连接就会形成一个网络，这个就是服务网格名字的由来。这个时候代理体现出来的就和前面的sidecar不一样了，形成网状。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-11_huac7eaea011d0bbdf3a8a137603270ded_130070_7d41d5fdf29d5177816d51de5fe8c014.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-11_huac7eaea011d0bbdf3a8a137603270ded_130070_2c35ffa134a66b7c1bd22a35efe15df9.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-11_huac7eaea011d0bbdf3a8a137603270ded_130070_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-11_huac7eaea011d0bbdf3a8a137603270ded_130070_7d41d5fdf29d5177816d51de5fe8c014.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;再来回顾前面给出的定义，大家回头看这四个关键词。首先第一个，服务网格是抽象的，实际上是抽象出了一个基础设施层，在应用之外。其次，功能是实现请求的可靠传递。部署上体现为轻量级的网络代理。最后一个关键词是，对应用程序透明。&lt;/p&gt;
&lt;p&gt;大家注意看，上面的图中，网络在这种情况下，可能不是特别明显。但是如果把左边的应用程序去掉，现在只呈现出来Service Mesh和他们之间的调用，这个时候关系就会特别清晰，就是一个完整的网络。这是Service Mesh定义当中一个非常重要的关键点，和Sidecar不相同的地方：&lt;strong&gt;不再将代理视为单独的组件，而是强调由这些代理连接而形成的网络&lt;/strong&gt;。在Service  Mesh里面非常强调代理连接组成的网络，而不像sidecar那样看待个体。&lt;/p&gt;
&lt;p&gt;现在我们基本上把Service Mesh的定义介绍清楚了，大家应该可以大概了解什么是Service Mesh了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-12_hu8c01221b1072ae8844c2a194079ef2cb_39409_ce8b942cf901614e2d428c5da314ae4e.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-12_hu8c01221b1072ae8844c2a194079ef2cb_39409_7fea11b830b1a33fca9862aaabe55936.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-12_hu8c01221b1072ae8844c2a194079ef2cb_39409_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-12_hu8c01221b1072ae8844c2a194079ef2cb_39409_ce8b942cf901614e2d428c5da314ae4e.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第二个部分和大家追溯一下Service Mesh的演进历程。要注意，虽然Service Mesh这个词汇直到2016年9才有，但是它表述的东西很早以前就出现了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-13_huc5c50923cd72b19afdd4a735657820ea_142654_c751b5517ab4268a93fc52204470d4bd.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-13_huc5c50923cd72b19afdd4a735657820ea_142654_fffdbb9485637454ee973af11196611d.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-13_huc5c50923cd72b19afdd4a735657820ea_142654_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-13_huc5c50923cd72b19afdd4a735657820ea_142654_c751b5517ab4268a93fc52204470d4bd.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;首先看“远古时代”，第一代网络计算机系统，最早的时候开发人员需要在自己的代码里处理网络通讯的细节问题，比如说数据包顺序、流量控制等等，导致网络逻辑和业务逻辑混杂在一起，这样是不行的。接下来出现了TCP/IP技术，解决了流量控制问题，从右边的图上可以看到，功能其实没发生变化：所有的功能都在，代码还是要写。但是，最重要的事情，流程控制，已经从应用程序里面抽出来了。对比左右两边的图，抽出来之后被做成了操作系统网络层的一部分，这就是TCP/IP，这样的话应用的结构就简单了。&lt;/p&gt;
&lt;p&gt;现在写应有，就不用考虑网卡到底怎么发。在TCP/IP之后，这是完全不需要考虑的。上面说的是非常遥远的事情，大概发生在五十年前。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-14_huc5c50923cd72b19afdd4a735657820ea_141898_d82b2f3ac7fb922a2d6750249af21545.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-14_huc5c50923cd72b19afdd4a735657820ea_141898_5a1cbd813fad9e17ad748cb5feaea7e0.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-14_huc5c50923cd72b19afdd4a735657820ea_141898_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-14_huc5c50923cd72b19afdd4a735657820ea_141898_d82b2f3ac7fb922a2d6750249af21545.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;微服务时代也面临着类似的一些东西，比如说我们在做微服务的时候要处理一系列的比较基础的事情，比如说常见的服务注册、服务发现，在得到服务器实例之后做负载均衡，为了保护服务器要熔断/重试等等。这些功能所有的微服务都跑不掉，那怎么办呢？只能写代码，把所有的功能写进来。我们发现最早的微服务又和刚才一样，应用程序里面又加上了大量的非功能性的代码。为了简化开发，我们开始使用类库，比如说典型的Netflix OSS套件。在把这些事情做好以后，开发人员的编码问题就解决了：只需要写少量代码，就可以把这些功能实现。因为这个原因，最近这些年大家看到Java社区Spring Cloud的普及程度非常快，几乎成为了微服务的代名词。&lt;/p&gt;
&lt;p&gt;到了这个地步之后，完美了吗？当然，如果真的完美了，那我今天就不会站在这里了:)&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-15_hu5cf22476bfd188e22b1cd737e995c49a_101039_7425a72542717b6997e395ebd7991e47.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-15_hu5cf22476bfd188e22b1cd737e995c49a_101039_32e4d39b300f65503eaeb0d0b7d49062.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-15_hu5cf22476bfd188e22b1cd737e995c49a_101039_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-15_hu5cf22476bfd188e22b1cd737e995c49a_101039_7425a72542717b6997e395ebd7991e47.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们看这几个被称之为痛点的东西:内容比较多，门槛比较高。调查一下，大家学Spring Cloud，到你能熟练掌握，并且在产品当中应用，可以解决出现的问题，需要多长时间？一个星期够不够？大部分人一个星期是不够的，大部分人需要三到六个月。因为你在真实落地时会遇到各种问题，要能自己解决的话，需要的时间是比较长的。这里是Spring Cloud的常见子项目，只列出了最常见的部分，其中spring cloud netflix下还有netflix OSS套件的很多内容。要真正吃透Spring Cloud，需要把这些东西全部吃透，否则遇到问题时还会非常难受。&lt;/p&gt;
&lt;p&gt;这么多东西，在座的各位相对来说学习能力比较强一点，可能一个月就搞定了，但是问题是你的开发团队，尤其是业务开发团队需要多久，这是一个很要命的事情：业务团队往往有很多比较初级的同事。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-16_huee50a8ae0d6a567d165a69262ceef860_125557_15bc9c769a6bc11ed29748cffcb66b80.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-16_huee50a8ae0d6a567d165a69262ceef860_125557_3b5d9e9a57f539b8c78a50191e008dd1.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-16_huee50a8ae0d6a567d165a69262ceef860_125557_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-16_huee50a8ae0d6a567d165a69262ceef860_125557_15bc9c769a6bc11ed29748cffcb66b80.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;然后事情并不止这么简单，所谓雪上加霜，我们还不得不面对一堆现实。&lt;/p&gt;
&lt;p&gt;比如说，我们的业务开发团队的强项是什么？最强的会是技术吗？不，通常来说我们的业务开发团队最强的是对业务的理解，是对整个业务体系的熟悉程度。&lt;/p&gt;
&lt;p&gt;第二个事情，业务应用的核心价值是什么？我们辛辛苦苦写了这么多的微服务，难道是为了实现微服务吗？微服务只是我们的手段，我们最终需要实现的是业务，这是我们真正的目标。&lt;/p&gt;
&lt;p&gt;第三个事情是，就微服务这个手段而言，有比学习微服务框架更艰巨的挑战。在做微服务的真正落地时，会有更深刻的理解。比如微服务的拆分，比如要设计一个良好的API，要保持稳定并且易于扩展，还有如果涉及到跨多个服务的数据一致性，大部分团队都会头疼。最后是康威定律，但凡做服务的同学最终都会遇到这个终极问题，而大多数情况下是欲哭无泪。&lt;/p&gt;
&lt;p&gt;但是这些还没完，比你写一个新的微服务系统更痛苦的事情，是你要对旧有的系统进行微服务改造。&lt;/p&gt;
&lt;p&gt;所有这些加在一起，还不够，还要再加一条，这条更要命：业务开发团队往往业务压力非常大，时间人力永远不足。说下月上线就是下月上线，说双十一促销就不会推到双十二。老板是不会管你有没有时间学习spring cloud的，也不会管你的业务团队能否搞得定微服务的方方面面。&lt;strong&gt;业务永远看的是结果&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-17_hu26c433cabd4c9b3fb16c3cd0c73f6842_108612_d211ed2f62dbe7f04567edf8456a1245.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-17_hu26c433cabd4c9b3fb16c3cd0c73f6842_108612_86eb49dc4a7d2535d468c9d54224b9ba.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-17_hu26c433cabd4c9b3fb16c3cd0c73f6842_108612_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-17_hu26c433cabd4c9b3fb16c3cd0c73f6842_108612_d211ed2f62dbe7f04567edf8456a1245.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第二个痛点，功能不够，这里列出了服务治理的常见功能。而Spring Cloud的治理功能是不够强大的，如果把这些功能一一应对做好，靠Spring Cloud直接提供的功能是远远不够的。很多功能都需要你在Spring Cloud的基础上自己解决。&lt;/p&gt;
&lt;p&gt;问题是你打算投入多少时间人力资源来做这个事情。有些人说我大不了有些功能我不做了，比如灰度，直接上线好了，但是这样做代价蛮高的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-18_hu78b2d297c4447f2d6005267375dbb2f4_129831_c27299e68bc01649203b16ddd708b3bc.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-18_hu78b2d297c4447f2d6005267375dbb2f4_129831_0635f98116ecc6cf2eb5107abd3c7528.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-18_hu78b2d297c4447f2d6005267375dbb2f4_129831_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-18_hu78b2d297c4447f2d6005267375dbb2f4_129831_c27299e68bc01649203b16ddd708b3bc.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第三个痛点，跨语言。微服务在刚开始面世的时候，承诺了一个很重要的特性：就是不同的微服务可以采用自己最擅长最喜欢的最适合的编程语言来编写，这个承诺只能说有一半是OK的，但是另外一半是不行的，是假的。因为你实现的时候，通常来说是基于一个类库或者框架来实现的，一旦开始用具体编程语言开始编码的时候你就会发现，好像不对了。为什么？左边是我从编程语言排行列表列出来的主流编程语言，排在前面的几种，大家比较熟悉.后面还有几十种没有列出来，中间是新兴的编程语言，比较小众一点。&lt;/p&gt;
&lt;p&gt;现在的问题在于&lt;strong&gt;我们到底要为多少种语言提供类库和框架&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这个问题非常尖锐，为了解决这个问题，通常只有两条路可选：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;一种就是统一编程语言，全公司就用一种编程语言&lt;/li&gt;
&lt;li&gt;另外一个选择，是有多少种编程语言就写多少个类库&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;我相信在座的如果有做基础架构的同学，就一定遇到过这个问题。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-19_hu17a4d484ffe75be91b12ca18fa8bf6c0_100132_60bbb0c8792f3f1f304ad90d194bda3c.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-19_hu17a4d484ffe75be91b12ca18fa8bf6c0_100132_46e351d7f383c19283d8c704f1c56bc8.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-19_hu17a4d484ffe75be91b12ca18fa8bf6c0_100132_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-19_hu17a4d484ffe75be91b12ca18fa8bf6c0_100132_60bbb0c8792f3f1f304ad90d194bda3c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;但是问题还没完，框架写好了，也有能够把各个语言都写一份。但是接下来会有第四个痛点：版本升级。&lt;/p&gt;
&lt;p&gt;你的框架不可能一开始就完美无缺，所有功能都齐备，没有任何BUG，分发出去之后就再也不需要改动，这种理想状态不存在的。必然是1.0、2.0、3.0慢慢升级，功能逐渐增加，BUG逐渐被修复。但是分发给使用者之后，使用者会不会立马升级？实际上做不到的。&lt;/p&gt;
&lt;p&gt;这种情况下怎么办，会出现客户端和服务器端版本不一致，就要非常小心维护兼容性，然后尽量督促你的使用者：我都是3.0了，你别用1.0了，你赶紧升级吧。但是如果如果他不升级，你就继续忍着，然后努力解决你的版本兼容性。&lt;/p&gt;
&lt;p&gt;版本兼容性有多复杂？服务端数以百计起，客户端数以千计起，每个的版本都有可能不同。这是一个笛卡尔乘积。但是别忘了，还有一个前面说的编程语言的问题，你还得再乘个N！&lt;/p&gt;
&lt;p&gt;设想一下框架的Java1.0客户端访问node.js的3.0的服务器端会发生什么事情，c++的2.0客户端访问golang的1.0服务器端会如何？你想把所有的兼容性测试都做一遍吗？这种情况下你的兼容性测试需要写多少个case，这几乎是不可能的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-20_hue55b056304dd7f81d2a619f08754d2f9_85201_f8b74ca482e2cc13c13da3822bf8f0e0.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-20_hue55b056304dd7f81d2a619f08754d2f9_85201_cc8ab5c4ea0a716fe6a5e2d41d070951.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-20_hue55b056304dd7f81d2a619f08754d2f9_85201_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-20_hue55b056304dd7f81d2a619f08754d2f9_85201_f8b74ca482e2cc13c13da3822bf8f0e0.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;那怎么办？怎么解决这些问题，这是现实存在的问题，总是要面对的。&lt;/p&gt;
&lt;p&gt;我们来想一想：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;第一个是这些问题的根源在哪里：我们做了这么多痛苦的事情，面临这么多问题，这些多艰巨的挑战，这些和服务本身有关系吗？比如写一个用户服务，对用户做CRUD操作，和刚才说的这些东西有一毛钱关系吗？发现有个地方不对，这些和服务本身没关系，而是服务间的通讯，这才是我们需要解决的问题。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后看一下我们的目标是什么。我们前面所有的努力，其实都是为了保证将客户端发出的业务请求，发去一个正确的地方。什么是正确的地方？比如说有版本上的差异，应该去2.0版本，还是去1.0版本，需要用什么样的负载均衡，要不要做灰度。最终这些考虑，都是让请求去一个你需要的正确的地方。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;第三个，事情的本质。整个过程当中，这个请求是从来不发生更改的。比如我们前面说的用户服务，对用户做CRUD，不管请求怎么走，业务语义不会发生变化。这是事情的本质，是不发生变化的东西。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;这个问题具有一个高度的普适性：所有的语言，所有的框架，所有的组织，这些问题对于任何一个微服务都是相同的。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;讲到这里，大家应该有感觉了：这个问题是不是和哪个问题特别像？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-21_hu81b263ffa1d1e77975428398873bac66_85476_d67872b7d6fc569ffb46a81a0ab3f552.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-21_hu81b263ffa1d1e77975428398873bac66_85476_8d54266d8f420967be4daeb36f8f23ae.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-21_hu81b263ffa1d1e77975428398873bac66_85476_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-21_hu81b263ffa1d1e77975428398873bac66_85476_d67872b7d6fc569ffb46a81a0ab3f552.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;五十年前的前辈们，他们要解决的问题是什么？为什么会出现TCP，TCP解决了什么问题？又是怎么解决的？&lt;/p&gt;
&lt;p&gt;TCP解决的问题和这个很像，都是要将请求发去一个正确的地方。所有的网络通讯，只要用到TCP协议，这四个点都是一致的。&lt;/p&gt;
&lt;p&gt;有了TCP之后会发生什么? 我们有了TCP之后，我们基于TCP来开发我们的应用，我们的应用需要做什么事情? 我们的应用需要关心TCP层下链路层的实现吗？不需要。同理，我们基于HTTP开发应用时，应用需要关心TCP层吗？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-22_hud71905a3e2112a53c76a2f9a0c3112ae_76065_de2b47d40ad21869cdbc59abcc4c9457.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-22_hud71905a3e2112a53c76a2f9a0c3112ae_76065_e37a2e0264431146d587dacaf71a6813.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-22_hud71905a3e2112a53c76a2f9a0c3112ae_76065_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-22_hud71905a3e2112a53c76a2f9a0c3112ae_76065_de2b47d40ad21869cdbc59abcc4c9457.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;为什么我们开发微服务应用的时候就要这么关心服务的通讯层？我们把服务通讯层所有的事情学一遍，做一遍，我们做这么多是为什么？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-23_huc5c50923cd72b19afdd4a735657820ea_121220_9e9ddfccf54ba4bd4d1ae36b842ff8a0.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-23_huc5c50923cd72b19afdd4a735657820ea_121220_9a9f90e315dc04f337a7986b245ed62d.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-23_huc5c50923cd72b19afdd4a735657820ea_121220_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-23_huc5c50923cd72b19afdd4a735657820ea_121220_9e9ddfccf54ba4bd4d1ae36b842ff8a0.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这种情况下，自然产生了另外一个想法：既然我们可以把网络访问的技术栈向下移为TCP，我们是可以也有类似的，把微服务的技术栈向下移？&lt;/p&gt;
&lt;p&gt;最理想的状态，就是我们在网络协议层中，增加一个微服务层来完成这个事情。但是因为标准问题，所以现在没有实现，暂时这个东西应该不太现实，当然也许未来可能出现微服务的网络层。&lt;/p&gt;
&lt;p&gt;之前有一些先驱者，尝试过使用代理的方案，常见的nginx，haproxy，apache等代理。这些代码和微服务关系不大，但是提供了一个思路：在服务器端和客户端之间插入了一个东西完成功能，避免两者直接通讯。当然代理的功能非常简陋，开发者一看，想法不错，但是功能不够，怎么办？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-24_huc5c50923cd72b19afdd4a735657820ea_115437_1e8fadb5270788b8243e0f8fc8ae65b2.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-24_huc5c50923cd72b19afdd4a735657820ea_115437_bf9bf61e6a1aa6503022dbe5ea1c6847.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-24_huc5c50923cd72b19afdd4a735657820ea_115437_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-24_huc5c50923cd72b19afdd4a735657820ea_115437_1e8fadb5270788b8243e0f8fc8ae65b2.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这种情况下，第一代的Sidecar出现了，Sidecar扮演的角色和代理很像，但是功能就齐全很多，基本上原来微服务框架在客户端实现的功能都会对应实现。&lt;/p&gt;
&lt;p&gt;第一代的sidecar主要是列出来的这几家公司，其中最有名气的还是netflix。&lt;/p&gt;
&lt;p&gt;在这个地方我们额外提一下，注意第四个，前面三个功能都是国外的公司，但是其实sidecar这个东西并不是只有国外的人在玩，国内也有厂商和公司在做类似的事情。比如唯品会，我当年在唯品会基础架构部工作的时候，在2015年上半年，我们的OSP服务化框架做了一个重大架构调整，加入了一个名为local proxy的Sidecar。注意这个时间是2015上半年，和国外差不多。相信国内肯定还有类似的产品存在，只是不为外界所知。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-25_hu8286840fd9409807339abe824e918fa3_103346_9127a26d61df05cb453d75bd1904892c.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-25_hu8286840fd9409807339abe824e918fa3_103346_dc6e86bd960353715b8840637a43b208.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-25_hu8286840fd9409807339abe824e918fa3_103346_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-25_hu8286840fd9409807339abe824e918fa3_103346_9127a26d61df05cb453d75bd1904892c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这个时期的Sidecar是有局限性的，都是&lt;strong&gt;为特定的基础设施而设计&lt;/strong&gt;，通常是和当时开发Sidecar的公司自己的基础设施和框架直接绑定的，在原有体系上搭出来的。这里面会有很多限制，一个最大的麻烦是无法通用：没办法拆出来给别人用。比如Airbnb的一定要用到zookeeper，netflix的一定要用eureka，唯品会的local proxy是绑死在osp框架和其他基础设施上的。&lt;/p&gt;
&lt;p&gt;之所以出现这些绑定，主要原因还是和这些sidecar出现的动机有关。比如netflix是为了让非JVM语言应用接入到Netflix OSS中，soundcloud是为了让遗留的Ruby应用可以使用到JVM的基础设置。而当年我们唯品会的OSP框架，local proxy是为了解决非Java语言接入，还有前面提到的业务部门不愿意升级的问题。这些问题都比较令人头疼的，但是又不得不解决，因为逼的憋出来sidecar这个一个解决方式。&lt;/p&gt;
&lt;p&gt;因为有这样的特殊的背景和需求，所以导致第一代的Sidecar无法通用，因为它本来就是做在原有体系之上的。虽然不能单独拿出来，但是在原有体系里面还是可以很好工作的，因此也没有动力做剥离。导致虽然之前有很多公司有Sidecar这个东西，但是其实一直没怎么流传出来，因为即使出来以后别人也用不上。&lt;/p&gt;
&lt;p&gt;这里提一个事情，在2015年年中的时候，我们当时曾经有一个想法，将Local proxy从OSP剥离，改造为通用的Sidecar。计划支持HTTH1.1，操作http header就可以，body对我们是可以视为透明的，这样就容易实现通用了。可惜因为优先级等原因未能实现，主要是有大量的其他工作比如各种业务改造，这个事情必要性不够。&lt;/p&gt;
&lt;p&gt;所有比较遗憾，当时我们有这个想法没做实现，这是在2015年，时间点非常早的了。如果当时有实现，很可能我们就自己折腾出业界第一个service mesh出来了。现在想想挺遗憾的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-26_huc5c50923cd72b19afdd4a735657820ea_97718_7981c6a5ff97ff757601e30a227ea003.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-26_huc5c50923cd72b19afdd4a735657820ea_97718_d573f8195366c18df990a44f6980e445.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-26_huc5c50923cd72b19afdd4a735657820ea_97718_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-26_huc5c50923cd72b19afdd4a735657820ea_97718_7981c6a5ff97ff757601e30a227ea003.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;但是，不只有我们会有这想法。还有有一些人想法和我们差不多，但是比较幸运的是，他们有机会把东西做出来了。这就是第一代的Service Mesh，通用性的sidecar。&lt;/p&gt;
&lt;p&gt;通用型的Service Mesh的出现，左边第一个Linkerd是业界第一个Service Mesh，也就是它创造了Service Mesh这个词。时间点：2016年1月15号，0.0.7发布，这是github上看到的最早的一个版本，其实这个版本离我们当时的有想法的时间点非常近。然后是1.0版本，2017年4月份发布，离现在六个月。所以说，Service Mesh是一个非常新的名词，大家没听过非常正常。&lt;/p&gt;
&lt;p&gt;接下来是Envoy，2016年发布的1.0版本。&lt;/p&gt;
&lt;p&gt;这里面要特别强调，Linkerd和Envoy都加入了CNCF，Linkerd在今年1月份，而Envoy进入的时间是9月份，离现在也才1个月。在座的各位应该都明白CNCF在Cloud Native领域是什么江湖地位吧？可以说CNCF在Cloud Native的地位，就跟二战后联合国在国际秩序中的地位一样。&lt;/p&gt;
&lt;p&gt;之后出现了第三个Service Mesh，nginmesh，来自于大家熟悉的nginx，2017年9月发布了第一个版本。因为实在太新，还在刚起步，没什么可以特别介绍的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-27_hu073cfa9b61fcb437f09c5d156c356614_122062_ccebba363bc6e40448bd0c8465dc35e8.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-27_hu073cfa9b61fcb437f09c5d156c356614_122062_87bef8edb17da0c4ab7aca6dd23d0647.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-27_hu073cfa9b61fcb437f09c5d156c356614_122062_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-27_hu073cfa9b61fcb437f09c5d156c356614_122062_ccebba363bc6e40448bd0c8465dc35e8.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们来看一下Service  Mesh和Sidecar的差异，前面两点是已经提到了：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;首先Service Mesh不再视为单独的组件，而是强调连接形成的网络&lt;/li&gt;
&lt;li&gt;第二Service Mesh是一个通用组件&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;然后要强调的是第三点，Sidecar是可选的，容许直连。通常在开发框架中，原生语言的客户端喜欢选择直连，其他语言选择走sidecar。比如java写的框架，java客户端直连，php客户端走sidecar。但是也可以都选择走sidecar，比如唯品会的OSP就是所有语言都走local proxy。在sidecar中也是可选的。但是，Service Mesh会要求完全掌控所有流量，也就是所有的请求都必须通过service mesh。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-28_huc5c50923cd72b19afdd4a735657820ea_115479_5defee30f37c7a602e956bafe2e05948.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-28_huc5c50923cd72b19afdd4a735657820ea_115479_94607f460b64f26b50037ce724a27d7f.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-28_huc5c50923cd72b19afdd4a735657820ea_115479_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-28_huc5c50923cd72b19afdd4a735657820ea_115479_5defee30f37c7a602e956bafe2e05948.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;接下来给大家介绍Istio，这个东西我给它的评价是&lt;strong&gt;王者风范&lt;/strong&gt;，来自于谷歌、IBM和Lyft，是Service  Mesh的集大成者。&lt;/p&gt;
&lt;p&gt;大家看它的图标，就是一个帆船。Istio是希腊语，英文语义是&amp;quot;sail&amp;quot;, 翻译过来是起航的意思。大家看这个名字和图标有什么联想？google在云时代的另外一个现象级产品，K8S，kubernete也同样起源于希腊语，船长，驾驶员或者舵手，图标是一个舵。&lt;/p&gt;
&lt;p&gt;istio名字和图标与k8s可以说是一脉相承的。这个东西在2017年5月份发布了0.1，就在两周前的10月4号发布了0.2。大家都熟悉软件开发，应该明白0.1/0.2在软件迭代中是什么阶段。0.1大概相当于婴儿刚刚出世，0.2还没断奶。但是，即使在这么早期的版本中，我对他的评价已经是集大成者，王者风范，为什么？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-29_huddfd1b56a9efab2b964e97dfde815108_160654_61c3075a5ea0ad90ab869b2c4385633b.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-29_huddfd1b56a9efab2b964e97dfde815108_160654_61b8e3c48bd86d03ffb8d096532f44e3.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-29_huddfd1b56a9efab2b964e97dfde815108_160654_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-29_huddfd1b56a9efab2b964e97dfde815108_160654_61c3075a5ea0ad90ab869b2c4385633b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;为什么说Istio王者风范？最重要的是他为Service Mesh带来了前所未有的控制力。以Sidecar方式部署的Service Mesh控制了服务间所有的流量，只要能够控制Service Mesh就能够控制所有的流量，也就可以控制系统中的所有请求。为此Istio带来了一个集中式的控制面板，让你实现控制。&lt;/p&gt;
&lt;p&gt;左边是单个视图，在sidecar上增加了控制面板来控制sidecar。这个图还不是特别明显，看右边这个图，当有大量服务时，这个服务面板的感觉就更清晰一些。在整个网络里面，所有的流量都在Service Mesh的控制当中，所有的Service Mesh都在控制面板控制当中。可以通过控制面板控制整个系统，这是Istio带来的最大的革新。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-30_hua90bd5152d0e19eb73f08c466accedf1_139587_533a89027d96c4258316bed7ec13d641.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-30_hua90bd5152d0e19eb73f08c466accedf1_139587_a811a0ab4fdfa846ff0a479984739654.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-30_hua90bd5152d0e19eb73f08c466accedf1_139587_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-30_hua90bd5152d0e19eb73f08c466accedf1_139587_533a89027d96c4258316bed7ec13d641.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Istio由三个公司开发，前两个比较可怕，谷歌和IBM，而且都是云平台，谷歌的云平台，IBM的云平台，尤其GCP的大名想必大家都知道。所谓出身名门，大概指的就是这个样子吧？&lt;/p&gt;
&lt;p&gt;Istio的实力非常强，我这里给了很多的赞誉：设计理念非常新颖前卫，有创意，有魄力，有追求，有格局。Istio的团队实力也非常惊人，大家有空可以去看看istio的委员会名单感受一下。Istio也是google的新的重量级的产品，很有可能成为下一个现象级的产品。Google现在的现象级产品是什么？K8s。而Istio很有可能成为下一个K8S级别的产品。&lt;/p&gt;
&lt;p&gt;说到应时而生，什么是势？我们今天所在的是什么时代？是互联网技术大规模普及的时代，是微服务容器如日中天的时代，是Cloud Native大势已成的时代。也是传统企业进行互联网转型的时代，今天的企业用户都想转型，这个大势非常明显，大家都在转或者准备转，但是先天不足。什么叫先天不足？没基因，没能力，没经验，没人才，而且面临我们前面说的所有的痛点。所有说Istio现在出现，时机非常合适。别忘了istio身后还有CNCF的背景，已经即将一统江湖的k8s。&lt;/p&gt;
&lt;p&gt;istio在发布之后，社区响应积极，所谓应者云集。其中作为市面上仅有的几个Service Mesh之一的Envoy，甘心为istio做底层，而另外两个实现Linkerd/nginmesh也直接放弃和istio的对抗，选择合作，积极和istio做集成。社区中的一众大佬，如这里列出来的，都在第一时间响应，要和istio做集成或者基于istio做自己的产品。为什么说是第一时间？istio出0.1版本，他们就直接表明态度开始战队了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-31_huc5a436dd846bdf1d5aec0eb89381d4eb_164904_ea41ea39ac909a470b0f41b981da6f6f.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-31_huc5a436dd846bdf1d5aec0eb89381d4eb_164904_de87cbe135f3da8546c7754577a716c4.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-31_huc5a436dd846bdf1d5aec0eb89381d4eb_164904_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-31_huc5a436dd846bdf1d5aec0eb89381d4eb_164904_ea41ea39ac909a470b0f41b981da6f6f.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Istio的架构，主要分为两大块。下面的数据面板，是给传统service mesh的，目前是Envoy，但是我们前面也提到linkerd和nginmesh都在和istio做集成，指的就是替代Envoy做数据面板。&lt;/p&gt;
&lt;p&gt;另外一大块就是上面的控制面板，这是istio真正带来的内容。主要分成三大块，图中我列出了他们各自的职责和可以实现的功能。&lt;/p&gt;
&lt;p&gt;因为时间有限，不在今天具体展开。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-32_hu1ecd4cfb8bc3ac1faf49516682181b15_67570_f8ff12d9a97a43c562060014653f79e9.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-32_hu1ecd4cfb8bc3ac1faf49516682181b15_67570_4696e00ea3fb3168a9a74f5295ecce58.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-32_hu1ecd4cfb8bc3ac1faf49516682181b15_67570_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-32_hu1ecd4cfb8bc3ac1faf49516682181b15_67570_f8ff12d9a97a43c562060014653f79e9.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里给大家留一个地址，是我之前做的一次线上分享，对Istio的详细介绍，内容比较多，大家看看仔细看看。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzA3MDg4Nzc2NQ==&amp;amp;mid=2652136078&amp;amp;idx=1&amp;amp;sn=b261631ffe4df0638c448b0c71497021&amp;amp;chksm=84d532b4b3a2bba2c1ed22a62f4845eb9b6f70f92ad9506036200f84220d9af2e28639a22045&amp;amp;mpshare=1&amp;amp;scene=1&amp;amp;srcid=0922JYb4MpqpQCauaT9B4Xrx&amp;amp;pass_ticket=DQ%2B13yxFroDiLJgSF3xOEOhvowBRom2sE4accBhVABdFMCE9q3EC/FqN6fLNDggP#rd&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;万字解读:Service Mesh服务网格新生代&amp;ndash;Istio&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然后我们还组织了一个service mesh的技术社区，对istio的文档进行了翻译。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://istio.doczh.cn/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Istio官方文档中文翻译&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-33_hub21a6c9d7c5782a14625b11dd8004b6b_142701_96e33fa4b1b661b27641fcd714b0ed0a.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-33_hub21a6c9d7c5782a14625b11dd8004b6b_142701_1353d9a3dae92f74a35631e9d6a1ae8c.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-33_hub21a6c9d7c5782a14625b11dd8004b6b_142701_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-33_hub21a6c9d7c5782a14625b11dd8004b6b_142701_96e33fa4b1b661b27641fcd714b0ed0a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;总结一下，service mesh这是一步一步过来的: 从原始的代理，到限制很多的Sidecar，再到通用性的Service  Mesh，然后到加强管理功能的Istio，在未来成为下一代的微服务。&lt;/p&gt;
&lt;p&gt;注意，离service mesh这个词汇出现的时间点，也才一年。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-34_hu8c01221b1072ae8844c2a194079ef2cb_38572_02ee6d05d2ffa460071280959e5fc08e.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-34_hu8c01221b1072ae8844c2a194079ef2cb_38572_8b83492c97fbacd3bf0b8e222786a960.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-34_hu8c01221b1072ae8844c2a194079ef2cb_38572_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-34_hu8c01221b1072ae8844c2a194079ef2cb_38572_02ee6d05d2ffa460071280959e5fc08e.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-35_hu459d952c1e32780809deadf3d12876c6_122252_c99b88cc600152a93bb8e846647c9e88.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-35_hu459d952c1e32780809deadf3d12876c6_122252_caa5224361c6a3d290847c061936b236.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-35_hu459d952c1e32780809deadf3d12876c6_122252_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-35_hu459d952c1e32780809deadf3d12876c6_122252_c99b88cc600152a93bb8e846647c9e88.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;前面三个痛点都被解决了，有了Service Mesh之后这些问题都不是问题了。升级的痛点怎么解决？Service Mesh是一个独立进程，可单独升级，而应用程序不用改。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-36_hu459d952c1e32780809deadf3d12876c6_98439_4948a17034d4af58adceafd8d0944bc3.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-36_hu459d952c1e32780809deadf3d12876c6_98439_60e3b8a71528f24996753aca2de2caf6.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-36_hu459d952c1e32780809deadf3d12876c6_98439_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-36_hu459d952c1e32780809deadf3d12876c6_98439_4948a17034d4af58adceafd8d0944bc3.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;service mesh是以远程调用的方式让客户端接入，只要能发出请求，简单发给service
mesh就可以。客户端极度简化，对于典型的rest请求，几乎所有的语言都有完善的支持。而服务器端只要做一个事情，服务注册。这样对于多语言的支持，就变得非常舒服了。现在终于可以真正的自由选择编程语言。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-37_hu6d9b116f8e1206037e8a67394d9a3dea_106717_7d7dcc4cffc292e27fce8eb5ac5c3268.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-37_hu6d9b116f8e1206037e8a67394d9a3dea_106717_62cd47d4da98550cd230dd16ce96a0c8.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-37_hu6d9b116f8e1206037e8a67394d9a3dea_106717_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-37_hu6d9b116f8e1206037e8a67394d9a3dea_106717_7d7dcc4cffc292e27fce8eb5ac5c3268.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里有一个奇迹，鱼与熊掌兼得：同时实现降低门槛，功能增加。有些信奉质量守恒的同学会感觉不科学，注意能同时实现这两个改进的原因，是把工作量最大最辛苦的事情都交给了Service  Mesh。而Service Mesh是通用的，可以反复重用的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-38_hu4ff5862683d4d91e3de5701920123341_101674_7a93aac6bd13fd58a7bdb38218469537.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-38_hu4ff5862683d4d91e3de5701920123341_101674_9be682db40964868f5ca363f25dd38d5.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-38_hu4ff5862683d4d91e3de5701920123341_101674_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-38_hu4ff5862683d4d91e3de5701920123341_101674_7a93aac6bd13fd58a7bdb38218469537.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Service mesh为业务开发团队带来的变革：降低入门门槛，提供稳定基座，帮助团队实现技术转型。最终达到的目的是，让业务开发团队从微服务实现的具体技术细节中解放出来，&lt;strong&gt;回归业务&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-39_hu4ff5862683d4d91e3de5701920123341_117664_97f67dfba068d0126bcecca47bd2ca2f.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-39_hu4ff5862683d4d91e3de5701920123341_117664_16dbc9b6b895211257c1384bad1a2ce7.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-39_hu4ff5862683d4d91e3de5701920123341_117664_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-39_hu4ff5862683d4d91e3de5701920123341_117664_97f67dfba068d0126bcecca47bd2ca2f.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;第二个变革，是对运维管理团队的强化，这里如果有做运维的同学，你们可以认真思考一下：如果有了service mesh，你们对系统的管理和控制力会有多大的？注意很多功能的实现已经不再和应用有关，都在移到service mesh中，而service mesh通常是在运维的掌控中。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-40_hu4ff5862683d4d91e3de5701920123341_126004_a2132365db15bce4b1fa9da7251aac9c.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-40_hu4ff5862683d4d91e3de5701920123341_126004_5b7ab008130743a2cd018a4a05b221f4.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-40_hu4ff5862683d4d91e3de5701920123341_126004_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-40_hu4ff5862683d4d91e3de5701920123341_126004_a2132365db15bce4b1fa9da7251aac9c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;service mesh对于新兴小众语言是极大的利好。对于新的语言来说，在和传统的主流编程语言竞争时，最痛苦的事情是什么？是生态，比如各种类库，各种框架。在微服务这个领域，新兴小众语言想和Java等比拼，非常的难：这是用自己的劣势对上别人的优势。而有了Service Mesh之后，小众语言就有机会避开这个弊端，再不用和Java比拼生态，而是充分发挥自己的语言特点，做自己最擅长的领域。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-41_hu26610c3510aaeb36a481dbd277e8f941_61245_37796f1651b8fec025255acedcc34511.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-41_hu26610c3510aaeb36a481dbd277e8f941_61245_80caeab46a21c98914e59e647bf02678.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-41_hu26610c3510aaeb36a481dbd277e8f941_61245_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-41_hu26610c3510aaeb36a481dbd277e8f941_61245_37796f1651b8fec025255acedcc34511.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-42_huc2760d3ec03e23a375429ed3b870c865_100412_d0cc8fb52da679726544ddb38ee77a8f.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-42_huc2760d3ec03e23a375429ed3b870c865_100412_4a8dee9386b2ae648c75b05aab9d399e.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-42_huc2760d3ec03e23a375429ed3b870c865_100412_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-42_huc2760d3ec03e23a375429ed3b870c865_100412_d0cc8fb52da679726544ddb38ee77a8f.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;今天的内容基本上到这儿了，最后给两个资料，这两个文章，一个是对Service Mesh的解释，一个是详细介绍Service Mesh的由来，大家如果回去之后可以详细看一下。尤其第二个文章，我的PPT援引了里面的很多图片。英文不是特别好的同学可以看一下中文翻译版本，作者翻译质量非常高。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-43_hu872ace900ea188bd71e35672615e9e55_109069_e06e65865ea00c6b11323d383ba4746e.webp 400w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-43_hu872ace900ea188bd71e35672615e9e55_109069_a00770f3460ac82ef51d8aad1459b616.webp 760w,
               /talk/201710-service-mesh-next-generation-microservice/images/ppt-43_hu872ace900ea188bd71e35672615e9e55_109069_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201710-service-mesh-next-generation-microservice/images/ppt-43_hu872ace900ea188bd71e35672615e9e55_109069_e06e65865ea00c6b11323d383ba4746e.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最后，我们拉了一个service mesh的技术社区，有一个微信群。主要是因为Service Mesh这个技术实在是太新了，就像刚才调查的只有三个同学之前有听过。所以现在我们遇到一个大的问题：我们想交流的时候找不到人。因此我们建立了这个群，如果大家愿意对Service Mesh技术有兴趣的话，可以直接加到群来。这是一个纯技术的群，只讨论技术的东西。&lt;/p&gt;
&lt;p&gt;然后我们的service mesh的技术社区目前正在准备中，不久将亮相，大家可以稍后关注。&lt;/p&gt;
&lt;p&gt;我们今天的内容就到这里结束，非常感谢大家！&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>服务网格新生代-Istio</title>
      <link>https://skyao.net/talk/201709-istio-introduction/</link>
      <pubDate>Thu, 21 Sep 2017 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/201709-istio-introduction/</guid>
      <description>&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/istio-introduction-thumbnail_hu66757395f3ac6177f686a1ecaba0f030_37063_45ee1021be83411c070b88405ea08923.webp 400w,
               /talk/201709-istio-introduction/images/istio-introduction-thumbnail_hu66757395f3ac6177f686a1ecaba0f030_37063_7b1599cf6e2bae90f291780943ef758d.webp 760w,
               /talk/201709-istio-introduction/images/istio-introduction-thumbnail_hu66757395f3ac6177f686a1ecaba0f030_37063_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/istio-introduction-thumbnail_hu66757395f3ac6177f686a1ecaba0f030_37063_45ee1021be83411c070b88405ea08923.webp&#34;
               width=&#34;458&#34;
               height=&#34;458&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h1 id=&#34;服务网格新生代-istio&#34;&gt;服务网格新生代-Istio&lt;/h1&gt;
&lt;p&gt;大家晚上好，欢迎参与直播，我是今天的讲师，来自数人云的资深架构师，敖小剑。&lt;/p&gt;
&lt;p&gt;相信大家进来前都有看到这次分享的介绍，今天的主角名叫 istio，我估计很多同学在此之前可能完全没有听过这个名字。请不必介意，没听过很正常，因为istio的确是一个非常新的东西，出世也才四个月而已。&lt;/p&gt;
&lt;p&gt;今天的内容将会分成三个部分:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;介绍： 让大家了解istio是什么，以及有什么好处，以及istio背后的开发团队&lt;/li&gt;
&lt;li&gt;架构： 介绍istio的整体架构和四个主要功能模块的具体功能，这块内容会比较偏技术&lt;/li&gt;
&lt;li&gt;展望： 介绍istio的后续开发计划，探讨未来的发展预期&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h1 id=&#34;介绍&#34;&gt;介绍&lt;/h1&gt;
&lt;h2 id=&#34;istio是什么&#34;&gt;istio是什么&lt;/h2&gt;
&lt;p&gt;istio是Google/IBM/Lyft联合开发的开源项目,2017年5月发布第一个release 0.1.0, 官方定义为:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Istio：一个连接，管理和保护微服务的开放平台。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;按照isito文档中给出的定义:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Istio提供一种简单的方式来建立已部署的服务的网络，具备负载均衡，服务到服务认证，监控等等功能，而&lt;strong&gt;不需要改动任何服务代码&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;简单的说，有了istio，你的服务就不再需要任何微服务开发框架（典型如spring cloud，dubbo），也不再需要自己动手实现各种复杂的服务治理的功能（很多是spring cloud和dubbo也不能提供的，需要自己动手）。只要服务的客户端和服务器可以进行简单的直接网络访问，就可以通过将网络层委托给istio，从而获得一系列的完备功能。&lt;/p&gt;
&lt;p&gt;可以近似的理解为：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;istio = 微服务框架 + 服务治理&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&#34;名字和图标&#34;&gt;名字和图标&lt;/h3&gt;
&lt;p&gt;Istio来自希腊语，英文意思是&amp;quot;sail&amp;quot;, 翻译为中文是“启航”。它的图标如下:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img src=&#34;./images/istio.png&#34; alt=&#34;&#34; loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;可以类比google的另外一个相关产品,Kubernetes,名字也是同样起源于古希腊，是船长或者驾驶员的意思。下图是Kubernetes的图标:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/k8s_logo_hu1c464641b6fa4bce11dec3f80a7b7807_8470_bd9fc8f635d7fec1cacd507551773612.webp 400w,
               /talk/201709-istio-introduction/images/k8s_logo_hu1c464641b6fa4bce11dec3f80a7b7807_8470_f77bdb8f0662a55056c2174d2bf8455b.webp 760w,
               /talk/201709-istio-introduction/images/k8s_logo_hu1c464641b6fa4bce11dec3f80a7b7807_8470_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/k8s_logo_hu1c464641b6fa4bce11dec3f80a7b7807_8470_bd9fc8f635d7fec1cacd507551773612.webp&#34;
               width=&#34;197&#34;
               height=&#34;169&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;后面我们会看到, istio和kubernetes的关系,就像他们的名字和图标一样, 可谓&amp;quot;一脉相传&amp;quot;.&lt;/p&gt;
&lt;h3 id=&#34;主要特性&#34;&gt;主要特性&lt;/h3&gt;
&lt;p&gt;Istio的关键功能:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP/1.1，HTTP/2，gRPC和TCP流量的自动区域感知负载平衡和故障切换。&lt;/li&gt;
&lt;li&gt;通过丰富的路由规则，容错和故障注入，对流行为的细粒度控制。&lt;/li&gt;
&lt;li&gt;支持访问控制，速率限制和配额的可插拔策略层和配置API。&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;h2 id=&#34;为什么要使用istio&#34;&gt;为什么要使用Istio？&lt;/h2&gt;
&lt;p&gt;在深入istio细节之前,我们先来看看,为什么要使用Istio？它可以帮我们解决什么问题?&lt;/p&gt;
&lt;h3 id=&#34;微服务的两面性&#34;&gt;微服务的两面性&lt;/h3&gt;
&lt;p&gt;最近两三年来微服务方兴未艾, 我们可以看到越来越多的公司和开发人员陆陆续续投身到微服务架构, 我们也看到一个一个的微服务项目落地.&lt;/p&gt;
&lt;p&gt;但是, 在这一片叫好的喧闹中, 我们还是发觉一些问题,普遍存在的问题: 虽然微服务对开发进行了简化，通过将复杂系统切分为若干个微服务来分解和降低复杂度，使得这些微服务易于被小型的开发团队所理解和维护。但是, 复杂度并非从此消失. 微服务拆分之后, 单个微服务的复杂度大幅降低, 但是由于系统被从一个单体拆分为几十甚至更多的微服务, 就带来了另外一个复杂度: 微服务的连接、管理和监控。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/two-faces_hu5224596c310d5f20f01f3549918daf5f_363147_cc8aaf89b3094a7da6f831e9c270f000.webp 400w,
               /talk/201709-istio-introduction/images/two-faces_hu5224596c310d5f20f01f3549918daf5f_363147_e5007e8a790193a26b0765c76fc34eec.webp 760w,
               /talk/201709-istio-introduction/images/two-faces_hu5224596c310d5f20f01f3549918daf5f_363147_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/two-faces_hu5224596c310d5f20f01f3549918daf5f_363147_cc8aaf89b3094a7da6f831e9c270f000.webp&#34;
               width=&#34;750&#34;
               height=&#34;500&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;试想, 对于一个大型系统, 需要对多达上百个甚至上千个微服务的管理、部署、版本控制、安全、故障转移、策略执行、遥测和监控等，谈何容易。更不要说更复杂的运维需求，例如A/B测试，金丝雀发布，限流，访问控制和端到端认证。&lt;/p&gt;
&lt;p&gt;开发人员和运维人员在单体应用程序向分布式微服务架构的转型中, 不得不面临上述挑战。&lt;/p&gt;
&lt;h3 id=&#34;服务网格&#34;&gt;服务网格&lt;/h3&gt;
&lt;p&gt;Service Mesh, 服务网格, 也有人翻译为&amp;quot;服务啮合层&amp;quot;.&lt;/p&gt;
&lt;p&gt;貌似是今年才出来的新名词?反正2017年之前我是没有听过, 虽然类似的产品已经存在挺长时间.&lt;/p&gt;
&lt;p&gt;什么是Service Mesh？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Service Mesh是专用的基础设施层。&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;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/mesh2_hu8761078e96502e57c87774f88df84e2a_28300_c756c602ac97cd62b1b7fb1b08043ac0.webp 400w,
               /talk/201709-istio-introduction/images/mesh2_hu8761078e96502e57c87774f88df84e2a_28300_980df77bea135a02687c56de8f439f2a.webp 760w,
               /talk/201709-istio-introduction/images/mesh2_hu8761078e96502e57c87774f88df84e2a_28300_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/mesh2_hu8761078e96502e57c87774f88df84e2a_28300_c756c602ac97cd62b1b7fb1b08043ac0.webp&#34;
               width=&#34;661&#34;
               height=&#34;421&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;图中应用作为服务的发起方，只需要用最简单的方式将请求发送给本地的服务网格代理，然后网格代理会进行后续的操作，如服务发现，负载均衡，最后将请求转发给目标服务。&lt;/p&gt;
&lt;p&gt;当有大量服务相互调用时，他们之间的服务调用关系就会形成网格，如下图所示：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/mesh1_hu8bdaf60d8777c0a1ddd956d973cbd280_13211_d2ba6969f4a3a75a478dc77798f433c7.webp 400w,
               /talk/201709-istio-introduction/images/mesh1_hu8bdaf60d8777c0a1ddd956d973cbd280_13211_b7e4fd501159a3f0b05b3d142061e04b.webp 760w,
               /talk/201709-istio-introduction/images/mesh1_hu8bdaf60d8777c0a1ddd956d973cbd280_13211_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/mesh1_hu8bdaf60d8777c0a1ddd956d973cbd280_13211_d2ba6969f4a3a75a478dc77798f433c7.webp&#34;
               width=&#34;440&#34;
               height=&#34;283&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在上图中绿色方块为服务，蓝色方块为边车部署的服务网格，蓝色线条为服务间通讯。可以看到蓝色的方块和线条组成了整个网格，我们将这个图片旋转90°，就更加明显了：服务网格呈现出一个完整的支撑态势，将所有的服务&amp;quot;架&amp;quot;在网格之上：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/mesh1-convert_huf2c36b634712244fb25d2248a2202e9c_10359_c56e43ca1459ef3176488f482ed06c69.webp 400w,
               /talk/201709-istio-introduction/images/mesh1-convert_huf2c36b634712244fb25d2248a2202e9c_10359_4ee9ed120d63e617e8edca9d48df3af3.webp 760w,
               /talk/201709-istio-introduction/images/mesh1-convert_huf2c36b634712244fb25d2248a2202e9c_10359_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/mesh1-convert_huf2c36b634712244fb25d2248a2202e9c_10359_c56e43ca1459ef3176488f482ed06c69.webp&#34;
               width=&#34;283&#34;
               height=&#34;440&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;服务网格的细节我们今天不详细展开, 详细内容大家可以参考网上资料。或者稍后我将会推出一个服务网格的专题，单独深入介绍服务网格。&lt;/p&gt;
&lt;p&gt;Istio也可以视为是一种服务网格, 在Istio网站上详细解释了这一概念：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;如果我们可以在架构中的服务和网络间透明地注入一层，那么该层将赋予运维人员对所需功能的控制，同时将开发人员从编码实现分布式系统问题中解放出来。通常将这个统一的架构层与服务部署在一起，统称为“服务啮合层”。由于微服务有助于分离各个功能团队，因此服务啮合层有助于将运维人员从应用特性开发和发布过程中分离出来。通过系统地注入代理到微服务间的网络路径中，Istio将迥异的微服务转变成一个集成的服务啮合层。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;istio能做什么&#34;&gt;Istio能做什么?&lt;/h3&gt;
&lt;p&gt;Istio力图解决前面我们列出的微服务实施后需要面对的问题。&lt;/p&gt;
&lt;p&gt;Istio 首先是一个服务网络,但是istio又不仅仅是服务网格: 在 Linkerd, Envoy 这样的典型服务网格之上, istio提供了一个完整的解决方案，为整个服务网格提供行为洞察和操作控制，以满足微服务应用程序的多样化需求。&lt;/p&gt;
&lt;p&gt;istio在服务网络中统一提供了许多关键功能(以下内容来自官方文档)：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;流量管理&lt;/strong&gt;。控制服务之间的流量和API调用的流向，使得调用更可靠，并使网络在恶劣情况下更加健壮。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可观察性&lt;/strong&gt;。了解服务之间的依赖关系，以及它们之间流量的本质和流向，从而提供快速识别问题的能力。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;策略执行&lt;/strong&gt;。将组织策略应用于服务之间的互动，确保访问策略得以执行，资源在消费者之间良好分配。策略的更改是通过配置网格而不是修改应用程序代码。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;服务身份和安全&lt;/strong&gt;。为网格中的服务提供可验证身份，并提供保护服务流量的能力，使其可以在不同可信度的网络上流转。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;除此之外，Istio针对可扩展性进行了设计，以满足不同的部署需要：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;平台支持&lt;/strong&gt;。Istio旨在在各种环境中运行，包括跨云, 预置，Kubernetes，Mesos等。最初专注于Kubernetes，但很快将支持其他环境。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;集成和定制&lt;/strong&gt;。策略执行组件可以扩展和定制，以便与现有的ACL，日志，监控，配额，审核等解决方案集成。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些功能极大的减少了应用程序代码，底层平台和策略之间的耦合，使微服务更容易实现，&lt;/p&gt;
&lt;h3 id=&#34;istio的真正价值&#34;&gt;istio的真正价值&lt;/h3&gt;
&lt;p&gt;我们在上面摘抄了istio官方的大段文档说明, 洋洋洒洒的列出了istio的大把大把高大上的功能.但是这些都不是重点!理论上说，任何微服务框架，只要愿意往上面堆功能，早晚都可以实现这些。&lt;/p&gt;
&lt;p&gt;那，关键在哪里？&lt;/p&gt;
&lt;p&gt;我们不妨设想一下, 在我们平时理解的微服务开发过程中, 在没有istio这样的服务网格的情况下, 我们要如何开发我们的应用程序, 才可以做到我们前面列出的这些丰富多彩的功能? 这数以几十记的各种特性, 如何才可以加入到我们的应用程序?&lt;/p&gt;
&lt;p&gt;无外乎, 找个spring cloud或者dubbo的成熟框架,直接搞定服务注册,服务发现,负载均衡,熔断等基础功能. 然后自己开发服务路由等高级功能, 接入zipkin等apm做全链路监控,自己做加密,认证,授权, 想办法搞定灰度方案, 用redis等实现限速,配额. 诸如此类, 一大堆的事情, 都需要自己做, 无论是找开源项目还是自己操刀, 最后整出一个带有一大堆功能的应用程序,上线部署. 然后给个配置说明到运维, 告诉他说如何需要灰度, 要如何如何, 如果要限速, 配置哪里哪里.&lt;/p&gt;
&lt;p&gt;这些工作, 我相信做微服务落地的公司, 基本都跑不掉, 需求是现实存在的. 无非能否实现, 以及实现多少的问题, 但是毫无疑问的是, 要做到这些, 绝对不是一件容易的事情.&lt;/p&gt;
&lt;p&gt;问题是, 即使费力做到这些, 事情到这里还没有完: 运维跑来提了点要求, 在他看来很合理的要求, 比如说, 简单点的加个黑名单, 复杂点的要做个特殊的灰度：将来自iphone的用户流量导1%到stagging环境的2.0新版本&amp;hellip;&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/requirments_hu137604024b973571c9a5b56a3763497d_32986_1aad98edbb708cde4abc88b86a282b67.webp 400w,
               /talk/201709-istio-introduction/images/requirments_hu137604024b973571c9a5b56a3763497d_32986_17709ae1d335f734e870da2332715254.webp 760w,
               /talk/201709-istio-introduction/images/requirments_hu137604024b973571c9a5b56a3763497d_32986_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/requirments_hu137604024b973571c9a5b56a3763497d_32986_1aad98edbb708cde4abc88b86a282b67.webp&#34;
               width=&#34;550&#34;
               height=&#34;289&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里就有一个很严肃的问题, 给每个业务程序的开发人员: 你到底想往你的业务程序里面塞多少管理和运维的功能? 就算你hold的住技术和时间, 你有能力一个一个的满足各种运维和管理的需求吗？ 当你发现你开始疲于响应各种非功能性的需求时, 就该开始反省了: 我们开发的是业务程序, 它的核心价值在业务逻辑的处理和实现, 将如此之多的时间精力花费在这些非业务功能上, 这真的合理吗? 而且即使是在实现层面，微服务实施时，最重要的是如何划分微服务，如何制定接口协议，你该如何分配你有限的时间和资源？&lt;/p&gt;
&lt;p&gt;istio **超越 spring cloud和dubbo ** 等传统开发框架之处, 就在于不仅仅带来了远超这些框架所能提供的功能, 而且也不需要应用程序为此做大量的改动, 开发人员也不必为上面的功能实现进行大量的知识储备.&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/unlock_hud7e6a06a5d83f27bb6dfc9c37134ca8c_7244_7b36be2e366b7f7b372c5066f20b5fb9.webp 400w,
               /talk/201709-istio-introduction/images/unlock_hud7e6a06a5d83f27bb6dfc9c37134ca8c_7244_3e0c99b4de535f23600442df1af5e963.webp 760w,
               /talk/201709-istio-introduction/images/unlock_hud7e6a06a5d83f27bb6dfc9c37134ca8c_7244_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/unlock_hud7e6a06a5d83f27bb6dfc9c37134ca8c_7244_7b36be2e366b7f7b372c5066f20b5fb9.webp&#34;
               width=&#34;461&#34;
               height=&#34;270&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;总结:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;istio 大幅降低微服务架构下应用程序的开发难度，势必极大的推动微服务的普及.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;个人乐观估计, 随着isito的成熟, 微服务开发领域将迎来一次颠覆性的变革。&lt;/p&gt;
&lt;p&gt;后面我们在介绍istio的架构和功能模块时, 大家可以了解到 istio 是如何做到这些的.&lt;/p&gt;
&lt;h2 id=&#34;开发团队&#34;&gt;开发团队&lt;/h2&gt;
&lt;p&gt;在开始介绍 istio 的架构之前, 我们再详细介绍一下 istio 的开发团队, 看看背后的大佬.&lt;/p&gt;
&lt;p&gt;首先, istio的开发团队主要来自 google, IBM 和 Lyft. 摘抄一段官方八股:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;基于我们为内部和企业客户构建和运营大规模微服务的常见经验，Google，IBM和Lyft联手创建Istio，希望为微服务开发和维护提供可靠的基础。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Google 和 IBM 相信不需要介绍了, 在istio项目中这两个公司是绝对主力. 举个例子,下图是 istio Working Group的成员列表:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/working_group_hud689b6ace20cfbe43b012fb6cd997848_103568_fb3c03780674e9fb415bc43617432b53.webp 400w,
               /talk/201709-istio-introduction/images/working_group_hud689b6ace20cfbe43b012fb6cd997848_103568_fd7db637f8cc39b77c71b7bcb0823580.webp 760w,
               /talk/201709-istio-introduction/images/working_group_hud689b6ace20cfbe43b012fb6cd997848_103568_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/working_group_hud689b6ace20cfbe43b012fb6cd997848_103568_fb3c03780674e9fb415bc43617432b53.webp&#34;
               width=&#34;760&#34;
               height=&#34;533&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;数一下, 总共18人, 10个google, 8个IBM. 注意这里没有Lyft出现, 因为Lyft的贡献主要集中在Envoy.&lt;/p&gt;
&lt;h3 id=&#34;google&#34;&gt;google&lt;/h3&gt;
&lt;p&gt;Istio来自鼎鼎大名的GCP/Google Cloud Platform, 这里诞生了同样大名鼎鼎的 app engine, cloud engine等重量级产品.&lt;/p&gt;
&lt;p&gt;google为istio带来了Kubernetes和gRPC, 还有和Envoy相关的特性如安全,性能和扩展性.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;八卦: 负责istio的GCP产品经理Varun Talwar, 同时也负责gRPC项目, 所以关注gRPC的同学（比如我自己）可以不用担心：istio对gRPC的支持必然是没有问题的.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;ibm&#34;&gt;IBM&lt;/h3&gt;
&lt;p&gt;IBM 的团队同来来自IBM云平台, IBM的贡献是:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;除了开发Istio控制面板之外, 还有和Envoy相关的其他特性如跨服务版本的流量切分, 分布式请求追踪(zipkin)和失败注入.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;lyft&#34;&gt;Lyft&lt;/h3&gt;
&lt;p&gt;Lyft的贡献主要集中在Envoy代理, 这是Lyft开源的服务网格, 基于C++. 据说Envoy在Lyft可以管理超过100个服务, 跨越10000个虚拟机，每秒处理2百万请求。本周最新消息，Envoy刚刚加入CNCF，成为该基金会的第十一个项目。&lt;/p&gt;
&lt;p&gt;最后, 在isito的介绍完成之后, 我们开始下一节内容, istio的架构.&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id=&#34;架构&#34;&gt;架构&lt;/h1&gt;
&lt;h2 id=&#34;整体架构&#34;&gt;整体架构&lt;/h2&gt;
&lt;p&gt;Istio服务网格逻辑上分为&lt;strong&gt;数据面板&lt;/strong&gt;和&lt;strong&gt;控制面板&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;数据面板&lt;/strong&gt;由一组智能代理（Envoy）组成，代理部署为边车，调解和控制微服务之间所有的网络通信。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;控制面板&lt;/strong&gt;负责管理和配置代理来路由流量，以及在运行时执行策略。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下图为istio的架构详细分解图：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/arch_hue9e188093afc6c678dc6c9276be33bbf_96018_c95a771e47ef2b4b845e98134784e9b9.webp 400w,
               /talk/201709-istio-introduction/images/arch_hue9e188093afc6c678dc6c9276be33bbf_96018_9eb313e2f2b2471ae51a111e5bfa8a11.webp 760w,
               /talk/201709-istio-introduction/images/arch_hue9e188093afc6c678dc6c9276be33bbf_96018_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/arch_hue9e188093afc6c678dc6c9276be33bbf_96018_c95a771e47ef2b4b845e98134784e9b9.webp&#34;
               width=&#34;760&#34;
               height=&#34;425&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是宏观视图，可以更形象的展示istio两个面板的功能和合作：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/mesh3_hu81255475ef3189800011fbd1c6b27a12_53790_260302aece96a50b1f3f32470c71a64e.webp 400w,
               /talk/201709-istio-introduction/images/mesh3_hu81255475ef3189800011fbd1c6b27a12_53790_433c79005005cad668679d0c434b6eb5.webp 760w,
               /talk/201709-istio-introduction/images/mesh3_hu81255475ef3189800011fbd1c6b27a12_53790_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/mesh3_hu81255475ef3189800011fbd1c6b27a12_53790_260302aece96a50b1f3f32470c71a64e.webp&#34;
               width=&#34;400&#34;
               height=&#34;336&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;以下分别介绍 istio 中的主要模块 Envoy/Mixer/Pilot/Auth.&lt;/p&gt;
&lt;h2 id=&#34;envoy&#34;&gt;Envoy&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/envoy_hue6432817fa2b369fbccaa1e2919bd225_37634_717f3d6dd7ac98fdf1d6580cf63c82e3.webp 400w,
               /talk/201709-istio-introduction/images/envoy_hue6432817fa2b369fbccaa1e2919bd225_37634_2d3b4a7bd77f4fe66c71654118ad9556.webp 760w,
               /talk/201709-istio-introduction/images/envoy_hue6432817fa2b369fbccaa1e2919bd225_37634_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/envoy_hue6432817fa2b369fbccaa1e2919bd225_37634_717f3d6dd7ac98fdf1d6580cf63c82e3.webp&#34;
               width=&#34;651&#34;
               height=&#34;363&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;以下介绍内容来自istio官方文档：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Istio 使用 Envoy 代理的扩展版本，Envoy 是以C++开发的高性能代理，用于调解服务网格中所有服务的所有入站和出站流量。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Istio利用了Envoy的许多内置功能，例如动态服务发现，负载均衡，TLS termination，HTTP/2&amp;amp;gRPC代理，熔断器，健康检查，基于百分比流量拆分的分段推出，故障注入和丰富的metrics。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Envoy实现了过滤和路由、服务发现、健康检查，提供了具有弹性的负载均衡。它在安全上支持TLS，在通信方面支持gRPC.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;概括说，Envoy 提供的是服务间网络通讯的能力，包括(以下均可支持TLS)：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HTTP／1.1&lt;/li&gt;
&lt;li&gt;HTTP/2&lt;/li&gt;
&lt;li&gt;gRPC&lt;/li&gt;
&lt;li&gt;TCP&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;以及网络通讯直接相关的功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;服务发现：从Pilot得到服务发现信息&lt;/li&gt;
&lt;li&gt;过滤&lt;/li&gt;
&lt;li&gt;负载均衡&lt;/li&gt;
&lt;li&gt;健康检查&lt;/li&gt;
&lt;li&gt;执行路由规则(Rule): 规则来自Polit,包括路由和目的地策略&lt;/li&gt;
&lt;li&gt;加密和认证: TLS certs来自 istio-Auth&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;此外, Envoy 也吐出各种数据给Mixer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;metrics&lt;/li&gt;
&lt;li&gt;logging&lt;/li&gt;
&lt;li&gt;distribution trace: 目前支持 zipkin&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总结: Envoy 是 istio 中负责&amp;quot;干活&amp;quot;的模块,如果将整个 istio 体系比喻为一个施工队,那么 Envoy 就是最底层负责搬砖的民工, 所有体力活都由 Envoy 完成. 所有需要控制,决策,管理的功能都是其他模块来负责,然后配置给 Envoy.&lt;/p&gt;
&lt;h3 id=&#34;istio架构回顾&#34;&gt;Istio架构回顾&lt;/h3&gt;
&lt;p&gt;在继续介绍istio其他的模块之前, 我们来回顾一下Istio的架构.前面我们提到, istio 服务网格分为两大块:数据面板和控制面板。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/arch_hue9e188093afc6c678dc6c9276be33bbf_96018_c95a771e47ef2b4b845e98134784e9b9.webp 400w,
               /talk/201709-istio-introduction/images/arch_hue9e188093afc6c678dc6c9276be33bbf_96018_9eb313e2f2b2471ae51a111e5bfa8a11.webp 760w,
               /talk/201709-istio-introduction/images/arch_hue9e188093afc6c678dc6c9276be33bbf_96018_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/arch_hue9e188093afc6c678dc6c9276be33bbf_96018_c95a771e47ef2b4b845e98134784e9b9.webp&#34;
               width=&#34;760&#34;
               height=&#34;425&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们刚刚介绍的 Envoy, 在istio中扮演的就是数据面板, 而其他我们下面将要陆续介绍的Mixer, Pilot和Auth属于控制面板. 上面我给出了一个类比: istio 中 Envoy (或者说数据面板)扮演的角色是底层干活的民工, 而该让这些民工如何工作, 由包工头控制面板来负责完成.&lt;/p&gt;
&lt;p&gt;在istio的架构中,这两个模块的分工非常的清晰,体现在架构上也是经纬分明: Mixer, Pilot和Auth 这三个模块都是Go语言开发,代码托管在github上, 三个仓库分别是 istio/mixer, istio/pilot/auth. 而Envoy来自lyft, 编程语言是c++ 11, 代码托管在github但不是istio下.从团队分工看, google和IBM关注于控制面板中的Mixer, Pilot和Auth, 而Lyft继续专注于Envoy.&lt;/p&gt;
&lt;p&gt;Istio的这个架构设计, 将底层service mesh的具体实现,和istio核心的控制面板拆分开. 从而使得istio可以借助成熟的Envoy快速推出产品,未来如果有更好的service mesh方案也方便集成.&lt;/p&gt;
&lt;h3 id=&#34;envoy的竞争者&#34;&gt;Envoy的竞争者&lt;/h3&gt;
&lt;p&gt;谈到这里, 我们聊一下目前市面上Envoy之外的另外一个service mesh成熟产品: 基于scala的 Linkerd。 linkerd的功能和定位和 Envoy 非常相似, 而且就在今年上半年成功进入CNCF. 而在 istio 推出之后, linkerd做了一个很有意思的动作: istio推出了和istio的集成, 实际为替换 Envoy 作为istio的数据面板, 和istio的控制面板对接.&lt;/p&gt;
&lt;p&gt;回到 istio 的架构图, 将这幅图中的 Envoy 字样替换为 Linkerd 即可. 另外还有不在图中表示的 Linkerd Ingress / Linkerd Egress 用于替代 Envoy 实现 k8s 的Ingress/Egress.&lt;/p&gt;
&lt;p&gt;本周最新消息： nginx推出了自己的服务网格产品nginmesh，功能类似，比较有意思的地方是ngxinmesh一出来就直接宣布要和istio集成，替换Envoy。有兴趣的同学可以去见我本周翻译转载的新闻 &lt;a href=&#34;https://mp.weixin.qq.com/s?__biz=MzIwMzYyNTcyNA==&amp;amp;mid=2247483742&amp;amp;idx=1&amp;amp;sn=308a6d1637c7211fe1c1a7b977f2d0ba&amp;amp;chksm=96cdc4cda1ba4ddbe83bced00a091af10f7bbcb507a00718e8a943f296e6900a5e1d017d829c&amp;amp;mpshare=1&amp;amp;scene=1&amp;amp;srcid=0920cQrJVxSsyMaBtg4okXvB&amp;amp;pass_ticket=Gr9AneZQDm6JATVKmC4oic5repkOWhnqW%2F00LhLI2FH%2Buur%2FfIkMEFVB7h9KdkUs#rd&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;nginx发布微服务平台,OpenShift Ingress控制器和服务网格预览&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;继续八卦: 一出小三上位原配出局的狗血剧情貌似正在酝酿中. 结局如何我等不妨拭目以待. 还是那句话: 没有挖不倒的墙角, 只有不努力的小三! Linkerd，nginmesh，加油!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下面开始介绍 istio 中最核心的控制面板.&lt;/p&gt;
&lt;h2 id=&#34;pilot&#34;&gt;Pilot&lt;/h2&gt;
&lt;h3 id=&#34;流量管理&#34;&gt;流量管理&lt;/h3&gt;
&lt;p&gt;istio 最核心的功能是流量管理, 前面我们看到的数据面板, 由Envoy组成的服务网格, 将整个服务间通讯和入口/出口请求都承载于其上.&lt;/p&gt;
&lt;p&gt;使用Istio的流量管理模型，本质上将&lt;strong&gt;流量和基础设施扩展解耦&lt;/strong&gt;，让运维人员通过Pilot指定他们希望流量遵循什么规则，而不是哪些特定的pod/VM应该接收流量.&lt;/p&gt;
&lt;p&gt;对这段话的理解, 可以看下图: 假定我们原有服务B,部署在Pod1/2/3上,现在我们部署一个新版本在Pod4在, 我们希望实现切5%的流量到新版本.&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/trafic-control-1_hu94c7a8d0a34e25287f5240667600ae43_69408_eff4681d136d2e86bccb7860b62921e8.webp 400w,
               /talk/201709-istio-introduction/images/trafic-control-1_hu94c7a8d0a34e25287f5240667600ae43_69408_08f9342b23ac463ea4ef6c14bdfede6c.webp 760w,
               /talk/201709-istio-introduction/images/trafic-control-1_hu94c7a8d0a34e25287f5240667600ae43_69408_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/trafic-control-1_hu94c7a8d0a34e25287f5240667600ae43_69408_eff4681d136d2e86bccb7860b62921e8.webp&#34;
               width=&#34;760&#34;
               height=&#34;253&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如果以基础设施为基础实现上述5%的流量切分,则需要通过某些手段将流量切5%到Pod4这个特定的部署单位, 实施时就必须和serviceB的具体部署还有ServiceA访问ServiceB的特定方式紧密联系在一起. 比如如果两个服务之间是用nginx做反向代理, 则需要增加pod4的ip作为upstream,并调整pod1/2/3/4的权重以实现流量切分.&lt;/p&gt;
&lt;p&gt;如果使用istio的流量管理功能, 由于Envoy组成的服务网络完全在istio的控制之下,因此要实现上述的流量拆分非常简单. 假定原版本为1.0, 新版本为2.0, 只要通过 Polit 给Envoy 发送一个规则: 2.0版本5%流量, 剩下的给1.0.&lt;/p&gt;
&lt;p&gt;这种情况下, 我们无需关注2.0版本的部署, 也无需改动任何技术设置, 更不需要在业务代码中为此提供任何配置支持和代码修改. 一切由 Pilot 和智能Envoy代理搞定。&lt;/p&gt;
&lt;p&gt;我们还可以玩的更炫一点, 比如根据请求的内容来源将流量发送到特定版本:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/trafic-control-2_hu91fe74e8af83035095218f1fa2b255e3_69637_cb8a073a324976f5f1cc6306e9450a9f.webp 400w,
               /talk/201709-istio-introduction/images/trafic-control-2_hu91fe74e8af83035095218f1fa2b255e3_69637_9b0e8996b58498fede809ceb3e2055e0.webp 760w,
               /talk/201709-istio-introduction/images/trafic-control-2_hu91fe74e8af83035095218f1fa2b255e3_69637_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/trafic-control-2_hu91fe74e8af83035095218f1fa2b255e3_69637_cb8a073a324976f5f1cc6306e9450a9f.webp&#34;
               width=&#34;760&#34;
               height=&#34;269&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;后面我们会介绍如何从请求中提取出User-Agent这样的属性来配合规则进行流量控制.&lt;/p&gt;
&lt;h3 id=&#34;pilot的功能概述&#34;&gt;Pilot的功能概述&lt;/h3&gt;
&lt;p&gt;我们在前面有强调说, Envoy在其中扮演的负责搬砖的民工角色, 而指挥Envoy工作的民工头就是Pilot模块.&lt;/p&gt;
&lt;p&gt;官方文档中对Pilot的功能描述:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Pilot负责收集和验证配置并将其传播到各种Istio组件。它从Mixer和Envoy中抽取环境特定的实现细节，为他们提供独立于底层平台的用户服务的抽象表示。此外，流量管理规则（即通用4层规则和7层HTTP/gRPC路由规则）可以在运行时通过Pilot进行编程。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;每个Envoy实例根据其从Pilot获得的信息以及其负载均衡池中的其他实例的定期健康检查来维护 负载均衡信息，从而允许其在目标实例之间智能分配流量，同时遵循其指定的路由规则。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Pilot负责在Istio服务网格中部署的Envoy实例的生命周期。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 id=&#34;pilot的架构&#34;&gt;Pilot的架构&lt;/h3&gt;
&lt;p&gt;下图是Pilot的架构图:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34;
           src=&#34;https://skyao.net/talk/201709-istio-introduction/images/PilotAdapters.svg&#34;
           loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Envoy API负责和Envoy的通讯, 主要是发送服务发现信息和流量控制规则给Envoy&lt;/li&gt;
&lt;li&gt;Envoy提供服务发现，负载均衡池和路由表的动态更新的API。这些API将istio和Envoy的实现解耦。(另外,也使得 Linkerd 之类的其他服务网络实现得以平滑接管Envoy)&lt;/li&gt;
&lt;li&gt;Polit 定了一个抽象模型, 以从特定平台细节中解耦, 为跨平台提供基础.&lt;/li&gt;
&lt;li&gt;Platform Adapter则是这个抽象模型的现实实现版本, 用于对接外部的不同平台&lt;/li&gt;
&lt;li&gt;最后是 Rules API, 提供接口给外部调用以管理 Pilot, 包括命令行工具istioctl以及未来可能出现的第三方管理界面&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;服务规范和实现&#34;&gt;服务规范和实现&lt;/h3&gt;
&lt;p&gt;Pilot架构中, 最重要的是Abstract Model和Platform Adapter, 我们详细介绍.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Abstract Model: 是对服务网格中&amp;quot;服务&amp;quot;的规范表示, 即定义在istio中什么是服务, 这个规范独立于底层平台.&lt;/li&gt;
&lt;li&gt;Platform Adapter: 这里有各种平台的实现, 目前主要是Kubernetes, 另外最新的0.2版本的代码中出现了Consul和Eureka.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们看一下Pilot 0.2的代码, pilot/platform 目录下:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/platform-list_hu3536c627a619296fb489685d931dce38_8558_647699bc031dd49b0b0b068f8768980d.webp 400w,
               /talk/201709-istio-introduction/images/platform-list_hu3536c627a619296fb489685d931dce38_8558_e4502f430561bd9b050c9c9dc677edd3.webp 760w,
               /talk/201709-istio-introduction/images/platform-list_hu3536c627a619296fb489685d931dce38_8558_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/platform-list_hu3536c627a619296fb489685d931dce38_8558_647699bc031dd49b0b0b068f8768980d.webp&#34;
               width=&#34;259&#34;
               height=&#34;216&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;瞄一眼platform.go:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// ServiceRegistry 定义支持服务注册的底层平台
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ServiceRegistry&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;const&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;// KubernetesRegistry environment flag
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;KubernetesRegistry&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ServiceRegistry&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Kubernetes&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;// ConsulRegistry environment flag
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;ConsulRegistry&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ServiceRegistry&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Consul&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;c1&#34;&gt;// EurekaRegistry environment flag
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;	&lt;span class=&#34;nx&#34;&gt;EurekaRegistry&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;ServiceRegistry&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;Eureka&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;服务规范的定义在&lt;code&gt;modle/service.go&lt;/code&gt;中:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;Service&lt;/span&gt; &lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Hostname&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;`json:&amp;#34;hostname&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Address&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;`json:&amp;#34;address,omitempty&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;Ports&lt;/span&gt; &lt;span class=&#34;nx&#34;&gt;PortList&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;`json:&amp;#34;ports,omitempty&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;ExternalName&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;`json:&amp;#34;external&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;	&lt;span class=&#34;nx&#34;&gt;ServiceAccounts&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;`json:&amp;#34;serviceaccounts,omitempty&amp;#34;`&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于时间有限, 代码部分我们不深入, 只是通过上面的两段代码来展示pilot中对服务的规范定义和目前的几个实现.&lt;/p&gt;
&lt;p&gt;暂时而言(当前版本是0.1.6, 0.2版本尚未正式发布), 目前 istio 只支持k8s一种服务发现机制.&lt;/p&gt;
&lt;p&gt;备注: Consul的实现据说主要是为了支持后面将要支持的Cloud Foundry, Eureka 没有找到资料. Etcd3 的支持还在issue列表中, 看issue记录争执中.&lt;/p&gt;
&lt;h3 id=&#34;pilot功能&#34;&gt;pilot功能&lt;/h3&gt;
&lt;p&gt;基于上述的架构设计, pilot提供以下重要功能:&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;li&gt;规则配置&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;由于时间限制, 今天不逐个展开详细介绍每个功能的详情. 大家通过名字就大概可以知道是什么, 如果希望了解详情可以关注之后的分享. 或者查阅官方文档的介绍.&lt;/p&gt;
&lt;h2 id=&#34;mixer&#34;&gt;Mixer&lt;/h2&gt;
&lt;p&gt;Mixer翻译成中文是混音器, 下面是它的图标:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/mixer-logo_hud3398194c6c46ed3301508381bc935a1_4697_3e81aa922bcb9c0c4c2b7e32457d2075.webp 400w,
               /talk/201709-istio-introduction/images/mixer-logo_hud3398194c6c46ed3301508381bc935a1_4697_e5058abf5f7e9548bd63bbcfde77267b.webp 760w,
               /talk/201709-istio-introduction/images/mixer-logo_hud3398194c6c46ed3301508381bc935a1_4697_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/mixer-logo_hud3398194c6c46ed3301508381bc935a1_4697_3e81aa922bcb9c0c4c2b7e32457d2075.webp&#34;
               width=&#34;128&#34;
               height=&#34;128&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;功能概括: Mixer负责在服务网格上执行访问控制和使用策略，并收集Envoy代理和其他服务的遥测数据。&lt;/p&gt;
&lt;h3 id=&#34;mixer的设计背景&#34;&gt;Mixer的设计背景&lt;/h3&gt;
&lt;p&gt;我们的系统通常会基于大量的基础设施而构建, 这些基础设施的后端服务为业务服务提供各种支持功能。包括访问控制系统，遥测捕获系统，配额执行系统，计费系统等。在传统设计中, 服务直接与这些后端系统集成，容易产生硬耦合.&lt;/p&gt;
&lt;p&gt;在istio中,为了避免应用程序的微服务和基础设施的后端服务之间的耦合, 提供了 Mixer 作为两者的通用中介层:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34;
           src=&#34;https://skyao.net/talk/201709-istio-introduction/images/mixer-traffic.svg&#34;
           loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Mixer 设计将策略决策从应用层移出并用配置替代，并在运维人员控制下。应用程序代码不再将应用程序代码与特定后端集成在一起，而是与Mixer进行相当简单的集成，然后 Mixer 负责与后端系统连接。&lt;/p&gt;
&lt;p&gt;特别提醒: Mixer&lt;strong&gt;不是&lt;/strong&gt;为了在基础设施后端之上创建一个抽象层或者可移植性层。也不是试图定义一个通用的logging API，通用的metric API，通用的计费API等等。&lt;/p&gt;
&lt;p&gt;Mixer的设计目标是减少业务系统的复杂性，&lt;strong&gt;将策略逻辑从业务的微服务的代码转移到Mixer中&lt;/strong&gt;, 并且改为让运维人员控制。&lt;/p&gt;
&lt;h3 id=&#34;mixer的功能&#34;&gt;Mixer的功能&lt;/h3&gt;
&lt;p&gt;Mixer 提供三个核心功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;前提条件检查&lt;/strong&gt;。允许服务在响应来自服务消费者的传入请求之前验证一些前提条件。前提条件包括认证，黑白名单，ACL检查等等。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;配额管理&lt;/strong&gt;。使服务能够在多个维度上分配和释放配额。典型例子如限速。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;遥测报告&lt;/strong&gt;。使服务能够上报日志和监控。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在Istio内，&lt;strong&gt;Envoy重度依赖Mixer&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;mixer的适配器&#34;&gt;Mixer的适配器&lt;/h3&gt;
&lt;p&gt;Mixer是高度模块化和可扩展的组件。其中一个关键功能是抽象出不同策略和遥测后端系统的细节，允许Envoy和基于Istio的服务与这些后端无关，从而保持他们的可移植。&lt;/p&gt;
&lt;p&gt;Mixer在处理不同基础设施后端的灵活性是通过使用通用插件模型实现的。单个的插件被称为适配器，它们允许Mixer与不同的基础设施后端连接，这些后台可提供核心功能，例如日志，监控，配额，ACL检查等。适配器使Mixer能够暴露一致的API，与使用的后端无关。在运行时通过配置确定确切的适配器套件，并且可以轻松指向新的或定制的基础设施后端。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/adapter_hu96ba9c09b3d701432de7c7adef8d6b6b_23450_d469732158875f1a75a68b8ce7ed0dc6.webp 400w,
               /talk/201709-istio-introduction/images/adapter_hu96ba9c09b3d701432de7c7adef8d6b6b_23450_aa3504d0b4bd5bbfef26e2b067fd946b.webp 760w,
               /talk/201709-istio-introduction/images/adapter_hu96ba9c09b3d701432de7c7adef8d6b6b_23450_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/adapter_hu96ba9c09b3d701432de7c7adef8d6b6b_23450_d469732158875f1a75a68b8ce7ed0dc6.webp&#34;
               width=&#34;340&#34;
               height=&#34;502&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这个图是官网给的, 列出的功能不多, 我从github的代码中抓个图给大家展示一下目前已有的mixer adapter:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/mixer-adapter-list_huabfb1d9be5c7c88ae59e92b42635889a_21123_f9667b6668f722de6662e099188fbc3e.webp 400w,
               /talk/201709-istio-introduction/images/mixer-adapter-list_huabfb1d9be5c7c88ae59e92b42635889a_21123_4ffa3496add8eac5aa34732cfd8f8aae.webp 760w,
               /talk/201709-istio-introduction/images/mixer-adapter-list_huabfb1d9be5c7c88ae59e92b42635889a_21123_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/mixer-adapter-list_huabfb1d9be5c7c88ae59e92b42635889a_21123_f9667b6668f722de6662e099188fbc3e.webp&#34;
               width=&#34;167&#34;
               height=&#34;655&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 id=&#34;mixer的工作方式&#34;&gt;Mixer的工作方式&lt;/h3&gt;
&lt;p&gt;Istio使用&lt;code&gt;属性&lt;/code&gt;来控制在服务网格中运行的服务的运行时行为。属性是描述入口和出口流量的有名称和类型的元数据片段，以及此流量发生的环境。Istio属性携带特定信息片段，例如：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;request.path: xyz/abc
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;request.size: &lt;span class=&#34;m&#34;&gt;234&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;request.time: 12:34:56.789 04/17/2017
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;source.ip: 192.168.0.1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;target.service: example
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;请求处理过程中, 属性由Envoy收集并发送给Mixer, Mixer中根据运维人员设置的配置来处理属性。基于这些属性，Mixer会产生对各种基础设施后端的调用。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201709-istio-introduction/images/machine_hu3a89731cced443ed11a6804bd5fa0e88_12141_d43b060f4ffef8e0a9d6e2b0fb2e7e76.webp 400w,
               /talk/201709-istio-introduction/images/machine_hu3a89731cced443ed11a6804bd5fa0e88_12141_2c06c0e7cd9ad09341aead58395802b4.webp 760w,
               /talk/201709-istio-introduction/images/machine_hu3a89731cced443ed11a6804bd5fa0e88_12141_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201709-istio-introduction/images/machine_hu3a89731cced443ed11a6804bd5fa0e88_12141_d43b060f4ffef8e0a9d6e2b0fb2e7e76.webp&#34;
               width=&#34;581&#34;
               height=&#34;239&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Mixer设计有一套强大(也很复杂, 堪称istio中最复杂的一个部分)的配置模型来配置适配器的工作方式, 设计有适配器, 切面, 属性表达式, 选择器, 描述符,manifests 等一堆概念.&lt;/p&gt;
&lt;p&gt;由于时间所限,今天不展开这块内容, 这里给出两个简单的例子让大家对mixer的配置有个感性的认识:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;这是一个ip地址检查的adapter.实现类似黑名单或者白名单的功能:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;adapters:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - name: myListChecker     &lt;span class=&#34;c1&#34;&gt;# 这个配置块的用户定义的名称&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    kind: lists             &lt;span class=&#34;c1&#34;&gt;# 这个适配器可以使用的切面类型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    impl: ipListChecker     &lt;span class=&#34;c1&#34;&gt;# 要使用的特定适配器组件的名称&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    params:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      publisherUrl: https://mylistserver:912
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      refreshInterval: 60s
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;metrics的适配器,将数据报告给Prometheus系统&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;adapters:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  - name: myMetricsCollector
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    kind: metrics
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    impl: prometheus
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;定义切面, 使用前面定义的 myListChecker 这个adapter 对属性 source.ip 进行黑名单检查&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;aspects:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- kind: lists               &lt;span class=&#34;c1&#34;&gt;# 切面的类型&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  adapter: myListChecker    &lt;span class=&#34;c1&#34;&gt;# 实现这个切面的适配器&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  params:
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    blacklist: &lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    checkExpression: source.ip
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;istio-auth&#34;&gt;Istio-Auth&lt;/h2&gt;
&lt;p&gt;Istio-Auth提供强大的服务到服务和终端用户认证，使用交互TLS，内置身份和凭据管理。它可用于升级服务网格中的未加密流量，并为运维人员提供基于服务身份而不是网络控制实施策略的能力。&lt;/p&gt;
&lt;p&gt;Istio的未来版本将增加细粒度的访问控制和审计，以使用各种访问控制机制（包括基于属性和角色的访问控制以及授权钩子）来控制和监视访问您的服务，API或资源的人员。&lt;/p&gt;
&lt;h3 id=&#34;auth的架构&#34;&gt;auth的架构&lt;/h3&gt;
&lt;p&gt;下图展示Istio Auth架构，其中包括三个组件：身份，密钥管理和通信安全。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34;
           src=&#34;https://skyao.net/talk/201709-istio-introduction/images/auth.svg&#34;
           loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在这个例子中, 服务A以服务帐户“foo”运行, 服务B以服务帐户“bar”运行, 他们之间的通讯原来是没有加密的. 但是istio在不修改代码的情况, 依托Envoy形成的服务网格, 直接在客户端envoy和服务器端envoy之间进行通讯加密。&lt;/p&gt;
&lt;p&gt;目前在Kubernetes上运行的 istio，使用Kubernetes service account/服务帐户来识别运行该服务的人员.&lt;/p&gt;
&lt;h3 id=&#34;未来将推出的功能&#34;&gt;未来将推出的功能&lt;/h3&gt;
&lt;p&gt;auth在目前的istio版本(0.1.6和即将发布的0.2)中,功能还不是很全, 未来则规划有非常多的特性:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;细粒度授权和审核&lt;/li&gt;
&lt;li&gt;安全Istio组件（Mixer, Pilot等）&lt;/li&gt;
&lt;li&gt;集群间服务到服务认证&lt;/li&gt;
&lt;li&gt;使用JWT/OAuth2/OpenID_Connect终端到服务的认证&lt;/li&gt;
&lt;li&gt;支持GCP服务帐户和AWS服务帐户&lt;/li&gt;
&lt;li&gt;非http流量（MySql，Redis等）支持&lt;/li&gt;
&lt;li&gt;Unix域套接字，用于服务和Envoy之间的本地通信&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;p&gt;回到我们前面的曾经讨论的问题，如果自己来做，完成这些功能大家觉得需要多少工作量？要把所有的业务模块都迁移到具备这些功能的框架和体系中，需要改动多少？而istio，未来就会直接将这些东西摆上我们的餐桌。&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id=&#34;未来&#34;&gt;未来&lt;/h1&gt;
&lt;p&gt;前面我们介绍了istio的基本情况, 还有istio的架构和主要组件. 相信大家对istio应该有了一个初步的认识.&lt;/p&gt;
&lt;p&gt;需要提醒的是, istio是一个今年5月才发布 0.1.0 版本的新鲜出炉的开源项目, 目前该项目也才发布到0.1.6正式版本和 0.2.2 pre release版本. 很多地方还不完善，希望大家可以理解，有点类似于最早期阶段的Kubernetes.&lt;/p&gt;
&lt;p&gt;在接下来的时间, 我们将简单介绍一下istio后面的一些开发计划和发展预期.&lt;/p&gt;
&lt;h2 id=&#34;运行环境支持&#34;&gt;运行环境支持&lt;/h2&gt;
&lt;p&gt;Istio目前只支持Kubernetes, 这是令人比较遗憾的一点. 不过 istio 给出的解释是istio未来会支持在各种环境中运行，只是目前在 0.1/0.2 这样的初始阶段暂时专注于Kubernetes，但很快会支持其他环境。&lt;/p&gt;
&lt;p&gt;注意: Kubernetes平台，除了原生Kubernetes, 还有诸如 IBM Bluemix Container Service和RedHat OpenShift这样的商业平台。 以及google自家的 Google Container Engine。这是自家的东西, 而且现在k8s/istio/gRPC都已经被划归到 google cloud platform部门, 自然会优先支持.&lt;/p&gt;
&lt;p&gt;另外isito所说的其他环境指的是:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;mesos: 这个估计是大多人非k8s的docker使用者最关心的了, 暂时从github上的代码中未见到有开工迹象, 但是istio的文档和官方声明都明显说会支持, 估计还是希望很大的.&lt;/li&gt;
&lt;li&gt;cloud foundry: 这个东东我们国内除了私有云外玩的不多, istio对它的支持似乎已经启动. 比如我看到代码中已经有了consul这个服务注册的支持, 从issue讨论上看到是说为上cloud foundry做准备, 因为cloud foundry没有k8s那样的原生服务注册机制.&lt;/li&gt;
&lt;li&gt;VM: 这块没有看到介绍, 但是有看到istio的讨论中提到会支持容器和非容器的混合(hybrid)支持&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;值得特别指出的是, 目前我还没有看到istio有对docker家的swarm有支持的计划或者讨论, 目前我找到的任何istio的资料中都不存在swarm这个东东。我只能不负责任的解读为: 有人的地方就有江湖, 有江湖就自然会有江湖恩怨。&lt;/p&gt;
&lt;h2 id=&#34;路线图&#34;&gt;路线图&lt;/h2&gt;
&lt;p&gt;按照istio的说法, 他们计划每3个月发布一次新版本, 我们看一下目前得到的一些信息:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;0.1 版本2017年5月发布,只支持Kubernetes&lt;/li&gt;
&lt;li&gt;0.2 即将发布,当前是0.2.1 pre-release, 也只支持Kubernetes&lt;/li&gt;
&lt;li&gt;0.3 roadmap上说要支持k8s之外的平台, &amp;ldquo;Support for Istio meshes without Kubernetes.&amp;rdquo;, 但是具体哪些特性会放在0.3中,还在讨论中.&lt;/li&gt;
&lt;li&gt;1.0 版本预计今年年底发布&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注: 1.0版本的发布时间官方没有明确给出, 我只是看到官网资料里面有信息透露如下:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;we invite the community to join us in shaping the project as we work toward a 1.0 release later this year.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;按照上面给的信息，简单推算：应该是9月发0.2, 然后12月发0.3, 但是这就已经是年底了, 所以不排除1.0推迟发布的可能, 或者0.3直接当成 1.0 发布.&lt;/p&gt;
&lt;h2 id=&#34;社区支持&#34;&gt;社区支持&lt;/h2&gt;
&lt;p&gt;虽然istio初出江湖, 乳臭未干, 但是凭借google和IBM的金字招牌, 还有istio前卫而实际的设计理念, 目前已经有很多公司在开始提供对istio的支持或者集成, 这是istio官方页面有记载的:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Red Hat: Openshift and OpenShift Application Runtimes&lt;/li&gt;
&lt;li&gt;Pivotal: Cloud Foundry&lt;/li&gt;
&lt;li&gt;Weaveworks: Weave Cloud and Weave Net 2.0&lt;/li&gt;
&lt;li&gt;Tigera: Project Calico Network Policy Engine&lt;/li&gt;
&lt;li&gt;Datawire: Ambassador project&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;然后一些其他外围支持, 从代码中看到的:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;eureka&lt;/li&gt;
&lt;li&gt;consul&lt;/li&gt;
&lt;li&gt;etcd v3: 这个还在争执中,作为etcd的坚定拥护者, 我对此保持密切关注.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;存在的问题&#34;&gt;存在的问题&lt;/h2&gt;
&lt;p&gt;istio毕竟目前才是0.2.2 pre release版本，毕竟才出来四个月，因此还是存在大量的问题，集中表现为：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;只支持k8s，而且要求k8s 1.7.4+，因为使用到k8s的 CustomResourceDefinitions&lt;/li&gt;
&lt;li&gt;性能较低，从目前的测试情况看，0.1版本很糟糕，0.2版本有改善&lt;/li&gt;
&lt;li&gt;很多功能尚未完成&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;给大家的建议：可以密切关注istio的动向，提前做好技术储备。但是，最起码在年底的1.0版本出来之前，别急着上生产环境。&lt;/p&gt;
&lt;h2 id=&#34;最后的话&#34;&gt;最后的话&lt;/h2&gt;
&lt;p&gt;感谢大家在今天参与这次的istio分享, 由于时间有限, 很多细节无法在今天给大家尽情展开. 如果大家对 istio 感兴趣, 可以之后自行浏览 istio 的官方网站, 我也预期会在之后陆陆续续的给出istio相关的文章和分享.&lt;/p&gt;
&lt;p&gt;今天的分享到此结束，感谢大家的全程参与, 下次再会!&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>利用开源社区打造微服务生态体系</title>
      <link>https://skyao.net/talk/201610-build-microservice-by-open-source/</link>
      <pubDate>Sat, 15 Oct 2016 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/201610-build-microservice-by-open-source/</guid>
      <description>&lt;p&gt;备注： 广州地区难得的一次技术分享会议。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/1_hu19b59785c19d2c345d618071807f7c85_165174_2c2888da083838590940199220c34561.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/1_hu19b59785c19d2c345d618071807f7c85_165174_9e30b370f000aa3b2569913ebb738eaf.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/1_hu19b59785c19d2c345d618071807f7c85_165174_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/1_hu19b59785c19d2c345d618071807f7c85_165174_2c2888da083838590940199220c34561.webp&#34;
               width=&#34;760&#34;
               height=&#34;380&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/2_huf43c0d09bf6be647dca070cefb198b7f_98979_88dc881490b6286aa932cff91a793f91.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/2_huf43c0d09bf6be647dca070cefb198b7f_98979_e906740624646cb3ab567128ef58edaf.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/2_huf43c0d09bf6be647dca070cefb198b7f_98979_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/2_huf43c0d09bf6be647dca070cefb198b7f_98979_88dc881490b6286aa932cff91a793f91.webp&#34;
               width=&#34;428&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr&gt;
&lt;h1 id=&#34;利用开源社区打造微服务生态体系&#34;&gt;利用开源社区打造微服务生态体系&lt;/h1&gt;
&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;大家好，我是敖小剑，今天给大家分享的主题是&amp;quot;利用开源设计打造微服务生态体系&amp;quot;。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt1_hu491c5fb6ab87c6995f4d38cb772a2248_239495_244e0f36a9c2db9492b62d27b1176619.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt1_hu491c5fb6ab87c6995f4d38cb772a2248_239495_f885b709ea22d26bd6a4121ca8946cf2.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt1_hu491c5fb6ab87c6995f4d38cb772a2248_239495_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt1_hu491c5fb6ab87c6995f4d38cb772a2248_239495_244e0f36a9c2db9492b62d27b1176619.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;主要内容如下：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt2_hu491c5fb6ab87c6995f4d38cb772a2248_254802_932b39243e1ad19c23265ceda087b000.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt2_hu491c5fb6ab87c6995f4d38cb772a2248_254802_33daca17ba7485e9863b8a51c10c07d3.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt2_hu491c5fb6ab87c6995f4d38cb772a2248_254802_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt2_hu491c5fb6ab87c6995f4d38cb772a2248_254802_932b39243e1ad19c23265ceda087b000.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;内容分为三个大的部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;微服务的核心技术&lt;/li&gt;
&lt;li&gt;目前可选的开源微服务框架&lt;/li&gt;
&lt;li&gt;为微服务提供支撑的基础设施&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;需要说明的是，由于时间有限，而分享的内容数量太多，因此：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;内容都只是罗列，不展开具体介绍&lt;/li&gt;
&lt;li&gt;个人知识面有限，列举过程中范围覆盖不足有所遗漏是必然的&lt;/li&gt;
&lt;li&gt;部分场景我会给出一些个人建议，但是请注意这些都是我的一家之言，仅供参考&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt3_hu491c5fb6ab87c6995f4d38cb772a2248_258812_5d93af5a2cc0ce51e50813e6f8c8e6b7.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt3_hu491c5fb6ab87c6995f4d38cb772a2248_258812_93e322572757e0df3fef8840febf4e71.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt3_hu491c5fb6ab87c6995f4d38cb772a2248_258812_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt3_hu491c5fb6ab87c6995f4d38cb772a2248_258812_5d93af5a2cc0ce51e50813e6f8c8e6b7.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;下面列出的是今天将会介绍的内容，数量非常多，可谓繁星璀璨。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt4_hu491c5fb6ab87c6995f4d38cb772a2248_270140_187150456add528d5a2a872c3e9d8893.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt4_hu491c5fb6ab87c6995f4d38cb772a2248_270140_c791dac4606d24b296cde31f8dbf736d.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt4_hu491c5fb6ab87c6995f4d38cb772a2248_270140_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt4_hu491c5fb6ab87c6995f4d38cb772a2248_270140_187150456add528d5a2a872c3e9d8893.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;第一部分核心技术&#34;&gt;第一部分：核心技术&lt;/h2&gt;
&lt;p&gt;现在开始第一个部分：核心技术。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt5_hu491c5fb6ab87c6995f4d38cb772a2248_237830_c343aaeae5443cc887af2fae034eb517.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt5_hu491c5fb6ab87c6995f4d38cb772a2248_237830_c5042928898289ef5975e1a317505ec4.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt5_hu491c5fb6ab87c6995f4d38cb772a2248_237830_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt5_hu491c5fb6ab87c6995f4d38cb772a2248_237830_c343aaeae5443cc887af2fae034eb517.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt6_hu491c5fb6ab87c6995f4d38cb772a2248_241574_e7bca565554d4eb035b068afb3bb534a.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt6_hu491c5fb6ab87c6995f4d38cb772a2248_241574_d0c1637ec977d67165365b587344e78d.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt6_hu491c5fb6ab87c6995f4d38cb772a2248_241574_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt6_hu491c5fb6ab87c6995f4d38cb772a2248_241574_e7bca565554d4eb035b068afb3bb534a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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;在这点上，微服务和以OSGi、jigsaw为代表的Java模块化方案形成鲜明对比。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt7_hu491c5fb6ab87c6995f4d38cb772a2248_248064_2563bd466e2a0caa681d413b6c3b27a4.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt7_hu491c5fb6ab87c6995f4d38cb772a2248_248064_d66ec30bb1e55f40b7f15aabac672c83.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt7_hu491c5fb6ab87c6995f4d38cb772a2248_248064_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt7_hu491c5fb6ab87c6995f4d38cb772a2248_248064_2563bd466e2a0caa681d413b6c3b27a4.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;进程间通讯的方式比较多，其多样性体现在两个方面：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;有三种风格的解决方案：REST，RPC 和 定制&lt;/li&gt;
&lt;li&gt;交互方式有两个维度：按照交互对象的数量分为一对一和一对多，按照应答返回的方式分为同步和异步。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt8_hu491c5fb6ab87c6995f4d38cb772a2248_242847_7d5e512b43286d8ace4af4b812717911.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt8_hu491c5fb6ab87c6995f4d38cb772a2248_242847_93b3c00bebbc7fd4107cdcc9ab7d32ab.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt8_hu491c5fb6ab87c6995f4d38cb772a2248_242847_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt8_hu491c5fb6ab87c6995f4d38cb772a2248_242847_7d5e512b43286d8ace4af4b812717911.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;两个维度组合之后的可能性如图：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt9_hu491c5fb6ab87c6995f4d38cb772a2248_259263_84cc5355901e686d8388a9139a40491f.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt9_hu491c5fb6ab87c6995f4d38cb772a2248_259263_a3315c262ea82ba03957691baaf92c9e.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt9_hu491c5fb6ab87c6995f4d38cb772a2248_259263_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt9_hu491c5fb6ab87c6995f4d38cb772a2248_259263_84cc5355901e686d8388a9139a40491f.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;目前业界常见的网络类库：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt10_hu491c5fb6ab87c6995f4d38cb772a2248_289737_1c0bc37585f6094ae76f6257e383d988.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt10_hu491c5fb6ab87c6995f4d38cb772a2248_289737_f80e904f7d1d2b24dafd124b479f2c8c.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt10_hu491c5fb6ab87c6995f4d38cb772a2248_289737_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt10_hu491c5fb6ab87c6995f4d38cb772a2248_289737_1c0bc37585f6094ae76f6257e383d988.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;考虑到 netty 通常会是大多数人的选择，这里再展开谈一下 netty 的版本选择问题：&lt;/p&gt;
&lt;p&gt;需要特别强调的是： netty 5.* 版本因为 ForkJoinPool 引入了太多复杂度而又未能带来明确的性能提升，已经被　netty　官方放弃，不再继续。使用 netty 5.* alpha 版本的同学请回退到 4.0 或者 4.1 版本。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt11_hu491c5fb6ab87c6995f4d38cb772a2248_251781_843a88c2679b6254c3aae4906b8ad878.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt11_hu491c5fb6ab87c6995f4d38cb772a2248_251781_9048e8b25f3e02d339e42af4e16ed563.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt11_hu491c5fb6ab87c6995f4d38cb772a2248_251781_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt11_hu491c5fb6ab87c6995f4d38cb772a2248_251781_843a88c2679b6254c3aae4906b8ad878.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Rest 研究不多，只能给出一点简单的建议。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt12_hu491c5fb6ab87c6995f4d38cb772a2248_252009_97b9dc6b86fff847bbd0fbf333d884ed.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt12_hu491c5fb6ab87c6995f4d38cb772a2248_252009_092b2e9abe401c794aea70ad624c8b3e.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt12_hu491c5fb6ab87c6995f4d38cb772a2248_252009_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt12_hu491c5fb6ab87c6995f4d38cb772a2248_252009_97b9dc6b86fff847bbd0fbf333d884ed.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;RPC框架，业界数得上数的大概有十几种，这里只详细介绍三种，分别代表老中新三代RPC框架。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt13_hu491c5fb6ab87c6995f4d38cb772a2248_250830_1f79d01424c92035ca271eda6cf4500d.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt13_hu491c5fb6ab87c6995f4d38cb772a2248_250830_18eeb25adcdac76a8c8f16a1817d78e5.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt13_hu491c5fb6ab87c6995f4d38cb772a2248_250830_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt13_hu491c5fb6ab87c6995f4d38cb772a2248_250830_1f79d01424c92035ca271eda6cf4500d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt14_hu491c5fb6ab87c6995f4d38cb772a2248_278684_3d5039a1726f54fb3dfb0cfbe31503e2.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt14_hu491c5fb6ab87c6995f4d38cb772a2248_278684_98dd2f76519a3d33d242e35307201685.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt14_hu491c5fb6ab87c6995f4d38cb772a2248_278684_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt14_hu491c5fb6ab87c6995f4d38cb772a2248_278684_3d5039a1726f54fb3dfb0cfbe31503e2.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt15_hu491c5fb6ab87c6995f4d38cb772a2248_269522_115b91a4a9a0d4cda369b93c1396a8d1.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt15_hu491c5fb6ab87c6995f4d38cb772a2248_269522_9aaa88ee0c94d4cab219383d70eade53.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt15_hu491c5fb6ab87c6995f4d38cb772a2248_269522_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt15_hu491c5fb6ab87c6995f4d38cb772a2248_269522_115b91a4a9a0d4cda369b93c1396a8d1.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt16_hu491c5fb6ab87c6995f4d38cb772a2248_269927_3b514f25ce6ae99494daa1360c9db76b.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt16_hu491c5fb6ab87c6995f4d38cb772a2248_269927_e6c7284e1491895fb9d1a44d8b04eaf4.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt16_hu491c5fb6ab87c6995f4d38cb772a2248_269927_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt16_hu491c5fb6ab87c6995f4d38cb772a2248_269927_3b514f25ce6ae99494daa1360c9db76b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;以下是个人给出的建议：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt17_hu491c5fb6ab87c6995f4d38cb772a2248_258858_8d9f58916ee84eb99f127e0a4ef84e47.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt17_hu491c5fb6ab87c6995f4d38cb772a2248_258858_2940cbb218f0934fadf5364d16f0de97.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt17_hu491c5fb6ab87c6995f4d38cb772a2248_258858_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt17_hu491c5fb6ab87c6995f4d38cb772a2248_258858_8d9f58916ee84eb99f127e0a4ef84e47.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;提醒一点的是：如果需要支持移动设备，如果想要用HTTTP 2 的新特性，那么就只能选择gRPC了。&lt;/p&gt;
&lt;p&gt;谈谈第三条路线：定制。选择这种方案的同学也不少。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt18_hu491c5fb6ab87c6995f4d38cb772a2248_258943_139430c5fc74a41178c3aecfee466e93.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt18_hu491c5fb6ab87c6995f4d38cb772a2248_258943_7f5bf04f05bf674d80583f637000f466.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt18_hu491c5fb6ab87c6995f4d38cb772a2248_258943_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt18_hu491c5fb6ab87c6995f4d38cb772a2248_258943_139430c5fc74a41178c3aecfee466e93.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;消息队列的选择，同样很多，这里列出三种常见的加一个特例 NSQ。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt19_hu491c5fb6ab87c6995f4d38cb772a2248_239427_7bc8366526a025dae8349a05763a2eac.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt19_hu491c5fb6ab87c6995f4d38cb772a2248_239427_ebcfbd808d5df60566f7b4132d0467ff.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt19_hu491c5fb6ab87c6995f4d38cb772a2248_239427_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt19_hu491c5fb6ab87c6995f4d38cb772a2248_239427_7bc8366526a025dae8349a05763a2eac.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt20_hu491c5fb6ab87c6995f4d38cb772a2248_276470_024996597713b541e9e014544d35298b.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt20_hu491c5fb6ab87c6995f4d38cb772a2248_276470_f26756bbf020303951fb571264c29296.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt20_hu491c5fb6ab87c6995f4d38cb772a2248_276470_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt20_hu491c5fb6ab87c6995f4d38cb772a2248_276470_024996597713b541e9e014544d35298b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;首先看服务注册和服务发现，在实现时根据对一致性要求的不同，分成两个流派：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;强一致性&lt;/p&gt;
&lt;p&gt;比较常见的分布式一致性协议是 PAXOS 协议和 Raft 协议。相比 PAXOS 而言，Raft 协议易于理解和实现，因此最新的分布式一致性方案大都选择 Raft 协议。&lt;/p&gt;
&lt;p&gt;zookeeper 采用的是 PAXOS 协议(实际为改进版本ZAP)，而 Raft 协议那边主要是 consul 和 etcd。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;弱一致性&lt;/p&gt;
&lt;p&gt;如果对一致性要求不高，可以选择以 DNS 为基础的方案，也可以像新浪微博的 Vintage 一样基于 Redis 。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt21_hu491c5fb6ab87c6995f4d38cb772a2248_258389_56fc30dabee619b82f1058a21b001867.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt21_hu491c5fb6ab87c6995f4d38cb772a2248_258389_add72071de141c1486344e1f4eab3d66.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt21_hu491c5fb6ab87c6995f4d38cb772a2248_258389_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt21_hu491c5fb6ab87c6995f4d38cb772a2248_258389_56fc30dabee619b82f1058a21b001867.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;常见的强一致性方案如下：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt22_hu491c5fb6ab87c6995f4d38cb772a2248_302064_b41bfb5c039f59eafd367be2d88a3386.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt22_hu491c5fb6ab87c6995f4d38cb772a2248_302064_a558a113fa6eb2f34b0e8d677db42cec.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt22_hu491c5fb6ab87c6995f4d38cb772a2248_302064_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt22_hu491c5fb6ab87c6995f4d38cb772a2248_302064_b41bfb5c039f59eafd367be2d88a3386.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;弱一致性方案比较少，一般多用于 REST 或者 HTTP + json / web service 等简单场合：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt23_hu491c5fb6ab87c6995f4d38cb772a2248_247289_17d2436f3482c3214572b1cd8add95ac.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt23_hu491c5fb6ab87c6995f4d38cb772a2248_247289_bb6786d6edf9578b6e932a084d0734c4.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt23_hu491c5fb6ab87c6995f4d38cb772a2248_247289_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt23_hu491c5fb6ab87c6995f4d38cb772a2248_247289_17d2436f3482c3214572b1cd8add95ac.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt24_hu491c5fb6ab87c6995f4d38cb772a2248_272881_5f70b2fe608c3443305d56e24b5f5919.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt24_hu491c5fb6ab87c6995f4d38cb772a2248_272881_aeb0c5ffa405d734483aaf603bbd5c8a.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt24_hu491c5fb6ab87c6995f4d38cb772a2248_272881_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt24_hu491c5fb6ab87c6995f4d38cb772a2248_272881_5f70b2fe608c3443305d56e24b5f5919.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt25_hu491c5fb6ab87c6995f4d38cb772a2248_255028_eac7bea2d05584d4e2dd41b9dd99d7c1.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt25_hu491c5fb6ab87c6995f4d38cb772a2248_255028_3387969e0afdcc86cd7669b52a0cd167.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt25_hu491c5fb6ab87c6995f4d38cb772a2248_255028_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt25_hu491c5fb6ab87c6995f4d38cb772a2248_255028_eac7bea2d05584d4e2dd41b9dd99d7c1.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;负载均衡的方案选择，注意区分服务器端负载均衡和客户端负载均衡。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt26_hu491c5fb6ab87c6995f4d38cb772a2248_266658_f3b441189966553b134ab1d5780931da.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt26_hu491c5fb6ab87c6995f4d38cb772a2248_266658_cc01c690f2dc3800a1430f18ffdfb45a.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt26_hu491c5fb6ab87c6995f4d38cb772a2248_266658_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt26_hu491c5fb6ab87c6995f4d38cb772a2248_266658_f3b441189966553b134ab1d5780931da.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;熔断器目前只有一个可选的开源方案，之前有同学吐糟说 Hystrix 的设计和实现不好，但是在2016年又改进了很多。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt27_hu491c5fb6ab87c6995f4d38cb772a2248_234484_d6356b7e199a884959f9f43775a6814a.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt27_hu491c5fb6ab87c6995f4d38cb772a2248_234484_1721870075b440c59fa011de3f03791a.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt27_hu491c5fb6ab87c6995f4d38cb772a2248_234484_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt27_hu491c5fb6ab87c6995f4d38cb772a2248_234484_d6356b7e199a884959f9f43775a6814a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;第二部分微服务框架&#34;&gt;第二部分：微服务框架&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt28_hu491c5fb6ab87c6995f4d38cb772a2248_248016_9aaf2a1073c7d52b76981cc7ca2fc0b8.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt28_hu491c5fb6ab87c6995f4d38cb772a2248_248016_a9c6ebc94dbd8b2563e8b5571a97ed2a.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt28_hu491c5fb6ab87c6995f4d38cb772a2248_248016_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt28_hu491c5fb6ab87c6995f4d38cb772a2248_248016_9aaf2a1073c7d52b76981cc7ca2fc0b8.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在国内讨论SOA、服务化、微服务时，dubbo 总是一个绕不开的名字。个人对 dubbo 的评价是&amp;quot;国内SOA框架集大成之作&amp;quot;，基本上一个SOA框架应有的功能都有了。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt29_hu491c5fb6ab87c6995f4d38cb772a2248_250099_5e8687828f1529cc6ae792f473acab48.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt29_hu491c5fb6ab87c6995f4d38cb772a2248_250099_647709a0b145edac8bc69307b34faf4c.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt29_hu491c5fb6ab87c6995f4d38cb772a2248_250099_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt29_hu491c5fb6ab87c6995f4d38cb772a2248_250099_5e8687828f1529cc6ae792f473acab48.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;回顾一下 dubbo 曾经辉煌的历史：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt30_hu491c5fb6ab87c6995f4d38cb772a2248_281595_6f21af157db743a753918938e34e8529.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt30_hu491c5fb6ab87c6995f4d38cb772a2248_281595_1055c1f383ea70e18bf50db678929829.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt30_hu491c5fb6ab87c6995f4d38cb772a2248_281595_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt30_hu491c5fb6ab87c6995f4d38cb772a2248_281595_6f21af157db743a753918938e34e8529.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;再对比一下现状，实在令人感叹：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt31_hu491c5fb6ab87c6995f4d38cb772a2248_269937_6480fbe57ef325b1a10ae565f8ef2886.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt31_hu491c5fb6ab87c6995f4d38cb772a2248_269937_2eecea75f500c23abc309cc13ce55589.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt31_hu491c5fb6ab87c6995f4d38cb772a2248_269937_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt31_hu491c5fb6ab87c6995f4d38cb772a2248_269937_6480fbe57ef325b1a10ae565f8ef2886.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt32_hu491c5fb6ab87c6995f4d38cb772a2248_272393_d012441e80a401e0dbafaea67980e4a4.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt32_hu491c5fb6ab87c6995f4d38cb772a2248_272393_7fffb9cdd2dcda3a3ee36b3d77874ce2.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt32_hu491c5fb6ab87c6995f4d38cb772a2248_272393_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt32_hu491c5fb6ab87c6995f4d38cb772a2248_272393_d012441e80a401e0dbafaea67980e4a4.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;从时间线上来看 dubbo 的崛起和兴盛，犹如流星划过夜空.&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt33_hu491c5fb6ab87c6995f4d38cb772a2248_263398_34359c25cc86a22cf5dd4bdb5915196a.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt33_hu491c5fb6ab87c6995f4d38cb772a2248_263398_8410c5cd29066b273328b7e45910bc51.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt33_hu491c5fb6ab87c6995f4d38cb772a2248_263398_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt33_hu491c5fb6ab87c6995f4d38cb772a2248_263398_34359c25cc86a22cf5dd4bdb5915196a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对 dubbo 的总结，有比较多的个人情绪在，仅供参考。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt34_hu491c5fb6ab87c6995f4d38cb772a2248_253858_8f0dfa32327990dc71a07111ccaee742.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt34_hu491c5fb6ab87c6995f4d38cb772a2248_253858_7022a227ebd21fa5eac4d157fe5f0033.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt34_hu491c5fb6ab87c6995f4d38cb772a2248_253858_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt34_hu491c5fb6ab87c6995f4d38cb772a2248_253858_8f0dfa32327990dc71a07111ccaee742.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Motan，能否接过 dubbo 的大旗？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt35_hu491c5fb6ab87c6995f4d38cb772a2248_250546_1e3912a49340a831b9dab9762940f807.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt35_hu491c5fb6ab87c6995f4d38cb772a2248_250546_e5e90819b95a365df4996dffe83873cc.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt35_hu491c5fb6ab87c6995f4d38cb772a2248_250546_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt35_hu491c5fb6ab87c6995f4d38cb772a2248_250546_1e3912a49340a831b9dab9762940f807.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;发现每个服务化框架出来，都要被问一个问题：为啥你们不直接用 dubbo 呢？ Motan也未能免俗 :)&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt36_hu491c5fb6ab87c6995f4d38cb772a2248_296739_6fa36fefff802000eb8bf2df15c3cee9.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt36_hu491c5fb6ab87c6995f4d38cb772a2248_296739_ae26a4c0b8482dcaf22e4201ab6e3a6b.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt36_hu491c5fb6ab87c6995f4d38cb772a2248_296739_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt36_hu491c5fb6ab87c6995f4d38cb772a2248_296739_6fa36fefff802000eb8bf2df15c3cee9.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;补充：这也是我自己不选择 dubbo，而是新设计 dolphin 微服务框架的重要理由之一。改造成本远不是一句轻巧的&amp;quot;稍微改改&amp;quot;那么简单。&lt;/p&gt;
&lt;p&gt;Motan的技术栈：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt37_hu491c5fb6ab87c6995f4d38cb772a2248_266084_2f712243620ae9b92737dad1d10b46fd.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt37_hu491c5fb6ab87c6995f4d38cb772a2248_266084_7720de66cae22b6504a693d75e971ec1.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt37_hu491c5fb6ab87c6995f4d38cb772a2248_266084_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt37_hu491c5fb6ab87c6995f4d38cb772a2248_266084_2f712243620ae9b92737dad1d10b46fd.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt38_hu491c5fb6ab87c6995f4d38cb772a2248_259432_df28fefb62da82746f3915806b85c0f9.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt38_hu491c5fb6ab87c6995f4d38cb772a2248_259432_0546521063c31d3ca93e6241edbcb453.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt38_hu491c5fb6ab87c6995f4d38cb772a2248_259432_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt38_hu491c5fb6ab87c6995f4d38cb772a2248_259432_df28fefb62da82746f3915806b85c0f9.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;下面介绍业界大佬 Netflix 出品的重量级开源产品 OSS 套件。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt39_hu491c5fb6ab87c6995f4d38cb772a2248_251903_21767b44197ad4abe7c110dfeab51e54.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt39_hu491c5fb6ab87c6995f4d38cb772a2248_251903_62e410ebd66cb47650b139541e1be376.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt39_hu491c5fb6ab87c6995f4d38cb772a2248_251903_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt39_hu491c5fb6ab87c6995f4d38cb772a2248_251903_21767b44197ad4abe7c110dfeab51e54.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Netflix 比较有意思的一个做法是他的组建拆分的比较细致，每个独立功能都拆分为单独的组件，方便按需选择，赞一个。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt40_hu491c5fb6ab87c6995f4d38cb772a2248_264538_2856a7da89bcd06815e5476196133cdb.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt40_hu491c5fb6ab87c6995f4d38cb772a2248_264538_c995ab2a09c49506ec1a9cfa0f6a1f67.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt40_hu491c5fb6ab87c6995f4d38cb772a2248_264538_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt40_hu491c5fb6ab87c6995f4d38cb772a2248_264538_2856a7da89bcd06815e5476196133cdb.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt41_hu491c5fb6ab87c6995f4d38cb772a2248_249603_f1a0c1827fa89d72650ef653394654bc.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt41_hu491c5fb6ab87c6995f4d38cb772a2248_249603_842543a70a857f1fadc79ebcae488338.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt41_hu491c5fb6ab87c6995f4d38cb772a2248_249603_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt41_hu491c5fb6ab87c6995f4d38cb772a2248_249603_f1a0c1827fa89d72650ef653394654bc.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;个人对 OSS 的一些看法，属于鸡蛋里面挑骨头性质，仅供参考。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt42_hu491c5fb6ab87c6995f4d38cb772a2248_295063_1b3e0662f9d4e90dadc5b5afb8014630.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt42_hu491c5fb6ab87c6995f4d38cb772a2248_295063_d3a1f46e3a0a88618d8c64924927be32.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt42_hu491c5fb6ab87c6995f4d38cb772a2248_295063_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt42_hu491c5fb6ab87c6995f4d38cb772a2248_295063_1b3e0662f9d4e90dadc5b5afb8014630.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;下面开始介绍另外一位业界超重量级大佬的一系列作品，所有Java同学都最熟悉不过的 spring。&lt;/p&gt;
&lt;p&gt;在介绍spring为微服务提供的支持之前，我们先回顾一下过去这十四年spring一路的历程：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt43_hu491c5fb6ab87c6995f4d38cb772a2248_280206_6addd6ca5d617e70f3bb9e9a26dc8db3.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt43_hu491c5fb6ab87c6995f4d38cb772a2248_280206_8d7788455854bc467188bd5b669d5434.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt43_hu491c5fb6ab87c6995f4d38cb772a2248_280206_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt43_hu491c5fb6ab87c6995f4d38cb772a2248_280206_6addd6ca5d617e70f3bb9e9a26dc8db3.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;开始大叔式的怀旧环节，想当年我们看这几本书的时候，我们还那么年轻 :)&lt;/p&gt;
&lt;p&gt;唠叨几句：Rod Johnson 大叔(现在可能要称为大爷了) 是我最敬仰最崇拜的业界大神之一。做技术能做到他这水准，此生无憾。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt44_hu491c5fb6ab87c6995f4d38cb772a2248_277873_b56685c946c86d7365ba0b4a2b081eed.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt44_hu491c5fb6ab87c6995f4d38cb772a2248_277873_406c4d8152953468e4c0041ff9410d41.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt44_hu491c5fb6ab87c6995f4d38cb772a2248_277873_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt44_hu491c5fb6ab87c6995f4d38cb772a2248_277873_b56685c946c86d7365ba0b4a2b081eed.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在spring从2002年出道开始，这十几年间出了很多里程碑式版本，增加了很多重量级的功能。但是，个人评价，2014年spring boot的问世，才是最近三五年间spring最大的变革和重新思考。&lt;/p&gt;
&lt;p&gt;springboot的出现，代表着spring已经不再沉迷于贪吃蛇游戏，而是开始反省自身和自我改造，对于一个发展了十多年的老框架来说，认识到这点，远比加一两个新功能重要的多。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt45_hu491c5fb6ab87c6995f4d38cb772a2248_268920_e9803a577bda2169f4a66d663d9365f5.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt45_hu491c5fb6ab87c6995f4d38cb772a2248_268920_e3a6ef6c64cfa1f9ae1653ff3f4e11cd.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt45_hu491c5fb6ab87c6995f4d38cb772a2248_268920_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt45_hu491c5fb6ab87c6995f4d38cb772a2248_268920_e9803a577bda2169f4a66d663d9365f5.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;springboot的功能介绍。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt46_hu491c5fb6ab87c6995f4d38cb772a2248_270312_79a4fcbc0edd39ab657aac655bfb3f94.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt46_hu491c5fb6ab87c6995f4d38cb772a2248_270312_7ff42b3829c50d11654d27946414d9b4.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt46_hu491c5fb6ab87c6995f4d38cb772a2248_270312_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt46_hu491c5fb6ab87c6995f4d38cb772a2248_270312_79a4fcbc0edd39ab657aac655bfb3f94.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对 spring boot 总结，这也是我选择 spring boot 作为新的 dolphin 微服务框架的基石的重要理由。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt47_hu491c5fb6ab87c6995f4d38cb772a2248_288005_fb91cc20bf5dc66f70cb113001984596.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt47_hu491c5fb6ab87c6995f4d38cb772a2248_288005_a47916f953224ffd98343409c284ce3a.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt47_hu491c5fb6ab87c6995f4d38cb772a2248_288005_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt47_hu491c5fb6ab87c6995f4d38cb772a2248_288005_fb91cc20bf5dc66f70cb113001984596.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;spring cloud 出场，2015年才出来的新面孔。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt48_hu491c5fb6ab87c6995f4d38cb772a2248_250490_18c224d3b0b623f7a4fb8da9203e9576.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt48_hu491c5fb6ab87c6995f4d38cb772a2248_250490_6abaf9afd73adf712d995c53e4f48f60.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt48_hu491c5fb6ab87c6995f4d38cb772a2248_250490_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt48_hu491c5fb6ab87c6995f4d38cb772a2248_250490_18c224d3b0b623f7a4fb8da9203e9576.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;承载着spring对微服务架构领域的众望和抱负。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt49_hu491c5fb6ab87c6995f4d38cb772a2248_248884_477751ffeafade571f00d518353ea508.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt49_hu491c5fb6ab87c6995f4d38cb772a2248_248884_e2cf2358cd92a42ee39b386aba677112.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt49_hu491c5fb6ab87c6995f4d38cb772a2248_248884_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt49_hu491c5fb6ab87c6995f4d38cb772a2248_248884_477751ffeafade571f00d518353ea508.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;一出场，就是大量的子项目，这里只列出平时比较常用的一些：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt50_hu491c5fb6ab87c6995f4d38cb772a2248_307947_c68dd593dcf534e5bc9dfb22a83b06d5.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt50_hu491c5fb6ab87c6995f4d38cb772a2248_307947_e30079105c5e60967533543d3fe01ffa.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt50_hu491c5fb6ab87c6995f4d38cb772a2248_307947_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt50_hu491c5fb6ab87c6995f4d38cb772a2248_307947_c68dd593dcf534e5bc9dfb22a83b06d5.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt51_hu491c5fb6ab87c6995f4d38cb772a2248_255531_cf0191f43b2bf9039734eacbcd2e2992.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt51_hu491c5fb6ab87c6995f4d38cb772a2248_255531_484a046c9a07bf3e115e532b9baf2c6e.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt51_hu491c5fb6ab87c6995f4d38cb772a2248_255531_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt51_hu491c5fb6ab87c6995f4d38cb772a2248_255531_cf0191f43b2bf9039734eacbcd2e2992.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;Spring Cloud Netflix 子项目的出现，更像是spring之前的做事风格，做他最擅长的领域：集成。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt52_hu491c5fb6ab87c6995f4d38cb772a2248_243582_629286d1d2ae95e09cbb8308e2a2a875.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt52_hu491c5fb6ab87c6995f4d38cb772a2248_243582_da64a2f588f712b81f52a6608d753dc5.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt52_hu491c5fb6ab87c6995f4d38cb772a2248_243582_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt52_hu491c5fb6ab87c6995f4d38cb772a2248_243582_629286d1d2ae95e09cbb8308e2a2a875.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;以下内容是后面补充，没有在会场直接说，纯属个人吐糟：&lt;/p&gt;
&lt;p&gt;对spring cloud的个人评价：想法很好，出发点正确，市场空缺而切入的时机很合适。但是，spring cloud的实际表现，总给人一种束手束脚，瞻前顾后，小富即安的感觉。对比十几年前 Rod Johnson 大叔意气风发，气壮山河，谈笑间掀翻EJB的王座的表现，如今的spring cloud，能力不足，信心不够，格局太小，难成大器。期待后面能有转变。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;下面是对目前微服务框架的个人看法：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt53_hu491c5fb6ab87c6995f4d38cb772a2248_250083_8929e20300f9277ad20ffab3d0cc07c7.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt53_hu491c5fb6ab87c6995f4d38cb772a2248_250083_19749060bef9cb8cbea96a568bf3297f.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt53_hu491c5fb6ab87c6995f4d38cb772a2248_250083_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt53_hu491c5fb6ab87c6995f4d38cb772a2248_250083_8929e20300f9277ad20ffab3d0cc07c7.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;第三部分基础设施&#34;&gt;第三部分：基础设施&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt54_hu491c5fb6ab87c6995f4d38cb772a2248_245171_8fd2c7848af9bf291c8a55f34f64b416.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt54_hu491c5fb6ab87c6995f4d38cb772a2248_245171_81b73fa2c72f3481de9b4a071629907e.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt54_hu491c5fb6ab87c6995f4d38cb772a2248_245171_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt54_hu491c5fb6ab87c6995f4d38cb772a2248_245171_8fd2c7848af9bf291c8a55f34f64b416.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;由于演讲时间只有一个小时，因此基础设施的很多内容无法罗列，这次只是介绍了其中小部分的内容。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt55_hu491c5fb6ab87c6995f4d38cb772a2248_232099_880c8131ff3eb7132f9248d11e8e73be.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt55_hu491c5fb6ab87c6995f4d38cb772a2248_232099_0fcf1ab6e6ff1eda02e97962a68b9074.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt55_hu491c5fb6ab87c6995f4d38cb772a2248_232099_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt55_hu491c5fb6ab87c6995f4d38cb772a2248_232099_880c8131ff3eb7132f9248d11e8e73be.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;分布式配置管理的目前主流底层存储的方案，如果自己动手打造那么可选的无非就是下面这些：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt56_hu491c5fb6ab87c6995f4d38cb772a2248_252688_ded4fc3059d8832aaa643f189df01b03.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt56_hu491c5fb6ab87c6995f4d38cb772a2248_252688_356ffbea9acadadec6f5bc225e68744e.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt56_hu491c5fb6ab87c6995f4d38cb772a2248_252688_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt56_hu491c5fb6ab87c6995f4d38cb772a2248_252688_ded4fc3059d8832aaa643f189df01b03.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;也可以选择现有成型的开源产品：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt57_hu491c5fb6ab87c6995f4d38cb772a2248_280430_ef786d14975ca2ed377bbe1e4149ad4a.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt57_hu491c5fb6ab87c6995f4d38cb772a2248_280430_d405842c6a2c7fe5df47adf2dc8c6cbe.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt57_hu491c5fb6ab87c6995f4d38cb772a2248_280430_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt57_hu491c5fb6ab87c6995f4d38cb772a2248_280430_ef786d14975ca2ed377bbe1e4149ad4a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;APM领域的选择，商业产品很多，但是开源的选择实在不多：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt58_hu491c5fb6ab87c6995f4d38cb772a2248_287960_df39807ccb633dcd7212cd0b0097c095.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt58_hu491c5fb6ab87c6995f4d38cb772a2248_287960_d1456f3971d0237c7e2491f3651a149a.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt58_hu491c5fb6ab87c6995f4d38cb772a2248_287960_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt58_hu491c5fb6ab87c6995f4d38cb772a2248_287960_df39807ccb633dcd7212cd0b0097c095.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在日志分析领域，ELK是王者，但是也有新秀出场：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt59_hu491c5fb6ab87c6995f4d38cb772a2248_269881_1e180e469e2385fda3679f72b7082195.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt59_hu491c5fb6ab87c6995f4d38cb772a2248_269881_0e17a33d6e7c0a5ae056030620c8863d.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt59_hu491c5fb6ab87c6995f4d38cb772a2248_269881_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt59_hu491c5fb6ab87c6995f4d38cb772a2248_269881_1e180e469e2385fda3679f72b7082195.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 id=&#34;结束语&#34;&gt;结束语&lt;/h2&gt;
&lt;p&gt;洋洋洒洒的列举了几十个名字，但并不是让大家每个名字都去探索一遍，日常中如果需要做技术抉择，我有两句话：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;仰望星空，看弱水三千：眼界要开阔，知识面要广，哪怕只是精通各种名字，至少，知道在某个地方有个好东西，知道某个领域有其他的选择&lt;/li&gt;
&lt;li&gt;立足当下，吾只取一瓢：最终还是要落地的，能玩的转的东西才是好东西。另外，好东西虽多，找到一个能适合自己，能解决问题的就好了，别贪心，别贪多&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt61_hu491c5fb6ab87c6995f4d38cb772a2248_242815_d313f8082030f11211c0030cf9823ea6.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt61_hu491c5fb6ab87c6995f4d38cb772a2248_242815_2e7934e323396c93e95c0f4987ecf40b.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt61_hu491c5fb6ab87c6995f4d38cb772a2248_242815_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt61_hu491c5fb6ab87c6995f4d38cb772a2248_242815_d313f8082030f11211c0030cf9823ea6.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;

















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201610-build-microservice-by-open-source/images/ppt62_hu491c5fb6ab87c6995f4d38cb772a2248_219158_ffae767c710104b46fd8c190cd9b2a61.webp 400w,
               /talk/201610-build-microservice-by-open-source/images/ppt62_hu491c5fb6ab87c6995f4d38cb772a2248_219158_a57cd7f2864078862d71e0dc7a73402c.webp 760w,
               /talk/201610-build-microservice-by-open-source/images/ppt62_hu491c5fb6ab87c6995f4d38cb772a2248_219158_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201610-build-microservice-by-open-source/images/ppt62_hu491c5fb6ab87c6995f4d38cb772a2248_219158_ffae767c710104b46fd8c190cd9b2a61.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>PPMoney微服务之路</title>
      <link>https://skyao.net/talk/201608-ppmoney-microservice/</link>
      <pubDate>Sat, 13 Aug 2016 00:00:00 +0000</pubDate>
      <guid>https://skyao.net/talk/201608-ppmoney-microservice/</guid>
      <description>&lt;p&gt;备注：这个内容先后讲过两次：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;2016-08-13 在又拍云组织的 &amp;ldquo;Open Talk No.24 广州&amp;quot;做过一次线下演讲&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/opentalk_hu0f259447b9d9c5f67795cdec8c9349b9_102537_f93860421e0838acf3a2c1d19cf076b4.webp 400w,
               /talk/201608-ppmoney-microservice/images/opentalk_hu0f259447b9d9c5f67795cdec8c9349b9_102537_1f46a4de17e112135baeba1f0f346b61.webp 760w,
               /talk/201608-ppmoney-microservice/images/opentalk_hu0f259447b9d9c5f67795cdec8c9349b9_102537_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/opentalk_hu0f259447b9d9c5f67795cdec8c9349b9_102537_f93860421e0838acf3a2c1d19cf076b4.webp&#34;
               width=&#34;760&#34;
               height=&#34;505&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;2016-10 在中生代技术群进行了一次线上分享(第三十六期)&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/sharing_hub2f81b6b62ddf4b9e23feec5e0738919_128936_57f1052eafcd4843a8d3b418733d32d1.webp 400w,
               /talk/201608-ppmoney-microservice/images/sharing_hub2f81b6b62ddf4b9e23feec5e0738919_128936_96a393e932094d95ce88dd517fb628dd.webp 760w,
               /talk/201608-ppmoney-microservice/images/sharing_hub2f81b6b62ddf4b9e23feec5e0738919_128936_1200x1200_fit_q75_h2_lanczos.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/sharing_hub2f81b6b62ddf4b9e23feec5e0738919_128936_57f1052eafcd4843a8d3b418733d32d1.webp&#34;
               width=&#34;429&#34;
               height=&#34;760&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h1 id=&#34;ppmoney-微服务之路&#34;&gt;PPmoney 微服务之路&lt;/h1&gt;
&lt;h2 id=&#34;前言&#34;&gt;前言&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-1_hua2d7ea099624d03778c710f7ae88fc1b_595013_b3efeafcbd2dae2d037d818b9c9c71a5.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-1_hua2d7ea099624d03778c710f7ae88fc1b_595013_faed6318d2378ccf3bba493f10079640.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-1_hua2d7ea099624d03778c710f7ae88fc1b_595013_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-1_hua2d7ea099624d03778c710f7ae88fc1b_595013_b3efeafcbd2dae2d037d818b9c9c71a5.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;大家晚上好，今天给大家分享的内容是 PPmoney 微服务之路.&lt;/p&gt;
&lt;p&gt;首先简单介绍一下，我是来自 ppmoney 的资深架构师 敖小剑，目前负责 ppmoney 的基础架构和服务化推进。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-2_hu8bbc6b700921e17046c2500b0accbed3_657763_6f1265844de86319259be58c56b43a98.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-2_hu8bbc6b700921e17046c2500b0accbed3_657763_350baf48ea1c44855ac642b7255ea38c.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-2_hu8bbc6b700921e17046c2500b0accbed3_657763_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-2_hu8bbc6b700921e17046c2500b0accbed3_657763_6f1265844de86319259be58c56b43a98.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&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;h2 id=&#34;第一部分-为什么要选择微服务架构&#34;&gt;第一部分 为什么要选择微服务架构&lt;/h2&gt;
&lt;p&gt;我们先开始第一部分的内容：为什么要选择微服务架构？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-3_hu15ee8e1d95e15caceac0caf5f433ac0a_600050_28c50966a3d4b6237a23f3a740114a70.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-3_hu15ee8e1d95e15caceac0caf5f433ac0a_600050_69c49d9fa49e8f486f06080807804d9f.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-3_hu15ee8e1d95e15caceac0caf5f433ac0a_600050_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-3_hu15ee8e1d95e15caceac0caf5f433ac0a_600050_28c50966a3d4b6237a23f3a740114a70.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;先简单介绍一下我们公司——PPmoney(万惠).&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-4_hu91e929830324c1ef4d26e81b1a61f979_628319_155b9b3a1ce6267625df102c4607d801.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-4_hu91e929830324c1ef4d26e81b1a61f979_628319_be26f0da9d98434a421606ac62adf0be.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-4_hu91e929830324c1ef4d26e81b1a61f979_628319_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-4_hu91e929830324c1ef4d26e81b1a61f979_628319_155b9b3a1ce6267625df102c4607d801.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;4年做到600亿元，企业可以说是 野蛮生长。在快速发展的同时，沉积的问题也很多。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-5_hu7452708e1e7012521390259b08b0b257_681662_82c4f54aba25d3cb9a32eafa28b059fd.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-5_hu7452708e1e7012521390259b08b0b257_681662_026c4175dfda1e9066e8855a1489dad9.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-5_hu7452708e1e7012521390259b08b0b257_681662_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-5_hu7452708e1e7012521390259b08b0b257_681662_82c4f54aba25d3cb9a32eafa28b059fd.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;大多数创业公司在初期技术上是很郁闷的，没有足够的技术基础，所以早期技术栈会呈现多样化。造成多样化的原因，首先是“黑猫白猫，能上线就是好猫”：只要能把代码写出来、能上线，就OK；第二个是怎么快怎么来？包括买。举个例子，编程语言我们现在有php，.net,java,c++&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;问题随即暴露，规划不足、实施艰难；需求太多，来不及规划；变更太快，规划跟不上；还有非技术的原因比如人员变动频繁。整个野蛮生长的过程中，技术债务会越来越多，开发成本会越来越高。现在在加新的功能，会比想象中的要难得多。而且，最严重的是出现了“恶性循环”。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-6_hu9c86bafcd9b049c906128851beea4bf4_727742_048da283acfce3f5ef99cf33f88c98a7.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-6_hu9c86bafcd9b049c906128851beea4bf4_727742_f0a20a2dc0a299563f09f344a9a218a2.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-6_hu9c86bafcd9b049c906128851beea4bf4_727742_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-6_hu9c86bafcd9b049c906128851beea4bf4_727742_048da283acfce3f5ef99cf33f88c98a7.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;而对于互联网金融企业，应对市场的速度必须要足够快，否则难于立足。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-7_hu99036ab418c50c453bd0daaa8a49e819_637884_3dc967275b73a205ce10649dac914383.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-7_hu99036ab418c50c453bd0daaa8a49e819_637884_5b394a65d4c43da0940008c35c44dcaf.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-7_hu99036ab418c50c453bd0daaa8a49e819_637884_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-7_hu99036ab418c50c453bd0daaa8a49e819_637884_3dc967275b73a205ce10649dac914383.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;如漫画中所示，我们出现几个问题：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;方法不得当，开发效率非常低，&lt;/li&gt;
&lt;li&gt;问题积累，工程师不堪重负&lt;/li&gt;
&lt;li&gt;没有时间改进，咬牙硬扛&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;即使给工程师现成的改进方案，他也会拒绝接受：我们很忙，我们没有时间。&lt;/p&gt;
&lt;p&gt;这是一个令人心酸的局面，双方都很无奈。&lt;/p&gt;
&lt;p&gt;我们改进的方向:&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-8_hu1542b1f4e1a7b5febbc0ff2185064e0b_592096_8ca72f37ecceab8a44dcf9876dca201b.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-8_hu1542b1f4e1a7b5febbc0ff2185064e0b_592096_5a208ce7ae663aad5d3c06be36c979db.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-8_hu1542b1f4e1a7b5febbc0ff2185064e0b_592096_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-8_hu1542b1f4e1a7b5febbc0ff2185064e0b_592096_8ca72f37ecceab8a44dcf9876dca201b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;首先事情要规范化，让无序的开发变成有序。无序的开发是什么概念？逮到哪就做到哪，至于用什么技术：有什么人用什么，会什么用什么。有序的开发有很重要的事情，叫做“统一”，同时简化技术栈。&lt;/li&gt;
&lt;li&gt;第二个就是要“可重用”。之前的项目都是从头开始或者是从上一个项目里头复制过来，这里面是有很多事情没有做好的：基础类库、基础设施、基础架构。做这些最终的目标是提升大家的项目起点，所谓&amp;quot;不要输在起跑线上&amp;rdquo;。&lt;/li&gt;
&lt;li&gt;第三个是“敏捷”。这个东西对我们而言做得非常不好，现在基本上是属于没有的状态。虽然各个团队都在宣称敏捷，但是实际做的不太好。&lt;/li&gt;
&lt;li&gt;第四个就是“自动化”。这个就是我们希望能改进的一个重点，包括自动化测试、自动化部署、云技术、容器化等，解决这个问题的最终的目标：摆脱低级重复。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-9_hu5cd5996929e0c417e8c2e3833befd5bc_688432_203e24b9f58e9a3a2a601b14487370bf.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-9_hu5cd5996929e0c417e8c2e3833befd5bc_688432_949d938a772ab09dd203e61ac90a57e8.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-9_hu5cd5996929e0c417e8c2e3833befd5bc_688432_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-9_hu5cd5996929e0c417e8c2e3833befd5bc_688432_203e24b9f58e9a3a2a601b14487370bf.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;DevOps和每日发布是我们的最终目标，虽然从目前看差距还非常大。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-10_hue5f1e2cfece0c1deebd070a48a71e03c_893079_200ff1e9bb24b6a30baf45c3077e7bb2.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-10_hue5f1e2cfece0c1deebd070a48a71e03c_893079_5fda139203f2a97d93496e1f71ebd150.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-10_hue5f1e2cfece0c1deebd070a48a71e03c_893079_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-10_hue5f1e2cfece0c1deebd070a48a71e03c_893079_200ff1e9bb24b6a30baf45c3077e7bb2.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们最终的选择是推行服务化，以微服务架构为目标进行技术转型。&lt;/p&gt;
&lt;p&gt;微服务的概念和好处这里就不展开。&lt;/p&gt;
&lt;h3 id=&#34;第二部分-dolphin-微服务框架的技术选型&#34;&gt;第二部分 dolphin 微服务框架的技术选型&lt;/h3&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-11_hu64b8d08259809d482ab4c4567ec40db4_600825_9cbc3cc1191ad7fcd2f9bb07e6175557.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-11_hu64b8d08259809d482ab4c4567ec40db4_600825_f976930f070b9d9b2000d53652f08eda.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-11_hu64b8d08259809d482ab4c4567ec40db4_600825_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-11_hu64b8d08259809d482ab4c4567ec40db4_600825_9cbc3cc1191ad7fcd2f9bb07e6175557.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;接下来我们开始第二部分的内容，讲一下我们微服务框架的技术选型。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-12_hu4ab9357e70061d6602652f14e7a40dd9_616290_bea654fc7d6e51472987bde53dc8ad9c.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-12_hu4ab9357e70061d6602652f14e7a40dd9_616290_8a8b268481e6ecaa9831852a1029b793.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-12_hu4ab9357e70061d6602652f14e7a40dd9_616290_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-12_hu4ab9357e70061d6602652f14e7a40dd9_616290_bea654fc7d6e51472987bde53dc8ad9c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是 PPmoney 自行开发的微服务框架，海豚，英文名 Dolphin。希望这个框架做的敏捷、轻快、优雅，就像海豚一样。&lt;/p&gt;
&lt;p&gt;开发工作从今年3月份刚开始，目前版本到了 0.7.*，已经在线上跑了。另外后面会提到，我们最重要的一个大系统已经基于这个框架做了重构(或者说重写)，即将在10月上线。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-13_hua25a20a7363a0aac2acc1bae97194c90_513930_48670c47372af58b02680af5b62ffc0a.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-13_hua25a20a7363a0aac2acc1bae97194c90_513930_3681ed4075fd2ddfcf2bbf4155120094.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-13_hua25a20a7363a0aac2acc1bae97194c90_513930_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-13_hua25a20a7363a0aac2acc1bae97194c90_513930_48670c47372af58b02680af5b62ffc0a.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们的小目标：打造业界一流的微服务框架。&lt;/p&gt;
&lt;p&gt;Dolphin要打通整个业务的全流程，这个可能是跟其他微服务框架极为不同，这也是我们技术选型的一个重要的基石。&lt;/p&gt;
&lt;p&gt;通常来说的微服务框架覆盖的都是服务器端，不同的的服务器之间的调用。但是这里我们会有一个非常重要的需求，我们必须要把手机App覆盖到。为什么要加这个需求？一个简单的数字足以说明：目前80%成交额来自于手机App。因此我们除了考虑服务器端之外，要考虑从手机App到服务器端的数据通讯。&lt;/p&gt;
&lt;p&gt;我们希望它能覆盖日常的开发场景，包括手机App开发、Web服务器开发、应用服务。另外要实现的一个目标就是要三位一体，也就是上面这句话，“打通开发、测试、运维三条线”，实现整个流程的畅通，最终实现全程自动化。&lt;/p&gt;
&lt;p&gt;我们看一下Dolphin的主要技术栈：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-14_hu472e5553e7fb27d5ebb1b2043ccea7da_720195_1315f49e6cc33bcab63f6f2c0649ceda.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-14_hu472e5553e7fb27d5ebb1b2043ccea7da_720195_4261cfcb3b41b1fd4740b097f1a024cd.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-14_hu472e5553e7fb27d5ebb1b2043ccea7da_720195_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-14_hu472e5553e7fb27d5ebb1b2043ccea7da_720195_1315f49e6cc33bcab63f6f2c0649ceda.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Google开源的gRPC框架，支持多平台多语言，最大的优点是支持手机App。&lt;/li&gt;
&lt;li&gt;SpringBoot，Spring团队集大成之做，口碑非常好，好用易上手。&lt;/li&gt;
&lt;li&gt;Etcd3，2016年7月1号才发布，够新鲜，主要用于服务发现和配置&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;首先介绍一下gPRC。这是 google 新推出来的 RPC 框架，今年8月才发布的 1.0 正式版。gPRC 的主要特性：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-15_hu73a2ea0796eca03b14b4e8bb7bec2fde_668715_545869ef17ed9655caf954264502314b.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-15_hu73a2ea0796eca03b14b4e8bb7bec2fde_668715_81a3d9603f4502831769ab23366e6d76.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-15_hu73a2ea0796eca03b14b4e8bb7bec2fde_668715_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-15_hu73a2ea0796eca03b14b4e8bb7bec2fde_668715_545869ef17ed9655caf954264502314b.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Protocol Buffer 3.0：最重要的改进就是可以支持 iOS 和 android&lt;/li&gt;
&lt;li&gt;HTTP/2 协议：出来有几年了，目前正在慢慢铺开&lt;/li&gt;
&lt;li&gt;netty 4.1：提供NIO支持和 HTTP/2支持，也是今年6月才刚发布的正式版本&lt;/li&gt;
&lt;li&gt;对Android/iOS的支持，这对我们来说是杀手锏级的特性&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;gPRC 的主要特性：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-16_hub09b95c739f633842c830723c79f4e41_692891_dacfbc5f8b71e20c69d946a888ffc2f2.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-16_hub09b95c739f633842c830723c79f4e41_692891_3f1c5537fafa29d5e480f9607696ce05.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-16_hub09b95c739f633842c830723c79f4e41_692891_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-16_hub09b95c739f633842c830723c79f4e41_692891_dacfbc5f8b71e20c69d946a888ffc2f2.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;有两个特性对我们来说特别的重要：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;多路复用，可以全双工发送请求和接收应答，不再需要连接池，即使几万 QPS 也是可以一条 socket 搞定。&lt;/li&gt;
&lt;li&gt;支持流/stream，在流的基础上实现了Server Push，方便做变更通知，不再需要客户端做费力的 Long Pull。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-17_huec05e25214f4fd7694c80cf36bb92b0a_658142_d71faa8064abd68d39d0700c015957fb.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-17_huec05e25214f4fd7694c80cf36bb92b0a_658142_e3ce2e50755f3837fce97a5992355e9d.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-17_huec05e25214f4fd7694c80cf36bb92b0a_658142_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-17_huec05e25214f4fd7694c80cf36bb92b0a_658142_d71faa8064abd68d39d0700c015957fb.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;google 给 gRPC 的地位中就明确提出：将移动和HTTP/2 放在首位。刚好契合我们的需求，因此成为我们dolphin微服务框架中最重要的一个技术选型目标。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-18_hu98e9d1349e248ea5690e63016cfec1b0_673847_36bc163520586e9934b7b5604fe12d67.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-18_hu98e9d1349e248ea5690e63016cfec1b0_673847_133819db82ad62393bf5fa26dd38fea0.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-18_hu98e9d1349e248ea5690e63016cfec1b0_673847_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-18_hu98e9d1349e248ea5690e63016cfec1b0_673847_36bc163520586e9934b7b5604fe12d67.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们选择了 Spring Boot 作为微服务框架的基石，这也是业界常见做法。暂时没有选择 spring cloud，主要是技术选项和我们差异比较大。&lt;/p&gt;
&lt;p&gt;在3月份我们做技术选项时，在 zookeeper，etcd， consul 之间我们最后选择了 consul。但是在7月1日 etcd 的 3.0 版本发布之后，我们决定将 consul 替换为 etcd 3.0。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-19_hu7a620839c72681f066860d0f717688f3_480136_0f079db35dcd29001705dfd6fd284f64.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-19_hu7a620839c72681f066860d0f717688f3_480136_db629095d80c0238713a9385341789e3.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-19_hu7a620839c72681f066860d0f717688f3_480136_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-19_hu7a620839c72681f066860d0f717688f3_480136_0f079db35dcd29001705dfd6fd284f64.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;因为我们觉得 Etcd3 更适合 Dolophin 框架。注意我说的是更适合，不是说 etcd3 更好。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-20_hue50561f42016854190e8a36fa4e86642_670731_2222ab1c70e1c3fa1df1436ed002c735.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-20_hue50561f42016854190e8a36fa4e86642_670731_0891e5923a51cc5164b4fc449792ef1f.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-20_hue50561f42016854190e8a36fa4e86642_670731_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-20_hue50561f42016854190e8a36fa4e86642_670731_2222ab1c70e1c3fa1df1436ed002c735.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;使用 etcd3 替代 consul 的几个理由：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;统一通讯协议：新发布的 Etcd3 给了我们一个很大的惊喜：它的通讯机制改了，Etcd3 改用 gRPC 作为通讯机制，替代原有的rest。因为 Dolphin 框架也是使用 gRPC，因此改用 etcd3 替代 consul 之后就简化了内部通讯机制，都统一为 gRPC 了。&lt;/li&gt;
&lt;li&gt;减少依赖：不用 consul 之后从而也省掉了 consul client 端引入的一大堆的用来实现 rest 和 long pull 的依赖包&lt;/li&gt;
&lt;li&gt;性能提升：这个容易理解，gRPC 是二进制格式，对 REST 明显速度肯定是优势&lt;/li&gt;
&lt;li&gt;更高效的推送机制：基于HTTP/2 stream 的服务器端推送机制，效率比基于 long pull 的高，考虑到除了服务发现之后，未来还要做配置变更的通知，而且配置项的数量远远超过服务的数量，这个带来的提升会更大。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-21_hu4cac35c204b30f98922851372c5c6967_744993_11ff5d1372522a4cf2d517d1ace255de.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-21_hu4cac35c204b30f98922851372c5c6967_744993_a7419be4e8de53205a0c5d8abf919bca.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-21_hu4cac35c204b30f98922851372c5c6967_744993_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-21_hu4cac35c204b30f98922851372c5c6967_744993_11ff5d1372522a4cf2d517d1ace255de.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是目前的开发路线图，包括 dolphin 框架外围的一些基础设施，我们预计在年底前能完成微服务框架必备的大部分基础功能。&lt;/p&gt;
&lt;h2 id=&#34;第三部分-微服务生态中的支撑体系&#34;&gt;第三部分 微服务生态中的支撑体系&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-22_huad2a89bd19c0a2265a8a5c0030390b60_603802_53d11ed7bcdc8b0f12be95ae2abbc650.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-22_huad2a89bd19c0a2265a8a5c0030390b60_603802_db4e120abbea8aa78bf4e0eda5eb220d.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-22_huad2a89bd19c0a2265a8a5c0030390b60_603802_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-22_huad2a89bd19c0a2265a8a5c0030390b60_603802_53d11ed7bcdc8b0f12be95ae2abbc650.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&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;p&gt;把框架做好之后，是不是就可以简单的可以在一家公司里推行微服务？我遗憾地告诉大家，这个没有什么必然的关系，并不是你有了微服务的框架，就可以把后面的事情做好。用数学的术语说，微服务框架只是一个 &lt;strong&gt;必要不充分&lt;/strong&gt; 条件。&lt;/p&gt;
&lt;p&gt;微服务不是银弹，不能指望微服务单枪匹马的解决问题，“只要微服务一出来，就轻轻松松搞定。” 这种想法不现实。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-23_hu198033449f9e923da80f79f8e3dfaa2c_1095769_7acb3206754078eedaef01bbfeca5fc2.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-23_hu198033449f9e923da80f79f8e3dfaa2c_1095769_9e24f17bce77486ff9e04d97d3ab9ddb.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-23_hu198033449f9e923da80f79f8e3dfaa2c_1095769_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-23_hu198033449f9e923da80f79f8e3dfaa2c_1095769_7acb3206754078eedaef01bbfeca5fc2.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;左边是幻想，右边是现实。&lt;/p&gt;
&lt;p&gt;微服务框架需要一系列的基础设施，作为整个微服务体系的基石。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-24_hu1eebe07ffc3c31ae5dc7ba76ada91e68_665049_b6865e5d102fc60d00690692db318184.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-24_hu1eebe07ffc3c31ae5dc7ba76ada91e68_665049_3147cc51700b9576cc78a1908e6d81e7.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-24_hu1eebe07ffc3c31ae5dc7ba76ada91e68_665049_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-24_hu1eebe07ffc3c31ae5dc7ba76ada91e68_665049_b6865e5d102fc60d00690692db318184.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这里面有些是微服务框架的标配，比如实现中央化配置管理的配置中心，管理服务实施服务治理的服务中心。有些是完全和微服务框架没有直接联系，但是又是微服务框架必备的，比如APM/应用性能监控，日志管理如ELK套件等。&lt;/p&gt;
&lt;p&gt;在上述的基础上，还需要进一步完善整个生态体系，比如以服务的方式直接提供部分通用功能。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-25_hu9973354905be3477e6778f54eae3685d_479879_dd2687955846cbb116d1a15cf25d4852.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-25_hu9973354905be3477e6778f54eae3685d_479879_4de8feaca2a77da014af51d34f1464cc.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-25_hu9973354905be3477e6778f54eae3685d_479879_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-25_hu9973354905be3477e6778f54eae3685d_479879_dd2687955846cbb116d1a15cf25d4852.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;图中是我们在实施中的一些实际例子：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;我们在 dolphin 框架中内置加密服务，限流服务，配合实现框架的基本功能。&lt;/li&gt;
&lt;li&gt;鉴权服务，统一的短信网关，验证码服务等，这些实际和框架就没有直接关系了，而是作为通用业务平台的一部分&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-26_hu13a36a38dca16f7d3a3ab3c310eeb549_692813_fdc24eb4ff109170245a0f385df75867.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-26_hu13a36a38dca16f7d3a3ab3c310eeb549_692813_cd1ceeccab44808634aa0cd8f372b8da.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-26_hu13a36a38dca16f7d3a3ab3c310eeb549_692813_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-26_hu13a36a38dca16f7d3a3ab3c310eeb549_692813_fdc24eb4ff109170245a0f385df75867.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;对于 微服务 和 docker，只能用天作之合来形容。&lt;/p&gt;
&lt;p&gt;docker 这块我们现在涉猎的不多，暂时还处于探索阶段，后面微服务框架基本成型之后肯定要继续铺开的。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-27_hu31cd80e25421147fa6ff5e8e6726f797_597600_272000ead3663955b20bb93087969a5c.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-27_hu31cd80e25421147fa6ff5e8e6726f797_597600_329f9657d8ec54346a62a1c40a22bd70.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-27_hu31cd80e25421147fa6ff5e8e6726f797_597600_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-27_hu31cd80e25421147fa6ff5e8e6726f797_597600_272000ead3663955b20bb93087969a5c.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;在第三部分的最后，我们总结一下实施微服务的四个要点。在微服务的实施的过程中，要真正的要把微服务做好，必须认真考量这些的足以决定成败的因素：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;敏捷开发&lt;/p&gt;
&lt;p&gt;敏捷是必备的，如果是敏捷都没有做到，微服务真的是“连爬都还不会就想跑”。有时候微服务一上手发现不合适了，做这个东西之前先自问一下，敏捷开发是不是跑起来了，团队是不是用敏捷的方式做开发？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;组织决定架构&lt;/p&gt;
&lt;p&gt;规划一个技术框架或者是技术路线的时候，需要考虑组织架构是不是和技术框架匹配。如康威定律所说，“组织决定架构”。为了实现服务化，你必须要让你的组织结构做出相应的调整。需要组建跨功能的团队，这个团队一定不是单纯的只有开发、只有测试、只有运维，或者是只有产品，这些功能应该都在你的团队里头。最重要的是要减少部门墙带来的沟通成本。这个墙是非常可怕的一件事情，它可以让一个小时能做的东西，一个星期都做不完。&lt;/p&gt;
&lt;p&gt;建议微服务团队按照业务而不是按照技术来划分组织，必须要想办法在一个团队内全栈，让团队自治。这个是我们现在试图想做的，但坦白说这个事情很难,有时甚至是绝望。&lt;/p&gt;
&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;li&gt;
&lt;p&gt;团队&lt;/p&gt;
&lt;p&gt;所有的问题，最终都会归根到人的问题。为了玩的转微服务，你得打造一支能满足高要求的团队，这个要求是真的比较高：产品，设计、开发 、测试都要搞得定，可能是三五个人，甚至七八个人，要一个团队啃下产品线，包括前端、后端、测试、运维和产品。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;对大多数公司来说，这四个要点完全做到还是挺难的。前面我们提到的服务化框架，各种技术选型，各种配套的基础设施，都是硬性条件，都是技术性的支撑。而这四点，则更多的是在人文条件方面提出的要求。&lt;/p&gt;
&lt;h2 id=&#34;第四部分-旧有系统的迁移改造&#34;&gt;第四部分 旧有系统的迁移改造&lt;/h2&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-28_hube1382e2d836928faa4d7bf6fdeed5b9_603164_aadd679f468cc69f68713910488013f4.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-28_hube1382e2d836928faa4d7bf6fdeed5b9_603164_33d2843100882a86489ea00ab2b854fc.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-28_hube1382e2d836928faa4d7bf6fdeed5b9_603164_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-28_hube1382e2d836928faa4d7bf6fdeed5b9_603164_aadd679f468cc69f68713910488013f4.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;下面我们开始最后一个部分的分享，谈一下我们最近的一个实际例子，在这个例子中我们是如何改造我们的一个App架构和团队，来实现微服务在实际产品中的落地。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-29_hue18c8ec1b701b9d3b2bc06af98449337_577070_75283c93e17e074af446484b629aa419.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-29_hue18c8ec1b701b9d3b2bc06af98449337_577070_8f4f15a1208a00eca0bfd25c2a5ea7f5.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-29_hue18c8ec1b701b9d3b2bc06af98449337_577070_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-29_hue18c8ec1b701b9d3b2bc06af98449337_577070_75283c93e17e074af446484b629aa419.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这是我们的ppmoney理财App(也就是前面说的80%营收的核心产品)，原有的架构足够简单而原始：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;app和服务器后台是常见的Restful&lt;/li&gt;
&lt;li&gt;中间是一个巨型的服务器后台程序：很要命，因为所有代码都堆在一个WAR中&lt;/li&gt;
&lt;li&gt;底层还好，一些基本功能被封装成SOA，难得。但是，用的语言是.net，然后通讯机制是以慢著称的SOAP&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;改造的第一个阶段，我们的目标是引入dolphin框架和实现基本的服务拆分：&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-30_hudeb1d7bf7be7249400465e2468991ac9_592977_fb0264645613ee40ba478d639bc7fb73.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-30_hudeb1d7bf7be7249400465e2468991ac9_592977_d5bceaf94b296a7acc4c0d7a9f0ad449.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-30_hudeb1d7bf7be7249400465e2468991ac9_592977_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-30_hudeb1d7bf7be7249400465e2468991ac9_592977_fb0264645613ee40ba478d639bc7fb73.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;首先app和服务器端改用gRPC&lt;/li&gt;
&lt;li&gt;引入 API Gateway来负责网络接入，然后按照业务逻辑进行服务编排，必要时在API Gateway中可以使用缓存&lt;/li&gt;
&lt;li&gt;将原有的war按照业务边界拆分为若干个服务，每个服务有自己的数据存储，缓存&lt;/li&gt;
&lt;li&gt;某些服务可能只是对SOA接口做一个转发和封装汇总&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这个工作我们目前基本完成，预计测试通过之后，10月份我们就会上线，逐步替代原有的APP和后台。完成之后系统的性能瓶颈可以得到极大缓解，部署弹性大为增强。&lt;/p&gt;
&lt;p&gt;改造的第二个阶段，目标是将现有.net的SOA用Java改写，让前面拆分出来的微服务变成完整的标准微服务。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-31_hu100937bffa7e9610709279c29712b7b5_585440_7c773fe34aa18a7b9d0601a5ff031f06.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-31_hu100937bffa7e9610709279c29712b7b5_585440_084d579eeb5e255cf7ffa54aa7861401.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-31_hu100937bffa7e9610709279c29712b7b5_585440_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-31_hu100937bffa7e9610709279c29712b7b5_585440_7c773fe34aa18a7b9d0601a5ff031f06.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这个工作还没有开始，坦白说这个工作量比第一阶段要复杂的多，SOA中负责的业务逻辑，相互关联调用的模块耦合，一个又一个的关联查询，挑战极大。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-32_huf14d3660f3b570dec9efcd71118a4607_1094733_4e96226323dbfe870e0b2fb2991236f0.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-32_huf14d3660f3b570dec9efcd71118a4607_1094733_e9b72199372d6073322705e34d50a2a8.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-32_huf14d3660f3b570dec9efcd71118a4607_1094733_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-32_huf14d3660f3b570dec9efcd71118a4607_1094733_4e96226323dbfe870e0b2fb2991236f0.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们再讨论一下人员和团队的问题，好的团队从来不是天上掉下来的，因此如何打造团队成为重点。&lt;/p&gt;
&lt;p&gt;在这里我们的做法是这样，分两步：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;把架构部门打造成高素质的敏捷团队&lt;/p&gt;
&lt;p&gt;这个是必须的，这个如果做不到，后面没得玩。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;然后再孵化满足要求的新型业务开发团队&lt;/p&gt;
&lt;p&gt;这个地方有一个很逗的词，孵化。为什么是孵化呢？因为很多时候情况下，即使你做到了第一步，你也仅仅是有一支架构部门的团队，而且也不可能满足整个公司业务各个产品线的需要的，你还要把整个的业务线的开发团队提升上来。&lt;/p&gt;
&lt;p&gt;如何做到这一点很重要，要想办法自己去培养、改造业务团队。我们称之为“孵化”，就是带领一支业务团队，跟他一起去做业务改造，在改造的过程中，顺带将新的团队带起来。过程感觉就像孵小鸡一样，需要耐心，需要投入，新的团队开始很弱小，但是未来的成长值得期待和投入。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这里依然要继续给大家泼凉水，理想和现实之间的差距，往往是远超事前的想象。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-33_hu03d8a5754a71a196ae87c96999548616_474497_c456b34d4339ad2efbb2f565e1e6f18f.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-33_hu03d8a5754a71a196ae87c96999548616_474497_f2e2aa0ff20125fb7d9f4e72669a99e4.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-33_hu03d8a5754a71a196ae87c96999548616_474497_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-33_hu03d8a5754a71a196ae87c96999548616_474497_c456b34d4339ad2efbb2f565e1e6f18f.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;下面我们以过来人的角度(其实也只是才上路)，给大家分析一下微服务推进的实际道路中常见的问题和难点。&lt;/p&gt;
&lt;p&gt;计划一开始都是很美好，但是在实施前，请先自问一个问题：资金、技术、专家，这三者是否已经齐备？&lt;/p&gt;
&lt;p&gt;这里有个很有意思的故事：就在今年，习总书记访问英国的时候，英国BBC记者问“英企能否在中国投资建设核电站”，中国驻英大使刘晓明反问：你们有资金吗？你们有技术吗？你们有专家吗？&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-34_hu6c59479d69d03eb7b4cc6f4a31f2185c_956943_3dfa00e244a9a783fa0eb617d17af970.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-34_hu6c59479d69d03eb7b4cc6f4a31f2185c_956943_896b3ecb563b11b3da89c60de3ac424c.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-34_hu6c59479d69d03eb7b4cc6f4a31f2185c_956943_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-34_hu6c59479d69d03eb7b4cc6f4a31f2185c_956943_3dfa00e244a9a783fa0eb617d17af970.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;我们为什么要提这个话题呢？因为一个公司要真正的提升上去，也要问一下自己有没有这三个要素：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;第一个是资金，你要组建团队，要在整个公司推广，把所有的流程都走通，投入巨大；&lt;/li&gt;
&lt;li&gt;第二个是技术：前面我们罗列了一堆&lt;/li&gt;
&lt;li&gt;第三个是专家：尤其是在业务团队，尤其是中小公司，一般业务团队只有一两个核心开发人员，有时甚至一个都微服务的都没有，更恶劣时，连一个有基本架构设计基础和模块理念的都没有&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;特别强调：第三点尤其致命，而且通常都是被高层忽略或者不认可，后者带来的问题更加麻烦。&lt;/p&gt;
&lt;p&gt;注意，虽然说微服务不是银弹，但微服务真是一个大炸弹！&lt;/p&gt;
&lt;p&gt;微服务所带来的变革是巨大的，当推行服务化，推广微服务框架的时候，远不是简单的微服务框架的技术推广问题。这个事情远比用mongo替代mysql要严重的多。推广微服务，往往是在实际上&lt;strong&gt;推翻整个公司的开发流程&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;微服务是真正意义上的颠覆性变革，或者用另外一个词会更准确：革命！&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-35_hu65262fd6b2c5de0963588f5ebcd09254_975014_7bf1ea6698d35ec36c3e85f2dd1af986.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-35_hu65262fd6b2c5de0963588f5ebcd09254_975014_c8edfe2ba58a71bfeb852f4631671e7d.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-35_hu65262fd6b2c5de0963588f5ebcd09254_975014_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-35_hu65262fd6b2c5de0963588f5ebcd09254_975014_7bf1ea6698d35ec36c3e85f2dd1af986.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;要推行微服务，要把这些东西通通跑通，而且做顺、做好，你的微服务框架才能真正落到实处。如果有一个卡住，就会发现经被念歪了，或者走路的时候感觉是腿瘸了一般。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-36_hu6abfeca1968d72a4c2200ebdefae8d5e_576818_7ef95cb1d530bbc3e79a54fbbc89454d.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-36_hu6abfeca1968d72a4c2200ebdefae8d5e_576818_ac04f582ff87420370878f7588b7ad3c.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-36_hu6abfeca1968d72a4c2200ebdefae8d5e_576818_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-36_hu6abfeca1968d72a4c2200ebdefae8d5e_576818_7ef95cb1d530bbc3e79a54fbbc89454d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;再一次重申&lt;strong&gt;康威定律&lt;/strong&gt;！&lt;/p&gt;
&lt;p&gt;对于任何一个试图推行微服务的架构师而言，康威定律是一道绕不开的槛。如果没有高层强力支持并愿意为此调整组织结构，就必然在这里遇到无法逾越的阻碍。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-37_hufa2166a2e28272322e6d3fc19fe5ae76_621688_a62be27f935a6b265f99b634f83b53cd.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-37_hufa2166a2e28272322e6d3fc19fe5ae76_621688_2091ddb2e56ba8678980cc05ba637d5b.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-37_hufa2166a2e28272322e6d3fc19fe5ae76_621688_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-37_hufa2166a2e28272322e6d3fc19fe5ae76_621688_a62be27f935a6b265f99b634f83b53cd.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;这个画面绝不是只会出现在漫画中&amp;hellip;&amp;hellip; 请做好心理准备。&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-38_hub4d647a2f2f3fa9476b10e1dc79cff2b_512110_52aa0483bad468af5c9d5e2cd2ce0199.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-38_hub4d647a2f2f3fa9476b10e1dc79cff2b_512110_8612f43c666c9eb52ec1a897035bd5e2.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-38_hub4d647a2f2f3fa9476b10e1dc79cff2b_512110_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-38_hub4d647a2f2f3fa9476b10e1dc79cff2b_512110_52aa0483bad468af5c9d5e2cd2ce0199.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;最后介绍一下我们的开源计划，目前的时间计划是这样：2016年底。&lt;/p&gt;
&lt;p&gt;但是，如果出现不可抗力，则无法预期&amp;hellip;&amp;hellip;&lt;/p&gt;
&lt;p&gt;















&lt;figure  &gt;
  &lt;div class=&#34;d-flex justify-content-center&#34;&gt;
    &lt;div class=&#34;w-100&#34; &gt;&lt;img alt=&#34;&#34; srcset=&#34;
               /talk/201608-ppmoney-microservice/images/ppt-39_hu816e7d3efed4771e016ba72aa8583a1c_618443_29ddf5657965bdcfabcc7cb46e52eb6d.webp 400w,
               /talk/201608-ppmoney-microservice/images/ppt-39_hu816e7d3efed4771e016ba72aa8583a1c_618443_1261d5e7fbcc12c52bb2d3a88f630d75.webp 760w,
               /talk/201608-ppmoney-microservice/images/ppt-39_hu816e7d3efed4771e016ba72aa8583a1c_618443_1200x1200_fit_q75_h2_lanczos_3.webp 1200w&#34;
               src=&#34;https://skyao.net/talk/201608-ppmoney-microservice/images/ppt-39_hu816e7d3efed4771e016ba72aa8583a1c_618443_29ddf5657965bdcfabcc7cb46e52eb6d.webp&#34;
               width=&#34;760&#34;
               height=&#34;428&#34;
               loading=&#34;lazy&#34; data-zoomable /&gt;&lt;/div&gt;
  &lt;/div&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;个人非常的期待在年底，在github，这只可爱的小海豚可以和大家见面。&lt;/p&gt;
&lt;p&gt;谢谢大家参与今天的分享，我们的内容到这里结束，谢谢大家！&lt;/p&gt;
&lt;h2 id=&#34;问答环节&#34;&gt;问答环节&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;问题1：微服务和服务化的关系是什么&lt;/p&gt;
&lt;p&gt;服务化是微服务的超级，服务化在很早之前就有提出并推行，典型如SOA。而微服务是最近才兴起，和服务化的最大差异在意服务化明确的将粒度调整为不能再小的&amp;quot;微&amp;quot;，同时明确提出必须做到：1. 独立进程 2. 数据分离&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题2:  服务治理应该包含那些内容，现在有那些工具可以用？&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题3: 请比较一下各技术堆栈，如果搭建微服务，最佳工具是哪些？&lt;/p&gt;
&lt;p&gt;这两个问题都比较大，不是三言两语能阐述清楚，每个话题都够再来开一两回今天的演讲 ~0~&lt;/p&gt;
&lt;p&gt;比较巧的是，在10月15日的中生带线下活动中，我会带来一个新的演讲，主题是如何利用开源社区来搭建微服务系统，届时会有详细的介绍和讨论，欢迎关注。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题4： 使用微服务后，业务接入有没有量化数据，说明效率提升？&lt;/p&gt;
&lt;p&gt;暂时还没有量化数据，因为我们最大的系统还没有正式上线。只能给出一个比较有意思的数字：在过去的两个半月中，我们正在加班加点的进行前面分享的这个app后台系统的重构，标准的996,然后目前测试中，全称我们将bug控制在个位数。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题5：这个服务化框架的性能怎样？系统测试过吗？&lt;/p&gt;
&lt;p&gt;简单测试过，服务器端空实现在普通i5主机上跑大概能有14w的 QPS。一些典型的简单业务场景，如简单访问一两次redis，大概几万 QPS。不过现在还没有时间进行深入的性能优化。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题6：请问如何通过设计提高代码质量&lt;/p&gt;
&lt;p&gt;在微服务这个话题中，通过微服务的理念，将系统拆分为小的粒度，开发团队也跟随系统拆分为小的团队，开发人员可以集中在小型的系统中，这本身使得开发人员容易把握全局。简单归纳为，大事化小，分而治之。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题7：谢谢老师的分享，本人最近也在看 spring boot，java做服务动辄几百兆，我想了解一下贵司选择它是否有更深的原因&lt;/p&gt;
&lt;p&gt;在分享中有给出来，你可以回头翻到那页PPT，理由都列出来了。个人对 spring boot 非常认可，使用方便，而且 spring 会的人也多。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题8：1.前面讲到的规范化，可重用，真敏捷，自动化也是架构师在推吗？2.你对docker什么看法？&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;是的，也是我们基础架构部门在力推。2. 我对docker很认同，和微服务简直是绝配，下一步必然要上docker的。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题9：grpc 没有服务治理的部分 这部分你们有什么好的实践嘛？&lt;/p&gt;
&lt;p&gt;grpc 有 name resolver，我们用来实现基于 etcd3 的服务注册和服务发现。另外 grpc 内建了负载均衡的支持，1.0版本之后基本可以拿来用了。我们最早在 0.10版本的时候这两个组件都不完善，我们放弃了他们自己实现了，但是1.0之后现在打算换回 grpc 自己的实现。其他的服务治理功能，打算自己动手，当然如果开源社区有合适的组件，我们会在评估之后直接拿来用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题10：你上马那么多技术，都是新技术，有没有考虑过这些技术的升级给你带来的影响？&lt;/p&gt;
&lt;p&gt;这是一个非常尖锐的问题。坦白说，在今年三月我决定选择自己搭建微服务框架，而不是继续dobbo，然后又选择了grpc/consul(后来换成etcd3)等新技术时，风险是非常大的。当时这几个项目都还是beta甚至alpha状态，我们比较幸运的时在最近几个月，grpc 1.0/netty 4.1/protocol buffer 3.0/etcd 3.0，这几个最重要的技术栈都陆续正式发布，而我们最大的重构项目10月才上线。有种很幸运的感觉。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题11： etcd3是做什么的，感觉没怎么用过，使用场景是什么和dubbo+zookeeper相比有什么不同&lt;/p&gt;
&lt;p&gt;etcd 和 zookeeper 类似，都是实现分布式的一致性，不过 etcd 底层是 Raft 协议，稍微简单一些。&lt;/p&gt;
&lt;p&gt;etcd 3.0 是 etcd 最新的版本，因为通讯协议从rest换成了grpc，所以我们在最后时刻选择了它。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题12：“通常来说的微服务框架覆盖的都是服务器端，不同的的服务器之间的调用。但是这里我们会有一个非常重要的需求，我们必须要把手机App覆盖到。” 为什么要加这个需求？ 请问一下这个怎么理解？框架层面做了些什么呢？&lt;/p&gt;
&lt;p&gt;不是要加这个需求，而是我们本来就有这个需求。分享中我们给出了一个数字，80%，这是我们手机app端占我们总的业务量的比例。因此我们在选型时，特别认同google对grpc的定位和要求。框架层面自然是以grpc为主要通讯协议，统一了app端到服务器端，和服务器端内部之间的通讯，由于etcd3的缘故，现在服务注册和配置管理也是统一为grpc了，这算是个意外，令人高兴的意外。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题13：微服务的粒度怎么划分，能结合业务场景简要说明下吗&lt;/p&gt;
&lt;p&gt;这个问题还是太大，有机会单独再出一个专题来讨论和分享。坦白说，现在我们自己也是在摸索，在实践中调整。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题14：“底层还好，一些基本功能被封装成SOA，难得。但是，用的语言是.net，然后通讯机制是以慢著称的SOAP”，soap的性能虽然很低，但是可以提供企业级的安全特性，而且支持原子事务，这方面在互联网金融的应用场景下是怎么考虑的？&lt;/p&gt;
&lt;p&gt;实际中我们现在的老系统，SOAP的这些特性都没有使用上。关于安全，我们会使用标准的SSL加密，这个grpc有支持，然后我们会搭建自己的鉴权服务。事务方面，现在主要还是尽量用数据库事务做强一致性，或者事后补偿来实现最终一致性。这块我们目前还没有形成足够完善的机制，后续努力中。如有所得，再来和大家讨论。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题15：微服务的力度如何把控，拆分过细会影响性能&lt;/p&gt;
&lt;p&gt;这个问题和前面的问题13类似，以后再细聊。的确在度的把握上，有很多讲究，需要权衡很多因素，除了业务边界和领域模型之后，性能，事务，安全都是需要考虑的。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;问题16：用thrift如何？&lt;/p&gt;
&lt;p&gt;我们选择 grpc 的一个重要因素是因为 grpc 支持 android 和 iOS，这是决定性的因素。另外 grpc 基于 HTTP/2 实现的 流 也是一大杀手锏，做服务器端推送优势太明显。再有就是不再需要多个连接和连接池，也简化了很多问题。thrift 理论上性能要稍微高一些，不过 grpc 也足够用了。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;片尾曲&#34;&gt;片尾曲&lt;/h2&gt;
&lt;p&gt;最后做一下广告， dolphin 框架使用了很多目前业界最新(绝不夸张)的技术栈，很多基本都没有中文资料，因此我自己写了一些学习笔记，里面翻译了部分这些技术的英文文档，如果感兴趣可以一起研究：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://skyao.net/learning-grpc/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;gRPC学习笔记&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skyao.net/learning-etcd3/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;etcd3学习笔记&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://skyao.net/learning-proto3/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;Protocol buffer 3学习笔记&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
    </item>
    
  </channel>
</rss>
