使用Python脚本防止系统休眠与锁屏

什么是pyautogui?

pyautogui 是一个跨平台的Python库,允许开发者通过代码控制鼠标、键盘以及进行屏幕图像识别。它用简单的语法模拟人类对计算机的操作,适合快速实现轻量级自动化任务,比如防止系统休眠、批量处理重复操作等。

核心功能速览

  1. 鼠标控制
    • 移动光标:moveTo(x, y)
    • 点击操作:click()
    • 拖动对象:dragTo(x, y)
    • 实时获取光标位置:position()
  2. 键盘操作
    • 输入文本:typewrite("Hello!")
    • 单次按键:press('enter')
    • 组合快捷键:hotkey('ctrl', 'c')
  3. 屏幕交互
    • 截图保存:screenshot('screen.png')
    • 图像定位:locateOnScreen('button.png') (通过图像匹配坐标)

如下:

import time
import pyautogui

def main():
    MAX_RUNTIME = 3600 * 8  # 8小时自动停止
    start_time = time.time()
    while time.time() - start_time < MAX_RUNTIME:
        pyautogui.moveRel(1,1)
        # pyautogui.press('press')
        pyautogui.press('esc',interval=0.5)
        pyautogui.scroll(1)
        pyautogui.hotkey('ctrl','f')
        current_time = time.strftime("%Y-%m-%d %H:%M:%S")
        print(f"移动:{current_time}")
        time.sleep(100)

if __name__=="__main__":
    main()

把 Windows 的 bat 文件固定在任务栏

我用常规方式无法将.bat脚本快捷方式固定到Windows任务栏。这里介绍通过伪装资源管理器进程绕过限制。

步骤

1. 创建特殊快捷方式

# 右键桌面 → 新建快捷方式 → 输入:
explorer.exe "D:\scripts\your_script.bat"

2. 固定到任务栏

  • 拖动该快捷方式至任务栏
  • 系统将识别为文件资源管理器项而非脚本

技术原理

  • explorer.exe代理执行:通过资源管理器宿主进程加载脚本,规避控制台进程限制
  • 任务栏缓存机制:系统仅校验首次固定时的宿主程序(explorer.exe)

注意事项

  • 路径含空格时必须用英文引号包裹

Python Selenium 忽略 HTTPS 证书错误

Chrome

通过 ChromeOptions 添加启动参数直接忽略证书验证:

from selenium import webdriver

options = webdriver.ChromeOptions()
options.add_argument('--ignore-certificate-errors')  

driver = webdriver.Chrome(options=options)
driver.get("https://expired.badssl.com") 

Firefox

设置 accept_insecure_certs 属性为 True

from selenium import webdriver

options = webdriver.FirefoxOptions()
options.accept_insecure_certs = True  

driver = webdriver.Firefox(options=options)
driver.get("https://self-signed.badssl.com")  

Prometheus调优:干掉高基数和慢查询

运维不是请客吃饭,Prometheus调优就得快准狠。今天记录我调优的一点内容。

一、PromQL优化三斧头

  1. 砍掉无用计算
    • 所有查询必须带标签过滤,别让Prometheus扫全表
      # 烂代码
      sum(rate(http_requests_total[5m])) 
      # 正确姿势
      sum(rate(http_requests_total{cluster="prod",service!~"test-.*"}[5m]))
      
  2. 预计算
    • 高频查询全做成 Recording Rules ```yaml

      prometheus.yml 配置示例

    • record: service:http_errors:rate5m expr: sum(rate(http_requests_total{status=~”5..”}[5m])) by (service) ```
  3. 函数选型要精准
    • 拒绝count()滥用,数值计算只用sum()
    • rate()irate()的区别:前者看趋势,后者抓毛刺

二、高基数指标

什么是高基数?

  • 一个指标标签组合超过500个时间序列就是高基数
  • 典型案例:把user_id当标签。

当某个标签的值具备以下特征时,就会引发高基数

  1. 动态生成:如用户ID、SessionID、TraceID、IP地址
  2. 不可预测数量:如错误信息error_message(可能无限增长)
  3. 高唯一性:如订单号、UUID

用这个PromQL量化风险:

# 直接找出Top10问题指标
topk(10, count by (__name__)({__name__=~".+"}))

# 查看单个指标的时间序列数量
count({__name__="your_metric_name"})

# 按标签维度分析
count by (label_name)({__name__="your_metric_name"})

风险阈值参考(根据集群规模调整)

时间序列数量 风险等级 处理建议
< 500 安全 无需处理
500-2000 警告 监控增长趋势
> 2000 危险 必须立即优化标签设计

