微服务间通信重构与服务治理笔记

父工程

依赖版本管理,但实际不引入依赖

pom.xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>SpringCloud</artifactId>
    <version>1.0-SNAPSHOT</version>
   
    <packaging>pom</packaging>
    <!-- 统一管理jar包版本 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
        <mysql.version>5.1.47</mysql.version>
        <druid.version>1.1.16</druid.version>
        <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
    </properties>


    <!-- 子模块继承之后,提供作用:锁定版本+子modlue不用写groupId和version  -->
    <dependencyManagement>
        <dependencies>
            <!--spring boot 2.2.2-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud Hoxton.SR1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud alibaba 2.1.0.RELEASE-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring.boot.version}</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <optional>true</optional>
            </dependency>

        </dependencies>
    </dependencyManagement>

    <build>
        <finalName>cloud</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.2.2.RELEASE</version> <!-- 与Spring Boot版本对应 -->
                <configuration>
                    <fork>true</fork>
                    <addResources>true</addResources>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

支付模块

复制代码
server:
  port: 8081

spring:
  application:
    name: cloud-payment-service
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: org.gjt.mm.mysql.Driver
    url: jdbc:mysql://xxxx:3306/db2019?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: xxxx
    password: xxxxxxx

mybatis:
  mapperLocations: classpath:mappers/*.xml
  #这些Java Bean在mapper XML文件中可以使用别名代替全限定类名
  type-aliases-package: com.example.commons.pojo
logging:
  level:
    com:
      example:
        pay:
          mapper: debug

#将服务注册到Eureka
eureka:
  client:
    #表示是否将自己注册进EurekaServer默认为true
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息默认true 单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      #defaultZone: http:http://eureka7001.com:7001/eureka/
      #集群版
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

模块结构

依赖 eureka client是后期要用的

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>SpringCloud</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-provider-payment8081</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.example</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

pojo

映射文件 因后期重构 以移动到commons

复制代码
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.pay.mapper.PaymentMapper">

    <insert id="createPayment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)value(#{serial})
    </insert>

    <select id="getPaymentById" resultType="com.example.commons.pojo.payment">
        select * from payment where id=#{id}
    </select>
</mapper>

控制器

订单模块

在父工程下创建moudle

配置RestTemplate

调用支付模块

application.yml

复制代码
server:
  port: 80

spring:
  application:
    name: cloud-consumer-ord
#将服务注册到Eureka
eureka:
  client:
    #表示是否将自己注册进EurekaServer默认为true
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息默认true 单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      #defaultZone: http://localhost:7001/eureka
      #集群版
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

将支付和订单的pojo单独重构放到commons模块并在支付和订单模块分别引入

Eureka服务治理

SpringCloud封装了Netflix公司的Eureka模块来实现服务治理

Eureka是服务发现与治理的一套解决方案 还有Nacos Zookeeper Sofa Consul Etcd

在传统的RPC远程调用(如Dubbo,RestTemplate不属于RPC调用)框架中,管理每个服务与服务之间依赖关系比较复杂,所以需要服务治理.实现服务发现与注册.Eureka维护一个服务注册表,其他服务可以查询这个注册表来发现和调用其他微服务.

Eureka使得各个微服务之间能够相互发现并进行通信,但它本身不提供远程调用的功能

Eureka采用CS设计架构.Eureka Server做为服务注册功能的服务器.它是服务注册中心,而系统中的其他微服务,使用Eureka的客户端连接到Eureka的Server并通过心跳连接检测.这样系统的维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行.

在服务注册与发现中,有一个注册中心,当服务器启动的时候,会把当前自己服务器的信息,比如服务器通讯地址等以别名方式注册到注册中心.消费者可通过注册中心获取服务通信地址.然后通过RPC调用.任何RPC远程调用框架都会有一个注册中心(存放服务地址相关信息包括接口地址)

Eureka包含两个组件:Eureka Server和Eureka Client

Eureka Server提供服务注册

各个微服务节点通过配置启动之后,会在EurekaServer进行注册,这样EurekaServer中的服务注册表中将存储可用服务的节点信息.

Eureka Client通过注册中心访问

是一个Java客户端,为了简化EurekaServer的交互,客户端同时也具备一个内置的,使用轮询(round-robin)负载算法的负载均衡器.应用启动后,将会向Eureka Server发送心跳(默认30秒发送一次).如果Eureka Server在多个心跳周期内没有接收到某个节点发送的心跳.EurekaServer将会从服务注册表中将该节点移除(默认90秒)

单机版Eureka服务注册中心构建

@EnableEurekaServer表示我是一个EurekaServer

application.yml

复制代码
server:
  port: 7001

eureka:
  instance:
    hostname: localhost  # eureka服务端的实例名称
  client:
    # 表示不向注册中心注册自己
    register-with-eureka: false
    # 表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      # 设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址  ${}是上面定义的
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

pom.xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>SpringCloud</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-eureka-server-7001</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.example</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web  -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>

    </dependencies>
</project>

localhost:7001/

支付模块完成服务注册

首先引入依赖

复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

启动类加上客户端注解

application.yml

复制代码
#将服务注册到Eureka
eureka:
  client:
    #表示是否将自己注册进EurekaServer默认为true
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息默认true 单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

订单模块完成服务注册

依赖

复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

访问 localhost:7001/

Eureka服务治理集群构建

目的高可用,如果单个Eureka服务挂了,会导致整个服务环境不可用

搭建Eureka注册中心集群,实现负载均衡+故障容错

比如有两台Eureka服务 7001和7002

那就是相互注册

如果是三台 7001 7002 7003

那么就是7001注册 7002和7003 7002注册7001和7003 7003注册7001和7002

两两相望 相互注册

为了看的清除

C:\Windows\System32\drivers\etc\hosts

127.0.0.1 eureka7001.com

127.0.0.1 eureka7002.com

pom.xml

复制代码
<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>

    <dependency>
        <groupId>org.example</groupId>
        <artifactId>cloud-api-commons</artifactId>
        <version>${project.version}</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web  -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>

</dependencies>

主启动类

application.yml配置文件需要相互注册

复制代码
server:
  port: 7002


eureka:
  instance:
    hostname: eureka7002.com  # eureka服务端的实例名称
  client:
    # 表示不向注册中心注册自己
    register-with-eureka: false
    # 表示自己就是注册中心,职责是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      # 设置与eureka server交互的地址查询服务和注册服务都需要依赖这个地址  ${}是上面定义的
      #defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
      defaultZone: http://eureka7001.com:7001/eureka/

在原先7001的application里修改配置

互相启动

支付模块和订单模块注册到服务治理集群

修改订单服务的application.yml

修改支付服务的application.yml

支付模块微服务集群搭建

剩下就是个复制过程

注意 对外暴露都是同一个服务名 重要

那么现在就牵扯出另外一件事 到底调用哪个服务 和 负载均衡

完成后

现在调用

那么订单这边也不能写死了

使用服务名

使用Ribbon做负载均衡

@LoadBalanced注解 表示使用Ribbon进行负载均衡

该注解是引入Eureka客户端依赖时引入的 默认轮询

默认是轮询策略 可以修改配置

Ribbon和Eureka整合后Consumer可以直接调用服务而不用再关心地址和端口号,且该服务还有负载功能.

其实就是引入了Eureka客户端依赖 就可以使用@LoadBalanced注解 是Ribbon的功能

actuator微服务信息完成功能

一般来说 web和actuator最好一起导入

原先的

在支付和订单模块

看下修改后的效果

那么原先的显示怎么回事

看下host

localhost:8081/actuator/health

让Eureka界面上有IP显示

服务发现Discovery

就是说Eureka上面很多服务,那么这些服务对应的信息比如 IP什么什么的

可以通过服务发现Discovery来获取该服务的信息

我单在8081里使用

发现不写这个注解也可以 上面没写

Eureka的自我保护

下面这排红字

概述:保护模式主要用于一组客户端和Eureka Server之间存在网络分区场景下的保护,一旦进入保护模式,Eureka Server将会尝试保护其服务注册表中的信息,不再删除服务注册表中的数据,也就是不会注销任何微服务

上面红字就是说Eureka进入了保护模式

在保护模式下,某时刻一个微服务即使不可用,Eureka也不会立即清理,依旧会对该微服务的信息进行保存,属于CAP理论的AP分支

为什么会产生Eureka自我保护机制

为了防止EurekaClient可以正常运行,但是与EurekaServer网络不通情况下,防止错误剔除

什么是自我保护模式:

默认情况下,如果EurekaServer在一定时间内没有接收到某个微服务实例的心跳,EurekaServer将会注销实例(默认90秒).但是当网络分区故障发生(延时,卡顿,拥挤)时,微服务与EurekaServer之间无法正常通信,以上行为可能变得非常危险---因为微服务本身其实是健康的,此时不应该注销这个服务.Eureka通过自我保护模式来解决这个问题。当EurekaServer节点在短时间内丢失过多客户端时(可能发生了网络分区故障),那么这个节点就会进入自我保护模式.

禁止自我保护,宁可杀错,不可放过,配置绝情版Eureka(我乱说的)

Eureka停更说明(嘿嘿)

github.com/Netflix/eureka/wiki

相关推荐
qcx231 小时前
【系统学AI】09 Multi-Agent架构(2026版):从学术理论到工业级实践
java·人工智能·架构·multi-agent·claude agent
wb043072012 小时前
厨房质检员——从阿明的“祖传配方“到标准化质检,看测试金字塔的落地
架构·log4j
Dongwoo Jeong2 小时前
微服务架构(MSA)是如何诞生的?
微服务·云原生·架构
半旧夜夏2 小时前
【保姆级】微服务组件环境搭建(Docker Compose版)
java·linux·spring cloud·微服务·云原生·容器
张忠琳3 小时前
【kubernetes v1.21】(kubelet 1)Kubelet 核心架构与启动流程
云原生·架构·kubernetes·kubelet
用户987409238873 小时前
超算中心 高性能计算 htc命令module use的作用
架构
AI科技星4 小时前
基于**v=c(空间光速螺旋运动)唯一第一性原理**重新完整求导证明
人工智能·线性代数·算法·机器学习·架构·概率论·学习方法
__log4 小时前
如何优雅地“借鉴”任何网站的设计系统
人工智能·架构·知识图谱
她的男孩5 小时前
从自然语言到数据大屏:Forge Report Studio 的 AI 生成链路
人工智能·后端·架构
她的男孩5 小时前
大屏动态数据接入:从静态 Mock 到真实业务 API
后端·架构