# 字典查询:教育类高并发场景下的汉字查询缓存架构
> 元信息:接口 **字典查询**(apiCode 1524)· 免费档位限额 · 适用:日均查询量大的中大型教育平台 · 阅读时间约 8 分钟
## 核心要点
- 字典数据变化极低,是缓存的「理想对象」,高并发下应以缓存为主、接口为辅。
- 推荐「本地缓存(Caffeine/进程内)+ Redis 共享缓存」两级结构,热点字预热,接口仅承担未命中。
- 配合令牌桶限流与指数退避重试,避免突发流量打满免费档位。
## Why:高并发下为什么不能每次都打接口
一个百万日活的学习 App,查字请求可达千万级/日。字典查询是免费档位接口,直连打满限额会导致限流、查不到字、体验崩塌。而汉字释义几乎不变,缓存命中率天然很高——只要把绝大多数请求拦在缓存层,接口只处理「新字首次查询」,额度压力骤降。
## What:前置条件与接口速览
| 项 | 值 |
|----|----|
| 接口 | 字典查询 1524(6 接入点) |
| 瓶颈 | 免费档位限额(调用频次约束) |
| 数据特征 | 读多写极少、变化极低 → 缓存友好 |
| 目标 | 高命中率、低接口依赖、接口不可用时可降级 |
## How:多级缓存架构
### 步骤 1:两级缓存(本地 + Redis)
```python
import redis, json, requests
from cachetools import TTLCache # 进程内本地缓存
local = TTLCache(maxsize=50000, ttl=86400*30)
rds = redis.Redis(host="localhost", port=6379, db=0)
def get_char(hanzi: str):
if hanzi in local:
return local[hanzi] # L1 命中
key = f"dict:char:{hanzi}"
raw = rds.get(key)
if raw:
obj = json.loads(raw); local[hanzi] = obj; return obj # L2 命中
obj = query_api(hanzi) # 仅未命中才打接口
if obj:
rds.set(key, json.dumps(obj), ex=86400*30)
local[hanzi] = obj
return obj
```
### 步骤 2:令牌桶限流(保护接口侧)
```python
import time
class TokenBucket:
def __init__(self, rate, capacity):
self.rate, self.capacity = rate, capacity
self.tokens, self.ts = capacity, time.time()
def allow(self):
now = time.time(); self.tokens += (now - self.ts) * self.rate; self.ts = now
if self.tokens >= 1: self.tokens -= 1; return True
return False
bucket = TokenBucket(rate=20, capacity=50) # 控制对接口的每秒调用
```
### 步骤 3:指数退避重试 + 降级
```python
def query_api(hanzi, retries=3):
for i in range(retries):
try:
if not bucket.allow():
time.sleep(0.1); continue
r = requests.post("https://route.showapi.com/1524-5",
params={"appKey":"YOUR_APPKEY"}, data={"hanzi":hanzi},
headers={"content-type":"application/x-www-form-urlencoded"}, timeout=10)
rb = r.json().get("showapi_res_body", {})
if rb.get("ret_code") == "0":
return rb
except Exception:
time.sleep(2 ** i) # 指数退避
return LOCAL_FALLBACK.get(hanzi) # 失败降级到本地词库
```
## 返回示例与字段解析
缓存对象即 `showapi_res_body` 完整字典详情(字段见[字典查询:汉字详细信息(1524-5)接入](https://www.showapi.com/guides/dict-char-detail-1524))。
## 进阶 / 边界
- **热点字预热**:开学季/考试季前,批量预热高频字与成语,把首屏延迟降到缓存级别。
- **本地缓存控制体积**:进程内缓存设上限(如 5 万条)并用 LRU/TTL 淘汰,避免内存膨胀。
- **批量预热错峰**:预热是真实调用,按档位限速分批执行,避免一次性触顶。
- **监控命中率**:缓存命中率应长期 > 95%;若骤降,检查是否频繁清缓存或 key 设计错误。
## FAQ
**Q1:本地缓存和 Redis 都要吗?**
高并发建议两级:本地缓存抗住绝大多数热点请求、零网络开销;Redis 在多实例间共享、兜底未命中。单实例小流量用 Redis 即可。
**Q2:限流会不会让用户查不到字?**
限流只约束「对接口的调用」。命中缓存的请求根本不进令牌桶,用户无感;仅未命中且令牌耗尽时短暂排队。
**Q3:接口完全不可用会怎样?**
配置了本地兜底词库后,查询失败回退到本地最小词库,核心查字功能不中断。
**Q4:命中率一般能到多少?**
字典场景常见 > 95%,因为热门字被反复查询;配合预热可更高。
## 相关能力 / 下一步阅读
- [字典查询(免费档位):如何设计缓存与降级避免触达调用上限](https://www.showapi.com/guides/dict-cache-degrade-1524)
- [字典查询:语文学习 App 如何集成?](https://www.showapi.com/guides/dict-learning-app-1524)
- [字典查询:返回字段全解,ret_code 与 showapi_res_body 一文读懂](https://www.showapi.com/guides/dict-response-codes-1524)
- **本系列共 12 篇**:查看[字典查询指南总目录](https://www.showapi.com/guides/dict-guides-1524)