第13章 Jenkins性能优化

13.1 性能优化概述

性能问题识别

常见性能瓶颈:

复制代码
Jenkins性能问题分类:

1. 系统资源瓶颈
   - CPU使用率过高
   - 内存不足或泄漏
   - 磁盘I/O瓶颈
   - 网络带宽限制

2. 应用层面问题
   - JVM配置不当
   - 垃圾回收频繁
   - 线程池配置问题
   - 数据库连接池不足

3. 架构设计问题
   - 单点瓶颈
   - 负载分布不均
   - 缓存策略不当
   - 同步操作过多

4. 配置和使用问题
   - 插件冲突或性能差
   - 构建配置不合理
   - 并发设置不当
   - 日志级别过详细

性能监控指标:

复制代码
关键性能指标(KPI):

1. 响应时间指标
   - 页面加载时间
   - API响应时间
   - 构建启动延迟
   - 队列等待时间

2. 吞吐量指标
   - 并发构建数量
   - 每分钟构建数
   - 用户并发数
   - 请求处理速率

3. 资源利用率
   - CPU使用率
   - 内存使用率
   - 磁盘使用率
   - 网络使用率

4. 错误率指标
   - 构建失败率
   - 系统错误率
   - 超时错误率
   - 连接失败率

性能测试方法:

复制代码
性能测试策略:

1. 基准测试
   - 建立性能基线
   - 定期性能回归测试
   - 版本间性能对比
   - 配置变更影响评估

2. 负载测试
   - 模拟正常负载
   - 测试系统稳定性
   - 验证性能指标
   - 识别性能拐点

3. 压力测试
   - 测试系统极限
   - 识别瓶颈点
   - 验证故障恢复
   - 评估扩展需求

4. 容量规划
   - 预测增长需求
   - 评估硬件需求
   - 规划扩展策略
   - 成本效益分析

性能优化策略

分层优化方法:

复制代码
优化层次结构:

┌─────────────────────────────────────┐
│           应用层优化                  │
│  - 代码优化                          │
│  - 算法优化                          │
│  - 缓存策略                          │
│  - 异步处理                          │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│           中间件优化                  │
│  - JVM调优                          │
│  - 数据库优化                        │
│  - 网络优化                          │
│  - 负载均衡                          │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│           系统层优化                  │
│  - 操作系统调优                      │
│  - 硬件配置                          │
│  - 存储优化                          │
│  - 网络配置                          │
└─────────────────────────────────────┘

优化原则:
1. 先测量,后优化
2. 优化最大瓶颈
3. 平衡各项指标
4. 持续监控验证

13.2 JVM调优

内存配置优化

堆内存配置:

bash 复制代码
# Jenkins启动脚本优化
#!/bin/bash

# 基础内存配置(适用于中等规模Jenkins)
JAVA_OPTS="
  -Xms4g                    # 初始堆大小
  -Xmx8g                    # 最大堆大小
  -XX:NewRatio=1            # 新生代与老年代比例
  -XX:SurvivorRatio=8       # Eden与Survivor比例
  -XX:MaxMetaspaceSize=512m # 元空间最大大小
  -XX:CompressedClassSpaceSize=128m
"

# 垃圾回收器配置(推荐G1GC)
GC_OPTS="
  -XX:+UseG1GC              # 使用G1垃圾回收器
  -XX:MaxGCPauseMillis=200  # 最大GC暂停时间
  -XX:G1HeapRegionSize=16m  # G1堆区域大小
  -XX:G1NewSizePercent=30   # 新生代初始占比
  -XX:G1MaxNewSizePercent=40 # 新生代最大占比
  -XX:G1MixedGCCountTarget=8 # 混合GC目标次数
  -XX:InitiatingHeapOccupancyPercent=45 # 并发标记触发阈值
"

# 大规模Jenkins配置(高并发场景)
LARGE_SCALE_OPTS="
  -Xms16g
  -Xmx32g
  -XX:NewRatio=1
  -XX:SurvivorRatio=6
  -XX:MaxMetaspaceSize=1g
  -XX:+UseG1GC
  -XX:MaxGCPauseMillis=100
  -XX:G1HeapRegionSize=32m
  -XX:ParallelGCThreads=16
  -XX:ConcGCThreads=4
"

# 性能监控和调试选项
MONITORING_OPTS="
  -XX:+PrintGC              # 打印GC信息
  -XX:+PrintGCDetails       # 详细GC信息
  -XX:+PrintGCTimeStamps    # GC时间戳
  -XX:+PrintGCApplicationStoppedTime # 应用暂停时间
  -Xloggc:/var/log/jenkins/gc.log    # GC日志文件
  -XX:+UseGCLogFileRotation # GC日志轮转
  -XX:NumberOfGCLogFiles=10 # GC日志文件数量
  -XX:GCLogFileSize=100M    # GC日志文件大小
  -XX:+HeapDumpOnOutOfMemoryError # OOM时生成堆转储
  -XX:HeapDumpPath=/var/log/jenkins/heapdump.hprof
"

# JIT编译器优化
JIT_OPTS="
  -XX:+TieredCompilation    # 分层编译
  -XX:TieredStopAtLevel=4   # 编译级别
  -XX:CompileThreshold=10000 # 编译阈值
  -XX:+UseCodeCacheFlushing # 代码缓存清理
  -XX:ReservedCodeCacheSize=256m # 代码缓存大小
"

# 网络和I/O优化
NETWORK_OPTS="
  -Djava.net.preferIPv4Stack=true
  -Djava.awt.headless=true
  -Dfile.encoding=UTF-8
  -Dsun.jnu.encoding=UTF-8
  -Dhudson.model.DirectoryBrowserSupport.CSP=
  -Djenkins.install.runSetupWizard=false
"

# 组合所有选项
export JAVA_OPTS="$JAVA_OPTS $GC_OPTS $MONITORING_OPTS $JIT_OPTS $NETWORK_OPTS"

# 启动Jenkins
java $JAVA_OPTS -jar jenkins.war --httpPort=8080

内存分析脚本:

bash 复制代码
#!/bin/bash
# jenkins_memory_analysis.sh

JENKINS_PID=$(pgrep -f jenkins.war)

if [ -z "$JENKINS_PID" ]; then
    echo "Jenkins进程未找到"
    exit 1
fi

echo "=== Jenkins内存分析报告 ==="
echo "时间: $(date)"
echo "PID: $JENKINS_PID"
echo

# 基本内存信息
echo "=== 基本内存信息 ==="
jcmd $JENKINS_PID VM.info | grep -E "(heap|metaspace|code cache)"
echo

# 堆内存使用情况
echo "=== 堆内存使用情况 ==="
jcmd $JENKINS_PID GC.run_finalization
jcmd $JENKINS_PID VM.memory
echo

# GC统计信息
echo "=== GC统计信息 ==="
jstat -gc $JENKINS_PID
echo

# 类加载统计
echo "=== 类加载统计 ==="
jstat -class $JENKINS_PID
echo

# 编译统计
echo "=== JIT编译统计 ==="
jstat -compiler $JENKINS_PID
echo

# 生成堆转储(可选)
read -p "是否生成堆转储文件?(y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    DUMP_FILE="/tmp/jenkins_heapdump_$(date +%Y%m%d_%H%M%S).hprof"
    echo "生成堆转储文件: $DUMP_FILE"
    jcmd $JENKINS_PID GC.run_finalization
    jcmd $JENKINS_PID VM.memory
    jhsdb jmap --heap --pid $JENKINS_PID
fi

# 内存使用趋势分析
echo "=== 内存使用趋势(最近10次采样) ==="
for i in {1..10}; do
    echo "采样 $i:"
    jstat -gc $JENKINS_PID | tail -1
    sleep 5
done

垃圾回收优化

G1GC调优配置:

bash 复制代码
# G1GC详细配置
G1_TUNING_OPTS="
  # 基础G1配置
  -XX:+UseG1GC
  -XX:MaxGCPauseMillis=200
  
  # 堆区域配置
  -XX:G1HeapRegionSize=16m
  -XX:G1NewSizePercent=20
  -XX:G1MaxNewSizePercent=30
  
  # 并发标记配置
  -XX:InitiatingHeapOccupancyPercent=45
  -XX:G1MixedGCLiveThresholdPercent=85
  -XX:G1HeapWastePercent=5
  
  # 混合GC配置
  -XX:G1MixedGCCountTarget=8
  -XX:G1OldCSetRegionThreshold=10
  
  # 并发线程配置
  -XX:ConcGCThreads=4
  -XX:ParallelGCThreads=16
  
  # 字符串去重(Java 8u20+)
  -XX:+UseStringDeduplication
  
  # 大对象处理
  -XX:G1ReservePercent=10
