{"slug":"cache-redis","title":"Redis Managed Cache","description":"Redis is an open-source, in-memory data structure store used as a database, cache, and message broker. DanubeData offers fully managed Redis instances with automatic failover, persistence, and easy sc...","section":"Features","url":"https://docs.danubedata.ro/cache-redis","markdown_url":"https://docs.danubedata.ro/cache-redis.md","breadcrumbs":[{"title":"Features","slug":null},{"title":"Cache","slug":"cache-overview"},{"title":"Redis","slug":"cache-redis"}],"headings":[{"level":1,"title":"Redis Managed Cache","id":"redis-managed-cache"},{"level":2,"title":"Overview","id":"overview"},{"level":2,"title":"Supported Redis Versions","id":"supported-redis-versions"},{"level":2,"title":"Creating a Redis Instance","id":"creating-a-redis-instance"},{"level":3,"title":"Via Dashboard","id":"via-dashboard"},{"level":3,"title":"Resource Profiles","id":"resource-profiles"},{"level":2,"title":"Connecting to Redis","id":"connecting-to-redis"},{"level":3,"title":"Connection Details","id":"connection-details"},{"level":3,"title":"Redis CLI","id":"redis-cli"},{"level":3,"title":"Connection from Application","id":"connection-from-application"},{"level":4,"title":"PHP (Predis)","id":"php-predis"},{"level":4,"title":"Python (redis-py)","id":"python-redis-py"},{"level":4,"title":"Node.js (ioredis)","id":"nodejs-ioredis"},{"level":4,"title":"Laravel","id":"laravel"},{"level":2,"title":"Redis Data Structures","id":"redis-data-structures"},{"level":3,"title":"Strings","id":"strings"},{"level":3,"title":"Hashes","id":"hashes"},{"level":3,"title":"Lists","id":"lists"},{"level":3,"title":"Sets","id":"sets"},{"level":3,"title":"Sorted Sets","id":"sorted-sets"},{"level":2,"title":"Common Use Cases","id":"common-use-cases"},{"level":3,"title":"Session Storage","id":"session-storage"},{"level":3,"title":"Caching","id":"caching"},{"level":3,"title":"Rate Limiting","id":"rate-limiting"},{"level":3,"title":"Leaderboard","id":"leaderboard"},{"level":3,"title":"Distributed Locking","id":"distributed-locking"},{"level":3,"title":"Pub/Sub Messaging","id":"pubsub-messaging"},{"level":2,"title":"Performance Optimization","id":"performance-optimization"},{"level":3,"title":"Pipelining","id":"pipelining"},{"level":3,"title":"Connection Pooling","id":"connection-pooling"},{"level":3,"title":"Key Naming","id":"key-naming"},{"level":3,"title":"Expiration","id":"expiration"},{"level":2,"title":"Upgrading Your Redis Version","id":"upgrading-your-redis-version"},{"level":2,"title":"Migrating a Standalone Instance","id":"migrating-a-standalone-instance"},{"level":2,"title":"Persistence","id":"persistence"},{"level":3,"title":"Persistence Options","id":"persistence-options"},{"level":4,"title":"RDB (Point-in-time Snapshots)","id":"rdb-point-in-time-snapshots"},{"level":4,"title":"AOF (Append-Only File)","id":"aof-append-only-file"},{"level":4,"title":"Both (Recommended)","id":"both-recommended"},{"level":3,"title":"Configuring Persistence","id":"configuring-persistence"},{"level":2,"title":"Eviction Policies","id":"eviction-policies"},{"level":3,"title":"Available Policies","id":"available-policies"},{"level":3,"title":"Choosing Eviction Policy","id":"choosing-eviction-policy"},{"level":3,"title":"Setting Eviction Policy","id":"setting-eviction-policy"},{"level":2,"title":"Monitoring and Maintenance","id":"monitoring-and-maintenance"},{"level":3,"title":"Key Metrics","id":"key-metrics"},{"level":3,"title":"Redis Commands for Monitoring","id":"redis-commands-for-monitoring"},{"level":2,"title":"Best Practices","id":"best-practices"},{"level":3,"title":"Key Management","id":"key-management"},{"level":3,"title":"Performance","id":"performance"},{"level":3,"title":"Security","id":"security"},{"level":3,"title":"High Availability","id":"high-availability"},{"level":2,"title":"Troubleshooting","id":"troubleshooting"},{"level":3,"title":"High Memory Usage","id":"high-memory-usage"},{"level":3,"title":"Low Hit Rate","id":"low-hit-rate"},{"level":3,"title":"Connection Errors","id":"connection-errors"},{"level":3,"title":"Slow Performance","id":"slow-performance"},{"level":2,"title":"Related Documentation","id":"related-documentation"}],"format":"markdown","word_count":361,"content":"# Redis Managed Cache\n\nRedis is an open-source, in-memory data structure store used as a database, cache, and message broker. DanubeData offers fully managed Redis instances with automatic failover, persistence, and easy scaling.\n\n## Overview\n\nRedis provides:\n\n- **High Performance**: Sub-millisecond response times\n- **Versatile Data Structures**: Strings, hashes, lists, sets, sorted sets, and more\n- **Persistence**: Optional data persistence to disk\n- **Replication**: Master-replica architecture for high availability\n- **Pub/Sub**: Real-time messaging capabilities\n- **Lua Scripting**: Server-side scripting support\n\n## Supported Redis Versions\n\nDanubeData supports the following Redis versions:\n\n- **Redis 8.4** (Latest Stable - Recommended)\n- **Redis 8.0**\n- **Redis 7.4**\n- **Redis 7.2** (LTS)\n\n> **Recommendation**: Use Redis 8.4 for new instances to get the latest features (vector sets, I/O threading) and performance improvements.\n\n**Redis 8.0 and later** bundle vector sets, native JSON, time series, and bloom-filter data types directly in the core engine — no module installation required — and ship with I/O threading enabled for higher throughput on multi-core profiles.\n\nParameter groups are **version-scoped**: a system parameter group built for one major version cannot be attached to an instance on a different major version, and the create form filters the dropdown to compatible groups automatically. Your own custom parameter groups remain compatible across versions.\n\n## Creating a Redis Instance\n\n### Via Dashboard\n\n1. Navigate to **Cache** in the main menu\n2. Click **Create Cache Instance**\n3. Select **Redis** as the engine\n4. Choose Redis version\n5. Select a resource profile (see below)\n6. Choose a data center location\n7. Configure optional settings:\n   - Instance name\n   - Enable replicas for high availability\n   - Persistence settings (AOF, RDB, or both)\n   - Eviction policy\n8. Click **Create Instance**\n\nYour Redis instance will be provisioned within 2-3 minutes.\n\n### Resource Profiles\n\nRedis instances are available in multiple memory-optimized profiles:\n\n| Profile | Memory | Price/Month |\n|---------|--------|-------------|\n| **Micro** | 256 MB | €4.99 |\n| **Small** | 1 GB | €9.99 |\n| **Medium** | 3 GB | €19.99 |\n| **Large** | 6 GB | €39.99 |\n\nAll profiles include:\n- NVMe SSD for persistence\n- Automatic failover with replicas\n- Hourly billing with monthly cap\n- TLS/SSL encryption\n\n## Connecting to Redis\n\n### Connection Details\n\nAfter creation, you'll receive connection details:\n\n```\nHost: redis-123456.danubedata.ro\nPort: 6379\nPassword: [secure_password]\nTLS: Required\n```\n\n### Redis CLI\n\nConnect using `redis-cli`:\n\n```bash\nredis-cli -h redis-123456.danubedata.ro -p 6379 -a your_password --tls\n```\n\n### Connection from Application\n\n#### PHP (Predis)\n\n```php\n<?php\nrequire 'vendor/autoload.php';\n\nuse Predis\\Client;\n\n$client = new Client([\n    'scheme' => 'tls',\n    'host'   => 'redis-123456.danubedata.ro',\n    'port'   => 6379,\n    'password' => 'your_password',\n]);\n\n// Set a value\n$client->set('user:1000', 'John Doe');\n\n// Get a value\n$name = $client->get('user:1000');\n\n// Set with expiration\n$client->setex('session:abc123', 3600, json_encode(['user_id' => 1000]));\n```\n\n#### Python (redis-py)\n\n```python\nimport redis\nimport ssl\n\nr = redis.Redis(\n    host='redis-123456.danubedata.ro',\n    port=6379,\n    password='your_password',\n    ssl=True,\n    ssl_cert_reqs=ssl.CERT_REQUIRED,\n    decode_responses=True\n)\n\n# Set a value\nr.set('user:1000', 'John Doe')\n\n# Get a value\nname = r.get('user:1000')\n\n# Set with expiration\nr.setex('session:abc123', 3600, '{\"user_id\": 1000}')\n\n# Hash operations\nr.hset('user:1000:profile', mapping={'name': 'John', 'age': 30})\nr.hget('user:1000:profile', 'name')\n```\n\n#### Node.js (ioredis)\n\n```javascript\nconst Redis = require('ioredis');\n\nconst redis = new Redis({\n  host: 'redis-123456.danubedata.ro',\n  port: 6379,\n  password: 'your_password',\n  tls: {\n    rejectUnauthorized: true\n  }\n});\n\n// Set a value\nawait redis.set('user:1000', 'John Doe');\n\n// Get a value\nconst name = await redis.get('user:1000');\n\n// Set with expiration\nawait redis.setex('session:abc123', 3600, JSON.stringify({user_id: 1000}));\n\n// Hash operations\nawait redis.hmset('user:1000:profile', 'name', 'John', 'age', 30);\nconst userName = await redis.hget('user:1000:profile', 'name');\n```\n\n#### Laravel\n\n```php\n// config/database.php\n'redis' => [\n    'client' => env('REDIS_CLIENT', 'phpredis'),\n    \n    'default' => [\n        'url' => env('REDIS_URL'),\n        'host' => env('REDIS_HOST', 'redis-123456.danubedata.ro'),\n        'password' => env('REDIS_PASSWORD'),\n        'port' => env('REDIS_PORT', '6379'),\n        'database' => env('REDIS_DB', '0'),\n        'scheme' => 'tls',\n    ],\n],\n\n// Usage in application\nuse Illuminate\\Support\\Facades\\Redis;\n\n// Set a value\nRedis::set('user:1000', 'John Doe');\n\n// Get a value\n$name = Redis::get('user:1000');\n\n// Cache usage\nCache::store('redis')->put('key', 'value', $seconds);\n```\n\n## Redis Data Structures\n\n### Strings\n\nBasic key-value storage:\n\n```bash\n# Set and get\nSET user:1000:name \"John Doe\"\nGET user:1000:name\n\n# Increment counter\nSET views:homepage 0\nINCR views:homepage\nINCRBY views:homepage 10\n\n# Set with expiration\nSETEX session:abc123 3600 \"user_data\"\n\n# Set if not exists\nSETNX lock:resource:1 \"locked\"\n```\n\n### Hashes\n\nStore objects as field-value pairs:\n\n```bash\n# Set hash fields\nHSET user:1000 name \"John Doe\" email \"john@example.com\" age 30\n\n# Get single field\nHGET user:1000 name\n\n# Get all fields\nHGETALL user:1000\n\n# Get multiple fields\nHMGET user:1000 name email\n\n# Increment field\nHINCRBY user:1000 age 1\n```\n\n### Lists\n\nOrdered collections:\n\n```bash\n# Add to list\nLPUSH notifications:user:1000 \"New message\"\nRPUSH queue:emails \"email1@example.com\"\n\n# Get from list\nLPOP notifications:user:1000\nRPOP queue:emails\n\n# Get range\nLRANGE queue:emails 0 10\n\n# List length\nLLEN queue:emails\n\n# Blocking pop (for queues)\nBLPOP queue:emails 0\n```\n\n### Sets\n\nUnordered collections of unique elements:\n\n```bash\n# Add to set\nSADD tags:article:100 \"redis\" \"caching\" \"performance\"\n\n# Check membership\nSISMEMBER tags:article:100 \"redis\"\n\n# Get all members\nSMEMBERS tags:article:100\n\n# Set operations\nSINTER tags:article:100 tags:article:101  # Intersection\nSUNION tags:article:100 tags:article:101  # Union\nSDIFF tags:article:100 tags:article:101   # Difference\n```\n\n### Sorted Sets\n\nOrdered sets with scores:\n\n```bash\n# Add members with scores\nZADD leaderboard 1000 \"player1\" 950 \"player2\" 1200 \"player3\"\n\n# Get by rank\nZRANGE leaderboard 0 10 WITHSCORES\n\n# Get by score\nZRANGEBYSCORE leaderboard 1000 2000\n\n# Get rank\nZRANK leaderboard \"player1\"\n\n# Increment score\nZINCRBY leaderboard 50 \"player1\"\n```\n\n## Common Use Cases\n\n### Session Storage\n\n```python\nimport redis\nimport json\n\nr = redis.Redis(host='redis-123456.danubedata.ro', ...)\n\ndef create_session(session_id, user_data, ttl=3600):\n    \"\"\"Create a user session with TTL\"\"\"\n    r.setex(f'session:{session_id}', ttl, json.dumps(user_data))\n\ndef get_session(session_id):\n    \"\"\"Retrieve session data\"\"\"\n    data = r.get(f'session:{session_id}')\n    return json.loads(data) if data else None\n\ndef update_session(session_id, updates):\n    \"\"\"Update session and refresh TTL\"\"\"\n    data = get_session(session_id)\n    if data:\n        data.update(updates)\n        create_session(session_id, data)\n```\n\n### Caching\n\n```php\nfunction get_user($user_id) {\n    // Try cache first\n    $cached = Redis::get(\"user:{$user_id}\");\n    if ($cached) {\n        return json_decode($cached, true);\n    }\n    \n    // Cache miss - fetch from database\n    $user = User::find($user_id);\n    \n    // Store in cache for 1 hour\n    Redis::setex(\"user:{$user_id}\", 3600, json_encode($user));\n    \n    return $user;\n}\n\nfunction invalidate_user_cache($user_id) {\n    Redis::del(\"user:{$user_id}\");\n}\n```\n\n### Rate Limiting\n\n```python\ndef is_rate_limited(user_id, limit=100, window=60):\n    \"\"\"Check if user exceeded rate limit\n    \n    Args:\n        user_id: User identifier\n        limit: Max requests per window\n        window: Time window in seconds\n    \n    Returns:\n        bool: True if rate limited\n    \"\"\"\n    key = f'rate_limit:{user_id}'\n    current = r.incr(key)\n    \n    if current == 1:\n        r.expire(key, window)\n    \n    return current > limit\n```\n\n### Leaderboard\n\n```javascript\nclass Leaderboard {\n  constructor(redis, name) {\n    this.redis = redis;\n    this.key = `leaderboard:${name}`;\n  }\n  \n  async addScore(player, score) {\n    await this.redis.zadd(this.key, score, player);\n  }\n  \n  async getTop(n = 10) {\n    return await this.redis.zrevrange(this.key, 0, n-1, 'WITHSCORES');\n  }\n  \n  async getRank(player) {\n    return await this.redis.zrevrank(this.key, player);\n  }\n  \n  async getScore(player) {\n    return await this.redis.zscore(this.key, player);\n  }\n}\n```\n\n### Distributed Locking\n\n```python\ndef acquire_lock(resource_id, timeout=10):\n    \"\"\"Acquire distributed lock\"\"\"\n    lock_key = f'lock:{resource_id}'\n    lock_value = str(uuid.uuid4())\n    \n    # Try to acquire lock\n    acquired = r.set(lock_key, lock_value, nx=True, ex=timeout)\n    \n    return lock_value if acquired else None\n\ndef release_lock(resource_id, lock_value):\n    \"\"\"Release distributed lock\"\"\"\n    lock_key = f'lock:{resource_id}'\n    \n    # Lua script for atomic check-and-delete\n    lua_script = \"\"\"\n    if redis.call(\"get\", KEYS[1]) == ARGV[1] then\n        return redis.call(\"del\", KEYS[1])\n    else\n        return 0\n    end\n    \"\"\"\n    \n    return r.eval(lua_script, 1, lock_key, lock_value)\n```\n\n### Pub/Sub Messaging\n\n```python\n# Publisher\ndef publish_message(channel, message):\n    r.publish(channel, json.dumps(message))\n\n# Subscriber\ndef subscribe_to_channel(channel):\n    pubsub = r.pubsub()\n    pubsub.subscribe(channel)\n    \n    for message in pubsub.listen():\n        if message['type'] == 'message':\n            data = json.loads(message['data'])\n            process_message(data)\n```\n\n## Performance Optimization\n\n### Pipelining\n\nBatch multiple commands for better performance:\n\n```python\n# Without pipelining (3 round trips)\nr.set('key1', 'value1')\nr.set('key2', 'value2')\nr.set('key3', 'value3')\n\n# With pipelining (1 round trip)\npipe = r.pipeline()\npipe.set('key1', 'value1')\npipe.set('key2', 'value2')\npipe.set('key3', 'value3')\npipe.execute()\n```\n\n### Connection Pooling\n\nReuse connections efficiently:\n\n```python\nimport redis\n\npool = redis.ConnectionPool(\n    host='redis-123456.danubedata.ro',\n    port=6379,\n    password='your_password',\n    max_connections=50,\n    ssl=True\n)\n\n# Use pool for all connections\nr = redis.Redis(connection_pool=pool)\n```\n\n### Key Naming\n\nUse consistent, hierarchical key naming:\n\n```\nuser:1000:profile\nuser:1000:sessions\nuser:1000:cart\narticle:500:views\narticle:500:comments\ncache:homepage:en\ncache:homepage:es\n```\n\n### Expiration\n\nAlways set expiration on temporary data:\n\n```python\n# Absolute expiration\nr.setex('temp:data', 3600, 'value')  # Expires in 1 hour\n\n# Set expiration on existing key\nr.expire('existing:key', 7200)  # Expires in 2 hours\n\n# Check time to live\nttl = r.ttl('existing:key')\n```\n\n## Upgrading Your Redis Version\n\nYou can move an existing instance to a newer Redis version without recreating it:\n\n1. Open the **Updates** tab on your Redis instance\n2. Choose from the available target versions and start the upgrade with one click\n3. A snapshot is taken automatically before the upgrade, so you can roll back if needed\n4. Progress is shown live on the instance page; the instance shows an **Updating** status while it runs\n\nThe same self-serve upgrade flow is available for Valkey and Dragonfly instances.\n\n## Migrating a Standalone Instance\n\nNew Redis instances run on our managed-operator backend by default. If you have an older standalone (non-replicated) Redis instance, open its actions menu and choose **Migrate to managed operator** to move it across yourself. A pre-migration snapshot is taken, your password and data carry over unchanged, and a short downtime window applies during cutover. Afterwards you get a grace period to confirm everything is healthy or roll back.\n\n## Persistence\n\n### Persistence Options\n\nDanubeData Redis offers two persistence methods:\n\n#### RDB (Point-in-time Snapshots)\n\n- **How it works**: Periodic snapshots of dataset\n- **Pros**: Compact, fast restart, good for backups\n- **Cons**: Potential data loss between snapshots\n- **Use case**: Can tolerate some data loss\n\n#### AOF (Append-Only File)\n\n- **How it works**: Logs every write operation\n- **Pros**: More durable, minimal data loss\n- **Cons**: Larger files, slower restart\n- **Use case**: Need maximum durability\n\n#### Both (Recommended)\n\n- Use RDB for backups and fast restarts\n- Use AOF for durability\n- Best of both worlds\n\n### Configuring Persistence\n\n1. Navigate to your Redis instance\n2. Click **Settings** > **Persistence**\n3. Select persistence method:\n   - None (cache-only, no persistence)\n   - RDB only\n   - AOF only\n   - RDB + AOF (recommended)\n4. Click **Save**\n\n> **Note**: Persistence settings can be changed anytime, but require instance restart.\n\n## Eviction Policies\n\nWhen Redis reaches max memory, it can evict keys based on policy:\n\n### Available Policies\n\n- **noeviction**: Return errors when memory limit reached (default)\n- **allkeys-lru**: Evict least recently used keys\n- **volatile-lru**: Evict least recently used keys with TTL\n- **allkeys-random**: Evict random keys\n- **volatile-random**: Evict random keys with TTL\n- **volatile-ttl**: Evict keys with shortest TTL\n\n### Choosing Eviction Policy\n\n**For Caching (recommended)**:\n```\nallkeys-lru\n```\nEvicts least recently used keys to make room for new data.\n\n**For Mixed Workload**:\n```\nvolatile-lru\n```\nOnly evicts keys with expiration set, preserves persistent data.\n\n**For Guaranteed Writes**:\n```\nnoeviction\n```\nReturns error if memory full, ensures no data loss.\n\n### Setting Eviction Policy\n\n1. Navigate to your Redis instance\n2. Click **Settings** > **Configuration**\n3. Select **Eviction Policy**\n4. Click **Save** (no restart required)\n\n## Monitoring and Maintenance\n\n### Key Metrics\n\nMonitor these metrics in the dashboard:\n\n- **Memory Usage**: Current memory consumption\n- **Hit Rate**: Cache hit ratio (should be > 90%)\n- **Commands/sec**: Operations per second\n- **Connected Clients**: Active connections\n- **Evicted Keys**: Keys evicted due to memory pressure\n- **Expired Keys**: Keys expired naturally\n\n### Redis Commands for Monitoring\n\n```bash\n# Memory info\nINFO memory\n\n# Stats\nINFO stats\n\n# Key space info\nINFO keyspace\n\n# Slow log\nSLOWLOG GET 10\n\n# Connected clients\nCLIENT LIST\n\n# Check specific key\nTYPE mykey\nTTL mykey\nMEMORY USAGE mykey\n```\n\n## Best Practices\n\n### Key Management\n\n- Use meaningful, hierarchical key names\n- Set expiration on temporary data\n- Avoid very large keys (> 1MB)\n- Use hashes for objects instead of serialized strings\n- Regularly clean up unused keys\n\n### Performance\n\n- Use pipelining for batch operations\n- Implement connection pooling\n- Avoid KEYS command in production (use SCAN instead)\n- Monitor slow log regularly\n- Keep values reasonably sized (< 100KB ideal)\n\n### Security\n\n- Always use TLS/SSL connections\n- Use strong passwords\n- Limit Redis access via firewalls\n- Don't expose Redis directly to internet\n- Regularly rotate passwords\n\n### High Availability\n\n- Enable replicas for production instances\n- Configure automatic failover\n- Monitor replication lag\n- Test failover procedures\n- Use DNS endpoints (not IP addresses)\n\n## Troubleshooting\n\n### High Memory Usage\n\n**Symptoms**: Redis using more memory than expected\n\n**Solutions**:\n- Review key space with `INFO keyspace`\n- Check for keys without expiration\n- Implement eviction policy\n- Consider scaling to larger profile\n\n### Low Hit Rate\n\n**Symptoms**: Cache hit rate below 80%\n\n**Solutions**:\n- Review cache key structure\n- Increase TTL for stable data\n- Pre-warm cache with common queries\n- Review access patterns\n\n### Connection Errors\n\n**Symptoms**: Cannot connect to Redis\n\n**Solutions**:\n- Verify connection details\n- Check TLS/SSL configuration\n- Ensure firewall allows your IP\n- Test with redis-cli\n- Check Redis instance status\n\n### Slow Performance\n\n**Symptoms**: High latency for Redis operations\n\n**Solutions**:\n- Check slow log for expensive commands\n- Review network latency\n- Use pipelining for batch operations\n- Consider upgrading instance profile\n- Monitor CPU usage\n\n## Related Documentation\n\n- [Cache Overview](https://docs.danubedata.ro/cache-overview)\n- [Redis Replicas](https://docs.danubedata.ro/cache-replicas)\n- [Cache Persistence](https://docs.danubedata.ro/cache-persistence)\n- [Cache Monitoring](https://docs.danubedata.ro/cache-monitoring)\n- [Monitoring Overview](https://docs.danubedata.ro/monitoring-overview)\n\n","prev":{"title":"Cache","slug":"cache-overview","url":"https://docs.danubedata.ro/cache-overview","markdown_url":"https://docs.danubedata.ro/cache-overview.md","json_url":"https://docs.danubedata.ro/cache-overview.json"},"next":{"title":"Redis Replicas","slug":"cache-replicas","url":"https://docs.danubedata.ro/cache-replicas","markdown_url":"https://docs.danubedata.ro/cache-replicas.md","json_url":"https://docs.danubedata.ro/cache-replicas.json"},"index_url":"https://docs.danubedata.ro/index.json"}