policy

package
v0.0.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 10, 2026 License: MIT Imports: 7 Imported by: 0

README

Policy 模块

概述

Policy 模块负责管理用户到后端的映射关系和访问策略。定义哪个代理用户可以访问哪个后端实例,以及访问时的路由、限流等策略。

职责

  • ✅ 用户-后端映射管理
  • ✅ 访问权限控制
  • ✅ 路由策略配置(轮询、哈希、读写分离)
  • ✅ 限流策略配置
  • ✅ 后端凭据管理(加密存储)
  • ✅ 映射关系缓存管理

数据模型

user_mappings 表(通用映射表)
CREATE TABLE user_mappings (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(64) NOT NULL COMMENT '代理用户名',
    service_name VARCHAR(64) NOT NULL COMMENT '服务名 (rds, ssh, redis)',
    backend_id VARCHAR(64) NOT NULL COMMENT '后端实例ID',
    backend_username VARCHAR(64) NOT NULL COMMENT '后端用户名',
    backend_password VARCHAR(512) NOT NULL COMMENT '后端密码(AES加密)',
    backend_database VARCHAR(64) COMMENT '目标库/数据库(可选)',
    read_only BOOLEAN DEFAULT FALSE COMMENT '是否只读',
    priority INT DEFAULT 1 COMMENT '优先级(值越大越优先)',
    enabled BOOLEAN DEFAULT TRUE COMMENT '是否启用',
    description VARCHAR(255) COMMENT '映射描述',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uk_user_service_backend (username, service_name, backend_id),
    INDEX idx_username (username),
    INDEX idx_service (service_name),
    INDEX idx_backend_id (backend_id),
    FOREIGN KEY (username) REFERENCES mproxy_users(username) ON DELETE CASCADE,
    FOREIGN KEY (backend_id) REFERENCES backend_instances(backend_id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户映射表';

-- 示例:app_developer 用户可以访问 mysql-biz-master
INSERT INTO user_mappings (username, service_name, backend_id, backend_username, backend_password, backend_database, read_only, priority)
VALUES ('app_developer', 'rds', 'mysql-biz-master', 'biz_user', 'encrypted:xxxxx', 'business_db', FALSE, 1);

-- 示例:report_user 可以访问两个从库(负载均衡)
INSERT INTO user_mappings (username, service_name, backend_id, backend_username, backend_password, backend_database, read_only, priority)
VALUES 
  ('report_user', 'rds', 'mysql-biz-slave-1', 'readonly_user', 'encrypted:yyyyy', 'business_db', TRUE, 1),
  ('report_user', 'rds', 'mysql-biz-slave-2', 'readonly_user', 'encrypted:yyyyy', 'business_db', TRUE, 2);
routing_policy 表(路由策略表)
CREATE TABLE routing_policies (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    policy_id VARCHAR(64) NOT NULL UNIQUE COMMENT '策略ID',
    username VARCHAR(64) NOT NULL COMMENT '用户名',
    service_name VARCHAR(64) NOT NULL COMMENT '服务名',
    routing_strategy VARCHAR(32) NOT NULL COMMENT '路由策略 (round_robin, hash, read_write_split, static)',
    rate_limit INT COMMENT '限流(连接数)',
    timeout INT COMMENT '超时时间(秒)',
    retry_count INT DEFAULT 3 COMMENT '重试次数',
    enabled BOOLEAN DEFAULT TRUE,
    metadata JSON COMMENT '策略特定配置',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_username_service (username, service_name),
    FOREIGN KEY (username) REFERENCES mproxy_users(username) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='路由策略表';

接口设计

核心接口
type Service interface {
    // 查询
    GetMapping(context.Context, *GetMappingRequest) (*Mapping, error)
    SearchMapping(context.Context, *SearchMappingRequest) (*types.Set[*Mapping], error)
    ListUserBackends(context.Context, *ListUserBackendsRequest) (*types.Set[*Mapping], error)
    
    // 管理
    CreateMapping(context.Context, *CreateMappingRequest) (*Mapping, error)
    UpdateMapping(context.Context, *UpdateMappingRequest) (*Mapping, error)
    DeleteMapping(context.Context, *DeleteMappingRequest) error
    
    // 路由策略
    GetRoutingPolicy(context.Context, *GetRoutingPolicyRequest) (*RoutingPolicy, error)
    CreateRoutingPolicy(context.Context, *CreateRoutingPolicyRequest) (*RoutingPolicy, error)
    UpdateRoutingPolicy(context.Context, *UpdateRoutingPolicyRequest) (*RoutingPolicy, error)
    
    // 路由决策
    ResolveRoute(context.Context, *ResolveRouteRequest) (*RouteResolution, error)
}

使用场景

场景 1: 用户关联后端
req := &CreateMappingRequest{
    Username:         "app_developer",
    ServiceName:      "rds",
    BackendId:        "mysql-biz-master",
    BackendUsername:  "biz_user",
    BackendPassword:  "encrypted_pass",
    BackendDatabase:  "business_db",
    ReadOnly:         false,
    Priority:         1,
}

mapping, _ := policyService.CreateMapping(ctx, req)
场景 2: 配置路由策略
req := &CreateRoutingPolicyRequest{
    Username:          "app_developer",
    ServiceName:       "rds",
    RoutingStrategy:   "round_robin",  // 多个后端时轮询
    RateLimit:         10,             // 最多10个并发连接
    Timeout:           30,             // 30秒超时
    RetryCount:        3,              // 重试3次
}

policy, _ := policyService.CreateRoutingPolicy(ctx, req)
场景 3: 路由决策
// RDS 代理需要将请求路由到某个后端
resolution, _ := policyService.ResolveRoute(ctx, &ResolveRouteRequest{
    Username:    "app_developer",
    ServiceName: "rds",
    SQL:         "SELECT * FROM users",
})

// 根据分辨率连接相应后端
backend := resolution.SelectedBackend
credentials := resolution.Credentials

API 端点

# 映射管理
GET    /api/mproxy/mappings              # 列表
GET    /api/mproxy/mappings/:mapping_id  # 详情
POST   /api/mproxy/mappings              # 创建
PUT    /api/mproxy/mappings/:mapping_id  # 更新
DELETE /api/mproxy/mappings/:mapping_id  # 删除

# 用户后端列表
GET    /api/mproxy/users/:username/backends  # 该用户可访问的所有后端

# 路由策略
GET    /api/mproxy/routing-policies              # 列表
POST   /api/mproxy/routing-policies              # 创建
PUT    /api/mproxy/routing-policies/:policy_id  # 更新

# 路由决策
POST   /api/mproxy/resolve-route  # 计算路由目标

路由策略说明

Round Robin(轮询)
  • 用途:多个等同后端实例,负载均衡
  • 配置:strategy = "round_robin"
  • 行为:请求依次分配到不同后端
Hash(哈希)
  • 用途:会话粘性,同一用户总是连接同一实例
  • 配置:strategy = "hash"
  • 行为:hash(username) % backend_count
Read/Write Split(读写分离)
  • 用途:MySQL 主从架构
  • 配置:strategy = "read_write_split"
  • 行为:SELECT→Slave, INSERT/UPDATE/DELETE→Master
Static(静态映射)
  • 用途:用户只能访问指定后端
  • 配置:strategy = "static"
  • 行为:总是连接唯一的 backend_id

文件结构

policy/
├── README.md           # 本文档
├── interface.go        # 接口定义
├── impl/
│   ├── impl.go        # 实现
│   └── router.go      # 路由决策逻辑
├── model.go           # 数据模型
└── api.go             # HTTP API

后续增强

  • 策略缓存优化
  • 动态权重调整
  • 蓝绿部署策略
  • 灰度发布策略
  • 限流限连接
  • 熔断策略

Documentation

Index

Constants

View Source
const (
	APP_NAME = "proxy_policy"
)

Variables

This section is empty.

Functions

func NewMappingSet

func NewMappingSet() *types.Set[*Mapping]

func NewRoutingPolicySet

func NewRoutingPolicySet() *types.Set[*RoutingPolicy]

Types

type CreateMappingRequest

type CreateMappingRequest struct {
	Username        string `json:"username"`
	ServiceName     string `json:"service_name"`
	BackendId       string `json:"backend_id"`
	BackendUsername string `json:"backend_username"`
	BackendPassword string `json:"backend_password"`
	BackendDatabase string `json:"backend_database"`
	ReadOnly        bool   `json:"read_only"`
	Priority        int    `json:"priority"`
	Enabled         bool   `json:"enabled"`
	Description     string `json:"description"`
}

func NewCreateMappingRequest

func NewCreateMappingRequest() *CreateMappingRequest

func (*CreateMappingRequest) Validate

func (r *CreateMappingRequest) Validate() error

type CreateRoutingPolicyRequest

type CreateRoutingPolicyRequest struct {
	PolicyId        string                 `json:"policy_id"`
	Username        string                 `json:"username"`
	ServiceName     string                 `json:"service_name"`
	RoutingStrategy string                 `json:"routing_strategy"`
	RateLimit       int                    `json:"rate_limit"`
	Timeout         int                    `json:"timeout"`
	RetryCount      int                    `json:"retry_count"`
	Enabled         bool                   `json:"enabled"`
	Metadata        map[string]interface{} `json:"metadata"`
}

func NewCreateRoutingPolicyRequest

func NewCreateRoutingPolicyRequest() *CreateRoutingPolicyRequest

func (*CreateRoutingPolicyRequest) Validate

func (r *CreateRoutingPolicyRequest) Validate() error

type DeleteMappingRequest

type DeleteMappingRequest struct {
	GetMappingRequest
}

func NewDeleteMappingRequest

func NewDeleteMappingRequest(id int64) *DeleteMappingRequest

type GetMappingRequest

type GetMappingRequest struct {
	Id int64 `json:"id"`
}

func NewGetMappingRequest

func NewGetMappingRequest(id int64) *GetMappingRequest

type GetRoutingPolicyRequest

type GetRoutingPolicyRequest struct {
	PolicyId string `json:"policy_id"`
}

func NewGetRoutingPolicyRequest

func NewGetRoutingPolicyRequest(policyId string) *GetRoutingPolicyRequest

type Mapping

type Mapping struct {
	Id              int64     `json:"id" gorm:"column:id;primaryKey"`
	Username        string    `json:"username" gorm:"column:username"`
	ServiceName     string    `json:"service_name" gorm:"column:service_name"`
	BackendId       string    `json:"backend_id" gorm:"column:backend_id"`
	BackendUsername string    `json:"backend_username" gorm:"column:backend_username"`
	BackendPassword string    `json:"-" gorm:"column:backend_password"`
	BackendDatabase string    `json:"backend_database" gorm:"column:backend_database"`
	ReadOnly        bool      `json:"read_only" gorm:"column:read_only"`
	Priority        int       `json:"priority" gorm:"column:priority"`
	Enabled         bool      `json:"enabled" gorm:"column:enabled"`
	Description     string    `json:"description" gorm:"column:description"`
	CreatedAt       time.Time `json:"created_at" gorm:"column:created_at"`
	UpdatedAt       time.Time `json:"updated_at" gorm:"column:updated_at"`
}

Mapping 用户到后端的映射关系

func NewMapping

func NewMapping() *Mapping

func (*Mapping) String

func (m *Mapping) String() string

func (*Mapping) TableName

func (m *Mapping) TableName() string

type MappingResponse

type MappingResponse struct {
	Data *Mapping `json:"data"`
}

MappingResponse API响应格式

type MappingSet

type MappingSet struct {
	*types.Set[*Mapping]
}

func (*MappingSet) String

func (s *MappingSet) String() string

type MappingSetResponse

type MappingSetResponse struct {
	Data *types.Set[*Mapping] `json:"data"`
}

MappingSetResponse 列表响应

type ResolveRouteRequest

type ResolveRouteRequest struct {
	Username    string `json:"username"`
	ServiceName string `json:"service_name"`
}

func NewResolveRouteRequest

func NewResolveRouteRequest(username, serviceName string) *ResolveRouteRequest

func (*ResolveRouteRequest) Validate

func (r *ResolveRouteRequest) Validate() error

type RoutingPolicy

type RoutingPolicy struct {
	Id              int64                  `json:"id" gorm:"column:id;primaryKey"`
	PolicyId        string                 `json:"policy_id" gorm:"column:policy_id;uniqueIndex"`
	Username        string                 `json:"username" gorm:"column:username"`
	ServiceName     string                 `json:"service_name" gorm:"column:service_name"`
	RoutingStrategy string                 `json:"routing_strategy" gorm:"column:routing_strategy"`
	RateLimit       int                    `json:"rate_limit" gorm:"column:rate_limit"`
	Timeout         int                    `json:"timeout" gorm:"column:timeout"`
	RetryCount      int                    `json:"retry_count" gorm:"column:retry_count"`
	Enabled         bool                   `json:"enabled" gorm:"column:enabled"`
	Metadata        map[string]interface{} `json:"metadata" gorm:"column:metadata;type:json"`
	CreatedAt       time.Time              `json:"created_at" gorm:"column:created_at"`
	UpdatedAt       time.Time              `json:"updated_at" gorm:"column:updated_at"`
}

RoutingPolicy 路由策略配置

func NewRoutingPolicy

func NewRoutingPolicy() *RoutingPolicy

func (*RoutingPolicy) Scan

func (p *RoutingPolicy) Scan(value interface{}) error

Scan 实现 Scanner 接口

func (*RoutingPolicy) String

func (p *RoutingPolicy) String() string

func (*RoutingPolicy) TableName

func (p *RoutingPolicy) TableName() string

type RoutingPolicyResponse

type RoutingPolicyResponse struct {
	Data *RoutingPolicy `json:"data"`
}

RoutingPolicyResponse API响应格式

type RoutingPolicySet

type RoutingPolicySet struct {
	*types.Set[*RoutingPolicy]
}

RoutingPolicySet 路由策略集合

func (*RoutingPolicySet) String

func (s *RoutingPolicySet) String() string

type RoutingStrategy

type RoutingStrategy string

RoutingStrategy 路由策略类型

const (
	RoundRobin     RoutingStrategy = "round_robin"
	Hash           RoutingStrategy = "hash"
	ReadWriteSplit RoutingStrategy = "read_write_split"
	Static         RoutingStrategy = "static"
)

type SearchMappingRequest

type SearchMappingRequest struct {
	Username    string `json:"username"`
	ServiceName string `json:"service_name"`
	BackendId   string `json:"backend_id"`
	Enabled     *bool  `json:"enabled"`
}

func NewSearchMappingRequest

func NewSearchMappingRequest() *SearchMappingRequest

type Service

type Service interface {
	// 获取映射详情
	GetMapping(context.Context, *GetMappingRequest) (*Mapping, error)
	// 查询映射列表
	SearchMapping(context.Context, *SearchMappingRequest) (*types.Set[*Mapping], error)
	// 创建映射
	CreateMapping(context.Context, *CreateMappingRequest) (*Mapping, error)
	// 更新映射
	UpdateMapping(context.Context, *UpdateMappingRequest) (*Mapping, error)
	// 删除映射
	DeleteMapping(context.Context, *DeleteMappingRequest) (*Mapping, error)
	// 获取路由策略
	GetRoutingPolicy(context.Context, *GetRoutingPolicyRequest) (*RoutingPolicy, error)
	// 创建路由策略
	CreateRoutingPolicy(context.Context, *CreateRoutingPolicyRequest) (*RoutingPolicy, error)
	// 解析路由 - 根据用户和服务名获取对应的后端
	ResolveRoute(context.Context, *ResolveRouteRequest) (*Mapping, error)
}

func GetService

func GetService() Service

type UpdateMappingRequest

type UpdateMappingRequest struct {
	Id              int64   `json:"id"`
	BackendUsername *string `json:"backend_username"`
	BackendPassword *string `json:"backend_password"`
	BackendDatabase *string `json:"backend_database"`
	ReadOnly        *bool   `json:"read_only"`
	Priority        *int    `json:"priority"`
	Enabled         *bool   `json:"enabled"`
	Description     *string `json:"description"`
}

func NewUpdateMappingRequest

func NewUpdateMappingRequest(id int64) *UpdateMappingRequest

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL