微服务

微服务是一种分布式系统解决方案。

微服务 (Microservices) 就是一些协同工作小而自治的服务。

2014年,Martin Fowler 与 James Lewis 共同提出了微服务的概念,定义了微服务是由以单一应用程序构成的小服务,自己拥有自己的进程与轻量化处理,服务依业务功能设计,以全自动的方式部署,与其他服务使用 HTTP API 通信。同时服务会使用最小的规模的集中管理 (例如 Docker) 能力,服务可以用不同的编程语言与数据库等组件实现 。

微服务与SOA

「面向服务的体系结构」 SOA (Service-Oriented Architecture) 听起来和微服务很像,但 SOA 早期均使用了总线模式,这种总线模式是与某种技术栈强绑定的,比如: J2EE。这导致很多企业的遗留系统很难对接,切换时间太长,成本太高,新系统稳定性的收敛也需要一些时间,最终 SOA 看起来很美,但却成为了企业级奢侈品,中小公司都望而生畏。 此外,实施SOA时会遇到很多问题,比如通信协议 (例如SOAP)的选择、第三方中间件如何选择、服务粒度如何确定等,目前也存在一些关于如何划分系统的指导性原则,但其中有很多都是错误的。SOA并没有告诉你如何划分单体应用成微服务,所以在实施SOA时会遇到很多问题。 这些问题再微服务框架中得到很好的解决,你可以认为微服务架构是SOA的一种特定方法。

分布式系统

什么是分布式系统
分布式系统是由一组通过网络进行通信、为了完成共同的任务而协调工作的计算机节点组成的系统。分布式系统的出现是为了用廉价的、普通的机器完成单个计算机无法完成的计算、存储任务。其目的是利用更多的机器,处理更多的数据。

首先需要明确的是,只有当单个节点的处理能力无法满足日益增长的计算、存储任务的时候,且硬件的提升 (加内存、加磁盘、使用更好的CPU) 高昂到得不偿失的时候,应用程序也不能进一步优化的时候,我们才需要考虑分布式系统。因为,分布式系统要解决的问题本身就是和单机系统一样的,而由于分布式系统多节点、通过网络通信的拓扑结构,会引入很多单机系统没有的问题,为了解决这些问题又会引入更多的机制、协议,带来更多的问题。。。

“什么是分布式系统?这取决于看系统的角度。对于坐在键盘前使用IBM个人电脑的人来说,电脑不是一个分布式的系统。但对于在电脑主板上趴着的虫子来说,这台电脑就是一个分布式系统。” —— Leslie Lamport

复杂性

流量管理 (Traffic management) : 超时、重试、负载均衡;

安全性 (Security) : 终端用户的认证和授权;

可观察性 (Observability) : 跟踪、监控和日志。

私有数据的所有权

当多个服务直接读写数据库中同一张表时,对这些表做任何改动都需要协调这些相关服务的部署。这一点违背了服务相互独立这一原则。共享的数据存储很容易不经意间造成耦合。每个服务需要有自己的私有数据。

私有数据还能提供另一个优势: 根据服务的具体用例选择最适合的数据库技术。

每个服务都要有自己的数据服务器吗?

不一定。每个服务需要自己的数据库,但这些数据库可共置在一台共享的数据服务器上。重点在于不应让服务知道其他服务底层数据库的存在。这样即可用一台共享数据服务器先开始开发,以后只要更改配置即可将不同服务的数据库隔离起来。

然而共享的数据服务器也可能造成一些问题。首先会形成单点故障,进而导致一大批服务同时故障,这一点绝不能掉以轻心。其次很可能因为一个服务占用太多资源而无意中对其他服务造成影响。

确定服务的边界

这个问题很复杂。每个服务应该是一种能提供某些业务能力的自治单位。

服务应当弱耦合在一起,对其他服务的依赖应尽可能低。一个服务与其他服务的任何通信都应通过公开暴露的接口 (API、事件等) 实现,这些接口需要妥善设计以隐藏内部细节。

服务应具备高内聚力。密切相关的多个功能应尽量包含在同一个服务中,这样可将服务之间的干扰降至最低。

服务应包含单一的界限上下文。界限上下文 (Bounded context) 可将某一领域的内部细节,包括该领域特定的模块封装在一起。

理想情况下,必须对自己的产品和业务有足够的了解才能确定最自然的服务边界。就算一开始确定的边界是错误的,服务之间的弱耦合也可以让你在未来轻松重构 (例如合并、拆分、重组) 。

无状态的服务实例

无状态 (Stateless) 服务实例不存储与上一个请求有关的任何信息,传入请求可发送至服务的任何实例。这种做法的主要收益在于可简化运维和伸缩工作。可以在后台服务之前增加一个简单的负载均衡器,随后即可根据请求数量的变化轻松地增加或删除实例,同时故障实例的替换过程也更为简单。

幂等性

