怕刺 - aapanel
type: channel
link: https://pa.ci/tag/aapanel/
items: 宝塔面板的0点CPU高占用bug解疑（二）
items: 宝塔面板的0点CPU高占用bug解疑（一）

宝塔面板的0点CPU高占用bug解疑（二）
type: item
date: 2022-06-10T12:14:14+00:00
description: 前情提要请看：宝塔面板的0点CPU高占用bug解疑（一），以下内容来源于hostloc的flyqie，原帖地址为：https://hostloc.com/thread-1030797-1-1.html本人测试环境: Bt-Panel 7.7.0, Debian10 amd64经查看本地/www/server/panel目录下的面板代码以及与老哥交流(原帖子回复), 确认原帖老哥拿到的代码并非宝塔目前主版本代码(可能是开发版)。[注：此处“老哥”为本人，原帖在hostloc中发帖并交流]分析宝塔目前主版本代码会执行/www/server/panel/BT-Task作为BT-Task service。在/www/server/panel/BT-Task引入了 /www/server/panel/task.py并执行其中的main函数。在task.py中，main函数中会开启多个线程去调用其他任务, 最后主进程交由startTask函数进行处理。startTask是个死循环函数, 它会先执行从面板数据库中拿取的任务, 之后调用siteEdate函数进行网站到期处理。siteEdate 函数正常来说应该在一天内只执行一次/www/server/panel/script/site_task.py，但是很不幸宝塔程序员逻辑写错了:def siteEdate(): global oldEdate try: # 程序拿到的永远是启动时候/www/server/panel/data/edate.pl的值, 第二次执行时候虽然oldEdate不为空, 但是/www/server/panel/data/edate.pl已经发生变化了, 没有去更新 # 两种解决方法, 删掉oldEdate判断或者在函数结束后将oldEdate手动置空 if not oldEdate: oldEdate = ReadFile('/www/server/panel/data/edate.pl') if not oldEdate: oldEdate = '0000-00-00' mEdate = time.strftime('%Y-%m-%d', time.localtime()) if oldEdate == mEdate: return False os.system(get_python_bin() + " /www/server/panel/script/site_task.py > /dev/null") except Exception as ex: logging.info(ex) pass这将会导致在第一次执行后, 每次调用siteEdate函数时都会继续执行/www/server/panel/script/site_task.py。更糟糕的是，/www/server/panel/script/site_task.py中似乎也没有对此做处理(判断时间), 也就是说site_task.py会不断执行一系列没有必要的检测。修复建议官方尽快解决, 目前可用临时修复补丁进行修复，但不保证完全可靠(补丁基于7.7.0并且未经过长期及生产环境测试), 建议谨慎使用。diff -uN old/task.py new/task.py --- old/task.py 2022-06-10 13:13:00.107691400 +0800 +++ new/task.py 2022-06-10 13:17:52.807987000 +0800 @@ -158,8 +158,7 @@ def siteEdate(): global oldEdate try: - if not oldEdate: - oldEdate = ReadFile('/www/server/panel/data/edate.pl') + oldEdate = ReadFile('/www/server/panel/data/edate.pl') if not oldEdate: oldEdate = '0000-00-00' mEdate = time.strftime('%Y-%m-%d', time.localtime())

宝塔面板的0点CPU高占用bug解疑（一）
type: item
date: 2022-06-10T02:53:00+00:00
description: 宝塔面板在最近两年，有个很奇怪的bug，具体表现为一旦过了0点，CPU使用率就会突然上去，并且一直下不来。可以考证的最早记录是2021年1月份pc6a写下的。具体情况如下图，在初始安装完成后，CPU的负载很低，表现一切正常。一旦过了0点，CPU使用率瞬间上去了。通过htop查看，占用CPU最高的是site_task.py，这个程序本身是系统的日志上报功能模块。但是每10秒钟就会出现一次，每次出现就极大的提高了CPU使用率，显得极其诡异。要不是因为能看到源码，一定会判定它是木马，实际上这个程序并不复杂，因此大概率是个逻辑错误或者程序员水平低下导致的bug。我使用的是Debian 11系统进行测试的，在腾讯云上有一篇记录，是在CentOS 7上测试出相同现象的。这说明了和系统本身相关性不大。宝塔面板的源码是开放的，于是在GitHub上下载了下来，搜索和site_task相关的内容。最终发现了site_task.py是通过bt-task.c这个文件调用/www/server/panel/pyenv/bin/python3 /www/server/panel/script/site_task.py而运行起来的。注释里面写的是“网站到期时间处理”，有一个while true的死循环，每个小时执行一次。仔细查看代码内容，发现这个循环中涉及到了日期更改。程序首先读取文件中的日期，判断和目前日期是否相同，如果相同就会睡眠一个小时。此外还有个将文件日期更改的功能，由于宝塔的代码稀烂，很难捋顺它的程序，我就不去细查了。此外，“重新标记执行日期并执行到期网站脚本”这里好像是缺了一个判断，它这种写法会导致频繁读写硬盘，降低运行效率。言归正传，0点CPU高占用bug大概率就是这个模块导致的了，涉及到日期更改和site_task.py程序。出于某种原因（比如程序员水平稀烂）导致了逻辑错误，最终造成一旦日期更改了，面板就不知道要做什么，然后疯狂进行10秒一次循环。这种好几年的bug居然都没有发现，只能说宝塔的水平是极其差的。临时的解决方法是设置定时任务，每天0点重启一次面板。终端输入crontab -e，然后写入2 0 * * * /etc/init.d/bt restart，即每天0点2分的时候重启一次面板，让日期归零，从而避开这个bug。我有点怀疑这个bug可能和Let's Encrypt的SSL证书申请有关，好像是在我全部使用第三方SSL证书之后才发现这个bug的。具体的表现可能是如果面板没有Let's Encrypt的SSL证书申请任务，那么就会出现这个bug，具体是不是我还在尝试中。