【SpringCloud和Docker】笔记

Spring Boot 注解

  • @GetMapping(“/{id}”)

  • @SpringBootApplication

组合注解,整合了@Configuration@EnableAutoConfiguration@ComponentScan

Spring Boot Actuator:提供很多监控端点

添加依赖,就可以通过http://{id}:{port}/{endpoint}的形式访问这些端点,从而了解应用程序的运行情况。可以查看配置信息、属性列表、线程活动快照、环境变量、健康检查、URL路径、最近100个HTTP请求

Eureka 服务发现组件

SpringCloud提供了多种服务发现组件的支持,例如Eureka、Consul和Zookeeper等,Eureka是Netflix开源的服务发现组件,它包含Server和Client。SpringCloud将它集成在子项目SpringCloud Netflix中,从而实现微服务的注册于发现。

原理

  • 各个微服务启动时向Eureka Server注册自己的信息,Eureka Server会存储这些信息

  • Eureka Client会周期性(默认30s)地向Eureka Server发送心跳续约自己的在线状态

  • Eureka Server的实例集群中,相互间通过复杂的方式实现注册表数据的同步

  • Eureka Client也会缓存Eureka Server中注册的信息,以便快捷完成调用

编写Eureka Server

  • 添加依赖
1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka-server</artifactId>
</dependency>
</dependencies>
  • @EnableEurekaServer

  • application.yml

1
2
3
4
5
6
7
8
server:
port:8081
eureka:
client:
registerWithWureka:false //是否注册自己
fetchRegistry:false //是否从Eureka Server获取注册信息
serviceUrl:
defaultZone:http://localhost:8081/eureka/ //可以配置多个地址,就是集群,一个也可以,会自动同步

微服务注册到Eureka Server

  • 添加依赖
1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
</dependencies>
  • @EnableEurekaClient 或者 @EnableDiscoveryClient

  • application.yml

1
2
3
4
5
6
7
8
9
spring:
application:
name:event-chenshinan
eureka:
client:
serviceUrl:
defaultZone:http://localhost:8081/eureka/
instance:
prefer-ip-address:true //表示将自己的IP注册到Eureka Server,默认为false就是微服务所在操作系统的hostname到Eureka Server

REST端点

Eureka Server提供了一些REST端点。非JVM的微服务可使用这些REST端点操作Eureka,从而实现注册与发现。事实上,Eureka Client就是使用java编写的操作这些REST端点的类库。Eureka提供的REST端点,可以使用XML或者JSON与这些端点通信,默认是XML。

自我保护模式

当Eureka Server节点在短时间内丢失过多客户端时,节点就会进入自我保护模式。就不再删除服务注册表中的数据。

可以通过多种方式忽略网卡

可以开启eureka的健康检查

Ribbon 实现客户端侧负载均衡

Ribbon是Netflix发布的负载均衡器,它有助于控制HTTP和TCP客户端的行为,为Ribbon配置服务提供者地址列表后,Ribbon就可基于某种负载均衡算法,自动帮助服务消费者去请求。

编写

  • 添加依赖
1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
</dependencies>

前面引入的spring-cloud-starter-eureka中包含了ribbon,可以不用再引入

  • @LoadBalanced 整合负载均衡

  • 可以通过注入LoadBalancerClient来获取当前是哪个节点

可以自定义Ribbon配置

1
2
3
event-chenshinan
ribbon:
NFLoadBalancerRuleClassName:com.netflix.loadbalancer.RandomRule

脱离Eureka使用Ribbon

  • 去掉@EnableDiscoveryClient

  • application.yml中添加

1
2
3
event-chenshinan
ribbon:
listOfServers:localhost:8080,localhost:8081

使用Fegin实现声明式REST调用

编写

  • 添加依赖
1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
</dependencies>
  • @EnableFeginClient 启动类添加

  • @FeignClient

1
@FeignClient(name="event-chenshinan", url="http://localhost:8000/", configuration="FeignConfiguration.class")
  • client接口中的方法需要@RequestParam("id") Long id
