本文目录导读:

针对PHP项目批量拉黑名单同步到多节点,推荐以下几种成熟方案:
Redis + 消息队列(推荐)
批量导入黑名单接口
<?php
// BatchBlacklistController.php
class BatchBlacklistController {
public function import($request) {
// 1. 接收批量数据(CSV/Excel/JSON)
$file = $request->file('blacklist');
$data = $this->parseFile($file);
// 2. 数据校验
$validData = $this->validate($data);
// 3. 写入Redis Set(原子操作)
$redis = new Redis();
$redis->sAddArray('global:blacklist', $validData);
// 4. 发布消息到队列
$this->publishSyncMessage([
'action' => 'batch_add',
'data' => $validData,
'timestamp' => time()
]);
return json(['success' => true, 'count' => count($validData)]);
}
private function publishSyncMessage($message) {
// 使用Redis Stream或RabbitMQ
$redis = new Redis();
$redis->xAdd('blacklist_sync', '*', $message);
}
}
多节点同步消费者
<?php
// BlacklistSyncWorker.php
class BlacklistSyncWorker {
public function consume() {
$redis = new Redis();
$redis->connect('redis-master', 6379);
// 每个节点独立消费
$group = 'blacklist_sync_group';
$consumer = 'node_' . gethostname();
while (true) {
$messages = $redis->xReadGroup(
$group,
$consumer,
['blacklist_sync' => '>'],
1, // 每次读取1条
1000 // 阻塞1秒
);
if (!empty($messages)) {
foreach ($messages as $stream => $msgs) {
foreach ($msgs as $id => $msg) {
$this->processMessage($msg);
$redis->xAck('blacklist_sync', $group, [$id]);
}
}
}
}
}
private function processMessage($msg) {
$action = $msg['action'];
$data = json_decode($msg['data'], true);
switch ($action) {
case 'batch_add':
// 更新本地内存/文件/数据库
$this->updateLocalBlacklist($data);
break;
case 'remove':
$this->removeFromLocal($data);
break;
}
}
}
使用Redis集群(最简单)
单节点写入,集群自动同步
<?php
// 使用Redis Cluster自动同步
class BlacklistManager {
private $redis;
public function __construct() {
// 连接Redis集群
$this->redis = new RedisCluster(null, [
'192.168.1.1:6379',
'192.168.1.2:6379',
'192.168.1.3:6379'
]);
}
public function batchAdd(array $users) {
// 使用Pipeline批量写入
$pipe = $this->redis->multi(Redis::PIPELINE);
foreach ($users as $user) {
$pipe->sAdd('global:blacklist', $user);
}
$pipe->exec();
}
public function isBlacklisted($userId) {
return $this->redis->sIsMember('global:blacklist', $userId);
}
}
文件同步 + inotify(适合小规模)
主节点生成文件
<?php
// Master节点
class BlacklistFileSync {
public function exportFile() {
$data = $this->getAllBlacklistUsers();
$content = implode("\n", $data);
// 写入共享存储(NFS/GFS/S3)
file_put_contents('/shared/blacklist/blacklist_' . date('Ymd_Hi') . '.txt', $content);
// 生成MD5校验
file_put_contents('/shared/blacklist/blacklist.md5', md5($content));
}
}
// 从节点监听
class BlacklistFileWatcher {
public function watch() {
// 使用inotify监控文件变化
$inotify = inotify_init();
$watch = inotify_add_watch($inotify, '/shared/blacklist', IN_CLOSE_WRITE);
while (true) {
$events = inotify_read($inotify);
foreach ($events as $event) {
if ($event['name'] === 'blacklist.md5') {
$this->reloadBlacklist();
}
}
}
}
public function reloadBlacklist() {
// 重新加载到内存/Redis/APC
$content = file_get_contents('/shared/blacklist/blacklist_latest.txt');
$users = explode("\n", $content);
// 更新到本地内存缓存
apcu_store('blacklist', $users);
// 或写入本地Redis
// $redis->del('local:blacklist');
// $redis->sAddArray('local:blacklist', $users);
}
}
数据库 + 轮询(适合低频率)
共享数据库 + 本地缓存
<?php
class BlacklistDatabaseSync {
// 写入主库
public function batchAdd(array $users) {
DB::table('blacklists')->insert($users);
// 更新同步时间戳
Cache::put('blacklist_last_update', time());
}
// 各节点定时获取增量
public function syncFromDb() {
$lastSync = Cache::get('local_blacklist_sync_time', 0);
$newRecords = DB::table('blacklists')
->where('created_at', '>', date('Y-m-d H:i:s', $lastSync))
->get();
if ($newRecords->isNotEmpty()) {
// 更新本地缓存
foreach ($newRecords as $record) {
Redis::sAdd('local:blacklist', $record->user_id);
}
Cache::put('local_blacklist_sync_time', time());
}
}
}
各方案对比
| 方案 | 延迟 | 复杂度 | 可靠性 | 适合场景 |
|---|---|---|---|---|
| Redis + MQ | <100ms | 中 | 高 | 大型分布式系统 |
| Redis Cluster | <1ms | 低 | 高 | 已有Redis集群 |
| 文件同步 | 1-5s | 低 | 中 | 小规模、非实时 |
| 数据库轮询 | 10-30s | 低 | 高 | 低频率更新 |
最佳实践建议
- 本地缓存+远程同步:各节点保留本地内存+Redis双重缓存
- 增量同步:避免全量同步造成性能问题
- 健康检查:定期验证各节点黑名单一致性
- 降级方案:同步失败时使用本地文件兜底
// 本地缓存 + Redis双写
class BlacklistChecker {
public function isBlocked($userId) {
// 先查本地内存(最快)
if (in_array($userId, $this->localBlacklist)) {
return true;
}
// 再查Redis(次快)
if ($this->redis->sIsMember('global:blacklist', $userId)) {
return true;
}
// 最后查数据库(兜底)
return DB::table('blacklists')->where('user_id', $userId)->exists();
}
}
选择方案时考虑你的系统规模、实时性要求和运维能力,Redis + MQ方案是大多数生产环境的最佳选择。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播