Vitess:云原生 MySQL 水平扩展集群

FreeGuideOnline 最新 2026-06-30

简介

Vitess 是一个用于部署、扩展和管理大型开源数据库实例集群的数据库解决方案。它最初为 YouTube 而构建,现已被 Cloud Native Computing Foundation (CNCF) 接受为毕业项目。Vitess 将许多重要的 MySQL 特性与 NoSQL 数据库的可扩展性相结合,能够对数据进行分析片、分片管理、连接池、查询重写等操作,让您的应用程序就像在操作一个单一的逻辑数据库一样。

简单来说,Vitess 是 云原生的 MySQL 水平扩展集群。它让您能够像使用单机 MySQL 一样使用一个可以水平扩展的数据库。

为什么需要 Vitess

当单体 MySQL 数据库在数据量或读写压力上达到瓶颈时,常见的垂直扩展(升级硬件)成本高昂且有上限。水平扩展(分库分表)虽然能解决容量问题,但会给应用层带来巨大的复杂性:需要感知分片键、处理跨分片查询、维护连接池、执行模式变更等。

Vitess 正是为了解决这些痛点而生,它提供了:

  • 透明的分片能力:应用无需关心数据被存储在哪个分片上,通过标准 SQL 即可访问。
  • 连接池与复用:内置连接池,可将数千个应用连接合并为少量 MySQL 连接,保护数据库免受过载。
  • 在线模式变更:通过与 gh-ostpt-online-schema-change 集成,在不锁表的情况下执行 DDL。
  • 故障恢复与重定向:内置守护进程与拓扑管理,检测到故障后可快速重定向流量,保证高可用。
  • 监控与可观测性:提供丰富的状态页面和 /debug/vars 端点,易于集成 Prometheus 等监控系统。
  • 云中立的部署:可以运行在 Kubernetes、裸机或任何云平台上。

核心概念

在学习 Vitess 之前,您需要理解几个关键术语:

Cell(单元)

Cell 是一个故障隔离域,通常对应一个数据中心或可用区。一个 Vitess 集群可以跨多个 Cell 部署,以实现地理分布式部署。每个 Cell 内可以包含多个 Tablet。

Keyspace(键空间)

Keyspace 是 Vitess 中的逻辑数据库,类似于 MySQL 中的数据库(database)。一个 Keyspace 可以包含多个分片。对于未分片的 Keyspace,所有数据都位于单个分片中。

Shard(分片)

分片是 Keyspace 中的数据分区。一个分片通常包含一个 MySQL 复制集(一主多从)。数据根据分片键和分片策略(哈希或范围)分布到不同的分片中。

Tablet(平板)

Tablet 是 Vitess 中最小的数据管理单元,它代表一个运行中的 mysqld 实例,并由 vttablet 进程进行管理。每个 Tablet 被赋予一种类型:

  • master(主):当前接受写入操作的 Tablet。
  • replica(从):用于读取操作,可能从主节点异步复制。
  • rdonly(只读):用于离线处理、分析查询等,也参与复制。

VTGate

VTGate 是一个轻量级的无状态代理,应用程序连接到此服务并通过它发送查询。它负责将 SQL 查询路由到正确的分片,并进行结果聚合。VTGate 对外呈现为单一的 MySQL 服务器端点。

VTTablet

VTTablet 是运行在每个 MySQL 实例旁的控制代理。它执行查询、管理连接池、进行权限检查、向拓扑服务上报状态,并与 VTGate 协同工作。

Topology Service(拓扑服务)

拓扑服务(如 etcd、ZooKeeper、Consul)存储了集群的所有元数据:Keyspace 和 Shard 定义、Tablet 的状态、主从关系等。所有的 Vitess 组件都从拓扑服务读取和更新元信息。

VTAdmin

VTAdmin 是一套用于管理和查看 Vitess 集群的 Web UI 和 API。它让您可以查看拓扑、执行紧急故障转移、启动重新分片任务等。

架构概览

一个典型的 Vitess 部署包括以下组件:

       应用程序
          |
       VTGate (无状态代理,可多实例)
          |
     拓扑服务 (etcd/consul 等)
          |
+---------+---------+
| Cell A            | Cell B            |
|                  |                  |
| VTTablet         | VTTablet         |
|  + MySQL         |  + MySQL         |
| VTTablet         | VTTablet         |
|  + MySQL         |  + MySQL         |
+------------------+------------------+
  • 数据平面:VTGate 将 SQL 路由到正确的 VTTablet,VTTablet 将 SQL 转发给 MySQL。结果沿原路返回。
  • 控制平面:VTTablet 向拓扑服务注册并上报健康状态。VTAdmin、VTOrc(协调器)等组件基于拓扑信息进行故障恢复、重分片等操作。

查询流程:

  1. 应用连接到 VTGate(通常使用 MySQL 协议)。
  2. VTGate 解析 SQL,根据分片键确定需要访问哪些分片。
  3. VTGate 向相关 VTTablet 发送请求。
  4. VTTablet 执行查询,可能利用连接池,最终将结果返回给 VTGate。
  5. 对于需要跨分片聚合的查询,VTGate 进行合并后返回给应用。

