Gatling压测ip_hash负载均衡的4节点Tomcat流量集中问题求助
问题根源
Nginx的ip_hash路由策略是基于客户端的源IP地址计算哈希值来分配请求的。而Gatling默认情况下,所有虚拟用户的请求都来自测试机器的同一个公网/内网IP,所以Nginx会把所有流量都哈希到同一个后端Tomcat节点——这就是你遇到的问题核心。
解决方案
要在保持会话持久化的同时让流量分发到所有4个节点,有两种可靠的方案,你可以根据测试环境选择:
方案1:让Gatling模拟不同的客户端IP(推荐)
这个方案不需要修改Nginx的ip_hash配置,只要让每个Gatling虚拟用户使用唯一的源IP(或通过请求头模拟),就能触发Nginx的ip_hash分发到不同节点,同时保证同一个用户的请求始终路由到同一节点。
子方案1.1:测试机器有多IP的情况
如果你的测试机器有多个可用的内网/公网IP,可以直接让Gatling为每个虚拟用户分配不同的本地IP:
val httpConf = http .baseUrl("http://your-nginx-host") // 从可用IP列表中按用户ID取模分配,保证同一个用户始终用同一个IP .localAddress(session => { val availableIps = List("192.168.1.10", "192.168.1.11", "192.168.1.12", "192.168.1.13") availableIps(session.userId % availableIps.size) })
子方案1.2:测试机器只有单IP的情况
如果测试机器只有一个IP,可以通过X-Forwarded-For请求头模拟不同客户端IP,同时修改Nginx的哈希策略基于这个头的值:
修改Nginx配置:把
ip_hash替换为基于X-Forwarded-For的哈希(保证会话持久化):hash $http_x_forwarded_for consistent;(
consistent参数可选,作用是当节点数量变化时减少会话重路由的比例,节点固定的场景可以省略)修改Gatling配置:为每个虚拟用户设置固定的
X-Forwarded-For值,确保同一个用户的所有请求用同一个“模拟IP”:val httpConf = http .baseUrl("http://your-nginx-host") // 生成唯一的模拟IP,比如10.0.0.1到10.0.0.100,按用户ID取模保证一致性 .header("X-Forwarded-For", session => s"10.0.0.${session.userId % 100 + 1}")
方案2:调整Nginx的ip_hash参数(备选)
如果你的场景不允许修改Gatling的IP配置,可以尝试调整Nginx的哈希算法,不过这个方案对单一源IP的情况效果有限:
ip_hash; hash_method crc32; # 切换哈希算法,默认是md5
但注意:如果所有请求还是来自同一个源IP,这个方法无法改变所有流量到单一节点的结果,仅作为备选尝试。
验证方法
修改完成后,你可以通过以下方式验证:
- 查看Nginx的访问日志,检查
$remote_addr(或$http_x_forwarded_for)是否对应不同的IP,且请求分布到了4个Tomcat节点; - 查看Tomcat的会话存储,确认同一个虚拟用户的所有请求都落在同一个节点上,保证会话持久化。
你的setUp代码修改示例
结合子方案1.2,修改后的完整代码大概是:
val httpConf = http .baseUrl("http://your-nginx-domain") .header("X-Forwarded-For", session => s"10.0.0.${session.userId % 4 + 1}") // 生成4个不同IP,对应4个节点 val scenario1 = scenario("Web App Load Test") .exec(http("Initial Request") .get("/")) // 添加你的其他测试步骤... setUp( scenario1.inject( atOnceUsers(50), rampUsers(300) over (1800 seconds) ).protocols(httpConf) )
内容的提问来源于stack exchange,提问作者Danny

