# Catatan Seekor: REDIS

Redis (Remote Dictionary Server) adalah in-memory data structure store yang dapat digunakan sebagai database, cache, dan message broker.

## Fundamental

### Redis Features

* **In-Memory Storage**: Data disimpan di RAM untuk akses cepat
* **Data Structures**: Mendukung berbagai tipe data
* **Persistence**: Dapat menyimpan data ke disk
* **Replication**: Master-slave replication
* **Clustering**: Distributed Redis cluster

### Redis Data Types

* **Strings**: Text atau binary data
* **Lists**: Ordered collections
* **Sets**: Unordered unique collections
* **Hashes**: Field-value pairs
* **Sorted Sets**: Ordered sets with scores
* **Streams**: Append-only log data structure

## Basic Commands

### String Operations

```bash
# Set and Get
SET key value
GET key

# Set with expiration
SETEX key seconds value
SET key value EX seconds

# Multiple operations
MSET key1 value1 key2 value2
MGET key1 key2

# Increment/Decrement
INCR key
DECR key
INCRBY key increment
DECRBY key decrement
```

### List Operations

```bash
# Push operations
LPUSH list value    # Left push
RPUSH list value    # Right push

# Pop operations
LPOP list           # Left pop
RPOP list           # Right pop

# Range operations
LRANGE list start stop
LINDEX list index
LLEN list

# Blocking operations
BLPOP list timeout
BRPOP list timeout
```

### Set Operations

```bash
# Add and remove
SADD set member1 member2
SREM set member1

# Set operations
SISMEMBER set member
SMEMBERS set
SCARD set

# Set operations
SINTER set1 set2    # Intersection
SUNION set1 set2    # Union
SDIFF set1 set2     # Difference
```

### Hash Operations

```bash
# Field operations
HSET hash field value
HGET hash field
HDEL hash field

# Multiple fields
HMSET hash field1 value1 field2 value2
HMGET hash field1 field2

# Hash operations
HGETALL hash
HKEYS hash
HVALS hash
HEXISTS hash field
```

### Sorted Set Operations

```bash
# Add with score
ZADD sortedset score member
ZREM sortedset member

# Score operations
ZSCORE sortedset member
ZRANK sortedset member
ZREVRANK sortedset member

# Range operations
ZRANGE sortedset start stop
ZREVRANGE sortedset start stop
ZRANGEBYSCORE sortedset min max
```

## Advanced Features

### Expiration and TTL

```bash
# Set expiration
EXPIRE key seconds
PEXPIRE key milliseconds

# Check TTL
TTL key
PTTL key

# Remove expiration
PERSIST key

# Set key with expiration
SET key value EX 3600    # Expire in 1 hour
```

### Transactions

```bash
# Start transaction
MULTI

# Queue commands
SET key1 value1
SET key2 value2
INCR counter

# Execute transaction
EXEC

# Discard transaction
DISCARD
```

### Pub/Sub

```bash
# Subscribe to channel
SUBSCRIBE channel1 channel2

# Publish message
PUBLISH channel message

# Pattern subscription
PSUBSCRIBE pattern*

# Unsubscribe
UNSUBSCRIBE channel
PUNSUBSCRIBE pattern*
```

## Redis with Go

### Basic Connection

```go
package main

import (
    "github.com/go-redis/redis/v8"
    "context"
)

func main() {
    // Create Redis client
    rdb := redis.NewClient(&redis.Options{
        Addr:     "localhost:6379",
        Password: "", // no password set
        DB:       0,  // use default DB
    })

    ctx := context.Background()

    // Test connection
    _, err := rdb.Ping(ctx).Result()
    if err != nil {
        panic(err)
    }
}
```

### String Operations in Go

```go
// Set and Get
err := rdb.Set(ctx, "key", "value", 0).Err()
if err != nil {
    panic(err)
}

val, err := rdb.Get(ctx, "key").Result()
if err != nil {
    panic(err)
}
fmt.Println("key", val)

// Set with expiration
err = rdb.Set(ctx, "key", "value", time.Hour).Err()

// Increment
val, err = rdb.Incr(ctx, "counter").Result()
```

### Hash Operations in Go

```go
// Set hash field
err := rdb.HSet(ctx, "user:1", map[string]interface{}{
    "name":  "John Doe",
    "email": "john@example.com",
    "age":   30,
}).Err()

// Get hash field
name, err := rdb.HGet(ctx, "user:1", "name").Result()
if err != nil {
    panic(err)
}

// Get all fields
user, err := rdb.HGetAll(ctx, "user:1").Result()
if err != nil {
    panic(err)
}
```

### List Operations in Go

```go
// Push to list
err := rdb.LPush(ctx, "list", "value1", "value2").Err()

// Get list range
list, err := rdb.LRange(ctx, "list", 0, -1).Result()
if err != nil {
    panic(err)
}

// Pop from list
val, err := rdb.LPop(ctx, "list").Result()
```

