Avatica-Go客户端连接Phoenix查询服务器负载均衡地址失败排查
问题排查:Go Avatica客户端连接Nginx负载均衡Phoenix Query Server时报错"driver: bad connection"
环境信息
- 组件版本:Hbase 2.0.0、Phoenix 5.0.0、Avatica-go-client 5.2.0、带sticky模块的Nginx 1.8.1
- 部署架构:3个Regionserver、3个Query Server,Nginx部署于
192.168.3.236,配置sticky负载均衡,原配置如下:
upstream phoenix_balance { sticky expires=1m; server 192.168.3.190:8765; server 192.168.3.236:8765; server 192.168.3.165:8765; } server { listen 8766; server_name localhost; location / { proxy_pass http://phoenix_balance/; } }
测试现象
- Java客户端连接单个PQS或负载均衡地址均正常,代码示例:
Class.forName("org.apache.phoenix.queryserver.client.Driver"); String url = "jdbc:phoenix:thin:url=http://192.168.3.236:8766;serialization=PROTOBUF"; conn = DriverManager.getConnection(url, prop);
- Go客户端连接单个PQS正常,但连接负载均衡地址
http://192.168.3.236:8766时出现错误driver: bad connection,代码示例:
db, err := sql.Open("avatica", "http://192.168.3.236:8765") // 正常 db, err := sql.Open("avatica", "http://192.168.3.236:8766") // 失败,报错driver:bad connection rows, err := db.Query("SELECT COUNT(*) FROM test.test1")
配置问题分析与调整建议
1. Nginx配置缺失关键转发参数
Java客户端能正常工作不代表Nginx配置无问题,Go的Avatica客户端对HTTP连接细节更敏感,原配置缺少以下关键设置:
(1)Host头传递
Phoenix Query Server可能依赖请求的Host头处理会话,原配置中server_name localhost会导致转发到后端的Host头被设置为localhost,而非客户端实际请求的192.168.3.236:8766,这会导致PQS无法正确识别请求来源。
(2)HTTP持久连接支持
Avatica客户端默认使用HTTP/1.1持久连接,Nginx默认配置未明确开启该支持,可能导致连接被提前关闭。
调整后的Nginx配置
upstream phoenix_balance { sticky expires=1m; server 192.168.3.190:8765; server 192.168.3.236:8765; server 192.168.3.165:8765; } server { listen 8766; server_name 192.168.3.236 localhost; # 匹配实际请求IP和本地访问 location / { proxy_http_version 1.1; # 启用HTTP/1.1 proxy_set_header Connection ""; # 清空Connection头,适配持久连接 proxy_set_header Host $host:$server_port; # 传递客户端请求的Host信息 proxy_set_header X-Real-IP $remote_addr; # 传递真实客户端IP proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://phoenix_balance/; } }
2. Sticky会话保持的Cookie兼容性问题
Nginx的sticky模块基于Cookie实现会话保持,但Avatica-Go客户端默认不自动处理Cookie,导致每次请求被分发到不同的PQS节点,而Avatica的连接会话是绑定到单个PQS实例的,跨节点请求会触发bad connection错误。
解决方式:
- 临时测试:注释Nginx配置中的
sticky expires=1m;,关闭会话保持后测试Go客户端是否能连接,验证是否为Cookie问题。 - 代码调整:如果确实是Cookie问题,修改Go代码启用Cookie管理,示例如下:
import ( "database/sql" "net/http" "net/http/cookiejar" _ "github.com/apache/calcite-avatica-go/v5" ) func main() { // 创建Cookie Jar,用于存储会话Cookie jar, err := cookiejar.New(nil) if err != nil { panic(err) } // 配置带Cookie管理的HTTP客户端 httpClient := &http.Client{Jar: jar} db, err := sql.Open("avatica", "http://192.168.3.236:8766") if err != nil { panic(err) } defer db.Close() // 将自定义HTTP客户端注入Avatica驱动 if driver, ok := db.Driver().(*avatica.Driver); ok { driver.SetHTTPClient(httpClient) } rows, err := db.Query("SELECT COUNT(*) FROM test.test1") if err != nil { panic(err) } defer rows.Close() // 处理查询结果... }
3. Nginx版本兼容性
Nginx 1.8.1版本较老,sticky模块可能存在兼容性问题,若上述调整无效,可尝试升级Nginx到较新版本(如1.20+)再测试。
内容的提问来源于stack exchange,提问作者kaber
相关产品推荐
相关产品推荐

