vscode 服务器

我一直挺喜欢vscode的ssh功能的,因为它可以加载文件目录,可以像用vscode本地编辑器一样对服务器文件进行操作,创建/移动/修改/删除文件都很方便。

而我为了图个方便,经常用vscode ssh到根目录,造成的结果就是:因为vscode会扫描节点下所有的文件,而我的服务器只是个4核的小服务器,直接把我cpu占满了

今天下午又因为这个原因把服务器崩了20分钟左右,当时ssh也连不上、宝塔也打不开,我还以为又得还原备份了,幸好后来又可以连上了

python 脚本

用python整了个针对vscode服务器资源占用的脚本,如果4个cpu的占用率达到90%以上超过5分钟,就执行pkill -f vscode-server杀掉vscode服务器进程,脚本创建在 /usr/local/bin/monitor_vscode.py

import psutil
import time
import subprocess
import sys
from collections import deque

# --- 配置参数 ---
CPU_THRESHOLD_PER_CORE = 90 # 单个CPU核心占用百分比阈值
HIGH_CPU_CORE_COUNT = 4 # 达到阈值的CPU核心数量
DURATION_THRESHOLD_MINUTES = 5 # 持续时间阈值(分钟)

CHECK_INTERVAL = 10 # 检查间隔(秒)
PROCESS_NAME_PARTIAL = "vscode-server" # 匹配的进程名部分
KILL_COMMAND = "pkill -f vscode-server" # 要执行的杀死命令

# --- 日志文件配置 ---
LOG_FILE = "/tmp/vscode_monitor.log" # 日志文件路径,可以根据需要修改
ENABLE_LOGGING = True # 是否启用日志

