springCloud 之 Eureka服务治理机制及代码运行

  

服务提供者

服务注册:

服务提供者在启动的时候通过发送Rest请求的方式将自己注册到Eureka Server上,同时带上了自身服务的一些元数据信息。Eureka Server在收到这个请求后,将元数据信息存储在一个双层结构Map中,第一层的key是服务名,第二层的key是具体服务的实例名。

服务同步:

两个服务提供者分别注册到两个不同的服务注册中心上,因为服务中心之间是相互注册为服务的,所以当服务提供者发送注册请求到一个服务注册中心时,它会将该请求转发给集群中的其他注册中心,从而实现服务注册中心之间的服务同步,通过服务同步,两个服务提供者的服务信息就可以通过这两台服务注册中心的任意一台获取到。

服务续约:

服务提供者在注册完后,会定期向注册中心发送一个“心跳"来告诉Eureka Server自己还存活着,以防被Eureka Servertichu踢出服务列表。

eureka.instance.lease-renewal-interval-in-seconds= 30 这个参数是定义服务续约的调用间隔时间,默认为30秒。

eureka.instance.lease-expiration-duration-in-seconds= 90 这个参数是定义服务失效时间,默认为90秒。

服务消费者

获取服务:

将自身注册为服务消费客户端。当我们启动服务消费者的时候,他会发送一个REST请求给服务注册中心,来获取上面注册的服务清单。为了性能考虑,Eureka Server会维护一份只读的服务清单来返回给客户端,同时该缓存清单会每隔30s更新一次,

获取服务时服务消费者的基础,必须确保eureka.client.fetch-registry=true参数没有被修改为false,该值默认为true。若希望修改缓存清单的更新时间,可以通过eureka.client.registry-fetch-interval-seconds=30参数进行修改。

获取服务:

发送REST请求给服务注册中心,服务注册中心会返回给服务消费者一个只读的服务清单。该缓存清单默认是30秒更新一次。

eureka.client.registry-fetch-interval-seconds= 30 这个参数用来修改缓存清单更新的时间间隔,时间单位为秒。

服务调用:

服务消费者在获取服务清单后,通过服务名可以获得具体提供服务的实例名和该实例的元数据信息,服务消费者可以根据需要调用哪个实例。在Ribbon中默认采用轮询的方式进行调用,从而实现客户端的负载均衡。

服务注册中心

失效剔除:

当某个服务提供者出现网络故障、内存溢出等各种原因而不能正常工作,服务中心并未受到”服务下线“的请求。为了能及时将这些无法提供服务的实例剔除,Eureka Server在启动的时候会创建一个定时任务,默认是60秒一次,将没有续约也就是没有发送”心跳“的服务剔除出去。

自我保护:

我们在本地调试Eureka程序的时候,基本上都会碰到一个红色的警告信息:

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY‘RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

这是Eureka Server启动了自我保护机制,自我保护机制的工作机制是如果在15分钟内超过85%的客户端节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,Eureka Server自动进入自我保护机制,在开发环境因为不会有网络故障等原因,所以很容易出现这个警告。启动自我保护后此时会出现以下几种情况:

1、Eureka Server不再从注册列表中移除因为长时间没收到心跳而应该过期的服务。

2、Eureka Server仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上,保证当前节点依然可用。

3、当网络稳定时,当前Eureka Server新的注册信息会被同步到其它节点中。

因此Eureka Server可以很好的应对因网络故障导致部分节点失联的情况,而不会像Zookeeper那样如果有一半不可用的情况会导致整个集群不可用而变成瘫痪。

eureka.server.enable-self-preservation= false 可以通过这个配置设置为false来关闭自我保护机制,默认识开启的,且建议在生产环境开启自我保护

一、高可用注册中心代码

注册中心1:

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>com.zxy</groupId>
    <artifactId>eureka-service-center1</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>eureka-service</name>
    <description>Forward project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    </properties>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

配置文件

 1 #定义注册中心端口号为8888
 2 server:
 3   port: 8888
 4 spring:
 5   application:
 6     name: server-center1
 7 eureka:
 8   instance:
 9     hostname: center1
10   client:
11     service-url:
12       defaultZone: http://127.0.0.1:9999/eureka/
13 #  注册中心没必要将自己注册给自己
14     register-with-eureka: false
15 #  注册中心不需要去检索服务,调用服务,故而不需要获取注册服务清单
16     fetch-registry: false
17   server:
18     peer-node-read-timeout-ms: 12000
19     enable-self-preservation: false

启动

 1 package com.zxy.forward;
 2
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
 6 @EnableEurekaServer
 7 @SpringBootApplication
 8 public class Center1Application {
 9
10     public static void main(String[] args) {
11         SpringApplication.run(Center1Application.class, args);
12     }
13 }

注册中心2:

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>com.zxy</groupId>
    <artifactId>eureka-client-center2</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>eureka-client-center2</name>
    <description>Forward project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

