控制与限制
网关存在的意义不是「开放」,而是 「开放但不受伤害」。本页将说明什么被阻止、什么被限制、什么被记录,并附上具体数值。
修改模式的语句会被阻止
如果第一个令牌是以下六种之一,则返回 400 QUERY_SYNTAX。
DROP · TRUNCATE · ALTER · CREATE · GRANT · REVOKE
{"result":"ERROR","error_code":"QUERY_SYNTAX",
"message":"DDL statements are not allowed: DROP"}
无法通过注释绕过。 在移除块注释和行注释后,我们才会查看第一个令牌。
/* 안녕 */ DROP TABLE pp.mm_tag -- 막힙니다
-- 한 줄
DROP TABLE pp.mm_tag -- 막힙니다
如果移除注释后无任何内容留存,这也返回 400。
存在分号即拒绝
{"result":"ERROR","error_code":"QUERY_SYNTAX",
"message":"Multiple statements are not allowed"}
仅检查第一个令牌的方法,只有当一条请求中包含一条语句时才成立。如果允许 SELECT 1; DROP TABLE x,那么第一个令牌就是 SELECT,检查便会直接通过。因此,一旦看到分号,在查看内容之前就会拒绝。
结果行数上限
| 设置 | 默认值 |
|---|---|
data.gateway.query.max.rows | 100,000(0 = 无限制) |
达到上限后,网关会在此处停止读取——而不是读取完整个结果后再截断。这样,即便结果巨大,也不会产生无限流。
POST /api/v1/query→ 响应中的truncated字段POST /api/v1/query/stream→end行中的truncated字段
服务器日志中也会记录。
Query result truncated to max_rows=[100000], lang=[PQL]
HTTP 返回 200,行数也正常。如果不查看 truncated,就会误以为结果是完整的并进行汇总。 这就是始终携带此标志的原因。
速率限制
| 设置 | 默认值 | 说明 |
|---|---|---|
data.gateway.rate.limit | 1000 | 每个客户端每秒请求数 |
data.gateway.rate.limit.global | 0(无限制) | 所有客户端合计的上限 |
data.gateway.trusted.proxies | 空 | 信任的直连对等节点列表,用于信任 X-Forwarded-For |
桶键是可信的客户端 IP。
X-Forwarded-For 默认情况下被忽略仅当直连对等节点存在于 trusted.proxies 中时,才信任 XFF 的第一跳作为客户端 IP。如果留空,则始终使用实际连接地址——否则,伪造一个请求头即可绕过限额。
如果部署在反向代理之后,请务必将该代理的地址加入此列表。否则,所有请求都会集中到该代理的一个桶中。
全局上限是对「桶激增」的防御——即使创建大量不同 IP,总吞吐量也不会超过此值。
/admin/* 也「共享」相同的限额/api/* 和 /admin/* 使用同一个计数器。如果分开设置,全局上限会实际翻倍,并且可以分摊到两个入口点来绕过限制。
请求大小
| 设置 | 默认值 |
|---|---|
data.gateway.max.body.bytes | 1,048,576(1 MB) |
data.gateway.max.params.bytes | 65,536(64 KB) |
超出后以 413 提前拒绝——在读取之前就断开,而不是读取之后。
超时与慢日志
| 设置 | 默认值 | 说明 |
|---|---|---|
data.gateway.async.timeout.ms | 60,000 | 异步请求超时 |
data.gateway.slow.query.ms | 10,000 | 比此值更慢的读取记录为警告 |
data.gateway.slow.update.ms | 2,000 | 比此值更慢的写入记录为警告 |
请求使用虚拟线程处理。并发执行上限是 data.gateway.async.concurrency.limit,默认值为 256(若为 0 则无限制)。达到上限时,提交方会等待有空间可用——不会丢弃,而是施加背压。启动日志会输出实际值。
Async executor: virtual threads, concurrency limit=[256]
以前的固定线程池,在队列达到 500 个请求之前不会将线程数增加到超过 20,因此实际并发查询为 20,而队列中等待的请求会因 60 秒超时而返回 503。实际瓶颈在于数据库连接池,因此现在只设置一个并发上限,而不是调整池的大小。
查询日志 — 所有请求都会记录
| 项目 | 值 |
|---|---|
| 表 | tm_data_gateway_log(Aster TSDB,timeuuid 主键) |
| 保留内容 | 语言 · 查询语句 · 行数 · 执行时间 · 是否失败 · 错误信息 |
| 写入 | 放入队列并批量 flush — 不会阻塞查询路径 |
队列的状态由 GET /admin/metrics 中的 gateway.querylog.* 指标输出。
/api/health 是就绪状态,而非存活状态仅凭上下文存在就报告 UP 没有意义——只有准备好接收查询时才是 UP。检查集(database · inmemory · query_log)必须全部为真,否则为 STARTING 或 DEGRADED。查询日志未初始化的网关不是 UP — 如果缺少审计记录却显示为「正常」,以后就无法回答「谁查询了什么」。
认证 · 控制台账户
- 认证由一条 Spring Security 链决定。不在列表中的路径会返回 401,而不是匿名访问。
- 不创建会话,也不使用 cookie(STATELESS)。凭证在每个请求中通过请求头传递。
- 控制台登录账户(
data.gateway.web.user·data.gateway.web.password)必须都填写才能访问。如果缺少任何一个,界面会提示「未配置」,并全部以 503LOGIN_NOT_CONFIGURED拒绝。
如果内置默认账户,所有客户安装都会携带相同的凭证,而且没有人会更改它们。 请将值放入渲染的配置(plantpulse-datalake-cli 的模板)中。
用户名和密码始终都要进行比对(即使一个错误,也不会跳过另一个),失败响应不会指明是哪一侧错误。
更改数值
权威配置是 plantpulse-datalake-cli 中的 config/templates/。在容器内修改的内容会在重启后丢失。
docker exec plantpulse-datalake pd config diff --templates
docker exec plantpulse-datalake pd restart data-gateway
流程参见更改配置,密钥轮换参见更改密码 · API 密钥。