一、微服务概念
1.1 微服务定义
- 微服务应该是独立和单独部署的,多个服务实例作为单独的软件构建启动和停止。
- 微服务是可配置的。当服务实例启动时,他应该读取它需要从中心位置配置自己的数据,或者将其配置信息传递为环境变量。配置服务不需要人为干预。
- 微服务实例需要对客户端是透明的。客户端永远不应该知道服务的确切位置。相反,一个微服务客户端应该与服务发现代理交互,将允许应用程序找到一个微服务实例,而无需知道它的物理位置。
微服务应该显示器健康状况。这是云架构的关键部分。微服务实例失败,客户端暴需要路由绕开坏的实例。 - 构建微服务推荐文档: https://12factor.net/
1.2 单体服务架构局限性
单体应用程序迫使多个开发团队人为地同步交付,因为它们的代码需要作为整个单元来极建、测试和部署。
详情如下图所示:
1.3 微服务架构优点
- 灵活:解耦的服务可以由重新快速提供新的功能。使用的代码单元越小,更改代码的时间越小,测试部署代码所需的时间就越少。
- 有弹性:控制程序的级联失败,从而降低在单体架构中某一部分故障从而发生不可恢复的错误几率大大增加。
- 可扩展: 解耦的服务器可以跨多个服务器水平分布,从而可以适当的扩展/服务。在单一的应用程序中,应用程序的所在逻辑相互交织在一起。整个程序想要需要扩展。哪怕是很小的一部分,都将成为应用的瓶颈。
- 小的,简单的,解耦的服务=可扩展的,有弹性的,灵活的应用
SpringBoot运行一个Web的大致流程:
二、构建微服务需要考虑的因素
2.1 核心开发模式
核心开发模式是构建微服务的最基础部分,需要考虑的因素:
- 服务职责,例如: 订单模块(只负责和订单相关)。
- 服务通讯协议,例如: HTTP或 RPC通信等。
- 服务配置管理,例如: 当前微服务迁移到不同的云环境,不需要通过修改代码来实现对应的环境配置等。
2.2 路由模式
- 服务发现 例如: Eureka注册中心。
- 服务路由 例如: Gateway或Zuul网管等。
2.3 客户端弹性模式
- 客户端负载均衡 例如: Ribbon。
- 断路器模式 例如: Hystrix。
- 回退模式 例如: Hystrix。
- 壁舱模式 例如: Hystrix。
2.4 安全模式
- 认证和授权 例如: SpringCloudSecurity, Oauth2,JWT。
2.5 日志记录和跟踪模式
微服务的优势是将单体应用程序分解成小的,可以独立部署的一个功能块。但是微服务架构的额不足之处是,各个服务之间的变得更难调试和跟踪。
- 日志关联分析 例如: Cat或SpringCloudSleuth。
- 日志聚合 例如: ELK(Elasticsearch, Logstash,Kibana)。
- 微服务跟踪 例如:Skywalking或Cat等。
2.6 构建和部署模式
- 构建和部署模式 例如: Docker
三、DevOps之微服务构建
3.1 服务装配:打包和部署微服务
3.2 服务引导:管理微服务的配置
3.3 服务注册与发现:客户端如何与微服务通信
3.4 监控微服务健康状况
3.5 构建微服务需要注意的十二个因素
- 基准代码: 所有应用程序代码和服务器配置信息都应处于版本控制中。每个微服务在源码系统内有自己独立的代码库。
- 依赖:通过使用构建工具如Maven显示声明你的应用程序的依赖。第三方JAR依赖性应该使用期特定版本号声明。这允许你的微服务总是使用不同版本的lib库进行构建。
- 配置:独立于代码存储应用程序配置(特别是特定于环境的配置)。你的应用程序配置不应该于源代码在同一个存储库中。
- 后端服务:你的微服务往往会通过网络与一个数据库或消息系统进行通信。当它这样做时,你应该确保在任务时候,你都可以讲数据库的实现从内部管理的服务转换为第三方服务。
- 构建,发布,运行:将你的构建,发布和运行部署的应用程序各部分完全分离。一旦代码被构建,开发人员就永远不应该在运行时对代码进行更改。任何修改都需要重新执行构建和重新部署。构建的服务是不可变的。不能更改。
- 进程:你的微服务应该是无状态的。他们在任何时候都可以被杀死和取代,而不必害怕一个受损的服务实例将导致数据丢失。
- 端口绑定:一个微服务对服务的运行时引擎(打包在服务的可执行文件)是完全独立的。你将能运行该服务而不需要分离的Web或应用服务器。服务应该在命令行中独立启动,并通过暴露的HTTP端口立即被访问。
- 并发:当您需要进行伸缩时,不要依赖于单个服务中的线程模型。相反,加载更多的微服务实例和在水平方向扩展。这并不排除在你的微服务使用线程,但别指望把它作为你伸缩的唯一路径。规模扩大,而不是上升。
- 通用性:微服务是一次性的,一经要求就可以启动和停止。启动时间应尽量减少,当接收到操作系统的一个终止型号时,进程应该优雅地关闭。
- 开发环境和线上环境等价:最小化服务运行的所有环境之间的差异(包括开发人员的桌面)。开发人员应该在本地使用与实际服务将运行的相同的基础设施来进行服务开发。
- 日志:日志是一个事件流。一旦日志被输出,他们对工具将是可流化的,如Splunk或Fluentd。他们讲日志聚合并将其写入到中心存储设备。微服务不应该关心这项技术是如何出现的,开发人员应该在视觉上通过STDOUT看日志,当日志正在被输出的时候。
- 管理进程:开发人员常常不得不针对他们的服务(数据迁移或转换)执行管理任务。这些任务不应该是临时的,而应该通过源代码存储管理和维护的脚本来完成。这些脚本应该是重复的,并且在他们运行的每个环境中多不改变(在每个环境中都不修改脚本代码)。
四、 微服务基础架构流程
4.1 服务发现机制
4.1.1 基础架构方式1
- 当服务客户机需要调用服务是,它将检查服务实例IPs的本地缓存。服务实例之间的负载均衡发生在服务上。
- 如果客户端在缓存中找到服务IP,它将使用它。否则,它将定位到服务发现。
- 客户端缓存将周期性地被服务发现层刷新。
4.1.2 基础架构方式2
- 当服务实例启动时,则将自己当前的IP等信息注册到Eureka中。
- 当许可服务调用组织服务时,它将使用Ribbon查找组织服务IP是否在本地缓存。
- Ribbon将周期性地刷新其IP地址缓存。
4.2 SpringCloud组件注意点
4.2.1 Hystrix 断路器
回退机制:
回退策略注意点:
- 回退是一种机制,当资源超市货失败时提供一种处理的方式。如果你发现自己使用回退捕获一个超市异常并且仅仅是记录错误日志,那么你应该在你的服务调用中使用一个标准的try…catch块,捕获HystrixRuntimeException异常,然后在try…catch块中添加日志记录逻辑。
- 注意你的回退功能锁采取的操作。当你的回退方法已经就位。你可以继续在此调用你的端点。返一次当你点击它并遇到超时错误时(记住你有 3 的机会),你不应该从服务调用中获得异常,而是返回模拟许可证值。
壁舱机制:(一个性能不好的服务可以包含在容器内而不会导致容器崩溃)
hystrix实现断路器模式的核心就是使用线程池待遇远程服务
请求.默认情况下,所有的Hystrix命令将共享相同的线程池来处理请求。这个线程池将有10个县城用于处理远程服务调用,这些服务可以包括任何东西,包括其Rest服务调用,数据库调用。
- Hystrix-wrapped resource call 包装Hystrix的资源调用
- Default Hystrix thread pool 默认的Hystrix线程池
- Hystrix worker threads Hystrix工作线程
- All remote resource calls are in a single shard thread pool 所有远程资源调用都在一个共享线程池中
- A single slow-performing service can saturate the Hystrix thread pool and cause resource exhausion in the Java cnotainer hosting the service 一个单一的执行速速较慢的服务可以使Hystrix线程池饱和,并导致托管服务的Java容器资源枯竭。
Hystrix短路流程:
通过一个10秒窗口和5秒窗口(可配置),并通过一些列检查确定是否断路器跳闸。
- Has the minimum number of requests failed? 请求失败次数达到最小数量了吗?
- Has the error threshold been reached? 达到错误阈值了吗?
- No problems encountered;call goes to remote resource 没有遇到问题;调用到远程资源。
- Circuit breaker tripped 断路器跳闸
- Is the problem still occuring with the remote service call? 远程服务调用是否仍然存在问题?
- Issue with remote resource resolve;call can go through 提供远程资源分析;调用可以通过
每当Hystrix命令遇到一个错误服务,他将启动一个10秒的定时器,计时器将被用来检查服务调用通常是如何失败的。这个10秒的窗口是可配置的。第一件事是Hystrix看在10秒的窗口内已经发生的调用次数。如果调用次数小于调用在窗口内需要发生的最小次数,然后Hystrix将不会采取行动,即使有些调用失败。例如,在10秒的窗口Hystrix将考虑行动之前,需要发生的调用次数缺省值是20。如果在10秒的时间内调用失败有15次,没有足够的调用发生来使断路器跳闸,即使所有 15 次调用都失败。Hystrix 将继续让调用到到达程服务。
当在程资源调用最小次数在10秒的窗口内发生,Hystrix将开始查看整体故障发生率。
如果失败的总百分比超过阈值,Hystrix会触发断路器和后续的调用绝大部分均失败。我们不久将讨论,Hystrix将让部分调用通过来测试,看看服务是否恢复。错误阈值的默认值是
50%。
当在远程调用上,Hystrix断路器已经跳闸时,它将尝试为活动启动新的窗口。每五秒(返个值是可配置的),Hystrix 会让调用到达挣扎中的服务。如果调用成功,Hystrix 将重置断路器并开始重新让调用通过。如果调用失败,Hystrix 将断路器闭合,在 5 秒之后再尝试。
Hystrix的隔离策略:
-
SEMAPHORE
它在调用线程上执行,并发请求受信号量计数的限制 -
THREAD
(默认) 它在一个单独的线程上执行,并发请求受到线程池中线程数的限制
默认Hystrix运行一个线程隔离。每个Hystrix命令用来保护运行在一个独立的线程池调用,不予进行调用的父线程共享它的上下文。这意味着Hystrix可以中断控制的一个线程执行,而不必担心中断任何与父线程做原始调用相关联的其他活动。
注意点:
- Hystrix,默认情况下,不会将父线程的上下文传播到由Hystrix命令管理的线程。如果有这方面需要,则需要重新进行配置。
4.2.2 Zuul 服务网管
4.2.3 微服务安全 springCloudSecurity/Oauth2(支持第三方服务)
- OAuth2是一个基于令牌的身份认证框架,它用来验证用户。
- OAuth2确保每一个微服务执行用户请求不需要提供每个调用的用户凭证。
- OAuth2提供不同的机制来保护Web服务调用。这些机制称为授权。
- 在 Spring 中使用OAuth2,你需要创建一个OAuth2认证服务。
- 想要调用服务的每个应用程序都需要在 OAuth2 认证服务中注册。
- 每个应用程序都有自己的应用程序名称和密钥。
- 用户凭证和角色是在数据库存储,且通过 Spring security 访问。
- 每个服务必须定义觉得可以采取的操作。
- SpringCloudSecuirty支持JavaScript web Token(JWT)规范。
4.2.4 SpringCloudStream事件驱动服务器
① The service client calls the service, and the service changes the state of the data
it owns. This is done in the business logic of the service.
服务客户端调用服务,服务更改它拥有的数据的状态。这是在服务的业务逻辑中完成的。
② The source is the service’s Spring code that publishes the message.
消息发布的源头是服务的 Spring 代码。
③ The message is published to a channel.
消息被发布到通道中。
④ A binder is the Spring Cloud Stream’s framework code that communicates to
the specific messaging system.
绑定器是 Spring Cloud Stream 的框架代码,它不特定的消息传递系统通信。
⑤ The message broker can be implemented using any number of messaging
platforms, including Apache Kafka and RabbitMQ.
消息代理可以使用任意数量的消息平台实现,包括 Apache Kafka 和 RabbitMQ。
⑥ The order of message processing (binder, channel, sink) changes as a service
receives a message.
消息处理(绑定器、通道、接收器)的顺序随着服务接收消息而发生变化。
⑦ A sink is the service-specific code that listens to a channel and then processes
the incoming message.
接收器是特定于服务的代码,它监听通道并处理传入消息。
SpringCloud中消息的发布和消费,在消息的发布和消费中涉及到四个组件:
- 消息源
当服务准备发布消息时,它将使用消息源来发布信息。消息源是一个Spring注解的接口,用普通Java对象(POJO)代表被发布的消息。消息源将消息序列化(默认的序列化是JSON),并发布消息到通道。
- 通道
- 绑定器
- 接收器
4.2.4 Spring Cloud Sleuth 和 Zipkin 进行分布式跟踪
使用关联 ID 处理 HTTP 调用,并提供将生成的跟踪数据提供给 OpenZipkin 的钩子。它通过添加过滤器并与其他Spring组件交互完成此操作,以便将生成的关联ID传递到所有系统调用。