上文提到过作业运行失败后可重试。自动重试失败作业的做法会遇到一个挑战: 可能会无法知道失败的作业在失败前是否完成了自己的工作。为确保相关操作足够简单,必须让作业具备幂等性 (Idempotent) 。在这个语境下,幂等性意味着多次运行同一个作业不会产生任何消极影响。无论作业运行一次或多次,最终结果必须相同。

负载均衡器

无状态服务的优势之一在于可同时为服务运行多个实例。由于每个实例都是无状态的,可由任何实例处理任何请求。这一特性与负载均衡器非常相符,借此可对服务进行更简单的伸缩。同时几乎所有云平台都提供了负载均衡器功能。

服务注册表

服务注册表可以作为信息的权威来源。其中包含有关可用服务的信息,以及服务网络位置。考虑到该服务本身的一些关键特质 (是一种单一故障点) ,该服务必须具备极高容错能力。

可通过两种方式将服务注册至服务注册表:

自注册: 服务可在启动过程中自行注册,并在生命周期的不同阶段 (初始化、正在接受请求、正在关闭等) 过程中发送状态信息。此外服务还要定期向注册表发送心跳信号,以便让注册表知道自己处于活跃状态。如果无法收到心跳信号,注册表会将服务标记为已关闭。这种方式最适合包含在服务模板中。

外部监控: 可通过外部服务监控服务运行状况并酌情更新注册表。很多微服务平台使用这种方法,通常还会用这种外部服务负责服务的整个生命周期管理。

微服务优点

技术异构性

不同服务内部的开发技术可以不一致,你可以用java来开发helloworld服务A,用golang来开发helloworld服务B,大家再也不用为哪种语言是世界上最好的语言而争论不休。 为不同的服务选择最适合该服务的技术,系统中不同部分也可以使用不同的存储技术,比如A服务可以选择redis存储,B服务你可以选择用MySQL存储 隔离性 一个服务不可用不会导致另一个服务也瘫痪,因为各个服务是相互独立和自治的系统。这在单体应用程序中是做不到的,单体应用程序中某个模块瘫痪,必将导致整个系统不可用,当然,单体程序也可以在不同机器上部署同样的程序来实现备份,不过,同样存在上面说的资源浪费问题。 可扩展性 庞大的单体服务如果出现性能瓶颈只能对软件整体进行扩展,可能真正影响性能的只是其中一个很小的模块,我们也不得不付出升级整个应用的代价。这在微服务架构中得到了改善,你可以只对那些影响性能的服务做扩展升级,这样对症下药的效果是很好的。 简化部署 如果你的服务是一个超大的单体服务,有几百万行代码,即使修改了几行代码也要重新编译整个应用,这显然是非常繁琐的,而且软件变更带来的不确定性非常高,软件部署的影响也非常大。在微服务架构中,各个服务的部署是独立的,如果真出了问题也只是影响单个服务,可以快速回滚版本解决。 易优化 微服务架构中单个服务的代码量不会很大,这样当你需要重构或者优化这部分服务的时候,就会容易很多,毕竟,代码量越少意味着代码改动带来的影响越可控。

微服务缺点 服务注册与发现 微服务之间相互调用完成整体业务功能,如何在众多微服务中找到正确的目标服务地址,这就是所谓「服务发现」功能。 常用的做法是服务提供方启动的时候把自己的地址上报给「服务注册中心」,这就是「服务注册」。服务调用方「订阅」服务变更「通知」,动态的接收服务注册中心推送的服务地址列表,以后想找哪个服务直接发给他就可以。 服务监控 单体程序的监控运维还好说,大型微服务架构的服务运维是一大挑战。服务运维人员需要实时的掌握服务运行中的各种状态,最好有个控制面板能看到服务的内存使用率、调用次数、健康状况等信息。 这就需要我们有一套完备的服务监控体系,包括拓扑关系、监控 (Metrics) 、日志监控 (Logging) 、调用追踪 (Trace) 、告警通知、健康检查等,防患于未然。 服务容错 任何服务都不能保证100%不出问题,生产环境复杂多变,服务运行过程中不可避免的发生各种故障 (宕机、过载等等) ,工程师能够做的是在故障发生时尽可能降低影响范围、尽快恢复正常服务。 程序员为此避免被祭天,需要引入「熔断、隔离、限流和降级、超时机制」等「服务容错」机制来保证服务持续可用性。 服务安全 有些服务的敏感数据存在安全问题,「服务安全」就是对敏感服务采用安全鉴权机制,对服务的访问需要进行相应的身份验证和授权,防止数据泄露的风险,安全是一个长久的话题,在微服务中也有很多工作要做。

微服务框架 Dubbo

https://www.zybuluo.com/liuhui0803/note/490701
http://www.infoq.com/cn/articles/best-practice-of-constructing-micro-service-system
https://www.cnblogs.com/xybaby/p/7787034.html

https://juejin.cn/post/6844904115298893831