SpringCloud基础(1)–简介与Eureka的使用

当我们创建一个传统的SpringBoot项目,随着项目的不断扩大,越来越多的功能被加入到项目中,此时如果所有功能都集中到单端上,会对服务器造成巨大压力,一台服务器承受不住巨大的单体应用的部署,且单体应用维护也愈发困难,这就需要我们开发新的框架来解决了。

  1. 微服务就是这个的解决方案,微服务把一个庞大的单体应用拆分为一个个的小型服务,每个小型的微服务,都可以独立部署和升级,这样,就算整个系统崩溃,那么也只会影响一个服务的运行。
  2. 微服务之间使用HTTP进行数据交互,不再是单体应用内部交互了,虽然这样会显得更麻烦,但是带来的好处也是很直接的,甚至能突破语言限制,使用不同的编程语言进行微服务开发,只需要使用HTTP进行数据交互即可。
  3. 我们可以同时购买多台主机来分别部署这些微服务,这样,单机的压力就被分散到多台机器,并且每台机器的配置不一定需要太高,这样就能节省大量的成本,同时安全性也得到很大的保证。
  4. 甚至同一个微服务可以同时存在多个,这样当其中一个服务器出现问题时,其他服务器也在运行同样的微服务,这样就可以保证一个微服务的高可用。

但其背后也存在许多问题:

  1. 要实现微服务并不是说只需要简单地将项目进行拆分,我们还需要考虑对各个微服务进行管理、监控等,这样我们才能够及时地寻找和排查问题。因此微服务往往需要的是一整套解决方案,包括服务注册和发现、容灾处理、负载均衡、配置管理等。
  2. 它不像单体架构那种方便维护,由于部署在多个服务器,我们不得不去保证各个微服务能够稳定运行,在管理难度上肯定是高于传统单体应用的。
  3. 在分布式的环境下,单体应用的某些功能可能会变得比较麻烦,比如分布式事务。


而SpringCloud就是Spring提供的一套分布式解决方案。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、熔断机制、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。

SpringCloud整体架构的亮点是非常明显的,分布式架构下的各个场景,都有对应的组件来处理,比如基于Netflix(奈飞)的开源分布式解决方案提供的组件:

  1. Eureka – 实现服务治理(服务注册与发现),我们可以对所有的微服务进行集中管理,包括他们的运行状态、信息等。
  2. Ribbon – 为服务之间相互调用提供负载均衡算法(现在被SpringCloudLoadBalancer取代)
  3. Hystrix – 断路器,保护系统,控制故障范围。暂时可以跟家里电闸的保险丝类比,当触电危险发生时能够防止进一步的发展。
  4. Zuul – api网关,路由,负载均衡等多种作用,就像我们的路由器,可能有很多个设备都连接了路由器,但是数据包要转发给谁则是由路由器在进行(已经被SpringCloudGateway取代)
  5. Config – 配置管理,可以实现配置文件集中管理

Eureka

Eureka能够自动注册并发现微服务,然后对服务的状态、信息进行集中管理,这样当我们需要获取其他服务的信息(如服务请求地址)时,我们只需要向Eureka进行查询就可以了。

首先我们需要让项目支持SpringCloud,我们需要在父项目里引入依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-dependencies</artifactId>
    <version>2021.0.1</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

然后,我们需要创建一个新的maven项目作为Eureka服务器(记得创建启动类和xml配置文件),引入Eureka服务器依赖:

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

启动类需要在@SpringBootApplication注解下面加上@EnableEurekaServer注解表示作为Eureka服务器

之后我们需要修改application配置(这里使用yml):

server:
  port: 8088
eureka:
  # 开启之前需要修改一下客户端设置(虽然是服务端
  client:
    # 由于我们是作为服务端角色,所以不需要获取服务端,改为false,默认为true
    fetch-registry: false
    # 暂时不需要将自己也注册到Eureka
    register-with-eureka: false
    # 将eureka服务端指向自己
    service-url:
      defaultZone: http://localhost:8088/eureka

之后我们就可以通过这个端口来访问Eureka管理页面了。

如果存在端口访问失败,很有可能是SpringBoot版本依赖问题,更换SpringCloud版本即可

配置完服务器端,我们就可以去配置客户端了。

与服务器端类似,我们需要先导入客户端依赖:

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

之后我们需要修改配置文件:

eureka:
  client:
      # 跟上面一样,需要指向Eureka服务端地址,这样才能进行注册
    service-url:
      defaultZone: http://localhost:8088/eureka

之后,我们启动项目后,就能在Eureka管理页面看到注册进来的项目了。

