配置 SSOT(TOML + .env) 统一错误契约 Auth 与事务边界 Redis / Celery 可靠性:业务 Redis(DB/0)与 Celery broker/backend(DB/1)显式拆分;连接池、sync client 可观测性(OpenTelemetry + LGTM)
3.6 KiB
3.6 KiB
title, impact, impactDescription, tags, description, alwaysApply
| title | impact | impactDescription | tags | description | alwaysApply |
|---|---|---|---|---|---|
| Choose JSON vs Hash vs String Appropriately | MEDIUM | Optimal data model for your use case | json, hash, string, data-structures, documents | Choose JSON vs Hash vs String Appropriately | true |
Choose JSON vs Hash vs String Appropriately
Redis offers three ways to store structured data: JSON, Hash, and serialized strings. Each has distinct trade-offs around atomic partial operations and indexability.
| Feature | JSON | Hash | String (serialized JSON) |
|---|---|---|---|
| Structure | Nested objects and arrays | Flat key-value pairs | Any structure |
| Atomic partial reads | Yes ($.field) |
Yes (HGET) |
No (must fetch entire value) |
| Atomic partial writes | Yes (JSON.SET $.field) |
Yes (HSET) |
No (must rewrite entire value) |
| RQE indexing | Yes | Yes | No |
| Geospatial indexing | Yes | Yes | No |
| Memory efficiency | Higher overhead | More efficient | Most compact |
| Field-level expiration | No | Yes (HEXPIRE) | No |
When to use each:
- JSON: Nested structures with atomic partial updates and indexing needs
- Hash: Flat objects with atomic field access, field-level expiration, or memory efficiency
- String: Simple caching where you always read/write the entire object and don't need indexing
Correct: Use JSON for nested structures with atomic partial updates.
Python (redis-py):
# JSON supports nested structures and atomic deep updates
redis.json().set("user:1001", "$", {
"name": "Alice",
"preferences": {"theme": "dark", "notifications": True}
})
# Atomic update of nested field - no read-modify-write needed
redis.json().set("user:1001", "$.preferences.theme", "light")
Java (Jedis):
import redis.clients.jedis.UnifiedJedis;
import redis.clients.jedis.json.Path2;
import org.json.JSONObject;
try (UnifiedJedis jedis = new UnifiedJedis("redis://localhost:6379")) {
JSONObject user = new JSONObject();
user.put("name", "Alice");
user.put("preferences", new JSONObject().put("theme", "dark"));
jedis.jsonSet("user:1001", new Path2("$"), user);
// Atomic update of nested field
jedis.jsonSet("user:1001", new Path2("$.preferences.theme"), "light");
}
Correct: Use Hash for flat objects with atomic field access.
Python (redis-py):
# Hash is efficient for flat data with atomic field operations
redis.hset("session:abc", mapping={
"user_id": "1001",
"created_at": "2024-01-01",
"ip": "192.168.1.1"
})
# Atomic field read and update
ip = redis.hget("session:abc", "ip")
redis.hset("session:abc", "ip", "10.0.0.1")
Correct: Use String for simple caching without partial updates.
Python (redis-py):
import json
# String is fine when you always read/write the entire object
# and don't need indexing or partial updates
config = {"feature_flags": {"dark_mode": True}, "version": "1.0"}
redis.set("config:app", json.dumps(config), ex=3600)
# Must fetch and parse entire object
config = json.loads(redis.get("config:app"))
Incorrect: Using String when you need atomic partial updates.
Python (redis-py):
import json
# BAD: Must fetch, parse, modify, serialize, and rewrite entire object
data = json.loads(redis.get("user:1001"))
data["preferences"]["theme"] = "light" # Not atomic!
redis.set("user:1001", json.dumps(data))
# Another client could have modified the object between GET and SET
Reference: Data Type Comparison