首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 實現 Redis 指定資料庫遷移:支援五大資料型別完整腳本

     編輯:PHP 綜合知識

遷移需求與挑戰

Redis 官方工具(redis-dump、RDB 備份、主從複寫)通常針對整個實例。當只需遷移特定 DB(如 DB 7)且線上服務不能停機時,自訂 PHP 腳本逐鍵遷移最靈活。

完整遷移腳本(支援 String/List/Hash/Set/ZSet)

<?php
/**
 * Redis 指定 DB 遷移工具
 * 用法: php migrate.php source_dsn target_dsn [db_number]
 * 例: php migrate.php 10.0.2.52:6379/7 127.0.0.1:6379/7
 */
declare(strict_types=1);

$fromDsn = $argv[1] ?? '10.0.2.52:6379/7';
$toDsn   = $argv[2] ?? '127.0.0.1:6379/7';

$from = connectRedis($fromDsn);
$to   = connectRedis($toDsn);

$keys = $from->keys('*');
$total = count($keys);
$migrated = 0;
$skipped = 0;
$errors = 0;

echo "開始遷移:$total 把鍵從 $fromDsn → $toDsn\n";

foreach ($keys as $key) {
    $migrated++;
    if ($migrated % 100 === 1) {
        echo "進度: $migrated/$total\n";
    }

    $type = $from->type($key);
    try {
        switch ($type) {
            case Redis::REDIS_STRING:
                $val = $from->get($key);
                $to->set($key, $val);
                break;

            case Redis::REDIS_LIST:
                $list = $from->lRange($key, 0, -1);
                if ($list) {
                    $to->del($key); // 確保目標為空
                    $to->rPush($key, ...$list); // PHP 5.6+ 解包陣列
                }
                break;

            case Redis::REDIS_HASH:
                $hash = $from->hGetAll($key);
                if ($hash) {
                    $to->hMSet($key, $hash);
                }
                break;

            case Redis::REDIS_SET:
                $members = $from->sMembers($key);
                if ($members) {
                    $to->sAdd($key, ...$members);
                }
                break;

            case Redis::REDIS_ZSET:
                $zset = $from->zRange($key, 0, -1, true); // withscores
                if ($zset) {
                    foreach ($zset as $member => $score) {
                        $to->zAdd($key, $score, $member);
                    }
                }
                break;

            default:
                $skipped++;
                echo "跳過不支援型別 [$type]: $key\n";
        }
    } catch (Throwable $e) {
        $errors++;
        echo "遷移失敗 [$key]: " . $e->getMessage() . "\n";
    }
}

echo "\n遷移完成:成功 $migrated,跳過 $skipped,錯誤 $errors\n";

function connectRedis(string $dsn): Redis {
    $redis = new Redis();
    // 解析 host:port/db
    if (!preg_match('/^([^:]+):(\d+)\/(\d+)$/', $dsn, $m)) {
        throw new InvalidArgumentException("DSN 格式錯誤,應為 host:port/db");
    }
    [$_, $host, $port, $db] = $m;
    $redis->connect($host, (int)$port);
    $redis->select((int)$db);
    return $redis;
}

關鍵技術細節

資料型別讀取指令寫入指令注意事項
StringGETSET大值建議用 GETRANGE 分塊讀寫
ListLRANGE 0 -1RPUSH (批次)保持順序,del 先清空目標
HashHGETALLHMSET單指令寫入所有欄位
SetSMEMBERSSADD (批次)無序去重
ZSetZRANGE 0 -1 WITHSCORESZADD (逐個)需保留分數,批次 ZADD 需 Redis 6.2+

生產環境優化建議

  • Scan 替代 Keys:生產環境禁用 KEYS *,改用 SCAN 迭代避免阻塞。
    $it = null;
    while ($keys = $from->scan($it, '*', 1000)) {
        foreach ($keys as $key) { /* 遷移邏輯 */ }
    }
  • Pipeline 批次寫入:減少網路往返。
    $pipe = $to->multi(Redis::PIPELINE);
    foreach ($list as $v) $pipe->rPush($key, $v);
    $pipe->exec();
  • 斷點續傳:記錄已遷移鍵到檔案/資料庫,支援中斷恢復。
  • TTL 保留:遷移前 TTL $key,遷移後 EXPIRE $key $ttl。
  • 驗證一致性:遷移後抽樣比對 TYPE、STRLEN、LLEN、HLEN、SCARD、ZCARD。

進階:支援 Cluster 模式

若源或目標為 Redis Cluster,需使用 phpredis 5.3+ 的 RedisCluster 類別,並注意 KEYS/SCAN 需在每個分片執行,或用 CLUSTER KEYSLOT 計算槽位。

總結

自訂 PHP 遷移腳本提供最大彈性:可過濾鍵前綴、轉換資料結構、保留 TTL、斷點續傳。搭配 SCAN + PIPELINE 可平穩遷移千萬級鍵值,是 Redis 運維工具箱必備技能。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved