前言
开发工具以及版本
IntelliJ IDEA 2018.2.5
SpringCloud:Greenwich.SR1
SpringBoot:2.1.3 RELEASE
SpringCloud 和 SpringBoot 版本对应关系
官网地址: https://projects.spring.io/spring-cloud/
一:服务注册与发现
1.Eureka-Server(服务注册)
依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
启动类:
@EnableEurekaServer
Yml文件:
server:
port: 8761
spring:
application:
name: eureka-server
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
server:
# 是否开启自我保护,默认为 true, 在开启自我保护的情况下,注册中心在丢失客户端时,
# 会进入自动保护模式,注册中心并不会将该服务从注册中心删除掉 , 如果设置为 true,在负载均衡条件下,
# 一个服务挂掉后,注册中心并没有删掉该服务,
# 会导致客户端请求的时候可能会请求到该服务,导致系统无法访问
enable-self-preservation: false
2.服务发现
Eureka-client服务发现
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
启动类
@EnableEurekaClient
@EnableDiscoveryClient
Yml文件
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
3:高可用(生产环境搭建集群)
Eureka服务端
server:
port: 8761
servlet:
context-path: /
spring:
profiles:
active: dev
application:
name: eureka-server
security:
user:
name: fish
password: fish
# dev
---
spring:
profiles: dev
eureka:
server:
# 是否开启自我保护,默认为 true, 在开启自我保护的情况下,注册中心在丢失客户端时,
# 会进入自动保护模式,注册中心并不会将该服务从注册中心删除掉 , 如果设置为 true,在负载均衡条件下,一个服务挂掉后,注册中心并没有删掉该服务,
# 会导致客户端请求的时候可能会请求到该服务,导致系统无法访问
enable-self-preservation: false
# 清理无效节点的时间间隔,默认60s
eviction-interval-timer-in-ms: 180000
# 读取对等节点服务器复制的超时的时间,单位为毫秒,默认为200
peer-node-read-timeout-ms: 2000
# 定义了renews 和renews threshold的比值,默认值为0.85。当server在15分钟内,比值低于percent,即少了15%的微服务心跳,
# server会进入自我保护状态,Self-Preservation, 在此状态下,server不会删除注册信息,这就有可能导致在调用微服务时,实际上服务并不存在。
#这种保护状态实际上是考虑了client和server之间的心跳是因为网络问题,而非服务本身问题,不能简单的删除注册信息
#
# stackoverflow上,有人给出的建议是: 这里采用 第一种
# 1、在生产上可以开自注册,部署两个server
# 2、在本机器上测试的时候,可以把比值调低,比如0.49
# 3、或者简单粗暴把自我保护模式关闭
renewal-percent-threshold: 0.49
instance:
# 是否将 IP 注册到注册中心, Eureka 默认是以 hostname 来注册的。
prefer-ip-address: true
client:
# 表示是否注册自身到eureka服务器
register-with-eureka: true
# 是否要从其他Eureka Server实例获取数据, 仅在开发环境关闭,默认开启
fetch-registry: false
service-url:
# 注册中心默认地址。
defaultZone: http://fish:fish@10.10.10.10:8761/eureka/
---
spring:
profiles: staging
eureka:
server:
# 是否开启自我保护,默认为 true, 在开启自我保护的情况下,注册中心在丢失客户端时,
# 会进入自动保护模式,注册中心并不会将该服务从注册中心删除掉 , 如果设置为 true,在负载均衡条件下,一个服务挂掉后,注册中心并没有删掉该服务,
# 会导致客户端请求的时候可能会请求到该服务,导致系统无法访问
enable-self-preservation: false
# 清理无效节点的时间间隔,默认60s
eviction-interval-timer-in-ms: 180000
# 读取对等节点服务器复制的超时的时间,单位为毫秒,默认为200
peer-node-read-timeout-ms: 2000
# 定义了renews 和renews threshold的比值,默认值为0.85。当server在15分钟内,比值低于percent,即少了15%的微服务心跳,
# server会进入自我保护状态,Self-Preservation, 在此状态下,server不会删除注册信息,这就有可能导致在调用微服务时,实际上服务并不存在。
#这种保护状态实际上是考虑了client和server之间的心跳是因为网络问题,而非服务本身问题,不能简单的删除注册信息
#
# stackoverflow上,有人给出的建议是: 这里采用 第一种
# 1、在生产上可以开自注册,部署两个server
# 2、在本机器上测试的时候,可以把比值调低,比如0.49
# 3、或者简单粗暴把自我保护模式关闭
renewal-percent-threshold: 0.49
instance:
# 是否将 IP 注册到注册中心, Eureka 默认是以 hostname 来注册的。
prefer-ip-address: true
client:
# 表示是否注册自身到eureka服务器
register-with-eureka: false
fetch-registry: false
service-url:
# 注册中心默认地址。
defaultZone: http://fish:fish@10.10.10.10:8761/eureka/
---
spring:
profiles: prod
eureka:
server:
# 是否开启自我保护,默认为 true, 在开启自我保护的情况下,注册中心在丢失客户端时,
# 会进入自动保护模式,注册中心并不会将该服务从注册中心删除掉 , 如果设置为 true,在负载均衡条件下,一个服务挂掉后,注册中心并没有删掉该服务,
# 会导致客户端请求的时候可能会请求到该服务,导致系统无法访问
enable-self-preservation: false
# 清理无效节点的时间间隔,默认60s
eviction-interval-timer-in-ms: 90000
# 读取对等节点服务器复制的超时的时间,单位为毫秒,默认为200
peer-node-read-timeout-ms: 2000
# 定义了renews 和renews threshold的比值,默认值为0.85。当server在15分钟内,比值低于percent,即少了15%的微服务心跳,
# server会进入自我保护状态,Self-Preservation, 在此状态下,server不会删除注册信息,这就有可能导致在调用微服务时,实际上服务并不存在。
#这种保护状态实际上是考虑了client和server之间的心跳是因为网络问题,而非服务本身问题,不能简单的删除注册信息
#
# stackoverflow上,有人给出的建议是: 这里采用 第一种
# 1、在生产上可以开自注册,部署两个server
# 2、在本机器上测试的时候,可以把比值调低,比如0.49
# 3、或者简单粗暴把自我保护模式关闭
renewal-percent-threshold: 0.9
instance:
# 是否将 IP 注册到注册中心, Eureka 默认是以 hostname 来注册的。
prefer-ip-address: true
client:
# 表示是否注册自身到eureka服务器
register-with-eureka: false
fetch-registry: false
service-url:
# 注册中心默认地址。
defaultZone: http://fish:fish@192.168.200.217:8761/eureka/,http://fish:fish@10.10.10.10:8761/eureka/
Eureka-Client端
server:
port: 9858
servlet:
context-path: /debt
undertow:
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
io-threads: 4
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
worker-threads: 20
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
# 每块buffer的空间大小,越小的空间被利用越充分
buffer-size: 2048
# 是否分配的直接内存
direct-buffers: true
spring:
application:
name: debt-center
main:
allow-bean-definition-overriding: true
profiles:
active: dev
http:
encoding:
charset: UTF-8
enabled: true
servlet:
multipart:
enabled: true
max-file-size: 3MB
max-request-size: 3MB
aop:
auto: true
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.zaxxer.hikari.HikariDataSource
# hikari 连接池 https://blog.csdn.net/X5fnncxzq4/article/details/80649679
hikari:
# 自动提交
auto-commit: true
connection-test-query: SELECT 1
# 等待连接池分配连接的最大时长(毫秒),超过这个时长还没可用的连接则发生SQLException, 默认:30秒
# 生产环境 connect-time 10 s
connection-timeout: 9000
# 一个连接idle状态的最大时长(毫秒),超时则被释放(retired),默认:10分钟
idle-timeout: 600000
# 一个连接的生命时长(毫秒),超时而且没被使用则被释放(retired),默认:30分钟 1800000ms,建议设置比数据库超时时长少60秒,参考MySQL wait_timeout 7200s 参数(# 一个连接的生命时长(毫秒),超时而且没被使用则被释放(retired),默认:30分钟 1800000ms,建议设置比数据库超时时长少60秒,参考MySQL wait_timeout参数(show variables like '%timeout%';) --> ) -->
max-lifetime: 1800000
# 连接池中允许的最大连接数。缺省值:10;推荐的公式:((core_count * 2) + effective_spindle_count)
maximum-pool-size: 15
# 最小连接数
minimum-idle: 10
# 连接池名字
pool-name: DebtCenterHikariCP
messages:
basename: i18n/messages
mybatis-plus:
# MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名
type-aliases-package: com.zichan360.debt.pojo.po.*
# 该配置请和 typeAliasesPackage 一起使用,如果配置了该属性,则仅仅会扫描路径下以该类作为父类的域对象 。
type-aliases-super-type: java.lang.Object
mapperLocations: classpath:/mapper/*.xml
configuration:
# 这个配置会将执行的sql打印出来,在开发或测试的时候可以用
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 驼峰下划线转换
map-underscore-to-camel-case: true
# 配置的缓存的全局开关
cache-enabled: true
# 延时加载的开关
lazy-loading-enabled: true
# 开启的话,延时加载一个属性时会加载该对象全部属性,否则按需加载属性
multiple-result-sets-enabled: true
use-generated-keys: true
default-statement-timeout: 60
default-fetch-size: 100
feign:
httpclient:
enabled: false
okhttp:
enabled: true
client:
config:
default:
# 连接时间
connectTimeout: 3000
# 超时时间
readTimeout: 6000
# Feign Log 粗粒度配置,对全局生效
# NONE【性能最佳,适用于生产】:不记录任何日志(默认值)。
# BASIC【适用于生产环境追踪问题】:仅记录请求方法、URL、响应状态代码以及执行时间。
# HEADERS:记录BASIC级别的基础上,记录请求和响应的header。
# FULL【比较适用于开发及测试环境定位问题】:记录请求和响应的header、body和元数据。
loggerLevel: BASIC
# 请求压缩
compression:
request:
enabled: true
mime-types: ["text/xml", "application/xml", "application/json"]
min-request-size: 2048
response:
enabled: true
ribbon:
okhttp:
enabled: true
# 开启ribbon 饥饿加载模式(默认情况下Ribbon是懒加载),解决首次请求过慢的问题
eager-load:
enabled: true
clients: auth-center
# Resolved exception caused by handler execution: feign.RetryableException: timeout executing POST ***
ReadTimeout: 5000
ConnectTimeout: 5000
management:
endpoints:
web:
exposure:
include: "*"
endpoint:
health:
show-details: ALWAYS
eureka:
instance:
# 如果项目配置有 server.servlet.context-path 属性,想要被 spring boot admin 监控,就要配置以下属性
# 可debug 源码中该类知悉 de.codecentric.boot.admin.server.cloud.discovery.DefaultServiceInstanceConverter
metadata-map:
management:
context-path: /debt/actuator
health-check-url-path: /actuator/health
---
spring:
profiles: dev
datasource:
url:
username:
password:
data:
elasticsearch:
cluster-name: elasticsearch
cluster-nodes: 149.129.192.156
repositories:
enabled: true
properties:
port: 9300
# 推荐计算方式:(CPU cores * 3)/2 + 1
thread-pool: 10
# actuator 检测es
elasticsearch:
rest:
uris: ["http://149.129.192.156:9200"]
# redis config
redis:
host: localhost
port: 6379
timeout: 1000s
database: 0
lettuce:
pool:
# 连接池最大连接数(使用负值表示没有限制) 默认 8
max-active: 8
# 连接池中的最大空闲连接 默认 8
max-idle: 8
# 连接池中的最小空闲连接 默认 0
min-idle: 0
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
max-wait: -1ms
session:
store-type: redis
# zipkin config
zipkin:
enabled: true
base-url: http://20.20.0.160:9411
sleuth:
sampler:
# 将采样比例设置为 1.0,也就是全部都需要。默认是 0.1
probability: 1.0
cloud:
config:
# 指定配置环境,配置文件多环境则取名类似: config-prod.yml
profile: prod
# 指定配置文件名字(多个配置文件以英文逗号隔开)
name: test
# git 仓库分支名称
label: master
discovery:
# 连接的配置中心名字(applicaiton.name)
service-id: config-server
enabled: true
eureka:
instance:
# 是否将 IP 注册到注册中心, Eureka 默认是以 hostname 来注册的。
prefer-ip-address: true
client:
service-url:
# 注册中心默认地址。
defaultZone: http://fish:fish@10.10.10.10:8761/eureka/
es:
# 更新java搜索引擎
update_case_upload_index:
# 阿里云配置
aliyun:
bucket:
url:
---
spring:
profiles: staging
datasource:
url:
username:
password:
data:
elasticsearch:
cluster-name: elasticsearch
cluster-nodes: elasticsearch-staging.assetcircle.id
properties:
port: 9300
# 推荐计算方式:(CPU cores * 3)/2 + 1
thread-pool: 10
# actuator 检测es
elasticsearch:
rest:
uris: ["http://elasticsearch-staging.assetcircle.id:9200"]
# redis config
redis:
host: redis-staging.assetcircle.id
port: 6379
timeout: 1000s
database: 0
lettuce:
pool:
# 连接池最大连接数(使用负值表示没有限制) 默认 8
max-active: 8
# 连接池中的最大空闲连接 默认 8
max-idle: 8
# 连接池中的最小空闲连接 默认 0
min-idle: 0
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
max-wait: -1ms
session:
store-type: redis
# zipkin config
zipkin:
enabled: true
base-url: http://192.168.199.175:9411
sleuth:
sampler:
# 将采样比例设置为 1.0,也就是全部都需要。默认是 0.1
probability: 1.0
eureka:
instance:
# 是否将 IP 注册到注册中心, Eureka 默认是以 hostname 来注册的。
prefer-ip-address: true
client:
service-url:
# 注册中心默认地址。
defaultZone: http://fish:fish@10.10.10.10:8761/eureka/
es:
# 更新java搜索引擎
update_case_upload_index:
# 阿里云配置
aliyun:
bucket:
url:
---
spring:
profiles: prod
datasource:
url:
username:
password:
data:
elasticsearch:
cluster-name: my-application
cluster-nodes: elasticsearch1.assetcircle.id,elasticsearch2.assetcircle.id,elasticsearch3.assetcircle.id
properties:
port: 9300
# 推荐计算方式:(CPU cores * 3)/2 + 1
thread-pool: 10
# actuator 检测es
elasticsearch:
rest:
uris: ["http://elasticsearch1.assetcircle.id:9200", "http://elasticsearch2.assetcircle.id:9200", "http://elasticsearch3.assetcircle.id:9200"]
# redis config
redis:
host: mastercache.redis.ap-southeast-5.rds.aliyuncs.com
port: 6379
timeout: 1000s
password: KKBqPanTSzCFv5R6
database: 0
lettuce:
pool:
# 连接池最大连接数(使用负值表示没有限制) 默认 8
max-active: 8
# 连接池中的最大空闲连接 默认 8
max-idle: 8
# 连接池中的最小空闲连接 默认 0
min-idle: 0
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
max-wait: -1ms
session:
store-type: redis
# zipkin config
zipkin:
enabled: true
base-url: http://192.168.200.230:9411
sleuth:
sampler:
# 将采样比例设置为 1.0,也就是全部都需要。默认是 0.1
probability: 1.0
eureka:
instance:
# 是否将 IP 注册到注册中心, Eureka 默认是以 hostname 来注册的。
prefer-ip-address: true
client:
service-url:
# 注册中心默认地址。
defaultZone: http://fish:fish@10.10.10.10:8761/eureka/,http://fish:fish@10.10.10.10:8761/eureka/
es:
# 更新java搜索引擎
update_case_upload_index:
# 阿里云配置
aliyun:
bucket:
url:
**4:用户认证**
Pom添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
Yml配置文件(可参考Eureka服务端配置)
security:
user:
name: fish
password: fish
其他服务作为客户端注册服务时候需要加上用户名&&密码例如:
defaultZone: http://fish:fish@10.10.10.10:8761/eureka/
5.Eureka元数据
两种元数据分别为标准元数据与自定义元数据
标准元数据指的是主机名,IP地址,端口号,状态页和健康检查等信息,这些信息都会被发布在注册列表中,用于服务之间的调用。
自定义元数据可以使用Eureka.instance.metadata-map设置,这些元数据
可以再远程客户端中访问,但一般不会改变客户端的行为,除非说是客户端知道这些元数据的含义。
6.总结
客户端发现:
优点:简单直接,不需要代理介入,知道所有可用服务的实际地址
缺点: A自己实现发现挑选(负载)B 的逻辑 , 耦合度 客户端与注册中心严重耦合
服务端发现:
优点: B服务 + 注册中心对 A 服务 透明, A 发请求给代理服务即可
缺点: 需要不断维护配置更新等。。。
-Nginx
-zookeeper
-Kubernetes(K8S)
二:Ribbon客户端负载均衡
Ribbon与Eureka结合使用时候,获取到EurekaServer的服务列表时候,基于负载均衡算法,请求道某一个服务提供者实例,默认的算法包括轮训,随机等也可以自定义算法。
Ribbon主要就是对请求做http请求的封装,通过请求中的服务名去Eureka服务中查询列表,然后经过指定的算法筛选出对应的服务,把对应服务的IP+端口替换原来的请求返回。
Pom文件
先前的spring cloud starter Netflix Eureka client包含ribbon的依赖,故无需导入
Java代码
RestTemplate 的三种实现方式
第一种: 直接使用restTemplate
RestTemplate restTemplate = new RestTemplate();
String object = restTemplate.getForObject("http://localhost:8881/a", String.class)
第二种: 利用loadBalancerClient
@Resource
private LoadBalancerClient loadBalancerClient;
ServiceInstance serviceInstance = loadBalancerClient.choose("A");
String url = String.format("http://%s:%s/a", serviceInstance.getHost(), serviceInstance.getHost());
RestTemplate restTemplate = new RestTemplate();
String object = restTemplate.getForObject(url, String.class);
第三种 利用注解 @LoadBalanced 注入 RestTemplate
@Bean
@LoadBalanced
Public RestTemplate restTemplate(){
return new RestTemplate();
}
String object = restTemplate.getForObject("http://A/a", String.class);
三:SpringCloudConfig 统一管理微服务配置
1.服务端
Pom文件:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
Yml文件
server:
port: 9999
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://user@gitlab.dev.zichan360.com/Vietnam/ConfigRepo.git
username: 用户名……
password: 密码……
timeout: 5
default-label: master
启动类:
@EnableConfigServer
命名规则:
/{name}-{profiles} name:表示微服务应用的名字 profiles代表环境命名(dev,staging)
/{label}/{name}-{profiles} label代表git分支的名字 默认是master
Config Server高可用:
配置服务中心的高可用的核心还是基于注册中心
2.客户端
Pom文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
Yml文件
spring:
application:
name: config-client客户端的名称(例:debt-center)
cloud:
config:
profile: dev
name: 文件名字(例:redis)
label: master
discovery:
service-id: config-server
enabled: true
组合后的yml文件例如就是 debt-center这个服务下的 redis-dev.yml 文件 master分支