🙈 By 单雷 2025-11-10
1.需求背景
目前市场上存在多种类型的分布式数据库,出于兼容性考虑,很多数据库都提供标准的mysql的访问接口; 其基本架构都是多节点分区存储数据,有的甚至采用存储和计算节点分离的模式,但无论怎样,出于高可用性以及支撑访问量水平扩展的需要,其前端都需要部署一个负载均衡设施。以Apache Doris为例,其配置文档中明确的指出了负载均衡设施的必要性,并给出了市场上常见的4层代理软件,如NGINX,HAPROXY,或特定的proxysql的配置样例。
Doris给出的配置样例,其仅仅采用配置文件,意味着数据库节点扩容时,必须修改配置文件,重启生效,会对业务有一定的影响,更重要的是NGINX/HAPROXY的配置,仅仅把后端的数据库节点当作一个TCP服务器,无法感知节点的状态,这样在节点状态异常时,会给客户端带来不好的访问体验。
针对此类数据库分布式访问的场景,以NJet作为数据库前端的负载均衡,其特有能力,可以大大简化分布式数据库的运维工作,提升使用者的体验。其一是动态成员维护,可以在数据库节点扩/缩容时,通过API自动进行成员变更,而正在进行的访问不受影响; 其二是特定的sql主动健康检查,可以预先发现问题节点,自动下线,避免使用者的故障感知;其三是可以使用json格式的配置文件,便于运维操作。
2.NJet实现Doris负载均衡
以Doris为例,在192.168.1.100上部署proxy,代理访问后端三个节点(192.168.1.101,102,103)利用NJet作为负载均衡设施,其初始配置和NGINX一致,不同的是在njet.conf中
events {
worker_connections 1024;
}
stream {
upstream mysqld {
hash $remote_addr consistent;
server 192.168.1.101:9030 weight=1 max_fails=2 fail_timeout=60s;
server 192.168.1.102:9030 weight=1 max_fails=2 fail_timeout=60s;
server 192.168.1.103:9030 weight=1 max_fails=2 fail_timeout=60s;
}
server {
# Proxy port
listen 6030;
proxy_connect_timeout 300s;
proxy_timeout 300s;
proxy_pass mysqld;
}
}
在njet启动后,下面就可以利用NJet的特有能力,方便数据库的运维
2.1 NJet动态成员维护
OpenNJet可以通过动态api接口的方式,动态对upstream中的成员进行新增,删除,修改,查询。为支持动态成员维护,NJet.conf和njet_ctrl文件需要做相关的配置变更,如下面配置样例中标黄色部分
- 数据面配置(njet.conf)示例
helper broker modules/njt_helper_broker_module.so conf/mqtt.conf;
helper ctrl modules/njt_helper_ctrl_module.so conf/ctrl.conf;
load_module modules/njt_http_upstream_member_module.so;
stream {
upstream mysqld {
zone mysqld 16k; #必须配置共享内存
hash $remote_addr consistent;
server 192.168.1.101:9030 weight=1 max_fails=2 fail_timeout=60s;
server 192.168.1.102:9030 weight=1 max_fails=2 fail_timeout=60s;
server 192.168.1.103:9030 weight=1 max_fails=2 fail_timeout=60s;
}
server {
# Proxy port
listen 6030;
proxy_connect_timeout 300s;
proxy_timeout 300s;
proxy_pass mysqld;
}
}
- 控制面配置(njet_ctrl.conf)示例
load_module modules/njt_http_sendmsg_module.so;
load_module modules/njt_http_upstream_api_module.so;
load_module modules/njt_helper_health_check_module.so;
http {
server {
listen 8081;
location /api {
dyn_module_api;
}
}
}
2.1.1 添加upstream成员
假设后续Doris做集群扩容,添加了节点192.168.1.104:9030,可以通过下面api进行添加:
api url: POST http://{机器ip}:8081/api/v1/upstream_api/stream/upstreams/{upstream_name}/servers/
curl -X POST http://127.0.0.1:8081/api/v1/upstream_api/stream/upstreams/mysqld/servers/ -d '{
"server": "192.168.1.104:9030",
"weight": 2,
"max_conns": 2,
"max_fails": 1,
"fail_timeout": "5s",
"slow_start": "5s",
"route": "",
"backup": false,
"down": false
}'
添加成员192.168.1.104:9030后,OpenNJet会自动给该成员按顺序分配id,可以通过该id后续对该成员进行查询,删除,修改等操作。
2.1.2 删除upstream成员
api url: DELETE http://{机器ip}:8081/api/v1/upstream_api/stream/upstreams/{upstream_name}/servers/{id}
执行后删除对应id的成员。
curl -X DELETE http://127.0.0.1:8081/api/v1/upstream_api/stream/upstreams/mysqld/servers/3
2.2 NJet 配置mysql健康检查
OpenNJet默认安装是启用主动健康检查的,可以直接通过控制面提供的api接口(默认启用8081端口来提供配置服务)进行配置。,api url: http://{机器ip}:8081/api/v1/hc/smysql/{upstreamname},具体样例如下:
curl -X 'POST' \
'http://127.0.0.1:8081/api/v1/hc/smysql/mysqld' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"interval": "5s",
"jitter": "1s",
"timeout": "5s",
"passes": 1,
"fails": 1,
"sql": {
"select": "select 1",
"useSsl": true,
"user": "root",
"password": "123456",
"db": "db"
}
}'
配置后就可以定期执行,并在后端服务故障时自动下线(下线后仍然会执行检查,并在检查成功后自动恢复上线)
2.2.1 健康检查配置说明
字段介绍
| 字段名称 | 必须配置 | 说明 |
|---|---|---|
| interval | 是 | 主动健康检查频率 |
| visit_interval | 否 | 健康检查时,如果指定的时间间隔内该server被客户端访问过,则该server跳过此次健康检查,interval > visit_interval |
| jitter | 是 | 设置健康检查项定时器最大偏差。防止所有检查项同时触发。 |
| timeout | 是 | 超时时间 |
| passes | 是 | server_body server 块内的指令集,每条指令用分号分隔。server_body内容可以为空。 |
| fails | 是 | 连续不通过fails次检测,更新peer为unhealthy状态 |
| port | 否 | 指定健康检查的端口,如果不指定,使用upstream中设置的端口 |
sql块配置字段详细介绍
| 字段名称 | 子字段名称 | 类型 | 必须配置 | 默认值 | 说明 |
|---|---|---|---|---|---|
| sql块 | select | 字符串 | 否 | select 1 | 查询语句 |
| useSsl | bool | 否 | true | 是否使用ssl连接 | |
| user | 字符串 | 否 | - | mysql数据库用户名 | |
| password | 字符串 | 否 | - | mysql数据库密码 | |
| db | 字符串 | 是 | - | mysql数据库名称 |
2.3 Json配置文件支持
目前常见的nginx,haproxy等代理设施,其配置文件,非常不方便维护,而NJet提供了json格式的配置文件,可以利用jsonpath快速定位,操作数据,方便运维。如上述的njet.conf,可以方便的转换为json格式,并把njet.conf修改为njet.json,就可以被njet使用(njet -c conf/njet.json)
[
{
"cmd": "events",
"args": [],
"block": [
{
"cmd": "worker_connections",
"args": [
"1024"
]
}
]
},
{
"cmd": "stream",
"args": [],
"block": [
{
"cmd": "upstream",
"args": [
"mysqld"
],
"block": [
{
"cmd": "hash",
"args": [
"$remote_addr",
"consistent"
]
},
{
"cmd": "server",
"args": [
"192.168.1.101:9030",
"weight=1",
"max_fails=2",
"fail_timeout=60s"
]
},
{
"cmd": "server",
"args": [
"192.168.1.102:9030",
"weight=1",
"max_fails=2",
"fail_timeout=60s"
]
},
{
"cmd": "server",
"args": [
"192.168.1.103:9030",
"weight=1",
"max_fails=2",
"fail_timeout=60s"
]
}
]
},
{
"cmd": "server",
"args": [],
"block": [
{
"cmd": "listen",
"args": [
"6030"
]
},
{
"cmd": "proxy_connect_timeout",
"args": [
"300s"
]
},
{
"cmd": "proxy_timeout",
"args": [
"300s"
]
},
{
"cmd": "proxy_pass",
"args": [
"mysqld"
]
}
]
}
]
}
]
3. 备注
- OpenNJet如何使用请参考https://docs.njet.org.cn/docs/v4.0.0/guide/install/index.html
- 更详细的健康检查介绍和配置可以参考https://docs.njet.org.cn/docs/v4.0.0/reference/upstream/health_check/mysql_health_check/index.html
- upstream_api全部功能介绍可以参考文档https://docs.njet.org.cn/docs/v4.0.0/reference/upstream/upstream_api/index.html
- Apache Doris https://doris.apache.org/zh-CN/docs/dev/gettingStarted/what-is-apache-doris
Apache Doris 是一款基于 MPP 架构的高性能、实时分析型数据库。 采用 MySQL 协议,高度兼容 MySQL 语法,支持标准 SQL。在生产环境中,可以部署多个 FE 节点以实现容灾备份。FE节点主要负责接收用户请求、查询解析和规划、元数据管理以及节点管理。
FE节点前需部署负载均衡,参考https://doris.apache.org/zh-CN/docs/dev/admin-manual/cluster-management/load-balancing
- sql的主动健康检查是NJet4.0提供的能力,目前支持mysql,后面支持pg等数据库接口
- 出于安全考虑,自4.0起,NJet的api接口默认只能通过本机访问,如果要通过远程访问,需修改njet_ctrl.conf中的监听配置,并强烈建议—配置访问控制