1
2
3
4
5
@FeignClient(name="event-chenshinan")
public interface UserFeignClient{
@RequestMapping(value="/get",method=RequestMethod.GET)
public User get1(@RequestParam("id") Long id);
}

自定义Feign配置

手动创建Feign,不用注解和注入的方式

Feign对压缩的支持

1
2
feign.compression.request.enabled=true
feign.compression.response.enabled=true

开启Feign日志

使用Hystrix实现微服务容错机制

Hystrix是一个实现了超时机制和断路器模式的工具类库

编写

  • 添加依赖
1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
</dependencies>
  • @EnableCircuitBreaker或EnableHystrix 启动类添加

  • @HystrixCommand(fallbackMethod=”xxxFallback”) 除了回退方法还有很多属性可以配置

1
2
3
4
5
6
7
8
9
@HystrixCommand(fallbackMethod="xxxFallback",commandProperties={
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="5000"),
@HystrixProperty(name="execution.isolation.strategy",value="SEMAPHORE")//线程隔离策略
...
})
@GetMapping("/user/{id}")
public User xxx(@PathVariable Long id){
...
}

注意:当请求失败、被拒绝、超时或者断路器打开时,都会进入回退方法

功能

  • 包裹请求

  • 跳闸机制

  • 资源隔离

  • 监控

  • 回退机制

  • 自我修复

Hystrix线程隔离策略与传播上下文

  • THREAD(线程隔离)[默认]:使用该方法,HystrixCommand将会在单独的线程上执行,并发请求受线程池中的线程数量限制

  • SEMAPHORE(信号量隔离):使用该方式,HystrixCommand将会在调用线程上执行,开销较小,并发请求受到信号量个数的限制

Fegin使用Hystrix,默认支持

回调方法

1
2
3
4
5
@FeignClient(name="event-chenshinan",fallback=xxxFallback.class)
public interface UserFeignClient{
@RequestMapping(value="/get",method=RequestMethod.GET)
public User get1(@RequestParam("id") Long id);
}

xxxFallback要实现UserFeignClient接口

通过FallbackFactory检查回退原因

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@FeignClient(name="event-chenshinan",fallbackFactory=xxxFallbackFactory.class)
public interface UserFeignClient{
@RequestMapping(value="/get",method=RequestMethod.GET)
public User get1(@RequestParam("id") Long id);
}

@FeignClient(name="event-chenshinan",fallbackFactory=xxxFallbackFactory.class)
class xxxFallbackFactory implements FallbackFactory<UserFeignClient>{
...Logger...
@Override
public UserFeignClient create(Throwable cause){
return new UserFeignClient;
}
@Override
public User get1(Long id){
...
}
}

禁用Hystrix

  • 单个禁用 FeignDisableHystrixConfiguration
1
2
3
4
5
@FeignClient(name="event-chenshinan",configuration=FeignDisableHystrixConfiguration.class)
public interface UserFeignClient{
@RequestMapping(value="/get",method=RequestMethod.GET)
public User get1(@RequestParam("id") Long id);
}
  • 全局禁用,在application.yml
1
2
3
feign:
hystrix:
enabled:false

监控

使用Turbine聚合监控数据

Turbine是一个聚合Hystrix监控数据的工具,它可将所有相关/hystrix.stream端点的数据聚合到一个组合的/turbine.stream中,从而让集群的监控更加方便

使用Zuul构建微服务网关

微服务网关是介于客户端和服务端之间的中间层,所有外部请求都会先经过微服务网关。Zuul是Netfix开源的微服务网关,Zuul的核心是一系列的过滤器。完成如下功能:身份认证与安全、审查与监控、动态路由、压力测试、负载分配、静态响应处理、多区域弹性

优点

  • 易于监控

  • 易于认证

  • 减少了客户端与各个微服务之间的交互次数

Zuul使用的默认HTTP客户端是Apache HTTP Client,也可以支持RestClient、OkHttpClient

编写

  • 添加依赖
1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
</dependencies>
  • @EnableZuulProxy 启动类添加

  • application.yml

