KeyDB

Redis互換のマルチスレッドNoSQLデータベース。2019年にRedisからフォークし、マルチスレッド対応で高性能化を実現。

キャッシュサーバーRedis互換マルチスレッドNoSQL高性能

キャッシュサーバー

KeyDB

概要

KeyDBは「Redis互換のマルチスレッドNoSQLデータベース」として開発された、高性能キャッシュサーバーです。2019年にRedisからフォークして誕生し、Redisの最大の制約であったシングルスレッド処理をマルチスレッド対応で解決。Redis互換性を完全に維持しながらマルチスレッド処理による高いパフォーマンス向上を実現し、既存のRedisアプリケーションからシームレスに移行可能な次世代キャッシュソリューションとして注目されています。

詳細

KeyDB 2025年版はRedisマルチスレッド化の先駆者として確固たる地位を維持しています。Snapchat社によって開発・メンテナンスされ、6年以上の実績により安定性と信頼性を証明。Redis 6.0系の機能をベースとしながら、マルチスレッド処理によりCPUコア数に応じた線形性能向上を実現します。特に高並行性ワークロードにおいて従来のRedisを大きく上回る性能を発揮し、Redis互換性により既存のクライアントライブラリ、ツールをそのまま利用可能です。

主な特徴

  • マルチスレッド処理: CPUコア数に応じた線形パフォーマンス向上
  • Redis完全互換: 既存のRedisアプリケーションからシームレス移行
  • アクティブレプリケーション: 高可用性とデータ一貫性確保
  • フラッシュストレージ: メモリ不足時の自動データ移行
  • クラスター対応: 水平スケーリングと分散処理
  • SSL/TLS対応: セキュアな通信とデータ保護

メリット・デメリット

メリット

  • Redis完全互換性による既存システムからの容易な移行
  • マルチスレッド処理によるCPUコア数に応じた性能向上
  • 高並行性ワークロードでの優れたスループット性能
  • 既存のRedisクライアントライブラリ・ツールがそのまま利用可能
  • アクティブレプリケーションによる高可用性実現
  • フラッシュストレージによる大容量データ対応

デメリット

  • Redisのエコシステムと比較して開発・運用情報が限定的
  • 高並行性での制約があり、極端な並行処理では性能上限あり
  • Redisの最新機能追従にタイムラグが発生する場合がある
  • コミュニティサイズがRedisより小さく、サードパーティサポート限定
  • 複雑なワークロードでの予期しない動作リスクがある
  • 企業サポートや長期保守についての不確実性

参考ページ

書き方の例

基本インストールとセットアップ

# Docker を使用したKeyDB起動
docker run -d --name keydb-server -p 6379:6379 eqalpha/keydb

# 設定ファイル付きでの起動
docker run -d --name keydb-server \
  -p 6379:6379 \
  -v /path/to/keydb.conf:/etc/keydb/keydb.conf \
  eqalpha/keydb keydb-server /etc/keydb/keydb.conf

# KeyDBクライアントでの接続確認
docker exec -it keydb-server keydb-cli
127.0.0.1:6379> PING
PONG

# ソースからのビルド
git clone https://github.com/snapchat/keydb.git
cd keydb
make -j4
make install

# KeyDBサーバー起動
keydb-server /etc/keydb/keydb.conf

# KeyDBクライアント接続
keydb-cli -h localhost -p 6379

マルチスレッド設定とパフォーマンス最適化

# keydb.conf での基本マルチスレッド設定
# サーバースレッド数(推奨: CPUコア数の1/2-3/4)
server-threads 4

# スレッドアフィニティの有効化
server-thread-affinity yes

# アクティブクライアントバランシング
active-client-balancing yes

# メモリ使用量制限
maxmemory 2gb
maxmemory-policy allkeys-lru

# 永続化設定
save 900 1
save 300 10
save 60 10000

# RDB圧縮の有効化
rdbcompression yes

# AOF設定
appendonly yes
appendfsync everysec

パフォーマンステストとベンチマーク

# 基本ベンチマーク(Redis-benchmarkツール使用)
redis-benchmark -h localhost -p 6379 -t get,set -n 100000 -c 50

# マルチスレッド性能確認
redis-benchmark -h localhost -p 6379 -t set -n 1000000 -c 100 -d 1024

# 各種操作のベンチマーク
redis-benchmark -h localhost -p 6379 -t ping,set,get,incr,lpush,rpush,lpop,rpop,sadd,hset,spop,lrange,mset -n 100000

# パイプライン性能テスト
redis-benchmark -h localhost -p 6379 -t set,get -n 100000 -P 10

