简介TongHttpServerTHS是一款稳定高效的负载均衡软件产品这份 x86 平台安装包面向运维工程师、后端开发与系统架构人员用于快速搭建负载均衡服务提升系统可靠性、可扩展性与资源利用率也可作为熟悉国产负载均衡方案部署与调优的实践素材。压缩包共 71 个文件、约 39.44MB主体由 12 个 so 动态库、6 个 conf 配置文件、6 个 sh 启动运维脚本以及 18 个 pem、3 个 pfx、3 个 crt、3 个 key 等证书文件组成配合 bin 下的可执行程序与 lib 中的 SSL 加密库基本覆盖运行所需的完整环境。目录中可见 httpserver、httpserverHA、gmproxy 等模块以及 mod_lbmethod_byhost、byminconn、iphash、byqueue 等负载策略库便于对照理解不同调度算法的配置方式。已有 4426 人学习下载适合需要落地负载均衡或研究其实现细节的读者参考。1. 从一台压测机说起THS_x86 装错一次负载均衡全白配TongHttpServerTHS的 THS_x86.tar.gz 装起来不复杂难的是把负载均衡配到能扛住压测。有次在一台压测机上包解压完直接./ths起服务upstream 里明明写了三台后端结果所有请求都落到第一台查了半天不是算法写错是ulimit和fail_timeout组合出的假健康。THS 这类 HTTP 服务器装不好不会立刻报错而是悄悄把流量打偏等你发现时压测数据已经不能看了。这篇按我自己的装机顺序走先钉环境再解压启动然后配 upstream 和健康检查最后用 curl 和压测验证。适合正在装 THS_x86、准备做反向代理和负载均衡的开发者新手能照着走熟手可以重点看参数取舍和排错那段。2. 装前把环境钉死THS_x86 的 x86_64、glibc 与端口规划THS_x86.tar.gz 是 x86 架构的压缩包别拿到 arm 机器上直接解压。我一般先确认三件事CPU 架构、glibc 版本、可用端口。这三项不先落纸后面启动失败会变成玄学问题。先跑一组只读命令不改系统# 确认架构输出 x86_64 才继续 uname -m # 查看 glibc 版本二进制包对 glibc 有最低要求 getconf GNU_LIBC_VERSION ldd --version | head -n 1 # 看发行版和内核便于判断 systemd 版本 cat /etc/os-release uname -r # 看内存、磁盘和已占用端口 free -m df -h /opt ss -lntpuname -m必须是x86_64如果是aarch64就换对应的包不要硬装。getconf GNU_LIBC_VERSION和ldd --version输出的是 glibc 版本THS 的二进制如果依赖动态库glibc 过低会在启动时报version GLIBC_2.xx not found这种错误换配置文件救不回来只能换匹配的包或换系统。ss -lntp是看 80、443、8080 这些端口有没有被占用别等启动时才发现端口冲突。2.1 先确认 x86_64 与 glibc 版本别急着解压我习惯先把包放到/opt下再检查不在/tmp里直接跑因为/tmp可能带noexec挂载选项解压后二进制执行不了。把THS_x86.tar.gz传到/opt后先看包内文件列表不着急解压# 看压缩包顶层目录结构确认没有绝对路径 tar -tzf THS_x86.tar.gz | head -n 30 # 计算校验值和交付方给的 sha256 对一下 sha256sum THS_x86.tar.gztar -tzf只列目录不解压能提前看到包内是ths/还是直接散文件。如果列表里出现../或/etc/这类绝对路径先停下来不要用 root 解压。sha256sum是防止传输过程中包损坏校验值不一致时后面的报错都不可信。常见做法是解压到/opt/ths配置文件、日志、pid 都收在这个目录下后面迁移时整目录打包即可。2.2 端口、目录与运行用户三张表先落纸端口规划不要拍脑袋。THS 作为反向代理时自身监听 80 或 443后端业务端口通常是 8080、8081 这类。下面是我装机时常用的规划表实际按业务改用途端口监听地址说明THS HTTP 入口800.0.0.0对外负载均衡入口THS HTTPS 入口4430.0.0.0需要证书时启用后端业务 A8080127.0.0.1 或内网 IPupstream 节点一后端业务 B8081127.0.0.1 或内网 IPupstream 节点二本地健康检查8080/health后端提供用于 curl 验证目录规划同样要提前定/opt/ths/conf放配置/opt/ths/logs放日志/opt/ths/run放 pid/opt/ths/sbin放二进制。运行用户不要用 root常见做法是建一个ths用户只给日志和 pid 目录写权限。80 端口需要特权可以用 systemd 的AmbientCapabilitiesCAP_NET_BIND_SERVICE给二进制绑定低端口的能力而不是直接 root 跑。# 建运行用户和目录目录属主给 ths useradd -r -s /sbin/nologin ths mkdir -p /opt/ths/{conf,logs,run,sbin} chown -R ths:ths /opt/ths/logs /opt/ths/run # 如果二进制需要绑定 80 端口给它低端口能力 setcap cap_net_bind_serviceep /opt/ths/sbin/thsuseradd -r建的是系统用户不登录 shellchown只给日志和 pid 目录写权限配置目录保持 root 可写、ths 只读避免运行用户改配置。setcap是给二进制文件加能力不是给用户加权限换包后要重新执行。注意如果后面用 systemd 托管优先在 unit 里写AmbientCapabilitiessetcap作为手动启动时的兜底。2.3 依赖包与内核参数只装缺的别整套换THS_x86.tar.gz 如果是预编译二进制不要上来就yum install一整套编译工具。先解压后ldd看缺什么库缺什么装什么。常见缺的是libpcre、zlib、openssl相关运行库不是开发包。内核参数也不要照抄网上的“优化大全”先看当前值只调影响 accept 队列和文件描述符的两三项# 看当前文件描述符和 accept 队列 ulimit -n sysctl net.core.somaxconn sysctl net.ipv4.tcp_max_syn_backlog # 临时调大确认有效后再写进 /etc/sysctl.d/ sysctl -w net.core.somaxconn1024 sysctl -w net.ipv4.tcp_max_syn_backlog1024ulimit -n是当前 shell 的文件描述符上限压测时连接数一高1024 很快不够表现是Too many open files。somaxconn是 accept 队列长度太小会在高并发时丢连接。临时sysctl -w只对当前内核生效重启失效确认有效后写到/etc/sysctl.d/99-ths.conf里。注意不要为了“优化”把tcp_tw_reuse之类参数乱开先保证装通、跑通再谈调优。提示环境检查阶段所有命令都是只读或可回退的别在还没解压时改一堆系统参数。先记录当前值后面出问题才能对比。3. 解压与首次启动THS_x86.tar.gz 落到 /opt 后的四步检查解压本身一条命令但首次启动前有四步检查不能省目录结构、二进制依赖、配置语法、端口监听。我见过太多“解压完直接后台启动然后 tail 日志发现配置文件路径写错”的翻车。下面按顺序走每步都有明确的失败信号。3.1 解压到 /opt/ths 并核对目录结构先解压到临时目录看结构再挪到/opt/ths避免包内顶层目录和现有目录冲突# 解压到 /opt 下先看顶层目录名 tar -xzf /opt/THS_x86.tar.gz -C /opt # 假设解压出来是 /opt/THS_x86看目录结构 find /opt/THS_x86 -maxdepth 2 -type d | sort # 确认二进制位置和配置文件位置 ls -l /opt/THS_x86/sbin/ths ls -l /opt/THS_x86/conf/tar -xzf的-C /opt指定解压目标不要用-C /。find -maxdepth 2只看两层目录能快速确认有没有conf、logs、sbin。如果包内目录名不是THS_x86按实际名字替换。确认无误后把内容挪到/opt/ths或者直接把/opt/THS_x86作为安装目录后面配置里路径统一即可。我一般保留/opt/ths作为软链接升级时换链接指向新目录回滚方便。# 用软链接固定安装路径升级时只换链接 ln -sfn /opt/THS_x86 /opt/ths ls -l /opt/thsln -sfn的-n是防止把链接建到已有目录里面去。软链接固定后systemd、日志轮转、监控脚本都只认/opt/ths升级时换链接再 reload比改一堆路径稳妥。3.2 二进制依赖与版本确认ldd 和 -v 先跑解压后不要急着启动先看二进制能不能执行、缺不缺库# 确认文件类型是 x86-64 可执行文件 file /opt/ths/sbin/ths # 看动态库依赖注意 not found 项 ldd /opt/ths/sbin/ths # 看版本输出确认包和文档一致 /opt/ths/sbin/ths -vfile输出里应该有ELF 64-bit LSB executable, x86-64如果是ARM aarch64说明拿错包。ldd里出现not found就是缺运行库按缺失的库名装对应的运行时包不要装-devel开发包。ths -v如果报GLIBC版本错误说明系统 glibc 低于二进制要求换包或换系统不要尝试单独升级 glibc容易把系统包管理弄坏。注意ldd不要对不可信二进制执行这里包来源明确才用。执行前确认文件属主和权限不要给777。3.3 配置文件最小改动监听、日志、pidTHS 的配置模板一般在conf/下文件名可能是ths.conf或类似 nginx 风格的模板实际以解压后文件为准。第一次启动只改四项监听端口、运行用户、日志路径、pid 路径。不要一上来就配负载均衡先把单机入口跑通。# /opt/ths/conf/ths.conf 最小片段字段名以包内模板为准 worker_processes auto; pid /opt/ths/run/ths.pid; error_log /opt/ths/logs/error.log warn; events { worker_connections 1024; } http { access_log /opt/ths/logs/access.log; server { listen 80; server_name _; location / { return 200 ths ok\n; } } }worker_processes auto按 CPU 核数起 worker第一次装不用手动写死。pid和日志路径必须指向ths用户有写权限的目录否则启动时可能不报错但 pid 文件写不出来。listen 80先用最小 server 返回固定文本确认入口通再加 upstream。worker_connections先给 1024压测阶段再按ulimit调整。# 配置语法检查常见参数是 -t /opt/ths/sbin/ths -t -c /opt/ths/conf/ths.conf # 前台启动观察输出不要直接 daemon /opt/ths/sbin/ths -c /opt/ths/conf/ths.conf -g daemon off;-t只检查配置语法不启动服务-c指定配置文件路径-g daemon off;让进程前台运行日志直接打到终端首次启动排错最有用。如果-t报unknown directive说明配置字段和当前包不匹配回头对照包内模板不要硬猜。前台启动看到ready或监听日志后再CtrlC停掉换 systemd 托管。3.4 systemd 托管与首次监听检查手动启动确认配置没问题后用 systemd 托管避免退出终端服务就停。unit 文件里把用户、能力、文件描述符上限都写清楚# /etc/systemd/system/ths.service [Unit] DescriptionTHS HTTP Server Afternetwork-online.target Wantsnetwork-online.target [Service] Typeforking Userths Groupths PIDFile/opt/ths/run/ths.pid ExecStartPre/opt/ths/sbin/ths -t -c /opt/ths/conf/ths.conf ExecStart/opt/ths/sbin/ths -c /opt/ths/conf/ths.conf ExecReload/bin/kill -HUP $MAINPID ExecStop/bin/kill -QUIT $MAINPID LimitNOFILE65535 AmbientCapabilitiesCAP_NET_BIND_SERVICE NoNewPrivilegestrue [Install] WantedBymulti-user.targetTypeforking对应 THS 默认后台模式如果包内默认前台运行改成Typesimple并去掉PIDFile。ExecStartPre每次启动前做语法检查配置写错时 systemd 直接失败不会带病启动。LimitNOFILE65535解决压测时文件描述符不够。AmbientCapabilities让非 root 用户能绑 80 端口比setcap更适合 systemd 管理。# 重载 systemd 并启动 systemctl daemon-reload systemctl enable --now ths # 看状态和端口监听 systemctl status ths --no-pager ss -lntp | grep :80 # 本地请求验证 curl -I http://127.0.0.1/systemctl status看Active: active (running)和最近日志ss -lntp看 80 端口是否真的在监听进程属主是不是thscurl -I看返回码是不是 200。三步都过单机入口才算装通。注意如果ss没有输出但systemctl显示 running多半是监听地址写成了127.0.0.1:80之外的其他地址或者配置里listen被注释了。4. 负载均衡配置THS 的 upstream、健康检查与转发头取舍单机入口跑通后才轮到负载均衡。THS 的配置风格接近常见 HTTP 服务器包内模板如果提供upstream块就按块写如果没有先看模板里的代理示例不要自己造指令。下面按 nginx 风格的最小片段写字段名以实际conf为准。核心取舍有三点算法选轮询还是最少连接、健康检查用被动还是主动、转发头带不带X-Forwarded-For。4.1 upstream 怎么写权重、最大失败次数与恢复先写一个两节点的 upstream权重先均等max_fails和fail_timeout不要一上来调很激进# /opt/ths/conf/ths.conf 中的 upstream 片段 upstream ths_backend { least_conn; server 10.0.0.11:8080 weight1 max_fails2 fail_timeout10s; server 10.0.0.12:8080 weight1 max_fails2 fail_timeout10s; keepalive 32; }least_conn是最少连接算法适合后端处理时间差异大的场景如果后端性能一致用默认轮询也行。weight1是权重机器配置不同时再调比如 8 核给 2、4 核给 1。max_fails2表示 10 秒内失败两次就标记不可用fail_timeout10s是标记后的冷却时间两个参数要一起看max_fails太小会把慢请求误判成宕机太大又会让故障节点继续接流量。keepalive 32是到上游的长连接池能减少握手开销但后端也要支持 keep-alive否则连接复用会出问题。# server 段把请求转到 upstream server { listen 80; server_name _; location / { proxy_pass http://ths_backend; proxy_http_version 1.1; proxy_set_header Connection ; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_connect_timeout 3s; proxy_read_timeout 30s; proxy_next_upstream error timeout http_502 http_504; } }proxy_pass http://ths_backend指向 upstream 名称不要写成具体 IP。proxy_http_version 1.1和Connection 配合keepalive使用清空 Connection 头才能复用长连接。proxy_connect_timeout 3s是连接上游超时内网可以短一点proxy_read_timeout 30s是读上游响应超时按业务接口调整慢接口多就放大否则会误判 504。proxy_next_upstream控制在哪些错误时换下一台http_502和http_504要不要重试看业务幂等性非幂等接口不要轻易重试。4.2 健康检查与被动探测别把慢请求当宕机THS 如果包内模板带主动健康检查指令就按模板开没有主动检查时靠max_fails和fail_timeout做被动探测。被动探测的逻辑是请求失败到阈值就标记节点不可用冷却后再试。这里最容易翻车的是把业务超时当成节点宕机。# 被动探测参数示例字段名以包内模板为准 upstream ths_backend { server 10.0.0.11:8080 max_fails3 fail_timeout30s; server 10.0.0.12:8080 max_fails3 fail_timeout30s; }max_fails3比 2 更稳一点fail_timeout30s给慢接口留恢复时间。如果接口平均响应 2 秒、偶尔 5 秒proxy_read_timeout至少给 10 秒以上否则正常慢请求会被记成失败节点被踢掉后流量全压到另一台压测曲线会突然塌。主动健康检查如果有独立 URI比如/health就配成不经过业务逻辑的轻量接口没有就先用被动探测别为了“看起来专业”硬造一个健康检查模块。提示健康检查阈值没有通用值。先按max_fails3、fail_timeout30s起步压测时看错误日志里是连接失败还是读超时再决定调哪个。4.3 转发头与会话保持X-Forwarded-For 和 sticky 的取舍反向代理后后端拿到的remote_addr是 THS 的地址业务要真实客户端 IP 就得带X-Forwarded-For。但转发头不能无脑透传客户端伪造的X-Forwarded-For要由 THS 覆盖或追加不能直接信任。# 透传真实 IP 的常见写法 proxy_set_header Host $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_add_x_forwarded_for是在已有头后面追加客户端地址如果前面还有一层代理后端拿到的是链式列表业务取第一个可信 IP。X-Forwarded-Proto告诉后端原始协议是 http 还是 https生成跳转链接时不会错。会话保持方面ip_hash按客户端 IP 哈希适合没有共享 session 的老系统但 NAT 后面大量用户会落到同一台负载不均sticky cookie 需要模块支持没有模块就不要硬配。取舍原则能改造后端共享 session 就优先共享不能改造再用ip_hash并且接受它带来的不均。# 需要会话保持且没有共享 session 时的兜底写法 upstream ths_backend { ip_hash; server 10.0.0.11:8080; server 10.0.0.12:8080; }ip_hash和least_conn不要同时写算法指令一个 upstream 只留一个。ip_hash下新增或摘除节点会导致部分客户端重新哈希发布时尽量整组切流不要单台反复上下线。5. 避坑与排查五个让 THS 起不来的现场THS 的报错有时候不直接说人话日志里一行emerg背后可能是权限、端口、配置包含顺序三个问题叠在一起。下面五条是我装 THS_x86 时真正常见的现场按“现象 → 原因 → 解决”记方便对着查。5.1 启动即退端口占用与权限的两种假象现象systemctl start ths返回成功但ss -lntp看不到 80 端口systemctl status过几秒变成 failed。原因通常有两种80 端口被其他进程占用或者ths用户没有绑定低端口的能力。日志里可能只写bind() to 0.0.0.0:80 failed (13: Permission denied)权限错误不会告诉你具体缺什么能力。解决先ss -lntp | grep :80看占用进程能停就停不能停就换端口。权限问题用getcap /opt/ths/sbin/ths看有没有cap_net_bind_servicesystemd 托管时看 unit 里AmbientCapabilities有没有写对。改完systemctl daemon-reload再启动。如果前台启动能起、systemd 起不来重点查 unit 的User和AmbientCapabilities不要反复改配置文件。5.2 502 与 504 混在一起上游健康检查的误判现象压测时一部分请求 502一部分 504后端日志却显示请求已经处理。原因502 是上游连接失败或上游返回无效响应504 是读上游超时proxy_next_upstream把两类错误都重试到下一台日志里看起来像“随机故障”实际是超时阈值和健康检查阈值不匹配。解决先把proxy_connect_timeout和proxy_read_timeout分开看连接失败查后端端口和防火墙读超时查业务耗时。再把max_fails调大、fail_timeout调长避免慢请求把节点踢掉。压测时临时把proxy_next_upstream只留error timeout观察错误分布确认是单台问题还是全局超时。不要用“多试几次”掩盖 504超时阈值必须和业务 P99 对齐。5.3 日志不写路径、权限与 logrotate 的连锁反应现象服务能启动access.log一直是空文件error.log也没有新内容。原因日志父目录不存在、ths用户没有写权限或者 logrotate 轮转后新文件属主变成 rootTHS 还持有旧文件描述符。-t检查配置语法不会检查目录权限所以启动不报错。解决启动前用sudo -u ths test -w /opt/ths/logs验证写权限目录不存在就mkdir -p并chown。logrotate 配置里用copytruncate或create时指定ths ths避免轮转后新文件 root 属主。排查时tail -f /opt/ths/logs/error.log和lsof -p $(cat /opt/ths/run/ths.pid) | grep log一起看确认进程实际写的是哪个文件。5.4 reload 不生效include 顺序与语法缓存现象改了 upstream 配置systemctl reload ths返回成功但流量还是打到旧节点。原因主配置里的include顺序导致新文件没被加载或者新配置文件语法错误reload 时旧 worker 继续跑日志里只有一行emerg被忽略。解决reload 前必须ths -t -c /opt/ths/conf/ths.conf语法错误会直接报文件名和行号。确认include通配符能匹配到新文件ls /opt/ths/conf/conf.d/*.conf看文件名后缀对不对。reload 后看 master 进程日志有没有reconfiguring再看ss -lntp和 upstream 节点状态。如果 reload 多次不生效宁可systemctl restart ths但重启前先确认配置检查通过别把旧进程也弄没。5.5 压测时连接被重置文件描述符与内核队列现象单请求 curl 正常一上压测就出现connection reset by peer错误率随并发升高。原因LimitNOFILE还是 1024somaxconn太小accept 队列溢出或者 THS 的worker_connections小于实际并发。解决ulimit -n和 systemd unit 的LimitNOFILE都调到 65535worker_connections按worker_processes * worker_connections估算总连接数。sysctl net.core.somaxconn调到 1024 以上ss -lnt看Send-Q是否持续非零非零说明队列满。压测时同时看 THS 错误日志和后端连接数确认是入口瓶颈还是上游瓶颈不要一上来就怪负载均衡算法。6. 装完怎么验证从 curl 到压测把 THS 负载均衡跑通验证不要只看systemctl status绿色。我一般按四步走配置语法、本地入口、轮询分布、故障切换。先跑语法和入口# 1. 配置语法检查 /opt/ths/sbin/ths -t -c /opt/ths/conf/ths.conf # 2. 本地入口返回码和耗时 for i in $(seq 1 5); do curl -s -o /dev/null -w %{http_code} %{time_total}\n http://127.0.0.1/ done # 3. 看 80 端口监听和进程 ss -lntp | grep :80 systemctl status ths --no-pager-t必须返回syntax is ok和test is successful有一条不满足就不要 reload。curl -w输出状态码和总耗时连续 5 次都应该是 200耗时波动大说明后端或连接池有问题。ss看监听地址和进程属主systemctl status看最近日志有没有emerg。轮询分布不能靠感觉让后端返回自己的标识连续请求看是否均匀# 后端 /whoami 返回节点标识连续请求观察分布 for i in $(seq 1 10); do curl -s http://127.0.0.1/whoami echo done如果 10 次全落同一台先检查 upstream 是不是只写了一个server再检查算法是不是ip_hash且客户端 IP 固定。least_conn在低并发下可能看起来不均压测并发上来后才明显。故障切换验证更直接停掉一台后端再连续 curl应该仍然返回 200错误日志里出现一次上游失败后恢复。最后再上压测工具观察错误率和 P99不要用压测结果反推配置语法顺序不能反。验证项通过标准失败先看配置语法-t返回 successful报错行号、include 路径入口监听ss有 80 且属主正确unit 权限、端口占用轮询分布多节点都有请求upstream 节点数、算法故障切换停一台仍返回 200max_fails、后端健康压测错误率错误率可接受且无持续 502/504超时阈值、文件描述符从那以后我每次装 THS_x86 都强制走一遍-t、ss、连续 curl、停一台后端这四步再谈压测和调优。这套顺序不花哨但能把“装上了”和“跑通了”分开。希望帮到你。本文还有配套的精品资源点击获取