配置文件

 1 server:
 2   port: 9999
 3 spring:
 4   application:
 5     name: server-center2
 6 eureka:
 7   instance:
 8     appname: center2
 9   client:
10     service-url:
11       defaultZone: http://127.0.0.1:8888/eureka/
12 #  注册中心没必要将自己注册给自己
13     register-with-eureka: false
14 #  注册中心不需要去检索服务,调用服务,故而不需要获取注册服务清单
15     fetch-registry: false
16   server:
17 #  设置读取超时时间
18     peer-node-read-timeout-ms: 12000
19 #    关闭自我保护
20     enable-self-preservation: false

启动

 1 package com.zxy.demo;
 2
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 6 import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
 7 import org.springframework.scheduling.annotation.EnableScheduling;
 8
 9 @SpringBootApplication
10 @EnableEurekaServer
11 public class Center2Application {
12
13     public static void main(String[] args) {
14         SpringApplication.run(Center2Application.class, args);
15     }
16 }

二、服务提供者代码

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>com.zxy</groupId>
    <artifactId>eureka-client-provider1</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>eureka-client</name>
    <description>Forward project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
                <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
<dependency>
    <groupId>net.logstash.logback</groupId>
    <artifactId>logstash-logback-encoder</artifactId>
    <version>4.11</version>
</dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

配置

server:
  port: 1001
spring:
  application:
    name: provider

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8888/eureka/
# 服务提供者如果也需要作为消费者则可以获取注册清单,如果单纯作为服务提供者则不需要获取服务清单
      fetch-registry: false
#  服务提供者需要提供服务,所以需要将自己注册在注册中心上
      register-with-eureka: false
# 服务提供者需要把下面的实例名关闭,否则在按照消费端的代码调用是会找不到主机名(启动单实例提供者把下面注释掉)
#  instance:
#    hostname: provider1
    

启动类

 1 package com.zxy.demo;
 2
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 6
 7 @SpringBootApplication
 8 @EnableDiscoveryClient
 9 public class ProviderApplication {
10
11     public static void main(String[] args) {
12         SpringApplication.run(ProviderApplication.class, args);
13     }
14 }

接口类

 1 package com.zxy.demo.proapi;
 2
 3 import org.slf4j.Logger;
 4 import org.slf4j.LoggerFactory;
 5 import org.springframework.web.bind.annotation.RequestMapping;
 6 import org.springframework.web.bind.annotation.RestController;
 7
 8 @RestController
 9 public class HelloWorldController {
10     private Logger logger = LoggerFactory.getLogger(this.getClass());
11
12     @RequestMapping(value="/welcome")
13     public String getWelcome() {
14         String str = "hello,welcome the world!!!";
15         logger.info(str);
16         System.out.println(str);
17         return str;
18     }
19
20 }

三、消费者代码

消费者添加一个负载均衡的模板和依赖

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>com.zxy</groupId>
    <artifactId>eureka-client-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>eureka-client-consumer</name>
    <description>Forward project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

配置

 1 server:
 2   port: 2001
 3 spring:
 4   application:
 5     name: consumer
 6 eureka:
 7 #  instance:
 8 #    hostname: consumer
 9   client:
10     service-url:
11       defaultZone: http://127.0.0.1:8888/eureka
12 #      如果需要提供接口共别人调用也可以将其注册在注册中心
13 #    register-with-eureka: false
14 #获取服务是服务消费者的基础,故而下面的设置必须为true,默认是true
15 #    fetch-registry: false

启动

 1 package com.zxy.demo;
 2
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 6 import org.springframework.cloud.client.loadbalancer.LoadBalanced;
 7 import org.springframework.context.annotation.Bean;
 8 import org.springframework.web.client.RestTemplate;
 9
10 @SpringBootApplication
11 @EnableDiscoveryClient
12 public class ConsumerApplication {
13
14     @Bean
15     @LoadBalanced
16     RestTemplate restTemplate() {
17         return new RestTemplate();
18     }
19     public static void main(String[] args) {
20         SpringApplication.run(ConsumerApplication.class, args);
21     }
22
23 }

接口的类

 1 package com.zxy.demo.consumer;
 2
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.web.bind.annotation.RequestMapping;
 5 import org.springframework.web.bind.annotation.RequestMethod;
 6 import org.springframework.web.bind.annotation.RestController;
 7 import org.springframework.web.client.RestTemplate;
 8
 9 @RestController
10 public class ConsumerController {
11     @Autowired
12     private RestTemplate template;
13     @RequestMapping(value="/msg0",method=RequestMethod.GET)
14     public String getStr() {
15         System.out.println("I am consumer msg0!");
16         return template.getForEntity("http://provider/welcome", String.class).getBody();
17     }
18
19     @RequestMapping(value="/msg1",method=RequestMethod.GET)
20     public String msg() {
21         RestTemplate t = new RestTemplate();
22         System.out.println("I am consumer msg1!");
23         return t.getForEntity("http://127.0.0.1:1001/welcome", String.class).getBody();
24     }
25 }

