关于微服务的思考

微服务最近很火,特别是搭上 Spring Cloud 的 Java,凡是涉及到的项目,基本都是大谈特谈微服务,服务治理等等。

什么是微服务?

解释微服务,可以简单的理解为的服务。原来的各个模块,组件被的拆分,自成一体。系统中的各个微服务可被独立部署,各个微服务之间,单体高度。每个微服务仅关注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表着一个小的业务能力。尽管“微服务”这种架构风格没有精确的定义,但其具有一些共同的特性,如围绕业务能力组织服务、自动化部署、智能端点、对语言及数据的“去集中化”控制等等。

单体服务到微服务的演化

单体服务

应用核心是业务逻辑,由定义服务、域对象和事件的模块完成。围绕着核心的是与外界打交道的适配器。适配器包括数据库访问组件、生产和处理消息的消息组件,以及提供API或者UI访问支持的web模块等。尽管也是模块化逻辑,但是最终它还是会打包并为式应用。具体的格式依赖于应用语言和框架。例如,许多Java应用会被打包为WAR格式,部署在Tomcat或者Weblogic上,而另外一些Java应用会被打包成自包含的JAR格式,同样,Rails和Node.js会被打包成层级目录。通俗的点说,就是一个大服务,包含了各种各样的模块、组件,比如用户模块,权限模块,订单模块,通知模块等等。各种模块犬牙交错的,互为耦合又互为依赖的拼接在一个服务中。这就是典型的单体服务。

单体服务的弊端

随着,需求的复杂度越来越高,模块分布越来越多,逻辑越来越复杂。慢慢的单体服务支撑不了,维护也越来越复杂。

主要有一下几方面问题:

问题一: 代码难以维护

对于一个大的单体服务,代码有可能超过百万行甚至于千万行。找问题犹如大海捞针。虽然也是按照模块化组件化区分的,但是不可避免的是,依赖的太多,定位问题繁琐。而且,由于单体服务在一个包中,所以启动速度相当缓慢,大大的影响开发效率。

问题二: 与敏捷开发相违背

复杂而巨大的单体式应用也不利于。今天,SaaS应用常态就是每天会改变很多次,而这对于单体式应用模式非常困难。另外,这种变化带来的影响并没有很好的被理解,所以不得不做很多手工测试。那么接下来,持续部署也会很艰难。

问题三: 服务的稳定性

如果一个模块或者组件出了一个bug,比如内存泄漏等,那么就会影响整个服务。

问题四: 架构的迭代复杂

随着新的技术的出现,或者需要尝试新版本的新特性。但是,往往修改一处,牵一发而动全身,所以,技术栈变得越来越滞后。

对于性能的问题,或者你会说,我加一些机器做负载就好了,但是,不要忘了,负载是相对于所有的单体服务,并不会大大提高需要负载的那个模块组件。

微服务的发展与展望

许多公司,比如Amazon、eBay和NetFlix,通过采用微处理结构模式解决了上述问题。其思路不是开发一个巨大的单体式的应用,而是将应用分解为小的、互相连接的微服务。

白热化,随着容器的普及,服务拓扑变得越来越动态化,这对网络功能提出了更多的要求。服务网格通过服务发现、路由、负载均衡、健康检测和可观察性来管理流量,简化容器与生俱来的复杂性。

架构的崛起,服务向订阅事件的观察者容器发送事件,容器异步做出响应,事件发送者可能对此一无所知。与请求响应式架构不同的是,在基于事件的系统架构中,发起事件的容器并不依赖下游的容器,它们的处理过程和加载的事务与下游容器的可用性或完成情况无关。这种架构的另一个好处是,开发者可以更加独立地设计各自的服务。

微服务的特点

简单从几个方面总结一下,微服务的基本特点:

1. 独立开发

小型独立的组件由单独的团队开发,比如一个小组只是开发订单服务,只是关注与相关联的服务,提供必要的一些API等,大大简化了开发的复杂度。

2. 独立的部署

每个单独的服务均可以独立的部署,这样可以以最快的速度和更少的风险发布新功能。

3. 独立的可伸缩性

每个组件可以彼此的独立进行缩放。比如订单服务突然需求量暴增,支撑不了现阶段的访问量。这时候,可以单独增加单个服务的负载,而不必扩大每个组件,这就使得弹性缩放可行,并且降低了运营的成本。