## Caching Patterns

### Cache-Aside Pattern

```go
func GetUser(ctx context.Context, userID string) (*User, error) {
    // Try to get from cache first
    cached, err := rdb.Get(ctx, "user:"+userID).Result()
    if err == nil {
        var user User
        json.Unmarshal([]byte(cached), &user)
        return &user, nil
    }

    // If not in cache, get from database
    user, err := db.GetUser(userID)
    if err != nil {
        return nil, err
    }

    // Store in cache
    userJSON, _ := json.Marshal(user)
    rdb.Set(ctx, "user:"+userID, userJSON, time.Hour)

    return user, nil
}
```

### Write-Through Pattern

```go
func UpdateUser(ctx context.Context, user *User) error {
    // Update database
    err := db.UpdateUser(user)
    if err != nil {
        return err
    }

    // Update cache
    userJSON, _ := json.Marshal(user)
    rdb.Set(ctx, "user:"+user.ID, userJSON, time.Hour)

    return nil
}
```

### Cache Invalidation

```go
func DeleteUser(ctx context.Context, userID string) error {
    // Delete from database
    err := db.DeleteUser(userID)
    if err != nil {
        return err
    }

    // Remove from cache
    rdb.Del(ctx, "user:"+userID)

    return nil
}
```

## Performance Optimization

### Connection Pooling

```go
rdb := redis.NewClient(&redis.Options{
    Addr:         "localhost:6379",
    PoolSize:     10,           // Connection pool size
    MinIdleConns: 5,            // Minimum idle connections
    MaxRetries:   3,            // Maximum retries
    DialTimeout:  5 * time.Second,
    ReadTimeout:  3 * time.Second,
    WriteTimeout: 3 * time.Second,
})
```

### Pipeline Operations

```go
// Use pipeline for multiple commands
pipe := rdb.Pipeline()
pipe.Set(ctx, "key1", "value1", time.Hour)
pipe.Set(ctx, "key2", "value2", time.Hour)
pipe.Expire(ctx, "key3", time.Hour)

// Execute all commands
_, err := pipe.Exec(ctx)
```

### Lua Scripting

```go
// Lua script for atomic operations
script := `
    local key = KEYS[1]
    local value = ARGV[1]
    local ttl = ARGV[2]
    
    redis.call('SET', key, value, 'EX', ttl)
    return redis.call('GET', key)
`

// Execute script
result, err := rdb.Eval(ctx, script, []string{"key"}, "value", 3600).Result()
```

## Monitoring and Maintenance

### Redis Info

```bash
# Get Redis information
INFO

# Get specific section
INFO memory
INFO stats
INFO replication

# Monitor commands in real-time
MONITOR

# Slow log
SLOWLOG GET 10
```

### Memory Optimization

```bash
# Check memory usage
MEMORY USAGE key
MEMORY STATS

# Set memory policy
CONFIG SET maxmemory-policy allkeys-lru
CONFIG SET maxmemory 2gb
```

### Persistence Configuration

```bash
# RDB configuration
save 900 1      # Save if at least 1 key changed in 900 seconds
save 300 10     # Save if at least 10 keys changed in 300 seconds
save 60 10000   # Save if at least 10000 keys changed in 60 seconds

# AOF configuration
appendonly yes
appendfsync everysec
```

## References

### Redis Resources

* [10 QUICK TIPS FOR REDIS](https://www.objectrocket.com/blog/how-to/10-quick-tips-about-redis/)
* [Golang + Redis + MySQL Integration](https://medium.com/@jaya.p/golang-redis-mysql-integration-5468829cbd49)
* [Optimize your application architecture and implement Redis caching](https://ddcode.net/2019/06/30/golang-gin-practice-serials-13-optimize-your-application-structure-and-implement-redis-cache/)
* [Redis and Golang: Designed to Improve Performance](https://redislabs.com/blog/redis-go-designed-improve-performance/)
* [Redis Best Practices and Performance Tuning](https://iamabhishek-dubey.medium.com/redis-best-practices-and-performance-tuning-c48611388bbc)
* [Redis Best Practices](https://redislabs.com/redis-best-practices/introduction/)
* [Redis Hash in Go With HSET, HGET and HGETALL](https://www.jajaldoang.com/post/redis-hash-in-go-with-hset-hget/)

## Best Practices

### Security

* **Authentication**: Use strong passwords
* **Network Security**: Bind to localhost, use firewall
* **SSL/TLS**: Enable for production environments
* **Access Control**: Limit access to trusted networks

### Performance

* **Memory Management**: Monitor memory usage
* **Connection Pooling**: Use appropriate pool sizes
* **Pipelining**: Batch multiple commands
* **Lua Scripts**: Use for complex atomic operations

### Monitoring

* **Health Checks**: Regular connection testing
* **Metrics Collection**: Monitor performance metrics
* **Alerting**: Set up alerts for critical issues
* **Logging**: Enable slow query logging
