典型操作特征
技术挑战
1. 存储结构方案对比
方案 | 优点 | 缺点 |
---|---|---|
String+JSON | 简单直观 | 修改需反序列化整个数据 |
Hash结构 | 支持字段级操作 | 嵌套结构处理略复杂 |
Sorted Set | 天然支持排序 | 存储成本较高 |
混合结构 | 平衡性能与灵活性 | 实现复杂度略高 |
2. 最终数据结构设计
// Key设计:cart:{userType}:{userId}
String cartKey = "cart:user:10001";
// Value结构:
// Hash结构存储商品基础信息
Map<String, String> itemData = new HashMap<>();
itemData.put("sku:1001",
"{\"quantity\":2,\"selected\":1,\"price\":5999,\"timestamp\":1717025661}");
// Sorted Set维护操作顺序
jedis.zadd(cartKey + ":zset", System.currentTimeMillis(), "sku:1001");
1. 多级缓存架构
2. 各层缓存配置
缓存层级 | 技术选型 | 容量 | 过期策略 |
---|---|---|---|
本地缓存 | Caffeine | 10万用户 | 基于大小+访问时间(1分钟) |
Redis缓存 | Hash+Zset | 1TB内存 | 动态TTL+LRU淘汰 |
持久化存储 | MySQL+TiDB | 无限扩展 | 事务保障 |
1. 批量操作管道化
public void batchAddItems(String userId, List<CartItem> items) {
try (Jedis jedis = jedisPool.getResource()) {
Pipeline pipeline = jedis.pipelined();
String cartKey = buildCartKey(userId);
items.forEach(item -> {
String field = "sku:" + item.getSkuId();
// 更新Hash
pipeline.hset(cartKey, field, serialize(item));
// 更新ZSET
pipeline.zadd(cartKey + ":zset", System.currentTimeMillis(), field);
});
pipeline.sync();
}
}
2. 异步队列削峰
@KafkaListener(topics = "cart_updates")
public void processCartUpdate(CartUpdateEvent event) {
redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
event.getUpdates().forEach(update -> {
connection.hSet(
update.getCartKey().getBytes(),
update.getField().getBytes(),
serialize(update.getValue())
);
});
return null;
});
}
1. 热点数据预加载
@Scheduled(fixedRate = 600000) // 每10分钟执行
public void preloadActiveCarts() {
List<String> activeUsers = userService.getRecentActiveUsers(10000);
activeUsers.parallelStream().forEach(userId -> {
String cartKey = buildCartKey(userId);
Map<String, String> cartData = jedis.hgetAll(cartKey);
localCache.put(userId, cartData);
});
}
2. 分片读取优化
public Map<String, CartItem> getCartSharded(String userId) {
String cartKey = buildCartKey(userId);
List<String> fields = new ArrayList<>();
// 分片读取Hash
Map<String, CartItem> result = new ConcurrentHashMap<>();
IntStream.range(0, 4).parallel().forEach(shard -> {
ScanParams params = new ScanParams().count(100).match("sku*");
String cursor = "0";
do {
ScanResult<Map.Entry<String, String>> scanResult =
jedis.hscan(cartKey, cursor, params);
scanResult.getResult().forEach(entry -> {
if (entry.getKey().hashCode() % 4 == shard) {
result.put(entry.getKey(), deserialize(entry.getValue()));
}
});
cursor = scanResult.getCursor();
} while (!"0".equals(cursor));
});
return result;
}
1. 库存缓存设计
// 库存Key结构
String stockKey = "stock:" + skuId + ":" + warehouseId;
// 原子扣减库存
Long remain = jedis.eval(
"local current = redis.call('get', KEYS[1])\n" +
"if not current then return -1 end\n" +
"if tonumber(current) < tonumber(ARGV[1]) then return -1 end\n" +
"return redis.call('decrby', KEYS[1], ARGV[1])",
Collections.singletonList(stockKey),
Collections.singletonList("1")
);
2. 库存预占机制
public boolean reserveStock(String userId, String skuId, int quantity) {
String lockKey = "stock_lock:" + skuId;
RLock lock = redissonClient.getLock(lockKey);
try {
if (lock.tryLock(100, 1000, TimeUnit.MILLISECONDS)) {
// 检查实际库存
int realStock = getRealStock(skuId);
if (realStock < quantity) return false;
// 写入预占记录
String reserveKey = "reserve:" + userId + ":" + skuId;
jedis.setex(reserveKey, 300, String.valueOf(quantity));
// 更新显示库存
jedis.decrBy("display_stock:" + skuId, quantity);
return true;
}
} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
return false;
}
1. 双写一致性方案
2. 补偿对账机制
@Scheduled(cron = "0 0 2 * * ?")
public void cartReconciliation() {
// 扫描所有购物车Key
ScanParams params = new ScanParams().match("cart:*").count(100);
String cursor = "0";
do {
ScanResult<String> scanResult = jedis.scan(cursor, params);
scanResult.getResult().parallelStream().forEach(cartKey -> {
// 对比Redis与数据库
Map<String, String> redisData = jedis.hgetAll(cartKey);
Map<String, CartItem> dbData = cartDAO.getFromDB(extractUserId(cartKey));
if (!dataEquals(redisData, dbData)) {
log.warn("数据不一致:{}", cartKey);
repairData(cartKey, redisData, dbData);
}
});
cursor = scanResult.getCursor();
} while (!"0".equals(cursor));
}
测试环境:
性能指标:
操作类型 | 优化前性能 | 优化后性能 | 提升倍数 |
---|---|---|---|
添加商品 | 1200 TPS | 8500 TPS | 7.1x |
批量删除 | 800 TPS | 6800 TPS | 8.5x |
全量获取 | 300 QPS | 4500 QPS | 15x |
库存校验 | 1500 TPS | 12000 TPS | 8x |
容量规划
故障应急方案
监控关键指标
# 实时监控命令
redis-cli info stats | grep -E "instantaneous_ops_per_sec|keyspace_hits"
redis-cli info memory | grep used_memory_human
redis-cli latency doctor
通过本方案可实现:
扩展优化方向:
https://www.kdocs.cn/l/cvk0eoGYucWA