服务的注册与发现Eureka(二)

1、服务治理概念

在传统rpc远程调用中,服务与服务依赖关系,管理比较复杂,所以需要使用服务治理,管理服务与服务之间依赖关系,可以实现服务调用、负载均衡、容错等,实现服务发现与注册。

2、服务的注册与发现概念

 在服务注册与发现中,有一个注册中心,当服务器启动的时候,会把当前自己服务器的信息 比如 服务地址通讯地址等以别名方式注册到注册中心上。

 另一方(消费者|服务提供者),以该别名的方式去注册中心上获取到实际的服务通讯地址,让后在实现本地rpc调用远程。

服务注册与发下原理图:

3、什么Eureka

Netflix在设计Euraka时遵守的就是AP原则

 

4、Eureka的基本架构

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

Eureka Server提供服务

各节点启动服务后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中

将会存储到所有可用服务节点的信息,服务节点信息可以在界面中直观的看到

Eureka Client是一个java客户端,用于简化Eureka Server的交互,客户端同时也具备一个内置的,使用轮询(round-robin)负载算法的负载均衡器.在应用启动后,将会向Eureka Server发送心跳(默认周期为30s).

如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90s)

 5、Eureka 三大角色

Eureka Server提供服务注册和发现

Service Provider服务提供方将自身服务注册到Eureka,从而是服务消费方能够找到

Service Consumer服务消费方从Eureka获取注册服务列表,从而能够消费服务

 6、服务提供者与消费关系

服务提供者:提供服务被人调用

消费者:调用被人服务

   1、服务消费者模式

       获取服务

       消费者启动的时候,使用服务别名,会发送一个rest请求到服务注册中心获取对应的服务信息,让后会缓存到本地jvm客户端中,同时客户端每隔30秒从服务器上更新一次。

可以通过 fetch-inte vall-seconds=30参数进行修以通过eureka.client .registry该参数默认值为30, 单位为秒。

      服务下线

      在系统运行过程中必然会面临关闭或重启服务的某个实例的情况,在服务关闭期有我们自然不希望客户端会继续调用关闭了的实例。所以在客户端程序中,当服务实例过正常的关闭操作时,它会触发一个服务下线的REST请求给Eureka Server, 告诉服务日中心:“我要下线了”。服务端在接收到请求之后,将该服务状态置为下线(DOWN),井该下线事件传播出去。

2、服务注册模式

失效剔除

      有些时候,我们的服务实例并不一定会正常下线,可能由于内存溢出、网络故障气因使得服务不能正常工作,而服务注册中心并未收到“服务下线”的请求。为了从服务表中将这些无法提供服务的实例剔除,Eureka Server 在启动的时候会创建一个定时任多默认每隔一一段时间(默认为60秒)将当前清单中超时(默认为90秒)没有续约的服务除出去

 自我保护

      当我们在本地调试基于Eureka的程序时,基本上都会碰到这样-一个问题, 在服务主中心的信息面板中出现类似下面的红色警告信息( )

      EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY 'RERENENALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIREDTO BE SAFE.

实际上,该警告就是触发了Eureka Server的自我保护机制。之前我们介绍过,服务注册到Eureka Server之后,会维护个心跳连接, 告诉Eureka Server自己还活 着。Eureka Server在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%如果出现低于的情况单机调试的时候很容易满足,实际在生产环境上通常是由于网络不稳定导致),EuServer会将当前的实例注册信息保护起来,让这些实例不会过期,尽可能保护这些注册信-息。但是,在这段保护期间内实例若出现问题,那么客户端很容易拿到实际已经不存服务实例,会出现调用失败的情况,所以客户端必须要有容错机制,比如可以使用请使用重试、断路器等机制。

由于本地调试很容易触发注册中心的保护机制,这会使得注册中心维护的服务实仍那么准确。所以,我们在本地进行开发的时候,可以使用eureka . server . enablself preservation=false参数来关闭保护机制,以确保注册中心可以将不可用的例正确剔除。

 后面搭建注册中心的时候加入这个配置就可以关闭自我保护

eureka:
  server:
     # 测试时关闭自我保护机制,保证不可用服务及时踢出
     enable-self-preservation: false
     eviction-interval-timer-in-ms: 2000

7、盘点下目前的工作情况

总父工程

通用模块api

服务提供者Provider