# --- 全局变量 ---
# 存储最近一段时间内,是否满足“4个CPU达到90%”的布尔值
# 队列的长度将决定我们需要多少个检查周期来达到持续时间阈值
# 队列长度 = (DURATION_THRESHOLD_MINUTES * 60) // CHECK_INTERVAL
cpu_history = deque(maxlen=(DURATION_THRESHOLD_MINUTES * 60) // CHECK_INTERVAL)

def log_message(message):
"""记录消息到控制台和日志文件"""
timestamp = time.strftime("%Y-%m-%d %H:%M:%S")
full_message = f"[{timestamp}] {message}"
print(full_message)
if ENABLE_LOGGING and LOG_FILE:
try:
with open(LOG_FILE, "a") as f:
f.write(full_message + "\n")
except IOError as e:
print(f"Error writing to log file {LOG_FILE}: {e}")

def get_vscode_server_processes():
"""获取所有匹配 vscode-server 的进程"""
vscode_processes = []
for proc in psutil.process_iter(['pid', 'name', 'cpu_percent', 'cmdline', 'username']):
try:
cmdline_str = " ".join(proc.info['cmdline'])
if PROCESS_NAME_PARTIAL in proc.info['name'] or PROCESS_NAME_PARTIAL in cmdline_str:
if sys.argv[0] not in cmdline_str: # 排除本脚本自身
vscode_processes.append(proc)
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
continue
return vscode_processes

def main():
log_message(f"VS Code 资源监控程序启动。")
log_message(f"触发条件: {HIGH_CPU_CORE_COUNT} 个CPU核心占用超过 {CPU_THRESHOLD_PER_CORE}% 持续 {DURATION_THRESHOLD_MINUTES} 分钟。")
log_message(f"检查间隔: {CHECK_INTERVAL}秒。")
log_message(f"监控进程名称包含: '{PROCESS_NAME_PARTIAL}'")
log_message(f"触发时执行命令: '{KILL_COMMAND}'")
if ENABLE_LOGGING:
log_message(f"日志将记录到: {LOG_FILE}")

# 确保队列的初始状态是 False,直到有足够的数据
# 填充队列,使其达到最大长度,避免在程序启动之初就触发
for _ in range(cpu_history.maxlen):
cpu_history.append(False)

while True:
try:
# 获取每个CPU核心的占用率
# interval=None 会返回自上次调用psutil.cpu_percent()以来的CPU使用率
# 第一次调用时需要等待一个interval,所以这里我们直接获取
# 也可以使用 interval=CHECK_INTERVAL 来确保每次获取都是一个新周期的数据
current_cpu_percents = psutil.cpu_percent(interval=CHECK_INTERVAL, percpu=True)
num_high_cpu_cores = 0
cpu_info_str = []

for i, percent in enumerate(current_cpu_percents):
cpu_info_str.append(f"CPU{i}: {percent:.2f}%")
if percent > CPU_THRESHOLD_PER_CORE:
num_high_cpu_cores += 1

log_message(f"当前CPU核心占用: {', '.join(cpu_info_str)}")
log_message(f"当前有 {num_high_cpu_cores} 个CPU核心占用超过 {CPU_THRESHOLD_PER_CORE}%。")

# 判断当前检查是否满足高CPU核心数量的条件
current_condition_met = (num_high_cpu_cores >= HIGH_CPU_CORE_COUNT)
cpu_history.append(current_condition_met)

# 检查历史记录,判断是否持续满足条件
# 如果队列中所有元素都为 True,则表示条件持续满足
if all(cpu_history):
log_message(f"!!! 警告: 连续 {DURATION_THRESHOLD_MINUTES} 分钟有 {HIGH_CPU_CORE_COUNT} 个或更多CPU核心占用超过 {CPU_THRESHOLD_PER_CORE}%。")
log_message(f"正在执行命令: '{KILL_COMMAND}'")
try:
result = subprocess.run(KILL_COMMAND, shell=True, capture_output=True, text=True)
if result.returncode == 0:
log_message("命令执行成功。")
# 杀死进程后,重置历史记录,避免立即再次触发
cpu_history.clear()
for _ in range(cpu_history.maxlen):
cpu_history.append(False)
else:
log_message(f"命令执行失败 (返回码: {result.returncode})。错误输出: {result.stderr.strip()}")
except Exception as e:
log_message(f"执行命令时发生错误: {e}")
else:
log_message("CPU 占用在正常范围内或未持续达到阈值。")

# 检查 VS Code Server 进程是否存在,只是为了日志记录,不影响触发逻辑
processes = get_vscode_server_processes()
if not processes:
log_message("未检测到 VS Code Server 进程。")
else:
active_pids = [proc.info['pid'] for proc in processes]
log_message(f"检测到 {len(processes)} 个 VS Code Server 进程 (PIDs: {active_pids})。")


except Exception as e:
log_message(f"监控过程中发生未知错误: {e}")

# 每次循环结束后,等待下一个检查间隔
# psutil.cpu_percent(interval=CHECK_INTERVAL) 已经包含了等待时间
# 所以这里不需要额外的 time.sleep()
pass

if __name__ == "__main__":
main()

之后用systemd服务后台运行,创建 /etc/systemd/system/vscode-monitor.service 输入:

[Unit]
Description=VS Code CPU Monitor Service
After=network.target

[Service]
User=root
Group=root

# WorkingDirectory 是服务启动时的工作目录
WorkingDirectory=/usr/local/bin/

# ExecStart 定义如何启动服务
# 确保 python3 是系统上 python 的路径
# 可以用 'which python3' 或 'which python' 来查找
ExecStart=/usr/bin/python3 /usr/local/bin/monitor_vscode.py

# Restart=always 表示服务崩溃或退出时总是尝试重启
Restart=always
# RestartSec=5s 表示在重启前等待 5 秒
RestartSec=5s

# StandardOutput 和 StandardError 控制服务的输出
# 这里将输出重定向到 syslog,可以通过 journalctl 查看
StandardOutput=syslog
StandardError=syslog
SyslogIdentifier=vscode-monitor

[Install]
WantedBy=multi-user.target

记得在python内核的环境中 pip install psutil,我这里图方便就直接在全局了

之后让 systemd 重新加载其配置:

sudo systemctl daemon-reload
sudo systemctl start vscode-monitor.service
sudo systemctl status vscode-monitor.service

查看记录脚本检测记录:

tail -f /tmp/vscode_monitor.log

启用开机自启:

sudo systemctl enable vscode-monitor.service

停止服务:

sudo systemctl stop vscode-monitor.service

禁用服务,停止开机自启:

sudo systemctl disable vscode-monitor.service

后记

所以用vscode服务器最好的方式是ssh到一个内层的目录,这样服务器压力小一点

但有没有其他好用的、资源占用率低的、文件修改操作方便的ssh软件啊,哭了