4. 可重用性

使用轻量级的通讯协议和简单的数据结构,比如 http+json,组件只是对特定功能的实现。所以,如果有其他依赖的服务,只要符合接口的规范,拿之即用,不用重复的开发相同的服务。

微服务的优点

降低单个服务的复杂性

将一种怪异的整体应用程序分解成一组服务。虽然功能总量不变,但应用程序已分解为可管理的块或服务。每个服务都以RPC或消息驱动的API的形式定义了一个明确的边界。

架构灵活

这种架构使每个服务都能够由专注于该服务的团队独立开发。开发人员可以自由选择任何有用的技术,只要该服务符合API规则。当然,大多数组织都希望避免完全无规则状态并限制技术选择。

然而,这种自由意味着开发人员不再有义务使用在新项目开始时存在的可能过时的技术。在编写新服务时,他们可以选择使用当前的技术。此外,由于服务相对较小,因此使用当前技术重写旧服务变得可行。

独立部署

开发人员不需要协调部署本地服务的变更。这些变化可以在测试后尽快部署。例如,UI团队可以执行A | B测试,并快速迭代UI更改。

独立扩展

使每个服务都可以独立调整,可以仅部署满足其容量和可用性限制的每个服务的实例数。此外,可以使用最符合服务资源要求的硬件。

微服务的不足

开发

对于开发者来说事情会变得更加困难。在开发人员想要在远程工作的情况下,或者可能跨越许多服务的功能的情况下,开发人员必须在他们的机器上运行它们,或者连接到它们。这通常比简单地运行单个程序更复杂。

运维

对于不开发服务但维护服务的团队来说,潜在的复杂性是一个巨大的挑战。他们不是管理几个正在运行的服务,而是管理数十,数百或数千个正在运行的服务。服务越多,沟通越多,潜在的失败风险就越多。

DevOps

目前面临的挑战是,许多组织仍然依靠独立的开发和运营团队来运行 – 而一些组织则更倾向于采用微服务。

对于已经采用了DevOps的组织来说,这仍然很难。既是开发者又是运维者,已经非常艰难(但是要建立好的软件却很关键),但是也必须了解容器编排系统的细微差别,特别是快速发展的系统是非常困难的。

状态和编排

如果服务是无状态的,这些技术可以缓解大量的挑战。但是无状态的服务非常坦率,容易处理。事实上,如果你有无状态的服务,那么我会倾向于考虑跳过微服务,并考虑使用无服务器模型。

实际上,许多服务需要管理。比如订阅服务,订阅服务的新版本可以以不同形状将数据存储在订阅数据库中。如果你同时运行这两个服务,则一次运行两个模式的系统。如果进行了蓝/绿部署,而其他服务依赖于新形状中的数据,则必须同时更新这些数据,并且如果订阅服务部署失败并回滚,则可能还需要使用级联回滚。

沟通

当你建立一个相互依赖的大型服务网络时,可能会有很多的服务间通信。这导致了一些挑战。首先,有很多事情可能会失败。我们必须假设网络call可能会失败,这意味着当一个服务call另一个服务时,它应该至少需要重试几次。现在当一个服务可能调用很多服务时,我们最终会遇到一个更加复杂的情况。

版本

这可能会使事情变得非常具有挑战性,并且很多时候可能会让你感到困惑——哪些版本的服务可以一起正常工作。

在软件系统中管理依赖关系是非常困难的,无论是节点模块,Java模块,C库还是其他。当一个实体消费独立组件之间的冲突的挑战是很难处理的。

当依赖关系是静态的时候,这些挑战是很难处理的。虽然可以进行修补、更新、编辑等,但是如果依赖关系本身是实时服务,那么你可能根本无法更新它们——你可能需要运行许多版本(上面已经描述过这些挑战),或者直到整个系统得到修复。

事务控制

在需要跨操作交易完整性的情况下,微服务可能会非常痛苦。分布式状态很难处理,很多小的单位可能会很难进行编排交易。

试图通过使操作幂等性,提供重试机制等来避免这个问题可能听起来很诱人,而且在很多情况下确实可能起作用。但可能有一些场景,你只需要一个事务失败或成功,而不想它处于中间状态。解决这个问题或者在微服务模型中实现它的代价可能是非常高的。

微服务实践

开发集成