"

# GC日志详细配置
GC_LOGGING_OPTS="
  -Xloggc:/var/log/jenkins/gc-%t.log
  -XX:+UseGCLogFileRotation
  -XX:NumberOfGCLogFiles=10
  -XX:GCLogFileSize=100M
  -XX:+PrintGC
  -XX:+PrintGCDetails
  -XX:+PrintGCTimeStamps
  -XX:+PrintGCDateStamps
  -XX:+PrintGCApplicationStoppedTime
  -XX:+PrintGCApplicationConcurrentTime
  -XX:+PrintStringDeduplicationStatistics
"

GC分析脚本:

python 复制代码
#!/usr/bin/env python3
# gc_analysis.py

import re
import sys
from datetime import datetime
from collections import defaultdict

class GCAnalyzer:
    def __init__(self, log_file):
        self.log_file = log_file
        self.gc_events = []
        self.pause_times = []
        self.heap_usage = []
        
    def parse_gc_log(self):
        """解析GC日志文件"""
        with open(self.log_file, 'r') as f:
            for line in f:
                self._parse_line(line.strip())
    
    def _parse_line(self, line):
        """解析单行GC日志"""
        # 解析G1GC暂停时间
        pause_pattern = r'\[GC pause.*?([0-9.]+) secs\]'
        pause_match = re.search(pause_pattern, line)
        if pause_match:
            pause_time = float(pause_match.group(1)) * 1000  # 转换为毫秒
            self.pause_times.append(pause_time)
        
        # 解析堆使用情况
        heap_pattern = r'(\d+)M->(\d+)M\((\d+)M\)'
        heap_match = re.search(heap_pattern, line)
        if heap_match:
            before = int(heap_match.group(1))
            after = int(heap_match.group(2))
            total = int(heap_match.group(3))
            self.heap_usage.append({
                'before': before,
                'after': after,
                'total': total,
                'utilization': (after / total) * 100
            })
    
    def analyze(self):
        """分析GC性能"""
        if not self.pause_times:
            print("未找到GC暂停时间数据")
            return
        
        # 暂停时间统计
        avg_pause = sum(self.pause_times) / len(self.pause_times)
        max_pause = max(self.pause_times)
        min_pause = min(self.pause_times)
        
        # 计算百分位数
        sorted_pauses = sorted(self.pause_times)
        p95_pause = sorted_pauses[int(len(sorted_pauses) * 0.95)]
        p99_pause = sorted_pauses[int(len(sorted_pauses) * 0.99)]
        
        print("=== GC性能分析报告 ===")
        print(f"总GC次数: {len(self.pause_times)}")
        print(f"平均暂停时间: {avg_pause:.2f}ms")
        print(f"最大暂停时间: {max_pause:.2f}ms")
        print(f"最小暂停时间: {min_pause:.2f}ms")
        print(f"95%暂停时间: {p95_pause:.2f}ms")
        print(f"99%暂停时间: {p99_pause:.2f}ms")
        
        # 堆使用情况分析
        if self.heap_usage:
            avg_utilization = sum(h['utilization'] for h in self.heap_usage) / len(self.heap_usage)
            max_utilization = max(h['utilization'] for h in self.heap_usage)
            
            print(f"\n=== 堆使用情况 ===")
            print(f"平均堆使用率: {avg_utilization:.2f}%")
            print(f"最大堆使用率: {max_utilization:.2f}%")
        
        # 性能建议
        self._provide_recommendations(avg_pause, max_pause, p95_pause)
    
    def _provide_recommendations(self, avg_pause, max_pause, p95_pause):
        """提供优化建议"""
        print("\n=== 优化建议 ===")
        
        if avg_pause > 200:
            print("- 平均暂停时间过长,建议减小MaxGCPauseMillis目标")
        
        if max_pause > 1000:
            print("- 最大暂停时间过长,建议增加堆大小或调整G1参数")
        
        if p95_pause > 500:
            print("- 95%暂停时间过长,建议优化应用代码减少对象分配")
        
        if len(self.pause_times) > 1000:
            print("- GC频率过高,建议增加堆大小")

if __name__ == "__main__":
    if len(sys.argv) != 2:
        print("用法: python3 gc_analysis.py <gc_log_file>")
        sys.exit(1)
    
    analyzer = GCAnalyzer(sys.argv[1])
    analyzer.parse_gc_log()
    analyzer.analyze()

13.3 系统级优化

操作系统调优

Linux系统优化:

bash 复制代码
#!/bin/bash
# jenkins_system_tuning.sh

echo "=== Jenkins系统优化脚本 ==="

# 1. 内核参数优化
echo "配置内核参数..."
cat >> /etc/sysctl.conf << EOF
# Jenkins系统优化参数

# 网络优化
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 5000
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.tcp_fin_timeout = 30
net.ipv4.tcp_keepalive_time = 1200
net.ipv4.tcp_max_tw_buckets = 6000
net.ipv4.ip_local_port_range = 1024 65535
net.ipv4.tcp_rmem = 4096 65536 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
net.core.rmem_default = 262144
net.core.rmem_max = 16777216
net.core.wmem_default = 262144
net.core.wmem_max = 16777216

# 内存管理
vm.swappiness = 1
vm.dirty_ratio = 15
vm.dirty_background_ratio = 5
vm.vfs_cache_pressure = 50
vm.min_free_kbytes = 65536

# 文件系统
fs.file-max = 2097152
fs.nr_open = 2097152

# 进程限制
kernel.pid_max = 4194304
kernel.threads-max = 4194304
EOF

# 应用内核参数
sysctl -p

# 2. 文件描述符限制
echo "配置文件描述符限制..."
cat >> /etc/security/limits.conf << EOF
# Jenkins用户限制
jenkins soft nofile 65535
jenkins hard nofile 65535
jenkins soft nproc 32768
jenkins hard nproc 32768
jenkins soft memlock unlimited
jenkins hard memlock unlimited

# 所有用户默认限制
* soft nofile 65535
* hard nofile 65535
EOF

# 3. systemd服务限制
echo "配置systemd服务限制..."
mkdir -p /etc/systemd/system/jenkins.service.d
cat > /etc/systemd/system/jenkins.service.d/limits.conf << EOF
[Service]
LimitNOFILE=65535
LimitNPROC=32768
LimitMEMLOCK=infinity
EOF

# 4. 磁盘I/O优化
echo "优化磁盘I/O..."
# 设置I/O调度器为deadline(适合SSD)
echo deadline > /sys/block/sda/queue/scheduler

# 禁用透明大页
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag

# 5. CPU优化
echo "优化CPU设置..."
# 设置CPU调度器
echo performance > /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

# 6. 创建优化的挂载选项
echo "优化文件系统挂载选项..."
cat >> /etc/fstab << EOF
# Jenkins工作目录优化挂载
/dev/sdb1 /var/lib/jenkins ext4 defaults,noatime,nodiratime,barrier=0 0 2
EOF

echo "系统优化完成,建议重启系统使所有设置生效"

性能监控脚本:

bash 复制代码
#!/bin/bash
# jenkins_performance_monitor.sh

LOG_FILE="/var/log/jenkins/performance.log"
INTERVAL=60  # 监控间隔(秒)

# 创建日志目录
mkdir -p $(dirname $LOG_FILE)

echo "Jenkins性能监控启动,日志文件: $LOG_FILE"
echo "监控间隔: ${INTERVAL}秒"

