第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調優

內存配置優化

堆內存配置:

# 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

內存分析腳本:

#!/bin/bash
# jenkins_memory_analysis.shJENKINS_PID=$(pgrep -f jenkins.war)if [ -z "$JENKINS_PID" ]; thenecho "Jenkins進程未找到"exit 1
fiecho "=== 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]$ ]]; thenDUMP_FILE="/tmp/jenkins_heapdump_$(date +%Y%m%d_%H%M%S).hprof"echo "生成堆轉儲文件: $DUMP_FILE"jcmd $JENKINS_PID GC.run_finalizationjcmd $JENKINS_PID VM.memoryjhsdb jmap --heap --pid $JENKINS_PID
fi# 內存使用趨勢分析
echo "=== 內存使用趨勢(最近10次采樣) ==="
for i in {1..10}; doecho "采樣 $i:"jstat -gc $JENKINS_PID | tail -1sleep 5
done

垃圾回收優化

G1GC調優配置:

# 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分析腳本:

#!/usr/bin/env python3
# gc_analysis.pyimport re
import sys
from datetime import datetime
from collections import defaultdictclass GCAnalyzer:def __init__(self, log_file):self.log_file = log_fileself.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系統優化:

#!/bin/bash
# jenkins_system_tuning.shecho "=== 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
EOFecho "系統優化完成,建議重啟系統使所有設置生效"

性能監控腳本:

