Keepalived + HAProxy 高可用集群安装部署文档文档版本版本：v1.0本次用于环境：Kubernetes 高可用控制平面 VIP 管理1. 环境规划1.1 服务器信息主机名IP地址角色Keepalived优先级VIPnode1100.100.157.10负载均衡节点1101100.100.157.200node2100.100.157.11负载均衡节点2100100.100.157.200node3100.100.157.12负载均衡节点399100.100.157.2001.2 网络规划虚拟IP（VIP）：100.100.157.200/24服务端口：6443（Kubernetes API Server）VRRP组ID：51认证密码：k8svip2. 前置准备2.1 所有节点执行# 更新系统 apt update && apt upgrade -y # 安装必要工具 apt install -y curl wget vim net-tools nftables # 关闭防火墙或配置放行规则（生产环境建议配置精确规则） systemctl stop ufw systemctl disable ufw2.2 网络配置检查# 确认网卡名称（本环境为 ens34） ip addr show # 确认网络互通 ping -c 3 100.100.157.10 ping -c 3 100.100.157.11 ping -c 3 100.100.157.12 # 检查 VRRP 协议是否允许（协议号 112） nft list ruleset3. HAProxy 安装配置3.1 所有节点安装 HAProxy# 安装 HAProxy apt install -y haproxy # 检查版本 haproxy -v3.2 配置 HAProxy（所有节点配置相同）# 备份原配置 cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.bak # 创建新配置 cat > /etc/haproxy/haproxy.cfg << 'EOF' global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin stats timeout 30s user haproxy group haproxy daemon maxconn 4096 defaults log global mode tcp # Kubernetes API 使用 TCP 模式 option tcplog # TCP 日志格式 option dontlognull timeout connect 5s timeout client 30s timeout server 30s retries 3 # 统计页面（可选） frontend stats bind *:8404 stats enable stats uri /stats stats refresh 10s stats admin if LOCALHOST # Kubernetes API Server 负载均衡 frontend k8s-api bind *:6443 mode tcp default_backend k8s-api-backend backend k8s-api-backend mode tcp balance roundrobin option tcp-check tcp-check connect port 6443 ssl tcp-check send "PING\r\n" tcp-check expect string "pong" server node1 100.100.157.10:6443 check fall 3 rise 2 inter 2000 weight 1 server node2 100.100.157.11:6443 check fall 3 rise 2 inter 2000 weight 1 server node3 100.100.157.12:6443 check fall 3 rise 2 inter 2000 weight 1 EOF3.3 验证配置并启动 HAProxy# 验证配置文件语法 haproxy -c -f /etc/haproxy/haproxy.cfg # 创建 haproxy 用户（如果不存在） id haproxy || useradd -r haproxy # 创建必要的目录 mkdir -p /var/lib/haproxy chown -R haproxy:haproxy /var/lib/haproxy # 启动并设置开机自启 systemctl start haproxy systemctl enable haproxy systemctl status haproxy # 检查端口监听 ss -tlnp | grep 6443 ss -tlnp | grep 84044. Keepalived 安装配置4.1 所有节点安装 Keepalived# 安装 Keepalived apt install -y keepalived # 检查版本 keepalived --version4.2 节点差异化配置node1 (100.100.157.10) 配置# 创建配置文件 cat > /etc/keepalived/keepalived.conf << 'EOF' ! Configuration File for keepalived - Kubernetes HA Control Plane VIP global_defs { router_id K8S_VIP_NODE1 vrrp_skip_check_adv_addr #vrrp_strict # 生产环境建议启用，但需要配置防火墙 enable_script_security script_user root max_auto_priority } vrrp_script chk_haproxy { script "/bin/sh -c '/usr/bin/pgrep haproxy > /dev/null 2>&1'" interval 2 weight 2 fall 3 rise 2 timeout 2 user root } vrrp_instance VI_K8S_API { state BACKUP # 所有节点都设为 BACKUP，通过优先级选举 interface ens34 # 根据实际网卡名修改 virtual_router_id 51 # 所有节点必须相同 priority 101 # node1 优先级最高 advert_int 1 authentication { auth_type PASS auth_pass k8svip # 所有节点密码相同 } # 单播模式配置（避免多播/广播问题） unicast_src_ip 100.100.157.10 # 本机 IP unicast_peer { 100.100.157.11 # node2 100.100.157.12 # node3 } virtual_ipaddress { 100.100.157.200/24 dev ens34 label ens34:vip } track_script { chk_haproxy } # 非抢占模式，避免频繁切换 nopreempt preempt_delay 300 # 状态切换通知脚本（可选） # notify /etc/keepalived/notify.sh # notify_master "/etc/keepalived/notify.sh master" # notify_backup "/etc/keepalived/notify.sh backup" # notify_fault "/etc/keepalived/notify.sh fault" # 调试日志（生产环境可关闭） debug } EOFnode2 (100.100.157.11) 配置# 与 node1 配置基本相同，只修改以下参数： # router_id K8S_VIP_NODE2 # unicast_src_ip 100.100.157.11 # priority 100node3 (100.100.157.12) 配置# 与 node1 配置基本相同，只修改以下参数： # router_id K8S_VIP_NODE3 # unicast_src_ip 100.100.157.12 # priority 994.3 启动并验证 Keepalived# 验证配置文件语法 keepalived -t -f /etc/keepalived/keepalived.conf # 启动 Keepalived systemctl start keepalived systemctl enable keepalived systemctl status keepalived # 查看实时日志 journalctl -u keepalived -f5. 功能验证5.1 基础功能验证# 检查 VIP 绑定（应该在 MASTER 节点上） ip addr show ens34 | grep 100.100.157.200 # 检查 Keepalived 状态 systemctl status keepalived # 检查 HAProxy 状态 systemctl status haproxy # 检查端口监听 ss -tlnp | grep -E '(6443|8404)' # 查看进程 ps aux | grep -E '(keepalived|haproxy)'5.2 故障切换测试# 1. 查看当前 MASTER 节点 cat /var/log/syslog | grep "Entering MASTER" | tail -1 # 2. 停止当前 MASTER 节点的 Keepalived systemctl stop keepalived # 3. 查看哪个节点接管了 VIP（等待约10秒） ip addr show ens34 | grep 100.100.157.200 # 4. 恢复原 MASTER 节点 systemctl start keepalived # 5. 验证是否保持当前状态（因为配置了 nopreempt） # 6. 切换选举日志 journalctl -u keepalived -f Jan 16 15:45:15 hxy Keepalived[41811]: Startup complete Jan 16 15:45:15 hxy systemd[1]: Started keepalived.service - Keepalive Daemon (LVS and VRRP). Jan 16 15:45:15 hxy Keepalived_vrrp[41812]: (VI_K8S_API) Entering BACKUP STATE (init) Jan 16 15:45:15 hxy Keepalived_vrrp[41812]: VRRP_Script(chk_haproxy) succeeded Jan 16 15:45:15 hxy Keepalived_vrrp[41812]: (VI_K8S_API) Changing effective priority from 100 to 102 Jan 16 15:45:15 hxy Keepalived_vrrp[41812]: (VI_K8S_API) received lower priority (101) advert from 100.100.157.10 - discarding Jan 16 15:45:16 hxy Keepalived_vrrp[41812]: (VI_K8S_API) received lower priority (101) advert from 100.100.157.10 - discarding Jan 16 15:45:17 hxy Keepalived_vrrp[41812]: (VI_K8S_API) received lower priority (101) advert from 100.100.157.10 - discarding Jan 16 15:45:18 hxy Keepalived_vrrp[41812]: (VI_K8S_API) received lower priority (101) advert from 100.100.157.10 - discarding Jan 16 15:45:18 hxy Keepalived_vrrp[41812]: (VI_K8S_API) Entering MASTER STATE Jan 16 15:47:47 hxy Keepalived_vrrp[41812]: (VI_K8S_API) Master received advert from 100.100.157.10 with higher priority 103, ours 102 Jan 16 15:47:47 hxy Keepalived_vrrp[41812]: (VI_K8S_API) Entering BACKUP STATE 5.3 HAProxy 健康检查测试# 测试 HAProxy 统计页面 curl http://100.100.157.200:8404/stats # 测试负载均衡功能 for i in {1..10}; do echo "请求 $i: $(curl -k -s https://100.100.157.200:6443/healthz 2>/dev/null || echo 'failed')" done # 查看 HAProxy 后端状态 echo "show stat" | socat /run/haproxy/admin.sock stdio6. QA故障排除6.1 常见问题及解决方案问题1：VIP 未绑定# 检查 Keepalived 状态 systemctl status keepalived journalctl -u keepalived -f # 手动检查 VIP ip addr show ens34 # 检查防火墙是否阻止 VRRP nft list ruleset | grep vrrp问题2：脚本检查失败# 手动测试健康检查脚本 /bin/sh -c '/usr/bin/pgrep haproxy > /dev/null 2>&1' echo $? # 检查 haproxy 进程 pgrep haproxy systemctl status haproxy问题3：节点间通信问题# 测试节点间通信 ping -c 3 100.100.157.11 ping -c 3 100.100.157.12 # 检查防火墙规则 nft list ruleset # 检查 VRRP 单播配置 grep -A5 "unicast_" /etc/keepalived/keepalived.conf问题4：频繁主备切换# 检查优先级配置 grep priority /etc/keepalived/keepalived.conf # 检查网络延迟 ping -c 10 100.100.157.11 | grep rtt # 调整 advert_int（增加通告间隔） # advert_int 27.日志分析# 查看完整日志 journalctl -u keepalived --no-pager -n 100 # 过滤重要信息 journalctl -u keepalived | grep -E "(MASTER|BACKUP|FAULT|priority|advert)" # 实时监控 journalctl -u keepalived -f8. 灾难恢复# 如果所有节点都故障，按以下顺序恢复： # 1. 启动 haproxy systemctl start haproxy # 2. 启动 keepalived systemctl start keepalived # 3. 检查 VIP 绑定 ip addr show ens34 | grep 100.100.157.200 # 4. 验证服务 curl -k https://100.100.157.200:6443/healthz9. 附录9.1 配置文件汇总HAProxy 配置文件路径主配置：/etc/haproxy/haproxy.cfg备份配置：/etc/haproxy/haproxy.cfg.backupKeepalived 配置文件路径主配置：/etc/keepalived/keepalived.conf备份配置：/etc/keepalived/keepalived.conf.backup通知脚本：/etc/keepalived/notify.sh
ESXi 虚拟机克隆（CLI方式）适用于 VMware ESXi 免费版 / 独立主机（无 vCenter），通过 shell 命令实现完整克隆（full clone），避免 UUID/MAC 冲突，确保新 VM 可独立启动。相对于vmware略微麻烦些，ui控制台没有直接克隆的方式，也有可能是我不会哈哈哈。适用场景：没有 vCenter，无法使用图形界面 Clone。需要快速复制 VM 用于测试、备份或扩容。源 VM 已关机（重要！运行中文件被锁定，无法 vmkfstools）。前提条件源 VM 已关机（power off）。已启用 ESXi Shell / SSH（Host → Actions → Services → Enable Secure Shell (SSH)）。有足够 datastore 空间（克隆会复制磁盘数据）。登录为 root（或有足够权限）。步骤总结以 devops-1 → devops-2 示例启用exsi shell查找源 VM 位置find / -name devops-1 # 输出示例：/vmfs/volumes/696858b1-809ba051-0a8c-000c29018345/devops-1进入 datastore 并创建目标目录cd /vmfs/volumes/696858b1-809ba051-0a8c-000c29018345/ mkdir devops-2 cd devops-2复制 .vmx 配置文件cp ../devops-1/devops-1.vmx ./devops-2.vmx克隆虚拟磁盘vmkfstools -i ../devops-1/devops-1.vmdk ./devops-2.vmdk # 或推荐 thin 节省空间（如果源是 thick，也可转 thin） # vmkfstools -i ../devops-1/devops-1.vmdk ./devops-2.vmdk -d thin # 进度显示 100% done. 即完成可选参数说明：-d thin：薄配置（thin provisioning），节省空间，但 I/O 稍慢。-d zeroedthick：默认，预零厚配置-d eagerzeroedthick：预零厚，适合高性能/故障转移场景。编辑 devops-2.vmx 文件（关键步骤！）用 sed 批量替换：sed -i 's/devops-1/devops-2/g' devops-2.vmx这会替换所有出现 "devops-1" 的地方，包括：displayName = "devops-1" → "devops-2"scsi0:0.fileName = "devops-1.vmdk" → "devops-2.vmdk"uuid.bios / uuid.location 等（自动生成新 UUID，避免冲突注册新虚拟机到 ESXi 库附件：自动化克隆脚本#!/bin/sh # ESXi VM 批量克隆 - 指定起始和结束编号版 # 用法示例: # ./clone_vms.sh /vmfs/volumes/696858b1-... devops-1 devops 3 6 # → 克隆出 devops-3 devops-4 devops-5 devops-6 if [ $# -ne 5 ]; then echo "用法: $0 <datastore_path> <source_vm_name> <target_prefix> <start_num> <end_num>" echo "示例:" echo " $0 /vmfs/volumes/696858b1-809ba051-0a8c-000c29018345 devops-1 devops 3 6" echo " → 生成 devops-3 到 devops-6" exit 1 fi DATASTORE_PATH="$1" SOURCE_VM="$2" TARGET_PREFIX="$3" START_NUM="$4" END_NUM="$5" cd "$DATASTORE_PATH" || { echo "无法进入 $DATASTORE_PATH"; exit 1; } [ -d "$SOURCE_VM" ] || { echo "源目录 $SOURCE_VM 不存在"; exit 1; } for i in $(seq "$START_NUM" "$END_NUM"); do TARGET_VM="${TARGET_PREFIX}-${i}" echo "正在克隆: $SOURCE_VM → $TARGET_VM" mkdir -p "$TARGET_VM" || { echo "创建 $TARGET_VM 失败"; continue; } cp "$SOURCE_VM/$SOURCE_VM.vmx" "$TARGET_VM/$TARGET_VM.vmx" || { echo "复制 vmx 失败"; continue; } vmkfstools -i "$SOURCE_VM/$SOURCE_VM.vmdk" "$TARGET_VM/$TARGET_VM.vmdk" || { echo "克隆磁盘失败"; continue; } # 替换 vmx 内容 sed -i "s/${SOURCE_VM}/${TARGET_VM}/g" "$TARGET_VM/$TARGET_VM.vmx" sed -i '/ethernet.*addressType/d' "$TARGET_VM/$TARGET_VM.vmx" 2>/dev/null sed -i '/ethernet.*generatedAddress/d' "$TARGET_VM/$TARGET_VM.vmx" 2>/dev/null sed -i '/uuid/d' "$TARGET_VM/$TARGET_VM.vmx" 2>/dev/null echo "完成: $TARGET_VM （已替换内容）" done echo "" echo "全部克隆完成。" echo "下一步：对每个新 VM 执行注册，例如：" echo "vim-cmd solo/registervm ${DATASTORE_PATH}/devops-3/devops-3.vmx"
Ubuntu 24.04 使用 Netplan 配置静态 IP适用于：Ubuntu Server 24.04、Ubuntu Desktop 24.04（使用 netplan 的版本）配置文件路径（常见位置）： /etc/netplan/示例配置文件（双网卡静态 IP）network: version: 2 renderer: networkd # 或 NetworkManager（桌面版常用） ethernets: ens34: # 第一块网卡（名称根据实际情况） dhcp4: false addresses: - 192.168.1.3/24 # IP地址/子网掩码（CIDR表示法） routes: - to: default via: 192.168.1.1 # 默认网关 nameservers: addresses: - 8.8.8.8 - 8.8.4.4 ens35: # 第二块网卡 dhcp4: false addresses: - 192.168.2.3/24 routes: - to: 10.0.0.0/8 via: 192.168.2.1 # 指向特定网段的静态路由 # on-link: true # 可选：如果下一跳不在本地子网常用参数说明参数说明是否必填示例值备注versionNetplan 配置格式版本，目前稳定使用 2必填2不要使用 1renderer后端渲染器选填networkd/NetworkManagerServer 推荐 networkd，桌面推荐 NMdhcp4/dhcp6是否开启 IPv4/IPv6 DHCP必填（静态时设 false）false/true静态 IP 必须设为 falseaddresses本机要绑定的 IP 地址列表（支持多个）静态必填- 192.168.1.3/24CIDR 格式，必带 /24 或 /20 等routes.to目标网络选填default或10.0.0.0/8default表示默认路由routes.via下一跳网关 IP选填192.168.1.1默认网关必填routes.metric路由优先级（数值越小优先级越高）选填100 / 200用于多网关场景nameservers.addressesDNS 服务器列表推荐- 8.8.8.8 - 114.114.114.114至少填一个，否则可能无法解析域名link-local是否启用链路本地地址（169.254.x.x / fe80::）选填[ipv4, ipv6]/[]默认启用，可设为空禁用optional是否为可选接口（开机时不等待该接口 ready 就继续启动）选填true用于次要网卡（如内网口）操作步骤编辑配置文件sudo nano /etc/netplan/00-installer-config.yaml检查语法sudo netplan generate sudo netplan try # 120秒内可回滚正式应用sudo netplan apply验证ip -c addr show ip route ping 8.8.8.8 ping www.google.com
灾备容灾体系建设一、背景在当前数字信息化建设中，数据是核心资产。无论是数据中台的运行、数字孪生的建模，还是数字可视化的展示，都需要依赖高质量的数据支持。然而，硬件故障、软件错误、网络攻击、自然灾害等不可预见的因素，都可能导致系统崩溃或数据丢失。灾备演练的核心目标是验证企业在突发情况下的应对能力，确保在最短时间内恢复业务运行，最大限度地减少损失。为保障业务连续性和数据安全性，公司亟需建立健全的灾备容灾体系，确保在突发事件发生时，能够快速检测故障并将业务切换至备用系统，将业务中断时间（RTO）和数据丢失量（RPO）控制在可接受范围内。1. 当前现状云上系统：无同城/异地灾备，依赖单地域单可用区或多可用区但未做应用级容灾云下系统：完全单点，无任何本地或异地备份环境数据库、中间件、静态资源均无跨地域备份与恢复机制缺乏灾备切换SOP与演练，RTO/RPO 未定义且实际趋近于无穷大2. 期望效果为云上、云下两套生产系统分别建设一套灾备环境，实现以下核心目标：目标项具体指标要求每套生产系统拥有独立灾备云上生产 → 云上灾备 （异地云/多云）/ 云下生产 → 云下灾备(异地数据中心)数据恢复点目标（RPO）核心数据库 ≤ 3 分钟（DTS数据通过/binlog复制）关键文件/对象存储 ≤ 5 小时业务恢复时间目标（RTO）关键系统 ≤ 5 分钟切换方式手动切换（DNS/负载均衡/全局流量调度）或可升级为半自动/自动切换演练频率每半年至少进行一次完整切换演练并出具报告回切能力具备支持故障修复后平滑回切至原生产环境最终效果： 无论云上生产还是云下生产发生整体故障，都能在可控时间内将其业务与数据快速切换/恢复到各自的灾备环境，对外服务不中断或极短中断，真正做到“两套系统各自有后路”。二、灾备方案1.主流方案排名方案名称RPO / RTO 典型值成本（相对生产）优点缺点1异地主备（Global Active-Passive）RPO ≤ 5分钟 / RTO 30秒～3分钟1.2～1.6倍改造最小、切换最可靠、演练最简单、100%过等保/监管/审计、成本最低RTO 无法做到秒级，极端情况下有几十秒到几分钟中断2同城双活 + 异地主备（2+1）RPO ≤ 1分钟 / RTO 10秒～1分钟1.8～2.5倍同城基本无感、异地仍有可靠兜底、监管最认可的“高级灾备”模式需要同城两套完整环境，建设和网络要求高，成本明显上升3异地双活/多活（单元化）RPO ≈ 0 / RTO ≤ 5秒2.5～4倍用户完全无感知、真正“业务不停”、极端场景下仍可扛区域级故障技术复杂度极高、业务改造巨大、容易脑裂/双写、演练风险极大、成本最高4三中心两主一备（2主1备）RPO ≤ 1分钟 / RTO ≤ 30秒2.2～3倍两个主中心互为备份+异地灾备，三重保险，监管评分最高建设和运维复杂度高，两个主中心要保持强一致，实际落地和演练都很难5同城双活 + 异地异步容灾RPO ≤ 15分钟 / RTO ≤ 4小时1.5～2倍过渡方案，同城做到高可用，异地成本低异地恢复时间长（几小时），属于“冷灾备”，不满足大部分监管要求2.方案选举2.1 主备灾备技术通常采用一主一备的架构，故障时需切换，用户可能感知等待时间。在这种架构下，主备之间无法同时在线，一旦系统出现问题，需要进行架构切换，用户可能会面临系统切换的等候时间。2.2 双活双活技术通过两套同时在线的架构互为灾备，实现无缝切换，确保业务连续性。双活技术采用两套同时在线的架构，互相作为对方的灾备。这种设计确保在主架构出现问题时，另一套双活架构能够无缝接管，实现无缝切换，用户无感知。三、灾备的难点及解决方案1.主备1.1 数据一致性问题2.双活
一、背景介绍近一年内对公司的 ELK 日志系统做过性能优化，也对 SkyWalking 使用的 ES 存储进行过性能优化，在此做一些总结。本篇主要是讲 ES 在 ELK 架构中作为日志存储时的性能优化方案。ELK 架构作为日志存储方案二、现状分析1. 版本及硬件配置JDK：JDK1.8\_171-b11 (64 位)ES集群：由3台16核32G的虚拟机部署 ES 集群，每个节点分配 20 G 堆内存ELK版本：6.3.0垃圾回收器：ES 默认指定的老年代（CMS）+ 新生代（ParNew）操作系统：CentOS Linux release 7.4.1708(Core)2. 性能问题随着接入 ELK 的应用越来越多，每日新增索引约 230 个，新增 document 约 3000 万到 5000 万。每日上午和下午是日志上传高峰期，在 Kibana 上查看日志，发现问题：(1) 日志会有 5-40 分钟的延迟(2) 有很多日志丢失，无法查到3. 问题分析3.1 日志延迟首先了解清楚：数据什么时候可以被查到？数据先是存放在 ES 的内存 buffer，然后执行 refresh 操作写入到操作系统的内存缓存 os cache，此后数据就可以被搜索到。所以，日志延迟可能是我们的数据积压在 buffer 中没有进入 os cache 。3.2 日志丢失查看日志发现很多 write 拒绝执行的情况write 线程池拒绝任务的日志.png从日志中可以看出 ES 的 write 线程池已经满负荷，执行任务的线程已经达到最大 16 个线程，而 200 容量的队列也已经放不下新的 task。查看线程池的情况也可以看出 write 线程池有很多写入的任务GET /_cat/thread_pool?v&h=host,name,type,size,active,largest,rejected,completed,queue,queue_sizewrite 线程池拒绝任务的情况.png所以我们需要优化 ES 的 write 的性能。4.解决思路4.1 分析场景ES 的优化分为很多方面，我们要根据使用场景考虑对 ES 的要求。根据个人实践经验，列举三种不同场景下的特点：SkyWalking：一般配套使用 ES 作为数据存储，存储链路追踪数据、指标数据等信息。ELK：一般用来存储系统日志，并进行分析，搜索，定位应用的问题。全文搜索的业务：业务中常用 ES 作为全文搜索引擎，例如在外卖应用中，ES 用来存储商家、美食的业务数据，用户在客户端可以根据关键字、地理位置等查询条件搜索商家、美食信息。这三类场景的特点如下： SkyWalkingELK全文搜索的业务并发写高并发写高并发写并发一般不高并发读并发低并发低并发高实时性要求5分钟以内30秒以内1分钟内数据完整性可容忍丢失少量数据可容忍丢失少量数据数据尽量100%不丢失关于实时性SkyWalking 在实际使用中，一般使用频率不太高，往往是发现应用的问题后，再去 SkyWalking 查历史链路追踪数据或指标数据，所以可以接受几分钟的延迟。ELK 不管是开发、测试等阶段，时常用来定位应用的问题，如果不能快速查询出数据，延迟太久，会耽误很多时间，大大降低工作效率；如果是查日志定位生产问题，那更是刻不容缓。全文搜索的业务中一般可以接受在1分钟内查看到最新数据，比如新商品上架一分钟后才看到，但尽量实时，在几秒内可以可看到。4.2 优化的方向可以从三方面进行优化：JVM 性能调优、ES 性能调优、控制数据来源三、ES性能优化可以从三方面进行优化：JVM 性能调优、ES 性能调优、控制数据来源1. JVM调优第一步是 JVM 调优。因为 ES 是依赖于 JVM 运行，没有合理的设置 JVM 参数，将浪费资源，甚至导致 ES 很容易 OOM 而崩溃。1.1 监控 JVM 运行情况（1）查看 GC 日志问题：Young GC 和 Full GC 都很频繁，特别是 Young GC 频率高，累积耗时非常多。(2) 使用 jstat 看下每秒的 GC 情况参数说明S0：幸存1区当前使用比例S1：幸存2区当前使用比例E：伊甸园区使用比例O：老年代使用比例M：元数据区使用比例CCS：压缩使用比例YGC：年轻代垃圾回收次数FGC：老年代垃圾回收次数FGCT：老年代垃圾回收消耗时间GCT：垃圾回收消耗总时间问题：从 jstat gc 中也可以看出，每秒的 eden 增长速度非常快，很快就满了。1.2 定位 Young GC 频繁的原因1.2.1 检查是否新生代的空间是否太小用下面几种方式都可查看新、老年代内存大小 (1) 使用 jstat -gc pid 查看 Eden 区、老年代空间大小 (2) 使用 jmap -heap pid 查看 Eden 区、老年代空间大小 (3) 查看 GC 日志中的 GC 明细其中 996800K 为新生代可用空间大小，即 Eden 区 +1 个 Survivor 区的空间大小，所以新生代总内存是996800K/0.9， 约1081M上面的几种方式都查询出，新生代总内存约1081M，即1G左右；老年代总内存为19864000K，约19G。新、老比例约1:19，出乎意料。1.2.1 新老年代空间比例为什么不是 JDK 默认的1:2【重点！】这真是一个容易踩坑的地方。如果没有显示设置新生代大小，JVM 在使用 CMS 收集器时会自动调参，新生代的大小在没有设置的情况下是通过计算得出的，其大小可能与 NewRatio 的默认配置没什么关系而与 ParallelGCThreads 的配置有一定的关系。参考文末链接：CMS GC 默认新生代是多大？所以：新生代大小有不确定性，最好配置 JVM 参数 -XX:NewSize、-XX:MaxNewSize 或者 -xmn ，免得遇到一些奇怪的 GC，让人措手不及。1.3 上面现象造成的影响新生代过小，老年代过大的影响新生代过小: (1) 会导致新生代 Eden 区很快用完，而触发 Young GC，Young GC 的过程中会 STW(Stop The World)，也就是所有工作线程停止，只有 GC 的线程在进行垃圾回收，这会导致 ES 短时间停顿。频繁的 Young GC，积少成多，对系统性能影响较大。(2) 大部分对象很快进入老年代，老年代很容易用完而触发 Full GC。老年代过大：会导致 Full GC 的执行时间过长，Full GC 虽然有并行处理的步骤，但是还是比 Young GC 的 STW 时间更久，而 GC 导致的停顿时间在几十毫秒到几秒内，很影响 ES 的性能，同时也会导致请求 ES 服务端的客户端在一定时间内没有响应而发生 timeout 异常，导致请求失败。1.4 JVM优化1.4.1 配置堆内存空间大小32G 的内存，分配 20G 给堆内存是不妥当的，所以调整为总内存的50%，即16G。修改 elasticsearch 的 jvm.options 文件-Xms16g -Xmx16g设置要求:Xms 与 Xmx 大小相同。在 jvm 的参数中 -Xms 和 -Xmx 设置的不一致，在初始化时只会初始 -Xms 大小的空间存储信息，每当空间不够用时再向操作系统申请，这样的话必然要进行一次 GC，GC会带来 STW。而剩余空间很多时，会触发缩容。再次不够用时再扩容，如此反复，这些过程会影响系统性能。同理在 MetaSpace 区也有类似的问题。jvm 建议不要超过 32G，否则 jvm 会禁用内存对象指针压缩技术，造成内存浪费Xmx 和 Xms 不要超过物理 RAM 的50%。参考文末：官方堆内存设置的建议Xmx 和 Xms 不要超过物理内存的50%。Elasticsearch 需要内存用于JVM堆以外的其他用途，为此留出空间非常重要。例如，Elasticsearch 使用堆外缓冲区进行有效的网络通信，依靠操作系统的文件系统缓存来高效地访问文件，而 JVM 本身也需要一些内存。1.4.2 配置堆内存新生代空间大小因为指定新生代空间大小，导致 JVM 自动调参只分配了 1G 内存给新生代。修改 elasticsearch 的 jvm.options 文件，加上-XX:NewSize=8G -XX:MaxNewSize=8G老年代则自动分配 16G-8G=8G 内存，新生代老年代的比例为 1:1。修改后每次 Young GC 频率更低，且每次 GC 后只有少数数据会进入老年代。2.3 使用G1垃圾回收器(未实践)G1垃圾回收器让系统使用者来设定垃圾回收堆系统的影响，然后把内存拆分为大量的小 Region，追踪每个 Region 中可以回收的对象大小和回收完成的预计花费的时间， 最后在垃圾回收的时候，尽量把垃圾回收对系统造成的影响控制在我们指定的时间范围内，同时在有限的时间内尽量回收更多的垃圾对象。G1垃圾回收器一般在大数量、大内存的情况下有更好的性能。ES默认使用的垃圾回收器是：老年代（CMS）+ 新生代（ParNew）。如果是JDK1.9，ES 默认使用 G1 垃圾回收器。因为使用的是 JDK1.8，所以并未切换垃圾回收器。后续如果再有性能问题再切换G1垃圾回收器，测试是否有更好的性能。1.5 优化的效果1.5.1 新生代使用内存的增长率更低优化前优化前.png每秒打印一次 GC 数据。可以看出，年轻代增长速度很快，几秒钟年轻代就满了，导致 Young GC 触发很频繁，几秒钟就会触发一次。而每次 Young GC 很大可能有存活对象进入老年代，而且，存活对象多的时候(看上图中第一个红框中的old gc数据)，有(51.44-51.08)/100 * 19000M = 约68M。每次进入老年代的对象较多，加上频繁的 Young GC，会导致新老年代的分代模式失去了作用，相当于老年代取代了新生代来存放近期内生成的对象。当老年代满了，触发 Full GC，存活的对象也会很多，因为这些对象很可能还是近期加入的，还存活着，所以一次 Full GC 回收对象不多。而这会恶性循环，老年代很快又满了，又 Full GC，又残留一大部分存活的，又很容易满了，所以导致一直频繁 Full GC。优化后优化后.png每秒打印一次 GC 数据。可以看出，新生代增长速度慢了许多，至少要 60 秒才会满，如上图红框中数据，进入老年代的对象约(15.68-15.60)/100 * 10000 = 8M，非常的少。所以要很久才会触发一次 Full GC 。而且等到 Full GC 时，老年代里很多对象都是存活了很久的，一般都是不会被引用，所以很大一部分会被回收掉，留一个比较干净的老年代空间，可以继续放很多对象。1.5.2 新生代和老年代 GC 频率更低ES 启动后，运行14个小时优化前优化前.pngYoung GC 每次的时间是不长的，从上面监控数据中可以看出每次GC时长 1467.995/27276 约等于 0.05 秒。那一秒钟有多少时间是在处理 Young GC ?计算公式：1467 秒/( 60 秒× 60 分 14 小时）= 约 0.028 秒，也就是 100 秒中就有 2.8 秒在Young GC，也就是有 2.8S 的停顿，这对性能还是有很大消耗的。同时也可以算出多久一次 Young GC， 方程是：60秒×60分*14小时/ 27276次 = 1次/X秒，计算得出X = 0.54，也就是 0.54 秒就会有一次 Young GC，可见 Young GC 频率非常频繁。优化后优化后效果.pngYoung GC 次数只有修改前的十分之一，Young GC 时间也是约八分之一。Full GC 的次数也是只有原来的八分之一，GC 时间大约是四分之一。GC 对系统的影响大大降低，性能已经得到很大的提升。2.ES 调优上面已经分析过 ES 作为日志存储时的特性是：高并发写、读少、接受 30 秒内的延时、可容忍部分日志数据丢失。下面我们针对这些特性对ES进行调优。2.1 优化 ES 索引设置2.2.1 ES 写数据底层原理ES写入数据的原理.pngrefresh ES 接收数据请求时先存入 ES 的内存中，默认每隔一秒会从内存 buffer 中将数据写入操作系统缓存 os cache，这个过程叫做 refresh；到了 os cache 数据就能被搜索到（所以我们才说 ES 是近实时的，因为 1 s 的延迟后执行 refresh 便可让数据被搜索到）fsync translog 会每隔 5 秒或者在一个变更请求完成之后执行一次 fsync 操作，将 translog 从缓存刷入磁盘，这个操作比较耗时，如果对数据一致性要求不是很高时建议将索引改为异步，如果节点宕机时会有5秒数据丢失;flush ES 默认每隔30分钟会将 os cache 中的数据刷入磁盘同时清空 translog 日志文件，这个过程叫做 flush。mergeES 的一个 index 由多个 shard 组成，而一个 shard 其实就是一个 Lucene 的 index ，它又由多个 segment 组成，且 Lucene 会不断地把一些小的 segment 合并成一个大的 segment ，这个过程被称为段merge（参考文末链接）。执行索引操作时，ES 会先生成小的segment，ES 有离线的逻辑对小的 segment 进行合并，优化查询性能。但是合并过程中会消耗较多磁盘 IO，会影响查询性能。2.2.2 优化方向2.2.2.1 优化 fsync为了保证不丢失数据，就要保护 translog 文件的安全:Elasticsearch 2.0 之后, 每次写请求(如 index 、delete、update、bulk 等)完成时, 都会触发fsync将 translog 中的 segment 刷到磁盘, 然后才会返回200 OK的响应;或者: 默认每隔5s就将 translog 中的数据通过fsync强制刷新到磁盘.该方式提高数据安全性的同时， 降低了一点性能.==> 频繁地执行 fsync 操作, 可能会产生阻塞导致部分操作耗时较久. 如果允许部分数据丢失, 可设置异步刷新 translog 来提高效率，还有降低 flush 的阀值，优化如下："index.translog.durability": "async", "index.translog.flush_threshold_size":"1024mb", "index.translog.sync_interval": "120s"2.2.2.2 优化 refresh写入 Lucene 的数据，并不是实时可搜索的，ES 必须通过 refresh 的过程把内存中的数据转换成 Lucene 的完整 segment 后，才可以被搜索。默认 1秒后，写入的数据可以很快被查询到，但势必会产生大量的 segment，检索性能会受到影响。所以，加大时长可以降低系统开销。对于日志搜索来说，实时性要求不是那么高，设置为 5 秒或者 10s；对于 SkyWalking，实时性要求更低一些，我们可以设置为 30s。设置如下："index.refresh_interval":"5s"2.2.2.3 优化 mergeindex.merge.scheduler.max\_thread\_count 控制并发的 merge 线程数，如果存储是并发性能较好的 SSD，可以用系统默认的 max(1, min(4, availableProcessors / 2))，当节点配置的 cpu 核数较高时，merge 占用的资源可能会偏高，影响集群的性能，普通磁盘的话设为1，发生磁盘 IO 堵塞。设置max\_thread\_count 后，会有 max\_thread\_count + 2 个线程同时进行磁盘操作，也就是设置为 1 允许3个线程。设置如下："index.merge.scheduler.max_thread_count":"1"2.2.2 优化设置2.2.2.1 对现有索引做索引设置# 需要先 close 索引,然后再执行,最后成功之后再打开 # 关闭索引 curl -XPOST 'http://localhost:9200/_all/_close' # 修改索引设置 curl -XPUT -H "Content-Type:application/json" 'http://localhost:9200/_all/_settings?preserve_existing=true' -d '{"index.merge.scheduler.max_thread_count" : "1","index.refresh_interval" : "10s","index.translog.durability" : "async","index.translog.flush_threshold_size":"1024mb","index.translog.sync_interval" : "120s"}' # 打开索引 curl -XPOST 'http://localhost:9200/_all/_open'该方式可对已经生成的索引做修改，但是对于后续新建的索引不生效，所以我们可以制作 ES 模板，新建的索引按模板创建索引。2.2.2.2 制作索引模板# 制作模板 大部分索引都是业务应用的日志相关的索引，且索引名称是 202* 这种带着日期的格式 PUT _template/business_log { "index_patterns": ["*202*.*.*"], "settings": { "index.merge.scheduler.max_thread_count" : "1","index.refresh_interval" : "5s","index.translog.durability" : "async","index.translog.flush_threshold_size":"1024mb","index.translog.sync_interval" : "120s"} } # 查询模板是否创建成功 GET _template/business_log因为我们的业务日志是按天维度创建索引，索引名称示例：user-service-prod-2020.12.12，所以用通配符**202.*.**匹配对应要创建的业务日志索引。2.2 优化线程池配置前文已经提到过，write 线程池满负荷，导致拒绝任务，而有的数据无法写入。而经过上面的优化后，拒绝的情况少了很多，但是还是有拒绝任务的情况。所以我们还需要优化 write 线程池。从 prometheus 监控中可以看到线程池的情况：为了更直观看到 ES 线程池的运行情况，我们安装了 elasticsearch\_exporter 收集 ES 的指标数据到 prometheus，再通过 grafana 进行查看。经过上面的各种优化，拒绝的数据量少了很多，但是还是存在拒绝的情况，如下图：write 线程池如何设置：参考文末链接：ElasticSearch线程池writeFor single-document index/delete/update and bulk requests. Thread pool type is fixed with a size of # of available processors, queue\_size of 200. The maximum size for this pool is 1 + # of available processors.write 线程池采用 fixed 类型的线程池，也就是核心线程数与最大线程数值相同。线程数默认等于 cpu 核数，可设置的最大值只能是 cpu 核数加 1，也就是 16 核 CPU，能设置的线程数最大值为 17。优化的方案：线程数改为 17，也就是 cpu 总核数加 1队列容量加大。队列在此时的作用是消峰。不过队列容量加大本身不会提升处理速度，只是起到缓冲作用。此外，队列容量也不能太大，否则积压很多任务时会占用过多堆内存。config/elasticsearch.yml文件增加配置# 线程数设置 thread_pool: write: # 线程数默认等于cpu核数，即16 size: 17 # 因为任务多时存在任务拒绝的情况，所以加大队列大小，可以在间歇性任务量陡增的情况下，缓存任务在队列，等高峰过去逐步消费完。 queue_size: 10000优化后效果：可以看到，已经没有拒绝的情况，这样也就是解决了日志丢失的问题。2.３ 锁定内存，不让 JVM 使用 SwapSwap 交换分区:当系统的物理内存不够用的时候，就需要将物理内存中的一部分空间释放出来，以供当前运行的程序使用。那些被释放的空间可能来自一些很长时间没有什么操作的程序，**这些被释放的空间被临时保存到 Swap 中，等到那些程序要运行时，再从 Swap 中恢复保存的数据到内存中。**这样，系统总是在物理内存不够时，才进行 Swap 交换。参考文末链接：ElasticSearch官方解释为什么要禁用交换内存Swap 交换分区对性能和节点稳定性非常不利，一定要禁用。它会导致垃圾回收持续几分钟而不是几毫秒，并会导致节点响应缓慢，甚至与集群断开连接。有三种方式可以实现 ES 不使用 Swap 分区2.3.1 Linux 系统中的关闭 Swap (临时有效)执行命令sudo swapoff -a可以临时禁用 Swap 内存，但是操作系统重启后失效2.3.2 Linux 系统中的尽可能减少 Swap 的使用(永久有效)执行下列命令echo "vm.swappiness = 1">> /etc/sysctl.conf正常情况下不会使用 Swap，除非紧急情况下才会 Swap。2.3.3 启用 bootstrap.memory\_lockconfig/elasticsearch.yml 文件增加配置#锁定内存，不让 JVM 写入 Swap，避免降低 ES 的性能 bootstrap.memory_lock: true2.4 减少分片数、副本数分片索引的大小取决于分片与段的大小，分片过小，可能导致段过小，进而导致开销增加；分片过大可能导致分片频繁 Merge，产生大量 IO 操作，影响写入性能。因为我们每个索引的大小在 15G 以下，而默认是 5 个分片，没有必要这么多，所以调整为 3 个。"index.number_of_shards": "3"分片的设置我们也可以配置在索引模板。副本数减少集群副本分片数，过多副本会导致 ES 内部写扩大。副本数默认为 1，如果某索引所在的 1 个节点宕机，拥有副本的另一台机器拥有索引备份数据，可以让索引数据正常使用。但是数据写入副本会影响写入性能。对于日志数据，有 1 个副本即可。对于大数据量的索引，可以设置副本数为0，减少对性能的影响。"index.number_of_replicas": "1"分片的设置我们也可以配置在索引模板。3.控制数据来源3.1 应用按规范打印日志有的应用 1 天生成 10G 日志，而一般的应用只有几百到 1G。一天生成 10G 日志一般是因为部分应用日志使用不当，很多大数量的日志可以不打，比如大数据量的列表查询接口、报表数据、debug 级别日志等数据是不用上传到日志服务器，这些即影响日志存储的性能，更影响应用自身性能。四、ES性能优化后的效果优化后的两周内 ELK 性能良好，没有使用上的问题：ES 数据不再丢失数据延时在 10 秒之内，一般在 5 秒可以查出每个 ES 节点负载比较稳定，CPU 和内存使用率都不会过高，如下图
Filebeat+Kafka+Logstash+Elasticsearch构建日志分析系统在现代分布式系统中，日志管理是至关重要的一环。日志不仅用于排查问题，还可以用于监控系统性能、分析用户行为等。为了高效地收集、处理和可视化日志，企业通常采用 Filebeat + Kafka + Logstash + Elasticsearch + Kibana 的组合架构。本文将深入探讨这一架构的工作原理、优势、适用场景以及实现步骤。组件介绍2.1 Filebeat• 功能：轻量级的日志收集工具，专为日志文件设计。• 特点：低资源消耗、支持多种输入输出、易于部署。• 适用场景：收集应用日志、系统日志等。2.2 Kafka• 功能：分布式消息队列，用于解耦数据生产和消费。• 特点：高吞吐量、低延迟、持久化存储、可扩展。• 适用场景：缓冲日志数据、解耦日志收集和数据处理。2.3 Logstash• 功能：数据管道工具，用于收集、过滤、转换和输出数据。• 特点：强大的插件生态系统、支持复杂的数据处理。• 适用场景：日志解析、数据格式化、数据过滤。2.4 Elasticsearch• 功能：分布式搜索引擎，用于存储和索引数据。• 特点：实时搜索、高扩展性、支持全文搜索。• 适用场景：日志存储、实时数据分析。2.5 Kibana• 功能：数据可视化工具，用于查询和展示 Elasticsearch 中的数据。• 特点：丰富的图表类型、交互式仪表盘、易于使用。• 适用场景：日志可视化、监控仪表盘。流程图组件交互详解Filebeat 收集日志并发送到 KafkaFilebeat 是一个轻量级的日志收集器，安装在各个日志源节点（如 Web 服务器、应用程序、容器等）上。Filebeat 的主要功能是读取日志文件并将其发送到 Logstash 或 Kafka。配置 Filebeat 发送到 Kafka： 在 Filebeat 配置文件 filebeat.yml 中，你可以设置 Kafka 输出配置，将日志发送到 Kafka 集群中的特定主题。Filebeat 配置示例：filebeat.inputs: - type: log enabled: true paths: - /var/log/*.log output.kafka: hosts: ["kafka_host:9092"] topic: "logs_topic" codec: jsonKafka 作为消息队列Kafka 在日志收集过程中充当消息队列的角色，将日志数据从 Filebeat 转发到 Logstash。Kafka 作为一个可靠的缓冲层，能够缓解高负载、网络延迟等问题。Kafka 接收 Filebeat 发送的日志，并将其存储在一个或多个分区（broker）中。它支持高吞吐量、持久化和容错，保证日志数据不会丢失。logstash 从kafka消费数据并处理logstash可以配置为kafka消费者，定期从kafka中读取日志数据。logstash可以对数据进行过滤、解析、转换等操作，处理后的数据会被转发到elasticsearch配置logstash从kafka消费数据：在logstash配置文件中，使用kafka input plugin来从kafka中读取数据，并使用elasticsearh output plugin将数据发送到elasticsearchlogstash 配置实例input { kafka { bootstrap_servers => "kafka_host:9092" topics => ["logs_topic"] group_id => "logstash-group" } } filter { # 可在这里进行数据过滤、解析和转换 json { source => "message" } } output { elasticsearch { hosts => ["http://elasticsearch_host:9200"] index => "logs-index-%{+YYYY.MM.dd}" } }kafka 输入插件从kafka中读取数据json过滤将日志数据解析为json格式（假设日志数据是json格式的）elasticsearch输出插件将处理后的数据发送到elasticsearchelasticsearch 存储和索引日志elasticsearch将logstash发送的数据存储为索引文档，并提供快速搜索和聚合功能。可以通过kibana或其他工具查询elasticsearch中的数据elasticseach会对日志数据进行倒排索引，使得可以非常高效的进行全文搜索和数据分析数据会根据指定的索引模版或者动态索引进行映射，并根据需求进行实时分析和可视化示意图+----------+ Kafka +----------+ Elasticsearch | Filebeat| --------> | Logstash | ------------> | Elasticsearch | +----------+ +----------+ +---------------+各组件的优点和作用filebeat： 轻量级、资源占用低的日志采集工具，支持各种日志源的监控（文件、容器等）。filebeat的优点是快速启动，低延迟，能够高效的将日志发送到kafkakafkka： 作为中间层的消息队列，kafka提供了数据流的缓冲、持久化、流量调节和高可用性。能够保障日志数据的可靠传输，即使elasticsearch和logstash暂时不可用，数据也不会丢失。logstash: 作为数据处理引擎，logstash能够处理复杂的日志解析、过滤、转换等任务。它还可以处理来自多种输入的数据流，支持多种输出（包括elasticsearch）elasticsearch：最终的存储和搜索引擎，支持日志数据的存储、索引和快速查询，支持复杂的聚合和可视化使用场景优点：解耦：通过kafka，filebeat和logstash之间的联系被解耦，增加了系统的灵活性。kafka的存在使得各个组件之间的依赖减少，提高了整体系统的可靠性高可用性和容错性：kafka和elasticsearch都具备高可用特性，可以处理大规模的数据流和高并发请求。kafka提供了数据持久化和复制，确保消息不会丢失灵活的流量调节：kafka可以在日志数据流量高峰时作为缓冲区，避免logstash和elasticsear被瞬间流量压垮实时处理：通过logstash和elasticsearch的集成，可以实现实时的日志分析和监控使用场景：大规模日志收集：由于适用分布式系统的日志收集中，kafka和filebeat可以高效的收集和转发日志数据，logstash负责日志处理，elasticsearch用于存储和分析日志实时监控和分析：通过elasticsearch提供的搜索和聚合功能，配合kibana，可以实现实时的日志分析、性能监控、故障排查等事件驱动架构：kafka作为事件队列，可以用于处理系统中产生的大量实时事件，数据可以流入elasticsearch进行分析总结通过将filebeat、kafka、logstash、elasticsearch结合使用，可以构建一个高效、可靠、可扩展的日志收集和分析系统。kafka在此架构中扮演着消息队列的角色，确保了数据传输的高吞吐量、可靠性和灵活性。logstash和elasticsearch提供了强大的数据处理、存储和分析能力调优建议logstash调优consumer\_threads（并发线程数）在logstash的kafka input插件中，consumer\_threads 是一个用于控制并发消费线程数量的参数。它影响logstash从kafka分区读取数据的效率和吞吐量基本概念1.作用：指定logstash从kafka消费数据时，使用的线程数量每个线程可以消费一个或多个kafka分区2.默认值：如果未设置，consumer\_threads默认值为1，即使用单线程消费3.调优点：增加consumer\_threads数量，可以提高数据消费的并发能力配置方式在losgstash.conf文件中配置kafka input插件时，可以添加consumer\_threads参数，例如：input { kafka { bootstrap_servers => "broker1:9092,broker2:9092" topics => ["your-topic"] group_id => "logstash-consumer-group" consumer_threads => 4 } } output { elasticsearch { hosts => ["http://es-host:9200"] index => "your-index-%{+YYYY.MM.dd}" } }注意事项1.线程数与kafka分区数的关系kafka的分区是消费并发度的上线每个线程最多只能处理一个分区如果consumer\_threads的值大于分区数，多余的线程会空闲实例topic有6个分区如果consumer\_threads设置为8，只有6个线程会实际工作，剩余2个线程闲置2.消费者组的分区分配如果有多个logstash实例（属于同一个consumer group），kafka会将分区分配到不同的logstash节点每个logstash节点使用自己的consumer\_threads参数处理分配它的区位3.线程数的合理设置避免设置过多的线程线程过多可能会导致上下文切换频繁，反而降低性能建议设置的线程数与分区数接近，但不要超过分区总数配置jvm内存logstash默认的jvm内存不能处理高吞吐场景建议：修改jvm.options 文件，增加堆内存-Xms4g -Xmx4g启用多管道多管道可以进行处理不通类型的数据建议：在piplines.yml配置多个管道，根据不同数据源或逻辑划分管道，提升吞吐量。- pipeline.id: pipeline1 path.config: "/etc/logstash/conf.d/pipeline1.conf" - pipeline.id: pipeline2 path.config: "/etc/logstash/conf.d/pipeline2.conf"调整批处理大小批处理大小决定了logstash每次从kafka消费的记录数建议：在kafka input配置中增加fetch\_min\_bytes 和 consumer\_threads。在output（如 Elasticsearch）中，增加批处理大小：flush\_size：定义每次批量发送的事件数量（默认值为 5000），批量大小太小可能导致性能下降，太大可能导致内存问题workers：定义用于并发处理的工作线程数（默认值为 1），适当增加可以提高吞吐量，但不要超过 Elasticsearch 节点的处理能力output { elasticsearch { hosts => ["http://es-host:9200"] index => "your-index" flush_size => 5000 workers => 4 } }配置持久队列当 Logstash 出现高负载时，内存队列可能会丢失数据。建议：启用持久队列，避免数据丢失queue.type: persisted queue.max_bytes: 2gbqueue.type: persisted启用 Logstash 的持久化队列。默认情况下，Logstash 使用的是内存队列（memory），所有数据缓存在内存中。而 persisted 队列会将数据缓存在磁盘上，避免因 Logstash 重启或崩溃导致数据丢失。queue.max\_bytes: 2gb设置持久化队列的最大容量为 2GB。当队列已满时，Logstash 会停止接收新的数据，直到队列有足够的空间。可以根据磁盘大小和流量需求调整此值。elasticsearch 调优1. index.number\_of\_shards作用：设置索引的分片数量。分片决定了数据如何分布在节点上。建议值：根据数据量和集群规模合理设置，可以设置为3-5个后果：分片数过少：单个分片过大，可能会导致查询和写入性能下降分片数过多：会增加开销，可能浪费资源并影响集群的稳定性2. index.number\_of\_replicas作用：设置每个索引的副本数量，用于数据冗余和提高查询性能建议值：建议设置为1到2个副本后果：副本数过少，节点故障时可能丢失数据，影响系统的高可用性副本数过多，会浪费存储空间并增加数据同步的负担3. index.refresh\_interval作用：控制索引的刷新频率，决定数据文档从内存刷新到磁盘的间隔时间建议值：可以适当增加刷新时间，设置为5秒或者10秒后果：刷新时间过段，频繁的刷新会增加io开销，影响写入性能刷新时间过长，查询时无法看到最新的数据，影响实时性4. indices.memory.index\_buffer\_size作用：设置索引时内存缓冲区大小，影响写入性能建议值：通常设置为物理内存的10%到15%后果：设置过小会导致频繁的磁盘io，影响写入性能如果过大会导致内存耗尽，影响其他操作的稳定性
OpenVPN原理及部署使用1. 简介 VPN技术通过密钥交换、封装、认证、加密手段在公共网络上建立起私密的隧道，保障传输数据的完整性、私密性和有效性。OpenVPN是近年来新出现的开放源码项目，实现了SSL VPN的一种解决方案。2.应用场景有一些类似这样的情形或需求：1、开发:通过OpenVPN让开发人员连接网站,进行开发测试(在家的时候)2、运维:通过OpenVPN让运维连接内网服务器,或者是连接JUMPSERVER在家里想进入公司网站的管理界面，但管理系统限制了仅允许来自公司IP可以访问想连接到某个特别网站的特别网络应用，但本地的ISP或路由节点不允许您去连接它本地的ISP或路由节点可能会监听您的数据而您不想被它拦截，想找一种可以跳过它的办法,您想访问的网站和应用是基于明文传输，但您希望这个线路是私密的和可靠的。这时候就需要用到VPN来实现。3.OpenVPN服务端配置3.1 环境准备serverIPopenvpn-server公网:100.100.1.1 内网:10.100.240.3client能访问Internet3.2 证书准备流程1) 安装openvpn服务端、证书创建工具#openvpn 服务端、证书工具安装 [root@openvpn-server ~]# yum install -y openvpn easy-rsa #证书工具目录 [root@openvpn-server ~]# rpm -ql easy-rsa /usr/share/easy-rsa/3.0.8/easyrsa ...2) 服务器充当权威机构，创建ca证书#路径太深，新建目录 [root@openvpn-server ~]# mkdir -p /opt/easy-rsa [root@openvpn-server ~]# cp -a /usr/share/easy-rsa/3.0.8/* /opt/easy-rsa/ [root@openvpn-server ~]# cp /usr/share/doc/easy-rsa-3.0.8/vars.example /opt/easy-rsa/vars #修改vars文件，配置默认参数值 [root@openvpn-server ~]# cat > /opt/easy-rsa/vars if [ -z "$EASYRSA_CALLER" ]; then echo "You appear to be sourcing an Easy-RSA 'vars' file." >&2 echo "This is no longer necessary and is disallowed. See the section called" >&2 echo "'How to use this file' near the top comments for more details." >&2 return 1 fi set_var EASYRSA_DN "cn_only" set_var EASYRSA_REQ_COUNTRY "CN" # 国家 set_var EASYRSA_REQ_PROVINCE "Beijing" # 省 set_var EASYRSA_REQ_CITY "ShangHai" # 城市 set_var EASYRSA_REQ_ORG "zxc.com" # 组织 set_var EASYRSA_REQ_EMAIL "123456@qq.com" # 邮箱 set_var EASYRSA_NS_SUPPORT "yes" EOF #配置完var后 检查 权威机构信息 [root@openvpn-server easy-rsa]# tree . |-- easyrsa |-- openssl-easyrsa.cnf |-- vars #var ca权威机构信息 `-- x509-types |-- ca |-- client |-- code-signing |-- COMMON |-- email |-- kdc |-- server `-- serverClient 1 directory, 11 files #初始化，会在当前目录创建PKI目录，用于存储证书 [root@openvpn-server easy-rsa]# ./easyrsa init-pki Note: using Easy-RSA configuration from: /opt/easy-rsa/vars #正在使用来自于vars init-pki complete; you may now create a CA or requests. #初始化完成 显示你可以尝试创建 CA证书 Your newly created PKI dir is: /opt/easy-rsa/pki #初始化后的目录在 pki下面 #创建根证书，会提示设置密码，用于ca对之后生成的server和client证书签名时使用，其他可默认 [root@openvpn-server easy-rsa]# ./easyrsa build-ca Note: using Easy-RSA configuration from: /opt/easy-rsa/vars Using SSL: openssl OpenSSL 1.0.2k-fips 26 Jan 2017 Enter New CA Key Passphrase: #密码1234 Re-Enter New CA Key Passphrase: #密码1234 Generating RSA private key, 2048 bit long modulus ..............+++ ...............................................+++ e is 65537 (0x10001) You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Common Name (eg: your user, host, or server name) [Easy-RSA CA]:zxc.com #域名即可 CA creation complete and you may now import and sign cert requests. Your new CA certificate file for publishing is at: /opt/easy-rsa/pki/ca.crt #查看ca证书和私钥 [root@openvpn-server easy-rsa]# tree pki/ pki/ |-- ca.crt #ca证书 |-- certs_by_serial |-- index.txt |-- index.txt.attr |-- issued |-- openssl-easyrsa.cnf |-- private | `-- ca.key #ca私钥 |-- renewed | |-- certs_by_serial | |-- private_by_serial | `-- reqs_by_serial |-- reqs |-- revoked | |-- certs_by_serial | |-- private_by_serial | `-- reqs_by_serial |-- safessl-easyrsa.cnf `-- serial 12 directories, 7 files 3) 创建server端证书#创建server端证书和私钥文件 # 创建请求文件及服务端私钥，gen-req请求文件、server可以自定义、nopass表示不加密私钥文件，其他可默认 [root@openvpn-server easy-rsa]# ./easyrsa gen-req server nopass Note: using Easy-RSA configuration from: /opt/easy-rsa/vars Using SSL: openssl OpenSSL 1.0.2k-fips 26 Jan 2017 Generating a 2048 bit RSA private key ....................................................+++ ......................................+++ writing new private key to '/opt/easy-rsa/pki/easy-rsa-5343.MYL42w/tmp.4slsGH' ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Common Name (eg: your user, host, or server name) [server]: Keypair and certificate request completed. Your files are: req: /opt/easy-rsa/pki/reqs/server.req #server.req 用于创建证书(证书资料) key: /opt/easy-rsa/pki/private/server.key #server私钥文件 #给server端证书签名，sign签名、第一个server是服务器类型、第二个server是需要签名的证书名称 #首先是对一些信息的确认，输入yes，然后输入创建ca根证书时设置的密码 [root@openvpn-server easy-rsa]# ./easyrsa sign server server Note: using Easy-RSA configuration from: /opt/easy-rsa/vars Using SSL: openssl OpenSSL 1.0.2k-fips 26 Jan 2017 You are about to sign the following certificate. Please check over the details shown below for accuracy. Note that this request has not been cryptographically verified. Please be sure it came from a trusted source or that you have verified the request checksum with the sender. Request subject, to be signed as a server certificate for 825 days: subject= commonName = server Type the word 'yes' to continue, or any other input to abort. Confirm request details: yes #输入yes Using configuration from /opt/easy-rsa/pki/easy-rsa-7938.RZEfrP/tmp.NCVg6D Enter pass phrase for /opt/easy-rsa/pki/private/ca.key: #输入创建ca时设置的密码 Check that the request matches the signature Signature ok The Subject's Distinguished Name is as follows commonName :ASN.1 12:'server' Certificate is to be certified until May 7 15:26:38 2026 GMT (825 days) Write out database with 1 new entries Data Base Updated Certificate created at: /opt/easy-rsa/pki/issued/server.crt #生成服务端证书 #验证是否创建了server的证书 [root@openvpn-server easy-rsa]# tree pki/ pki/ |-- ca.crt #ca证书 |-- certs_by_serial | `-- 63D708FF122452B7558651207A1AF01B.pem |-- index.txt |-- index.txt.attr |-- index.txt.attr.old |-- index.txt.old |-- issued | `-- server.crt #server证书 |-- openssl-easyrsa.cnf |-- private | |-- ca.key | `-- server.key #server私钥 |-- renewed | |-- certs_by_serial | |-- private_by_serial | `-- reqs_by_serial |-- reqs | `-- server.req |-- revoked | |-- certs_by_serial | |-- private_by_serial | `-- reqs_by_serial |-- safessl-easyrsa.cnf |-- serial `-- serial.old 12 directories, 14 files4) 创建client端证书#创建client端证书和私钥文件 # 创建请求文件及服务端私钥，gen-req请求文件、client可以自定义、nopass表示不加密私钥文件，其他可默认 [root@openvpn-server easy-rsa]# ./easyrsa gen-req client nopass Common Name (eg: your user, host, or server name) [client]: #直接回车 Keypair and certificate request completed. Your files are: req: /opt/easy-rsa/pki/reqs/client.req key: /opt/easy-rsa/pki/private/client.key #给client端证书签名，sign签名、第一个client是服务器类型、第二个client是需要签名的证书名称 #给client端证书签名时，首先是对一些信息的确认，可以输入yes，然后创建ca根证书时设置的密码 [root@openvpn-server easy-rsa]# ./easyrsa sign client client ...... Type the word 'yes' to continue, or any other input to abort. Confirm request details: yes Using configuration from /opt/easy-rsa/pki/easy-rsa-32687.69KFgb/tmp.y1hokA Enter pass phrase for /opt/easy-rsa/pki/private/ca.key: ...... Certificate created at: /opt/easy-rsa/pki/issued/client.crt5) 创建dh-pem算法文件和目录汇总#创建Diffie-Hellman文件，秘钥交换时的Diffie-Hellman算法 [root@openvpn-server easy-rsa]# ./easyrsa gen-dh ....... DH parameters of size 2048 created at /opt/easy-rsa/pki/dh.pem #目录汇总 [root@openvpn-server easy-rsa]# tree . |-- easyrsa |-- openssl-easyrsa.cnf |-- pki | |-- ca.crt #ca证书 | |-- certs_by_serial | | |-- 58D4C3BEB5AA4931D7CE3D9D0119C3CF.pem | | `-- 63D708FF122452B7558651207A1AF01B.pem | |-- dh.pem #df算法文件 | |-- index.txt | |-- index.txt.attr | |-- index.txt.attr.old | |-- index.txt.old | |-- issued | | |-- client.crt #client证书 | | `-- server.crt #server证书 | |-- openssl-easyrsa.cnf | |-- private | | |-- ca.key | | |-- client.key #客户端私钥 | | `-- server.key #服务端私钥 | |-- renewed | | |-- certs_by_serial | | |-- private_by_serial | | `-- reqs_by_serial | |-- reqs | | |-- client.req | | `-- server.req | |-- revoked | | |-- certs_by_serial | | |-- private_by_serial | | `-- reqs_by_serial | |-- safessl-easyrsa.cnf | |-- serial | `-- serial.old |-- vars `-- x509-types |-- ca |-- client |-- code-signing |-- COMMON |-- email |-- kdc |-- server `-- serverClient6) 小结1、创建vars文件(伪装ca机构),创建ca证书 build-ca2、创建server证书和私钥 gen-req server nopass sign server server3、创建client证书和私钥 gen-req client nopass sign client client4、dh.pem 文件3.3 服务端配置文件#配置文件中 各种路径默认相对于 /etc/openvpn [root@openvpn-server ~]# tree -F /etc/openvpn/ /etc/openvpn/ |-- client/ `-- server/ 2 directories, 0 files #服务端配置文件 [root@openvpn-server ~]# vim /etc/opnvpn/server/server.conf [root@openvpn-server server]# cat server.conf port 1194 #端口 proto udp #协议 dev tun #采用路由隧道模式tun ca ca.crt #ca证书文件位置 /etc/openvpn /etc/opnevpn/server cert server/server.crt #服务端公钥名称 /etc/openvpn key server/server.key #服务端私钥名称 /etc/openvpn dh server/dh.pem #加密算法文件, 交换证书 校验算法 /etc/openvpn server 192.168.1.0 255.255.255.0 #给客户端分配地址池(ip地址范围)，注意：不能和VPN服务器内网网段有相同 push "route 10.100.240.0 255.255.255.0" #客户端连接后,推送给客户端的路由规则 #客户端想访问10.100.240.0/24网段联系openvpn服务端 #ifconfig-pool-persist ipp.txt #地址池记录文件位置 未来让openvpn 客户端固定ip地址使用的. keepalive 10 120 #存活时间，10秒ping一次,120 如未收到响应则视为断线 max-clients 100 #最多允许100个客户端连接 status /var/log/openvpn-status.log #日志记录位置openvpn状态 log /var/log/openvpn.log #openvpn日志记录位置 verb 3 #verbose 日志输出级别 数字越大越详细最多11(debug) client-to-client #客户端与客户端之间支持通信 persist-key #通过keepalive检测超时后，重新启动VPN，不重新读取keys，保留第一次使用的keys 对私钥进行缓存. persist-tun #检测超时后，重新启动VPN，一直保持tun是linkup的。否则网络会先linkdown然后再linkup duplicate-cn #客户端密钥(证书和私钥)是否可以重复 #复制证书及密钥 [root@openvpn-server server]# sudo vim server.conf [root@openvpn-server server]# cd /opt/easy-rsa/pki/ [root@openvpn-server pki]# cp ca.crt /etc/openvpn/ [root@openvpn-server pki]# cp dh.pem /etc/openvpn/server/ [root@openvpn-server pki]# cp issued/server.crt private/server.key /etc/openvpn/server/ #修改systemctl 配置,因为新建的文件夹通过systemctl启动openvpn时找不到路径 [root@openvpn-server server]# cat /usr/lib/systemd/system/openvpn@.service [Unit] Description=OpenVPN Robust And Highly Flexible Tunneling Application On %I After=network.target [Service] Type=notify PrivateTmp=true ExecStart=/usr/sbin/openvpn --cd /etc/openvpn/ --config %i/%i.conf #增加%i即可，只修改这一行 #%i/%i 就是运行systemctl start openvpn@server时，会把@后面的server传给%i，就会读到server/server.conf [Install] WantedBy=multi-user.target #重新加载 [root@openvpn-server server]# systemctl daemon-reload #启动和加入开机自启 [root@openvpn-server server]# systemctl enable openvpn@server [root@openvpn-server server]# systemctl start openvpn@server #检查进程与端口 [root@openvpn-server openvpn]# ss -lntup |grep 1194 udp UNCONN 0 0 *:1194 *:* users:(("openvpn",pid=31362,fd=5)) [root@openvpn-server openvpn]# ps -ef |grep openvpn root 960 1 0 Feb02 ? 00:00:00 /sbin/dhclient -q -lf /var/lib/dhclient/dhclient--eth0.lease -pf /var/run/dhclient-eth0.pid -H openvpn-server eth0 root 31362 1 0 03:05 ? 00:00:00 /usr/sbin/openvpn --cd /etc/openvpn/ --config server/server.conf root 31912 10767 0 03:07 pts/1 00:00:00 grep --color=auto openvpn [root@openvpn-server openvpn]# ip a s tun0 3: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100 link/none inet 192.168.1.1 peer 192.168.1.2/32 scope global tun0 valid_lft forever preferred_lft forever inet6 fe80::6813:2c79:d971:d16e/64 scope link flags 800 valid_lft forever preferred_lft forever3.4 客户端配置文件1) windows#openvpn客户端下载：https://swupdate.openvpn.org/community/releases/OpenVPN-2.6.8-I001-amd64.msi #把需要的证书先放到client，方便下载 [root@openvpn-server openvpn]# cp /opt/easy-rsa/pki/private/client.key /opt/easy-rsa/pki/issued/client.crt /etc/openvpn/client/ #创建客户端配置文件 [root@openvpn-server openvpn]# cat /etc/openvpn/client/clinet.ovpn client #指定当前VPN是客户端 dev tun #使用tun隧道传输协议 proto udp #使用udp协议传输数据 remote 100.100.1.1 1194 #openvpn服务器IP地址（公网）、端口号 resolv-retry infinite #断线自动重新连接，在网络不稳定的情况下非常有用 nobind #不绑定本地特定的端口号 ca ca.crt #指定CA证书的文件路径 cert client.crt #指定当前客户端的证书文件路径 key client.key #指定当前客户端的私钥文件路径 verb 3 #指定日志文件的记录详细级别，可选0-9，等级越高日志内容越详细 persist-key #通过keepalive检测超时后，重新启动VPN，不重新读取keys，保留第一次使用的keys #安装完客户端 在C:\Program Files\OpenVPN\config\zxc.com\ ca.crt #ca证书 client.crt #客户端证书 client.key #客户端私钥 client.ovpn #客户端配置文件 类似于client.conf 有多个VPN，可以新建config\zxc1.com\目录2) OpenVPN客户端配置（linux端）root@openvpn-client ~]# cat /etc/openvpn/client/clinet.conf client #指定当前VPN是客户端 dev tun #使用tun隧道传输协议 proto udp #使用udp协议传输数据 remote 100.100.1.1 1194 #openvpn服务器IP地址（公网）、端口号 resolv-retry infinite #断线自动重新连接，在网络不稳定的情况下非常有用 nobind #不绑定本地特定的端口号 ca ca.crt #指定CA证书的文件路径 cert client/client.crt #指定当前客户端的证书文件路径 key client/client.key #指定当前客户端的私钥文件路径 verb 3 #指定日志文件的记录详细级别，可选0-9，等级越高日志内容越详细 #修改systemctl 配置 [root@openvpn-client ~]# cat /usr/lib/systemd/system/openvpn@.serv [Unit] Description=OpenVPN Robust And Highly Flexible Tunneling Application On %I After=network.target [Service] Type=notify PrivateTmp=true ExecStart=/usr/sbin/openvpn --cd /etc/openvpn/ --config %i/%i.conf #增加%i即可，只修改这一行 #%i/%i 就是运行systemctl start openvpn@client时，会把@后面的client传给%i，就会读到client/client.conf [Install] WantedBy=multi-user.target #重新加载 [root@openvpn-client ~]# systemctl daemon-reload #启动和加入开机自启 [root@openvpn-client ~]# systemctl enable openvpn@client [root@openvpn-client ~]# systemctl start openvpn@client #检查进程与端口 [root@openvpn-client ~]# ss -lntup |grep openvpn udp UNCONN 0 0 *:53781 *:* users:(("openvpn",pid=12553,fd=3)) [root@openvpn-client ~]# ip a 4: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100 link/none inet 192.168.1.6 peer 192.168.1.5/32 scope global tun0 valid_lft forever preferred_lft forever inet6 fe80::b198:27bb:5967:356b/64 scope link flags 800 valid_lft forever preferred_lft forever 3）效果4、OpenVPN加密/认证考虑到万一证书被泄露或者丢失，外人直接就可以连接到内网，所以再加上 用户/密码 验证4.1 先配置服务端支持密码认证[root@openvpn-server ~]# cat /etc/openvpn/server/server.conf port 1194 #端口 proto udp #协议 dev tun #采用路由隧道模式tun ca ca.crt #ca证书文件位置 /etc/openvpn /etc/opnevpn/server cert server/server.crt #服务端公钥名称 /etc/openvpn key server/server.key #服务端私钥名称 /etc/openvpn dh server/dh.pem #加密算法文件, 交换证书 校验算法 /etc/openvpn server 192.168.1.0 255.255.255.0 #给客户端分配地址池(ip地址范围)，注意：不能和VPN服务器内网网段有相同 push "route 10.100.240.0 255.255.255.0" #客户端连接后,推送给客户端的路由规则 #客户端想访问10.100.240.0/24网段联系openvpn服务端 #ifconfig-pool-persist ipp.txt #地址池记录文件位置 未来让openvpn 客户端固定ip地址使用的. keepalive 10 120 #存活时间，10秒ping一次,120 如未收到响应则视为断线 max-clients 100 #最多允许100个客户端连接 status /var/log/openvpn-status.log #日志记录位置openvpn状态 log /var/log/openvpn.log #openvpn日志记录位置 verb 3 #verbose 日志输出级别 数字越大越详细最多11(debug) client-to-client #客户端与客户端之间支持通信 persist-key #通过keepalive检测超时后，重新启动VPN，不重新读取keys，保留第一次使用的keys 对私钥进行缓存. persist-tun #检测超时后，重新启动VPN，一直保持tun是linkup的。否则网络会先linkdown然后再linkup duplicate-cn #客户端密钥(证书和私钥)是否可以重复 #下面是要用户认证时才配置 script-security 3 #允许使用自定义脚本 auth-user-pass-verify /etc/openvpn/check.sh via-env #指定认证脚本 username-as-common-name #用户密码登陆方式验证4.2 编写用户验证 check.sh 脚本[root@openvpn-server ~]# cat /etc/openvpn/check.sh #!/bin/bash PASSFILE="/etc/openvpn/openvpnfile" #密码文件 用户名 密码明文 LOG_FILE="/var/log/openvpn-password.log" #用户登录情况的日志 TIME_STAMP=`date "+%Y-%m-%d %T"` if [ ! -r "${PASSFILE}" ]; then echo "${TIME_STAMP}: Could not open password file \"${PASSFILE}\" for reading." >> ${LOG_FILE} exit 1 fi CORRECT_PASSWORD=`awk '!/^;/&&!/^#/&&$1=="'${username}'"{print $2;exit}' ${PASSFILE}` if [ "${CORRECT_PASSWORD}" = "" ]; then echo "${TIME_STAMP}: User does not exist: username=\"${username}\",password=\"${password}\"." >> ${LOG_FILE} exit 1 fi if [ "${password}" = "${CORRECT_PASSWORD}" ]; then echo "${TIME_STAMP}: Successful authentication: username=\"${username}\"." >> ${LOG_FILE} exit 0 fi echo "${TIME_STAMP}: Incorrect password: username=\"${username}\", password=\"${password}\"." >> ${LOG_FILE} exit 14.3 脚本授权[root@openvpn-server ~]# chmod 700 /etc/openvpn/check.sh4.4 添加用户[root@openvpn-server ~]# cat /etc/openvpn/openvpnfile zxc 1234564.5 重启openvpn服务[root@openvpn-server ~]# systemctl restart openvpn@server4.6 客户端只需要在配置文件加个参数在client.ovpn或者client.conf文件最后一行添加 auth-user-pass4.7 最终效果5、OpenVPN连接内网其它服务器#先在openvpn服务端开启内核转发。 [root@openvpn-server ~]# echo 'net.ipv4.ip_forward = 1' >>/etc/sysctl.conf [root@openvpn-server ~]# sysctl -p net.ipv4.ip_forward = 1 #客户端尝试ping其他内网服务器，会显示请求超时。 [c:\~]$ ping 10.100.240.14 -t 正在 Ping 10.100.240.14 具有 32 字节的数据: 请求超时。 请求超时。 请求超时。 请求超时。 请求超时。 请求超时。 #服务端抓包，发现只有请求的包，没有响应的包。 [root@openvpn-server ~]# tcpdump -i eth0 host 10.100.240.14 tcpdump: verbose output suppressed, use -v or -vv for full protocol decode listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes 16:15:48.527017 IP 192.168.1.6 > 10.100.240.14: ICMP echo request, id 1, seq 738, length 40 16:15:53.087817 IP 192.168.1.6 > 10.100.240.14: ICMP echo request, id 1, seq 739, length 40 16:15:58.101622 IP 192.168.1.6 > 10.100.240.14: ICMP echo request, id 1, seq 740, length 40 16:16:03.083202 IP 192.168.1.6 > 10.100.240.14: ICMP echo request, id 1, seq 741, length 40 #一般都是10.100.240.14上没有192.168.1.0的路由，在10.100.240.14上添加路由 [root@localhost ~]# route add -net 192.168.1.0/24 gw 10.100.240.3 #在重新连vpn，再ping 10.100.240.14 会通 [c:\~]$ ping 10.100.240.14 -t 正在 Ping 10.100.240.14 具有 32 字节的数据: 来自 10.100.240.14 的回复: 字节=32 时间=1ms TTL=64 来自 10.100.240.14 的回复: 字节=32 时间<1ms TTL=64 来自 10.100.240.14 的回复: 字节=32 时间=1ms TTL=64 来自 10.100.240.14 的回复: 字节=32 时间<1ms TTL=64以上就是手把手教你搭建OpenVPN（保姆级教程）！
每次新机器都配置很麻烦，记录一下如何配置网络yum一、配置本地yum源首先将centos自带的网络yum源删掉（自带的默认从centos官网下载软件，服务器在国外，非常不稳定） [root@cloud ~]# rm -rf /etc/yum.repos.d/*创建挂载点并挂载镜像[root@cloud ~]# mkdir /opt/centos [root@cloud ~]# mount /dev/cdrom /opt/centos/ mount: /dev/sr0 写保护，将以只读方式挂载创建并编写本地yum源配置文件，编写完成之后wq保存退出[root@cloud ~]# vi /etc/yum.repos.d/local.repo [centos] name=centos # Yum源的名称，用于描述这个源 baseurl=file:///opt/centos # 本地Yum源的位置，指向挂载点目录 gpgcheck=0 # 不进行GPG签名检查 enabled=1 # 启用该Yum源清除缓存原来的生成新的缓存并列出当前系统中已配置和启用的Yum仓库（repositories）及其状态[root@cloud ~]# yum clean all 已加载插件：fastestmirror, langpacks 正在清理软件源： centos Cleaning up list of fastest mirrors Other repos take up 1.0 G of disk space (use --verbose for details) [root@cloud ~]# yum makecache 已加载插件：fastestmirror, langpacks Determining fastest mirrors centos | 3.6 kB 00:00:00 (1/4): centos/group_gz | 153 kB 00:00:00 (2/4): centos/primary_db | 3.3 MB 00:00:00 (3/4): centos/other_db | 1.3 MB 00:00:00 (4/4): centos/filelists_db | 3.3 MB 00:00:00 元数据缓存已建立 [root@cloud ~]# yum repolist 已加载插件：fastestmirror, langpacks Loading mirror speeds from cached hostfile 源标识 源名称 状态 centos centos 4,070 repolist: 4,070下载httpd测试一下[root@cloud ~]# yum install -y httpd 已加载插件：fastestmirror, langpacks Loading mirror speeds from cached hostfile 正在解决依赖关系 --> 正在检查事务 ---> 软件包 httpd.x86_64.0.2.4.6-95.el7.centos 将被 安装 --> 正在处理依赖关系 httpd-tools = 2.4.6-95.el7.centos，它被软件包 httpd-2.4.6-95.el7.centos.x86_64 需要 --> 正在处理依赖关系 /etc/mime.types，它被软件包 httpd-2.4.6-95.el7.centos.x86_64 需要 --> 正在处理依赖关系 libaprutil-1.so.0()(64bit)，它被软件包 httpd-2.4.6-95.el7.centos.x86_64 需要 --> 正在处理依赖关系 libapr-1.so.0()(64bit)，它被软件包 httpd-2.4.6-95.el7.centos.x86_64 需要 --> 正在检查事务 ---> 软件包 apr.x86_64.0.1.4.8-7.el7 将被 安装 ---> 软件包 apr-util.x86_64.0.1.5.2-6.el7 将被 安装 ---> 软件包 httpd-tools.x86_64.0.2.4.6-95.el7.centos 将被 安装 ---> 软件包 mailcap.noarch.0.2.1.41-2.el7 将被 安装 --> 解决依赖关系完成 依赖关系解决 ======================================================================================================================== Package 架构 版本 源 大小 ======================================================================================================================== 正在安装: httpd x86_64 2.4.6-95.el7.centos centos 2.7 M 为依赖而安装: apr x86_64 1.4.8-7.el7 centos 104 k apr-util x86_64 1.5.2-6.el7 centos 92 k httpd-tools x86_64 2.4.6-95.el7.centos centos 93 k mailcap noarch 2.1.41-2.el7 centos 31 k 事务概要 ======================================================================================================================== 安装 1 软件包 (+4 依赖软件包) 总下载量：3.0 M 安装大小：10 M Downloading packages: ------------------------------------------------------------------------------------------------------------------------ 总计 95 MB/s | 3.0 MB 00:00:00 Running transaction check Running transaction test Transaction test succeeded Running transaction 正在安装 : apr-1.4.8-7.el7.x86_64 1/5 正在安装 : apr-util-1.5.2-6.el7.x86_64 2/5 正在安装 : httpd-tools-2.4.6-95.el7.centos.x86_64 3/5 正在安装 : mailcap-2.1.41-2.el7.noarch 4/5 正在安装 : httpd-2.4.6-95.el7.centos.x86_64 5/5 验证中 : httpd-tools-2.4.6-95.el7.centos.x86_64 1/5 验证中 : mailcap-2.1.41-2.el7.noarch 2/5 验证中 : apr-1.4.8-7.el7.x86_64 3/5 验证中 : httpd-2.4.6-95.el7.centos.x86_64 4/5 验证中 : apr-util-1.5.2-6.el7.x86_64 5/5 已安装: httpd.x86_64 0:2.4.6-95.el7.centos 作为依赖被安装: apr.x86_64 0:1.4.8-7.el7 apr-util.x86_64 0:1.5.2-6.el7 httpd-tools.x86_64 0:2.4.6-95.el7.centos mailcap.noarch 0:2.1.41-2.el7 完毕！下载成功二、配置网络yum源优点：软件包和元数据由源服务器自动更新，国内镜像下载速度非常快缺点：需要稳定的网络连接，网络不稳定或断开时无法使用首先找到国内的镜像站（我这里以阿里云举例）找到自己的Linux版本（以centos为例）找到对应的系统版本（我的是7）并且复制这段命令到虚拟机粘贴同样需要先删除原有的yum仓库列出当前系统中已配置和启用的Yum仓库（repositories）及其状态[root@cloud ~]# rm -rf /etc/yum.repos.d/* [root@cloud ~]# wget -O /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo --2024-06-09 12:36:26-- https://mirrors.aliyun.com/repo/Centos-7.repo 正在解析主机 mirrors.aliyun.com (mirrors.aliyun.com)... 183.215.53.217, 183.215.53.222, 183.215.53.224, ... 正在连接 mirrors.aliyun.com (mirrors.aliyun.com)|183.215.53.217|:443... 已连接。 已发出 HTTP 请求，正在等待回应... 200 OK 长度：2523 (2.5K) [application/octet-stream] 正在保存至: “/etc/yum.repos.d/CentOS-Base.repo” 100%[======================================>] 2,523 --.-K/s 用时 0.006s 2024-06-09 12:36:26 (401 KB/s) - 已保存 “/etc/yum.repos.d/CentOS-Base.repo” [2523/2523]) [root@cloud ~]# yum repolist 已加载插件：fastestmirror, langpacks Loading mirror speeds from cached hostfile * base: mirrors.aliyun.com * extras: mirrors.aliyun.com * updates: mirrors.aliyun.com 源标识 源名称 状态 !base/7/x86_64 CentOS-7 - Base - mirrors.aliyun.com 10,072 !extras/7/x86_64 CentOS-7 - Extras - mirrors.aliyun.com 526 !updates/7/x86_64 CentOS-7 - Updates - mirrors.aliyun.com 5,890 repolist: 16,488可以看到已经保存成功，网络yum源就配置好了
Linux磁盘扩容需求：新增第二块磁盘 sdb 的空间（30G）扩展到当前的根目录 / 下，典型的 “添加新磁盘 → 扩容已有 LVM 根分区” 的操作流程。你的系统使用了 LVM（逻辑卷管理），所以我们可以把 sdb 加入到现有的 LVM 卷组并扩展根目录。✅ 操作目标将 sdb → 加入 LVM 卷组 centos → 扩容 centos-root → 扩容 / 挂载点空间🧰 操作步骤（谨慎操作，建议备份重要数据）① 确认当前卷组信息vgs输出示例（你应该会看到一个名为 centos 的卷组）：VG #PV #LV #SN Attr VSize VFree centos 1 2 0 wz--n- <29.00g 0② 对 sdb 创建物理卷（PV）pvcreate /dev/sdb成功输出类似：Physical volume "/dev/sdb" successfully created.③ 把 /dev/sdb 加入现有的卷组（VG）vgextend centos /dev/sdb成功输出类似：Volume group "centos" successfully extended④ 扩容逻辑卷（LV）到占满所有空间lvextend -l +100%FREE /dev/centos/root（这会将 VG 中剩余所有空间分配给 centos-root，即 /）⑤ 扩容文件系统如果你用的是 xfs 文件系统（CentOS 7+ 默认）：xfs_growfs /如果你用的是 ext4 文件系统（检查用 df -T /）：resize2fs /dev/centos/root✅ 完成后确认df -h /你应该可以看到 / 挂载点从原来的 26G 增加到了接近 56G（即原有 26G + sdb 的 30G）。[root@cicd_gitlab ~]# df -h 文件系统 容量 已用 可用 已用% 挂载点 devtmpfs 2.9G 0 2.9G 0% /dev tmpfs 2.9G 84K 2.9G 1% /dev/shm tmpfs 2.9G 18M 2.9G 1% /run tmpfs 2.9G 0 2.9G 0% /sys/fs/cgroup /dev/mapper/centos-root 56G 25G 32G 45% / /dev/sda1 1014M 189M 826M 19% /boot tmpfs 581M 0 581M 0% /run/user/0 [root@cicd_gitlab ~]# lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT sda 8:0 0 30G 0 disk ├─sda1 8:1 0 1G 0 part /boot └─sda2 8:2 0 29G 0 part ├─centos-root 253:0 0 56G 0 lvm / └─centos-swap 253:1 0 3G 0 lvm [SWAP] sdb 8:16 0 30G 0 disk └─centos-root 253:0 0 56G 0 lvm / sr0 11:0 1 1024M 0 rom [root@cicd_gitlab ~]# 🛑 注意事项操作过程对系统影响较大，请在低峰时段操作或备份重要数据。如果后续计划卸载或缩容，建议新磁盘单独挂载，而不是扩展 /。
Node.js 安装（兼容旧版 glibc 的方案）在 CentOS 等 Linux 系统中运行 Node.js 时，可能遇到如下错误：node: /lib64/libm.so.6: version `GLIBC_2.27' not found (required by node)这是由于系统中的 glibc 版本过低（如 CentOS 7 的默认 glibc 为 2.17），而某些 Node.js 版本依赖更新版本的 glibc（如 2.27 及以上）。✅ 解决方案为避免升级系统或使用 Docker，可使用 专为旧版 glibc 编译的 Node.js 预构建版本，例如：node-v18.18.0-linux-x64-glibc-217.tar.gz该版本可在 CentOS 7 等使用 glibc 2.17 的系统中正常运行。🔧 安装步骤1️⃣ 下载 Node.js 版本进入 Node.js 非官方兼容版本下载页面，下载：node-v18.18.0-linux-x64-glibc-217.tar.gz2️⃣ 上传至服务器例如上传到目录：/root/node/3️⃣ 解压安装包cd /root/node tar -xzvf node-v18.18.0-linux-x64-glibc-217.tar.gz4️⃣ 重命名目录（可选）mv node-v18.18.0-linux-x64-glibc-217 node-v185️⃣ 配置环境变量创建配置文件 /etc/profile.d/nodejs.sh：vi /etc/profile.d/nodejs.sh添加内容如下：export NODE_HOME=/root/node/node-v18 export PATH=.:$NODE_HOME/bin:$PATH保存后使其生效：source /etc/profile6️⃣ 配置国内 npm 镜像源（建议）为加快依赖安装速度，设置为阿里云镜像：npm config set registry=https://registry.npmmirror.com✅ 验证安装node -v npm -v确保输出的版本正确，即代表安装成功。📌 总结通过该方法，可 避免升级系统 glibc，而直接使用为旧系统编译的 Node.js 版本，适合在 CentOS 7 等老系统上运行现代 Node.js 应用。