php 多副本数据同步延迟===数据版本号/时间戳一致性方案
·
1. 原理说明
- 每条数据都带有一个版本号(如
version字段)或更新时间戳(如updated_at字段)。 - 读数据时,客户端或服务端记录下当前的版本号/时间戳。
- 当再次读取数据时,如果发现版本号/时间戳落后于主库,说明数据过旧,可以选择重试或强制回源主库获取最新数据。
2. 适用场景
- 主从数据库、分布式缓存等多副本架构下,存在同步延迟。
- 需要在最终一致性和强一致性之间做权衡的业务场景。
3. 完整流程
-
数据表设计
增加version(自增整数)或updated_at(时间戳)字段。 -
写操作
- 每次更新数据时,
version加1或更新时间戳。
- 每次更新数据时,
-
读操作
- 读数据时返回
version或updated_at。 - 客户端/服务端保存本次读取的版本号。
- 下次读取时,如果发现版本号/时间戳比预期的旧,则说明数据未同步,可以选择重试或回源主库。
- 读数据时返回
4. 表结构示例
CREATE TABLE `users` (
`id` INT PRIMARY KEY,
`name` VARCHAR(50),
`info` TEXT,
`version` INT DEFAULT 1,
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
5. PHP实现示例
写操作(更新数据时)
<?php
$pdo = new PDO("mysql:host=127.0.0.1;dbname=test", "root", "123456");
$user_id = 1;
$new_info = "新资料";
// 先查当前版本号
$stmt = $pdo->prepare("SELECT version FROM users WHERE id = ?");
$stmt->execute([$user_id]);
$row = $stmt->fetch(PDO::FETCH_ASSOC);
$current_version = $row['version'];
// 更新数据时,version加1
$new_version = $current_version + 1;
$stmt = $pdo->prepare("UPDATE users SET info = ?, version = ? WHERE id = ?");
$stmt->execute([$new_info, $new_version, $user_id]);
?>
读操作(带版本号)
<?php
$pdo = new PDO("mysql:host=127.0.0.1;dbname=test", "root", "123456");
$user_id = 1;
// 读数据时返回version
$stmt = $pdo->prepare("SELECT id, name, info, version FROM users WHERE id = ?");
$stmt->execute([$user_id]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
// 假设客户端保存了上次读取的version
$client_version = $_GET['client_version'] ?? 0;
if ($user['version'] > $client_version) {
// 数据有更新,返回最新数据
echo json_encode(['code' => 200, 'data' => $user]);
} else {
// 数据未更新,或数据过旧
echo json_encode(['code' => 304, 'msg' => '数据未更新']);
}
?>
主从延迟下的重试/回源主库
- 如果你用读写分离,读操作默认走从库。
- 发现
version比预期旧,可以让应用层重试一次并强制走主库。
// 伪代码
if ($user['version'] < $client_version) {
// 说明从库数据还没同步到最新
// 强制从主库再查一次
$pdo_master = new PDO("mysql:host=主库IP;dbname=test", "root", "123456");
$stmt = $pdo_master->prepare("SELECT id, name, info, version FROM users WHERE id = ?");
$stmt->execute([$user_id]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
// 返回主库最新数据
}
6. 实际应用举例
- 缓存一致性:缓存数据带版本号,客户端发现版本号落后时主动刷新缓存。
- 主从延迟:订单、支付等场景,写完后读到旧数据时,自动重试或回源主库。
7. 注意事项
- 版本号/时间戳要保证每次写操作都更新。
- 业务层要能识别“数据过旧”并做出相应处理(如重试、回源、提示用户等)。
- 适合对一致性有要求但能容忍短暂延迟的场景。
8. 总结
- 数据版本号/时间戳是分布式系统中常用的一致性保障手段。
- 结合主从读写分离、缓存等架构,可以大幅提升数据一致性体验。
更多推荐
所有评论(0)