Central Starter Probe
概述
Central Starter Probe 主要用于为应用提供探测入口,主要用于监控应用当前是否稳定可用。
使用 Kubernetes 部署应用时,Kubernetes 一般通过监探容器的进程来判断容器是否还在正常工作。但是有时候 Web 容器的进程还在,但是却无法再接受外部请求,此时应用可能更希望 Kubernetes 通过重启的方式让应用恢复正常。
本类库提供了轻量级的应用探测功能,通过简单的配置完成应用的探测功能。
集成
Maven 座标
<dependency>
<groupId>com.central-x</groupId>
<artifactId>central-starter-probe</artifactId>
<version>${centralx.version}</version>
</dependency>
启用探针服务
在应用启动类,或应用配置类中,添加 @EnableProbe
注解,启用探针服务。
import central.starter.probe.EnableProbe;
import org.springframework.context.annotation.Configuration;
/**
* 应用配置
*
* @author Alan Yeh
* @since 2023/12/29
*/
@EnableProbe
@Configuration
public class ApplicationConfiguration {
}
使用类库
全局配置
探针的配置信息存放在 central.probe
节点下。如果需要修改探针的配置,可以在 application.yml
配置文件中添加以下配置:
central:
probe:
# 动态禁用探针服务
enabled: true
# 探针超时时间
timeout: 5000
enabled
: 如果想在运行阶段停止探针服务,则可以通过该属性禁用探针服务;timeout
: 探针超时时间。探测时,所有的探测点(Endpoint)都是并发执行的,如果在超时时间结束前还未探测完毕,则直接中断探测,返回Timeout
。
探测点(Endpoint)
Central Starter Probe 通过控测点(Endpoint)执行探测任务。目前已提供以下几种探测点类型:
- 数据源探测点(DataSourceEndpoint): 使用 JDBC 连接到指定数据库,执行测试 Sql。如果无法连接到数据库,或测试 Sql 执行失败/未返回数据,则探测失败;
- Redis 探测点(RedisEndpoint): 使用 Lettuce 连接到指定数据库,执行 PING。如果无法连接到数据库,或未能返回 PONG 响应,则探测失败;
- 主机名探测(HostEndpoint): 测试主机名/域名是否能解析。如果主机名/域名无法解析成 IP,则探测失败;
- Http 探测(HttpEndpoint): 测试指定的接口地址是否能返回正确的信息。如果服务不能返回指定的状态码或指定的内容,则探测失败。
DataSourceEndpoint
DataSourceEndpoint 探测点主要用于探测应用是否能正常连接到数据库。为应用添加数据源探测点时,只需要在配置文件中添加以下配置信息:
central:
probe:
points:
- name: mySqlEndpoint
type: datasource
params:
driver: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://mysql:3306/centralx?useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: root
query: select 1
name
: 探测点标识,探针服务会将该探测点注册为 Spring Bean,因此注意该 name 不要和别的探测点或内部的 Bean 重名type
: 探测点类型params
: 探测点初始化参数params.driver
(required): jdbc 驱动params.url
(required): 数据库连接params.username
(required): 数据库用户名params.password
(required): 数据库密码params.query
(optional): 检测 Sql。该 Sql 必须能返回至少一行数据,则否探测失败。如果本字段为空,则数据源探测点自动根据数据库类型选择合适的检测 Sql。
DataSourceEndpoint 目前已支持 MySql、PostgreSql、Oracle、人大金仓(Kingbase)、神舟(Oscar)、H2、海量数据(Vastbase)、达梦(Dameng)、翰高(HighGo)。
RedisEndpoint
RedisEndpoint 探测点主要用于探测应用是否能正常连接到 Redis 数据库。为应用添加 Redis 探测点时,只需要在配置文件中添加以下配置信息:
central:
probe:
points:
- name: redisEndpoint
type: redis
params:
host: 127.0.0.1
port: 6379
username: root
password: root
name
: 探测点标识,探针服务会将该探测点注册为 Spring Bean,因此注意该 name 不要和别的探测点或内部的 Bean 重名type
: 探测点类型params
: 探测点初始化参数params.host
(required): Redis 主机地址params.port
(required): Redis 服务端口params.username
(optional): 用户名。如果用户名不为空时,则密码必须不为空,否则用户名将不起效params.password
(optional): 密码。密码不为空时,用户名可以为空
HostEndpoint
HostEndpoint 探测点主要用于探测主机名/域名是否可以正常解析。注意,主机名探测点只检测主机名是否可以解析,不检测主机是否可达(Reachable)。为应用添加主机名探测点时,只需要在配置文件中添加以下配置信息:
central:
probe:
points:
- name: providerHostEndpoint
type: host
params:
host: central-provider
name
: 探测点标识,探针服务会将该探测点注册为 Spring Bean,因此注意该 name 不要和别的探测点或内部的 Bean 重名type
: 探测点类型params
: 探测点初始化参数params.host
(required): 主机名/域名
HttpEndpoint
HttpEndpoint 探测点主要用于通过调用接口的方式探测应用依赖的其它服务是否可用。为应用添加 Http 探测点时,只需要在配置文件中添加以下配置信息:
central:
probe:
points:
- name: githubGraphqlEndpoing
type: http
params:
method: post
url: https://api.github.com/graphql
headers:
- name: X-Forwarded-Tenant
value: test
expects:
status: [200, 401]
content: |
{"message": "API rate limit exceeded for 50.7.158.106. (But here's the good news: Authenticated requests get a higher rate limit. Check out the documentation for more details.)",
"documentation_url": "https://docs.github.com/rest/overview/resources-in-the-rest-api#rate-limiting"}
name
: 探测点标识,探针服务会将该探测点注册为 Spring Bean,因此注意该 name 不要和别的探测点或内部的 Bean 重名type
: 探测点类型params
: 探测点初始化参数params.method
(optional): 请求方法。如果不设置该参数时,默认为GET
params.url
(required): 请求地址params.headers
(optional): 请求头params.headers.name
(required): 请求头名params.headers.value
(required): 请求头值params.expects
(optional): 响应期望params.expects.status
(optional): 期望响应状态码。如果是字符串时,可以使用OK
代表 200 ~ 299 的状态码。如果是数组的话,则可以列出可接受的状态码值。params.expects.content
(optional): 期望响应体。如果是 Json(对象或数组),且请求响应的 ContentType 是application/json
时,将自动匹配内容是否相等,忽略内容的顺序。其它情况直接判断两者是否相等。
提示
匹配内容是否相等,表示在以下情况时,两者是相等的:
{"name": "alan", "age": 18}
与{"age": 18, "name": "alan"}
两者是相同的["alan", "alex", "alvin"]
与["alvin", "alex", "alan"]
两者是相同的
鉴权
由于探针可能会泄露应用内部运行状态,因此建议为探针开启鉴权功能。开启鉴权功能后,调用方必须在请求头(Request Header)Authorization
上提供相关鉴权凭证才可以正常调用探针服务。鉴权失败时,探针将直接返回 403 Forbidden
状态码。
Central Starter Probe 内置了两种鉴权机制:
- JwtAuthorizer: 使用 JWT(Json Web Token)提供鉴权信息。该鉴权方式安全性较高,但对调用方有一定要求,需要调用方可以根据密钥动态生成 JWT;
- FixedAuthorizer: 使用固定的鉴权字符串。该鉴权方式安全性相对较低,只要提供了指定字符串即可满足鉴权要求。
JwtAuthorizer
JwtAuthorizer 采用动态 JWT 来对调用方进行鉴权。开启 JwtAuthorizer 鉴权只需要在配置文件中添加以下配置信息:
central:
probe:
authorizer:
type: jwt
params:
algorithm: HMAC256
secret: cZlUdvgXkIEViQagLnPkgvxRXenisjZP
claims:
iss: com.central-x
type
: 鉴权类型params
: 鉴权初始化参数params.algorithm
(required): 签名算法。支持HMAC256
、HMAC384
、HMAC512
、ECDSA256
、ECDSA384
、ECDSA512
、RSA256
、RSA384
、RSA512
。一般情况下,建议选用HMAC256
或ECDSA256
。params.secret
(required): 签名密钥。不同签名算法对签名密钥有不同要求,ECDSA
、RSA
的公钥要求使用 Base64 字符串提供。params.claims
(optional): 声明(Claim)。要求 JWT 必须提供指定值的声明。使用键值对的方式表示。如果值为null
、""
,则表示只需要出现该声明,但不校验该声明的值。
FixedAuthorizer
FixedAuthorizer 采用静态密钥的方式对调用方进行鉴权。开启 FixedAuthorizer 鉴权只需要在配置文件中添加以下配置信息:
central:
probe:
authorizer:
type: fixed
params:
secret: yVynEftqCbCbIeVMXqVsGsNGztnbvOwcZZYmsQFXckaNnkVwTKbXiqHdRhEdmWWO
type
: 鉴权类型params
: 鉴权初始化参数params.secret
(required): 鉴权密钥
提示
由于 FixedAuthorizer 是采用静态密钥的方式鉴权,因此建议鉴权密钥的长度不要设置得过短(如设置 64 位随机字符串),提高破解难度。
缓存
正常情况下探测接口返回的数据,因为这样有可能会导致无法正常探测应用真实的运行情况。
但是在一些情况下,探针间可能产生依赖,如在 Central Studio[链接]中,Gateway、Identity、Storage、Multicast、Storage 等都必须在 Provider 存活的情况下才能正常运行,因此这些应用的探针会去探测 Provider 是否存活,也就是这些应用的探针会探测 Provider 的探针(通过 HttpEndpoint),这就导致了 Provider 的探针在高频率的探测下工作,继而产生不良后果。
为了解决这个问题,可以在 Provider 中启用探测缓存,在缓存失效前产生的探测行为都将返回上一次探测结果,这样就可以大大降低 Provider 的探测压力了。但是在设置缓存有效期时,需要注意的是该。如 Kubernetes 的探测间隔如果是 10s 的话,那么 Provider 的缓存失效时间可以设置为 9s,这样就可以保证 Provider 自身的探测都是有效且真实的。
开启探针缓存只需要在配置文件中添加以下配置信息:
central:
probe:
cache:
enabled: true
timeout: 9000
enabled
: 启用探针缓存功能。默认为 false。timeout
: 缓存有效期(毫秒)
技巧
在配置数据源探测点(DataSourceEndpoint)或 Redis 探测点(RedisEndpoint)时,需要提供连接信息,这些信息一般与对应的数据源配置或 Redis 配置是相同的,这样就导致我们需要配置两次。如果后续需要修改配置时,容易出现修改漏的问题。因此可以通过 Spring 的占位符来解决这个问题,如:
# Spring 数据源配置
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://mysql:3306/centralx?useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: <password>
# 探测配置
central:
probe:
points:
- name: dataSourceEndpoint
type: datasource
params:
# 通过 Spring 占位符的方式引用数据源配置
driver: ${spring.datasource.driver-class-name}
url: ${spring.datasource.url}
username: ${spring.datasource.username}
password: ${spring.datasource.password}