# 並行クライアント数での性能測定
for clients in 10 50 100 200; do
  echo "Testing with $clients clients:"
  redis-benchmark -h localhost -p 6379 -t get,set -n 50000 -c $clients
done

# KeyDB固有の統計情報確認
keydb-cli --stat

アクティブレプリケーションとクラスター構成

# マスターサーバー設定 (keydb-master.conf)
# 基本設定
bind 0.0.0.0
port 6379
server-threads 4

# アクティブレプリケーション有効化
active-replica yes
replica-read-only no

# レプリカサーバー設定 (keydb-replica.conf)
bind 0.0.0.0
port 6380
server-threads 4

# マスターサーバーの指定
replicaof 127.0.0.1 6379
active-replica yes
replica-read-only no

# KeyDBクラスター設定用ノード設定
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000
cluster-announce-ip 192.168.1.100
cluster-announce-port 6379

# マスター・レプリカ起動
keydb-server /path/to/keydb-master.conf
keydb-server /path/to/keydb-replica.conf

# クラスター作成(6ノード構成: 3マスター + 3レプリカ)
keydb-cli --cluster create \
  192.168.1.100:6379 192.168.1.101:6379 192.168.1.102:6379 \
  192.168.1.100:6380 192.168.1.101:6380 192.168.1.102:6380 \
  --cluster-replicas 1

# クラスター状態確認
keydb-cli -c -h 192.168.1.100 -p 6379 cluster nodes
keydb-cli -c -h 192.168.1.100 -p 6379 cluster info

プログラミング言語での利用例

# Python (redis-py ライブラリ利用)
import redis
import time
from concurrent.futures import ThreadPoolExecutor

# KeyDB接続設定
r = redis.Redis(
    host='localhost',
    port=6379,
    decode_responses=True,
    socket_keepalive=True,
    socket_keepalive_options={},
    health_check_interval=30
)

# 接続確認
print(r.ping())  # True

# 基本操作
r.set('key1', 'value1')
r.set('key2', 'value2', ex=60)  # 60秒でexpire
print(r.get('key1'))  # value1

# Hash操作
r.hset('user:1001', mapping={
    'name': '田中太郎',
    'email': '[email protected]',
    'age': 30
})
user_data = r.hgetall('user:1001')
print(user_data)

# List操作
r.lpush('tasks', 'task1', 'task2', 'task3')
task = r.rpop('tasks')
print(f"Processing: {task}")

# Set操作
r.sadd('online_users', 'user1', 'user2', 'user3')
online_users = r.smembers('online_users')
print(f"Online users: {online_users}")

# Sorted Set操作
r.zadd('leaderboard', {'player1': 1000, 'player2': 1500, 'player3': 800})
top_players = r.zrevrange('leaderboard', 0, 2, withscores=True)
print(f"Top players: {top_players}")

# パフォーマンステスト(マルチスレッド活用)
def stress_test_worker(worker_id, operations=1000):
    local_r = redis.Redis(host='localhost', port=6379, decode_responses=True)
    start_time = time.time()
    
    for i in range(operations):
        key = f"test:{worker_id}:{i}"
        value = f"value_{worker_id}_{i}"
        local_r.set(key, value)
        retrieved = local_r.get(key)
        assert retrieved == value
    
    end_time = time.time()
    print(f"Worker {worker_id}: {operations} ops in {end_time - start_time:.2f}s")

# 10スレッドでの並行処理テスト
with ThreadPoolExecutor(max_workers=10) as executor:
    futures = []
    for worker_id in range(10):
        future = executor.submit(stress_test_worker, worker_id, 1000)
        futures.append(future)
    
    # 全スレッド完了待機
    for future in futures:
        future.result()

# パイプライン利用
pipe = r.pipeline()
for i in range(1000):
    pipe.set(f"pipeline:key{i}", f"value{i}")
pipe.execute()

# Pub/Sub(メッセージング)
import threading

def message_handler():
    pubsub = r.pubsub()
    pubsub.subscribe('notifications')
    
    for message in pubsub.listen():
        if message['type'] == 'message':
            print(f"Received: {message['data']}")

# メッセージ受信用スレッド開始
handler_thread = threading.Thread(target=message_handler)
handler_thread.daemon = True
handler_thread.start()

# メッセージ送信
r.publish('notifications', 'Hello from KeyDB!')
time.sleep(1)

Node.js での利用例

// Node.js (ioredis ライブラリ利用)
const Redis = require('ioredis');

