服务网格:Istio

    如果你此时并不曾了解过什么是“The Fenix Project”,建议先阅读。

    当软件架构演进至基于 Kubernetes 实现的微服务时,已经能够相当充分地享受到虚拟化技术发展的红利,如应用能够灵活地扩容缩容、不再畏惧单个服务的崩溃消亡、立足应用系统更高层来管理和编排各服务之间的版本、交互。可是,单纯的 Kubernetes 仍然不能解决我们面临的所有分布式技术问题,在此前对基于 Kubernetes 的架构中“”的介绍里,笔者已经说明光靠着 Kubernetes 本身的虚拟化基础设施,难以做到精细化的服务治理,譬如熔断、流控、观测,等等;而即使是那些它可以提供支持的分布式能力,譬如通过 DNS 与服务来实现的服务发现与负载均衡,也只能说是初步解决了的分布式中如何调用服务的问题而已,只靠 DNS 难以满足根据不同的配置规则、协议层次、均衡算法等去调节负载均衡的执行过程这类高级的配置需求。Kubernetes 提供的虚拟化基础设施是我们尝试从应用中剥离分布式技术代码踏出的第一步,但只从微服务的灵活与可控这一点而言,基于 Kubernetes 实现的版本其实比上一个 Spring Cloud 版本里用代码实现的效果(功能强大、灵活程度)是有所倒退的,这也是当时我们未放弃 Hystrix、Spring Security OAuth 2 等组件的原因。

    Kubernetes 给予了我们强大的虚拟化基础设施,这是一把好用的锤子,但我们却不必把所有问题都看作钉子,不必只局限于纯粹基础设施的解决方案。现在,基于 Kubernetes 之上构筑的服务网格(Service Mesh)是目前最先进的架构风格,即通过中间人流量劫持的方式,以介乎于应用和基础设施之间的边车代理(Sidecar)来做到既让用户代码可以专注业务需求,不必关注分布式的技术,又能实现几乎不亚于此前 Spring Cloud 时代的那种通过代码来解决分布式问题的可配置、安全和可观测性。这一个目标,现在已成为了最热门的服务网格框架Istio服务网格:Istio - 图7的 Slogan:Connect, Secure, Control, And Observe Services。

    得益于 Kubernetes 的强力支持,小书店 Fenix’s Bookstore 已经能够依赖虚拟化基础设施进行扩容缩容,将用户请求分散到数量动态变化的 Pod 中处理,可以应对相当规模的用户量了。不过,随着 Kubernetes 集群中的 Pod 数量规模越来越庞大,到一定程度之后,运维的同学无奈地表示已经不可能够依靠人力来跟进微服务中出现的各种问题了:一个请求在哪个服务上调用失败啦?是 A 有调用 B 吗?还是 C 调用 D 时出错了?为什么这个请求、页面忽然卡住了?怎么调度到这个 Node 上的服务比其他 Node 慢那么多?这个 Pod 有 Bug,消耗了大量的 TCP 链接数……

    而另外一方面,随着 Fenix’s Bookstore 程序规模与用户规模的壮大,开发团队人员数量也变得越来越多。尽管根据不同微服务进行拆分,可以将每个服务的团队成员都控制于“”的范围以内,但一个很现实的问题是高端技术人员的数量总是有限的,人多了就不可能保证每个人都是精英,如何让普通的、初级的程序员依然能够做出靠谱的代码,成为这一阶段技术管理者的要重点思考的难题。这时候,团队内部出现了一种声音:微服务太复杂了,已经学不过来了,让我们回归单体吧……

    在上述故事背景下,Fenix’s Bookstore 迎来了它的下一次技术架构的演进,这次的进化的目标主要有以下两点:

    • 目标一:实现在大规模虚拟服务下可管理、可观测的系统。
      必须找到某种方法,针对应用系统整体层面,而不是针对单一微服务来连接、调度、配置和观测服务的执行情况。此时,可视化整个系统的服务调用关系,动态配置调节服务节点的断路、重试和均衡参数,针对请求统一收集服务间的处理日志等功能就不再是系统锦上添花的外围功能了,而是关乎系统是否能够正常运行、运维的必要支撑点。
    • 目标二:在代码层面,裁剪技术栈深度,回归单体架构中基于 Spring Boot 的开发模式,而不是 Spring Cloud 或者 Spring Cloud Kubernetes 的技术架构。
      我们并不是要去开历史的倒车,相反,我们是很贪心地希望开发重新变得简单的同时,又不能放弃现在微服务带来的一切好处。在这个版本的 Fenix’s Bookstore 里,所有与 Spring Cloud 相关的技术组件,如上个版本遗留的 Zuul 网关、Hystrix 断路器,还有上个版本新引入用于感知适配 Kubernetes 环境的 Spring Cloud Kubernetes 都将会被拆除掉。如果只观察单个微服务的技术堆栈,它与最初的单体架构几乎没有任何不同——甚至还更加简单了,连从单体架构开始一直保护着服务调用安全的 Spring Security 都移除掉(由于 Fenix’s Bookstore 借用了 Spring Security OAuth2 的密码模式做为登陆服务的端点,所以在 Jar 包层面 Spring Security 还是存在的,但其用于安全保护的 Servlet 和 Filter 已经被关闭掉)

    服务网格:Istio - 图9

    在已经部署 Kubernetes与 Istio 的前提下,通过以下几种途径,可以运行程序,浏览最终的效果:

    • 在 Kubernetes 无 Sidecar 状态下运行:
      在业务逻辑的开发过程中,或者其他不需要双向 TLS、不需要认证授权支持、不需要可观测性支持等非功能性能力增强的环境里,可以不启动 Envoy(但还是要安装 Istio 的,因为用到了 Istio Ingress Gateway),工程在编译时已通过 Kustomize 产生出集成式的资源描述文件:

      请注意资源文件中对 Istio Ingress Gateway 的设置是针对 Istio 默认安装编写的,即以作为标签,以 LoadBalancer 形式对外开放 80 端口,对内监听 8080 端口。在部署时可能需要根据实际情况进行调整,你可观察以下命令的输出结果来确认这一点:

      在浏览器访问:,系统预置了一个用户(user:icyfenix,pw:123456),也可以注册新用户来测试。

    • 服务全部启动后,在浏览器访问:http://localhost服务网格:Istio - 图12,系统预置了一个用户(user:icyfenix,pw:123456),也可以注册新用户来测试,注意这里开放和监听的端口同样取决于 Istio Ingress Gateway,可能需要根据系统环境进行调整

    • 调整代理自动注入

      项目提供的资源文件中,默认是允许边车代理自动注入到 Pod 中的,这会导致服务需要有额外的容器初始化过程。开发期间,我们可能需要关闭自动注入以提升容器频繁改动、重新部署时的效率。如需关闭代理自动注入,请自行调整bookstore-kubernetes-manifests目录下的资源文件,根据需要将istio-injection修改为 enable 或者 disable。

      如果关闭了边车代理,意味着你的服务丧失了访问控制(以前是基于 Spring Security 实现的,在 Istio 版本中这些代码已经被移除)、断路器、服务网格可视化等一系列依靠 Envoy 代理所提供能力。但这些能力是纯技术的,与业务无关,并不影响业务功能正常使用,所以在本地开发、调试期间关闭代理是可以考虑的。

    Fenix’s Bookstore 采用基于 Istio 的服务网格架构,其中主要的技术组件包括:

    • 配置中心:通过 Kubernetes 的 ConfigMap 来管理。
    • 服务发现:通过 Kubernetes 的 Service 来管理,由于已经不再引入 Spring Cloud Feign 了,所以在 OpenFeign 中,直接使用短服务名进行访问。
    • 负载均衡:未注入边车代理时,依赖 KubeDNS 实现基础的负载均衡,一旦有了 Envoy 的支持,就可以配置丰富的代理规则和策略。
    • 服务网关:依靠 Istio Ingress Gateway 来实现,已经移除了 Kubernetes 版本中保留的 Zuul 网关。
    • 服务容错:依靠 Envoy 来实现,已经移除了 Kubernetes 版本中保留的 Hystrix。
    • 本作品代码部分采用进行许可。遵循许可的前提下,你可以自由地对代码进行修改,再发布,可以将代码用作商业用途。但要求你:

      • 署名:在原有代码和衍生代码中,保留原作者署名及代码来源信息。
      • 保留许可证:在原有代码和衍生代码中,保留 Apache 2.0 协议文件。
    • 本作品文档部分采用知识共享署名 4.0 国际许可协议服务网格:Istio - 图15进行许可。 遵循许可的前提下,你可以自由地共享,包括在任何媒介上以任何形式复制、发行本作品,亦可以自由地演绎、修改、转换或以本作品为基础进行二次创作。但要求你:

      • 署名:应在使用本文档的全部或部分内容时候,注明原作者及来源信息。
      • 非商业性使用:不得用于商业出版或其他任何带有商业性质的行为。如需商业使用,请联系作者。
      • 相同方式共享的条件:在本文档基础上演绎、修改的作品,应当继续以知识共享署名 4.0 国际许可协议进行许可。