Spring Cloud 之 Eureka.

1、微服务概述

1. 什么是微服务

 简单地说, 微服务是系统架构上的一种设计风格, 它的主旨是将一个本来独立的系统拆分红多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间基于 RPC 进行通讯协做。 被拆分红的每个小型服务都围绕着系统中的某一项或一些耦合度较高的业务功能进行构建, 而且每一个服务都维护着自身的数据存储(划重点,每一个微服务都有本身的数据库实例)、 业务开发、自动化测试案例以及独立部署机制。java

2. 微服务的特性

  • 服务组件化:一个独立的系统拆成多个小型服务。
  • 以业务划分服务:微服务应该以业务来划分,而不是按能力或其余因素来划分(好比以前作的一个项目直接将缓存能力建成了一个微服务组件)。
  • 智能端点和哑管道:服务之间经过 RPC 的方式调用,一般会使用如下两种服务调用方式:
    第一种:使用 HTTP 的 RESTfl API 或轻量级的消息发送协议, 实现信息传递与服务调用的触发。
    第二种:经过在轻量级消息总线上传递消息, 相似 RabbitMQ 等 一些提供可靠异步交换的中间件。
  • 去中心化处理:不一样的微服务组件能够选择不一样的技术方案,甚至能够选择不一样的语言。只有实现了对技术平台的透明, 才能更好地发挥不一样语言对不一样业务处理能力的优点, 从而打造更为强大的大型系统。
  • 去中心化管理数据:采用分布式数据库,不一样的微服务组件有着本身单独的数据库实例。虽然数据管理的去中心化可让数据管理更加细致化,经过采用更合适的技术可以让数据存储和性能达到最优。可是,因为数据存储于不一样的数据库实例中后,数据一致性也成为微服务架构中亟待解决的问题之一。
  • 基础设施自动化:自动化测试(每次部署前的强心剂, 尽量地得到对正在运行的软件的信心)、自动化部署(解放烦琐枯燥的重复操做以及对多环境的配置管理)等。
  • 容错设计:在微服务架构中,快速检测出故障源并尽量自动恢复服务是必须被设计和考虑的。
  • 演进式设计:没有必要一开始就把服务拆分的又细又多,能够随着业务系统的发展,把压力大的服务或者稳定不变化的模块作拆分合并动做。

2. 微服务的缺陷

  1. 运维的成本提升。这个是不可避免的,原来只须要运维一个单一独立的系统,如今要管理几个或者几十个微服务。
  2. 接口的一致性问题。A 微服务修改了接口,须要调用方B、C 服务同时作出修改。除非开发过程当中严格遵照开闭原则(在这个敏捷流式开发的背景下,几乎很难作到)。
  3. 分布式的复杂性。网络延迟、分布式事务、异步消息等。

tips:分布式事务自己的实现难度就很是大,因此在微服务架构中,咱们更强调在各服务之间进行 “ 无事务 ” 的调用,而对于数据一致性,只要求数据在最后的处理状态是一致的便可;若在过程当中发现错误,经过补偿机制来进行处理,使得错误数据可以达到最终的一致性。git

2、Spring Cloud 简介

 Spring Cloud 是一个基于Spring Boot实现的微服务架构开发工具。它为微服务架构中涉及的配置管理、服务治理、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、分布式会话和集群状态管理等操做提供了一种简单的开发方式。github

 Spring Cloud 的出现,能够说是对微服务架构的巨大支持和强有力的技术后盾。它是一个解决微服务架构实施的综合性解决框架,它整合了诸多被普遍实践和证实过的框架做为实施的基础部件,又在该体系基础上建立了一些很是优秀的边缘组件。举个 Dubbo 和 Spring Cloud 差别性的例子:在使用 Dubbo 开发过程当中,分布式配置中心(百度的 Disconf、Netflix的Archaius、360的QConf、淘宝的 Diamond 等)、连接跟踪(京东的 Hydra、Twitter的 Zipkin 等)...一系列须要的组件,我都要去找第三方进行集成,还要考虑版本兼容的问题。而 Spring Cloud 就是一个微服务解决方案的“全家桶”,几乎我须要的所有微服务组件,我都能在其中找到“原装组件”:分布式配置中心(Config)、连接跟踪(Sleuth)、批量任务(Task),并且能够完美兼容。spring