结果

原文地址:https://www.cnblogs.com/xiaoyao-001/p/9736734.html

时间: 2024-10-07 15:53:04

springCloud 之 Eureka服务治理机制及代码运行的相关文章

微服务:整合 Spring cloud Eureka - 服务治理机制

一.简介 在体验了Spring Cloud Eureka 通过简单的注解配置就能实现强大的服务治理功能之后,我们可以进一步了解一些Eureka基础架构中各个元素之间的通信行为,以此来更加深入的理解Eureka服务治理体系是如何运转起来的. 二.微服务基础架构拓扑图 1.“Eureka Server 服务注册中心-1” 和 “Eureka Server 服务注册中心-2” ,他们相互注册成为高可用集群. 2.服务提供者启动两个实例,一个注册到“Eureka Server 服务注册中心-1” 上,另

SpringCloud——服务治理机制笔记

SpringCloud--服务治理机制笔记 服务治理机制 服务提供者 服务注册服务提供者 在启动的时候会通过发送REST请求的方式将自己注册到Eureka Server上,同时带上了自身服务的一些元数据信息. eureka.client.register-with-eureka=true:启动注册操作 服务同步 服务续约 eureka.instance.lease-renewal-interval-in-seconds=30:用于定义服务续约任务的调用间隔时间,默认30秒eureka.insta

Eureka服务治理

Eureka服务治理 什么是服务治理? SpringCloud封装了Netflit公司开发的Eureka模块来实现服务治理: 在传统的rpc远程调用框架中,管理每个服务与服务之间的依赖关系比较复杂,所以需要使用服务治理,管理服务与服务之间的依赖关系,可以实现服务调用.负载均衡.容错.实现服务的发现与注册. 什么是服务的注册与发现? Eureka采用了CS的设计架构,Eureka Server 作为服务注册的服务器,他是服务的注册中心.而系统中的其他微服务,使用Eureka的客户端连接到Eurek

1 Spring Cloud Eureka服务治理

注:此随笔为读书笔记.<Spring Cloud微服务实战> 什么是微服务? 微服务是将一个原本独立的系统拆分成若干个小型服务(一般按照功能模块拆分),这些小型服务都在各自独立的进程中运行,服务之间通过基于HTTP的RESTful API进行通信协作.每个微服务维护自身的数据存储.业务开发.自动化测试案例以及独立部署机制.维护自身的数据存储称为数据管理的去中心化.由于数据管理的去中心化,各个微服务的数据一致性成为一个难题,因此,需要强调的是各个服务之间进行无"事务"的调用.

spring-cloud配置eureka服务端

spring-cloud配置eureka服务端 eureka用来发现其他程序 依赖 <?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=&

微服务之SpringCloud实战(二):SpringCloud Eureka服务治理

服务治理 SpringCloud Eureka是SpringCloud Netflix微服务套件的一部分,它基于Netflix Eureka做了二次封装,主要完成微服务的服务治理功能,SpringCloud通过为Eureka增加了SpringBoot自动化配置,只需要简单的依赖和配置就可完成Eureka整合搭建.   服务治理可以说是微服务中做核心的模块,主要负责服务的自动化注册与发现,在最初开始构建微服务的时候,可能服务并不会很多,我们可以通过一些静态配置进行相互调用,但是随着业务的更新迭代,

springCloud eureka服务治理集群增加安全认证

做为SpringCloud Netflix服务套件中的一部分,springCloud eureka基于Netflix Eureka做了二次封装,默认提供WEB管理页面及服务治理. 为了确保在生产环境中的,eureka注册服务的元数据及WEB管理的信息安全,可以结合spring security增加安全认证. 步骤如下: 第一步,在eureka server端,开启安全认证配置,设置访问用户名和密码. 首先,增加spring security依赖包, <dependency> <group

SpringCloud(3)---Eureka服务注册与发现

Eureka服务注册与发现 一.Eureka概述 1.Eureka特点 (1) Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移. (2) Eureka 主管服务注册与发现,在微服务中,以后了这两者,只需要使用服务的标识符(==就是那个在每个服务的yml文件中取得服务名称==), 就可以访问到服务,不需要修改服务调用的配置文件. (3) Eureka遵循AP原则(高可用,分区容错性),因为使用了自我保护机制所以保证了高可用. 2.Eureka两大组件 两大组

SpringCloud(四)Eureka服务注册与发现

1 Eureka Server 提供服务注册和发现 2 Service Provider 服务提供方 将自身服务注册到Eureka,从而使服务消费方能够找到 3 Service Consumer 服务消费方 从Eureka获取注册服务列表,从而能够消费服务 介绍 我们的服务发现一般分为两种模式一种为客户端发现模式(我们主要讲这个),一种为服务端发现模式 服务实例的网络位置都是动态分配的,而且因为扩展,失效和升级等需求,服务实例会常常发生动态改变,因此客户端一种更加复杂的服务发现机制 当使用客户端