使用一致查找 Vindex 实现数据一致性
什么是 Vindex
Vitess 使用 Vindex(Vitess 索引的缩写)来将表中的行与一个称为 Keyspace ID 的指定地址关联。这使得 Vitess 能够将数据行定向到其目标(通常是集群内的一个分片)。
Vindex 扮演了双重角色:通过 Primary Vindex 实现数据分片,并通过 Secondary Vindex 提供全局索引支持。通过这一机制,Vindex 成为一种在分片数据库中路由查询的重要工具,确保了最佳的性能和可扩展性。
查找 Vindex
作为 Secondary Vindex 的查找 Vindex 用于将 Select/Update/Delete 查询定向到适当的分片,而无需依赖 scatter-gather 操作(将查询发往所有分片处理),从而避免性能开销。
当向表插入数据时,一个单独的全局索引表会维护 Secondary Index 列与其对应的 Keyspace ID 的映射关系。随后,这些映射信息用于高效地将查询路由到目标分片。
Secondary Vindex 可分为唯一型(unique)或非唯一型(non-unique)两类。以下是一个示例,展示这两种类型的运作方式。
数据表定义
USER 表
+-------+--------------+------+-----+ | Field | Type | Null | Key | +-------+--------------+------+-----+ | id | bigint | NO | PRI | | name | varchar(255) | YES | | | phone | bigint | YES | UNI | | email | varchar(255) | YES | | +-------+--------------+------+-----+
非唯一型 Vindex 表定义
NAME_USER_VDX 表 +-------------+--------------+------+-----+ | Field | Type | Null | Key | +-------------+--------------+------+-----+ | name | varchar(255) | NO | PRI | | id | bigint | NO | PRI | | keyspace_id | binary(8) | YES | | +-------------+--------------+------+-----+
唯一型 Vindex 表定义
PHONE_USER_VDX 表 +-------------+-----------+------+-----+ | Field | Type | Null | Key | +-------------+-----------+------+-----+ | phone | bigint | NO | PRI | | keyspace_id | binary(8) | YES | | +-------------+-----------+------+-----+
当执行类似以下查询时:
SELECT id, phone, email FROM user WHERE name = 'Alex';
查询规划器会使用查找 Vindex 表 name_user_vdx
来将值 Alex
映射到其对应的 **Keyspace ID**,从而使规划器将查询定向到单一目标分片,而非所有分片,从而避免昂贵的 scatter-gather 操作。
特别值得一提的是 **一致查找 Vindex(Consistent Lookup Vindex)**,它是一种 Secondary Vindex,可进一步提高路由机制的效率和可靠性。
一致查找 Vindex
在大多数情况下,用户数据表和查找 Vindex 表都会分片以实现性能与存储的优化。用户表与 Vindex 表的分片列可能不同。在以上场景中,我们假定各表的分片列如下:
表名 | Primary Vindex 列 |
User | id |
Name_User_Vdx | name |
Phone_User_Vdx | phone |
通过 DML(数据操作语言)语句对用户表进行数据更改(如 **Insert/Update/Delete**)会导致 Vindex 表中的行也发生变化。为了保持用户数据表与 Vindex 表之间的一致性,所有这些操作必须在跨多个分片的事务中进行。这意味着需要实施类似 两阶段提交协议(2PC) 的昂贵机制,以保证原子性与隔离性(ACID 中的 A 和 I)。如果在这些操作中未使用正确的多分片事务,可能导致部分提交及数据不一致问题。
一致查找 Vindex 使用了一种替代方法,通过小心的锁定与事务序列的使用,在所有 DML 操作中实现一致性而不需要 2PC。这使得 Vitess 即使在 Vindex 表中的记录可能不一致的情况下,也能提供用户数据表的一致视图。
数据修改时使用的连接
当数据被修改时,Vitess 使用三个连接执行 DML 操作,分别称为:Pre、Main 和 Post。这些连接的任一事务都会遵循一套明确的操作序列。提交事务时按以下顺序执行:
- Pre 事务提交;
- Main 事务提交;
- Post 事务提交。
任一步骤失败时,剩余的事务将按相同顺序回滚。
示例:如何运作
样例行数据
USER 表:
+-----+------+------------+-----------------+ | id | name | phone | email | +-----+------+------------+-----------------+ | 100 | Alex | 8877991122 | alex@mail.com | | 200 | Emma | 8811229988 | emma@mail.com | +-----+------+------------+-----------------+
NAME_USER_VDX 表:
+------+-----+--------------------------+ | name | id | keyspace_id | +------+-----+--------------------------+ | Alex | 100 | 0x313030 | | Emma | 200 | 0x323030 | +------+-----+--------------------------+
PHONE_USER_VDX 表:
+------------+--------------------------+ | phone | keyspace_id | +------------+--------------------------+ | 8811229988 | 0x323030 | | 8877991122 | 0x313030 | +------------+--------------------------+
删除操作(Delete Operation)
通过 Post 连接删除查找 Vindex 数据。
示例:
DELETE FROM user WHERE id = 100;
- 从用户表中选择所有查找列:
- 删除对应查找 Vindex 的行:
- 删除用户表行:
如果针对用户表的删除操作成功而针对 Vindex 表的删除操作失败,那么仍然能够保持查询结果的一致性。
插入操作(Insert Operation)
通过 Pre 连接插入查找 Vindex 数据。
示例:
INSERT INTO user(id, name, phone, email) VALUES (300, 'Emma', 8877991122, 'xyz@mail.com');
总结
一致查找 Vindex 提供了一种无需使用昂贵的 2PC 协议的替代方案,Vitess 通过精细的锁定和事务序列操作有效地维护用户数据表与 Vindex 表之间的一致性。它帮助查询能够返回与用户表保持一致的结果,同时保证了分片数据库的整体性能与可靠性。
关注公众号:程序新视界,一个让你软实力、硬技术同步提升的平台
除非注明,否则均为程序新视界原创文章,转载必须以链接形式标明本文链接
本文链接:https://choupangxia.com/2025/09/14/vitess-consistent-lookup-vindex/