while true; do
    TIMESTAMP=$(date '+%Y-%m-%d %H:%M:%S')
    
    # 获取Jenkins进程信息
    JENKINS_PID=$(pgrep -f jenkins.war)
    
    if [ -n "$JENKINS_PID" ]; then
        # CPU使用率
        CPU_USAGE=$(ps -p $JENKINS_PID -o %cpu --no-headers)
        
        # 内存使用情况
        MEMORY_INFO=$(ps -p $JENKINS_PID -o %mem,vsz,rss --no-headers)
        MEM_PERCENT=$(echo $MEMORY_INFO | awk '{print $1}')
        VSZ=$(echo $MEMORY_INFO | awk '{print $2}')
        RSS=$(echo $MEMORY_INFO | awk '{print $3}')
        
        # 文件描述符使用情况
        FD_COUNT=$(lsof -p $JENKINS_PID 2>/dev/null | wc -l)
        
        # 线程数量
        THREAD_COUNT=$(ps -p $JENKINS_PID -o nlwp --no-headers)
        
        # 系统负载
        LOAD_AVG=$(uptime | awk -F'load average:' '{print $2}' | sed 's/^[ \t]*//')
        
        # 磁盘使用情况
        DISK_USAGE=$(df -h /var/lib/jenkins | tail -1 | awk '{print $5}' | sed 's/%//')
        
        # JVM堆内存使用情况(如果jstat可用)
        if command -v jstat >/dev/null 2>&1; then
            HEAP_INFO=$(jstat -gc $JENKINS_PID | tail -1)
            HEAP_USED=$(echo $HEAP_INFO | awk '{print ($3+$4+$6+$8)/1024}' | bc -l 2>/dev/null || echo "N/A")
            HEAP_TOTAL=$(echo $HEAP_INFO | awk '{print ($1+$2+$5+$7)/1024}' | bc -l 2>/dev/null || echo "N/A")
        else
            HEAP_USED="N/A"
            HEAP_TOTAL="N/A"
        fi
        
        # 记录性能数据
        echo "$TIMESTAMP,CPU:${CPU_USAGE}%,MEM:${MEM_PERCENT}%,VSZ:${VSZ}KB,RSS:${RSS}KB,FD:${FD_COUNT},THREADS:${THREAD_COUNT},LOAD:${LOAD_AVG},DISK:${DISK_USAGE}%,HEAP_USED:${HEAP_USED}MB,HEAP_TOTAL:${HEAP_TOTAL}MB" >> $LOG_FILE
        
        # 检查性能阈值并告警
        if (( $(echo "$CPU_USAGE > 80" | bc -l) )); then
            echo "[$TIMESTAMP] 警告: CPU使用率过高 ${CPU_USAGE}%" | tee -a $LOG_FILE
        fi
        
        if (( $(echo "$MEM_PERCENT > 85" | bc -l) )); then
            echo "[$TIMESTAMP] 警告: 内存使用率过高 ${MEM_PERCENT}%" | tee -a $LOG_FILE
        fi
        
        if [ "$FD_COUNT" -gt 50000 ]; then
            echo "[$TIMESTAMP] 警告: 文件描述符使用过多 $FD_COUNT" | tee -a $LOG_FILE
        fi
        
        if [ "$DISK_USAGE" -gt 85 ]; then
            echo "[$TIMESTAMP] 警告: 磁盘使用率过高 ${DISK_USAGE}%" | tee -a $LOG_FILE
        fi
        
    else
        echo "[$TIMESTAMP] Jenkins进程未运行" >> $LOG_FILE
    fi
    
    sleep $INTERVAL
done

存储优化

磁盘配置优化:

bash 复制代码
#!/bin/bash
# jenkins_storage_optimization.sh

echo "=== Jenkins存储优化 ==="

# 1. 创建优化的文件系统结构
echo "创建优化的目录结构..."

# Jenkins主目录
JENKINS_HOME="/var/lib/jenkins"

# 分离不同类型的数据
mkdir -p $JENKINS_HOME/{jobs,workspace,logs,plugins,tools,secrets}
mkdir -p /var/cache/jenkins/{builds,artifacts}
mkdir -p /tmp/jenkins/{workspace,builds}

# 2. 配置tmpfs用于临时文件
echo "配置tmpfs..."
cat >> /etc/fstab << EOF
# Jenkins临时文件系统
tmpfs /tmp/jenkins tmpfs defaults,size=4G,mode=1777 0 0
EOF

# 3. 设置合适的文件权限
echo "设置文件权限..."
chown -R jenkins:jenkins $JENKINS_HOME
chown -R jenkins:jenkins /var/cache/jenkins
chown -R jenkins:jenkins /tmp/jenkins