tips:

  1. 动态标签死刑名单 永远不要用作指标标签

    user_id, ip, session_id, trace_id, request_id, 
    order_no, email, phone, uuid, error_message
    
  2. 安全标签范例 这些标签值可控,放心使用:

    status_code(如200/404/500), 
    http_method(GET/POST), 
    env(prod/stage/dev), 
    region(固定机房编号)
    
  3. 紧急止血方案 发现高基数指标后立即执行:

    # prometheus.yml 配置
    metric_relabel_configs:
      - source_labels: [user_id]  # 要清理的标签
        regex: (.+)
        action: labeldrop        # 直接丢弃该标签
    

三、性能监控三板斧

  1. 内存防线
    # 当内存突破16GB立即告警
    prometheus_tsdb_head_series > 10000000
    
  2. 慢查询追杀令
    # 查询延迟超过2秒的全给我记下来
    rate(prometheus_engine_query_duration_seconds_sum{slice="query"}[1m]) > 2
    
  3. 存储健康检查
    # 直接分析TSDB状态
    promtool tsdb analyze /data/prometheus/wal
    

四、巡检

  • 每周必查topk(10, count by (__name__)({__name__=~".+"}))
  • 发现高基数指标,24小时内必须解决
  • 查询超过1秒的统统优化

多维度优化降低Prometheus资源消耗的实践

最近在玩 Prometheus ,我在grafana上使用了以下PromQL查询:

sum by (user) (
  rate(iftop_traffic_bytes_total{direction="send",user!=""}[1m])
) > 1000

这个查询导致 Prometheus 主机系统负载高的问题。通过count by (__name__)({__name__=~".+"})分析发现,iftop_traffic_bytes_total指标存在约5万个时间序列,其中user标签的基数占比超过75%。

一、分阶段优化过程

阶段一:查询层优化

1. 过滤无效标签

user!~"(?:^$|default|system)"

该操作减少约8%的时间序列数量,但查询延迟仅从3.2s降至3.0s,效果有限。

2. 调整时间窗口

将计算窗口从[1m]缩短至[30s]

原始执行时间:3.2s → 2.7s

但观察到流量曲线有些波动,pass。

阶段二:数据源治理

3. 指标生成层过滤

通过改造指标生成脚本,在数据源头排除无效数据:

# 原始数据采集脚本片段
awk '/iftop_traffic_bytes_total/ && $6 != "" {print $0}' raw_metrics.log > metrics.prom

优化效果:

  • 指标生成量减少12%
  • user标签基数从5200下降至4600
  • Prometheus TSDB写入速率降低15%

4. 采集配置增强

prometheus.yml中补充过滤规则:

metric_relabel_configs:
- source_labels: [user]
  regex: '^(?:|default|system)$'
  action: drop

双重保障确保无效数据不会进入存储环节。

阶段三:计算层优化

5. 预计算规则

配置Recording Rules实现查询逻辑固化:

- record: job:iftop_traffic_bytes:rate1m
  expr: |
    rate(iftop_traffic_bytes_total{
      direction="send"
    }[1m])

优化后的查询语句简化为:

sum by (user) (job:iftop_traffic_bytes:rate1m) > 1000

二、效果验证

通过多维度优化措施组合实施,系统指标变化如下:

优化阶段 时间序列数量 查询延迟 内存消耗
原始状态 52,000 3200ms 1.2GB
查询层优化后 47,800 2700ms 900MB
数据源治理后 42,000 2200ms 750MB
预计算规则启用后 820 420ms 150MB

通过rate(prometheus_engine_query_duration_seconds_sum[1h])指标观测,查询延迟P99值下降89%。

三、衍生效益

基于优化后的数据模型,我扩展实现了以下监控指标:

# 实时在线用户数
count(sum by (user)(job:iftop_traffic_bytes:rate1m) > bool 1)

四、经验总结

  1. 源头治理优先:在指标生成环节过滤无效数据,比后期处理更高效
  2. 分层防御体系:结合脚本过滤+metric_relabel_configs构建双重保障
  3. 预计算价值:Recording Rules将复杂查询转换为简单检索,效果显著
  4. 基数监控:建立count(count by (user)({__name__=~".+"}))例行检查机制

Shell 脚本 while 循环只执行一次的问题

最近在做 Prometheus 告警的自动化运维场景,我通过 Shell 脚本循环处理多个 long_uptime 告警。然而,脚本在首次执行 SSH 命令后直接退出循环,导致后续告警未被处理。本文记录完整的排错过程。

