Vert.x高吞吐量下出现‘Cannot assign requested address’错误的解决问询
解决Vert.x高RPS压力测试下"Cannot assign requested address"问题
核心问题分析
出现该错误的本质是本地TCP端口耗尽,结合你的代码和场景,主要诱因有三个:
- 每次请求都新建
WebClient实例,完全丧失连接复用能力,短时间内产生大量TIME_WAIT状态的TCP连接 - 系统默认TCP参数无法支撑10K RPS的高并发请求,端口回收速度跟不上消耗速度
- Vert.x的Verticle和线程池配置不合理,加剧资源消耗
解决方案
1. 复用WebClient实例(最关键修复)
WebClient是重量级对象,包含连接池、线程管理等资源,必须在Verticle启动时初始化一次,而非每次请求都创建:
private WebClient httpClient; @Override public void start(Promise<Void> startPromise) throws Exception { WebClientOptions webClientOptions = new WebClientOptions(); webClientOptions.setMaxPoolSize(2000); // 开启连接复用关键配置 webClientOptions.setKeepAlive(true); webClientOptions.setTcpKeepAlive(true); webClientOptions.setReuseAddress(true); // 设置请求排队上限,避免内存溢出 webClientOptions.setMaxWaitQueueSize(5000); httpClient = WebClient.create(vertx, webClientOptions); vertx.eventBus().consumer(FIRE_GET_METRIC_TO_STATS, this::fire); startPromise.complete(); } private void fire(Message<StatsRequest> message) { StatsRequest body = message.body(); MultiMap multimapHeader = MultiMap.caseInsensitiveMultiMap(); httpClient.request(HttpMethod.GET, port, "example.com", "/1x1.gif" + "?" + "queryParamsString") .followRedirects(false) .putHeaders(multimapHeader) .timeout(120000) .send() .onSuccess(response -> { logger.info("All good"); }) .onFailure(err -> { logger.error("Exception: " + err.getMessage()); }); }
2. 调整系统TCP参数(Linux环境)
编辑/etc/sysctl.conf添加以下配置,扩大端口范围并加速端口回收:
# 扩大本地可用端口范围 net.ipv4.ip_local_port_range = 1024 65535 # 缩短TIME_WAIT状态端口的回收时间 net.ipv4.tcp_fin_timeout = 30 # 允许复用TIME_WAIT状态的端口 net.ipv4.tcp_tw_reuse = 1 # 快速回收TIME_WAIT端口 net.ipv4.tcp_tw_recycle = 1 # 增大连接跟踪表容量 net.netfilter.nf_conntrack_max = 1000000
执行sysctl -p使配置生效。
3. 优化Vert.x部署配置
- 调整WorkerVerticle数量:当前10个Verticle+每个50线程的配置过于激进,建议根据CPU核心数调整(例如CPU核心数*4),避免线程上下文切换开销过大:
// 修改deployWorker调用的第三个参数,比如调整为4 deployWorker(vertx, injector, StatsHttpVerticle.class, 4)
- 放宽EventLoop执行时间限制:当前
setMaxEventLoopExecuteTime(1)过于严格,会频繁触发EventLoop阻塞告警,建议移除该配置或调整为合理值(如100毫秒):
final VertxOptions vertxOptions = new VertxOptions(); // 移除或调整以下配置 // .setMaxEventLoopExecuteTime(100) // .setMaxEventLoopExecuteTimeUnit(TimeUnit.MILLISECONDS);
4. 优化EventBus调用方式(可选)
如果不需要接收WorkerVerticle的响应,将eventBus.request()改为eventBus.send(),避免发送端因等待响应产生阻塞:
public void send(Map<String, Object> queryParams, HashMap<String, String> headers, boolean followRedirect, Event eventToFire) { StatsRequest statsRequest = new StatsRequest(queryParams, headers, eventToFire, followRedirect); eventBus.send(FIRE_GET_METRIC_TO_STATS, statsRequest); }
内容的提问来源于stack exchange,提问作者Tal Rosentzweig
相关产品推荐
相关产品推荐