# 4. 配置日志轮转
echo "配置日志轮转..."
cat > /etc/logrotate.d/jenkins << EOF
/var/lib/jenkins/logs/*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    copytruncate
    su jenkins jenkins
}

/var/log/jenkins/*.log {
    daily
    missingok
    rotate 30
    compress
    delaycompress
    notifempty
    copytruncate
    su jenkins jenkins
}
EOF

# 5. 创建清理脚本
cat > /usr/local/bin/jenkins_cleanup.sh << 'EOF'
#!/bin/bash
# Jenkins存储清理脚本

JENKINS_HOME="/var/lib/jenkins"
RETENTION_DAYS=30
WORKSPACE_RETENTION_DAYS=7

echo "开始Jenkins存储清理..."

# 清理旧的构建日志
echo "清理构建日志..."
find $JENKINS_HOME/jobs/*/builds/*/log -type f -mtime +$RETENTION_DAYS -delete

# 清理旧的工作空间
echo "清理工作空间..."
find $JENKINS_HOME/workspace/* -type d -mtime +$WORKSPACE_RETENTION_DAYS -exec rm -rf {} + 2>/dev/null

# 清理临时文件
echo "清理临时文件..."
find /tmp/jenkins -type f -mtime +1 -delete
find /var/cache/jenkins -type f -mtime +$RETENTION_DAYS -delete

# 清理旧的插件缓存
echo "清理插件缓存..."
find $JENKINS_HOME/plugins -name "*.tmp" -delete
find $JENKINS_HOME/plugins -name "*.bak" -mtime +7 -delete

# 压缩旧的构建产物
echo "压缩构建产物..."
find $JENKINS_HOME/jobs/*/builds/*/archive -type f -name "*.jar" -mtime +7 ! -name "*.gz" -exec gzip {} \;

# 统计清理结果
echo "清理完成,当前磁盘使用情况:"
df -h $JENKINS_HOME

echo "Jenkins目录大小:"
du -sh $JENKINS_HOME
EOF

chmod +x /usr/local/bin/jenkins_cleanup.sh

# 6. 设置定时清理任务
echo "设置定时清理任务..."
cat > /etc/cron.d/jenkins-cleanup << EOF
# Jenkins存储清理任务
0 2 * * * jenkins /usr/local/bin/jenkins_cleanup.sh >> /var/log/jenkins/cleanup.log 2>&1
EOF

echo "存储优化配置完成"

存储监控脚本:

python 复制代码
#!/usr/bin/env python3
# jenkins_storage_monitor.py

import os
import sys
import json
import time
from datetime import datetime
from pathlib import Path

class StorageMonitor:
    def __init__(self, jenkins_home='/var/lib/jenkins'):
        self.jenkins_home = Path(jenkins_home)
        self.report_file = '/var/log/jenkins/storage_report.json'
        
    def get_directory_size(self, path):
        """获取目录大小"""
        total_size = 0
        try:
            for dirpath, dirnames, filenames in os.walk(path):
                for filename in filenames:
                    filepath = os.path.join(dirpath, filename)
                    try:
                        total_size += os.path.getsize(filepath)
                    except (OSError, IOError):
                        continue
        except (OSError, IOError):
            pass
        return total_size
    
    def get_disk_usage(self, path):
        """获取磁盘使用情况"""
        try:
            statvfs = os.statvfs(path)
            total = statvfs.f_frsize * statvfs.f_blocks
            free = statvfs.f_frsize * statvfs.f_available
            used = total - free
            return {
                'total': total,
                'used': used,
                'free': free,
                'usage_percent': (used / total) * 100 if total > 0 else 0
            }
        except OSError:
            return None
    
    def analyze_jenkins_storage(self):
        """分析Jenkins存储使用情况"""
        report = {
            'timestamp': datetime.now().isoformat(),
            'jenkins_home': str(self.jenkins_home),
            'directories': {},
            'disk_usage': {},
            'recommendations': []
        }
        
        # 分析各个目录的大小
        directories_to_check = [
            'jobs',
            'workspace',
            'plugins',
            'logs',
            'tools',
            'secrets',
            'userContent',
            'war'
        ]
        
        total_jenkins_size = 0
        for dir_name in directories_to_check:
            dir_path = self.jenkins_home / dir_name
            if dir_path.exists():
                size = self.get_directory_size(dir_path)
                total_jenkins_size += size
                report['directories'][dir_name] = {
                    'size_bytes': size,
                    'size_mb': size / (1024 * 1024),
                    'size_gb': size / (1024 * 1024 * 1024)
                }
        
        report['total_jenkins_size'] = {
            'size_bytes': total_jenkins_size,
            'size_mb': total_jenkins_size / (1024 * 1024),
            'size_gb': total_jenkins_size / (1024 * 1024 * 1024)
        }
        
        # 获取磁盘使用情况
        disk_usage = self.get_disk_usage(self.jenkins_home)
        if disk_usage:
            report['disk_usage'] = {
                'total_gb': disk_usage['total'] / (1024 * 1024 * 1024),
                'used_gb': disk_usage['used'] / (1024 * 1024 * 1024),
                'free_gb': disk_usage['free'] / (1024 * 1024 * 1024),
                'usage_percent': disk_usage['usage_percent']
            }
        
        # 生成建议
        self._generate_recommendations(report)
        
        return report
    
    def _generate_recommendations(self, report):
        """生成优化建议"""
        recommendations = []
        
        # 检查磁盘使用率
        if 'disk_usage' in report and report['disk_usage']['usage_percent'] > 85:
            recommendations.append({
                'type': 'critical',
                'message': f"磁盘使用率过高 ({report['disk_usage']['usage_percent']:.1f}%),需要立即清理"
            })
        
        # 检查各目录大小
        if 'directories' in report:
            # 检查workspace目录
            if 'workspace' in report['directories']:
                workspace_size_gb = report['directories']['workspace']['size_gb']
                if workspace_size_gb > 10:
                    recommendations.append({
                        'type': 'warning',
                        'message': f"workspace目录过大 ({workspace_size_gb:.1f}GB),建议清理旧的工作空间"
                    })
            
            # 检查jobs目录
            if 'jobs' in report['directories']:
                jobs_size_gb = report['directories']['jobs']['size_gb']
                if jobs_size_gb > 20:
                    recommendations.append({
                        'type': 'warning',
                        'message': f"jobs目录过大 ({jobs_size_gb:.1f}GB),建议清理旧的构建记录"
                    })
            
            # 检查logs目录
            if 'logs' in report['directories']:
                logs_size_gb = report['directories']['logs']['size_gb']
                if logs_size_gb > 5:
                    recommendations.append({
                        'type': 'info',
                        'message': f"logs目录较大 ({logs_size_gb:.1f}GB),建议配置日志轮转"
                    })
        
        report['recommendations'] = recommendations
    
    def save_report(self, report):
        """保存报告到文件"""
        os.makedirs(os.path.dirname(self.report_file), exist_ok=True)
        with open(self.report_file, 'w') as f:
            json.dump(report, f, indent=2)
    
    def print_report(self, report):
        """打印报告"""
        print("=== Jenkins存储分析报告 ===")
        print(f"时间: {report['timestamp']}")
        print(f"Jenkins主目录: {report['jenkins_home']}")
        print()
        
        # 总体使用情况
        if 'total_jenkins_size' in report:
            total_size = report['total_jenkins_size']
            print(f"Jenkins总大小: {total_size['size_gb']:.2f} GB")
        
        if 'disk_usage' in report:
            disk = report['disk_usage']
            print(f"磁盘使用情况: {disk['used_gb']:.1f}GB / {disk['total_gb']:.1f}GB ({disk['usage_percent']:.1f}%)")
        
        print()
        
        # 目录详情
        print("=== 目录大小详情 ===")
        if 'directories' in report:
            for dir_name, info in sorted(report['directories'].items(), 
                                       key=lambda x: x[1]['size_gb'], reverse=True):
                print(f"{dir_name:15}: {info['size_gb']:8.2f} GB")
        
        print()
        
        # 建议
        if 'recommendations' in report and report['recommendations']:
            print("=== 优化建议 ===")
            for rec in report['recommendations']:
                icon = {'critical': '🚨', 'warning': '⚠️', 'info': 'ℹ️'}.get(rec['type'], '')
                print(f"{icon} {rec['message']}")
        else:
            print("✅ 存储使用情况良好,无需特别优化")
    
    def run(self):
        """运行存储监控"""
        report = self.analyze_jenkins_storage()
        self.save_report(report)
        self.print_report(report)
        return report

if __name__ == '__main__':
    jenkins_home = sys.argv[1] if len(sys.argv) > 1 else '/var/lib/jenkins'
    monitor = StorageMonitor(jenkins_home)
    monitor.run()

13.4 构建优化

Pipeline性能优化

并行化优化策略:

groovy 复制代码
// 高性能Pipeline示例
pipeline {
    agent none
    
    options {
        // 构建保留策略
        buildDiscarder(logRotator(
            numToKeepStr: '10',
            daysToKeepStr: '30',
            artifactNumToKeepStr: '5'
        ))
        
        // 超时设置
        timeout(time: 30, unit: 'MINUTES')
        
        // 禁用并发构建
        disableConcurrentBuilds()
        
        // 跳过默认检出
        skipDefaultCheckout()
    }
    
    environment {
        // 优化环境变量
        MAVEN_OPTS = '-Xmx2g -XX:+UseG1GC -Dmaven.repo.local=/var/cache/maven'
        GRADLE_OPTS = '-Xmx2g -XX:+UseG1GC -Dorg.gradle.daemon=false'
        DOCKER_BUILDKIT = '1'
    }
    
    stages {
        stage('Checkout') {
            agent { label 'fast-ssd' }
            steps {
                sh 'mvn clean compile -T 4'
            }
        }
    }
}

资源池管理:

groovy 复制代码
// 资源池管理脚本
class ResourcePoolManager {
    def jenkins = Jenkins.instance
    def pools = [:]
    
    def initializePools() {
        pools['build'] = [
            maxConcurrent: 10,
            current: 0,
            queue: [],
            nodes: ['build-1', 'build-2', 'build-3']
        ]
        
        pools['test'] = [
            maxConcurrent: 5,
            current: 0,
            queue: [],
            nodes: ['test-1', 'test-2']
        ]
        
        pools['deploy'] = [
            maxConcurrent: 2,
            current: 0,
            queue: [],
            nodes: ['deploy-1']
        ]
    }
    
    def requestResource(String poolName, Closure task) {
        def pool = pools[poolName]
        
        if (pool.current < pool.maxConcurrent) {
            pool.current++
            try {
                task()
            } finally {
                pool.current--
                processQueue(poolName)
            }
        } else {
            pool.queue.add(task)
            echo "任务已加入${poolName}队列,当前队列长度: ${pool.queue.size()}"
        }
    }
    
    def processQueue(String poolName) {
        def pool = pools[poolName]
        
        if (pool.queue.size() > 0 && pool.current < pool.maxConcurrent) {
            def nextTask = pool.queue.remove(0)
            pool.current++
            
            // 异步执行下一个任务
            Thread.start {
                try {
                    nextTask()
                } finally {
                    pool.current--
                    processQueue(poolName)
                }
            }
        }
    }
}

// 使用示例
def resourceManager = new ResourcePoolManager()
resourceManager.initializePools()

pipeline {
    agent none
    
    stages {
        stage('Build') {
            steps {
                script {
                    resourceManager.requestResource('build') {
                        node('build') {
                            sh 'mvn clean package'
                        }
                    }
                }
            }
        }
    }
}

13.5 网络优化

带宽优化

网络配置优化:

bash 复制代码
#!/bin/bash
# jenkins_network_optimization.sh

echo "=== Jenkins网络优化配置 ==="

# 1. TCP优化
echo "配置TCP参数..."
cat >> /etc/sysctl.conf << EOF
# Jenkins网络优化
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_no_metrics_save = 1
net.ipv4.tcp_moderate_rcvbuf = 1
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq

# 连接跟踪优化
net.netfilter.nf_conntrack_max = 1048576
net.netfilter.nf_conntrack_tcp_timeout_established = 7200
EOF

sysctl -p

# 2. 配置Jenkins反向代理
echo "配置Nginx反向代理..."
cat > /etc/nginx/sites-available/jenkins << 'EOF'
upstream jenkins {
    server 127.0.0.1:8080 fail_timeout=0;
}

server {
    listen 80;
    server_name jenkins.company.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name jenkins.company.com;
    
    # SSL配置
    ssl_certificate /etc/ssl/certs/jenkins.crt;
    ssl_certificate_key /etc/ssl/private/jenkins.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;
    
    # 性能优化
    client_max_body_size 100M;
    client_body_timeout 60s;
    client_header_timeout 60s;
    keepalive_timeout 65s;
    send_timeout 60s;
    
    # 压缩配置
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types
        text/plain
        text/css
        text/xml
        text/javascript
        application/json
        application/javascript
        application/xml+rss
        application/atom+xml
        image/svg+xml;
    
    # 缓存配置
    location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }
    
    # Jenkins代理配置
    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Port $server_port;
        
        proxy_pass http://jenkins;
        proxy_read_timeout 90s;
        proxy_redirect http://jenkins https://jenkins.company.com;
        
        # WebSocket支持
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        
        # 缓冲优化
        proxy_buffering on;
        proxy_buffer_size 128k;
        proxy_buffers 4 256k;
        proxy_busy_buffers_size 256k;
    }
    
    # 健康检查
    location /health {
        access_log off;
        return 200 "healthy\n";
        add_header Content-Type text/plain;
    }
}
EOF

# 启用站点
ln -sf /etc/nginx/sites-available/jenkins /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx

echo "网络优化配置完成"

CDN配置:

yaml 复制代码
# cloudfront-jenkins.yml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Jenkins CDN配置'

Parameters:
  JenkinsOrigin:
    Type: String
    Default: 'jenkins.company.com'
    Description: 'Jenkins服务器域名'

Resources:
  JenkinsCDN:
    Type: AWS::CloudFront::Distribution
    Properties:
      DistributionConfig:
        Enabled: true
        Comment: 'Jenkins CDN Distribution'
        
        Origins:
          - Id: jenkins-origin
            DomainName: !Ref JenkinsOrigin
            CustomOriginConfig:
              HTTPPort: 443
              HTTPSPort: 443
              OriginProtocolPolicy: https-only
              OriginSSLProtocols:
                - TLSv1.2
        
        DefaultCacheBehavior:
          TargetOriginId: jenkins-origin
          ViewerProtocolPolicy: redirect-to-https
          AllowedMethods:
            - GET
            - HEAD
            - OPTIONS
            - PUT
            - POST
            - PATCH
            - DELETE
          CachedMethods:
            - GET
            - HEAD
            - OPTIONS
          Compress: true
          ForwardedValues:
            QueryString: true
            Headers:
              - Authorization
              - Host
              - X-Forwarded-For
              - X-Forwarded-Proto
            Cookies:
              Forward: all
          DefaultTTL: 0
          MaxTTL: 31536000
          MinTTL: 0
        
        CacheBehaviors:
          # 静态资源缓存
          - PathPattern: '*.css'
            TargetOriginId: jenkins-origin
            ViewerProtocolPolicy: redirect-to-https
            AllowedMethods: [GET, HEAD]
            CachedMethods: [GET, HEAD]
            Compress: true
            ForwardedValues:
              QueryString: false
              Headers: []
            DefaultTTL: 86400
            MaxTTL: 31536000
            MinTTL: 0
          
          - PathPattern: '*.js'
            TargetOriginId: jenkins-origin
            ViewerProtocolPolicy: redirect-to-https
            AllowedMethods: [GET, HEAD]
            CachedMethods: [GET, HEAD]
            Compress: true
            ForwardedValues:
              QueryString: false
              Headers: []
            DefaultTTL: 86400
            MaxTTL: 31536000
            MinTTL: 0
          
          - PathPattern: '*.png'
            TargetOriginId: jenkins-origin
            ViewerProtocolPolicy: redirect-to-https
            AllowedMethods: [GET, HEAD]
            CachedMethods: [GET, HEAD]
            Compress: false
            ForwardedValues:
              QueryString: false
              Headers: []
            DefaultTTL: 2592000
            MaxTTL: 31536000
            MinTTL: 0
        
        PriceClass: PriceClass_100
        ViewerCertificate:
          AcmCertificateArn: !Ref SSLCertificate
          SslSupportMethod: sni-only
          MinimumProtocolVersion: TLSv1.2_2021
  
  SSLCertificate:
    Type: AWS::CertificateManager::Certificate
    Properties:
      DomainName: !Sub 'cdn.${JenkinsOrigin}'
      ValidationMethod: DNS

Outputs:
  CDNDomainName:
    Description: 'CloudFront域名'
    Value: !GetAtt JenkinsCDN.DomainName
    Export:
      Name: !Sub '${AWS::StackName}-CDN-Domain'

连接优化

连接池配置:

groovy 复制代码
// Jenkins系统配置脚本
import jenkins.model.Jenkins
import org.jenkinsci.plugins.workflow.libs.GlobalLibraries
import org.jenkinsci.plugins.workflow.libs.LibraryConfiguration
import org.jenkinsci.plugins.workflow.libs.SCMSourceRetriever
import jenkins.plugins.git.GitSCMSource

// HTTP连接池优化
System.setProperty('hudson.model.ParametersAction.keepUndefinedParameters', 'true')
System.setProperty('hudson.model.DirectoryBrowserSupport.CSP', '')
System.setProperty('jenkins.model.Jenkins.slaveAgentPort', '50000')
System.setProperty('jenkins.model.Jenkins.slaveAgentPortEnforce', 'true')

// 网络超时设置
System.setProperty('hudson.remoting.Launcher.pingIntervalSec', '300')
System.setProperty('hudson.remoting.Launcher.pingTimeoutSec', '60')
System.setProperty('hudson.slaves.ChannelPinger.pingInterval', '5')
System.setProperty('hudson.slaves.ChannelPinger.pingTimeout', '10')

// Git连接优化
System.setProperty('org.jenkinsci.plugins.gitclient.Git.timeOut', '30')
System.setProperty('hudson.plugins.git.GitSCM.ALLOW_LOCAL_CHECKOUT', 'true')

// HTTP客户端优化
System.setProperty('hudson.ProxyConfiguration.DEFAULT_CONNECT_TIMEOUT_MILLIS', '20000')
System.setProperty('hudson.ProxyConfiguration.DEFAULT_READ_TIMEOUT_MILLIS', '60000')

println "网络连接优化配置完成"

13.6 监控和调优工具

性能分析工具

JProfiler集成脚本:

bash 复制代码
#!/bin/bash
# jenkins_profiling.sh

JPROFILER_HOME="/opt/jprofiler"
JENKINS_PID=$(pgrep -f jenkins.war)

if [ -z "$JENKINS_PID" ]; then
    echo "Jenkins进程未找到"
    exit 1
fi

echo "=== Jenkins性能分析 ==="
echo "Jenkins PID: $JENKINS_PID"

# 1. 启动JProfiler代理
echo "启动JProfiler代理..."
$JPROFILER_HOME/bin/jpenable --pid=$JENKINS_PID --port=8849

# 2. 生成堆转储
echo "生成堆转储..."
HEAP_DUMP_FILE="/tmp/jenkins_heap_$(date +%Y%m%d_%H%M%S).hprof"
jcmd $JENKINS_PID GC.run_finalization
jhsdb jmap --heap --pid $JENKINS_PID > "${HEAP_DUMP_FILE}.txt"
jcmd $JENKINS_PID VM.memory >> "${HEAP_DUMP_FILE}.txt"

# 3. 线程转储
echo "生成线程转储..."
THREAD_DUMP_FILE="/tmp/jenkins_threads_$(date +%Y%m%d_%H%M%S).txt"
jstack $JENKINS_PID > $THREAD_DUMP_FILE

# 4. GC分析
echo "分析GC日志..."
GC_LOG_FILE="/var/log/jenkins/gc.log"
if [ -f "$GC_LOG_FILE" ]; then
    # 使用GCViewer分析GC日志
    java -jar $JPROFILER_HOME/lib/gcviewer.jar $GC_LOG_FILE
fi

# 5. 性能报告
echo "生成性能报告..."
cat > "/tmp/jenkins_performance_report_$(date +%Y%m%d_%H%M%S).txt" << EOF
Jenkins性能分析报告
生成时间: $(date)
Jenkins PID: $JENKINS_PID

=== 系统信息 ===
$(uname -a)

=== CPU信息 ===
$(lscpu)

=== 内存信息 ===
$(free -h)

=== 磁盘信息 ===
$(df -h)

=== 网络连接 ===
$(netstat -an | grep :8080)

=== Java进程信息 ===
$(ps -p $JENKINS_PID -o pid,ppid,cmd,%mem,%cpu,etime)

=== JVM信息 ===
$(jcmd $JENKINS_PID VM.info)

=== 类加载统计 ===
$(jstat -class $JENKINS_PID)

=== 编译统计 ===
$(jstat -compiler $JENKINS_PID)

=== GC统计 ===
$(jstat -gc $JENKINS_PID)
EOF

echo "性能分析完成,文件保存在 /tmp/ 目录"
ls -la /tmp/jenkins_*

自动化调优脚本:

python 复制代码
#!/usr/bin/env python3
# jenkins_auto_tuning.py

import os
import re
import json
import subprocess
from datetime import datetime, timedelta

class JenkinsAutoTuner:
    def __init__(self):
        self.jenkins_home = '/var/lib/jenkins'
        self.config_file = '/etc/jenkins/tuning.json'
        self.metrics = {}
        
    def collect_metrics(self):
        """收集性能指标"""
        # 获取Jenkins进程信息
        jenkins_pid = self._get_jenkins_pid()
        if not jenkins_pid:
            return False
            
        # CPU使用率
        cpu_usage = self._get_cpu_usage(jenkins_pid)
        
        # 内存使用情况
        memory_info = self._get_memory_info(jenkins_pid)
        
        # GC信息
        gc_info = self._get_gc_info(jenkins_pid)
        
        # 响应时间
        response_time = self._get_response_time()
        
        # 构建队列长度
        queue_length = self._get_queue_length()
        
        self.metrics = {
            'timestamp': datetime.now().isoformat(),
            'cpu_usage': cpu_usage,
            'memory': memory_info,
            'gc': gc_info,
            'response_time': response_time,
            'queue_length': queue_length
        }
        
        return True
    
    def analyze_performance(self):
        """分析性能并生成调优建议"""
        recommendations = []
        
        # CPU分析
        if self.metrics['cpu_usage'] > 80:
            recommendations.append({
                'type': 'cpu',
                'severity': 'high',
                'message': 'CPU使用率过高,建议增加执行器或优化构建脚本',
                'action': 'increase_executors'
            })
        
        # 内存分析
        heap_usage = self.metrics['memory']['heap_usage_percent']
        if heap_usage > 85:
            recommendations.append({
                'type': 'memory',
                'severity': 'high',
                'message': '堆内存使用率过高,建议增加堆大小',
                'action': 'increase_heap_size'
            })
        
        # GC分析
        gc_time_percent = self.metrics['gc']['time_percent']
        if gc_time_percent > 5:
            recommendations.append({
                'type': 'gc',
                'severity': 'medium',
                'message': 'GC时间占比过高,建议调整GC参数',
                'action': 'tune_gc_parameters'
            })
        
        # 响应时间分析
        if self.metrics['response_time'] > 5000:  # 5秒
            recommendations.append({
                'type': 'response',
                'severity': 'medium',
                'message': '响应时间过长,建议优化插件或增加资源',
                'action': 'optimize_plugins'
            })
        
        # 队列分析
        if self.metrics['queue_length'] > 20:
            recommendations.append({
                'type': 'queue',
                'severity': 'medium',
                'message': '构建队列过长,建议增加构建节点',
                'action': 'add_build_nodes'
            })
        
        return recommendations
    
    def apply_tuning(self, recommendations):
        """应用调优建议"""
        applied_changes = []
        
        for rec in recommendations:
            if rec['action'] == 'increase_heap_size':
                if self._increase_heap_size():
                    applied_changes.append('增加堆内存大小')
            
            elif rec['action'] == 'tune_gc_parameters':
                if self._tune_gc_parameters():
                    applied_changes.append('优化GC参数')
            
            elif rec['action'] == 'increase_executors':
                if self._increase_executors():
                    applied_changes.append('增加执行器数量')
        
        return applied_changes
    
    def _get_jenkins_pid(self):
        """获取Jenkins进程ID"""
        try:
            result = subprocess.run(['pgrep', '-f', 'jenkins.war'], 
                                  capture_output=True, text=True)
            return result.stdout.strip() if result.returncode == 0 else None
        except:
            return None
    
    def _get_cpu_usage(self, pid):
        """获取CPU使用率"""
        try:
            result = subprocess.run(['ps', '-p', pid, '-o', '%cpu', '--no-headers'],
                                  capture_output=True, text=True)
            return float(result.stdout.strip()) if result.returncode == 0 else 0
        except:
            return 0
    
    def _get_memory_info(self, pid):
        """获取内存信息"""
        try:
            # 获取进程内存使用
            ps_result = subprocess.run(['ps', '-p', pid, '-o', '%mem,vsz,rss', '--no-headers'],
                                     capture_output=True, text=True)
            mem_percent, vsz, rss = ps_result.stdout.strip().split()
            
            # 获取JVM堆信息
            jstat_result = subprocess.run(['jstat', '-gc', pid],
                                        capture_output=True, text=True)
            gc_data = jstat_result.stdout.strip().split('\n')[-1].split()
            
            heap_used = float(gc_data[2]) + float(gc_data[3]) + float(gc_data[5]) + float(gc_data[7])
            heap_total = float(gc_data[0]) + float(gc_data[1]) + float(gc_data[4]) + float(gc_data[6])
            
            return {
                'mem_percent': float(mem_percent),
                'vsz_kb': int(vsz),
                'rss_kb': int(rss),
                'heap_used_kb': heap_used,
                'heap_total_kb': heap_total,
                'heap_usage_percent': (heap_used / heap_total) * 100 if heap_total > 0 else 0
            }
        except:
            return {}
    
    def _get_gc_info(self, pid):
        """获取GC信息"""
        try:
            result = subprocess.run(['jstat', '-gc', pid],
                                  capture_output=True, text=True)
            lines = result.stdout.strip().split('\n')
            if len(lines) >= 2:
                headers = lines[0].split()
                values = lines[1].split()
                gc_data = dict(zip(headers, values))
                
                # 计算GC时间占比
                gc_time = float(gc_data.get('GCT', 0))
                uptime_result = subprocess.run(['ps', '-p', pid, '-o', 'etime', '--no-headers'],
                                             capture_output=True, text=True)
                uptime_str = uptime_result.stdout.strip()
                uptime_seconds = self._parse_uptime(uptime_str)
                
                time_percent = (gc_time / uptime_seconds) * 100 if uptime_seconds > 0 else 0
                
                return {
                    'total_time': gc_time,
                    'time_percent': time_percent,
                    'young_gc_count': int(gc_data.get('YGC', 0)),
                    'full_gc_count': int(gc_data.get('FGC', 0))
                }
        except:
            pass
        return {}
    
    def _parse_uptime(self, uptime_str):
        """解析进程运行时间"""
        # 格式: [[DD-]HH:]MM:SS
        parts = uptime_str.split(':')
        seconds = 0
        
        if len(parts) == 2:  # MM:SS
            seconds = int(parts[0]) * 60 + int(parts[1])
        elif len(parts) == 3:  # HH:MM:SS
            seconds = int(parts[0]) * 3600 + int(parts[1]) * 60 + int(parts[2])
        elif '-' in uptime_str:  # DD-HH:MM:SS
            day_part, time_part = uptime_str.split('-')
            days = int(day_part)
            time_parts = time_part.split(':')
            seconds = days * 86400 + int(time_parts[0]) * 3600 + int(time_parts[1]) * 60 + int(time_parts[2])
        
        return seconds
    
    def _get_response_time(self):
        """获取响应时间"""
        try:
            import time
            import urllib.request
            
            start_time = time.time()
            urllib.request.urlopen('http://localhost:8080/api/json', timeout=10)
            end_time = time.time()
            
            return (end_time - start_time) * 1000  # 转换为毫秒
        except:
            return 0
    
    def _get_queue_length(self):
        """获取构建队列长度"""
        try:
            import urllib.request
            import json
            
            response = urllib.request.urlopen('http://localhost:8080/queue/api/json', timeout=5)
            data = json.loads(response.read().decode())
            return len(data.get('items', []))
        except:
            return 0
    
    def _increase_heap_size(self):
        """增加堆内存大小"""
        # 这里应该修改Jenkins启动脚本
        # 实际实现需要根据具体的部署方式
        print("建议增加堆内存大小到当前的1.5倍")
        return True
    
    def _tune_gc_parameters(self):
        """调整GC参数"""
        print("建议调整GC参数以减少GC时间")
        return True
    
    def _increase_executors(self):
        """增加执行器数量"""
        print("建议增加执行器数量以提高并发处理能力")
        return True
    
    def run(self):
        """运行自动调优"""
        print("=== Jenkins自动调优开始 ===")
        
        # 收集指标
        if not self.collect_metrics():
            print("无法收集性能指标")
            return
        
        print(f"当前性能指标:")
        print(f"  CPU使用率: {self.metrics['cpu_usage']:.1f}%")
        print(f"  内存使用率: {self.metrics['memory'].get('heap_usage_percent', 0):.1f}%")
        print(f"  GC时间占比: {self.metrics['gc'].get('time_percent', 0):.1f}%")
        print(f"  响应时间: {self.metrics['response_time']:.0f}ms")
        print(f"  队列长度: {self.metrics['queue_length']}")
        
        # 分析性能
        recommendations = self.analyze_performance()
        
        if not recommendations:
            print("✅ 系统性能良好,无需调优")
            return
        
        print(f"\n发现 {len(recommendations)} 个优化建议:")
        for i, rec in enumerate(recommendations, 1):
            print(f"  {i}. [{rec['severity'].upper()}] {rec['message']}")
        
        # 应用调优
        applied_changes = self.apply_tuning(recommendations)
        
        if applied_changes:
            print(f"\n已应用以下优化:")
            for change in applied_changes:
                print(f"  ✓ {change}")
        
        print("\n=== 自动调优完成 ===")

if __name__ == '__main__':
    tuner = JenkinsAutoTuner()
    tuner.run()

本章小结

本章详细介绍了Jenkins的性能优化:

  1. 性能优化概述:了解性能问题识别和优化策略
  2. JVM调优:掌握内存配置和垃圾回收优化
  3. 系统级优化:学习操作系统和存储优化
  4. 构建优化:实现Pipeline和资源管理优化
  5. 网络优化:配置带宽和连接优化
  6. 监控调优工具:使用性能分析和自动调优工具

通过系统性的性能优化,可以显著提升Jenkins的运行效率和用户体验。

下一章预告

下一章我们将学习Jenkins的故障排除,包括常见问题诊断、日志分析和恢复策略。

练习与思考

理论练习

  1. 性能分析

    • 分析不同类型的性能瓶颈
    • 设计性能监控方案
    • 制定性能优化计划
  2. 调优策略

    • 比较不同JVM垃圾回收器的特点
    • 设计资源分配策略
    • 规划网络优化方案

实践练习

  1. JVM调优

    • 配置G1GC参数
    • 分析GC日志
    • 优化内存配置
  2. 系统优化

    • 实施操作系统调优
    • 配置存储优化
    • 部署监控工具

思考题

  1. 优化平衡

    • 如何在性能和稳定性之间找到平衡?
    • 如何评估优化效果?
    • 如何避免过度优化?
  2. 持续改进

    • 如何建立性能优化的持续改进机制?

    • 如何处理性能回归问题?

    • 如何在团队中推广性能优化最佳实践? {

      script {

      // 优化的检出策略

      checkout([
      class:′GitSCM′,branches:[[name:env.BRANCHNAME]],doGenerateSubmoduleConfigurations:false,extensions:[[class: 'GitSCM', branches: [[name: env.BRANCH_NAME]], doGenerateSubmoduleConfigurations: false, extensions: [ [class:′GitSCM′,branches:[[name:env.BRANCHNAME]],doGenerateSubmoduleConfigurations:false,extensions:[[class: 'CloneOption',

      depth: 1,

      noTags: true,

      shallow: true],

      $class: 'CheckoutOption', timeout: 10

      ],

      userRemoteConfigs: [[url: env.GIT_URL]]

      ])

      }

      复制代码
             // 缓存依赖
             stash includes: '**', name: 'source-code'
         }

      }

      stage('Parallel Build & Test') {

      parallel {

      stage('Unit Tests') {

      agent { label 'test-runner' }

      steps {

      unstash 'source-code'

      复制代码
                     // 使用缓存的依赖
                     script {
                         if (fileExists('pom.xml')) {
                             sh '''
                                 # Maven并行构建
                                 mvn clean test \
                                     -T 4 \
                                     -Dmaven.test.failure.ignore=true \
                                     -Dmaven.repo.local=/var/cache/maven \
                                     -Dparallel=methods \
                                     -DthreadCount=4
                             '''
                         } else if (fileExists('build.gradle')) {
                             sh '''
                                 # Gradle并行构建
                                 ./gradlew test \
                                     --parallel \
                                     --max-workers=4 \
                                     --build-cache \
                                     --gradle-user-home=/var/cache/gradle
                             '''
                         }
                     }
                 }
                 post {
                     always {
                         publishTestResults(
                             testResultsPattern: '**/target/surefire-reports/*.xml,**/build/test-results/**/*.xml',
                             allowEmptyResults: true
                         )
                     }
                 }
             }
             
             stage('Code Quality') {
                 agent { label 'sonar-scanner' }
                 steps {
                     unstash 'source-code'
                     
                     script {
                         // 并行代码质量检查
                         parallel([
                             'SonarQube': {
                                 sh '''
                                     sonar-scanner \
                                         -Dsonar.projectKey=${JOB_NAME} \
                                         -Dsonar.sources=src \
                                         -Dsonar.host.url=${SONAR_URL} \
                                         -Dsonar.login=${SONAR_TOKEN}
                                 '''
                             },
                             'Security Scan': {
                                 sh '''
                                     # OWASP依赖检查
                                     dependency-check.sh \
                                         --project ${JOB_NAME} \
                                         --scan . \
                                         --format XML \
                                         --out dependency-check-report.xml
                                 '''
                             }
                         ])
                     }
                 }
             }
             
             stage('Build Artifacts') {
                 agent { label 'build-server' }
                 steps {
                     unstash 'source-code'
                     
                     script {
                         if (fileExists('pom.xml')) {
                             sh '''
                                 # Maven优化构建
                                 mvn clean package \
                                     -T 4 \
                                     -DskipTests \
                                     -Dmaven.repo.local=/var/cache/maven \
                                     -Dmaven.compile.fork=true \
                                     -Dmaven.compiler.maxmem=1024m
                             '''
                         } else if (fileExists('Dockerfile')) {
                             sh '''
                                 # Docker多阶段构建
                                 docker build \
                                     --build-arg BUILDKIT_INLINE_CACHE=1 \
                                     --cache-from ${IMAGE_NAME}:cache \
                                     -t ${IMAGE_NAME}:${BUILD_NUMBER} \
                                     -t ${IMAGE_NAME}:latest .
                             '''
                         }
                     }
                     
                     // 存储构建产物
                     stash includes: '**/target/*.jar,**/build/libs/*.jar', name: 'artifacts'
                 }
             }
         }

      }

      stage('Integration Tests') {

      agent { label 'integration-test' }

      when {

      anyOf {

      branch 'main'

      branch 'develop'

      changeRequest()

      }

      }

      steps {

      unstash 'source-code'

      unstash 'artifacts'

      复制代码
             script {
                 // 并行集成测试
                 def testStages = [:]
                 
                 ['api-tests', 'ui-tests', 'performance-tests'].each { testType ->
                     testStages[testType] = {
                         sh "./run-${testType}.sh"
                     }
                 }
                 
                 parallel testStages
             }
         }

      }

      stage('Deploy') {

      agent { label 'deployment' }

      when {

      branch 'main'

      }

      steps {

      unstash 'artifacts'

      复制代码
             script {
                 // 蓝绿部署
                 sh '''
                     # 部署到蓝绿环境
                     ./deploy.sh --strategy=blue-green --timeout=300
                 '''
             }
         }

      }

      }

    post {

    always {

    script {

    // 清理工作空间

    cleanWs(

    cleanWhenAborted: true,

    cleanWhenFailure: true,

    cleanWhenNotBuilt: true,

    cleanWhenSuccess: true,

    cleanWhenUnstable: true,

    deleteDirs: true

    )

    }

    }

    复制代码
     success {
         script {
             // 成功通知
             if (env.BRANCH_NAME == 'main') {
                 slackSend(
                     channel: '#deployments',
                     color: 'good',
                     message: "✅ 部署成功: ${env.JOB_NAME} #${env.BUILD_NUMBER}"
                 )
             }
         }
     }
     
     failure {
         script {
             // 失败通知和分析
             emailext(
                 subject: "构建失败: ${env.JOB_NAME} #${env.BUILD_NUMBER}",
                 body: '''
                     构建失败详情:
                     
                     项目: ${env.JOB_NAME}
                     构建号: ${env.BUILD_NUMBER}
                     分支: ${env.BRANCH_NAME}
                     提交: ${env.GIT_COMMIT}
                     
                     查看详情: ${env.BUILD_URL}
                 ''',
                 to: '${DEFAULT_RECIPIENTS}'
             )
         }
     }

    }

    }

    构建缓存优化:

    groovy 复制代码
    // 共享库中的缓存管理
    @Library('jenkins-shared-library') _
    
    def buildWithCache(Map config) {
        def cacheKey = generateCacheKey(config)
        def cacheHit = false
        
        stage('Cache Check') {
            script {
                // 检查缓存是否存在
                cacheHit = checkCache(cacheKey)
                if (cacheHit) {
                    echo "缓存命中: ${cacheKey}"
                    restoreCache(cacheKey)
                } else {
                    echo "缓存未命中,开始构建"
                }
            }
        }
        
        if (!cacheHit) {
            stage('Build') {
                script {
                    // 执行构建
                    config.buildSteps()
                    
                    // 保存缓存
                    saveCache(cacheKey, config.cachePatterns)
                }
            }
        }
    }
    
    def generateCacheKey(Map config) {
        // 基于文件内容生成缓存键
        def checksums = []
        
        config.cacheFiles.each { file ->
            if (fileExists(file)) {
                def checksum = sh(
                    script: "sha256sum ${file} | cut -d' ' -f1",
                    returnStdout: true
                ).trim()
                checksums.add(checksum)
            }
        }
        
        def combinedChecksum = sh(
            script: "echo '${checksums.join(',')}' | sha256sum | cut -d' ' -f1",
            returnStdout: true
        ).trim()
        
        return "${config.projectName}-${combinedChecksum}"
    }
    
    def checkCache(String cacheKey) {
        // 检查S3或其他缓存存储
        def exitCode = sh(
            script: "aws s3 ls s3://jenkins-cache/${cacheKey}.tar.gz",
            returnStatus: true
        )
        return exitCode == 0
    }
    
    def restoreCache(String cacheKey) {
        sh """
            aws s3 cp s3://jenkins-cache/${cacheKey}.tar.gz cache.tar.gz
            tar -xzf cache.tar.gz
            rm cache.tar.gz
        """
    }
    
    def saveCache(String cacheKey, List patterns) {
        def files = patterns.join(' ')
        sh """
            tar -czf cache.tar.gz ${files}
            aws s3 cp cache.tar.gz s3://jenkins-cache/${cacheKey}.tar.gz
            rm cache.tar.gz
        """
    }
    
    // 使用示例
    pipeline {
        agent any
        
        stages {
            stage('Build with Cache') {
                steps {
                    script {
                        buildWithCache([
                            projectName: 'my-app',
                            cacheFiles: ['pom.xml', 'package.json', 'requirements.txt'],
                            cachePatterns: ['~/.m2/repository', 'node_modules', '.venv'],
                            buildSteps: {
                                sh 'mvn clean package'
                                sh 'npm install'
                                sh 'pip install -r requirements.txt'
                            }
                        ])
                    }
                }
            }
        }
    }