问题现象

原始代码片段:

while read -r alert; do
    # 提取告警信息...
    ssh "$node" "docker restart $container_name"
    # 其他逻辑...
done <<< "$alerts"

表现

  • 循环仅处理第一个告警后退出,未遍历所有符合条件的告警。
  • 取消注释 ssh 命令后问题消失,证明与 SSH 执行相关。

原因分析

1. SSH 阻塞导致循环中断

  • 默认行为:SSH 会读取标准输入(stdin),可能导致后续的 read 命令获取到空值
  • 错误传播:若 SSH 连接失败且未处理退出码,Bash 可能因 set -e 或默认行为终止脚本

2. 缺乏并发与超时控制

  • 串行执行:每个 SSH 命令需等待前一个完成,若节点响应慢,总耗时过长
  • 超时缺失:网络波动或节点宕机时,SSH 可能无限期挂起

解决方案

1. 非阻塞 SSH 执行

ssh -n -o ConnectTimeout=10 "$node" "docker restart $container_name" </dev/null &>/dev/null &
  • 关键参数
    • -n:禁用 stdin 输入
    • ConnectTimeout=10:10秒连接超时
    • &:后台执行,立即返回控制权

2. 并发控制与错误处理

max_jobs=5  # 最大并发数
while read -r alert; do
    # 处理告警逻辑...
    ssh "$node" "docker restart $container_name" &
    
    # 控制并发
    if [[ $(jobs -r -p | wc -l) -ge $max_jobs ]]; then
        wait -n  # 等待任意一个任务完成
    fi
done <<< "$alerts"
wait  # 等待所有后台任务
  • jobs -r -p:获取当前运行的后台任务 PID
  • wait -n:避免资源耗尽,动态控制并发数

3. 错误容忍设计

if ! ssh "$node" "docker restart $container_name"; then
    echo "Failed to restart $container_name on $node" >&2
    continue  # 跳过失败任务,继续处理后续告警
fi
  • continue:即使单个 SSH 失败,仍继续循环

验证步骤

  1. 模拟多告警输入

    alerts='[
      {"labels": {"category": "long_uptime", "name": "app1", "node": "node1"}},
      {"labels": {"category": "long_uptime", "name": "app2", "node": "node2"}}
    ]'
    

    确认脚本处理所有告警

  2. 压力测试
    使用 tc 模拟高延迟网络,观察脚本是否仍正常执行

    tc qdisc add dev eth0 root netem delay 2000ms
    

最终优化代码

while read -r alert; do
    # 提取变量(省略部分代码)
    if [[ "$category" == "long_uptime" ]]; then
        # 并行执行 SSH 命令
        ssh -n -o ConnectTimeout=10 "$node" "docker restart $container_name" </dev/null &>/dev/null &
        
        # 控制并发(示例:最大 10 个并行任务)
        if [[ $(jobs -r -p | wc -l) -ge 10 ]]; then
            wait -n
        fi
    fi
done <<< "$alerts"
wait  # 等待所有后台任务完成

Prometheus 数据保留时间配置

今天在调整Prometheus的数据保留时间,将默认的15天存储延长到30天,记录下过程。

配置

按照网上查到的教程,在启动命令中添加了--storage.tsdb.retention.time=30d,结果Prometheus直接报错

Error parsing commandline arguments: unknown long flag '--storage.tsdb.retention.time'

通过prometheus --version确认当前版本为2.6.0,资料显示:

  • 3.0.0+版本才支持--storage.tsdb.retention.time参数
  • 旧版本需要使用--storage.tsdb.retention=30d(无.time后缀)

将参数改为旧版格式:

./prometheus --storage.tsdb.retention=30d --config.file=prometheus.yml

配置优先级验证

为了确认配置生效方式,做了两组测试:

命令行 vs 配置文件冲突

  • prometheus.yml中设置storage.tsdb.retention: 15d
  • 命令行参数--storage.tsdb.retention=30d

结果:命令行参数覆盖配置文件,实际生效30天

可以通过这个页面查看生效的配置:

http://<prometheus-server>/flags

image-20250325午前111838386

完整配置示例

# 启动脚本示例(适用于v2.6)
./prometheus \
  --storage.tsdb.retention=30d \   # 旧版参数
  --config.file=prometheus.yml \   # 配置文件路径
  --web.enable-lifecycle           # 可选:启用热加载
# prometheus.yml(兼容新旧版本)
storage:
  tsdb:
    retention: 30d  # 新版本写成retention.time