PhpRedis

キャッシュライブラリPHPRedis拡張モジュール高性能分散キャッシュ

GitHub概要

phpredis/phpredis

A PHP extension for Redis

スター10,157
ウォッチ451
フォーク2,150
作成日:2011年3月15日
言語:C
ライセンス:Other

トピックス

clusterkeydbphpredisredis-clustervalkey

スター履歴

phpredis/phpredis Star History
データ取得日時: 2025/10/22 08:07

キャッシュライブラリ

PhpRedis

概要

PhpRedisは、PHP用のRedis拡張モジュールです。C言語で実装されたネイティブ拡張として、Redisサーバーとの高性能な通信を提供します。単一のRedisインスタンスから、RedisCluster、RedisSentinelを使った高可用性構成まで幅広くサポートし、キャッシュ、セッション管理、リアルタイムデータ処理に活用されます。

詳細

PhpRedisは、Redisの豊富な機能をPHPから効率的に利用するためのC拡張です。Pure PHPライブラリ(Predis等)と比較して大幅な性能向上を実現し、プロダクション環境での大規模運用に最適化されています。

主要な技術的特徴:

  • ネイティブC実装: PHP Pure実装比で大幅な性能向上
  • フル機能対応: Redis 7.x の最新機能まで包括的サポート
  • クラスター対応: RedisClusterによる水平スケーリング
  • 高可用性: RedisSentinelによる自動フェイルオーバー
  • 配列サポート: RedisArrayによる自動シャーディング
  • セッション統合: PHPセッションハンドラーとしての利用

技術アーキテクチャ:

  • 接続管理: 永続化接続、接続プール、タイムアウト制御
  • シリアライゼーション: PHP、igbinary、msgpack対応
  • 圧縮: LZF、ZSTD、LZ4による帯域幅削減
  • SSL/TLS: 暗号化通信のサポート

メリット・デメリット

メリット

  • 最高性能: C拡張による最適化されたRedis通信
  • 完全機能: Redis全機能への包括的アクセス
  • 本格運用対応: クラスター、センチネル、配列機能
  • セッション統合: PHPセッションストレージとしての利用
  • 豊富な設定: 接続、シリアライゼーション、圧縮オプション
  • 実績: 多くの大規模Webサービスでの実績
  • アクティブ開発: 継続的なアップデートと最新Redis対応

デメリット

  • インストール要件: C拡張のコンパイル・インストール必要
  • 環境依存: サーバー環境でのモジュール有効化が必要
  • Redis必須: Redisサーバーへの依存
  • 学習コスト: Redis知識と設定ノウハウが必要
  • デバッグ難易度: C拡張レベルの問題は調査困難
  • バージョン管理: PHP・Redis・PhpRedisの3層バージョン管理

参考ページ

書き方の例

基本的なRedis接続と操作

<?php
// Redis接続
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

// 認証が必要な場合
// $redis->auth('your_password');

// 基本的なキー・バリュー操作
$redis->set('user:1000', 'John Doe');
$redis->expire('user:1000', 3600); // 1時間で期限切れ

$username = $redis->get('user:1000');
echo "ユーザー名: " . $username . "\n";

// 複数キーの一括操作
$redis->mset([
    'product:1' => 'Laptop',
    'product:2' => 'Mouse',
    'product:3' => 'Keyboard'
]);

$products = $redis->mget(['product:1', 'product:2', 'product:3']);
print_r($products);

// リストデータ構造
$redis->lpush('notifications', 'New message from admin');
$redis->lpush('notifications', 'Your order has been shipped');

$notifications = $redis->lrange('notifications', 0, -1);
print_r($notifications);
?>

PHPセッションストレージとしての利用

<?php
// セッション設定(php.ini または実行時設定)
ini_set('session.save_handler', 'redis');
ini_set('session.save_path', 'tcp://127.0.0.1:6379?auth=password&database=1');

// セッション開始
session_start();

// 通常のセッション操作
$_SESSION['user_id'] = 12345;
$_SESSION['username'] = 'john_doe';
$_SESSION['last_login'] = time();

// セッションデータの表示
echo "ユーザーID: " . $_SESSION['user_id'] . "\n";
echo "ユーザー名: " . $_SESSION['username'] . "\n";

// セッション破棄
// session_destroy();
?>

RedisClusterの利用

<?php
// RedisCluster接続
$cluster = new RedisCluster(null, [
    'host1:7000',
    'host2:7001', 
    'host3:7002'
], 1.5, 1.5, true, 'cluster_password');

// クラスター情報確認
$masters = $cluster->_masters();
echo "マスターノード数: " . count($masters) . "\n";

// データ分散保存
for ($i = 0; $i < 100; $i++) {
    $cluster->set("key:$i", "value:$i");
}

// ハッシュタグによる同一ノード配置
$cluster->set('{user:1000}:profile', json_encode(['name' => 'John', 'age' => 30]));
$cluster->set('{user:1000}:settings', json_encode(['theme' => 'dark']));

// トランザクション(同一ノード内)
$cluster->multi();
$cluster->set('{transaction}:key1', 'value1');
$cluster->set('{transaction}:key2', 'value2');
$result = $cluster->exec();

print_r($result);
?>

RedisSentinelによる高可用性

<?php
// Sentinel接続
$sentinel = new RedisSentinel([
    'host' => '127.0.0.1',
    'port' => 26379,
    'connectTimeout' => 2.5,
    'auth' => 'sentinel_password'
]);