资源管理优化

动态节点管理:

groovy 复制代码
// 智能节点分配脚本
@Library('jenkins-shared-library') _

def allocateOptimalNode(Map requirements) {
    def availableNodes = getAvailableNodes()
    def optimalNode = selectOptimalNode(availableNodes, requirements)
    
    if (optimalNode) {
        return optimalNode
    } else {
        // 动态创建节点
        return createDynamicNode(requirements)
    }
}

def getAvailableNodes() {
    def nodes = []
    
    Jenkins.instance.computers.each { computer ->
        if (computer.isOnline() && !computer.isTemporarilyOffline()) {
            def node = computer.getNode()
            def executor = computer.getExecutors().find { !it.isBusy() }
            
            if (executor) {
                nodes.add([
                    name: node.getNodeName(),
                    labels: node.getLabelString().split(' '),
                    cpu: getNodeCpuUsage(computer),
                    memory: getNodeMemoryUsage(computer),
                    disk: getNodeDiskUsage(computer),
                    load: getNodeLoad(computer)
                ])
            }
        }
    }
    
    return nodes
}

def selectOptimalNode(List nodes, Map requirements) {
    // 过滤满足标签要求的节点
    def candidateNodes = nodes.findAll { node ->
        requirements.labels.every { label ->
            node.labels.contains(label)
        }
    }
    
    if (candidateNodes.isEmpty()) {
        return null
    }
    
    // 计算节点得分
    def scoredNodes = candidateNodes.collect { node ->
        def score = calculateNodeScore(node, requirements)
        [node: node, score: score]
    }
    
    // 选择得分最高的节点
    def bestNode = scoredNodes.max { it.score }
    return bestNode.node
}

