springcloud使用了也有快1年了,整理总结下springcloud的一些使用方法,持续更新。 🥕
该文章记录总结使用的springboot版本为2.0.8.RELEASE,对应的springcloud版本为Finchley.RELEASE。
分布式链路跟踪(zipkin+sleuth)
微服务架构是一个分布式架构,它按业务划分服务单元,一个分布式系统往往有很多个服务单元。由于服务单元数量众多,业务的复杂性,如果出现了错误和异常,很难去定位。主要体现在,一个请求可能需要调用很多个服务,而内部服务的调用复杂性,决定了问题难以定位。所以微服务架构中,必须实现分布式链路追踪,去跟进一个请求到底有哪些服务参与,参与的顺序又是怎样的,从而达到每个请求的步骤清晰可见,出了问题,很快定位。
安装zipkin
直接采用消息总线rabbitmq方式,使服务和zipkin解耦。需要注意的是这种方式默认的队列是叫zipkin,而且是由zipkin服务端创建的,所以需要先启动zipkin。
下载最新版的zipkin.jar,然后就可以根据以下命令启动:
1 | wget -O zipkin.jar 'https://search.maven.org/remote_content?g=io.zipkin.java&a=zipkin-server&v=LATEST&c=exec' |
如果用Docker的话,直接1
docker run -d -p 9411:9411 openzipkin/zipkin
可以配置的参数如下:
属性 | 环境变量 | 描述 |
---|---|---|
zipkin.collector.rabbitmq.concurrency | RABBIT_CONCURRENCY | 并发消费者数量,默认为1 |
zipkin.collector.rabbitmq.connection-timeout | RABBIT_CONNECTION_TIMEOUT | 建立连接时的超时时间,默认为 60000毫秒,即 1 分钟 |
zipkin.collector.rabbitmq.queue | RABBIT_QUEUE | 从中获取 span 信息的队列,默认为 zipkin |
zipkin.collector.rabbitmq.uri | RABBIT_URI | 符合 RabbitMQ URI 规范 的 URI,例如amqp://user:pass@host:10000/vhost |
如果设置了 URI,则以下属性将被忽略。
属性 | 环境变量 | 描述 |
---|---|---|
zipkin.collector.rabbitmq.addresses | RABBIT_ADDRESSES | 用逗号分隔的 RabbitMQ 地址列表,例如localhost:5672,localhost:5673 |
zipkin.collector.rabbitmq.password | RABBIT_PASSWORD | 连接到 RabbitMQ 时使用的密码,默认为 guest |
zipkin.collector.rabbitmq.username | RABBIT_USER | 连接到 RabbitMQ 时使用的用户名,默认为guest |
zipkin.collector.rabbitmq.virtual-host | RABBIT_VIRTUAL_HOST | 使用的 RabbitMQ virtual host,默认为 / |
zipkin.collector.rabbitmq.use-ssl | RABBIT_USE_SSL | 设置为true则用 SSL 的方式与 RabbitMQ 建立链接 |
服务接入
因为采用的消息总线rabbitmq方式,zipkin宕机的话,相应的链路的信息会在队列中存放,重启后又会消费掉。
在对应微服务的pom增加依赖:1
2
3
4
5
6
7
8
9
10
11
12
13
14<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
然后增加对应的配置:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23spring:
application:
name: login
cloud:
bus:
trace:
enabled: true
stream:
default-binder: rabbit
zipkin:
#base-url: http://localhost:9411
sender:
type: rabbit
sleuth:
web:
client:
enabled: true
sampler:
probability: 1.0 # 采样比例设置为1.0也就是全部都需要。
rabbitmq:
host: 127.0.0.1
username: admin
password: admin
这样就配置完成了,触发请求,可以得到服务间调用的链路,耗时等信息。
服务重试机制
微服务架构下会衍生出非常多的服务调用,而在一些极端网络情况下,会出现服务调用超时或者失败等,这时候我们就需要加入服务重试机制,来保证好的用户体验。
需要引入的依赖:1
2
3
4
5
6
7
8
9<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
然后对应的配置文件:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18feign:
hystrix:
enabled: true
hystrix:
command:
default:
execution:
timeout:
enabled: true
isolation:
thread:
timeoutInMilliseconds: 7000
ribbon:
ConnectTimeout: 5000 # 请求连接的超时时间
ReadTimeout: 5000 # 请求处理的超时时间
MaxAutoRetries: 1 # 对当前实例的重试次数
MaxAutoRetriesNextServer: 2 # 切换实例的重试次数
OkToRetryOnAllOperations: true # 对所有操作请求都进行重试
需要注意点是:Hystrix的超时时间大于Ribbon的超时时间,否则Hystrix命令超时后,该命令直接熔断,重试机制就没有任何意义了。
另外MaxAutoRetries和MaxAutoRetriesNextServer这样的设置,最多请求次数会是 2*3=6次,根据业务特性,自行优化设置。
对于网关(zuul)来说,需要额外增加依赖:
1 | <dependency> |
配置稍微有些不同:1
2
3
4
5
6
7
8
9zuul:
retryable: true
sensitive-headers: # 传递原始的header信息到最终的微服务
ribbon:
ConnectTimeout: 500 # 请求连接的超时时间
ReadTimeout: 1000 # 请求处理的超时时间
MaxAutoRetries: 2 # 对当前实例的重试次数
MaxAutoRetriesNextServer: 1 # 切换实例的重试次数
OkToRetryOnAllOperations: true # 对所有操作请求都进行重试
需要加上retryable: true
JPA打印sql优化
因为平台使用的是jpa,而jpa不支持输出完整的sql,下面的方式通过依赖log4jdbc的方式可以实现。
需要引入的依赖:1
2
3
4
5<dependency>
<groupId>com.googlecode.log4jdbc</groupId>
<artifactId>log4jdbc</artifactId>
<version>1.2</version>
</dependency>
修改配置文件:1
2
3
4
5
6spring:
datasource:
url: jdbc:log4jdbc:postgresql://127.0.0.1:5432/shine
username: ${ymsg.datasource.username}
password: ${ymsg.datasource.password}
driver-class-name: net.sf.log4jdbc.DriverSpy
这样就可以实现输出完整的sql(包括占位符也能替换),因为输出的日志较多,通过logback进行过滤,具体的配置如下:1
2
3
4
5<logger name="jdbc.sqlonly" level="OFF" />
<logger name="jdbc.audit" level="OFF" />
<logger name="jdbc.resultset" level="OFF" />
<logger name="jdbc.connection" level="INFO" />
<logger name="jdbc.sqltiming" level="INFO" />
最后得到的效果就是:
2019-05-22 20:22:22.129 INFO shine [elastic-2] [jdbc.sqltiming] - select * from shine m where m.type = 1 order by m.create_time limit 5
{executed in 11 msec}
其中executed就是执行的时间,可以用来排查慢查询。