3、Eureka 简介

 服务治理体系能够说是微服务架构中最为核心和基础的模块, 它主要用来实现各个微服务实例的自动化注册与发现。服务治理体系中的三个核心角色: 服务注册中心、 服务提供者以及服务消费者。而 Eureka Server 就承担了 Spring Cloud 的服务注册中心。接下来捋一捋 Eureka Server 进行服务治理的过程:数据库

  1. 服务注册:”服务提供者”在启动的时候会经过发送 REST 请求的方式将本身注册到 Eureka Server 上,同时带上了自身服务的一些元数据信息(hostName 之类的)。Eureka Server 接收到这个 REST 请求以后,将元数据信息存储在一个双层结构Map中,其中第一层的key是服务名,第二层的key是具体服务的实例名。
  2. 服务同步:因为服务注册中心之间互相注册为服务(Eureka Server 高可用场景),当服务提供者发送注册请求到一个服务注册中心时,它会将该请求转发给集群中相连的其余注册中心, 从而实现注册中心之间的服务同步。经过服务同步,两个服务提供者的服务信息就能够经过这两台服务注册中心中的任意一台获取到。
  3. 服务续约:在注册完服务以后,“服务提供者”会维护一个心跳用来持续告诉 Eureka Sever "我还活着 ”, 以防止Eureka Server 的 “ 剔除任务 ” 将该服务实例从服务列表中排除出去。
  4. 服务消费:当咱们启动“服务消费者”的时候,它会发送一个 REST 请求给服务注册中心,来获取上面注册的服务清单 。为了性能考虑, Eureka Serer会维护一份只读的服务清单来返回给客户端,同时该缓存清单会每隔30秒更新一次。
  5. 服务调用:“服务消费者”在 获取服务清单后,经过服务名能够得到具体提供服务的实例名和该实例的元数据信息。由于有这些服务实例的详细信息,因此客户端能够根据本身的须要决定具体调用哪一个实例,在 Ribbon 中会默认采用轮询的方式进行调用,从而实现客户端的负载均衡。
  6. 服务下线:服务实例进行正常的关闭操做时,它会触发一个服务下线的 REST 请求给 Eureka Server,告诉服务注册中心:“我要下线了 ”。服务端在接收到请求以后,将该服务状态置为下线(DOWN), 并把该下线事件传播出去。
  7. 失效剔除:有些时候,咱们的服务实例并不必定会正常下线,可能因为内存溢出、网络故障等缘由使得服务不能正常工做,而服务注册中心并未收到 “服务下线 ” 的请求。为了从服务列表中将这些没法提供服务的实例剔除,Eureka Server 在启动的时候会建立一个定时任务,默认每隔 一段时间(默认为60秒) 将当前清单中超时(默认为90秒)没有续约的服务剔除出去。
  8. 自我保护:Eureka Server在运行期间,会统计心跳失败的比例在15分钟以内是否低于85%, 若是出现低于的状况(在单机调试的时候很容易知足, 实际在生产环境上一般是因为网络不稳定致使),Eureka Server 会将当前的实例注册信息保护起来, 让这些实例不会过时, 尽量保护这些注册信息。

4、Eureka 实战

SpringBoot 版本号:2.1.6.RELEASE
SpringCloud 版本号:Greenwich.RELEASE缓存

1. 服务注册中心

  • pom.xml
<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>
  • application.yml
server:
  port: 1111

eureka:
  instance:
    hostname: localhost
    prefer-ip-address: true
  client:
    # 表示不向注册中心注册本身
    register-with-eureka: false
    # 注册中心的职责是维护实例,不须要去检索服务
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
   server:
     # 是否要打开自我保护机制
     enable-self-preservation: true

eureka 的配置项主要有三项:instance、client、server。“instance”维护该服务的实例信息,包括 hostname、port 这类描述实例特征的元数据信息;“client”主要是服务注册数据的配置,好比超时时间、服务缓存时间等;“server”是服务注册中心特有的配置,配置 Eureka Server 的相关配置项,好比上面的是否打开自我保护。网络

  • Application.java
//启动一个服务注册中心
@EnableEurekaServer
@SpringBootApplication
public class Application {

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

至此,咱们一个Eureka Server — 服务注册中心就搭建好了。架构

2. 服务提供者

  • pom.xml
<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
  • application.yml
server:
  port: 2222

spring:
  application:
    name: cloud-eureka-client

eureka:
  # 服务注册相关的配置信息
  client:
    service-url:
      defaultZone: http://localhost:1111/eureka/
  instance:
    # 是否优先使用IP地址做为主机名的标识
    prefer-ip-address: true

就这样,咱们的一个 Eureka Client 算是注册到 Eureka Server 上了。接下来,让咱们试试用 DiscoveryClient 发现咱们的服务信息:app

// 自动化配置, 建立 DiscoveryClient 接口针对 Eureka 客户端的 EurekaDiscoveryClient 实例
@EnableDiscoveryClient
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application .class, args);
    }
}
@RestController
public class HelloController {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private DiscoveryClient discoveryClient;
    @Value("${spring.application.name}")
    private String serviceId;

    @RequestMapping(value = "/hello", method = RequestMethod.GET)
    public String index() {
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);
        ServiceInstance instance = instances.get(0);
        logger.info("/hello, host:" + instance.getHost() + ", serviceId:" + instance.getServiceId());
        return "Hello World";
    }
}

3. 服务消费者

有了服务注册中心和服务提供者,咱们试试用 RestTemplate 调用一次服务吧!负载均衡

@RestController
public class ConsumerController {

    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/ribbon-consumer")
    public String helloConsumer() {
        // 这里访问的是服务名,而不是一个具体的地址(为了实现负载均衡策略),在服务治理框架中,这是一个很是重要的特性。
        ResponseEntity<String> result = restTemplate.getForEntity("http://cloud-eureka-client/hello", String.class);
        return result.getBody();
    }
}

5、附加

  • 默认状况下,Eureka 使用 Jersey 和 XStream 配合 JSON 做为 Server 与 Client 之间的通讯协议。
  • YAML 的意思实际上是: Yet Another Markup Language — 还是一种标记语言(这个看着有点想笑)。
  • 在 SpringBoot 的属性配置文件中,能够经过使用 ${random} 配置来产生随机的 int 值、long 值或者 string 字符串。
  • 在 Spring Boot 中,多环境配置的文件名须要知足 application-{profile}.properties的格式, 其中{profile}对应你的环境标识。经过启动参数 --spring.profiles.active=test 来指定激活的环境变量。

演示源代码 :https://github.com/JMCuixy/spring-cloud-demo

内容参考《Spring Cloud 微服务实战》

相关文章
相关标签/搜索