def calculateNodeScore(Map node, Map requirements) {
    def score = 0
    
    // CPU得分(使用率越低得分越高)
    score += (100 - node.cpu) * 0.3
    
    // 内存得分
    score += (100 - node.memory) * 0.3
    
    // 磁盘得分
    score += (100 - node.disk) * 0.2
    
    // 负载得分
    score += Math.max(0, 100 - node.load * 20) * 0.2
    
    // 特殊要求加分
    if (requirements.preferSSD && node.labels.contains('ssd')) {
        score += 10
    }
    
    if (requirements.preferHighCpu && node.labels.contains('high-cpu')) {
        score += 10
    }
    
    return score
}

def createDynamicNode(Map requirements) {
    // 基于需求创建云节点
    def nodeTemplate = selectNodeTemplate(requirements)
    def cloudName = nodeTemplate.cloud
    
    // 触发节点创建
    def cloud = Jenkins.instance.getCloud(cloudName)
    def provisionedNode = cloud.provision(nodeTemplate, 1)
    
    // 等待节点上线
    waitForNodeOnline(provisionedNode.name, 300) // 5分钟超时
    
    return provisionedNode
}

def selectNodeTemplate(Map requirements) {
    def templates = [
        [
            name: 'small-node',
            cloud: 'aws-ec2',
            instanceType: 't3.medium',
            labels: ['linux', 'docker'],
            cpu: 2,
            memory: 4
        ],
        [
            name: 'medium-node',
            cloud: 'aws-ec2',
            instanceType: 't3.large',
            labels: ['linux', 'docker', 'maven'],
            cpu: 2,
            memory: 8
        ],
        [
            name: 'large-node',
            cloud: 'aws-ec2',
            instanceType: 't3.xlarge',
            labels: ['linux', 'docker', 'high-cpu'],
            cpu: 4,
            memory: 16
        ]
    ]
    
    // 选择满足需求的最小模板
    def suitableTemplates = templates.findAll { template ->
        template.cpu >= requirements.minCpu &&
        template.memory >= requirements.minMemory &&
        requirements.labels.every { label ->
            template.labels.contains(label)
        }
    }
    
    return suitableTemplates.min { it.cpu + it.memory }
}

