diff --git a/docs/docs/Features/sharding.md b/docs/docs/Features/sharding.md index 978f24e4..fb0b5609 100644 --- a/docs/docs/Features/sharding.md +++ b/docs/docs/Features/sharding.md @@ -16,9 +16,13 @@ sidebar_position: 6 ``` ### 名词解释 + SQL 解析: 在分片中,请求到达 Pisa-Proxy 后会首先经过 SQL Parser,将 SQL 解析成 AST。 + SQL 改写: 解析结束后,Pisa-Proxy 会根据分片规则对当前 SQL 语句进行改写,生成真实要执行的 SQL 语句。 + SQL 路由: Pisa-Proxy 会根据分片规则,将改写好的 SQL 语句路由到后端对应数据源上执行 SQL 语句。 + 结果归并: SQL 被下推执行之后,Pisa-Proxy 会对查询结果进行归并,并最终返回给客户端。 ### SQL 改写介绍 @@ -37,6 +41,11 @@ SELECT order_id FROM order.t_order WHERE order_id = 1; ``` SELECT order_id FROM order.t_order_00001 WHERE order_id = 1; ``` +下图展示了数据查询过程 +![](/img/sharding-select.png) + +以数据插入为例,数据写入过程如下图: +![](/img/sharding-select.png) **特别说明: SQL rewrite 在修改标识符计算实际表名时会自动根据分片规则添加表索引,索引规则位 表名_索引,索引位为5位表示。例如:`t_order` 表改写后为 `t_order_00000`。因此用户需要根据实际业务场景先创建好对应的表名** @@ -81,9 +90,9 @@ SELECT COUNT(price) AS AVG_DERIVED_COUNT_00000, SUM(price) AS AVG_DERIVED_SUM_00 | 属性 | 值类型 | 是否依赖 | 默认值 | 含义 | |-----|-------|---------|-------|-----| | table_name |String|是|无|分片表名| -| actual_datanodes| Vec\|是|无|后端数据源| -|binding_tables|Vec\|否|无|暂不支持|| -|broadcast_tables|Vec\|否|无|暂不支持|| +| actual_datanodes| array[String]|是|无|后端数据源| +|binding_tables|arrayString]|否|无|暂不支持|| +|broadcast_tables|array[String]|否|无|暂不支持|| |table_sharding_algorithm_name|enum|是|无|分片算法| |table_sharding_column|String|是|无|分片键| |sharding_count|u64|是|无|分片数| \ No newline at end of file diff --git a/docs/package-lock.json b/docs/package-lock.json index 323c670a..64467192 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -15,7 +15,7 @@ "prism-react-renderer": "^1.3.1", "react": "^17.0.2", "react-dom": "^17.0.2", - "react-github-btn": "^1.2.1" + "react-github-btn": "^1.4.0" } }, "node_modules/@algolia/autocomplete-core": { @@ -6313,9 +6313,9 @@ } }, "node_modules/github-buttons": { - "version": "2.21.1", - "resolved": "https://registry.npmmirror.com/github-buttons/-/github-buttons-2.21.1.tgz", - "integrity": "sha512-n9bCQ8sj+5oX1YH5NeyWGbAclRDtHEhMBzqw2ctsWpdEHOwVgfruRu0VIVy01Ah10dd/iFajMHYU71L7IBWBOw==" + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/github-buttons/-/github-buttons-2.22.0.tgz", + "integrity": "sha512-N5bk01s1WgK1FVtoeSUVkRkJpkaSu8yHMPcjye+PTa0jsRjMRNrYqVLgpUf2RA5Kvec05DfHYAT6/68fwkdqPw==" }, "node_modules/github-slugger": { "version": "1.4.0", @@ -9676,11 +9676,14 @@ "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" }, "node_modules/react-github-btn": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/react-github-btn/-/react-github-btn-1.2.2.tgz", - "integrity": "sha512-X4IcX2qwaLciSa4wcUsrFgF2PcT+ukMbZZRBT50ZvO2HJMyqQJNYNHErCN2R0sgZfSFQHUuUHlGndF15VQUhPA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/react-github-btn/-/react-github-btn-1.4.0.tgz", + "integrity": "sha512-lV4FYClAfjWnBfv0iNlJUGhamDgIq6TayD0kPZED6VzHWdpcHmPfsYOZ/CFwLfPv4Zp+F4m8QKTj0oy2HjiGXg==", "dependencies": { - "github-buttons": "^2.21.1" + "github-buttons": "^2.22.0" + }, + "peerDependencies": { + "react": ">=16.3.0" } }, "node_modules/react-helmet-async": { @@ -11362,6 +11365,19 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", + "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/ua-parser-js": { "version": "0.7.31", "resolved": "https://registry.npmmirror.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz", @@ -17248,9 +17264,9 @@ } }, "github-buttons": { - "version": "2.21.1", - "resolved": "https://registry.npmmirror.com/github-buttons/-/github-buttons-2.21.1.tgz", - "integrity": "sha512-n9bCQ8sj+5oX1YH5NeyWGbAclRDtHEhMBzqw2ctsWpdEHOwVgfruRu0VIVy01Ah10dd/iFajMHYU71L7IBWBOw==" + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/github-buttons/-/github-buttons-2.22.0.tgz", + "integrity": "sha512-N5bk01s1WgK1FVtoeSUVkRkJpkaSu8yHMPcjye+PTa0jsRjMRNrYqVLgpUf2RA5Kvec05DfHYAT6/68fwkdqPw==" }, "github-slugger": { "version": "1.4.0", @@ -19638,11 +19654,11 @@ "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" }, "react-github-btn": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/react-github-btn/-/react-github-btn-1.2.2.tgz", - "integrity": "sha512-X4IcX2qwaLciSa4wcUsrFgF2PcT+ukMbZZRBT50ZvO2HJMyqQJNYNHErCN2R0sgZfSFQHUuUHlGndF15VQUhPA==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/react-github-btn/-/react-github-btn-1.4.0.tgz", + "integrity": "sha512-lV4FYClAfjWnBfv0iNlJUGhamDgIq6TayD0kPZED6VzHWdpcHmPfsYOZ/CFwLfPv4Zp+F4m8QKTj0oy2HjiGXg==", "requires": { - "github-buttons": "^2.21.1" + "github-buttons": "^2.22.0" } }, "react-helmet-async": { @@ -20916,6 +20932,12 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", + "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", + "peer": true + }, "ua-parser-js": { "version": "0.7.31", "resolved": "https://registry.npmmirror.com/ua-parser-js/-/ua-parser-js-0.7.31.tgz", diff --git a/docs/package.json b/docs/package.json index 53dcffcd..8b83bb0e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -21,7 +21,7 @@ "prism-react-renderer": "^1.3.1", "react": "^17.0.2", "react-dom": "^17.0.2", - "react-github-btn": "^1.2.1" + "react-github-btn": "^1.4.0" }, "browserslist": { "production": [ diff --git a/docs/static/img/sharding-insert.png b/docs/static/img/sharding-insert.png new file mode 100644 index 00000000..4f2f6351 Binary files /dev/null and b/docs/static/img/sharding-insert.png differ diff --git a/docs/static/img/sharding-select.png b/docs/static/img/sharding-select.png new file mode 100644 index 00000000..05e25320 Binary files /dev/null and b/docs/static/img/sharding-select.png differ diff --git a/docs/versioned_docs/version-v0.3.0/Features/_category_.json b/docs/versioned_docs/version-v0.3.0/Features/_category_.json new file mode 100644 index 00000000..0dbbad58 --- /dev/null +++ b/docs/versioned_docs/version-v0.3.0/Features/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "特性", + "position": 3 +} diff --git a/docs/versioned_docs/version-v0.3.0/Features/loadbalancer.md b/docs/versioned_docs/version-v0.3.0/Features/loadbalancer.md new file mode 100644 index 00000000..368ccfda --- /dev/null +++ b/docs/versioned_docs/version-v0.3.0/Features/loadbalancer.md @@ -0,0 +1,51 @@ +--- +sidebar_position: 1 +--- + +# 负载均衡 + +负载均衡模块为 Pisa-Proxy 代理后端节点时,新建链接时对后端节点选取策略的实现。 + +## 已支持负载均衡策略 +- [x] Random +- [x] RoundRobin + +## 配置示例 + +若需要在代理中启用负载均衡,则需要配置 `simple_loadbalance` 块. +``` +[proxy.config.simple_loadbalance] +balance_type = "roundrobin" +nodes = ["ds001","ds002"] +``` +其中 balance_type: 可选值为 random,roundrobin,默认值为 random;nodes: 选取后端数据源中定义的 `name`. + +后端数据源配置: +``` +[[mysql.node]] +name = "ds001" +user = "root" +password = "12345678" +db = "test" +host = "127.0.0.1" +port = 3306 + +[[mysql.node]] +name = "ds002" +user = "root" +password = "12345678" +db = "test" +host = "127.0.0.1" +port = 3307 +``` + +## 模块设计 + +该模块定义了一个负载均衡的 Trait,封装了在 Pisa-Proxy 中对于负载均衡的构建方式。以及定义了 Random 和 RoundRobin 两种负载均衡策略所要实现的具体方法。 + +### 代码结构 + FILES IN THIS DIRECTORY (loadbalance/src) + balance.rs - 负载均衡 Trait,定义了负载均衡方法和构建负载均衡模块 + random_weighted.rs - random weighted 负载均衡策略 + roundrobin_weighted.rs - roundrobin weighted 负载均衡策略 + diff --git a/docs/versioned_docs/version-v0.3.0/Features/mysql-protocol.md b/docs/versioned_docs/version-v0.3.0/Features/mysql-protocol.md new file mode 100644 index 00000000..edd85369 --- /dev/null +++ b/docs/versioned_docs/version-v0.3.0/Features/mysql-protocol.md @@ -0,0 +1,51 @@ +--- +sidebar_position: 2 +--- +# MySQL 协议 + +此功能主要为 Pisa-Proxy MySQL 代理的核心组件, 依据 [MySQL 协议](https://dev.mysql.com/doc/internals/en/client-server-protocol.html) 进行实现。该功能主要使用 Rust 生态的 [Tokio](https://github.com/tokio-rs/tokio) 异步运行时框架。其中对网络数据包的读写、协议的编码等操作都通过 Tokio 提供的工具集实现。 + + +## 已支持命令 +- [x] COM_INIT_DB +- [x] COM_QUERY +- [x] COM_FIELD_LIST +- [x] COM_QUIT +- [x] COM_PING +- [x] COM_STMT_PREPARE +- [x] COM_STMT_EXECUTE +- [x] COM_STMT_CLOSE +- [x] COM_STMT_RESET + +## 支持认证方式 +- [x] mysql_native_password +- [ ] sha256_password +- [ ] caching_sha2_password + +## 设计说明 + +本模块共由3部分组成,对应 Pisa-Proxy 中作为客户端和服务端两部分。在 `server` 目录中主要定义了 Pisa-Proxy 作为服务端对客户端请求的处理逻辑。也包含了在 TCP 层的网络数据包的读写操作。在 `client` 目录中定义了 Pisa-Proxy 作为客户端对 MySQL 数据库的建立链接、握手认证和发送客户端命令等操作。 + +### 代码结构 + + FILES IN THIS DIRECTORY (protocol/mysql/src/client) + auth.rs - 对 MySQL 登陆认证 + codec.rs - 对 MySQL 协议的解码 + conn.rs - 对 MySQL 发起链接、握手及命令处理 + err.rs - MySQL Error 类型定义 + resultset.rs - 一些 MySQL ResultSet 结果处理方法 + stmt.rs - 对 MySQL Prepare Statement 处理方法 + stream.rs - 对 Tokio TcpSteam 封装 + + FILES IN THIS DIRECTORY (protocol/mysql/src/server) + conn.rs - 和客户端建链、握手认证处理 + packet.rs - 网络数据包的读写操作 + stream.rs - 对底层 Tcp 流的封装 + tls.rs - MySQL TLS 链接封装 + + FILES IN THIS DIRECTORY (protocol/mysql/src) + charset.rs - MySQL 字符集声明 + err.rs - 协议解析错误处理定义 + mysql_const.rs。 - 常量定义 + util.rs - 一些通用函数的实现 + diff --git a/docs/versioned_docs/version-v0.3.0/Features/observability.md b/docs/versioned_docs/version-v0.3.0/Features/observability.md new file mode 100644 index 00000000..a8bc2dc4 --- /dev/null +++ b/docs/versioned_docs/version-v0.3.0/Features/observability.md @@ -0,0 +1,18 @@ +--- +sidebar_position: 5 +--- + +# 可观测性 + +Pisanix 目前在 Pisa-Proxy 处理 SQL 命令的时候采集相关指标,并以 `/metrics` 路径进行暴露。 + +## 已支持指标 +- SQL_PROCESSED_TOTAL: 统计所有执行的 SQL 数量 +- SQL_PROCESSED_DURATION: 统计所有 SQL 的执行时间 +- SQL_UNDER_PROCESSING: 记录当前正在执行的 SQL 数量 + +测试效果如下图: + +![grafana](/img/grafana.jpg) + +下一步将支持更多标签和指标,如 SQL 语句类型、延迟、错误率、TopK、运行时资源等。 diff --git a/docs/versioned_docs/version-v0.3.0/Features/readwritesplitting.md b/docs/versioned_docs/version-v0.3.0/Features/readwritesplitting.md new file mode 100644 index 00000000..e4e1f65c --- /dev/null +++ b/docs/versioned_docs/version-v0.3.0/Features/readwritesplitting.md @@ -0,0 +1,283 @@ +--- +sidebar_position: 3 +--- + +# 读写分离 + +读写分离是业界使用 MySQL 最常用的方案之一, 在实际场景中可以提高查询性能,降低服务器负载。一般架构如以下: + +``` ++--------+ +-------+ +-----------+ +| Client | --> | Proxy | -+-----> | ReadNode1 | ++--------+ +-------+ | +-----------+ + | +-----------+ + +-----> | ReadNode2 | + | +-----------+ + | +-----------+ + +-----> | ReadNode3 | + | +-----------+ + | +-----------+ + +-----> | WriteNode | + +-----------+ + +``` + +读写分离是 Pisa-Proxy 流量治理的一部分。 + +Pisa-Proxy 支持两种类型的读写分离方案: +- 静态读写分离 + +指无动态感知后端数据库角色变更。配置说明[请见](#读写分离配置)。 + +- 动态读写分离 + +指能够感知后端数据库角色变更,配置说明[请见](#动态读写分离)。 + +目前,两种方案都需要配置[读写分离规则](#读写分离规则说明)。 + +## 名词解释: + +本章中出现的`关键字`代表的含义。 + +节点: 指后端数据库节点 + +内部逻辑如下: + +``` ++------------+ +------------+ +-------------+ +----------------+ +| RulesMatch | --> | TargetRole | --> | LoadBalance | --> | TargetInstance | ++------------+ +------------+ +-------------+ +----------------+ +``` + + +RulesMatch: RulesMatch 引擎通过编写的规则集,与 Pisa-Proxy 接收到的 SQL 查询语句做匹配。 + +TargetRole: 指通过规则匹配引擎匹配到的 TargetRole 组,每个 TargetRole 组里可能会有一个或多个节点。 + +LoadBalance: 负载均衡模块会按照相应的算法从 TargetRole 组里选取一个合适的节点。 + +TargetInstnce: 指由 LoadBalance 模块选出的节点。 + +## 读写分离配置 +配置说明: + +| 属性 | 值类型 | 是否依赖 | 默认值 | 含义 | +|-----|-------|---------|-------|-----| +| static | [object](#静态读写分离配置) | 否 | 无 | 静态读写分离类型 | +| dynamic| object| 否 | 无 | 动态读写分离类型, ***目前还不支持*** | + +### 静态读写分离配置 +配置说明: + +| 属性 | 值类型 | 是否依赖 | 默认值 | 含义 | +|-----|-------|---------|-------|-----| +| defaultTarget | [enum](#targetrole-enum-值) | 否 | 无 | 默认路由的 TargetRole 组 | +| rules | [array[rule]](#读写分离规则说明)| 是 | 无 | 读写分离规则| + +***defaultTarget 值在真实场景中要配置成 `readwrite`*** + +## 读写分离规则说明 +读写分离规则是指 Pisa-Proxy 需要把查询的 SQL 语句和配置的规则做匹配,如果匹配成功,将根据规则把 SQL 语句路由到对应的节点上。 + +目前读写分离规则支持通用规则和正则匹配两种方式。配置通用规则后,Pisa-Proxy 会根据 SQL 自动路由请求。若配置正则规则,则 Pisa-Proxy 会基于正则表达式行路由。此处用户可以同时配置两种路由规则,Pisa-Proxy 会优先根据正则进行路由,若未匹配到则通过通用规则进行路由,若两种规则全未命中,则 SQL 会被路由到默认节点上。 + +通用规则是基于匹配 SQL 语句进行路由的,Pisa—Proxy 接收到 SQL 语句解析后会以 SQL 字符串起始第一个字段作为判断依据进行路由。当前版本 DML 对应路由规则如下: + +|SQL 语句|路由节点| +|-----|-----| +|SELECT|read only| +|INSERT|readwrite| +|DELETE|readwrite| +|UPDATE|readwrite| +|SET|readwrite| +|START|readwrite| +|事务相关|readwrite| +|其他|`defaultTarget` 指定节点| + +通用路由规则配置说明: + +| 属性 | 值类型 | 是否依赖 | 默认值 | 含义 | +|-----|-------|---------|-------|-----| +|name | string| 是 | 无 | 规则名称| +|type | string| 是 | 无 | 路由类型为通用规则类型,此处值为 `generic`| +|algorithName| [enum](#algorithname-enum-值)| 是| 无 | 负载均衡算法的名称,将作用与路由到的 `role` 组中的机器列表| + +正则规则配置说明: + +| 属性 | 值类型 | 是否依赖 | 默认值 | 含义 | +|-----|-------|---------|-------|-----| +|name | string| 是 | 无 | 规则名称| +|type | string| 是 | 无 | 路由类型为正则类型,此处值为 `regex`| +|regex| array[string]| 是 | 无 | 具体的正则,将通过这些正则去匹配 SQL 语句| +|target| [enum](#targetrole-enum-值)| 是 | 无 | 路由到的 TargetRole 组,对应 DatabaseEndpoint CRD 的Annotation 属性中 `database-mesh.io/role` 的 值| +|algorithName| [enum](#algorithname-enum-值)| 是| 无 | 负载均衡算法的名称,将作用与路由到的 `role` 组中的机器列表| + +### TargetRole Enum 值 +- read +- readwrite + +### algorithName Enum 值 +- random +- roundrobin + +## 配置示例 + +基于通用路由规则的 `TrafficStrategy` CRD 配置如下: +```yaml +apiVersion: core.database-mesh.io/v1alpha1 +kind: TrafficStrategy +metadata: + name: test + namespace: default +spec: + selector: + matchLabels: + source: test + loadBalance: + readWriteSplitting: + static: + defaultTarget: read # or readwrite + rules: + - name: read-rule + type: generic + algorithmName: random # lb algorithm +``` + +基于正则匹配的 `TrafficStrategy` CRD 配置如下: + +``` yaml +apiVersion: core.database-mesh.io/v1alpha1 +kind: TrafficStrategy +metadata: + name: test + namespace: default +spec: + selector: + matchLabels: + source: test + loadBalance: + readWriteSplitting: + static: + defaultTarget: read # or readwrite + rules: + - name: read-rule + type: regex + regex: + - "^select" + target: read # readwrite + algorithmName: random # lb algorithm + - name: write-rule + type: regex + regex: + - "^insert" + target: readwrite + algorithmName: roundrobin +``` + +一个完整的 `DatabaseEndpoint` CRD 配置如下: +``` yaml +apiVersion: core.database-mesh.io/v1alpha1 +kind: DatabaseEndpoint +metadata: + annotations: + database-mesh.io/role: read # or readwrite + labels: + source: test + name: mysql + namespace: default +spec: + database: + MySQL: + db: test + host: mysql.default + password: root + port: 3306 + user: root +``` + +## 动态读写分离 + +动态读写分离是在静态读写分离基础之上加入了对后端数据源的动态感知,Pisa-Proxy 主动探测后端集群节点状态和主从之间的状态,并根据探测到的状态来动态调整 Pisa-Proxy 的路由策略。在动态读写分离中主要包含了 Discovery,Monitor 两个模块用来感知后端数据源状态。 + +#### 名词解释 +Discovery: discovery 指 Pisa-Proxy 对后端高可用的感知方式,例如: MHA,RDS,MGR等等。在当前版本中支持 MHA 的方式。 + +Monitor: monitor 为对后端数据源的探测模块,其中包含了以下4种探测方式。 + +- Connect Monitor: 探测后端数据源的网络层连通性。 +- Ping Monitor: 探测后端数据源是否健康。 +- Replication Lag Monitor: 探测后端数据源主从复制状态和延迟情况。 +- Read Only Monitor: 探测后端数据源角色。 + +#### 配置项 +|参数 | 类型| 是否依赖| 默认值 | 含义| +|-- | -- | -- | -- | --| +|user | string | 是 | None |探测模块执行检查 SQL 语句用户名| +|password | string | 是 | None |探测模块执行检查 SQL 语句密码| +|monitor_period | u64 | 是 | 1000 |探测模块更新感知后端数据源状态周期(毫秒)| +|connect_period | u64 | 是 | 1000 |connect 模块探测周期(毫秒)| +|connect_timeout | u64 | 是| 6000 |connect 模块探测超时时间(毫秒)| +|connect_failure_threshold | u64 | 是 | 1 |connect 模块探测失败重试次数| +|ping_period | u64 | 是 | 1000 |ping 模块探测周期(毫秒)| +|ping_timeout | u64 | 是 | 6000 |ping 模块探测超市时间(毫秒)| +|ping_failure_threshold | u64 | 是 | 1 |ping 模块探测失败重试次数| +|replication_lag_period | u64 | 是 | 1000 |replication lag 模块探测周期(毫秒)| +|replication_lag_timeout | u64 | 是 | 6000|replication lag 模块探测超时时间(毫秒)| +|replication_lag_failure_threshold | u64 | 是 | 1 |replication lag 探测失败重拾次数| +|max_replication_lag | u64 | 是 | 10000 |用户定义主从最大延迟时间阈值(毫秒)| +|read_only_period | u64 | 是 | 1000 |read only 探测周期(毫秒)| +|read_only_timeout | u64 | 是 | 6000|read only 探测超市时间(毫秒)| +|read_only_failure_threshold | u64 | 是 | 3 |read only 探测失败重拾次数| + + +#### 一个完整的 TrafficStrategy CRD 配置如下: +```yaml +apiVersion: core.database-mesh.io/v1alpha1 +kind: TrafficStrategy +metadata: + name: catalogue + namespace: demotest +spec: + selector: + matchLabels: + source: test + loadBalance: + readWriteSplitting: + dynamic: + defaultTarget: readwrite + discovery: + masterHighAvailability: + connectionProbe: + failureThreshold: 3 + periodMilliseconds: 1000 + timeoutMilliseconds: 6000 + monitorPeriod: 1000 + pingProbe: + failureThreshold: 3 + periodMilliseconds: 1000 + timeoutMilliseconds: 6000 + readOnlyProbe: + failureThreshold: 3 + periodMilliseconds: 1000 + timeoutMilliseconds: 6000 + replicationLagProbe: + failureThreshold: 3 + maxReplicationLag: 3 + periodMilliseconds: 1000 + timeoutMilliseconds: 6000 + user: monitor + password: monitor + rules: + - algorithmName: roundrobin + name: write-rule + regex: + - ^insert + target: readwrite + type: regex + - algorithmName: roundrobin + name: read-rule + regex: + - ^select + target: read + type: regex +``` diff --git a/docs/versioned_docs/version-v0.3.0/Features/sharding.md b/docs/versioned_docs/version-v0.3.0/Features/sharding.md new file mode 100644 index 00000000..fb0b5609 --- /dev/null +++ b/docs/versioned_docs/version-v0.3.0/Features/sharding.md @@ -0,0 +1,98 @@ +--- +sidebar_position: 6 +--- + +# 数据分片 + +数据分片是应对海量数据存储与计算的有效手段。Pisanix 基于底层数据库提供了数据分片的治理能力,用户可以通过 Pisanix 水平扩展计算和存储。 + +## 数据分片介绍 +如下图,在数据分片中主要包函了 SQL 解析、SQL 改写、SQL 路由、结果归并这几个重要模块, + +``` ++------------+ +-------------+ +-----------+ +--------------+ +| SQL Parse | --> | SQL Rewrite | --> | SQL Route | --> | Result Merge | ++------------+ +-------------+ +-----------+ +--------------+ +``` + +### 名词解释 + +SQL 解析: 在分片中,请求到达 Pisa-Proxy 后会首先经过 SQL Parser,将 SQL 解析成 AST。 + +SQL 改写: 解析结束后,Pisa-Proxy 会根据分片规则对当前 SQL 语句进行改写,生成真实要执行的 SQL 语句。 + +SQL 路由: Pisa-Proxy 会根据分片规则,将改写好的 SQL 语句路由到后端对应数据源上执行 SQL 语句。 + +结果归并: SQL 被下推执行之后,Pisa-Proxy 会对查询结果进行归并,并最终返回给客户端。 + +### SQL 改写介绍 +在数据分片中,SQL 改写是很重要的一个模块。Pisa-Proxy 需要根据分片规则将 SQL 语句改写成真正要执行的 SQL 语句。在 SQL 改写中通常有以下几种改写类型。 + +#### 1. 标识符改写 +在 SQL 改写中,需要改写的标识符包括表名称、索引名称以及Schema名称。 + +表名称改写是指将找到逻辑表在原始SQL中的位置,并将其改写为真实表的过程。表名称改写是一个典型的需要对SQL进行解析的场景。 从一个最简单的例子开始,若逻辑SQL为: + +``` +SELECT order_id FROM order.t_order WHERE order_id = 1; +``` +假设该表配置的分片键位 `order_id` 并且 `order_id = 1`,分片数指定为4,那么经过改写后的 SQL 语句为: + +``` +SELECT order_id FROM order.t_order_00001 WHERE order_id = 1; +``` +下图展示了数据查询过程 +![](/img/sharding-select.png) + +以数据插入为例,数据写入过程如下图: +![](/img/sharding-select.png) + +**特别说明: SQL rewrite 在修改标识符计算实际表名时会自动根据分片规则添加表索引,索引规则位 表名_索引,索引位为5位表示。例如:`t_order` 表改写后为 `t_order_00000`。因此用户需要根据实际业务场景先创建好对应的表名** + +#### 2. 补列 +需要在查询语句中补列通常由两种情况导致。 第一种情况是 Pisa-Proxy 需要在结果归并时获取相应数据,但该数据并未能通过查询的SQL返回。 这种情况主要是针对 GROUP BY 和 ORDER BY。结果归并时,需要根据 GROUP BY 和 ORDER BY 的字段项进行分组和排序,但如果原始SQL的选择项中若并未包含分组项或排序项,则需要对原始SQL进行改写。 +例如有以下 SQL 语句: +``` +SELECT order_id, user_id FROM t_order ORDER BY user_id; +``` +由于排序时用到了 `user_id` , 在结果归并时需要用到 `user_id` 这一列的数据,上面的 SQL 语句中包含了 `user_id` 的数据,因此不需要补列,只需要修改标识符即可。 + +``` +SELECT order_id FROM t_order ORDER BY user_id; +``` +这条 SQL 中依赖排序依赖于 `user_id` 因此需要补列,改写后的 SQL 如下: +``` +SELECT order_id, user_id AS USER_ID_ORDER_BY_DERIVED_00000 FROM t_order_00000 ORDER BY user_id; +``` +补列的另一种情况是使用AVG聚合函数。在分布式的场景中,使用avg1 + avg2 + avg3 / 3计算平均值并不正确,需要改写为 (sum1 + sum2 + sum3) / (count1 + count2 + count3)。 这就需要将包含AVG的SQL改写为SUM和COUNT,并在结果归并时重新计算平均值。例如以下SQL: +``` +SELECT AVG(price) FROM t_order WHERE user_id = 1; +``` +改写后的 SQL 如下: +``` +SELECT COUNT(price) AS AVG_DERIVED_COUNT_00000, SUM(price) AS AVG_DERIVED_SUM_00000 FROM t_order_00000 WHERE user_id = 1; +``` +# 支持特性 +#### 特性 +- 基于单 shard-key 的静态分片规则 +- 分片算法:crc32mod 和 mod +- 单库水平分表 +- 基于分片的查询,更新,删除,修改 + +#### 使用限制 +- 不支持子查询 +- 不支持分库 +- 不支持分布式事务 +- 不支持基于表达式配置的分片规则 +- 不支持跨库 join 查询 + +# 配置说明 +| 属性 | 值类型 | 是否依赖 | 默认值 | 含义 | +|-----|-------|---------|-------|-----| +| table_name |String|是|无|分片表名| +| actual_datanodes| array[String]|是|无|后端数据源| +|binding_tables|arrayString]|否|无|暂不支持|| +|broadcast_tables|array[String]|否|无|暂不支持|| +|table_sharding_algorithm_name|enum|是|无|分片算法| +|table_sharding_column|String|是|无|分片键| +|sharding_count|u64|是|无|分片数| \ No newline at end of file diff --git a/docs/versioned_docs/version-v0.3.0/Features/sql-circuit-breaker-and-concurrency-control.md b/docs/versioned_docs/version-v0.3.0/Features/sql-circuit-breaker-and-concurrency-control.md new file mode 100644 index 00000000..6acf576d --- /dev/null +++ b/docs/versioned_docs/version-v0.3.0/Features/sql-circuit-breaker-and-concurrency-control.md @@ -0,0 +1,71 @@ +--- +sidebar_position: 4 +--- + +# 断路和并发控制 + +目前实现了两个默认插件 `SQL 断路` 和 `SQL 并发控制`。 + +### SQL 断路 + +禁止运行匹配正则的语句。 + +#### 示例配置 +如:不允许执行` SELECT *` + +``` toml +[[proxy.config.plugin.circuit_break]] +regex = ["SELECT \\*"] +``` +> 注:可以有多个规则 + +### SQL 并发控制 + +SQL 并发控制规则表示在 `duration` 秒内并发运行匹配正则的 SQL 语句只能有 `max_concurrency` 条, + +#### 配置示例 +如:不允许100秒内并发执行多于1条 `SELECT *` + +``` toml +[[proxy.config.plugin.concurrency_control]] +regex = ["SELECT \\*"] +max_concurrency = 1 +duration = 100 +``` + +> 注:可以有多个规则 + +#### 使用场景 +SQL 并发控制通常使用在慢查询或者 OLAP 查询中,即一个 SQL 查询需要耗费大量时间的场景下。例如, 这里使用两个客户端同时执行以下 SQL 语句, 可以看出,当第一条 SQL 语句被阻塞后,在 `duration = 100` 周期内,另外一条 SQL 语句已经被插件限制执行 `max_concurrency = 1` 次。 + + +``` +# client 1 + +MySQL [(none)]> SELECT * FROM (SELECT SLEEP(5)) AS sock; +``` + +``` +# client 2 + +MySQL [test]> SELECT * FROM sbtest1 LIMIT 1; +ERROR 1047 (08S01): concurrency control plugin rejected +``` + +## 设计说明 + +目前运行中间件的方式参考了[ Tower-rs ](https://github.com/tower-rs/tower.git),可以很好的满足未来扩展的需求。 + +其中有两个概念: +> Layer: 是对 `Service` 的包装,每个 `Service` 可以有多个不同的中间件。 + +> Service: 指 `Pisanix` 内部允许执行中间件的服务或者是某个功能函数,可以运行一些自定义的逻辑,如 `Metrics` 收集。 + +实现[伪代码](https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0db8ca6f72096c7a74682085a66e3270)。 + +注意 + +- 并发控制规则表示在 `duration` 秒内并发运行匹配正则的 SQL 语句只能有 `max_concurrency` 条,从第一次匹配到开始计时,如果超过 `duration` 时间,则并发控制失效,重新开始下一次匹配。 +- 目前由于不能动态生效并发控制规则,因此规则的生效时间是从第一次匹配到的时间开始,持续 `duration` 时间,超过后继续下次循环,没有失效情况,在未来支持动态生效后,规则失效有两种情况: + - `duration` 的时间将从获取到开启动作的时间开始,持续 `duration` 时间,规则失效。 + - 等到获取到关闭动作时,规则失效。 diff --git a/docs/versioned_docs/version-v0.3.0/Features/sql-parser.md b/docs/versioned_docs/version-v0.3.0/Features/sql-parser.md new file mode 100644 index 00000000..2210ad11 --- /dev/null +++ b/docs/versioned_docs/version-v0.3.0/Features/sql-parser.md @@ -0,0 +1,37 @@ +--- +sidebar_position: 3 +--- + +# SQL 解析 + +Pisa-Proxy 除了理解 SQL 协议外, 能读懂 SQL 语句也是一个很重要的功能,读写分离,分片等功能也都依赖 SQL 解析,在 Pisa-Proxy 中占着举足轻重的作用。 +由于 Pisa-Proxy 支持多种数据源,因此在 Pisa-Proxy 中,每种不同的数据源都要实现各自对应的 SQL 解析,未来我们会支持不同数据源使用 SQL 之间的转换,以实现快速支持新的数据源。 + +## 已支持语句 +- [x] SELECT +- [x] INSERT +- [x] UPDATE +- [x] DELETE +- [x] PREPARE +- [x] EXECUTE +- [x] BEGIN +- [x] SET +- [ ] SHOW +- [ ] CREATE + + +## 设计说明 +目前 Pisanix 只实现了对 MySQL 的语法的解析。 + +### MySQL 语法 +为了最大的程度的兼容原生的 MySQL 语法,Pisanix 采用原生的[ MySQL 语法文件](https://github.com/mysql/mysql-server/blob/8.0/sql/sql_yacc.yy),基于 `Grmtools` 实现了 SQL 语法解析。 + `Grmtools` 是一个用 Rust 写的兼容 `Yacc` 的语法解析工具,详细信息请参考[ Github ](https://github.com/softdevteam/grmtools.git)。 + +### AST 说明 +Pisanix 中的 SQL 解析不会为所有表达式都生成 AST,只会为 Pisanix 感兴趣的部分生成 AST。 +详细信息请参考[ Github ](https://github.com/database-mesh/pisanix/tree/master/pisa-proxy/parser/mysql/src/ast)。 + +### 测试 +目前使用了 MySQL test 框架中能正常运行的 SQL 语句作为测试集来测试。目前只测试了 `SELECT` 语句,有`98%`的语句能成功解析, 还在不断完善中。 + + diff --git a/docs/versioned_docs/version-v0.3.0/UseCases/_category_.json b/docs/versioned_docs/version-v0.3.0/UseCases/_category_.json new file mode 100644 index 00000000..ad288b16 --- /dev/null +++ b/docs/versioned_docs/version-v0.3.0/UseCases/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "使用场景", + "position": 4 +} diff --git a/docs/versioned_docs/version-v0.3.0/UseCases/kubernetes.md b/docs/versioned_docs/version-v0.3.0/UseCases/kubernetes.md new file mode 100644 index 00000000..9bf28768 --- /dev/null +++ b/docs/versioned_docs/version-v0.3.0/UseCases/kubernetes.md @@ -0,0 +1,345 @@ +--- +sidebar_position: 1 +--- + +# 在 Kubernetes 中部署 + +***Pisanix*** 的三个组件在项目规划之初即按照`控制面`配合多`数据面`的形式进行设计,它们都可部署在 kubernetes 之上,并通过 CustomResourceDefinition 完成各种配置,由 ***Pisa-Controller*** 转换为相应的配置后,下发给 ***Pisa-Proxy*** 或 ***Pisa-Daemon***。 + + + +## 前期准备 + +- Helm v3.8.0+ + +- kubectl 1.19+ + +- kubernetes 1.19+ + +**⚠️⚠️⚠️⚠️:目前已在 kubernetes 1.19+ 和 1.20+ 版本集群上通过测试** + +## 安装步骤 + +### 源码安装 + +通过 Helm 构建依赖并安装 ***Pisanix*** 到 namespace `pisa-system` + +```shell +kubectl create namespace pisa-system + +cd charts/pisa-controller +helm dependency build +cd .. +helm install pisa-controller pisa-controller -n pisa-system +``` + +Helm 将安装如下资源 + +- apiservice: v1alpha1.admission.database-mesh.io +- deployment: pisa-controller +- service: pisa-controller +- clusterrole: pisa-controller +- clusterrolebinding: pisa-controller +- customresourcedefinitions: + - virtualdatabases.core.database-mesh.io + - databaseendpoints.core.database-mesh.io + - trafficstrategies.core.database-mesh.io + +### 清理 + +测试完成后使用 Helm 命令卸载 ***Pisanix*** + +``` +helm uninstall pisa-controller -n pisa-system +``` + +## Helm values 配置项介绍 + + +| Name | Description | Value | +| --------------------------- | ---------------------------------------------- | ---------------------- | +| `replicaCount` | Pisa-Controller 节点数 | `1` | +| `image.repository` | Pisa-Controller 镜像名 | `pisanixio/controller` | +| `image.pullPolicy` | Pisa-Controller 镜像拉取策略 | `IfNotPresent` | +| `image.tag` | Pisa-Controller 镜像标签 | `v0.3.0` | +| `imagePullSecrets` | Docker 私有仓库的密钥,以数组形式注入 | `[]` | +| `proxyImage.repository` | Pisa-Proxy 的镜像名 | `pisanixio/proxy` | +| `proxyImage.tag` | Pisa-Proxy 镜像标签 | `v0.3.0` | +| `resources.limits` | Pisa-Controller 资源限制数值 | `{}` | +| `resources.requests.cpu` | Pisa-Controller 资源申请 cpu 核数 | `100m` | +| `resources.requests.memory` | Pisa-Controller 资源申请内存数量 | `128Mi` | +| `service.corePort` | Pisa-Controller 核心暴露端口 | `80` | +| `service.webhookPort` | Pisa-Controller Webhook 暴露端口 | `6443` | +| `service.proxyConfigsPort` | Pisa-Controller 和 Pisa-Proxy 配置文件通信端口 | `8080` | + +## CustomResourceDefinition 字段说明 + +**⚠️⚠️⚠️⚠️: 注意: VirtualDatabase 中 db 字段需要和 DatabaseEndpoint 中 db 字段保持一致,客户端中连接指定的 schema 需要和 db 字段三者保持一致** + +### VirtualDatabase + +| Name | Description | +| -------------------------- | ---------------------------------------------------------- | +| `services` | 一个 VirtualDatabase 的详细设置 | +| `services.name` | 虚拟数据库名字 | +| `services.trafficStrategy` | 虚拟数据库的相关策略 [TrafficStrategy](###TrafficStrategy) | +| `databaseMySQL` | 一个虚拟的 MySQL 类型 | +| `host` | 虚拟 MySQL Host地址 | +| `port` | 虚拟 MySQL 端口 | +| `user` | 虚拟 MySQL 用户名 | +| `password` | 虚拟 MySQL 密码 | +| `db` | 虚拟 MySQL schema名字 | +| `poolSize` | 虚拟 MySQL 连接池大小 | +| `serverVersion` | 虚拟 MySQL 版本 | + +***VirtualDatabase的名称需要与应用名称一致*** + +### TrafficStrategy + +| Name | Description | +| -------------------------------------- | ------------------------------------------------------------ | +| `selector` | 标签选择器,用于选择 [DatabaseEndpoint](###DatabaseEndpoint) | +| `loadBalance` | 负载均衡器,现阶段支持:simpleLoadBalancer | +| `loadBalance.simpleLoadBalancer` | 基础负载均衡声明 | +| `loadBalance.simpleLoadBalancer.kind` | 负载均衡策略类型 | +| `loadBalance.readWriteSplitting` | 读写分离策略声明 +| `loadBalance.readWriteSplitting.static`| 读写分离策略声明静态配置 +| `loadBalance.readWriteSplitting.static.defaultTarget` | 读写分离策略声明静态配置默认后端 +| `loadBalance.readWriteSplitting.static.rules` | 读写分离策略声明静态规则集 +| `loadBalance.readWriteSplitting.static.rules[].name` | 读写分离策略声明静态规则名称 +| `loadBalance.readWriteSplitting.static.rules[].type` | 读写分离策略声明静态规则类型 +| `loadBalance.readWriteSplitting.static.rules[].regex[]` | 读写分离策略声明静态规则正则表达式 +| `loadBalance.readWriteSplitting.static.rules[].target` | 读写分离策略声明静态规则目标后端 +| `loadBalance.readWriteSplitting.static.rules[].algorithmName` | 读写分离策略声明静态规则算法 +| `circuitBreaks` | 断路器 | +| `circuitBreaks.regex[]` | 断路正则规则, 类型为数组 | +| `concurrencyControls` | 并发控制器 | +| `concurrencyControls.regex[]` | 并发控制正则规则,类型为数组 | +| `concurrencyControls.duration` | 并发控制时延 | +| `concurrencyControls.maxConcurrency` | 最大并发执行数量 | + +### DatabaseEndpoint + +Spec 配置说明 + +| Name | Description | +| ---------- | -------------------- | +| `database` | 后端的数据源类型 | +| `MySQL` | MySQL 类型的详细描述 | +| `host` | MySQL Host 地址 | +| `port` | MySQL 端口 | +| `user` | MySQL 用户名 | +| `password` | MySQL 密码 | +| `db` | MySQL schema 名字 | + + +Annoations 说明 +在使用读写分离配置的时候,需要在 DatabaseEndpoint 资源的 Annotations 里添加如下注解,标识该节点的角色属性: +``` +annotations: + database-mesh.io/role: read +``` + +默认的角色属性为 `readwrite` + + + +## Demo 运行 + +**以下 Demo 均在 namespace:demotest 中运行,如果需要改变 namespace,请改变相应的 namespace** + +### 示例业务部署 + +以 [Weaveworks Socks-shop(github.com)](https://github.com/database-mesh/microservices-demo) 为运行应用 Demo,下列演示将展示怎么样在 microservices-demo 使用 ***Pisanix*** + +首先利用 Helm 部署 microservices-demo + +```shell +git clone https://github.com/database-mesh/microservices-demo.git +kubectl create ns demotest +cd deploy/kubernetes/helm-chart +helm dependency build +cd .. +helm install microservices-demo helm-chart -n demotest +``` +检查 Helm 命令部署情况: + +![socks-shop-deployed](/img/socks-shop-deployed.png) + +等待程序启动并看到如下页面后确认已正确运行: + +注:如果前面执行 `helm dependency build` 提示 nginx ingress 报错,可以跳过继续执行后面的 `helm install` 命令,最终查看部署结果使用的是 `kubectl port-forward` 子命令而非 `ingress`。 + +![socks-shop-preview](/img/socks-shop-preview.png) + +### 使用 Pisanix 实现 Database Mesh 理念 + +#### Pisanix 配置 + +编写如下三个 CustomResourceDefinitions: + +- VirtualDatabase + +```yaml +apiVersion: core.database-mesh.io/v1alpha1 +kind: VirtualDatabase +metadata: + name: catalogue + namespace: demotest +spec: + services: + - name: "mysql" + databaseMySQL: + host: "127.0.0.1" + port: 3306 + user: "catalogue_user" + password: "default_password" + db: "socksdb" + trafficStrategy: "catalogue" +``` + +***VirtualDatabase的名称需要与应用的名称一致*** + +- TrafficStrategy + +```yaml +apiVersion: core.database-mesh.io/v1alpha1 +kind: TrafficStrategy +metadata: + name: catalogue + namespace: demotest +spec: + selector: + matchLabels: + source: catalogue + loadBalance: + simpleLoadBalance: + kind: "random" +``` + +- DatabaseEndpoint + +```yaml +apiVersion: core.database-mesh.io/v1alpha1 +kind: DatabaseEndpoint +metadata: + name: catalogue-db + namespace: demotest + labels: + source: catalogue +spec: + database: + MySQL: + host: "catalogue-db.demotest" + port: 3306 + user: "root" + password: "fake_password" + db: "socksdb" +``` + +- DataShard + +```yaml +apiVersion: core.database-mesh.io/v1alpha1 +kind: DataShard +metadata: + name: catalogue + namespace: demotest + labels: + source: catalogue +spec: + rules: + - tableName: "t_order" + tableStrategy: + tableShardingAlgorithmName: "mod" + tableShardingColumn: "id" + shardingCount: 4 + actualDatanodes: + valueSource: + nodes: + - value: "ds001" +``` + +#### 应用访问数据库切换至 Pisanix + +为 namespace 添加标签以开启注入 + +```shell +kubectl label ns demotest pisanix.io/inject=enabled +``` + +检查 catalogue-dep.yaml 或 catalogue deployment 以确认是否已添加标签并开启注入: + +```yaml +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: catalogue + labels: + name: catalogue +spec: + replicas: 1 + selector: + matchLabels: + name: catalogue + template: + metadata: + labels: + name: catalogue + pisanix.io/inject: enabled # 通过该 Label 标识注入启用 + {{- if .Values.istio.enabled }} + annotations: + sidecar.istio.io/rewriteAppHTTPProbers: "true" + {{- end }} + spec: + containers: + - name: catalogue + image: {{if .Values.global.registry}}{{ .Values.global.registry }}/{{end}}{{ .Values.catalogue.image.repo }}:{{ .Values.catalogue.image.tag }} + command: ["/app"] + args: + - -port={{ .Values.catalogue.containerPort }} + - -DSN=catalogue_user:default_password@tcp(127.0.0.1:3306)/socksdb # DSN 中用户名、密码、主机名和端口都参照 VirtualDatabase 里的信息进行修改 + {{- if .Values.zipkin.enabled }} + env: + - name: ZIPKIN + value: http://{{ .Values.zipkin.url }}:9411/api/v1/spans + {{- end }} + resources: +{{ toYaml .Values.catalogue.resources | indent 10 }} + ports: + - containerPort: {{ .Values.catalogue.containerPort }} + securityContext: + runAsNonRoot: true + runAsUser: 10001 +{{- if lt (int .Values.carts.containerPort) 1024 }} + capabilities: + drop: + - all + add: + - NET_BIND_SERVICE +{{- end }} + readOnlyRootFilesystem: true + livenessProbe: + httpGet: + path: /health + port: {{ .Values.catalogue.containerPort }} + initialDelaySeconds: 300 + periodSeconds: 3 + readinessProbe: + httpGet: + path: /health + port: {{ .Values.catalogue.containerPort }} + initialDelaySeconds: 180 + periodSeconds: 3 +``` + +通过 Helm 升级应用 +```shell +helm upgrade microservices-demo helm-chart -n demotest +``` + +等待程序正常启动,并测试访问即可验证( FRONT_END_POD_NAME 为 front-end 的 Pod 名) +```shell +kubectl port-forward pod/${FRONT_END_POD_NAME} -n demotest 8080:8079 +``` diff --git a/docs/versioned_docs/version-v0.3.0/UseCases/standalone.md b/docs/versioned_docs/version-v0.3.0/UseCases/standalone.md new file mode 100644 index 00000000..db3834d9 --- /dev/null +++ b/docs/versioned_docs/version-v0.3.0/UseCases/standalone.md @@ -0,0 +1,460 @@ +--- +sidebar_position: 2 +--- + +# 单独部署 Pisa-Proxy + +***Pisa-Proxy*** 作为高性能代理不仅可以在 kubernetes 中以 Sidecar 的方式部署,也可以作为统一接入层单独部署在 kubernetes 之外的服务器上: + +![single.png](/img/single.png) + +目前***Pisa-Proxy***支持 MySQL 协议,无论后端是云上的 RDS 实例,还是自建的 MySQL、ShardingSphere、TiDB 等,都可以由 Pisa-Proxy 统一流量分发,实现无感的高可用切换、面向 SQL 的可观测性等。 + +## 部署说明 + +Pisa-Proxy 支持从配置文件和 Remote API 获取配置。目前支持 ```daemon``` 和 ```sidecar``` 两个子命令,用来指定不同的启动方式。 + +### 命令行参数 +``` +# ./proxy --help +Pisa-Proxy - + +USAGE: + proxy [OPTIONS] + +OPTIONS: + -h, --host Http host [env: PISA_PROXY_ADMIN_LISTEN_HOST=] [default: 0.0.0.0] + --help Print help information + --log-level Log level [env: PISA_PROXY_ADMIN_LOG_LEVEL=] [default: WARN] + -p, --port Http port [env: PISA_PROXY_ADMIN_LISTEN_PORT=] [default: 5591] + -V, --version Print version information + +SUBCOMMANDS: + daemon used for standalone mode + help Print this message or the help of the given subcommand(s) + sidecar used for sidecar mode +``` + +通常在单机部署中使用 ```daemon``` 子命令并通过 ```-c,--config``` 指定配置文件路径。 +``` +# ./proxy daemon --help +proxy-daemon +used for standalone mode + +USAGE: + proxy daemon [OPTIONS] + +OPTIONS: + -c, --config Config path [default: etc/config.toml] + -h, --help Print help information +``` + +在 Kubernetes 中以 sidecar 方式部署可以通过 ```sidecar``` 子命令从远程获取配置。 +``` +# ./proxy sidecar -h +proxy-sidecar +used for sidecar mode + +USAGE: + proxy sidecar [OPTIONS] + +OPTIONS: + -h, --help + Print help information + + --pisa-controller-host + Pisa Controller Host [env: PISA_CONTROLLER_HOST=] [default: localhost:8080] + + --pisa-deployed-name + Name [env: PISA_DEPLOYED_NAME=] [default: default] + + --pisa-deployed-namespace + Namespace [env: PISA_DEPLOYED_NAMESPACE=] [default: default] +``` + +### 环境变量 + +环境变量包括如下: +1. PISA_PROXY_ADMIN_LISTEN_HOST: HTTP 服务启动 IP +1. PISA_PROXY_ADMIN_LISTEN_PORT: HTTP 服务启动端口号 +2. DEFAULT_PISA_PROXY_ADMIN_LOG_LEVEL: 日志级别 + +### 配置文件 + +Pisa-Proxy 在本地作为单独部署启动的时候需要以下配置文件: + +``` +# api 配置块,对应命令行参数和环境变量 +[admin] +# Http IP 地址 +host = "0.0.0.0" +# api 端口 +port = 5591 +# 日志级别 +log_level = "INFO" + +# pisa-proxy 代理配置块 +[proxy] +# config a proxy +[[proxy.config]] +# proxy 代理地址 +listen_addr = "0.0.0.0:9088" +# proxy 认证用户名 +user = "root" +# proxy 认证密码 +password = "12345678" +# proxy schema +db = "test" +# 配置后端数据源类型 +backend_type = "mysql" +# proxy 与后端数据库建连连接池大小,值范围:1 ~ 255, 默认值:64 +pool_size = 3 +# 服务端版本 +server_version = "5.7.37" + +# 后端负载均衡配置 +# 基础负载均衡策略 +[proxy.config.simple_loadbalance] +# 负载均衡算法:[random/roundrobin], 默认值: random 算法 +balance_type = "random" +# 选择挂载后端节点 +nodes = ["ds001"] + +# 读写分离策略 +[proxy.config.read_write_splitting] +# 读写分离策略静态模式 +[proxy.config.read_write_splitting.static] +default_target = "readwrite" + +# 读写分离策略静态规则 +[[proxy.config.read_write_splitting.static.rule]] +name = "read-rule" +type = "regex" +regex = ["^select"] +target = "read" +algorithm_name = "random" + +[[proxy.config.read_write_splitting.static.rule]] +name = "write-rule" +type = "regex" +regex = ["^create","^update","^insert","^delete"] +target = "readwrite" +algorithm_name = "roundrobin" + +# 并发控制规则 +[[proxy.config.plugin.concurrency_control]] +regex = ["aaa"] +max_concurrency = 5 +duration = 333 + +# 断路器规则 +[[proxy.config.plugin.circuit_break]] +regex = ["111"] + +# 后端数据源配置 +[mysql] +[[mysql.node]] +# 数据源 name +name = "ds001" +# database name +db = "" +# 数据库 user +user = "root" +# 数据库 password +password = "root" +# 数据库地址 +host = "127.0.0.1" +# 数据库端口 +port = 3307 +# 数据库属性, 默认可选 "read" 或 "readwrite" +role = "read" + +[[mysql.node]] +# 数据源 name +name = "ds002" +# database name +db = "" +# 数据库 user +user = "root" +# 数据库 password +password = "root" +# 数据库地址 +host = "127.0.0.1" +# 数据库端口 +port = 3307 +# 数据库属性,默认可选 "read" 或 "readwrite" +role = "readwrite" +``` + +### 部署示例 + +#### 编译 Pisa-Proxy +首先在 `pisa-proxy` 目录中执行 `make build` 即可编译得到二进制的 `pisa-proxy`。注意,首次编译更新 Crates 耗时较长。 + + +#### 配置后端数据库基础负载均衡 +然后参考如下示例,配置多个代理或后端数据库负载均衡: + +``` +[admin] +log_level = "INFO" + +[proxy] +[[proxy.config]] +listen_addr = "0.0.0.0:9088" +user = "root" +password = "12345678" +db = "test" +backend_type = "mysql" +pool_size = 3 + +[proxy.config.simple_loadbalance] +balance_type = "random" +nodes = ["ds001"] + +[proxy] +[[proxy.config]] +listen_addr = "0.0.0.0:9089" +user = "root" +password = "root" +db = "test" +backend_type = "mysql" +pool_size = 3 + +[proxy.config.simple_loadbalance] +balance_type = "random" +nodes = ["ds001"] + +[mysql] +[[mysql.node]] +name = "ds001" +db = "test" +user = "root" +password = "root" +host = "127.0.0.1" +port = 3307 +``` + +#### 配置后端数据库读写分离 +``` +[admin] +log_level = "INFO" + +[proxy] +[[proxy.config]] +listen_addr = "0.0.0.0:9089" +user = "root" +password = "root" +db = "test" +backend_type = "mysql" +pool_size = 3 + +[proxy.config.read_write_splitting] +[proxy.config.read_write_splitting.static] +default_target = "read" + +# 通用路由规则 +[[proxy.config.read_write_splitting.static.rule]] +name = "read-rule" +type = "generic" +algorithm_name = "random" + +# 基于正则表达式的路由规则 +[[proxy.config.read_write_splitting.static.rule]] +name = "read-rule" +type = "regex" +regex = [".*"] +target = "read" +algorithm_name = "random" + +# 基于正则表达式的路由规则 +[[proxy.config.read_write_splitting.static.rule]] +name = "write-rule" +type = "regex" +regex = [".*"] +target = "readwrite" +algorithm_name = "roundrobin" + +[mysql] +[[mysql.node]] +name = "ds001" +db = "test" +user = "root" +password = "root" +host = "127.0.0.1" +port = 3307 +role = "read" + +[[mysql.node]] +name = "ds002" +db = "test" +user = "root" +password = "root" +host = "127.0.0.1" +port = 3308 +role = "readwrite" +``` + +#### 配置后端数据库动态读写分离 +``` +[admin] +log_level = "INFO" + +[proxy] +[[proxy.config]] +listen_addr = "0.0.0.0:9089" +user = "root" +password = "root" +db = "test" +backend_type = "mysql" +pool_size = 3 + +[proxy.config.read_write_splitting] + +[proxy.config.read_write_splitting.dynamic] +default_target = "readwrite" + +[proxy.config.read_write_splitting.dynamic.discovery] +type = "mha" +user = "root" +password = "12345678" +monitor_period = 1 +connect_period = 100 +connect_timeout = 600 +connect_failure_threshold = 1 +ping_period = 100 +ping_timeout = 300 +ping_failure_threshold = 1 +replication_lag_period = 100 +replication_lag_timeout = 600 +replication_lag_failure_threshold = 1 +max_replication_lag = 3 +read_only_period = 100 +read_only_timeout = 600 +read_only_failure_threshold = 1 + +# 通用路由规则 +[[proxy.config.read_write_splitting.static.rule]] +name = "read-rule" +type = "generic" +algorithm_name = "random" + +# 基于正则的路由规则 +[[proxy.config.read_write_splitting.dynamic.rule]] +name = "write-rule" +type = "regex" +regex = ["^insert"] +target = "readwrite" +algorithm_name = "roundrobin" + +[[proxy.config.read_write_splitting.dynamic.rule]] +name = "read-rule" +type = "regex" +regex = ["^select"] +target = "read" +algorithm_name = "roundrobin" + +[mysql] +[[mysql.node]] +name = "ds001" +db = "test" +user = "root" +password = "root" +host = "127.0.0.1" +port = 3307 +role = "read" + +[[mysql.node]] +name = "ds002" +db = "test" +user = "root" +password = "root" +host = "127.0.0.1" +port = 3308 +role = "readwrite" +``` + +#### 基于分片键的分片配置 +``` +# api 配置块,对应命令行参数和环境变量 +[admin] +# api 地址 +host = "0.0.0.0" +# api 端口 +port = 8082 +# 日志级别 +log_level = "INFO" + +# pisa-proxy 代理配置块 +[proxy] +# config a proxy +[[proxy.config]] +# proxy 代理地址 +listen_addr = "0.0.0.0:9088" +# proxy 认证用户名 +user = "root" +# proxy 认证密码 +password = "12345678" +# proxy schema +db = "test_shard" +# 配置后端数据源类型 +backend_type = "mysql" +# proxy 与后端数据库建连连接池大小,值范围:1 ~ 255, 默认值:64 +pool_size = 3 +# 服务端版本 +server_version = "" + +[proxy.config.simple_loadbalance] +balance_type = "random" +nodes = ["ds001"] + +#后端数据源配置 +[[proxy.config.sharding]] +# 逻辑表名 +table_name = "t_order" +# 后端节点, 对应 mysql.node 的 name +actual_datanodes = ["ds001"] +# 暂不支持 +binding_tables = [] +# 暂不支持 +broadcast_tables = [] + +# 单库分表 +[proxy.config.sharding.table_strategy] +# 分片算法名 +table_sharding_algorithm_name = "mod" +# 分片键 +table_sharding_column = "id" +# 分片数 +sharding_count = 4 + +[mysql] +[[mysql.node]] +# 数据源 name +name = "ds001" +# database name +db = "test_shard" +# 数据库 user +user = "root" +# 数据库 password +password = "12345678" +# 数据库地址 +host = "127.0.0.1" +# 数据库端口 +port = 3306 +# 负载均衡节点权重 +weight = 1 +# 后端数据源角色 +role = "read" +``` + +#### 启动 Pisa-Proxy + +这里假设配置文件存放路径为 `examples/example-config.toml`,最后使用如下命令即可完成启动。 + +```shell +/bin/proxy daemon -c examples/example-config.toml +``` + +当观察日志确认 ***Pisa-Proxy*** 启动后即可进行访问。 + diff --git a/docs/versioned_docs/version-v0.3.0/intro.md b/docs/versioned_docs/version-v0.3.0/intro.md new file mode 100644 index 00000000..44641df1 --- /dev/null +++ b/docs/versioned_docs/version-v0.3.0/intro.md @@ -0,0 +1,67 @@ +--- +sidebar_position: 1 +--- + +# 简介 + +`Pisanix` [Pi-sanics] 是一款面向 Kubernetes 的数据库治理框架。Pisanix 通过 SQL 感知的流量治理、审计、安全和扩展性等能力实现 [Database Mesh](https://www.database-mesh.io) 风格的数据库治理体验。 + +## 概述 + +Pisanix 关注如下几个问题: + +* SQL 感知的流量治理:支持 SQL 流量负载均衡、访问控制和可观测性。 +* 运行时资源管理: 支持多种可扩展的资源控制能力 +* 数据库可靠性工程:简化 Kubernetes 环境下数据库的治理 + +Pisanix 的架构图如下: + +![Pisanix Arch](/img/pisanix-arch.png) + +三个组件的功能分别为: + +* ***Pisa-Controller***: 用 Go 实现的控制面,提供对数据面组件的管控,如 Sidecar 注入、配置转换和下发,是 Pisanix 所有配置的入口。 + +* ***Pisa-Proxy***: 用 Rust 实现的高性能量代理,通过 MySQL 协议获取应用的数据库访问流量,并基于此实现 SQL 流量治理、访问控制、防火墙、可观测性等各种治理能力。 + +* ***Pisa-Daemon(即将推出)***: 节点级数据面,部署在集群中每个节点上并通过宿主机内核的各种能力提供可编程资源管理,如 TrafficQoS 等。 + + +## 特性 + +### 数据库流量治理 + +应用通过 SQL 访问数据库,Pisanix 可以劫持所有的 SQL 流量。借助这个能力,Pisanix 可以实现多种流量治理能力,如负载均衡、SQL 防火墙等。 + +### 可观测性 + +数据库的监控指标通常从相关实例处获取,借助 Pisanix 可以透视多种数据库访问指标。 + +### 可编程 + +Pisanix 支持多种插件机制,如 Lua 和 Wasm,工程师们有机会重新定义数据库各种行为。 + + +## 快速开始 + +- [简介](https://www.pisanix.io/docs) +- [快速开始](https://www.pisanix.io/docs/quickstart) + +## 文档 + +所有文档可以在 [Pisanix 站点查看](https://www.pisanix.io/). + +## 社区和支持 + +||| +|:-|:-| +| 邮件列表| https://groups.google.com/g/database-mesh | +| 英文社区会议(开始于 2022-02-16), 周三 9:00AM PST|https://meet.google.com/yhv-zrby-pyt | +| 中文社区会议 (开始于 2022-04-27), 周三 9:00PM GMT+8|https://meeting.tencent.com/dm/6UXDMNsHBVQO | +| Slack | https://join.slack.com/t/databasemesh/shared_invite/zt-19rhvnxkz-USjZ~am~ghd_Q0q~8bAJXA | +| 会议记录 |https://bit.ly/39Fqt3x | + + +- 微信交流群: 添加小助手微信邀请进群 + +![Wechat user group broker](/img/wechat-user-group-broker.jpeg) diff --git a/docs/versioned_docs/version-v0.3.0/quickstart.md b/docs/versioned_docs/version-v0.3.0/quickstart.md new file mode 100644 index 00000000..42a7daf7 --- /dev/null +++ b/docs/versioned_docs/version-v0.3.0/quickstart.md @@ -0,0 +1,17 @@ +--- +sidebar_label: '快速开始' +sidebar_position: 2 +--- + +# 快速开始 + +## 推荐部署 + +[在 Kubernetes 中部署](./UseCases/kubernetes.md) + +## 单独部署 + +[Pisa-Proxy 单独部署](./UseCases/standalone.md) + + + diff --git a/docs/versioned_sidebars/version-v0.3.0-sidebars.json b/docs/versioned_sidebars/version-v0.3.0-sidebars.json new file mode 100644 index 00000000..caea0c03 --- /dev/null +++ b/docs/versioned_sidebars/version-v0.3.0-sidebars.json @@ -0,0 +1,8 @@ +{ + "tutorialSidebar": [ + { + "type": "autogenerated", + "dirName": "." + } + ] +} diff --git a/docs/versions.json b/docs/versions.json index 750bb2b9..ac45c70c 100644 --- a/docs/versions.json +++ b/docs/versions.json @@ -1,4 +1,5 @@ [ + "v0.3.0", "v0.2.0", "v0.1.1", "v0.1.0"