分布式与微服务
作者:mmseoamin日期:2023-12-25

分布式与微服务,第1张

目录

微服务 (Microservices)

微服务

微服务架构

微服务集群架构

简单代码举例

微服务架构在购物下单平台的简单应用

传统单体架构

微服务架构转变

微服务架构下的购物平台模块

微服务架构的优势

分布式系统 (Distributed Systems)

分布式

分布式架构图

分布式服务器集群部署架构图

简单代码举例

互联网架构演变

互联网架构演化概览

架构设计演进原因

架构演进的过程

架构演进的优缺点

架构演进的驱使

SpringCloud

集群+分布式+节点概念

集群(Cluster)

分布式(DistributedSystem)

节点(Node)

关系和区别

远程调用 (Remote Call)

1.远程过程调用(RPC)

2.远程方法调用(RMI)

3.Web服务

4.RepresentationalStateTransfer(REST)

5.gRPC

6.服务网格(ServiceMesh)

分布式常用工具与组件

SpringCloud

SpringCloud下的工具

阿里巴巴提供的工具

Netflix开源的组件

项目中采用的工具

负载均衡 (Load Balancing)

常见的负载均衡算法:

使用 Netflix Ribbon 实现负载均衡

全局负载均衡策略配置(策略1)

为特定服务配置负载均衡策略(策略2)

1. 引入 Maven 依赖

2. 添加注解

3. 进行调用

服务注册与发现 (Service Registry and Discovery)

1.Eureka

2.Consul

3.Zookeeper

4.Nacos

导入依赖

修改配置

添加注解

启动服务器

服务发现的过程

查看 Nacos Discovery 注册中心

5.etcd

6.KubernetesServiceDiscovery

7.IstioServiceDiscovery

8.SkyDNS

综合比较

接口共享 (Interface Sharing)

步骤1:创建接口模块

步骤2:在服务提供者模块中实现接口

步骤3:在服务消费者模块中调用接口

分布式事务 (Distributed Transaction)

分布式事务解决方案

1. 两阶段提交(2PC, Two-Phase Commit)

2. 三阶段提交(3PC, Three-Phase Commit)

3. 补偿事务(TCC, Try-Confirm/Cancel)

4. 本地消息表

5. 消息队列

6. 分布式事务中间件

7. 最终一致性

8. SAGA模式

分布式事务中间件Seata

第一阶段:预备阶段

第二阶段:提交阶段

实际操作步骤

配置中心 (Configuration Center)

配置中心解决方案

Spring Cloud Config

配置中心服务端(Config Server)

客户端(Config Client)

服务熔断&服务降级

服务熔断 (Service Circuit Breaker)

服务降级 (Service Degradation)

实际应用

结合实际情景

服务容错

API网关 (API Gateway)

分布式API网关

核心功能

实现工具

架构考虑

Gateway

单点登录 (Single Sign-On, SSO)

分布式单点登录的关键组件

分布式单点登录的工作流程

扩展功能

总结

Spring Security OAuth2