快速上手:部署一个简单的 Vitess 集群

以下步骤将引导您在本地使用 docker-compose 启动一个 Vitess 集群,体验基本的分片操作。本示例基于 Vitess 官方示例。

前提条件

  • 安装 Docker 与 Docker Compose
  • 安装 MySQL 客户端(用于测试连接)

步骤 1:克隆 Vitess 仓库并进入示例目录

git clone https://github.com/vitessio/vitess.git
cd vitess/examples/compose

步骤 2:启动集群

docker-compose up -d

此命令会启动拓扑服务(etcd)、VTGate、VTTablet 和一个未分片的 Keyspace(名为 commerce)。可能需要几分钟下载镜像。

步骤 3:验证环境

# 检查容器运行状态
docker-compose ps

# 进入 VTGate 容器,连接 MySQL 协议端口
docker-compose exec vttablet101 mysql -u root -h vttablet101 -P 3306

在 MySQL 客户端中,您应该能看到 commerce 数据库。

步骤 4:创建分片 Keyspace 并插入数据

我们将创建一个名为 customer 的 Keyspace,采用哈希分片,并分成两个分片:

# 使用 vtctld 命令创建 Keyspace
docker-compose exec vtctld vtctldclient CreateKeyspace customer --durability-policy=semi_sync

# 创建分片定义:使用 - 表示分片范围,对哈希分片通常用 -80, 80- 表示两个分片
docker-compose exec vtctld vtctldclient ApplyVSchema --vschema='{
  "sharded": true,
  "vindexes": {
    "hash": {
      "type": "hash"
    }
  },
  "tables": {
    "customer": {
      "column_vindexes": [
        {
          "column": "customer_id",
          "name": "hash"
        }
      ]
    }
  }
}' customer

# 创建两个分片 tablet(-80 和 80-)
# 以下示意使用本地示例脚本,实际操作可参考:https://vitess.io/docs/get-started/local/
# 为简化,我们直接使用 compose 内置的已有分片示例。官方 compose 示例通常已预置了 `customer` 分片。

如果使用预置的 compose 示例,启动后应存在 customer keyspace 及其两个分片。

步骤 5:通过 VTGate 访问分片表

使用 MySQL 客户端连接 VTGate(端口 15306):

mysql -h 127.0.0.1 -P 15306 -u user

在 MySQL 终端中执行:

USE customer;
CREATE TABLE customer (
  customer_id bigint NOT NULL,
  email varbinary(128),
  PRIMARY KEY (customer_id)
);

-- 插入几条数据,customer_id 会被哈希到不同分片
INSERT INTO customer (customer_id, email) VALUES (1, 'alice@domain.com');
INSERT INTO customer (customer_id, email) VALUES (2, 'bob@domain.com');
INSERT INTO customer (customer_id, email) VALUES (3, 'charlie@domain.com');

-- 查询,Vitess 会路由到正确分片
SELECT * FROM customer WHERE customer_id = 2;
-- 跨分片全表扫描(适用于小表)
SELECT * FROM customer;

此时您已经体验了 Vitess 的基本分片路由能力。

使用 Vitess 的关键实践

分片键选择

  • 选用高基数的列,如用户 ID、订单 ID。
  • 避免选择会导致数据倾斜的列(如状态字段)。
  • 推荐使用 hash vindex(虚拟索引)以均匀分布数据。

避免跨分片查询

  • 设计数据模型时,尽量让关联数据落在同一分片(通过分片键)。
  • 对于必须跨分片聚合的场景,Vitess 支持 GROUP BYORDER BY 的分散查询,但性能会受影响。

连接池管理

  • VTGate 与 VTTablet 之间以及 VTTablet 与 MySQL 之间都有连接池,您只需关注应用端连接 VTGate 的配置。
  • VTGate 是无状态的,可以通过水平扩展来增加并发处理能力。

模式变更

  • 使用 vtctldclient ApplySchema 执行 DDL,它会与 Vitess 集成的在线变更工具协作,避免锁表。
  • 注意:某些复杂 DDL 操作仍需谨慎规划。

监控与告警

  • 每个 Vitess 组件都导出 Prometheus 指标,可借助 Grafana 仪表盘进行可视化。
  • 关注指标:Vtgate 查询延迟、错误率、VTTablet 复制延迟、连接池使用率。

总结

Vitess 将 MySQL 从单体架构中解放出来,使其具备像 NoSQL 系统一样的水平扩展能力,同时保留了完整的 SQL 支持和 ACID 事务。通过透明的分片、连接池、内置高可用和在线变更,Vitess 成为云原生数据库管理的理想选择,尤其适合需要处理海量数据和高并发的互联网应用。

想要深入了解更多高级特性,如重分片(resharding)、物化视图、VReplication 等,请查阅 Vitess 官方文档。现在您已经迈出了第一步,可以尝试在开发环境中实践更复杂的部署模式。