#!/bin/bash
# jenkins_performance_monitor.shLOG_FILE="/var/log/jenkins/performance.log"
INTERVAL=60  # 監控間隔(秒)# 創建日志目錄
mkdir -p $(dirname $LOG_FILE)echo "Jenkins性能監控啟動,日志文件: $LOG_FILE"
echo "監控間隔: ${INTERVAL}秒"while true; doTIMESTAMP=$(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; thenHEAP_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")elseHEAP_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) )); thenecho "[$TIMESTAMP] 警告: CPU使用率過高 ${CPU_USAGE}%" | tee -a $LOG_FILEfiif (( $(echo "$MEM_PERCENT > 85" | bc -l) )); thenecho "[$TIMESTAMP] 警告: 內存使用率過高 ${MEM_PERCENT}%" | tee -a $LOG_FILEfiif [ "$FD_COUNT" -gt 50000 ]; thenecho "[$TIMESTAMP] 警告: 文件描述符使用過多 $FD_COUNT" | tee -a $LOG_FILEfiif [ "$DISK_USAGE" -gt 85 ]; thenecho "[$TIMESTAMP] 警告: 磁盤使用率過高 ${DISK_USAGE}%" | tee -a $LOG_FILEfielseecho "[$TIMESTAMP] Jenkins進程未運行" >> $LOG_FILEfisleep $INTERVAL
done

存儲優化

磁盤配置優化:

#!/bin/bash
# jenkins_storage_optimization.shecho "=== 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 {dailymissingokrotate 30compressdelaycompressnotifemptycopytruncatesu jenkins jenkins
}/var/log/jenkins/*.log {dailymissingokrotate 30compressdelaycompressnotifemptycopytruncatesu 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=7echo "開始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_HOMEecho "Jenkins目錄大小:"
du -sh $JENKINS_HOME
EOFchmod +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
EOFecho "存儲優化配置完成"

存儲監控腳本:

#!/usr/bin/env python3
# jenkins_storage_monitor.pyimport os
import sys
import json
import time
from datetime import datetime
from pathlib import Pathclass 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 = 0try: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):continueexcept (OSError, IOError):passreturn total_sizedef get_disk_usage(self, path):"""獲取磁盤使用情況"""try:statvfs = os.statvfs(path)total = statvfs.f_frsize * statvfs.f_blocksfree = statvfs.f_frsize * statvfs.f_availableused = total - freereturn {'total': total,'used': used,'free': free,'usage_percent': (used / total) * 100 if total > 0 else 0}except OSError:return Nonedef 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 = 0for dir_name in directories_to_check:dir_path = self.jenkins_home / dir_nameif dir_path.exists():size = self.get_directory_size(dir_path)total_jenkins_size += sizereport['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 reportdef _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'] = recommendationsdef 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 reportif __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性能優化

并行化優化策略:

// 高性能Pipeline示例
pipeline {agent noneoptions {// 構建保留策略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'}}}
}

資源池管理:

// 資源池管理腳本
class ResourcePoolManager {def jenkins = Jenkins.instancedef 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 nonestages {stage('Build') {steps {script {resourceManager.requestResource('build') {node('build') {sh 'mvn clean package'}}}}}}
}

13.5 網絡優化

帶寬優化

網絡配置優化:

#!/bin/bash
# jenkins_network_optimization.shecho "=== 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
EOFsysctl -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_typestext/plaintext/csstext/xmltext/javascriptapplication/jsonapplication/javascriptapplication/xml+rssapplication/atom+xmlimage/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 nginxecho "網絡優化配置完成"

CDN配置:

# cloudfront-jenkins.yml
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Jenkins CDN配置'Parameters:JenkinsOrigin:Type: StringDefault: 'jenkins.company.com'Description: 'Jenkins服務器域名'Resources:JenkinsCDN:Type: AWS::CloudFront::DistributionProperties:DistributionConfig:Enabled: trueComment: 'Jenkins CDN Distribution'Origins:- Id: jenkins-originDomainName: !Ref JenkinsOriginCustomOriginConfig:HTTPPort: 443HTTPSPort: 443OriginProtocolPolicy: https-onlyOriginSSLProtocols:- TLSv1.2DefaultCacheBehavior:TargetOriginId: jenkins-originViewerProtocolPolicy: redirect-to-httpsAllowedMethods:- GET- HEAD- OPTIONS- PUT- POST- PATCH- DELETECachedMethods:- GET- HEAD- OPTIONSCompress: trueForwardedValues:QueryString: trueHeaders:- Authorization- Host- X-Forwarded-For- X-Forwarded-ProtoCookies:Forward: allDefaultTTL: 0MaxTTL: 31536000MinTTL: 0CacheBehaviors:# 靜態資源緩存- PathPattern: '*.css'TargetOriginId: jenkins-originViewerProtocolPolicy: redirect-to-httpsAllowedMethods: [GET, HEAD]CachedMethods: [GET, HEAD]Compress: trueForwardedValues:QueryString: falseHeaders: []DefaultTTL: 86400MaxTTL: 31536000MinTTL: 0- PathPattern: '*.js'TargetOriginId: jenkins-originViewerProtocolPolicy: redirect-to-httpsAllowedMethods: [GET, HEAD]CachedMethods: [GET, HEAD]Compress: trueForwardedValues:QueryString: falseHeaders: []DefaultTTL: 86400MaxTTL: 31536000MinTTL: 0- PathPattern: '*.png'TargetOriginId: jenkins-originViewerProtocolPolicy: redirect-to-httpsAllowedMethods: [GET, HEAD]CachedMethods: [GET, HEAD]Compress: falseForwardedValues:QueryString: falseHeaders: []DefaultTTL: 2592000MaxTTL: 31536000MinTTL: 0PriceClass: PriceClass_100ViewerCertificate:AcmCertificateArn: !Ref SSLCertificateSslSupportMethod: sni-onlyMinimumProtocolVersion: TLSv1.2_2021SSLCertificate:Type: AWS::CertificateManager::CertificateProperties:DomainName: !Sub 'cdn.${JenkinsOrigin}'ValidationMethod: DNSOutputs:CDNDomainName:Description: 'CloudFront域名'Value: !GetAtt JenkinsCDN.DomainNameExport:Name: !Sub '${AWS::StackName}-CDN-Domain'

連接優化

連接池配置:

// 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集成腳本:

#!/bin/bash
# jenkins_profiling.shJPROFILER_HOME="/opt/jprofiler"
JENKINS_PID=$(pgrep -f jenkins.war)if [ -z "$JENKINS_PID" ]; thenecho "Jenkins進程未找到"exit 1
fiecho "=== 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)
EOFecho "性能分析完成,文件保存在 /tmp/ 目錄"
ls -la /tmp/jenkins_*

自動化調優腳本:

#!/usr/bin/env python3
# jenkins_auto_tuning.pyimport os
import re
import json
import subprocess
from datetime import datetime, timedeltaclass 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 Truedef 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 recommendationsdef 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_changesdef _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 Noneexcept:return Nonedef _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 0except:return 0def _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 0return {'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:passreturn {}def _parse_uptime(self, uptime_str):"""解析進程運行時間"""# 格式: [[DD-]HH:]MM:SSparts = uptime_str.split(':')seconds = 0if len(parts) == 2:  # MM:SSseconds = int(parts[0]) * 60 + int(parts[1])elif len(parts) == 3:  # HH:MM:SSseconds = int(parts[0]) * 3600 + int(parts[1]) * 60 + int(parts[2])elif '-' in uptime_str:  # DD-HH:MM:SSday_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 secondsdef _get_response_time(self):"""獲取響應時間"""try:import timeimport urllib.requeststart_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 0def _get_queue_length(self):"""獲取構建隊列長度"""try:import urllib.requestimport jsonresponse = urllib.request.urlopen('http://localhost:8080/queue/api/json', timeout=5)data = json.loads(response.read().decode())return len(data.get('items', []))except:return 0def _increase_heap_size(self):"""增加堆內存大小"""# 這里應該修改Jenkins啟動腳本# 實際實現需要根據具體的部署方式print("建議增加堆內存大小到當前的1.5倍")return Truedef _tune_gc_parameters(self):"""調整GC參數"""print("建議調整GC參數以減少GC時間")return Truedef _increase_executors(self):"""增加執行器數量"""print("建議增加執行器數量以提高并發處理能力")return Truedef run(self):"""運行自動調優"""print("=== Jenkins自動調優開始 ===")# 收集指標if not self.collect_metrics():print("無法收集性能指標")returnprint(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("? 系統性能良好,無需調優")returnprint(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.BRANCHN?AME]],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 = falsestage('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.gztar -xzf cache.tar.gzrm 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.gzrm cache.tar.gz"""
}// 使用示例
pipeline {agent anystages {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'}])}}}}
}

資源管理優化

動態節點管理:

// 智能節點分配腳本
@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 nonestages {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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/95850.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/95850.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/95850.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python+DRVT 從外部調用 Revit:批量創建梁

今天讓我們繼續&#xff0c;看看如何批量創建常用的基礎元素&#xff1a;梁。 跳過軸線為直線段形的&#xff0c;先從圓弧形的開始&#xff1a; from typing import List, Tuple import math # drvt_pybind 支持多會話、多文檔&#xff0c;先從簡單的單會話、單文檔開始 # My…

水上樂園票務管理系統設計與開發(代碼+數據庫+LW)

摘 要 隨著旅游業的蓬勃發展&#xff0c;水上樂園作為夏日娛樂的重要組成部分&#xff0c;其票務管理效率和服務質量直接影響游客體驗。然而&#xff0c;傳統的票務管理模式往往面臨信息更新不及時、服務響應慢等問題。因此&#xff0c;本研究旨在通過設計并實現一個基于Spri…

【前端教程】JavaScript DOM 操作實戰案例詳解

案例1&#xff1a;操作div子節點并修改樣式與內容 功能說明 獲取div下的所有子節點&#xff0c;設置它們的背景顏色為紅色&#xff1b;如果是p標簽&#xff0c;將其內容設置為"我愛中國"。 實現代碼 <!DOCTYPE html> <html> <head><meta ch…

qiankun+vite+react配置微前端

微前端框架&#xff1a;qiankun。 主應用&#xff1a;react19vite7&#xff0c;子應用1&#xff1a;react19vite7&#xff0c;子應用2 &#xff1a;react19vite7 一、主應用 1. 安裝依賴 pnpm i qiankun 2. 注冊子應用 (1) 在src目錄下創建個文件夾&#xff0c;用來存儲關于微…

git: 取消文件跟蹤

場景&#xff1a;第一次初始化倉庫的時候沒有忽略.env或者node_modules&#xff0c;導致后面將.env加入.gitignore也不生效。 取消文件跟蹤&#xff1a;如果是因為 node_modules 已被跟蹤導致忽略無效&#xff0c; 可以使用命令git rm -r --cached node_modules來刪除緩存&…

開講啦|MBSE公開課:第五集 MBSE中期設想(下)

第五集 在本集課程中&#xff0c;劉玉生教授以MBSE建模工具選型及二次定制開發為核心切入點&#xff0c;系統闡釋了"為何需要定制開發"與"如何實施定制開發"的實踐邏輯&#xff0c;并提煉出MBSE中期實施的四大核心要素&#xff1a;高效高質建摸、跨域協同…

CSDN個人博客文章全面優化過程

兩天前達到博客專家申請條件&#xff0c;興高采烈去申請博客專家&#xff1a; 結果今天一看&#xff0c;申請被打回了&#xff1a; 我根據“是Yu欸”大神的博客&#xff1a; 【2024-完整版】python爬蟲 批量查詢自己所有CSDN文章的質量分&#xff1a;附整個實現流程_抓取csdn的…

Websocket的Key多少個字節

在WebSocket協議中&#xff0c;握手過程中的Sec-WebSocket-Key是一個由客戶端生成的隨機字符串&#xff0c;用于安全地建立WebSocket連接。這個Sec-WebSocket-Key是基于Base64編碼的&#xff0c;并且通常由客戶端在WebSocket握手請求的頭部字段中發送。根據WebSocket協議規范&a…

SVT-AV1編碼器中實現WPP依賴管理核心調度

一 assign_enc_dec_segments 函數。這個函數是 SVT-AV1 編碼器中實現波前并行處理&#xff08;WPP&#xff09; 和分段依賴管理的核心調度器之一。//函數功能&#xff1a;分配編碼解碼段任務//返回值Bool//True 成功分配了一個段給當前線程&#xff0c;調用者應該處理這個段//F…

直接讓前端請求代理到自己的本地服務器,告別CV報文到自己的API工具,解放雙手

直接使用前端直接調用本地服務器&#xff0c;在自己的瀏覽器搜索插件proxyVerse&#xff0c;類似的插件應該還有一些&#xff0c;可以選擇自己喜歡的這類插件可以將瀏覽器請求&#xff0c;直接轉發到本地服務器&#xff0c;這樣在本地調試的時候&#xff0c;不需要前端項目&…

Golang Goroutine 與 Channel:構建高效并發程序的基石

在當今這個多核處理器日益普及的時代&#xff0c;利用并發來提升程序的性能和響應能力已經成為軟件開發的必然趨勢。而Go語言&#xff0c;作為一門為并發而生的語言&#xff0c;其設計哲學中將“并發”置于核心地位。其中&#xff0c;Goroutines 和 Channels 是Go實現并發編程的…

17 C 語言宏進階必看:從宏替換避坑到宏函數用法,不定參數模擬實現一次搞定

預處理詳解1. 預定義符號//C語?設置了?些預定義符號&#xff0c;可以直接使?&#xff0c;預定義符號也是在預處理期間處理的。 __FILE__ //進?編譯的源?件--預處理階段被替換成指向文件名字符串的指針--char* 類型的變量 __LINE__ //?件當前的?號 --預處理階段替換成使用…

深入剖析 HarmonyOS ArkUI 聲明式開發:狀態管理藝術與最佳實踐

好的&#xff0c;請看這篇關于 HarmonyOS ArkUI 聲明式開發范式與狀態管理的技術文章。 深入剖析 HarmonyOS ArkUI 聲明式開發&#xff1a;狀態管理藝術與最佳實踐 引言 隨著 HarmonyOS 4、5 的廣泛應用以及面向未來的 HarmonyOS NEXT&#xff08;API 12&#xff09;的發布&…

Qwen-Code安裝教程

一、概述Qwen Code 是一個強大的基于命令行、面向開發者的 AI 工作流工具&#xff0c;改編自 Gemini CLI&#xff0c;專門針對 Qwen3-Coder 模型進行了優化。它專門為代碼理解、代碼重構、自動化工作流、Git 操作等場景設計&#xff0c;讓你的開發工作變得更高效、更智能。它既…

老師傅一分鐘精準判斷電池好壞!就靠這個神器!

在汽車維修與保養領域&#xff0c;蓄電池狀態的準確判斷一直是技術人員面臨的重要挑戰。傳統的電壓測量方法只能反映表面現象&#xff0c;無法深入評估蓄電池的實際健康狀態。Midtronics MDX-P300蓄電池及電氣系統測試儀作為專業級診斷設備&#xff0c;通過電導測試技術和多系統…

Axure筆記

Axure介紹 快速原型的軟件 應用場景&#xff1a;拉投資、給項目團隊、銷售演示、項目投標、內部收集反饋、教學 軟件安裝與漢化 漢化&#xff1a;復制lang文件夾和三個dll 軟件的基礎功能 基本布局&#xff1a;菜單欄、工具欄、頁面和摘要、元件和母版、畫布、樣式交互和說明設…

Pytorch Yolov11 OBB 旋轉框檢測+window部署+推理封裝 留貼記錄

Pytorch Yolov11 OBB 旋轉框檢測window部署推理封裝 留貼記錄 上一章寫了下【Pytorch Yolov11目標檢測window部署推理封裝 留貼記錄】&#xff0c;這一章開一下YOLOV11 OBB旋轉框檢測相關的全流程&#xff0c;有些和上一章重復的地方我會簡寫&#xff0c;要兩篇結合著看&#x…

《Keil 開發避坑指南:STM32 頭文件加載異常與 RTE 配置問題全解決》

《Keil 開發避坑指南&#xff1a;STM32 頭文件加載異常與 RTE 配置問題全解決》文章提綱一、引言? 簡述 Keil 在 STM32 開發中的核心地位&#xff0c;指出頭文件加載和 RTE&#xff08;運行時環境&#xff09;配置是新手常遇且關鍵的問題&#xff0c;說明本文旨在為開發者提…

TortoiseGit 2.4.0.0 64位安裝教程(附詳細步驟和Git配置 附安裝包)

本教程詳細講解 ?TortoiseGit 2.4.0.0 64位版本? 的完整安裝步驟&#xff0c;包括如何運行 ?TortoiseGit-2.4.0.0-64bit.msi? 安裝包、設置安裝路徑、關聯 Git 環境&#xff0c;以及安裝后的基本配置方法&#xff0c;適合 Windows 用戶快速上手 Git 圖形化管理工具。 一、…

大數據畢業設計選題推薦-基于大數據的高級大豆農業數據分析與可視化系統-Hadoop-Spark-數據可視化-BigData

?作者主頁&#xff1a;IT畢設夢工廠? 個人簡介&#xff1a;曾從事計算機專業培訓教學&#xff0c;擅長Java、Python、PHP、.NET、Node.js、GO、微信小程序、安卓Android等項目實戰。接項目定制開發、代碼講解、答辯教學、文檔編寫、降重等。 ?文末獲取源碼? 精彩專欄推薦?…