1 · 場景與價值
在日志累加、指標采集、消息追蹤等場景中,我們常需快速判斷某個字符串字段“到底有多長”,以便:
- 阻止過大日志:若長度超限則截斷或歸檔;
- 動態分桶:按長度選擇不同存儲策略;
- 性能監控:突然飆長可能暗示異常循環或惡意輸入。
有了 JSON.STRLEN
,無需把整段內容取回客戶端,也無需額外存副本,即可 O(1) 地獲取字段長度。
2 · 指令概覽
指令 | 作用 | 復雜度 |
---|---|---|
JSON.STRLEN key [path] | 返回指定路徑 JSON 字符串的長度 | O(1)(單路徑) / O(N)(多路徑,與鍵大小相關) |
- 可用版本:RedisJSON ≥ 1.0
- ACL 標簽:
@json @read @slow
- 默認路徑:
$
(根)
3 · 語法參數
JSON.STRLEN <key> [<path>]
參數 | 必填 | 說明 |
---|---|---|
key | ? | 目標鍵名 |
path | JSONPath,缺省為 $ |
返回值
- 若匹配為字符串:返回其長度(整型)。
- 若路徑不存在 / 類型非字符串:返回
nil
。 - 多路徑:遞歸數組,順序對應各匹配點。
4 · 基本示例
redis> JSON.SET doc $ '{"a":"foo","nested":{"a":"hello"},"nested2":{"a":31}}'
OK# 多路徑統計
redis> JSON.STRLEN doc $..a
1) (integer) 3 # $.a -> "foo"
2) (integer) 5 # $.nested.a -> "hello"
3) (nil) # $.nested2.a 不是字符串
5 · 常見用法場景
5.1 日志超長保護
> len=$(redis-cli JSON.STRLEN log:123 $.trace)
> if [ "$len" -gt 2048 ]; then
> redis-cli JSON.SET log:123 $.trace '"<truncated>"'
> fi
5.2 統計動態字段占用
# 查看所有用戶簡介 bio 的平均長度
redis-cli --raw KEYS "user:*" | while read k; doredis-cli JSON.STRLEN $k $.bio
done | awk '{s+=$1;c++} END{print s/c}'
6 · 踩坑與注意
坑 | 癥狀 | 解決方案 |
---|---|---|
路徑非字符串 | 返回 nil ,誤以為不存在 | 先 JSON.TYPE 或保證字段類型一致 |
多路徑掃描過大文檔 | 延遲抖動 | 精準路徑,避免 $..field |
空鍵 / 空路徑 | 直接 nil | 先用 EXISTS 或 JSON.TYPE 判斷 |
把數組當字符串 | 長度不是元素數 | STRLEN 只算字節數,不是元素數,數組用 JSON.ARRLEN |
7 · Go-Redis 完整示例
package mainimport ("context""fmt""log""github.com/redis/go-redis/v9"
)func main() {ctx := context.Background()rdb := redis.NewClient(&redis.Options{Addr: "localhost:6379"})defer rdb.Close()// 初始化測試文檔_, err := rdb.Do(ctx, "JSON.SET", "msg:1", "$",`{"body":"hello world","meta":{"note":"short"}}`).Result()if err != nil { log.Fatal(err) }// 1?? 單路徑長度len1, _ := rdb.Do(ctx, "JSON.STRLEN", "msg:1", "$.body").Int64()fmt.Println("body len =", len1) // 11// 2?? 多路徑長度res, _ := rdb.Do(ctx, "JSON.STRLEN", "msg:1", "$..note").Slice()fmt.Println("meta.note len =", res[0]) // 5// 3?? 類型不符示例_, _ = rdb.Do(ctx, "JSON.SET", "msg:1", "$.count", 100)res2, _ := rdb.Do(ctx, "JSON.STRLEN", "msg:1", "$.count").Slice()fmt.Printf("count -> %#v\n", res2[0]) // <nil>
}
8 · 性能建議
-
批量調用使用 Pipeline
pipe := rdb.Pipeline() keys := []string{"user:1", "user:2", "user:3"} for _, k := range keys {pipe.Do(ctx, "JSON.STRLEN", k, "$.bio") } _, _ = pipe.Exec(ctx)
-
監控慢查詢
復雜 JSON + 多路徑 ($..field
) 會觸發 SLOWLOG,需關注。 -
字符串膨脹預警
可用MEMORY USAGE key
+JSON.STRLEN
建立長度閾值報警。
9 · 與其它指令的協同
需求 | 組合 | 說明 |
---|---|---|
追加后檢測 | JSON.STRAPPEND → JSON.STRLEN | 先寫后查,防止長度爆表 |
長度分片 | JSON.STRLEN + JSON.SET | 達閾值切換到新字段 |
類型校驗 | JSON.TYPE + JSON.STRLEN | 防止對非字符串統計 |
10 · 總結
JSON.STRLEN
提供 O(1) 字段級長度統計,是日志與配額場景的利器。- 返回值為整型或
nil
,多路徑時請按序處理。 - 精準路徑 ? 通配路徑,能顯著降低 O(N) 掃描成本。
- 在 Go-Redis 中用
Do()
一行即可調用,并能與 Pipeline/事務無縫整合。
至此,字符串家族三兄弟 STRLEN / STRAPPEND / SET 已全部集齊。靈活運用它們,你的 RedisJSON 文檔讀寫將更加高效、細粒度且安全。祝編碼愉快,歡迎留言交流實踐體會!