Skip to content

Redis Setup Guide - Performance Optimization 80x

📊 Performance Comparison

Métrica CloudSQL Session Redis Session Melhoria
append_event() O(n) - read all + write O(1) - RPUSH 80x
Latência típica ~800-1000ms ~10-20ms 50-80x
Eventos/interação 3-5 events × 200ms 3-5 events × 2ms 80x
User experience Lento, visível delay Instantâneo 🚀

Root Cause (CloudSQL Session):

# CloudSQL append_event() - O(n) complexity
def append_event(session_id, event):
    1. SELECT events FROM sessions WHERE id = session_id  # ~100ms - read ALL
    2. events = json.loads(blob)                           # ~50ms - deserialize ALL
    3. events.append(new_event)                            # ~1ms
    4. blob = json.dumps(events)                           # ~50ms - serialize ALL
    5. UPDATE sessions SET events = blob WHERE id = ...    # ~100ms - write ALL
    # Total: ~300ms × 3 events = ~900ms overhead

Solution (Redis Session):

# Redis append_event() - O(1) constant time
def append_event(session_id, event):
    redis.rpush(f"session:{session_id}:events", json.dumps(event))
    # Total: ~2ms - append to list, no reads

🏗️ Architecture

┌─────────────────────────────────────────────────────────────┐
│                         Slack Bot                           │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────────┐              ┌──────────────────┐     │
│  │  Session Service│◄────HOT─────►│  Redis           │     │
│  │  (Runner)       │   ~10ms      │  Memorystore     │     │
│  │                 │   O(1)       │  (Session data)  │     │
│  │  • get_session  │              │  • Fast          │     │
│  │  • append_event │              │  • TTL cleanup   │     │
│  │  • list_sessions│              │  • Persistence   │     │
│  └─────────────────┘              └──────────────────┘     │
│                                                             │
│  ┌─────────────────┐              ┌──────────────────┐     │
│  │  Memory Service │◄───COLD─────►│  CloudSQL        │     │
│  │  (Runner)       │   ~100ms     │  MySQL           │     │
│  │                 │              │  (Memory data)   │     │
│  │  • add_memory   │              │  • Analytics     │     │
│  │  • get_memories │              │  • Long-term     │     │
│  │  • search       │              │  • Full-text     │     │
│  └─────────────────┘              └──────────────────┘     │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Strategy: - Redis: Hot data (sessions) - High frequency, short TTL, need speed - CloudSQL: Cold data (memories) - Low frequency, long-term storage, need analytics


🚀 Quick Start (Local Development)

1. Start Redis (Docker)

# Redis 7 Alpine (lightweight)
docker run -d \
  --name ifriend-redis \
  -p 6379:6379 \
  redis:7-alpine

# Verify
docker ps | grep redis
redis-cli ping  # Should return: PONG

2. Configure Environment

# Copy example
cp .env.redis.example .env

# Edit .env
SESSION_BACKEND=redis
MEMORY_BACKEND=cloudsql
REDIS_URL=redis://localhost:6379/0
REDIS_SESSION_TTL=3600

3. Run Slack Bot

# Install dependencies (if not done)
pip install -r ifriend_agent/requirements.txt

# Run
python slack_bot.py

# Expected logs:
# ✅ SessionService inicializado
# ⚡ Redis: Performance otimizada (~10ms vs ~800ms CloudSQL)

4. Test in Slack

You: @IFriendBot busca tours em Paris
Bot: [responds in ~500ms instead of ~3s]

# Verify Redis keys
redis-cli KEYS "session:*"
redis-cli LLEN "session:slack_C123_U456_T789:events"
redis-cli LRANGE "session:slack_C123_U456_T789:events" 0 -1

☁️ Production Deployment (Google Cloud)

Step 1: Create Memorystore Instance

gcloud redis instances create ifriend-redis \
  --size=1 \
  --region=us-central1 \
  --network=default \
  --tier=standard \
  --redis-version=redis_7_0

# Get IP address
gcloud redis instances describe ifriend-redis \
  --region=us-central1 \
  --format="get(host)"
# Output: 10.123.45.67

Step 2: Configure VPC Connector (Cloud Run)

# Create VPC Connector (if not exists)
gcloud compute networks vpc-access connectors create ifriend-connector \
  --region=us-central1 \
  --network=default \
  --range=10.8.0.0/28

# Verify
gcloud compute networks vpc-access connectors list

Step 3: Update cloudbuild.yaml

steps:
  # ... existing build steps ...

  - name: 'gcr.io/cloud-builders/gcloud'
    id: 'deploy-cloud-run'
    args:
      - 'run'
      - 'deploy'
      - 'ifriend-slack-bot'
      - '--image=gcr.io/$PROJECT_ID/ifriend-slack-bot:$SHORT_SHA'
      - '--region=us-central1'
      - '--platform=managed'
      - '--vpc-connector=ifriend-connector'  # ← ADD THIS
      - '--set-env-vars=SESSION_BACKEND=redis,REDIS_URL=redis://10.123.45.67:6379/0,REDIS_SESSION_TTL=3600'
      - '--set-env-vars=MEMORY_BACKEND=cloudsql,CLOUDSQL_UNIX_SOCKET=/cloudsql/...'

Step 4: Deploy

gcloud builds submit --config cloudbuild.slack.yaml

# Verify logs
gcloud run logs read ifriend-slack-bot --limit 50 | grep Redis
# Should see: "RedisSessionService inicializado"

Option 2: Redis Cloud (Alternative)

# 1. Create account: https://redis.com/try-free/
# 2. Get connection URL: rediss://default:password@host:port

# 3. Update .env
REDIS_URL=rediss://default:xxxxx@redis-12345.c123.us-east-1-1.ec2.cloud.redislabs.com:12345

