SpringCloud微服务实战学习笔记(1)

220 阅读8分钟

SpringCloud 学习笔记

根据SpringCloud微服务实战学习

SpringEureka

服务提供者

  • 服务注册

在启动的时候会通过发送REST请求的方式将自己注册到EurekaServer上, 同时带上了自身服务的一些元数据信息。

Eureka Server接收到这个REST请求之后,将元数据信息存储在一个双层结构Map中, 其中第一层的key是服务名, 第二层的key是 具体服务的实例名。

在服务注册时, 需要确认一下 eureka.client.register-with-eureka=true 参数是否正确, 该值默认为true。若设置为false将不会启动注册操作。

  • 服务同步

由于服务注册中心之间互相注册为服务, 当服务提供者发送注册请求到一个服务注册中心时, 它会将该请求转发给集群中相连的其他注册中心, 从而实现注册中心之间的服务同步 。

通过服务同步,两个服务提供者的服务信息就可以通过这两台服务注册中心中的任意一台获取到。

  • 服务续约

在注册完服务之后,服务提供者会维护一个心跳用来持续告诉EurekaSever: "我还活着 ”, 以防止Eureka Server的 “剔除任务 ” 将该服务实例从服务列表中排除出去。

服务消费者

  • 获取服务

启动服务消费者的时候,它会发送一个REST请求给服务注册中心,来获取上面注册的服务清单 。

为了性能考虑, EurekaServer会维护一份只读的服务清单来返回给客户端,同时该缓存清单会每隔30秒更新一次。 获取服务是服务消费者的基础,所以必须确保eureka.c巨ent.feth-registry=true参数没有被修改成false,该值默认为七rue。

若希望修改缓存清单的更新时间,可以通过eureka.client.registry-fetch-interval-seconds=30参数进行修改, 该参数默认值为30, 单位为秒。

  • 服务调用

服务消费者在 获取服务清单后,通过服务名可以获得具体提供服务的实例名和该实例的元数据信息。

因为有这些服务实例的详细信息,所以客户端可以根据自己的需要决定具体调用哪个实例,在Ribbon中会默认采用轮询的方式进行调用,从而实现客户端的负载均衡。

对于访问实例的选择,Eureka中有Region和Zone的概念,一个Region中可以包含多个Zone,每个服务客户端需要被注册到一个Zone中, 所以每个客户端对应一个Region和一个Zone。在进行服务调用的时候,优先访问同处一个Zone中的服务提供方,若访问不到,就访问其他的Zone。

  • 服务下线

在客户端程序中,当服务实例进行正常的关闭操作时,它会触发一个服务下线的REST请求给Eurka Server,告诉服务注册中心:“我要下线了”。服务端在接收到请求之后,将该服务状态置为下线(DOWN),并把该下线事件传播出去。

服务注册中心

  • 失效剔除

Eureka Server在启动的时候会创建一个定时任务, 默认每隔一段时间(默认为60秒) 将当前清单中超时(默认为90秒)没有续约的服务剔 除出去。

  • 自我保护

服务注册到EurekaServer之后,会维护一个心跳连接,告诉EurekaServer自己还活着。EurekaServer在运行期间,会统计心跳失败的比例在15分钟之内是否低于85%,如果出现低于的情况(在单机调试的时候很容易满足,实际在生产环境上通常是由于网络不稳定导致), EurekaServer会将当前的实例注册信息保护起来,让这些实例不会过期, 尽可能保护这些注册信息。

但是, 在这段保护期间内实例若出现问题,那么客户端很容易拿到实际已经不存在的服务实例,会出现调用失败的清况,所以客户端必须要有容错机制,比如可以使用请求重试、断路器等机制。由于本地调试很容易触发注册中心的保护机制,这会使得注册中心维护的服务实例不那么准确。 所以, 我们在本地进行开发的时候, 可以使用enable-self-preservation=false参数来关闭保护机制, 以确保注册中心可以将不可用的实例正确剔除。

1、创建一个聚合项目
springCloud
--api-server(服务提供者)
--eureka-server(注册中心)
--ribbon-consumer(服务消费者)

