为什么
我们新JavaScript客户端应用程序会定期调用Grails后端的/health
端点来确定离线状态。 事情开始变得“有趣”。
我们免费获得此端点,因为Grails基于Spring Boot,而Spring Boot带有一个名为Spring Boot Actuator的子项目。
这给了我们许多端点 ,使我们可以监视我们的应用程序并与之交互,包括/health
返回健康信息。
因此,我们的JS客户端会检查它是否可以到达此/health
端点(每隔几秒钟执行一次),以确定用户是在线还是离线。 没什么好想的,以后我们可能会切换到仅使用Google主页之类的东西,但是现在可以了。
健康检查失败
在localhost
一切似乎都很好,但是一旦我有了Jenkins管道,最终在每次构建后将应用程序部署到测试服务器上,然后我们开始在那里验证应用程序,事情就变得很有趣了。
通常情况下,我们的通话情况非常好。
GET https://tst.example.com/health 200 ()
GET https://tst.example.com/health 200 ()
GET https://tst.example.com/health 200 ()
etc
每隔几秒钟,我们就会在Chrome Inspector中看到错误累积的情况。 运行状况检查将失败,并且HTTP状态代码503 Service unavailable
长时间503 Service unavailable
。
GET https://tst.example.com/health 503 ()
GET https://tst.example.com/health 503 ()
GET https://tst.example.com/health 503 ()
etc
过了一会儿,我们会再次接到好电话!
GET https://tst.example.com/health 200 ()
GET https://tst.example.com/health 200 ()
etc
这些失败请求的响应只是说
{"status":"DOWN"}
从设计上来说,这不是很描述。
我当然没有写任何healh指标自己会这样,为什么会“下降”?
经验丰富的Spring Booters知道它将在类路径上获取任何运行状况指示器,并且默认情况下带有一些。 实际使用的是一个谜,因为默认情况下,Spring Boot将该端点归类为“敏感”,因此不会向外界公开太多信息。
我必须通过设置以下设置来使运行状况检查更加“有趣”:
endpoints.health.sensitive: false
现在,手动调用端点即可显示竞争者!
{
"status":"DOWN",
"diskSpace":{
"status":"DOWN",
"total":8579448832,
"free":20480,
"threshold":10485760
},
"db":{
"status":"UP",
"database":"H2",
"hello":1
}
}
“关闭”的一般状态是(在本例中为2)现在明确列出的自动配置的运行状况指示器的汇总结果。
当我看到以下内容时,立即想到的是:
- 我为什么还没有去除H2
- 嘿,测试服务器上的磁盘空间已经用完了吗?
H2数据库是所有Grails应用程序中的默认依赖项,但是我们的应用程序不使用它-不在生产环境中也不用于测试-因此,我们一定要从依赖项中删除它。 不用担心。
关于磁盘空间,这是很好的DiskSpaceHealthIndicator
(实际上是自动配置的指示器的一部分 ),告诉我事情不健康 。
它的默认阈值为10485760字节或10 MB ,这是应该可用的最小磁盘空间。
而且……只有20 kb的可用空间? 总共8场演出。
那是一个相当低的数字
在最初的0.7秒内,我不相信健康指标,您能想象吗?
因此,我通过SSH进入测试服务器,以使用df
实用程序检查可用磁盘空间:
[Ted@server-01t ~]$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rhel-root 8.0G 8.0G 20K 100% /
...
是的,至少健康检查证明了事实的真相:实际上只剩下一小块空间。
我将其转给配置此机器的IT同事进行调查。 似乎早先的实验已经存在一些Java堆转储,占用了空间-有人告诉我将尽快将其删除。
最好也检查其他节点。
[Ted@server-02t ~]$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/mapper/rhel-root 8.0G 5.3G 2.8G 66% /
那里有足够的空间。
等一下? “其他节点?” 是的,我们有2个测试服务器01t
和02t
。
那时,我意识到:我看到的行为是由于负载tst.example.com
将请求转发到tst.example.com
到server-01t
或另一个server-02t
。 其中之一是磁盘空间不足,这说明该服务器上Grails应用程序的运行状况指示器显示“关闭”,从而导致HTTP 503。
当通过Chrome Inspector观察这些运行状况调用(这些请求由我们的JS客户端不断发出)时,只剩下一个小问题:为什么我们会有(有时50倍)“涨”( 200
),然后一连串的“跌” ”( 503
),然后看似随机?
负载平衡器应使我们“固定”在JS客户端首次发出请求的那个节点上,因为我们这样配置服务器。
如果负载tst.example.com
将每个请求 (发送给tst.example.com
)轮流发送给服务器1或2,我期望会有更多(随机)响应,例如“ up” , “ down” , “ down” , “ up” ,“ “向下” , “向上” , “向上” , “向下” , “向上” 。
好吧,在我观察此行为的窗口期间,似乎团队的其他成员仍在开发功能,并…推向Jenkins选择的Git,并将其部署到两台服务器上。 由于将应用程序串行重新部署到ech服务器,因此负载平衡器“看到”该应用程序在一台服务器上的不可用(具有足够的磁盘空间: “ up” , “ up” , “ up” , “ up” , “ up” ” )在部署期间将流量重定向到另一台服务器 (几乎没有磁盘空间: “关闭” , “关闭” , “关闭” ))…
…不久之后便用新的WAR更新,并再次在另一台服务器上结束请求(具有足够的磁盘空间: “ up” , “ up” , “ up” , “ up” , “ up” )。
再花3个小时浪费我的生命。 包括一些时间在这里记下这些东西(但我认为这是值得的)
学过的知识
了解你的过程
知道有一个负载均衡器和多个节点(以及它们如何工作)会有所帮助。 而且CI服务器不断将新版本部署到正在调查的环境中并没有帮助。 但是完全知道这确实有助于澄清观察到的行为。
了解您的框架的“明智”默认设置。
如果使用Grails 3和Spring Boot,请了解从类路径“自动配置”的内容 ,检查并确保它确实是您想要的 。
我们将摆脱H2并检查我们实际需要的运行状况指标,可能会完全禁用自动配置。 我们清理了导致堆满的Java堆转储。 我们已经再次确认Unix团队将监视操作系统,包括磁盘空间,以便至少不再需要DiskSpaceHealthIndicator
。
翻译自: https://www.javacodegeeks.com/2017/10/why-is-springs-health-down-down-up-up-up-and-down-again.html