1
2
3
4
5
6
7
8
9
server:
port:8040
spring:
application:
name:chenshinan-gateway-zuul
eureka:
client:
service-url:
defaultZone:http://localhost:8761/eureka/

默认情况下,Zuul会代理所有注册到Eureka Server的微服务,并且Zuul的路径规则如下:
http://ZUUL_HOST:ZUUL_PORT/微服务在Eureka上的serviceId/**会被转发到serviceId对应的微服务

路由配置详解

  • 自定义指定微服务的访问路径
1
2
3
zuul:
routes:
event-chenshinan:/chenshinan/**
  • 忽略指定微服务
1
2
3
zuul:
ignord-services:
event-chenshinan,user-chenshinan
  • 同时指定path和URL
1
2
3
4
5
zuul:
routes:
user-route: //该配置方式中,user-route只是给路由一个名词,可以任何起名
url:http://localhost:8000/ //指定的url
path: /user/** //url对应的路径

这种配置的路由不会作为HystrixCommand执行,同时也不能使用Ribbon来负载均衡多个URL

  • 同时指定path和URL,并且不破坏Zuul的Hystrix、Ribbon特性
1
2
3
4
5
6
7
8
9
10
11
zuul:
routes:
user-route: //该配置方式中,user-route只是给路由一个名词,可以任何起名
path: /user/** //url对应的路径
service-id:user-chenshinan
ribbon:
eureka:
enabled:false //为Ribbon禁用Eureka
user-chenshinan:
ribbon:
listOfServers:localhost:8000,localhost:8001 //为user-chenshinan提供两个负载路径
  • 路由前缀
1
2
3
4
5
zuul:
prefix: /api //转发前缀
strip-prefix:false //true转发过滤前缀,false转发不过滤前缀
routes:
user-chenshinan: /user/**

可将com.netflix包的日志级别设为DEBUG,这样有助于理解Zuul的路由配置

1
2
3
logging:
level:
com.netflix:DEBUG

Zuul的安全与Header

  • 为防止某些敏感Header外泄
1
2
3
4
5
zuul:
routes:
user-chenshinan:
path: /users/**
sensitive-headers:Cookie,Set-Cookie,Authorization
  • 全局指定敏感Header
1
2
zuul:
sensitive-headers:Cookie,Set-Cookie,Authorization
  • 忽略Header
1
2
3
4
5
zuul:
routes:
user-chenshinan:
path: /users/**
sensitive-headers:Cookie,Set-Cookie,Authorization

使用Zuul上传文件

对于小文件(1M以内)上传,无须任何处理。对于大文件(10M以上),需要为上传路径添加/zuul前缀。也可以使用zuul.servlet-path自定义前缀。

  • 如果Zuul使用了Ribbon做负载均衡,对于超大文件(500M),需要提升超时设置。设置在gate-way
1
2
3
4
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:6000
ribbon:
ConnectTimeout:3000
ReadTimeout:60000
  • application.yml设置multipart的文件大小
1
2
3
4
http:
multipart:
max-file-size:2000Mb //默认1M
max-request-size:2500Mb //默认10M

Zuul过滤器

过滤类型与请求周期

  • PRE:这种过滤器在请求被路由之前调用

  • ROUTING:这种过滤器将请求路由到微服务

  • POST:这种过滤器在路由到微服务以后执行

  • ERROR:在其他阶段发送错误时执行该过滤器

  • 自定义过滤类型

编写Zuul过滤器

继承抽象类ZuulFilter实现抽象方法

  • filterType:返回过滤器类型

  • filterOrder:指定过滤器的执行顺序

  • shouldFilter:返回是否执行该过滤器

  • run:过滤器的具体逻辑

禁用Zuul过滤器

只需设置zuul.<SimpleClassName>.<filterType>.disable=true

容错与退回

Zuul的Hystrix监控的粒度是微服务,而不是某个API。回退的话需要实现ZuulFallbackProvider接口,并指定为哪个微服务提供回退

高可用

  • Zuul客户端也注册到了Eureka Server上,自动提供多个Zuul节点

  • Zuul客户端为手机APP等,无法注册到Eureka Server上,需要借助一个额外的负载均衡器来实现Zuul的高可用,例如Nginx、HAProxy等,Zuul客户端将请求发送到负载均衡器,负载均衡器将请求转发到其代理的其中一个Zuul节点上。

使用Zuul聚合微服务

外部请求需要查询Zuul后端的多个微服务,可使用Zuul聚合微服务请求,例如手机APP只需发送一个请求给Zuul,由Zuul请求用户微服务以及电影微服务,并组织好数据给手机APP

使用Spring Cloud Config统一管理服务器配置

Spring Cloud Config为分布式系统外部化配置提供服务器端和客户端的支持,它包括Config Server和Config Client两部分。Config Server是一个可横向扩展、集中式的配置服务器,默认使用Git存储配置内容。Config Client在各个微服务中,各个微服务在启动时,会起球Config Server以获取所需要的配置属性,然后缓存这些属性以提高性能。

特性

  • 集中管理配置

  • 不同环境不同配置

  • 运行期间可动态调整

  • 配置修改后可自动更新

编写Config Server

  • 添加依赖
1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
  • @EnableConfigServer 启动类添加

  • application.yml

1
2
3
4
5
6
7
8
9
10
11
12
server:
port:8080
spring:
application:
name:chenshinan-config-server
cloud:
config:
server:
git:
uri:https://git.xxx //配置Git仓库的地址
username:xx //Git仓库的账号
password:xx //Git仓库的密码
  • 可以使用Config Server的端点获取配置文件的内容,映射规则如下:
1
2
3
4
5
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{lable}/{application}-{profile}.properties

以上端点都可以映射到{application}-{profile}.properties这个配置文件,{application}表示微服务的名称,{label}对应Git仓库的分支,默认是master

  • 通过构造URL的方式,获取了Git仓库中的配置信息

编写Config Client

  • 添加依赖
1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
  • application.yml
1
2
3
4
5
6
7
8
spring:
application:
name:chenshinan-config-server
cloud:
config:
uri:http://localhost:8080/
profile:dev
label:master
  • spring.application.name:对应Config Server所获取的配置文件中的{application}

  • spring.cloud.config.uri:指定Config Server的地址,默认是http://localhost:8888

  • spring.cloud.config.profile:profile对应Config Server所获取的配置文件中的{profile}

  • spring.cloud.config.label:指定Git仓库的分支,对应{label}

注意

以上属性应配置在bootstrap.yml,而不是application.yml

bootstrap与application

加载顺序:这里主要是说明application和bootstrap的加载顺序。

  • bootstrap.yml(bootstrap.properties)先加载
  • application.yml(application.properties)后加载

    bootstrap.yml 用于应用程序上下文的引导阶段。
    bootstrap.yml 由父Spring ApplicationContext加载。
    父ApplicationContext 被加载到使用 application.yml 的之前。
    

配置区别

bootstrap.yml 和application.yml 都可以用来配置参数。

  • bootstrap.yml 可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。
  • application.yml 可以用来定义应用级别的,如果搭配 spring-cloud-config 使用 application.yml 里面定义的文件可以实现动态替换。

    使用Spring Cloud Config Server时,应在 bootstrap.yml 中指定:
    spring.application.name
    spring.cloud.config.server.git.uri
    

注意

一旦bootStrap.yml 被加载,则内容不会被覆盖,即便后期加载的application.yml的内容标签与bootstrap的标签一致,application 也不会覆盖bootstrap,而application.yml 里面的内容可以动态替换。

Git仓库配置详解

  • 占位符支持

  • 模式匹配

  • 搜索目录

  • 启动时加载配置文件

Config Server和Config Client都注册搭配Eureka Server上

将Config Server和Config Client都注册到Eureka Server上,在Config Client的bootstrap.yml配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
spring:
application:
name:event-chenshinan
cloud:
config:
profile:dev
label:master
discovery:
enabled:true //表示使用服务发现组件中的Config Server,而不时指定的Config Server的uri,默认false
service-id:chenshinan-config-server
eureka:
client:
serviceUrl:
defaultZone:http://localhost:8761/eureka/

使用Spring Cloud Sleuth实现微服务跟踪

  • 添加依赖
1
2
3
4
5
6
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
</dependencies>
  • 设置配置
1
2
3
4
5
6
7
spring:
application:
name:chenshinan-user
logging:
level:
root:INFO
org.springframework.web.servlet.DispatcherServlet:DEBUG
  • 可以配合Zipkin使用,Zipkin是Twitter开源的分布式跟踪系统

  • 可以配合Zipkin,再用RabbitMQ收集数据,并把数据存储在Elasticsearch

常见问题总结

Eureka注册服务慢

想要解决服务注册慢的问题,只需将eureka.instance.leaseRenewalIntervalInSeconds设成一个更小的值。该配置用于设置Eureka Client向Eureka Server发送心跳的时间间隔,默认是30s。在生产环境中,建议坚持使用默认值。

如何自定义微服务的InstanceID

1
2
3
4
5
6
spring:
application:
name:chenshinan-user
eureka:
instance:
instance-id:${spring.cloud.client.ipAddress}:${server.port}

Eureka的UNKNOWN问题

一般就是未配置spring.application.name或者eureka.instance.appname属性,实例的状态为UNKNOWN可能是由健康检查导致,eureka.client.healthcheck.enabled=true必须设置在application.yml中,而不能设置在bootstrap.yml中,否则一些场景下回导致应用状态UNKNOWN的问题。

Hystrix/Feign整合Hystrix后首次请求失败

  • 延长Hystrix的超时时间
1
hystrix.command.default.execution.isolation.thread.thomeoutInMilliseconds:5000
  • 禁用Hystrix的超时
1
hystrix.command.default.execution.timeout.enabled:false
  • 可以为Feign禁用Hystrix
1
feign.hystrix.enabled:false

使用 Docker Compose 编排微服务

使用compose来快速创建并启动多个容器

安装compose

工程、服务、容器

Dokcer Compose将所管理的容器分为三层,分别是工程(project),服务(service)以及容器(container),Docker Compose运行目录下的所有文件组成一个工程,一个工程可包含多个服务。

docker-compose.yml常用命令

  • build:通过指定dockerfile启动容器

  • environment:环境变量设置

  • expose:暴露端口,只将端口暴露给连接的服务,而不暴露给宿主机

  • image:指定镜像名称或镜像ID,如果本地不存在该镜像,Compose会尝试下载该镜像

  • links:连接到其他服务的容器

  • ports:暴露端口信息,可使用HOST:CONTAINER的格式,也可只指定容器端口

  • volumes:卷挂载路径设置

docker-compose常用命令

  • build 构建或重新构建服务
1
docker-compose build
  • help 帮助
1
docker-compose help build
  • kill 通过发送SIGKILL信号停止服务的容器
1
docker-compose kill eureka
  • logs 查看服务的日志输出

  • ps 列出所有容器

1
docker-compose ps
  • scale 设置指定服务运行容器的个数,以service=num的形式指定,单个服务启动多个节点来负载均衡
1
docker-compose scale user=3
  • start 启动指定服务已存在的容器
1
docker-compose start eureka
  • stop 停止已运行的容器
1
docker-compose stop eureka
  • up 构建、创建、重新创建、启动,连接服务的相关容器

docker-compose up命令会聚合所有容器的输出,当命令退出时,所有容器都会停止。使用-d参数在后台运行

1
docker-compose up -d

网络设置

默认情况下,Compose会为应用创建一个网络,服务的每个容器都会加入该网络中。这样,容器就可被该网络中的其他容器访问

更新容器

当服务的配置发生更改时,同样可以用up更新配置,此时Compose会删除旧容器并创建新容器,新容器会以不同的IP地址加入网络。任何指向旧容器的连接都会被关闭,容器会重新找到新容器并连接上去。

网络隔离

A服务与B服务隔离,两者分别使用自己的网络,C服务可以与两者通信。使用networks命令,即可方便实现服务间的网络隔离与连接

参考文献

  • 【SpringCloud和Docker】书籍