🔍 Redis Schema

Session Keys

session:{session_id}:meta       → HASH
  - app_name
  - user_id
  - created_at

session:{session_id}:events     → LIST
  - [event1_json, event2_json, ...]
  - RPUSH for O(1) append
  - LRANGE for get_session

Memory Keys (if using Redis for memory)

memory:{app_name}:{user_id}:{memory_id}   → HASH
  - id, session_id, user_id, created_at, events_json

memory:index:{app_name}:{user_id}         → ZSET
  - Scored by timestamp for time-range queries

📊 Monitoring

Redis CLI Commands

# Connect
redis-cli

# Check sessions
KEYS "session:*"
LLEN "session:slack_C123_U456_T789:events"
HGETALL "session:slack_C123_U456_T789:meta"

# Check memory usage
INFO memory

# Monitor live
MONITOR

Cloud Logging Queries

-- Redis initialization
resource.type="cloud_run_revision"
jsonPayload.message=~"RedisSessionService inicializado"

-- Performance metrics
resource.type="cloud_run_revision"
jsonPayload.message=~"⚡ Redis"

-- Latency tracking
resource.type="cloud_run_revision"
jsonPayload.message=~"Processamento.*ms"

Expected Metrics

  • Session Operations: 2-10ms
  • Total Latency (Slack message → response): 300-800ms
  • LLM: ~200-500ms (unchanged)
  • Session: ~10ms (was ~800ms)
  • Network: ~50-100ms
  • Total: ~260-610ms (vs previous ~1050-1400ms)

🐛 Troubleshooting

Issue: "Cannot connect to Redis"

# Check REDIS_URL format
REDIS_URL=redis://localhost:6379/0  # ✅ Correct
REDIS_URL=localhost:6379            # ❌ Missing scheme

# Test connection
redis-cli -u $REDIS_URL ping

# Cloud Run: Check VPC connector
gcloud run services describe ifriend-slack-bot \
  --region=us-central1 \
  --format="get(spec.template.spec.containers[0].env)"

Issue: "Redis connection timeout"

# Verify network rules
gcloud compute firewall-rules list | grep redis

# Check Memorystore status
gcloud redis instances list

# Test from Cloud Shell (same VPC)
gcloud compute ssh instance-name
redis-cli -h 10.123.45.67 ping

Issue: "Session not persisting"

# Check TTL
redis-cli TTL "session:slack_C123_U456_T789:meta"
# If -1: no expiration set (bug)
# If -2: key doesn't exist
# If >0: expires in N seconds (correct)

# Verify REDIS_SESSION_TTL env var
echo $REDIS_SESSION_TTL  # Should be 3600 or similar

Fallback to CloudSQL

# If Redis unavailable, switch backend
SESSION_BACKEND=cloudsql  # Slower but works
MEMORY_BACKEND=cloudsql

# Or inmemory for dev
SESSION_BACKEND=inmemory  # No persistence

🧪 Testing

Load Test Script

import asyncio
import time
from ifriend_agent.config.backends import get_session_service

async def test_performance():
    session_service = get_session_service("redis")

    # Create session
    session = await session_service.create_session(
        app_name="test",
        user_id="test_user"
    )

    # Test append_event performance
    events = []
    for i in range(100):
        start = time.perf_counter()
        await session_service.append_event(
            session.id,
            {"type": "text", "text": f"Event {i}"}
        )
        elapsed_ms = (time.perf_counter() - start) * 1000
        events.append(elapsed_ms)

    print(f"Average append_event: {sum(events)/len(events):.2f}ms")
    print(f"P50: {sorted(events)[50]:.2f}ms")
    print(f"P95: {sorted(events)[95]:.2f}ms")
    print(f"P99: {sorted(events)[99]:.2f}ms")

asyncio.run(test_performance())

Expected Results (Redis): - Average: 2-5ms - P95: 8-12ms - P99: 15-20ms

Previous Results (CloudSQL): - Average: 150-200ms - P95: 300-500ms - P99: 800-1200ms


💡 Tips

1. TTL Strategy

# Short TTL for sessions (ephemeral)
REDIS_SESSION_TTL=3600  # 1 hour

# Long TTL for memory (if using Redis)
REDIS_MEMORY_TTL_DAYS=30  # 30 days

2. Connection Pooling

Redis client uses connection pool automatically:

# redis_session_service.py
self.redis = redis.asyncio.from_url(
    redis_url,
    decode_responses=True,
    max_connections=10  # Pool size
)

3. Pipeline for Atomicity

# Create session atomically
async with self.redis.pipeline(transaction=True) as pipe:
    pipe.hset(meta_key, mapping=meta)
    pipe.lpush(events_key, "{}")  # Init empty
    pipe.expire(meta_key, ttl)
    pipe.expire(events_key, ttl)
    await pipe.execute()

4. Monitor Memory Usage

# Memorystore console
gcloud redis instances describe ifriend-redis \
  --region=us-central1 \
  --format="get(currentLocationId,memorySizeGb)"

# If approaching limit, reduce TTL or increase size

📈 Next Steps

  1. Deploy to production with Memorystore
  2. Monitor latency in Cloud Logging
  3. Compare metrics before/after Redis
  4. Adjust TTL based on usage patterns
  5. Consider Redis for Memory too (optional, if analytics not needed)

🎯 Success Criteria

  • ✅ Session operations < 10ms average
  • ✅ Total response time < 1s (vs previous 2-3s)
  • ✅ No session loss during bot restarts
  • ✅ TTL cleanup automatic (no manual pruning)
  • ✅ Cloud Logs show "Redis: Performance otimizada"

Documentation References: - Google Cloud Memorystore - Redis Python Client - ADK Session Service