在微服务和分布式系统的背景下,这些组件共同工作以支持构建可靠、可伸缩和高效的软件应用。具体选择哪些技术和组件取决于应用的需求、团队的经验以及系统的预期规模。

  • 微服务 提供了一种将大型应用分解为独立、单一职责的服务的方法。
  • 分布式系统 涉及多个协作的计算机(或节点),共同完成任务。
  • 集群 提高了应用的可用性和可伸缩性。
  • 节点 是分布式系统中的基本单位,可以是物理机器或虚拟实例。
  • 远程调用 允许服务间的通信和协作。
  • 负载均衡 在多个服务器之间分配请求,以提高性能和可靠性。
  • 服务注册与发现 使服务能够动态地找到网络中的其他服务。
  • 注册中心 是服务注册与发现的中心点。
  • 接口共享 保证了服务间通信的兼容性。
  • 分布式事务 保持了跨多个节点的数据一致性。
  • 配置中心 管理分布在不同服务和环境中的配置。
  • 服务熔断 防止系统过载,通过快速失败保护系统。
  • 服务降级 在系统压力大时暂时关闭一些功能,保证核心功能的运行。
  • API网关 作为系统的统一入口,处理所有外部请求。
  • 单点登录 (SSO) 简化了用户在多个系统之间的认证过程。

    这些概念和技术的实现通常需要依赖于成熟的框架和库,如Spring Boot和Spring Cloud在Java生态中非常流行。它们提供了一套完整的解决方案来支持微服务架构和分布式系统的构建。通过这些工具,开发者可以更加专注于业务逻辑的实现,而不是底层的技术细节。

    以下是从不同角度对这些概念的详细解释,包括简单代码示例。

    微服务 (Microservices)

            简单来说,微服务是一种架构风格,它提倡将单一应用程序划分为一组小的服务,每个服务运行在其独立的进程中,并使用轻量级的通信机制(通常是HTTP RESTful API)进行交互。每个服务围绕特定业务功能构建,并且可以独立部署、扩展和更新。

        微服务架构风格这种开发方法,是以开发一组小型服务的方式来开发一个独立的应用系统。
    其中每个小型服务都运行在自己的进程中,并经常采用HTTP资源API这样轻量的机制来相互通信。
    这些服务围绕业务功能进行构建,并能通过全自动的部署机制来进行独立部署。
    这些微服务可以使用不同的语言来编写,并且可以使用不同的数据存储技术。
    对这些微服务,我们仅做最低限度的集中管理。
                                               -世界级软件架构大师Martin Fowler

    微服务

            微服务架构是一种设计方法,它将传统的单体应用程序分解为一系列小型、自治的服务单元。每个微服务都具有专注的业务职责,并且以独立的进程形式运行,通常通过轻量级的通信协议(如HTTP/REST)进行相互连接。这种风格强调服务的独立性,允许使用不同的编程语言和数据存储技术,并提倡最小化集中管理的方式。

            微服务架构的出现,是为了应对日益复杂的业务需求和日渐庞大的用户群体。在高并发场景下,单体应用的局限性变得尤为明显,无法有效地进行快速迭代和扩展。微服务通过将大型应用拆分为互相协作的小服务,实现了系统的模块化,使得各个服务可以独立开发、测试、部署和扩展,从而提高了整个系统的灵活性和可维护性。

            然而,微服务架构并非银弹,它在解决单体应用的问题时也带来了新的挑战,如服务间的通信、数据一致性、分布式事务处理等。这些挑战需要通过合适的技术和模式来克服,例如服务发现、配置中心、API网关、断路器、服务熔断和降级等策略。

            总的来说,微服务架构是对单体应用的一种补充和演进,它为现代软件开发提供了一种更为灵活和可扩展的设计路径,但同时也要求开发者和团队能够适应其带来的复杂性和挑战。

    微服务架构图

    分布式与微服务,第2张

    微服务集群架构

    分布式与微服务,第3张

    简单代码举例

    使用Spring Boot创建一个简单的微服务:

    @SpringBootApplication
    @RestController
    public class ProductServiceApplication {
        public static void main(String[] args) {
            SpringApplication.run(ProductServiceApplication.class, args);
        }
        @GetMapping("/products")
        public List listProducts() {
            // 返回产品列表
            return productService.findAll();
        }
    }

    微服务架构在购物下单平台的简单应用

    传统单体架构

    - 集成性:产品浏览、用户账户管理、订单处理、支付流程等功能集中在一个单体应用中。

    - 操作职责:应用程序负责处理用户的账户活动、产品搜索和选择、下单操作、支付事务等。

    微服务架构转变

    - 模块化服务:将账户管理、产品管理、订单处理、支付等核心功能拆分成独立的微服务。

    - 多维拆分策略:服务不仅可以按功能拆分,还可以根据业务需求或数据逻辑进行拆分,提供灵活性。

    微服务架构下的购物平台模块

    1. 账户服务

       - 职责:管理用户账户和身份验证。

       - 数据独立性:拥有专门的数据库来储存用户资料。

       - 核心操作:在用户注册或登录时验证信息,并在数据库中进行管理。

    2. 产品服务

       - 职责:维护产品目录和详情。

       - 数据独立性:管理产品信息的专有数据库。

       - 核心操作:向用户展示产品列表和详细描述。

    3. 订单服务

       - 职责:处理购物车和订单生成。

       - 数据独立性:使用独立数据库追踪订单状态和历史。

       - 核心操作:在用户下单时收集购物车内容,确认库存,并记录订单信息。

    4. 支付服务

       - 职责:执行支付授权和结账。

       - 核心操作:与银行或支付提供者接口,处理交易和支付确认。

    微服务架构的优势

    - 模块独立性:服务独立开发、部署,易于管理和扩展。

    - 可扩展性:根据业务增长独立扩展服务,无需重构整个应用。

    - 通信效率:服务间通过高效的网络协议(如REST API、消息队列)进行互联。

    采用微服务架构的购物下单平台能够更快适应市场变化,提升产品的迭代速度,同时降低系统故障的影响范围。这种架构使得平台能够在不同业务峰值时期灵活调整资源,保证用户体验和操作效率。

    分布式系统 (Distributed Systems)

    分布式

    分布式系统由多个计算机组成,这些计算机在网络中协作,共同完成任务。分布式系统的目标是让系统在用户看来像一个单一的协调工作的整体。

    分布式架构图

    分布式与微服务,第4张

    分布式服务器集群部署架构图

    分布式与微服务,第5张

    简单代码举例

    在分布式系统中,可以使用Java RMI(Remote Method Invocation)进行远程调用:

    public interface HelloService extends Remote {
        String sayHello(String name) throws RemoteException;
    }
    public class HelloServiceImpl extends UnicastRemoteObject implements HelloService {
        protected HelloServiceImpl() throws RemoteException {
            super();
        }
        @Override
        public String sayHello(String name) throws RemoteException {
            return "Hello, " + name;
        }
    }

    互联网架构演变

    互联网架构的演化是对技术进步和业务需求变化的一种适应。从早期的单体应用到现在的微服务和无服务器(Serverless)架构,每个阶段的变革都反映了数据管理和服务交付方式的根本变化。

    互联网架构演化概览

    1. 互联网1.0阶段 —— 以内容为王,数据主要用于展示和提取,如门户网站。

    2. 互联网2.0阶段 —— 用户生成内容(UGC)的兴起,强调数据关系和分析,如社交媒体平台。

    3. 移动互联网阶段 —— 生活服务的数字化,如即时通讯和社交应用。

    4. 万联网阶段 —— 物联网(IoT)的兴起,万物互联和数据化,如智能家居。

    架构设计演进原因

    • - 单体架构 —— 无法应对大数据量、高并发请求、快速业务迭代和庞大服务规模的挑战。
    • - 功能复杂性增加 —— 需要更多的计算能力。
    • - 数据量增加 —— 需要更有效的数据处理和存储方案。
    • - 请求密集 —— 需要更高效的负载均衡和网络处理能力。
    • - 业务迭代速度加快 —— 需要快速部署和持续集成的能力。
    • - 服务规模增大 —— 需要服务的自动化管理和弹性伸缩。

      架构演进的过程

      1. 单体架构 —— 初期的简单、集中式应用,易于部署和管理,但难以扩展。

      2. 水平分层架构 —— 技术和业务的逻辑分层,提高了一定的可维护性和可扩展性。

      3. 集群架构 —— 通过多个服务器实例提高应用的可用性和负载能力。

      4. 面向服务的架构(SOA) —— 服务的重用和集成,但依赖于服务总线(ESB),可能造成单点故障。

      5. 微服务架构 —— 服务细粒度拆分,独立部署,支持多种技术栈,提高了系统的灵活性和敏捷性。

      6. 服务网格架构 —— 解决微服务间通信的复杂性,提供了细粒度的通信控制和监视。

      7. 无服务化架构(Serverless) —— 抽象了服务器层,开发者只需关注业务逻辑,平台自动管理运行时环境和资源分配。

      架构演进的优缺点

      - 单体架构 —— 优点是简单易管理,缺点是不易扩展和维护。

      - 水平分层架构 —— 提高了可维护性,但可能增加了系统复杂性。

      - 集群架构 —— 提高了系统的可靠性和负载能力,但管理和维护成本增加。

      - SOA —— 服务可重用,易于集成,但对ESB的依赖可能成为瓶颈。

      - 微服务架构 —— 极大提升了系统的灵活性和扩展性,但也带来了服务治理和网络通信的复杂性。

      - 服务网格架构 —— 提供了微服务通信的高级功能,但增加了基础设施的复杂性。

      - 无服务化架构 —— 降低了运维负担,但可能带来冷启动问题和平台依赖性。

      架构演进的驱使

      核心驱动力是数据的处理需求和业务的快速迭代需求。技术的发展总是为了适应当前和未来的业务挑战,而架构的演进则是为了提供更加灵活、高效、可扩展的解决方案来支持这些需求。随着互联网技术的不断进步,架构设计也将继续演化,以满足新的业务需求和技术挑战。

      SpringCloud

      分布式与微服务,第6张

      集群+分布式+节点概念

      集群(Cluster)

      物理状态:集群指的是一组物理上汇集在一起的服务器或计算机。

      协作性:这些服务器可能并不总是协作工作,它们可以独立工作或被配置为协作工作。

      功能目的:当集群中的服务器协作时,它们通常是为了提高性能、可用性和负载均衡。

      业务实现:集群可以用于实现同一业务的高可用性和负载均衡,例如,一个Web服务可能部署在多个服务器上形成一个Web服务器集群。

      分布式(DistributedSystem)

      工作方式:分布式系统是一种工作方式,其中多个独立的计算机在网络中协作,共同完成任务或服务。

      用户透明性:对于用户来说,分布式系统看起来像是一个单一的、一致的系统。

      软件系统:这是一个建立在网络之上的软件系统,由多个节点组成,每个节点都可能承担不同的业务逻辑。

      业务分布:系统中的不同业务可能分布在不同的地理位置,每个业务可以是单独的服务或应用。

      例子:京东作为一个大型的分布式系统,拥有多个业务(如用户系统、订单系统、支付系统等)分布在不同的机器上。

      节点(Node)

      定义:在分布式系统或集群中,节点是指单个服务器或计算机。

      集群组成:节点是集群的基本组成单元。

      分布式架构:在分布式系统中,每个节点可能负责系统的一部分功能,可以是独立的服务或应用。

      集群化:分布式系统中的每个业务节点都可以进一步形成集群,以提高该业务的性能和可用性。

      关系和区别

      集群与分布式:集群通常是分布式系统的一部分,但一个集群本身不一定构成一个分布式系统。集群强调的是资源的物理组织形态,而分布式系统强调的是计算和工作的逻辑分布。

      节点的双重角色:一个节点可以是单独工作的独立计算机,也可以是集群或分布式系统中的组成部分。在分布式系统中,节点间通过网络连接,协同完成任务;而在集群中,节点可能仅仅是物理上集中在一起。

      集群化与分布式系统:一个业务系统的集群化是为了处理更高的访问压力,而分布式系统设计是为了整体架构的可扩展性、健壮性和地理分散性。

      简而言之,集群是指一组服务器的物理集合,可以但不必须协作执行任务;分布式系统是一种计算模型,其中任务在多个计算节点之间分配和执行,这些节点通过网络相连;而节点是构成集群和分布式系统的基本单元,每个节点都是一个计算实体。

      远程调用 (Remote Call)

              简单来说,远程调用是分布式计算中的一种通信过程,其中一个程序可以请求另一个位于远程计算机上的程序执行过程。

              分布式远程调用(DistributedRemoteInvocation)是分布式系统中的一种机制,它允许一个节点(客户端)调用另一个节点(服务器)上的方法或函数,就像调用本地方法一样。在分布式系统中,由于组件可能分布在不同的物理位置,因此需要一种能够在网络上进行通信的方法,远程调用就是实现这一点的关键技术。

      1.远程过程调用(RPC)

              远程过程调用(RPC)是一种协议,它允许程序调用另一台计算机上的程序,而无需了解网络的具体细节。RPC抽象了网络通信的复杂性,使得开发者可以像调用本地函数一样调用远程函数。

      2.远程方法调用(RMI)

      远程方法调用(RMI)是RPC的面向对象版本,特别用于Java环境。它允许一个Java虚拟机上的对象调用另一个Java虚拟机上的对象的方法。RMI使用序列化来编码请求和编码响应,以便它们可以在网络上发送。

      3.Web服务

              Web服务是一种服务导向架构(SOA)的实现,它允许不同的应用在网络上通过标准的HTTP协议进行互操作。Web服务通常使用SOAP(简单对象访问协议)或REST(表述性状态传递)作为它们的通信协议。

      4.RepresentationalStateTransfer(REST)

              REST是一种软件架构风格,它利用HTTP协议的标准方法(如GET、POST、PUT、DELETE)来进行通信。RESTfulWeb服务是基于REST原则构建的,它们易于理解和使用,并且是创建和使用WebAPI的流行方法。

      5.gRPC

              gRPC是一个现代的开源高性能RPC框架,它可以在任何环境中运行。它使用HTTP/2作为传输协议,以及ProtocolBuffers作为接口描述语言。gRPC支持双向流、流控制、头部压缩等高级特性。

      6.服务网格(ServiceMesh)

              服务网格是一种基础设施层,它提供了微服务之间的通信控制、服务发现、负载均衡、故障恢复和加密。Istio和Linkerd是两个流行的服务网格实现。

      在进行远程调用时,通常需要处理以下方面的问题:

      网络延迟:远程调用可能会受到网络延迟的影响,这可能导致性能问题。

      可靠性:网络通信可能不可靠,远程调用需要处理消息丢失、重复或乱序的问题。

      序列化:调用参数和返回值需要在网络上传输,这就需要序列化和反序列化机制。

      安全性:远程调用需要保证通信的安全性,防止数据泄露或被篡改。

      服务发现:在动态环境中,客户端需要一种机制来发现可用的服务实例。

              分布式远程调用是现代分布式系统中不可或缺的一部分,它支持构建高度可扩展、弹性和解耦的系统。

      Java简单代码示例:

      使用Spring Web的`RestTemplate`进行远程调用:

      RestTemplate restTemplate = new RestTemplate();
      String result = restTemplate.getForObject("http://remote-service/path", String.class);

      分布式常用工具与组件

              分布式系统通常需要一系列的工具和组件来处理服务发现、配置管理、通信、负载均衡、容错等方面的问题。以下是一些在构建和维护分布式系统时常用的工具及其用途的整理:

      SpringCloud

      目标:为开发者提供一套工具,用以实现分布式系统中的常见模式。

      功能:包括配置管理、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话和集群状态等。

      环境适应性:可以在各种分布式环境中运行,从开发者的个人笔记本电脑到裸机数据中心,再到云平台。

      组件生态:SpringCloud提供了一系列的子项目和组件,用于支持分布式系统的开发。

      SpringCloud下的工具

      SpringCloudGateway:提供智能路由服务,用于请求转发、过滤和路由。

      SpringCloudLoadBalancer:用于服务的负载均衡。

      SpringCloudOpenFeign:声明式的服务调用客户端,简化远程HTTP服务的调用。

      阿里巴巴提供的工具

      Nacos:提供服务发现和配置管理。

      Dubbo:高性能的JavaRPC框架,用于服务之间的调用。

      Sentinel:面向分布式服务架构的高可用性保障组件,提供服务容错。

      Netflix开源的组件

      Ribbon:客户端负载均衡器,可以在进行远程调用时提供负载均衡策略。

      Hystrix:用于处理分布式系统的延迟和容错。

      项目中采用的工具

      Nacos:用于服务发现和配置管理。

      Sentinel:作为服务容错的解决方案。

      Seata:处理分布式事务。

      Gateway:作为服务网关,管理服务的入口。

      OpenFeign:用于声明式的服务调用。

      Ribbon:在客户端提供负载均衡。

              这些工具和组件的组合为分布式系统的构建提供了一套完整的解决方案,旨在简化分布式系统中复杂问题的处理,如服务的发现、配置、调用、负载均衡和容错等。通过这些工具,开发者可以更加专注于业务逻辑的实现,而不是底层的通信和协调问题。

      负载均衡 (Load Balancing)

              负载均衡是指分散到多个执行资源(如计算机、网络链接等)的工作负载,以达到优化资源使用、最大化吞吐量、最小化响应时间和避免任何单一资源的过载。

      在Java中,负载均衡通常由负载均衡器(如Nginx, HAProxy)或服务发现框架(如Netflix Eureka)处理。

              在分布式系统中,服务之间的通信是通过网络进行的。当服务A需要调用服务B时,而服务B部署在多台机器上,服务A可以调用任意一台机器上的服务B来完成所需的功能。为了确保各个服务器的负载均衡,即没有服务器过载或空闲,需要引入负载均衡机制。

      常见的负载均衡算法:

       轮询(Round Robin):按顺序依次将请求分配给每个服务器,当到达列表末尾时,再次从头开始。

       最小连接(Least Connections):选择当前连接数最少的服务器,适用于会话较长的场景。

      使用 Netflix Ribbon 实现负载均衡

      Netflix Ribbon 是一个客户端负载均衡器,它可以与 Nacos Discovery 结合使用来实现服务间的负载均衡。Ribbon 有多种内置的负载均衡策略:

      •  BestAvailableRule:选择最小并发请求的服务器。
      •  AvailabilityFilteringRule:过滤掉连接失败标记为熔断的服务器,以及并发连接数过高的服务器。
      •  WeightedResponseTimeRule:根据响应时间计算权重,响应时间越长,权重越小。
      •  RetryRule:在选定的负载均衡策略上加上重试机制。
      •  RoundRobinRule:轮询方式选择服务器。
      •  RandomRule:随机选择一个服务器。
      •  ZoneAvoidanceRule:根据区域性能和服务器可用性选择服务器。

        全局负载均衡策略配置(策略1)

        @Bean
        public IRule loadBalanceRule(){
            return new RandomRule(); // 使用随机策略
        }

        为特定服务配置负载均衡策略(策略2)

        在 `application.yml` 中配置:

        user1:
          ribbon:
            NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

        服务调用

        使用 Spring Cloud OpenFeign,一个声明式的服务调用组件,可以简化远程调用:

        1. 引入 Maven 依赖
        
            Hoxton.SR8
        
        
            
                org.springframework.cloud
                springcloudstarteropenfeign
            
            
                org.springframework.cloud
                springclouddependencies
                ${springcloud.version}
                pom
                import
            
        
        2. 添加注解

        在启动类上添加 `@EnableFeignClients` 注解,并指定客户端接口所在的包路径。

        @SpringBootApplication
        @EnableFeignClients("com.woniuxy.cloud.order1.client") // 指定Feign客户端的包路径
        public class Order1Application {
            public static void main(String[] args) {
                SpringApplication.run(Order1Application.class, args);
            }
        }

        定义 Feign 客户端接口:

        @FeignClient("user1") // 指定调用的服务名
        public interface UserClient {
            @GetMapping("mallUser/getUser")
            String getUser(@RequestParam(value = "uid") Integer uid);
            @PostMapping("mallUser/putUser")
            String putUser(@RequestBody MallUserUpdateParam form);
            @DeleteMapping("mallUser/deleteUser")
            String deleteUser(@RequestParam(value = "uid") Integer uid);
            @PostMapping("mallUser/register")
            String register(@RequestBody MallUserParam form);
        }
        3. 进行调用

        在业务逻辑中,注入 Feign 客户端并调用:

        @RestController
        public class UserController {
            @Resource
            private UserClient userClient; // 注入Feign客户端
            @GetMapping("/deleteUser")
            public String deleteUser(@RequestParam(value = "uid") Integer uid) {
                return userClient.deleteUser(uid); // 使用Feign客户端进行远程调用
            }
        }

        通过这样的配置和代码,你可以实现服务间的负载均衡调用,同时使用声明式的服务调用来简化远程调用过程。

        服务注册与发现 (Service Registry and Discovery)

                服务注册与发现是微服务架构中的一个关键组件,允许服务实例在启动时注册自己的地址,并允许其他服务发现并调用这些实例。

        1.Eureka

        提供者:Netflix

        特点:Eureka是一个REST(RepresentationalStateTransfer)基础的服务,用于定位服务以实现中间层服务器的负载平衡和故障转移。EurekaServer作为服务注册中心,而客户端服务使用EurekaClient连接到服务器进行注册和查询。

        优点:

        与SpringCloud集成良好,适用于SpringBoot应用。

        简单易用,具有自我保护模式,能够应对网络分区问题。

        支持负载均衡和故障转移。

        缺点:

        与非Java语言的集成较为复杂。

        Netflix宣布Eureka2.0停止开发,未来可能需要依赖社区支持。

        适用场景:

        主要适用于使用SpringCloud构建的微服务架构。

        当需要快速搭建服务注册与发现功能时。

        对比优劣:

        相比于Consul和Zookeeper,Eureka的配置和使用更加简单,但是功能较为基础。

        相比Nacos,Eureka不提供配置管理功能。

        使用Spring Cloud的Eureka进行服务注册与发现:

        // 注册服务
        @EnableEurekaClient
        @SpringBootApplication
        public class MyServiceApplication {
            public static void main(String[] args) {
                SpringApplication.run(MyServiceApplication.class, args);
            }
        }
        // 发现服务
        @RestController
        public class DiscoveryController {
            @Autowired
            private DiscoveryClient discoveryClient;
            public String serviceUrl() {
                List list = discoveryClient.getInstances("MY-SERVICE-NAME");
                if (list != null && list.size() > 0 ) {
                    return list.get(0).getUri().toString();
                }
                return null;
            }
        }

        2.Consul

        提供者:HashiCorp

        特点:Consul提供了服务发现、健康检查、键值存储、多数据中心等功能。它使用一个分布式、高可用的系统来管理服务注册信息,并且提供了一个全功能的控制平面。

        优点:

        提供了服务发现、健康检查、键值存储和多数据中心的支持。

        具有良好的跨语言支持,适合多语言环境。

        可以通过ConsulTemplate实现配置管理。

        缺点:

        相对于Eureka和Nacos,配置和管理稍微复杂。

        对新手而言学习曲线较陡。

        适用场景:

        多数据中心的分布式系统。

        需要键值存储和服务发现结合的场景。

        对比优劣:

        相比于Eureka,Consul提供了更全面的特性,但配置和维护更为复杂。

        相比于Zookeeper,Consul更专注于服务发现和健康检查,而Zookeeper更多用于分布式协调。

        3.Zookeeper

        提供者:ApacheSoftwareFoundation

        特点:Zookeeper不仅是一个服务注册与发现的工具,还是一个分布式协调服务。在微服务架构中,它可以用来维护服务列表,并提供分布式锁和选举等机制。

        优点:

        提供了强一致性的服务发现和分布式协调。

        成熟稳定,被广泛应用于生产环境。

        缺点:

        配置和使用相对复杂,学习曲线陡峭。

        性能在大规模服务注册场景下可能会成为瓶颈。

        适用场景:

        需要强一致性保证的分布式服务。

        分布式锁、队列、领导选举等场景。

        对比优劣:

        相比于Consul和Eureka,Zookeeper在分布式协调方面更加出色,但在服务发现方面可能不那么直观。

        相比于etcd,Zookeeper社区更为成熟,但etcd在API设计上可能更现代。

        4.Nacos

        提供者:AlibabaGroup

        特点:Nacos支持服务发现和服务健康监测,同时也提供动态服务配置功能。它易于部署和维护,并且可以无缝集成到SpringCloud等框架中。

        优点:

        综合了服务发现和配置管理的能力。

        支持动态服务发现和健康检查。

        与SpringCloud和Dubbo等框架集成良好。

        缺点:

        相对较新,社区和生态可能不如Eureka和Consul成熟。

        在非Java环境下的支持可能不如Consul全面。

        适用场景:

        适用于需要同时进行服务发现和动态配置管理的微服务架构。

        主要针对SpringCloud或Dubbo等Java生态。

        对比优劣:

        相比于Eureka,Nacos提供了配置管理的附加功能。

        相比于Consul,Nacos可能在Java环境下更易于集成和使用。

        导入依赖

        在你的 Spring Boot 项目的 `pom.xml` 文件中,添加 Nacos Discovery Starter 依赖:

        
            com.alibaba.cloud
            springcloudstarteralibabanacosdiscovery
        

        这个依赖将允许你的应用程序使用 Nacos 作为服务发现的注册中心。

        修改配置

        在你的 Spring Boot 应用程序的 `application.yml` 或 `application.properties` 文件中,配置 Nacos 服务器的地址和服务的名称:

        spring:
          application:
            name: website  服务名称
          cloud:
            nacos:
              discovery:
                serveraddr: localhost:8848  Nacos 服务器地址

        这里指定了服务将注册到的 Nacos 服务地址,以及服务自身的名称。

        添加注解

        在你的 Spring Boot 应用的启动类上添加 `@EnableDiscoveryClient` 注解:

        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
        @SpringBootApplication
        @EnableDiscoveryClient // 启用服务发现客户端
        public class WebsiteApplication {
            public static void main(String[] args) {
                SpringApplication.run(WebsiteApplication.class, args);
            }
        }

        `@EnableDiscoveryClient` 注解告诉 Spring Cloud 创建一个用于发现服务的客户端。

        启动服务器

        在启动你的服务之前,确保 Nacos 服务已经启动并运行。你可以从 Nacos 的 [GitHub 发布页面](https://github.com/alibaba/nacos/releases) 下载 Nacos 服务器的最新版本,并根据其文档启动 Nacos 服务。

        服务发现的过程

        1. 生产者启动时进行服务注册:当你的服务(生产者)启动时,它会将自己的地址注册到 Nacos 服务中。

           

        2. 消费者拉取服务列表:服务消费者通过 Nacos 客户端查询服务注册列表,获取生产者的地址。

           

        3. 服务注册表对生产者进行健康检测:Nacos 会定期检查服务实例的健康状态。

           

        4. 如果发生变更,服务注册表则通知消费者:如果服务实例的状态发生变化,Nacos 会通知其他服务实例。

           

        5. 消费者重新拉取服务列表:消费者可以重新从 Nacos 获取更新后的服务实例列表。

        查看 Nacos Discovery 注册中心

        完成上述操作后,你可以通过访问 Nacos 控制台来查看服务的注册情况。默认情况下,Nacos 控制台的地址是 `http://localhost:8848/nacos`。

         登录:使用默认账号 `nacos` 和密码 `nacos` 进行登录。

         服务列表:登录后,点击 "服务列表" 或 "服务管理" 来查看当前注册的服务。

        在 Nacos 控制台中,你将能够看到你的服务 `website` 是否已经成功注册,以及它的健康状态和其他元数据信息。

        5.etcd

        提供者:CoreOS

        特点:etcd是一个高可用的键值存储,常用于配置共享和服务发现。etcd的设计考虑了分布式系统的需求,提供了一致性和高可靠性。

        优点:

        设计简单,提供了一致性和高可用性。

        性能优异,尤其适合读多写少的场景。

        Kubernetes使用etcd作为其后端存储。

        缺点:

        API相对底层,直接使用较为复杂。

        对于非Kubernetes环境,可能不是最直观的服务发现选择。

        适用场景:

        Kubernetes环境下的服务发现和配置管理。

        分布式系统中的一致性键值存储需求。

        对比优劣:

        相比于Zookeeper,etcd提供了更现代的API和更好的性能。

        相比于Consul,etcd在Kubernetes生态中更为常用。

        6.KubernetesServiceDiscovery

        提供者:CloudNativeComputingFoundation(CNCF)

        特点:在Kubernetes中,服务发现是一个内建功能。Pod和服务都有自己的IP地址和DNS名,服务发现和负载均衡是通过KubernetesServices实现的。

        优点:

        内建在Kubernetes中,与Kubernetes的其他功能紧密集成。

        自动处理Pod和服务的生命周期变化。

        缺点:

        仅限于Kubernetes环境。

        相对于独立的服务发现解决方案,定制化能力有限。

        适用场景:

        在Kubernetes环境下运行的微服务。

        对比优劣:

        相比于其他服务发现工具,Kubernetes的服务发现是为容器编排设计的,与Pod生命周期紧密集成。

        7.IstioServiceDiscovery

        提供者:Istio

        特点:Istio提供了一个连接、管理和保护微服务的完整的服务网格。它的服务发现机制是通过Pilot组件实现的,Pilot负责把服务信息分发给Envoy代理。

        优点:

        提供了一整套服务网格功能,包括服务发现、智能路由、流量管理等。

        与Kubernetes和其他平台集成良好。

        缺点:

        相对复杂,需要一定时间学习和部署。

        性能开销较大,需要额外资源。

        适用场景:

        需要复杂的流量管理和微服务治理的大规模分布式系统。

        对于服务之间的通信有严格的安全和监控要求的环境。

        对比优劣:

        相比于传统的服务注册与发现工具,Istio提供了更为全面的服务网格功能,但也带来了更高的复杂性和资源消耗。

        在Kubernetes环境中,Istio可以与内建的服务发现机制互补,提供更高级的流量控制和安全特性。

        8.SkyDNS

        SkyDNS是基于etcd的服务发现机制,它使用DNS协议进行服务发现。在Kubernetes的早期版本中,SkyDNS被用作其服务发现的机制,但在后续版本中被CoreDNS所取代。尽管如此,了解SkyDNS仍然有助于理解Kubernetes生态中服务发现的演变。

        特点:SkyDNS是基于etcd的服务发现工具,它使用DNS协议提供服务发现功能。SkyDNS可以与Kubernetes和etcd集成,提供服务发现和配置的功能。

        服务注册与发现组件是微服务架构中不可或缺的部分,它们确保服务间的通信是动态的、可靠的,并且可以适应不断变化的服务实例。选择哪个工具通常取决于系统的具体需求、技术栈的兼容性以及团队的熟悉程度。

        优点:

        简单的DNS接口:使用标准的DNS协议,可以很容易地被应用程序和开发者所理解和使用。

        基于etcd:由于依赖于etcd,它继承了etcd的高可用性和一致性特性。

        轻量级:SkyDNS相对较轻量级,对资源的消耗不大。

        缺点:

        限制性的查询:作为DNS系统,它不如HTTPAPI那样灵活,查询类型受到限制。

        被CoreDNS取代:在Kubernetes中,SkyDNS已经被CoreDNS取代,这意味着它没有得到最新的功能更新和社区支持。

        缺乏先进特性:相比于其他服务发现机制,SkyDNS缺少一些高级特性,如智能路由、流量管理等。

        适用场景:

        小型或简单的环境,不需要复杂的服务发现机制。

        需要利用DNS进行服务发现,且对服务发现的要求不是非常高级的场景。

        对比优劣:

        相比于Eureka和Consul,SkyDNS提供了一个更基础的服务发现机制,没有健康检查和服务间通信的高级功能。

        与Zookeeper和etcd相比,SkyDNS在分布式协调和配置管理方面不具备优势,它更专注于利用DNS进行服务发现。

        在Kubernetes生态中,相比于内建的服务发现和Istio提供的服务网格,SkyDNS的功能显得较为简单,适合于早期的Kubernetes集群或者非Kubernetes环境。

        SkyDNS在现代云原生架构中已经较少被单独使用,但它的设计思想和实现对理解DNS在服务发现中的作用仍有参考价值。在选择服务发现解决方案时,SkyDNS可能不是一个前沿的选择,但对于某些特定场景或遗留系统,它仍然可能是一个可行的选项。

        综合比较

        在选择服务注册与发现工具时,需要考虑以下因素来决定最适合的选项:

        技术栈兼容性:选择与现有技术栈兼容的工具,例如Java生态更倾向于选择Eureka或Nacos。

        功能需求:根据是否需要额外的功能(如配置管理、服务网格等)来选择,例如需要服务网格时考虑Istio。

        复杂性和易用性:考虑团队的技术能力和维护成本,简单场景可能更适合Eureka,而复杂场景可能需要Consul或Istio。

        性能和可靠性:大规模或高可用性需求的系统可能更倾向于使用etcd或Zookeeper。

        社区和生态支持:成熟的社区可以提供更多的资源和支持,如Zookeeper和Consul具有较为成熟的社区。

        扩展性和未来发展:考虑工具的发展趋势和未来支持,例如Eureka虽然简单但未来可能需要依赖社区支持。

        最终,选择哪个工具取决于具体的业务需求、团队的技术栈以及对于未来维护和扩展性的考量。在实际应用中,可能还会结合多种工具,以适应不同的场景和需求。

        接口共享 (Interface Sharing)

                将项目的接口和实现类,拆分开,项目的接口单独打包成模块,在另外一个项目中通过导入依赖的形式,使接口能够共享。

                在微服务架构中,将项目的接口与实现分离是一种常见的做法,这样做可以提高代码的重用性,同时也使得服务之间的依赖更加明确。以下是如何将接口拆分成单独模块并在其他项目中通过添加依赖来使用的步骤。

        步骤1:创建接口模块

        首先,你需要创建一个新的模块(通常是一个Maven项目),用于存放所有的接口和DTO(Data Transfer Object)类。这个模块不包含任何业务逻辑的实现。

        例如,创建一个名为 `service-api` 的Maven模块:service-api/pom.xml

        
            4.0.0
            com.example
            service-api
            1.0.0
        

        在这个模块中,你可以定义接口和DTO:

        service-api/src/main/java/com/example/serviceapi/UserService.java

        package com.example.serviceapi;
        public interface UserService {
            String getUser(Long id);
            // 其他方法定义
        }

        service-api/src/main/java/com/example/serviceapi/dto/UserDto.java

        package com.example.serviceapi.dto;
        public class UserDto {
            private Long id;
            private String name;
            // getter and setter methods
        }

        步骤2:在服务提供者模块中实现接口

        在服务提供者的项目中,你需要添加对 `service-api` 模块的依赖,并实现那里定义的接口。

        service-provider/pom.xml

        
            
                com.example
                service-api
                1.0.0
            
            
        

        然后,实现接口:

        service-provider/src/main/java/com/example/serviceprovider/UserServiceImpl.java

        package com.example.serviceprovider;
        import com.example.serviceapi.UserService;
        import com.example.serviceapi.dto.UserDto;
        import org.springframework.stereotype.Service;
        @Service
        public class UserServiceImpl implements UserService {
            @Override
            public String getUser(Long id) {
                // 实现获取用户逻辑
                return "User Details";
            }
            // 其他方法实现
        }

        步骤3:在服务消费者模块中调用接口

        在服务消费者的项目中,同样添加对 `service-api` 模块的依赖。

        service-consumer/pom.xml

        
            
                com.example
                service-api
                1.0.0
            
            
        

        在服务消费者项目的 `infra` 层(或其他适当的层),你可以通过远程调用服务提供者暴露的接口:

        service-consumer/src/main/java/com/example/serviceconsumer/infra/UserClient.java

        package com.example.serviceconsumer.infra;
        import com.example.serviceapi.UserService;
        import org.springframework.cloud.openfeign.FeignClient;
        @FeignClient("user-service-provider") // user-service-provider 是服务提供者的服务名
        public interface UserClient extends UserService {
            // 继承了 UserService 接口,Feign 会处理具体的实现
        }

        现在,你可以在服务消费者的业务逻辑中注入 `UserClient` 并使用它来调用远程服务:

        service-consumer/src/main/java/com/example/serviceconsumer/controller/UserController.java

        package com.example.serviceconsumer.controller;
        import com.example.serviceconsumer.infra.UserClient;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.web.bind.annotation.*;
        @RestController
        @RequestMapping("/user")
        public class UserController {
            @Autowired
            private UserClient userClient;
            @GetMapping("/{id}")
            public String getUser(@PathVariable Long id) {
                return userClient.getUser(id);
            }
        }

        通过这种方式,你可以将接口单独打包成模块,并在不同的项目之间共享,这样做的好处是接口的变动只需要在接口模块中修改一次,所有依赖此接口模块的服务都可以共享这些变动。同时,这种做法也符合微服务架构中服务契约的理念。

        分布式事务 (Distributed Transaction)

        分布式事务是在分布式系统中执行的事务,它需要跨多个数据源或网络分布的节点保持一致性。

        分布式事务解决方案

        分布式事务是指事务的操作分布在不同的节点上,每个节点都可以是一个独立的服务提供者。在分布式系统中,保证事务的ACID属性(原子性、一致性、隔离性和持久性)通常比单体应用中更加复杂。以下是一些解决分布式事务的常见方案:

        1. 两阶段提交(2PC, Two-Phase Commit)

           两阶段提交是经典的分布式事务协议。它包括两个阶段:准备阶段和提交/回滚阶段。在准备阶段,协调者询问所有参与者是否准备好提交事务,如果所有参与者都同意,那么在提交阶段,协调者指示所有参与者提交事务;否则,协调者指示所有参与者回滚事务。两阶段提交保证了事务的原子性,但它有可能导致资源锁定和单点故障。

        2. 三阶段提交(3PC, Three-Phase Commit)

           三阶段提交是对两阶段提交的改进,它增加了一个预提交阶段,以减少锁定资源的时间,并尝试避免单点故障。三阶段提交比两阶段提交更为复杂,但在某些情况下可以提供更好的性能和更少的阻塞。

        3. 补偿事务(TCC, Try-Confirm/Cancel)

           TCC是一种业务层面的分布式事务解决方案。它将事务分为三个操作:尝试(Try)、确认(Confirm)和取消(Cancel)。首先执行Try操作预留资源,然后在确认阶段执行Confirm操作提交事务,如果任何一个服务失败,则执行Cancel操作回滚事务。TCC适用于业务逻辑允许明确的补偿操作的场景。

        4. 本地消息表

           应用程序将事务操作和消息通知写入同一个本地数据库中的表里,确保它们在同一个本地事务中。然后通过轮询或其他机制发送消息,确保最终一致性。这种方式简单且不依赖于外部系统,但需要应用程序自行管理消息的重试和监控。

        5. 消息队列

           利用消息队列进行异步通信,实现最终一致性。这种方式通常结合本地事务和消息系统的可靠性来保证消息的传递,但不保证全局事务的即时一致性。

        6. 分布式事务中间件

           如Seata、Atomikos等,提供了完整的分布式事务解决方案,包括分支事务的注册、状态同步、事务回滚等功能。这些框架通常提供对2PC或TCC等模式的封装,简化了分布式事务的实现。

        7. 最终一致性

           有些场景下,可以接受事务不是立即一致,而是最终一致的。这种情况下,可以使用各种基于时间或条件的一致性模型,如BASE(Basically Available, Soft state, Eventually consistent)模型,通过业务和技术手段保证最终数据的一致性。

        8. SAGA模式

           SAGA是一种将长期事务分解为一系列的本地事务,每个本地事务完成后发布事件或消息以触发下一个本地事务的模式。如果某个本地事务失败,SAGA会执行一系列的补偿事务来回滚之前的操作。

                选择哪种分布式事务解决方案通常取决于具体的业务需求、性能要求和系统设计。例如,对于需要强一致性的场景,可能需要选择2PC或3PC;而对于可以容忍最终一致性的业务,可以使用基于消息的解决方案或SAGA模式。

        分布式事务中间件Seata

                Seata 是一个开源的分布式事务解决方案,旨在提供高性能和简单的分布式事务服务。AT模式是其支持的几种事务模式之一,它使用两阶段提交机制处理分布式事务。以下是使用 Seata AT模式进行分布式事务处理的详细步骤和相关解释:

        第一阶段:预备阶段

                在这个阶段,业务逻辑被执行。Seata 会代理数据源并截获所有的 SQL 操作。对于每个 SQL 操作,Seata 记录数据库操作的前后镜像,这些镜像信息会被存储在 `undo_log` 表中。这样做的目的是为了在事务提交失败时能够回滚到事务开始之前的状态。

        第二阶段:提交阶段

                如果业务操作正常完成,Seata 会从 `undo_log` 表中删除对应的镜像数据,表示事务已经成功提交。如果业务操作失败,Seata 会使用 `undo_log` 表中的镜像数据来将数据库回滚到事务开始之前的状态,以保证数据一致性。

        实际操作步骤

        1. 导入依赖:在项目的 `pom.xml` 文件中添加 Seata 的依赖。

        
            com.alibaba.cloud
            spring-cloud-starter-alibaba-seata
        

        2. 创建 `undo_log` 表:在数据库中创建 `undo_log` 表,用于存储事务的镜像数据。

        CREATE TABLE `undo_log` (
          `id` bigint(20) NOT NULL AUTO_INCREMENT,
          `branch_id` bigint(20) NOT NULL,
          `xid` varchar(100) NOT NULL,
          `context` varchar(128) NOT NULL,
          `rollback_info` longblob NOT NULL,
          `log_status` int(11) NOT NULL,
          `log_created` datetime NOT NULL,
          `log_modified` datetime NOT NULL,
          `ext` varchar(100) DEFAULT NULL,
          PRIMARY KEY (`id`),
          UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
        ) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;

        3. 使用 `@GlobalTransactional` 注解:在需要进行分布式事务控制的业务方法上添加 `@GlobalTransactional` 注解。

        @GlobalTransactional
        public void someTransactionalMethod() {
            // 业务逻辑
        }

        4. 配置 `application.yml`:在应用的配置文件中配置 Seata 相关参数,包括服务分组、服务名、注册中心地址等。

        seata:
          enabled: true
          application-id: my-application
          tx-service-group: my-tx-group
          service:
            vgroup-mapping:
              my-tx-group: default
            enable-degrade: false
            disable-global-transaction: false

        5. 启动 Seata Server:Seata Server 作为事务协调者(Transaction Coordinator,TC),需要独立部署和启动。

        sh seata-server.sh

                通过以上步骤,你可以在你的应用中集成 Seata 并使用 AT模式来管理分布式事务,确保跨服务的数据一致性。需要注意的是,Seata 的配置和使用可能会因版本和环境的不同而有所差异,因此在实际部署时应参考官方文档进行配置。

        配置中心 (Configuration Center)

                配置中心是用于集中管理应用配置的工具,它允许开发人员在不同环境和服务之间共享和管理配置。

        配置中心解决方案

                分布式配置中心是现代微服务架构中的一个关键组件,它们帮助集中管理服务配置,从而简化了跨多个环境和服务实例的配置管理。以下是一些流行的分布式配置中心解决方案:

        1. Spring Cloud Config: 提供服务器和客户端支持,配置存储在后端如Git仓库或文件系统中。

        2. Consul: 由HashiCorp开发,它不仅提供配置管理,还提供服务发现功能。

        3. Apache Zookeeper: 主要用于协调分布式系统,但也可以用作配置信息的存储和同步。

        4. etcd: 由CoreOS开发,是一个分布式键值存储,常用于保存和管理配置数据。

        5. Netflix Archaius: 配合Eureka使用,支持动态配置管理,可以从多种来源读取配置。

        6. Nacos: 由阿里巴巴开发,支持服务发现和服务配置管理。

        7. Configurate: 为Java应用程序提供配置管理,支持多种数据源和格式。

        8. Vault: 也是由HashiCorp开发,主要用于存储敏感信息,但也可以用于配置管理。

        9. Redis: 虽然它是一个键值数据库,但它的速度和简单性使得一些组织也用它来管理配置数据。

        10. AWS Parameter Store / AWS AppConfig: Amazon Web Services提供的配置管理服务,可以集中管理应用配置和机密数据。

        11. Azure App Configuration / Azure Key Vault: 微软Azure提供的配置管理服务,用于管理应用程序设置和机密。

        12. Google Cloud Config: Google Cloud Platform提供的配置管理服务,用于集中管理运行在GCP上的应用程序的配置。

        选择哪个分布式配置中心取决于多个因素,包括与现有工具的兼容性、对配置更新的敏感性、对故障恢复的要求、安全性需求、以及是否需要与某个云服务提供商紧密集成。每个工具都有其特点和最佳使用场景,因此在选择之前应当根据具体的业务需求和技术栈进行评估。

        Spring Cloud Config

                为了集中管理微服务的配置信息,Spring Cloud 提供了一个名为 Spring Cloud Config 的项目。Spring Cloud Config 支持配置信息的集中存储,并且可以在不重启服务的情况下刷新配置。这样,当你需要更改配置时,只需在配置中心更改一次,所有连接到配置中心的服务都会更新到最新的配置。

        以下是如何使用 Spring Cloud Config 来实现配置中心的基本步骤:

        配置中心服务端(Config Server)

        1. 创建一个新的 Spring Boot 应用作为配置中心服务端。

        2. 在 `pom.xml` 中添加 Config Server 的依赖:

        
            
                org.springframework.cloud
                spring-cloud-config-server
            
        

        3. 在程序的入口类上添加 `@EnableConfigServer` 注解,以激活配置服务器功能。

        @SpringBootApplication
        @EnableConfigServer
        public class ConfigServerApplication {
            public static void main(String[] args) {
                SpringApplication.run(ConfigServerApplication.class, args);
            }
        }

        4. 在 `application.yml` 中配置配置服务器的相关信息,如配置文件的存储位置(可以是本地文件系统或远程Git仓库)。

        server:
          port: 8888
        spring:
          cloud:
            config:
              server:
                git:
                  uri: https://github.com/your-organization/config-repo.git
                  clone-on-start: true
                  default-label: main

        客户端(Config Client)

        1. 在每个微服务应用中,添加 Config Client 的依赖:

        
            
                org.springframework.cloud
                spring-cloud-starter-config
            
        

        2. 在 `bootstrap.yml` 文件(注意不是 `application.yml`)中配置连接到配置服务器的信息:

        spring:
          application:
            name: product-service
          cloud:
            config:
              uri: http://localhost:8888
              label: main

        3. 通过注解 `@RefreshScope`,可以在不重启服务的情况下,刷新配置。

        @RestController
        @RefreshScope
        public class ConfigClientController {
            @Value("${some.config.value}")
            private String configValue;
            @GetMapping("/show-config")
            public String showConfig() {
                return configValue;
            }
        }

        4. 当配置中心的配置信息更新后,可以通过调用客户端的 `/actuator/refresh` 端点来刷新配置。

        为了使 `/actuator/refresh` 端点可用,需要在客户端应用中添加以下依赖:

        
            org.springframework.boot
            spring-boot-starter-actuator
        

        并在 `application.yml` 中暴露该端点:

        management:
          endpoints:
            web:
              exposure:
                include: refresh

        现在,每当配置中心的配置更新后,可以发送一个 POST 请求到每个微服务的 `/actuator/refresh` 端点,或者使用 Spring Cloud Bus 自动刷新所有服务的配置。

        通过以上的配置,你就可以实现一个基本的配置中心,它能够集中管理微服务的配置信息,并且支持动态刷新配置。

        服务熔断&服务降级

        服务熔断 (Service Circuit Breaker)

                服务熔断是一种自动化的保护机制,当服务失败的比率超过一个阈值时,熔断器会打开,后续的调用会自动失败,而不是继续让调用方等待。

                在微服务架构中,服务熔断和服务降级是两种重要的容错机制,它们可以防止系统因为一个服务的失败而导致整个系统不可用,即所谓的“雪崩效应”。

        服务熔断的概念类似于电路中的断路器。当某个微服务出现问题,比如响应时间过长或错误率过高时,熔断机制会被触发。这时,熔断器会“断开”,阻止进一步的访问,从而避免不必要的等待和资源消耗。同时,熔断器会定期检查服务是否恢复正常,一旦检测到服务状态良好,熔断器会自动“闭合”,恢复服务调用。

        熔断器通常有三种状态:

        - 闭合(Closed): 所有请求都可以直接调用服务。

        - 打开(Open): 所有请求都会被熔断器拦截,并快速返回错误响应。

        - 半开(Half-Open): 允许部分请求通过以测试服务是否恢复正常。

        服务降级 (Service Degradation)

                服务降级是在系统负载较重时,暂时屏蔽掉一些服务功能,以保证核心功能的正常运行。

                服务降级通常与熔断机制一起使用,如上面的Hystrix示例中的`reliable`方法。

                服务降级是指在某些情况下,为了保证核心服务的可用性,有意识地放弃或者降低某些服务的服务质量。例如,在系统负载过高时,可以暂时关闭一些非核心功能,或者提供一个简化的服务响应。

                服务降级可以在客户端实施,也可以在服务器端实施。客户端降级通常是在请求超时或熔断触发时,执行一些预定义的备选方案(如返回缓存数据或默认值)。服务器端降级则可能是由于资源紧张,主动限制某些服务的功能,比如限流。

        实际应用

                在实际应用中,熔断和降级往往需要配合使用。使用如Hystrix、Resilience4j等工具可以实现这些模式。在Spring Cloud生态中,可以通过以下方式实现:

        使用Hystrix实现熔断

        @Service
        public class InventoryService {
            @HystrixCommand(fallbackMethod = "getDefaultInventoryResponse")
            public String getInventoryStatus(String productId) {
                // 调用库存服务获取状态
            }
            public String getDefaultInventoryResponse(String productId) {
                // 当熔断发生时返回默认响应
                return "Default Inventory Response";
            }
        }

         使用Sentinel实现降级

        public class ProductService {
            @SentinelResource(value = "getProductDetails", fallback = "fallbackForGetProductDetails")
            public Product getProductDetails(String productId) {
                // 调用商品服务获取产品详情
            }
            public Product fallbackForGetProductDetails(String productId, Throwable ex) {
                // 服务降级的逻辑
                return new Product(productId, "Fallback Product", 0);
            }
        }

                在这些示例中,`@HystrixCommand` 和 `@SentinelResource` 注解分别用于指定熔断和降级的逻辑。当服务调用失败或不满足某些条件时,这些备用方法将被调用。

        结合实际情景

                在实际情景中,比如订单服务调用商品服务,商品服务再调用库存服务:

        - 如果库存服务响应缓慢,商品服务可以设置一个合理的超时时间,并且使用熔断机制。一旦库存服务的响应时间超过这个阈值或失败率过高,熔断器会打开,后续的调用会直接返回一个预定义的默认响应或错误信息,避免影响到订单服务。

        - 在高峰期,如果系统资源紧张,可以通过服务降级来关闭或简化一些非关键业务流程。例如,商品服务可以返回一些缓存的商品信息或简化的库存信息,而不是实时查询库存服务。

                通过这样的机制,即使在高并发情况下,也能有效地防止系统崩溃,保持服务的最大可用性。

        服务容错

                Sentinel是阿里巴巴开源的面向分布式服务架构的高可用性和弹性的服务容错库。它主要用于处理微服务架构中的服务稳定性和负载保护问题。Sentinel提供了以下几个关键特性来保证分布式服务的容错:

        1.流量路由:Sentinel可以控制请求根据某些参数(如来源、参数等)路由到不同的服务实例。

        2.流量控制:它可以限制应用的流量,防止应用过载,包括QPS限流和并发线程数限流。

        3.流量整形:Sentinel支持冷启动、排队等待等多种流量整形方式,以平滑地处理突发流量。

        4.熔断降级:在服务不稳定或响应时间过长时,Sentinel可以自动进行熔断降级,快速释放资源。

        5.系统自适应过载保护:Sentinel可以根据系统负载自动调整流量入口的阈值。

        6.热点流量防护:Sentinel可以识别热点参数,并对这些热点参数进行限流,防止某个特定的参数导致的流量集中爆发。

                Sentinel控制台是一个管理界面,可以让开发者可视化地管理和监控Sentinel规则和活动。通过控制台,开发者可以实时监控应用的运行状态,以及动态地调整规则。

                规则的定义和推送是Sentinel非常重要的一个特性。Sentinel支持多种规则的定义,包括流量控制规则、熔断降级规则、系统保护规则等。规则可以通过代码定义,也可以通过控制台动态推送。Sentinel支持多种数据源,如文件、Nacos、Zookeeper、Apollo、Etcd等,可以实现规则的实时推送和动态变更。

                例如,如果你想实现QPS限流,你可以通过Sentinel控制台为某个资源设置流量控制规则,定义QPS阈值。一旦流量超过这个阈值,Sentinel就会根据预设的流量控制效果(如直接拒绝、冷启动、排队等待)进行处理。

                在微服务架构中,Sentinel的这些特性非常有用,因为它们可以保护系统在高流量或者服务故障时仍然能够正常运行,或者至少能够优雅地降级,从而提高系统的稳定性和可靠性。

        API网关 (API Gateway)

        分布式API网关

                在现代微服务架构中,API网关是一个核心服务,它充当所有客户端和服务端之间的中介。API网关处理非业务功能,如请求路由、负载均衡、认证、授权、安全、缓存、监控等,允许业务逻辑服务专注于处理核心业务需求。

        核心功能

        1. 请求路由:API网关负责将外部请求路由到正确的服务实例上。在微服务架构中,服务实例可能有多个,并且可能分布在不同的服务器或容器中。

        2. 客户端负载均衡:API网关通常包括一个负载均衡器,它可以将请求分散到多个服务实例,以防止任何单个实例的过载。

        3. 服务熔断:API网关可以实现熔断机制,当下游服务出现问题时,快速失败,防止问题扩散。

        4. 灰度发布:灰度发布是一种软件发布方法,允许你逐渐将新版本的服务引入生产环境,API网关可以控制流量分配,使一部分用户使用新版本,而其他用户仍使用旧版本。

        5. 统一认证:API网关可以提供一个集中的认证服务,确保所有进入微服务架构的请求都被适当地认证。

        6. 限流和监控:API网关可以限制客户端对API的使用频率,以防止资源过度使用。同时,它可以监控服务使用情况,为性能分析和计费提供数据。

        7. 日志和统计:API网关可以记录关于流量模式、服务使用情况、响应时间等的详细日志和统计信息。

        8. 跨域资源共享(CORS):API网关可以处理跨域请求,允许或拒绝来自不同域的请求,从而简化单个服务的CORS配置。

        9. API聚合:网关可以将多个服务调用聚合成一个API调用,减少客户端的网络请求次数。

        10. 协议转换:API网关可以在不同的通信协议之间进行转换,例如将外部的HTTP请求转换为内部的gRPC或AMQP消息。

        11. 缓存:为了减少后端服务的负载,API网关可以实现响应缓存。

        12. 服务发现集成:API网关通常与服务发现机制集成,自动检测服务实例的变化。

        实现工具

        市场上有多种API网关产品和开源项目,包括但不限于:

        - Kong:一个开源API网关和微服务管理层,支持插件扩展。

        - Amazon API Gateway:AWS提供的托管服务,可以创建、发布、维护、监控和保护REST、HTTP和WebSocket APIs。

        - Zuul:由Netflix开发的API网关服务,与Eureka等其他Netflix OSS组件紧密集成。

        - Spring Cloud Gateway:Spring Cloud的API网关,专为Spring Boot应用设计。

        - Apigee:Google Cloud提供的一个平台,用于API管理。

        - Tyk:一个轻量级的API网关,支持多种协议。

        架构考虑

        在设计API网关时,需要考虑以下几个关键点:

        -高可用性:API网关是所有请求的入口点,因此必须是高度可用的。

        -扩展性:随着服务数量和请求量的增加,API网关应该能够水平扩展。

        -安全性:API网关是安全策略的理想实施点,如API密钥管理、OAuth令牌验证等。

        -性能:API网关可能成为瓶颈,因此必须优化以处理高并发请求。

        Gateway

        API网关是系统的入口,它处于客户端和服务之间,负责请求转发、认证、协议转换等。

        使用Spring Cloud Gateway作为API网关:

        @Bean
        public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
            return builder.routes()
                    .route(r -> r.path("/api/service/**")
                            .uri("lb://MY-SERVICE"))
                    .build();
        }

        单点登录 (Single Sign-On, SSO)

        单点登录是一种身份验证过程,它允许用户使用一个认证源登录多个独立的系统。

        分布式单点登录(SSO)是一种身份验证过程,允许用户在多个应用程序和服务中使用一组登录凭据进行访问。这不仅提高了用户体验,还简化了用户管理和安全性监控。在微服务架构中,这一点尤其重要,因为用户可能需要跨多个服务进行操作。

        分布式单点登录的关键组件

        1. 认证服务器:负责处理登录认证和令牌发放。认证服务器是单点登录的核心,所有的服务都会委托它进行用户认证。

        2. 会话存储:通常使用Redis这样的内存数据存储来维护全局会话状态。这样可以实现快速访问和跨服务的会话共享。

        3. 客户端Cookie:浏览器中的Cookie用于存储令牌(如访问令牌或者刷新令牌),以便在用户与不同的服务交互时保持会话。

        4. 令牌管理:令牌是认证的凭证,必须安全生成和验证。sa-token是一个轻量级权限认证框架,可以很好地管理这些令牌。

        分布式单点登录的工作流程

        1. 用户登录:用户在单点登录系统的登录页面输入凭据。

        2. 认证并生成令牌:认证服务器验证用户凭据,成功后生成令牌,并将其存储在Redis中。

        3. 设置Cookie:认证服务器将令牌发送给用户的浏览器,并设置相应的Cookie。

        4. 服务间共享状态:用户随后的请求会携带这个Cookie,每个服务都可以通过Cookie中的令牌来向认证服务器验证用户身份。

        5. 服务访问:一旦身份验证成功,用户就可以在不同的服务之间无缝切换,无需再次登录。

        扩展功能

        - 会话同步:当用户在一个服务中登出时,其他服务也应同步登出。这通常通过发布/订阅模式在各服务间同步会话状态来实现。

        - 令牌刷新:长时间运行的应用可能需要在令牌过期之前自动刷新它们,以保持用户会话。

        - 多因素认证:为了增强安全性,可以集成多因素认证(MFA),要求用户提供额外的认证因素。

        - 适配多种客户端:单点登录系统应支持从各种客户端访问,包括浏览器、移动应用和桌面应用。

        - 安全性增强:例如,使用HTTPS保护所有的通信,限制Cookie的作用域和生命周期,以及实现防止CSRF攻击的措施。

        总结

        通过使用基于Redis共享和Cookie的方法,结合sa-token框架,可以有效地实现分布式单点登录。这种方法的优势在于它的高可用性、可扩展性和相对简单的实现。然而,随着系统的成熟和用户基础的增长,可能需要考虑引入更复杂的安全措施和认证机制,如OAuth 2.0、OpenID Connect等。这些协议提供了标准化的方式来处理身份验证和授权,使得单点登录更加安全和可靠。

        Spring Security OAuth2

        SSO通常涉及到安全框架,如Spring Security OAuth2:

        @Configuration
        @EnableOAuth2Sso
        public class SSOConfiguration extends WebSecurityConfigurerAdapter {
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                http
                    .antMatcher("/**")
                    .authorizeRequests()
                    .antMatchers("/", "/login**")
                    .permitAll()
                    .anyRequest()
                    .authenticated();
            }
        }
        

        在这个例子中,@EnableOAuth2Sso注解启用了单点登录功能。configure方法定义了安全规则,允许所有用户访问首页和登录页面,而其他请求则需要认证。

         

        分布式与微服务,第7张

        有用请点赞,养成良好习惯!

        疑问、交流、鼓励请留言!