// 使用示例
pipeline {
    agent none
    
    stages {
        stage('Lightweight Tasks') {
            agent {
                label allocateOptimalNode([
                    labels: ['linux', 'docker'],
                    minCpu: 1,
                    minMemory: 2,
                    preferSSD: false
                ]).name
            }
            steps {
                sh 'echo "Running on optimized node"'
            }
        }
        
        stage('Heavy Compilation') {
            agent {
                label allocateOptimalNode([
                    labels: ['linux', 'maven', 'high-cpu'],
                    minCpu: 4,
                    minMemory: 8,
                    preferSSD: true,
                    preferHighCpu: true
                ]).name
            }
            steps
相关推荐
七夜zippoe5 小时前
CANN Runtime任务描述序列化与持久化源码深度解码
大数据·运维·服务器·cann
Fcy6486 小时前
Linux下 进程(一)(冯诺依曼体系、操作系统、进程基本概念与基本操作)
linux·运维·服务器·进程
袁袁袁袁满6 小时前
Linux怎么查看最新下载的文件
linux·运维·服务器
代码游侠7 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
Harvey9037 小时前
通过 Helm 部署 Nginx 应用的完整标准化步骤
linux·运维·nginx·k8s
珠海西格电力科技8 小时前
微电网能量平衡理论的实现条件在不同场景下有哪些差异?
运维·服务器·网络·人工智能·云计算·智慧城市
释怀不想释怀8 小时前
Linux环境变量
linux·运维·服务器
zzzsde8 小时前
【Linux】进程(4):进程优先级&&调度队列
linux·运维·服务器
yuanmenghao9 小时前
Linux 性能实战 | 第 7 篇 CPU 核心负载与调度器概念
linux·网络·性能优化·unix
聆风吟º10 小时前
CANN开源项目实战指南:使用oam-tools构建自动化故障诊断与运维可观测性体系
运维·开源·自动化·cann