服务消费者Consumer

 8、微服务构建案例工程模块

   构建步骤

      1、microservicecloud整体父工程Project

       新建父工程microservicecloud,切记为Packaging是pom模式,主要是定义pom文件,将后续各个子模块公用的jar包等统一提出来,类似一个抽象的父类

    pom文件:

 <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>
        <springcloud-version>Finchley.SR1</springcloud-version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${springcloud-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.0.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.0.4</version>
            </dependency>

            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.0.31</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.0</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>1.2.3</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

2、microservicecloud-api公共子模块Module

新建microservicecloud-api

 

创建完成后请回到父工程查看pom文件变化如下图所示:

pom文件

<dependencies><!-- 当前Module需要用到的jar包,按自己需求添加,如果父类已经包含了,可以不用写版本号 -->
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>
</dependencies>

新建部门Entity且配合lombok使用

@AllArgsConstructor//全参数构造
@NoArgsConstructor//无参数构造器
@Data//get set 方法
@Accessors(chain = true)//链式风格
public class Dept implements Serializable {
    private Long   deptno; // 主键
    private String     dname; // 部门名称
    private String     db_source;// 来自那个数据库,因为微服务架构可以一个服务对应一个数据库,同一个信息被存储到不同数据库

}

mvn clean install 后给其他模块引用,达到通用的目的,也即需要用到部门实体的话,不用每个都定义一份直接引用本模块即可

 3、microservicecloud-provider-dept-8001部门微服务提供者Module

新建一个microservicecloud-provider-dept-8001,创建完成后请回到父工程查看pom文件变化如下图所示:

 

pom文件

<dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Dept部门Entity -->
        <dependency>
            <groupId>com.yehui</groupId>
            <artifactId>microservicecloud-api</artifactId>
            <version>${project.version}</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

application.yml文件

server:
 port: 8001
mybatis:
 config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路径
 type-aliases-package: com.yehui.entity    # 所有Entity别名类所在包
 mapper-locations: classpath:mybatis/mapper/**/*.xml                       # mapper映射文件
spring:
 application:
  name: microservicecloud-dept //服务注册名称
 datasource:
 type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
 driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包
 url: jdbc:mysql://localhost:3306/clouddb01             # 数据库名称
 username: root
 password: root
 dbcp2:
  min-idle: 5                                           # 数据库连接池的最小维持连接数
  initial-size: 5                                       # 初始化连接数
  max-total: 5                                          # 最大连接数
  max-wait-millis: 200       # 等待连接获取的最大超时时间

工程src/main/resources目录下新建mybatis文件夹后新建mybatis.cfg.xml文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <setting name="cacheEnabled" value="true"/><!-- 二级缓存开启 -->
    </settings>
</configuration>

mysql创建部门sql脚本

DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept`  (
  `deptno` BIGINT(20) NOT NULL DEFAULT 0,
  `dname` VARCHAR(60) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `db_source` VARCHAR(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL
) ENGINE = INNODB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = COMPACT;
INSERT INTO `dept` VALUES (1, '开发部', 'clouddb01');
INSERT INTO `dept` VALUES (2, '人事部', 'clouddb01');
INSERT INTO `dept` VALUES (3, '财务部', 'clouddb01');
INSERT INTO `dept` VALUES (4, '市场部', 'clouddb01');
INSERT INTO `dept` VALUES (5, '运维部', 'clouddb01');

DeptMapper部门接口

@Mapper
public interface DeptMapper {
    public boolean addDept(Dept dept);
    public Dept findById(Long id);
    public List<Dept> findAll();
}

工程src/main/resources/mybatis目录下新建mapper文件夹后在建立DeptMapper.xml

<?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.yehui.mapper.DeptMapper">

    <select id="findById" resultType="Dept" parameterType="Long">
      select deptno,dname,db_source from dept where deptno=#{deptno};
   </select>
    <select id="findAll" resultType="Dept">
      select deptno,dname,db_source from dept;
   </select>
    <insert id="addDept" parameterType="Dept">
      INSERT INTO dept(dname,db_source) VALUES(#{dname},DATABASE());
   </insert>
</mapper>

DeptService部门服务接口

public interface DeptService {

    public boolean addDept(Dept dept);

    public Dept findById(Long id);

    public List<Dept> findAll();
}

DeptServiceImpl部门服务接口实现类

@Service
public class DeptServiceImpl implements DeptService {
    @Autowired
    private DeptMapper deptMapper;
    @Override
    public boolean addDept(Dept dept) {
        return deptMapper.addDept(dept);
    }
    @Override
    public Dept findById(Long id) {
        return deptMapper.findById(id);
    }

    @Override
    public List<Dept> findAll() {
        return deptMapper.findAll();
    }
}

DeptController部门微服务提供者REST

@RestController
@RequestMapping("/dept")
public class DeptController {
    @Autowired
    private DeptService deptService;

    @RequestMapping(value = "/addDept")
    public boolean addDept(Dept dept) {
        return deptService.addDept(dept);
    }

    @RequestMapping("/findById/{id}")
    public Dept findById(@PathVariable("id") Long id) {
        return deptService.findById(id);
    }

    @RequestMapping("/findAll")
    public List<Dept> findAll() {
        return deptService.findAll();
    }
}

主启动类

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

测试

访问地址:http://localhost:8001/dept/findAll

效果如下:

4、microservicecloud-consumer-dept-80部门微服务消费者Module

新建一个microservicecloud-provider-dept-80,创建完成后请回到父工程查看pom文件变化如下图所示:

pom文件

<dependencies>
        <!-- 引入自己定义的api通用包,可以使用Dept部门Entity -->
        <dependency>
            <groupId>com.yehui</groupId>
            <artifactId>microservicecloud-api</artifactId>
            <version>${project.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

    </dependencies>

 yml文件

server:
  port: 80

com.yehui.config包下ConfigBean编写(类似spring里面的applicationContext.xml写入的注入Bean)

@Configuration
public class ConfigBean {
    @Bean
      public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

com.yehui.controller包下新建DeptController部门微服务消费者REST

@RestController
public class DeptController {

    private static String REST_URL_PREFIX = "http://localhost:8001";
    /**
     RestTemplate 提供了多种便捷访问远程Http服务的方法,是一种简单便捷的访问restful服务模板类,是spring提供的用于访问Rest服务的客户端模板工具集
     * 使用 使用restTemplate访问restful接口非常的简单粗暴无脑。 (url, requestMap,
     * ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。
     */
    @Autowired
    private RestTemplate restTemplate;
    @RequestMapping(value = "/consumer/dept/add")
    public boolean add(Dept dept)
    {
        return restTemplate.postForObject(REST_URL_PREFIX + "/dept/addDept", dept, Boolean.class);
    }

    @RequestMapping("/findAll")
    public List<Dept> findAll() {
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/findAll",List.class);
    }
}

ConSumeAppStart主启动类

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

测试访问http://localhost:80/findAll

效果:

5、注册中心环境搭建

pom文件

 <dependencies>
        <!--eureka-server服务端-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
    </dependencies>

 application.yml

server:
  port: 7001
  ###eureka 基本信息配置
eureka:
  instance:
        ###注册到eurekaip地址
    hostname: localhost #eureka服务端的实例名称
  client:
    service-url:
      defaultZone:  http://${eureka.instance.hostname}:${server.port}/eureka/   #单机  设置与Eureka Server交互的地址查询服务和注册服务都需要依赖这个地址(单机)。
        ###因为自己是为注册中心,不需要自己注册自己
    register-with-eureka: false #表示不像注册中心注册自己
    ###因为自己是为注册中心,不需要检索服务
    fetch-registry: false #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务

 主启动类

@SpringBootApplication
@EnableEurekaServer // EurekaServer服务器端启动类,接受其它微服务注册进来
public class SpringCloudService7001_APP {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudService7001_APP.class);
    }
}

测试:http://localhost:7001/

如果所示:

5、注册服务提供者

microservicecloud-provider-dept-8001将已有的部门将微服务注册到eureka服务中心

修改microservicecloud-provider-dept-8001

pom文件添加相关依赖

    <!-- 将微服务provider侧注册进eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

yml添加

eureka:
  client: #客户端注册进eureka服务列表内
    service-url:
      defaultZone: http://localhost:7001/eureka/
      ###因为该应用为注册中心,不会注册自己
      register-with-eureka: true
      ###是否需要从eureka上获取注册信息
      fetch-registry: true

主启动类添加新注解

@SpringBootApplication
@EnableEurekaClient//本服务启动后会自动注册进eureka服务中
public class ProviderAppStart8001 {
    public static void main(String[] args) {
        SpringApplication.run(ProviderAppStart8001.class);
    }
}

效果如下:访问路径http://localhost:7001/

6、主机映射名称修改

hosts 文件里面映射这样127.0.0.1  eureka7001.com

修改microservicecloud-eureka-7001工程的yml文件

server:
  port: 7001
eureka:
  client:
    fetch-registry: false
    service-url:
      defaultZone:  http://${eureka.instance.hostname}:${server.port}/eureka/
    register-with-eureka: false
  instance:
    hostname: eureka7001.com #实例的名称

修改microservicecloud-provider-dept-8001 yml文件

server:
 port: 8001
mybatis:
 config-location: classpath:mybatis/mybatis.cfg.xml        # mybatis配置文件所在路径
 type-aliases-package: com.yehui.entity    # 所有Entity别名类所在包
 mapper-locations: classpath:mybatis/mapper/**/*.xml                       # mapper映射文件
 #应用名称
spring:
 application:
  name: microservicecloud-dept
 datasource:
  type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
  driver-class-name: org.gjt.mm.mysql.Driver              # mysql驱动包
  url: jdbc:mysql://localhost:3306/clouddb01             # 数据库名称
  username: root
  password: root
  dbcp2:
   min-idle: 5                                           # 数据库连接池的最小维持连接数
   initial-size: 5                                       # 初始化连接数
   max-total: 5                                          # 最大连接数
   max-wait-millis: 200       # 等待连接获取的最大超时时间
eureka:
  client: #客户端注册进eureka服务列表内
    service-url:
      defaultZone: http://localhost:7001/eureka/
      ###是否向注册中心注册自己
    register-with-eureka: true
      ###是否需要从eureka上获取注册信息
    fetch-registry: true

修改microservicecloud-eureka-7001yml文件 修改添加

server:
  port: 7001
eureka:
  client:
    fetch-registry: false
    service-url:
      defaultZone:  http://${eureka.instance.hostname}:${server.port}/eureka/
    register-with-eureka: false
  instance:
    hostname: eureka7001.com #实例的名称

效果访问路径:http://eureka7001.com:7001/

7、完善_主机IP信息提示

在父类pom文件添加如下配置

<build>
        <!--父工程的项目名称-->
        <finalName>microservicecloud</finalName>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <filtering>true</filtering>
            </resource>
        </resources>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <configuration>
                    <!--以$开头结尾 符合在src/main/resources路径下面访问到 主要是yml文件或者properties文件-->
                    <delimiters>
                        <delimit>$</delimit>
                    </delimiters>
                </configuration>
            </plugin>
        </plugins>
    </build>

microservicecloud-provider-dept-8001 pom文件添加依赖

<!-- actuator监控信息完善 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

在microservicecloud-provider-dept-8001 yml文件添加如下:

8、使用rest方式调用服务

修改microservicecloud-consumer-dept-80

pom文件添加依赖

  <!-- 将微服务provider侧注册进eureka -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

yml文件添加配置

###服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone:  http://localhost:7001/eureka/  #向服务中心注册自己
      ###是否向服务中心注册自己
    register-with-eureka: true
      ###是否需要从eureka上获取注册信息
    fetch-registry: true
#服务的名称
spring:
  application:
    name: ConsomeApp

config配置类添加注解

@Configuration
public class ConfigBean {
    @Bean
    @LoadBalanced //注解表明这个restRemplate开启负载均衡的功能。
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

controller类修改

@RestController
public class DeptController {

    private static String REST_URL_PREFIX="http://MICROSERVICECLOUD-DEPT";//引用的名称
    /**
     RestTemplate 提供了多种便捷访问远程Http服务的方法,是一种简单便捷的访问restful服务模板类,是spring提供的用于访问Rest服务的客户端模板工具集
     * 使用 使用restTemplate访问restful接口非常的简单粗暴无脑。 (url, requestMap,
     * ResponseBean.class)这三个参数分别代表 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。
     */
    @Autowired
    private RestTemplate restTemplate;
    @RequestMapping(value = "/consumer/dept/add")
    public boolean add(Dept dept)
    {
        return restTemplate.postForObject(REST_URL_PREFIX + "/dept/addDept", dept, Boolean.class);
    }

    @RequestMapping("/findAll")
    public List<Dept> findAll() {
        return restTemplate.getForObject(REST_URL_PREFIX + "/dept/findAll",List.class);
    }
}

启动类新增注解

@SpringBootApplication
@EnableEurekaClient //表明自己是一个eurekaclient.
public class ConSumeAppStart {
    public static void main(String[] args) {
        SpringApplication.run(ConSumeAppStart.class);
    }
}

 测试访问;http://localhost/findAll

原文地址:https://www.cnblogs.com/cxyyh/p/10634319.html