gateway.sql 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. -- ============================================================================
  2. -- ai-gateway 网关表(按用户粘性路由,见 docs/design/ai-gateway-user-sticky-routing.md)
  3. -- 目标库:PostgreSQL(与 ai-server 共享同一个库,网关表独立于业务表)
  4. -- 执行方式:ai-gateway 启动时由 spring.sql.init 自动执行(本脚本可重复执行)
  5. --
  6. -- 注意:同 user.sql,这是**平台库**表,不登记到 table_info / table_field。
  7. -- ============================================================================
  8. -- ---------------------------------------------------------------------------
  9. -- 1. 服务:一组对外路径前缀 + 一组后端节点
  10. -- 首次启动若表为空,用 ai-gateway application.yaml 的 gateway.services 播种;
  11. -- 之后以数据库为准,YAML 不再覆盖(变更走 /gateway/admin/** 管理接口)。
  12. -- ---------------------------------------------------------------------------
  13. CREATE TABLE IF NOT EXISTS gateway_service (
  14. id VARCHAR(64) PRIMARY KEY,
  15. name VARCHAR(128) NOT NULL,
  16. -- 对外路径前缀,如 /js/a;全局唯一,不能以 / 结尾、不能是 /gateway
  17. path_prefix VARCHAR(128) NOT NULL,
  18. -- 相对登录路径(相对 path_prefix),如 /auth/login;可空 = 无登录粘性
  19. login_path VARCHAR(128),
  20. -- 完整健康检查路径,如 /js/a/sys/health
  21. health_path VARCHAR(255) NOT NULL,
  22. -- 存量用户兜底节点;网关上线前已存在的用户若未绑定路由则落到该节点
  23. default_node_id VARCHAR(64),
  24. enabled SMALLINT NOT NULL DEFAULT 1,
  25. create_time TIMESTAMP NOT NULL DEFAULT now(),
  26. update_time TIMESTAMP NOT NULL DEFAULT now()
  27. );
  28. CREATE UNIQUE INDEX IF NOT EXISTS uk_gateway_service_path_prefix
  29. ON gateway_service (path_prefix);
  30. COMMENT ON TABLE gateway_service IS '网关服务定义(路径前缀 -> 节点组)';
  31. COMMENT ON COLUMN gateway_service.login_path IS '相对路径前缀的登录路径,如 /auth/login;空 = 不做登录粘性';
  32. COMMENT ON COLUMN gateway_service.default_node_id IS '存量用户兜底节点 id;无绑定的已登录用户会被绑定到该节点';
  33. -- ---------------------------------------------------------------------------
  34. -- 2. 节点:一台 ai-server 实例
  35. -- base_url 不含路径(context-path 由转发的原始路径携带);同一服务内地址唯一。
  36. -- ---------------------------------------------------------------------------
  37. CREATE TABLE IF NOT EXISTS gateway_node (
  38. id VARCHAR(64) PRIMARY KEY,
  39. service_id VARCHAR(64) NOT NULL,
  40. name VARCHAR(128) NOT NULL,
  41. base_url VARCHAR(255) NOT NULL,
  42. enabled SMALLINT NOT NULL DEFAULT 1,
  43. remark VARCHAR(512),
  44. create_time TIMESTAMP NOT NULL DEFAULT now(),
  45. update_time TIMESTAMP NOT NULL DEFAULT now()
  46. );
  47. CREATE UNIQUE INDEX IF NOT EXISTS uk_gateway_node_service_base_url
  48. ON gateway_node (service_id, base_url);
  49. COMMENT ON TABLE gateway_node IS '网关后端节点(一台 ai-server)';
  50. COMMENT ON COLUMN gateway_node.base_url IS 'http(s)://host:port,不含路径';
  51. ALTER TABLE gateway_node
  52. DROP CONSTRAINT IF EXISTS fk_gateway_node_service;
  53. ALTER TABLE gateway_node
  54. ADD CONSTRAINT fk_gateway_node_service
  55. FOREIGN KEY (service_id) REFERENCES gateway_service (id) ON DELETE RESTRICT;
  56. -- ---------------------------------------------------------------------------
  57. -- 3. 用户路由:用户 -> 节点 的粘性绑定
  58. -- user_id / username 至少一个非空;唯一性用「部分唯一索引」保证:
  59. -- - (service_id, user_id) user_id 非空时唯一
  60. -- - (service_id, lower(username)) username 非空时唯一(用户名不区分大小写,
  61. -- 与 sys_user 的 uk_sys_user_username 对齐)
  62. -- bindIfAbsent 用不带冲突目标的 ON CONFLICT DO NOTHING,由上面两个索引裁决并发。
  63. -- ---------------------------------------------------------------------------
  64. CREATE TABLE IF NOT EXISTS gateway_user_route (
  65. id BIGSERIAL PRIMARY KEY,
  66. service_id VARCHAR(64) NOT NULL,
  67. -- sys_user.id;可空(允许只按用户名预绑定)
  68. user_id BIGINT,
  69. username VARCHAR(64),
  70. node_id VARCHAR(64) NOT NULL,
  71. create_time TIMESTAMP NOT NULL DEFAULT now(),
  72. update_time TIMESTAMP NOT NULL DEFAULT now(),
  73. -- user_id、username 至少一个非空
  74. CONSTRAINT ck_gateway_user_route_owner CHECK (user_id IS NOT NULL OR username IS NOT NULL)
  75. );
  76. CREATE UNIQUE INDEX IF NOT EXISTS uk_gateway_user_route_user
  77. ON gateway_user_route (service_id, user_id) WHERE user_id IS NOT NULL;
  78. CREATE UNIQUE INDEX IF NOT EXISTS uk_gateway_user_route_name
  79. ON gateway_user_route (service_id, lower(username)) WHERE username IS NOT NULL;
  80. CREATE INDEX IF NOT EXISTS idx_gateway_user_route_node
  81. ON gateway_user_route (node_id);
  82. COMMENT ON TABLE gateway_user_route IS '网关用户粘性路由(用户 -> 节点)';
  83. COMMENT ON COLUMN gateway_user_route.node_id IS '绑定的目标节点;节点不可用时网关返回 503,不自动切换';
  84. ALTER TABLE gateway_user_route
  85. DROP CONSTRAINT IF EXISTS fk_gateway_user_route_service;
  86. ALTER TABLE gateway_user_route
  87. ADD CONSTRAINT fk_gateway_user_route_service
  88. FOREIGN KEY (service_id) REFERENCES gateway_service (id) ON DELETE RESTRICT;
  89. ALTER TABLE gateway_user_route
  90. DROP CONSTRAINT IF EXISTS fk_gateway_user_route_node;
  91. ALTER TABLE gateway_user_route
  92. ADD CONSTRAINT fk_gateway_user_route_node
  93. FOREIGN KEY (node_id) REFERENCES gateway_node (id) ON DELETE RESTRICT;