// マスター情報取得
$masters = $sentinel->masters();
foreach ($masters as $master) {
    echo "マスター名: " . $master['name'] . "\n";
    echo "IPアドレス: " . $master['ip'] . ":" . $master['port'] . "\n";
    echo "状態: " . $master['flags'] . "\n";
}

// 現在のマスターアドレス取得
$masterAddr = $sentinel->getMasterAddrByName('mymaster');
if ($masterAddr) {
    $redis = new Redis();
    $redis->connect($masterAddr[0], $masterAddr[1]);
    
    // マスターへの書き込み
    $redis->set('counter', 1);
    echo "マスターに書き込み完了\n";
}

// スレーブ情報取得
$slaves = $sentinel->slaves('mymaster');
echo "スレーブ数: " . count($slaves) . "\n";
?>

RedisArrayによる自動シャーディング

<?php
// HashRing設定(redis.ini)
/*
redis.arrays.names = "user_cache"
redis.arrays.hosts = "user_cache[]=host1:6379&user_cache[]=host2:6379&user_cache[]=host3:6379"
redis.arrays.functions = "user_cache=user_hash_function"
redis.arrays.index = "user_cache=1"
redis.arrays.auth = "user_cache=password"
*/

// カスタムハッシュ関数
function user_hash_function($key) {
    // ユーザーIDに基づくハッシュ
    if (preg_match('/user:(\d+)/', $key, $matches)) {
        return $matches[1]; // ユーザーIDでシャーディング
    }
    return $key;
}

// RedisArray利用
$redisArray = new RedisArray(['host1:6379', 'host2:6379', 'host3:6379'], [
    'function' => 'user_hash_function',
    'consistent' => true, // 一貫性ハッシュ
    'algorithm' => 'crc32'
]);

// データ分散保存
$redisArray->set('user:1000:profile', json_encode(['name' => 'Alice']));
$redisArray->set('user:2000:profile', json_encode(['name' => 'Bob']));
$redisArray->set('user:3000:profile', json_encode(['name' => 'Charlie']));

// どのノードに配置されたかを確認
$target = $redisArray->_target('user:1000:profile');
echo "user:1000のデータ配置先: " . $target . "\n";

// 同一ユーザーのデータを同じノードに配置
$host = $redisArray->_target('user:1000:profile');
$redisArray->multi($host)
          ->set('user:1000:settings', json_encode(['theme' => 'light']))
          ->sadd('user:1000:friends', '2000', '3000')
          ->exec();
?>

高度なデータ構造とパフォーマンス最適化

<?php
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

// パイプライン処理による高速化
$pipe = $redis->multi(Redis::PIPELINE);
for ($i = 0; $i < 1000; $i++) {
    $pipe->set("batch:$i", "value:$i");
    $pipe->expire("batch:$i", 3600);
}
$results = $pipe->exec();
echo "パイプライン実行結果: " . count($results) . "件処理\n";

// Lua スクリプト実行
$luaScript = '
    local key = KEYS[1]
    local increment = ARGV[1]
    local current = redis.call("GET", key)
    if current == false then
        current = 0
    end
    local new_value = current + increment
    redis.call("SET", key, new_value)
    return new_value
';

$result = $redis->eval($luaScript, ['counter:atomic', '5'], 1);
echo "アトミックカウンター結果: " . $result . "\n";

// ハッシュデータ構造
$redis->hset('user:profile:1000', 'name', 'John Doe');
$redis->hset('user:profile:1000', 'email', '[email protected]');
$redis->hset('user:profile:1000', 'age', 30);

$profile = $redis->hgetall('user:profile:1000');
print_r($profile);

// ソート済みセット(ランキング)
$redis->zadd('leaderboard', 1500, 'player1');
$redis->zadd('leaderboard', 2000, 'player2');
$redis->zadd('leaderboard', 1800, 'player3');

// 上位ランキング取得
$topPlayers = $redis->zrevrange('leaderboard', 0, 2, true);
foreach ($topPlayers as $player => $score) {
    echo "プレイヤー: $player, スコア: $score\n";
}
?>

設定とモニタリング

<?php
$redis = new Redis();

// 接続設定
$redis->connect('127.0.0.1', 6379, 2.5); // 2.5秒タイムアウト

// または永続化接続
// $redis->pconnect('127.0.0.1', 6379, 2.5, 'persistent_id');

// オプション設定
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_JSON);
$redis->setOption(Redis::OPT_COMPRESSION, Redis::COMPRESSION_LZ4);

// サーバー情報取得
$info = $redis->info();
echo "Redis バージョン: " . $info['redis_version'] . "\n";
echo "使用メモリ: " . $info['used_memory_human'] . "\n";
echo "接続クライアント数: " . $info['connected_clients'] . "\n";

// 統計情報
$stats = $redis->info('stats');
echo "総接続数: " . $stats['total_connections_received'] . "\n";
echo "総コマンド数: " . $stats['total_commands_processed'] . "\n";

// スロー クエリ確認
$slowlog = $redis->slowlog('get', 10);
foreach ($slowlog as $entry) {
    echo "スロークエリ: " . implode(' ', $entry[3]) . " (実行時間: " . $entry[2] . "μs)\n";
}

// 設定確認・変更
$maxMemory = $redis->config('get', 'maxmemory');
echo "最大メモリ設定: " . $maxMemory['maxmemory'] . "\n";

// 実行時設定変更
// $redis->config('set', 'maxmemory', '1gb');
?>