最外层pom(springCloud的pom)

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.7.RELEASE</version>
        <relativePath/>
    </parent>

    <groupId>com.study</groupId>
    <artifactId>springcloud</artifactId>
    <packaging>pom</packaging>
    <version>1.0.0</version>
    <modules>
        <module>eureka-server</module>
        <module>api-server</module>
        <module>ribbon-consumer</module>
    </modules>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <type>pom</type>
                <version>Brixton.SR5</version>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
2、创建Eureka注册中心

注册中心pom(eureka-server的pom) 依赖了父项目的配置

    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>com.study</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

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

配置两个yml文件或者也可以用spring.profiles 来区分配置文件

配置一个application-peer1.yml 和 application-peer2.yml 到时候根据配置文件不同来启动两个不同的注册中心模拟负载均衡

application-peer1.yml

server:
  port: 1111
eureka:
  instance:
    hostname: peer1
  client:
    ##是否向注册中心注册自己
    register-with-eureka: false
    ##是否维护服务实例
    fetch-registry: false
    serviceUrl:
      defaultZone: http://peer2:1112/eureka/
  server:
    ##本地调试关闭保护机制确保注册中心可以将不可用实例剔除
    enable-self-preservation: false

application-peer2.yml

server:
  port: 1112
eureka:
  instance:
    hostname: peer2
  client:
    ##是否向注册中心注册自己
    register-with-eureka: false
    ##是否维护服务实例
    fetch-registry: false
    serviceUrl:
      defaultZone: http://peer1:1111/eureka/

启动类添加 @EnableEurekaServer 启动服务作为注册中心

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

然后系统的host文件添加peer1 dns指向本地,不改host文件的话注册地址peer1改成localhost也行 启动的时候 添加 --spring.profiles.active=peer1 --spring.profiles.active=peer2这样就启动了两个互相注册同步信息的注册中心了访问http://peer1:1111可以看到eureka的控制台

我是用idea修改配置文件启动多个服务的

3.创建服务提供者

pom(eureka-server的pom) 依赖了父项目的配置

spring:
  application:
    #给服务命名
    name: hello-service
eureka:
  instance:
    #服务续约任务调用间隔默认三十秒
    lease-renewal-interval-in-seconds: 30
    #服务失效时间默认90秒
    lease-expiration-duration-in-seconds: 90
  client:
    serviceUrl:
       ##使用默认区指定注册中心地址
       defaultZone: http://peer1:1111/eureka/,http://peer2:1112/eureka/

添加一个controller

@RestController
public class HelloController {
    private final Logger logger = Logger.getLogger(getClass().getName());
    /**获取服务注册信息*/
    @Autowired
    private DiscoveryClient discoveryClient;

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String index() {
        ServiceInstance serviceInstance = discoveryClient.getLocalServiceInstance();
        logger.info(String.format("/hello,host:%s,service_id:%s", serviceInstance.getHost()
                , serviceInstance.getServiceId()));
        return "hello world";
    }
}

启动类添加@EnableDiscoveryClient将服务按配置信息注册到注册中心

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

启动可以添加--server.port=xxxx修改多个端口启动多个服务

也可以修改idea的配置

4.创建服务消费者

pom文件配置

    <parent>
        <artifactId>springcloud</artifactId>
        <groupId>com.study</groupId>
        <version>1.0.0</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

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

yml文件配置

spring:
  application:
    name: ribbon-consumer
server:
  port: 9000
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:1111/eureka/
    #是否维护服务实例默认为true,设置成false就不会向注册中心获取服务清单了
    fetch-registry: true
    #更新缓存服务清单时间默认30秒
    registry-fetch-interval-seconds: 30

添加controller

@RestController
public class ConsumerController {
    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping(value = "/ribbon-consumer", method = RequestMethod.GET)
    public String helloConsumer() {
        //根据消费者在用户中心注册的名字轮询请求
        return restTemplate.getForEntity("http://HELLO-SERVICE/hello", String.class)
                .getBody();
    }
}

启动类添加 @EnableDiscoveryClient注册为eureka客户端应用,通过@LoadBalanced开启客户端负载均衡

@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {
    public static void main(String args[]) {
        SpringApplication.run(ConsumerApplication.class, args);
    }
    /**
     * LoadBalanced 开启客户端负载均衡
     * */
    @Bean
    @LoadBalanced
    RestTemplate restTemplate(){
        return new RestTemplate();
    }
}

启动后访问http://localhost:9000/ribbon-consumer多访问几次查看服务提供者的日志多个服务之间会交替打印日志