“宠辱若惊,贵大患若身。
何谓宠辱若惊?
宠为下。
得之若惊,失之若惊,是谓宠辱若惊。
何谓贵大患若身?
吾所以有大患者,为吾有身。
及吾无身,吾有何患?
故贵以身为天下,若可以寄于天下,爱以身为天下者,若可托天下。”1
SpringCloud服务优雅启停的打开方式
The marvel’s service UP and DOWN in elegant model
问题:
1.服务已经发布,在eureka上已经看到注册成功了,但是服务调用方在调用服务时,依然调不到。
2.发布服务时,不能粗暴的kill或者重新部署,由于服务提供方并不支持幂等请求,所以粗暴的方式无可避免导致请求的异常,因此平台要支持服务优雅的上下线。
解决:
对于问题1:
EurekaServer有两个缓存机制:
- ReadWriteMap: 当服务注册或者维持心跳时,更新。
- ReadOnlyMap: 当有服务调用者查询服务列表时,访问。
解决方案:
EurekaServer: marvel-eureka-dev[test].yml
1 | #eureka server刷新readCacheMap的时间,注意,client读取的是readCacheMap,这个时间决定了多久会把readWriteCacheMap的缓存更新到readCacheMap上 |
2 | #默认30s |
3 | eureka.server.responseCacheUpdateIntervalMs=3000 |
4 | #eureka server缓存readWriteCacheMap失效时间,这个只有在这个时间过去后缓存才会失效,失效前不会更新,过期后从registry重新读取注册服务信息,registry是一个ConcurrentHashMap。 |
5 | #由于启用了evict其实就用不太上改这个配置了 |
6 | #默认180s |
7 | eureka.server.responseCacheAutoExpirationInSeconds=180 |
8 | |
9 | #启用主动失效,并且每次主动失效检测间隔为3s |
10 | eureka.server.eviction-interval-timer-in-ms=3000 |
Client:marvel-eureka-client-dev[test].yml
1 | #服务过期时间配置,超过这个时间没有接收到心跳EurekaServer就会将这个实例剔除 |
2 | #注意,EurekaServer一定要设置eureka.server.eviction-interval-timer-in-ms否则这个配置无效,这个配置一般为服务刷新时间配置的三倍 |
3 | #默认90s |
4 | eureka.instance.lease-expiration-duration-in-seconds=15 |
5 | #服务刷新时间配置,每隔这个时间会主动心跳一次 |
6 | #默认30s |
7 | eureka.instance.lease-renewal-interval-in-seconds=5 |
8 | |
9 | |
10 | #eureka client刷新本地缓存时间 |
11 | #默认30s |
12 | eureka.client.registryFetchIntervalSeconds=5 |
13 | #eureka客户端ribbon刷新时间 |
14 | #默认30s |
15 | ribbon.ServerListRefreshInterval=5000 |
对于问题2:
需要整合actuator,在marvel-client-eureka-dev[test].yml已经整合:
1 | management: |
2 | endpoint: |
3 | health: |
4 | show-details: always |
5 | endpoints: |
6 | web: |
7 | exposure: |
8 | include: '*' |
各个项目在启动的时候,可以看到控制台有如下输出:
1 | 2019-06-24 14:18:36.810 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/archaius],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
2 | 2019-06-24 14:18:36.811 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/auditevents],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
3 | 2019-06-24 14:18:36.811 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/beans],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
4 | 2019-06-24 14:18:36.812 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/health],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
5 | 2019-06-24 14:18:36.812 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/conditions],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
6 | 2019-06-24 14:18:36.812 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/configprops],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
7 | 2019-06-24 14:18:36.812 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/env],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
8 | 2019-06-24 14:18:36.813 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/env/{toMatch}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
9 | 2019-06-24 14:18:36.813 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/env],methods=[POST],consumes=[application/vnd.spring-boot.actuator.v2+json || application/json],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
10 | 2019-06-24 14:18:36.814 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/env],methods=[DELETE],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
11 | 2019-06-24 14:18:36.814 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/info],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
12 | 2019-06-24 14:18:36.814 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/logfile],methods=[GET],produces=[application/octet-stream]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
13 | 2019-06-24 14:18:36.814 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/loggers],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
14 | 2019-06-24 14:18:36.815 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/loggers/{name}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
15 | 2019-06-24 14:18:36.815 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/loggers/{name}],methods=[POST],consumes=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
16 | 2019-06-24 14:18:36.815 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/heapdump],methods=[GET],produces=[application/octet-stream]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
17 | 2019-06-24 14:18:36.815 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/threaddump],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
18 | 2019-06-24 14:18:36.816 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/metrics/{requiredMetricName}],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
19 | 2019-06-24 14:18:36.816 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/metrics],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
20 | 2019-06-24 14:18:36.816 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/scheduledtasks],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
21 | 2019-06-24 14:18:36.817 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/httptrace],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
22 | 2019-06-24 14:18:36.817 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/mappings],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
23 | 2019-06-24 14:18:36.817 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/refresh],methods=[POST],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
24 | 2019-06-24 14:18:36.817 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/features],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
25 | 2019-06-24 14:18:36.818 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/service-registry],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
26 | 2019-06-24 14:18:36.818 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator/service-registry],methods=[POST],consumes=[application/vnd.spring-boot.actuator.v2+json || application/json],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto public java.lang.Object org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(javax.servlet.http.HttpServletRequest,java.util.Map<java.lang.String, java.lang.String>) |
27 | 2019-06-24 14:18:36.819 [main] INFO o.s.b.a.e.w.s.WebMvcEndpointHandlerMapping - 547 : Mapped "{[/actuator],methods=[GET],produces=[application/vnd.spring-boot.actuator.v2+json || application/json]}" onto protected java.util.Map<java.lang.String, java.util.Map<java.lang.String, org.springframework.boot.actuate.endpoint.web.Link>> org.springframework.boot.actuate.endpoint.web.servlet.WebMvcEndpointHandlerMapping.links(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) |
其中:/actuator/service-registry 通过GET请求可以查看服务的状态,通过POST可以设置服务的状态 UP or Down
当设置服务的状态为DOWN时即优雅的关闭(下线)了该服务,查看eureka控制台时,此服务即已下线,通过观察服务的log,当没有任何请求log时可以对服务进行重新发布。
注意:如采用这种方式,请做好api的权限控制,否则:(。
关于Actuator的详细知识,可以点击查看这篇博客,讲的很详细了。
1:老子《道德经》第九章,老子故里,中国鹿邑。