但此时我们发现,这些项目在管理页面都还是UnKnown项目,这就需要我们在配置文件内添加项目名称:

spring:
  application:
    name: userservice

之后我们就能在管理页面看到项目(这里存在缓存,如果没重启服务器端则会依然显示几个Unknown)

当我们的服务启动之后,会每隔一段时间跟Eureka发送一次心跳包,这样Eureka就能够感知到我们的服务是否处于正常运行状态。

服务发现

在我们使用Eureka之前,如果需要几个项目相互调用接口,我们需要知道其准确的接口地址,而在较大项目中,很明显这个操作是难以维护的。而我们有了Eureka之后就能直接用服务名称向其进行查询,得到微服务地址。

此时,我们需要将RestTemplate(发起http请求的类)注册为bean来交由Spring管理,并添加@LoadBalance注解来让它支持按服务名称查询的同时,支持负载均衡。

由于bean的注册只能在启动类和配置类中,因此我们需要创建一个新的配置类:

@Configuration
public class BeanConfig {
    @Bean
    @LoadBalanced
    RestTemplate template(){
        return new RestTemplate();
    }
}

这样,我们在需要使用其他项目接口的地方,注入这个bean,然后通过http://服务名称就可以请求这个服务接口了。

说到负载均衡,我们需要知道在服务器上,一个Spring项目是可以开多个的,在IDEA的启动配置(编辑配置)内就可以添加:

我们可以通过加号,添加新的springboot项目,并配置名称与主类来实现

此时,我们需要配置两个项目的端口,我们首先把配置文件内端口删除,同时在编辑配置中的环境变量里添加端口:

这样我们就能运行两个相同的项目了。

那么接下来,运行两个相同项目有什么用呢?这就不得不提Eureka的作用。

当我们运行了两个相同的项目,我们会发现在管理页面,该项目的数量和地址数都增加了,这就代表,如果我们通过Eureka去查询接口,即使一个客户端断了,我们依然可以使用其他的地址去完成请求!

并且由于我们上面使用了@LoadBalance 注解实现负载均衡,在我们调用这个服务的时候,Eureka会使用轮询的方式进行请求,很大程度平摊了服务器压力,同时当一个服务停止运行时,可以由另外的服务来继续进行工作。

Eureka高可用

Eureka的使用方便了我们将服务划分为多个微服务,同时借由多个相同项目的同时注册实现服务的高可用。

但实际上我们会发现一个问题,当我们处于中心的Eureka停止运行时,整个项目都会奔溃,这明显就是我们不愿看到的情况,因此我们需要去规避这种风险。

那该怎么办呢?如同上面我们多开同一服务来分散压力同时保证只要有一个服务存在就能维持服务使用,Eureka也能通过多开,相互注册来实现高可用。

那该如何实现呢?

首先我们需要知道一点,由于需要多开Eureka,我们就需要复制下来的Eureka运行项有着不同的配置,因此我们需要创建不同配置项。

我们创建application-01和application-02来实现不同配置

我们修改application为

server:
  port: 8801
spring:
  application:
    name: eurekaserver
eureka:
  instance:
      # 由于不支持多个localhost的Eureka服务器,但是又只有本地测试环境,所以就只能自定义主机名称了
      # 主机名称改为eureka01
    hostname: eureka01
  client:
    fetch-registry: false
    # 去掉register-with-eureka选项,让Eureka服务器自己注册到其他Eureka服务器,这样才能相互启用
    service-url:
        # 注意这里填写其他Eureka服务器的地址,不用写自己的
      defaultZone: http://eureka02:8802/eureka

这里主要使用eureka.instance.hostname给Eureka服务器添加了主机名称,之后把register-with-eurekar让eureka能注册到其他Eureka服务中,并使用client.service.defaultZone 把Eureka服务器地址指向其他Eureka服务就可以使用了。

值得注意的是,因为Eureka只支持一个localhost地址的Eureka服务器,所以需要更改主机名称来“伪造”其他地址。

但会存在最后指向eureka服务地址时,指向了网络地址而非本地地址,因此需要在操作系统的host文件内将相关地址指向本地如:

127.0.0.1 eureka01

之后我们就可以配置运行设置,在各个eureka运行项的环境变量中添加spring.profiles.active=x

这个变量用于指定使用的配置文件名称,x表示配置文件名称 ‘-’ 后面的字样

这样就实现了Eureka集群的搭建。

之后,我们只需要修改其他微服务,让微服务在这些Eureka中都注册一次就行了,即在defaultZone 内写如多个服务地址即可。

这样即使一个Eureka服务挂掉,只要有一个Eureka,服务就能持续运行下去。