// KeyDB接続設定
const keydb = new Redis({
  host: 'localhost',
  port: 6379,
  maxRetriesPerRequest: 3,
  retryDelayOnFailover: 100,
  enableOfflineQueue: false,
  lazyConnect: true
});

// 接続確認
async function testConnection() {
  try {
    const result = await keydb.ping();
    console.log('Connection successful:', result);
  } catch (error) {
    console.error('Connection failed:', error);
  }
}

// 基本的なCRUD操作
async function basicOperations() {
  // String操作
  await keydb.set('user:session:12345', JSON.stringify({
    userId: 12345,
    loginTime: new Date().toISOString(),
    permissions: ['read', 'write']
  }), 'EX', 3600); // 1時間でexpire

  const sessionData = await keydb.get('user:session:12345');
  console.log('Session:', JSON.parse(sessionData));

  // Hash操作
  await keydb.hmset('product:1001', {
    name: 'KeyDB Server',
    price: 0,
    category: 'database',
    inStock: true
  });

  const product = await keydb.hgetall('product:1001');
  console.log('Product:', product);

  // List操作(キュー)
  await keydb.lpush('job_queue', 
    JSON.stringify({ id: 1, type: 'email', data: '[email protected]' }),
    JSON.stringify({ id: 2, type: 'sms', data: '+1234567890' })
  );

  const job = await keydb.brpop('job_queue', 10); // 10秒でタイムアウト
  if (job) {
    console.log('Processing job:', JSON.parse(job[1]));
  }
}

// パフォーマンス測定
async function performanceTest() {
  const operations = 10000;
  const batchSize = 100;
  
  console.log(`Starting performance test: ${operations} operations`);
  const startTime = Date.now();

  // パイプライン処理でバッチ実行
  for (let i = 0; i < operations; i += batchSize) {
    const pipeline = keydb.pipeline();
    
    for (let j = 0; j < batchSize && (i + j) < operations; j++) {
      const key = `perf:test:${i + j}`;
      const value = `value_${i + j}_${Date.now()}`;
      pipeline.set(key, value);
    }
    
    await pipeline.exec();
  }

  const endTime = Date.now();
  const duration = endTime - startTime;
  const opsPerSec = Math.round(operations / (duration / 1000));
  
  console.log(`Completed ${operations} operations in ${duration}ms`);
  console.log(`Performance: ${opsPerSec} ops/sec`);
}

// Pub/Sub メッセージング
async function setupMessaging() {
  const subscriber = new Redis({
    host: 'localhost',
    port: 6379
  });

  const publisher = new Redis({
    host: 'localhost',
    port: 6379
  });

  // メッセージ受信設定
  subscriber.subscribe('user_events', 'system_alerts');

  subscriber.on('message', (channel, message) => {
    console.log(`[${channel}] ${message}`);
    
    // メッセージタイプ別処理
    if (channel === 'user_events') {
      const event = JSON.parse(message);
      console.log(`User ${event.userId} performed ${event.action}`);
    } else if (channel === 'system_alerts') {
      console.log(`System Alert: ${message}`);
    }
  });

  // メッセージ送信例
  setInterval(async () => {
    await publisher.publish('user_events', JSON.stringify({
      userId: Math.floor(Math.random() * 1000),
      action: 'login',
      timestamp: new Date().toISOString()
    }));
  }, 5000);

  // システムアラート送信
  await publisher.publish('system_alerts', 'KeyDB performance test completed');
}

// 実行
async function main() {
  await testConnection();
  await basicOperations();
  await performanceTest();
  await setupMessaging();
}

main().catch(console.error);

監視とメンテナンス

# KeyDB統計情報の確認
keydb-cli info all

# メモリ使用状況
keydb-cli info memory

# レプリケーション状況
keydb-cli info replication

# クラスター情報
keydb-cli cluster info
keydb-cli cluster nodes

# リアルタイム監視
keydb-cli --stat

# スローログ確認
keydb-cli slowlog get 10

# 接続中のクライアント確認
keydb-cli client list

# 設定の動的変更
keydb-cli config set maxmemory 4gb
keydb-cli config set save "900 1 300 10 60 10000"

# バックアップ作成
keydb-cli bgsave

# データベースサイズ確認
keydb-cli dbsize

# 全データベースのフラッシュ(注意)
keydb-cli flushall

# 特定データベースのフラッシュ
keydb-cli -n 1 flushdb

# パフォーマンス診断
keydb-cli --latency-history -i 1
keydb-cli --latency-dist

# メモリ使用量分析
keydb-cli --memkeys
keydb-cli --bigkeys