主要是搭建一个微服务平台需要具备的一些工具和仓库

运行容器

微服务平台来提供一些基础能力和分布式的支撑能力,微服务运行容器则会运行在这个平台之上。

监控治理

致力于在运行时能够对受管的微服务进行统一的监控、配置等能力。

服务网关

负责与前端的 WEB 应用 移动 APP 等渠道集成,对前端请求进行认真鉴权,然后路由转发。

服务契约与 API 管理

提供了方便的服务发布能力,能够快速的将业务功能对外发布,生成服务的规格契约,当然也可以先设计服务契约,在根据契约来生成服务的默认实现代码。

服务契约与服务编排

简化分布式服务调用的复杂度,如同步、异步、异步模拟同步、超时重试、事务补偿等,均有服务编排引擎完成, 可以快速的将已经提供的微服务能力进行组合发布,非常适合业务的快速创新。

微服务容器

服务注册发现路由

由SpringCloud Eureka 组件实现的。服务在启动的时候,会将自己要发布的服务注册到服务注册中心,运行时,如果需要调用其他微服务的接口,那么就要先到注册中心获取服务提供者的地址,拿到地址后,通过微服务容器内部的简单负载均衡器作为路由使用。

统一认证鉴权

基于 Spring Security 结合 Auth2 再加上 JWT(Json web token)做安全令牌,实现统一的安全认证与鉴权,使得微服务之间能够按需隔离和安全互通。

日志与流水设计

基于日志的流水号,快速定位服务运行中出现的问题,在上线的问题排查中尤为重要。比如 应用编号,进程编号,请求编号,响应编号等等。

集中配置管理

微服务分布式环境下,一个系统拆分为很多个微服务,一定要告别运维手工修改配置的方式。需要采用集中配置管理的方式来提升运维的效率。

统一管理门户

每个微服务有几个节点实例再运行,可以监控微服务的子节点状态,对微服务进行配置管理和监控。

分布式事务问题

微服务之间是独立的、调用协议也是无状态的,因此数据库事务方案在一开始就已经不在考虑的范围内。我们要解决的是一定时间后的数据达到最终一致状态,准确的说就是采用传统的业务补偿与冲正方式。

推荐的事务一致性方案有三种:

可靠事件模式:即事件的发送和接收保障高可靠性,来实现事务的一致性。

补偿模式:Confirm Cancel ,如果确认失败,则全部逆序取消。

TCC 模式:Try Confirm Cancel ,补偿模式的一种特殊实现 通常转账类交易会采用这种模式。

分布式同步调用问题

所依赖的服务的可靠性是无法保证的情况下,如何保证自己能够正常的提供服务,不被依赖的其他服务拖垮?

SEDA : staged event-driven architecture 本质上就是采用分布式事件驱动的模式,用异步模拟来同步,无阻塞等待,再加上资源分配隔离结起来的一个解决方案。

总结

如果业务需求没有那么大,团队很小,并发量也不是很高,那么上微服务 就有些鸡肋了,效率反而会拖后。比如,并发量小于100的项目,真的没必要为了潮流而潮流。但是如果你的并发量超过10000了,那你还是乖乖的上微服务吧。

一个真正的项目生命周期中,刚开始的时候没必要上微服务,因为需求不确定,变化太快,用微服务反而效率更低。还不如理清功能模块,做好结构划分,慢慢的迭代集成,一旦项目变大了,成熟了,那么那时候 分割微服务 也未尝不可。因为先前做好了代码的分层,所以分割也是很快的,工足量也可以接受。

微服务架构有很多吸引人的地方,但在拥抱微服务之前,也需要认清它所带来的挑战。

需要避免为了“微服务”而“微服务”。特别鄙视那种,一个公司有好几个新项目,然后同时都在实施微服务。本来项目需求都不成熟,然后每个项目独自划分模块,开发一大批重复的功能,实际上并没有真正的集成。

微服务架构引入策略 – 对传统企业而言,开始时可以考虑引入部分合适的微服务架构原则对已有系统进行改造或新建微服务应用,逐步探索及积累微服务架构经验,而非全盘实施微服务架构。

找了一个比较成熟的平台,他们的架构还是比较清晰,具有借鉴意义的。

微服务对我们的思考,更多的是思维上的转变。对于微服务架构:技术上不是问题,意识比工具重要。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180723G1APRV00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券