一、功能概述
小象买菜系统的动态价格展示功能需要实现以下核心需求:
1. 实时显示商品价格及变化
2. 支持不同用户等级/促销活动的差异化定价
3. 价格变动历史记录与追溯
4. 高性能的价格查询接口
二、技术架构设计
1. 系统架构
```
客户端(Web/App) → API网关 → 价格服务 → 缓存层 → 数据库
↑ ↓
商品服务 促销服务
```
2. 关键组件
- 价格服务:核心价格计算与展示逻辑
- Redis缓存:存储实时价格数据
- 消息队列:处理价格变更事件
- 定时任务:批量更新价格
三、核心实现方案
1. 数据库设计
```sql
-- 商品基础表
CREATE TABLE product (
id BIGINT PRIMARY KEY,
name VARCHAR(100),
base_price DECIMAL(10,2),
status TINYINT
);
-- 价格规则表
CREATE TABLE price_rule (
id BIGINT PRIMARY KEY,
product_id BIGINT,
rule_type ENUM(MEMBER, PROMOTION, TIME_BASED),
rule_value JSON, -- 存储规则参数如会员等级、时间范围等
priority INT,
start_time DATETIME,
end_time DATETIME,
FOREIGN KEY (product_id) REFERENCES product(id)
);
-- 实时价格表(可选)
CREATE TABLE realtime_price (
product_id BIGINT PRIMARY KEY,
current_price DECIMAL(10,2),
update_time DATETIME,
FOREIGN KEY (product_id) REFERENCES product(id)
);
```
2. 价格计算服务实现
```java
public class PriceCalculator {
@Autowired
private PriceRuleRepository priceRuleRepository;
@Autowired
private RedisTemplate
redisTemplate;
// 获取商品实时价格
public BigDecimal getRealtimePrice(Long productId, UserContext userContext) {
// 1. 尝试从缓存获取
String cacheKey = "price:" + productId + ":" + userContext.getUserId();
String cachedPrice = redisTemplate.opsForValue().get(cacheKey);
if (cachedPrice != null) {
return new BigDecimal(cachedPrice);
}
// 2. 计算实时价格
BigDecimal price = calculatePrice(productId, userContext);
// 3. 写入缓存(设置较短过期时间)
redisTemplate.opsForValue().set(cacheKey, price.toString(), 1, TimeUnit.MINUTES);
return price;
}
private BigDecimal calculatePrice(Long productId, UserContext userContext) {
// 获取所有适用规则
List applicableRules = priceRuleRepository.findApplicableRules(
productId,
userContext.getMemberLevel(),
LocalDateTime.now()
);
// 按优先级排序
applicableRules.sort(Comparator.comparingInt(PriceRule::getPriority));
// 应用规则计算价格
BigDecimal basePrice = getBasePrice(productId);
BigDecimal finalPrice = basePrice;
for (PriceRule rule : applicableRules) {
switch (rule.getRuleType()) {
case MEMBER:
finalPrice = applyMemberDiscount(finalPrice, rule);
break;
case PROMOTION:
finalPrice = applyPromotion(finalPrice, rule);
break;
// 其他规则类型...
}
}
return finalPrice;
}
}
```
3. 价格变动通知实现
```javascript
// 前端WebSocket实现
const priceSocket = new WebSocket(wss://yourdomain.com/price-updates);
priceSocket.onmessage = function(event) {
const data = JSON.parse(event.data);
if (data.type === PRICE_CHANGE && data.productId in window.productPriceMap) {
// 更新页面价格显示
updatePriceDisplay(data.productId, data.newPrice);
// 显示价格变动动画
showPriceChangeAnimation(data.productId, data.oldPrice, data.newPrice);
}
};
function updatePriceDisplay(productId, newPrice) {
const priceElement = document.getElementById(`price-${productId}`);
if (priceElement) {
priceElement.textContent = `¥${newPrice.toFixed(2)}`;
}
}
```
4. 价格历史记录实现
```python
Django模型示例
class PriceHistory(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
old_price = models.DecimalField(max_digits=10, decimal_places=2)
new_price = models.DecimalField(max_digits=10, decimal_places=2)
change_reason = models.CharField(max_length=255)
changed_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
change_time = models.DateTimeField(auto_now_add=True)
class Meta:
indexes = [
models.Index(fields=[product, -change_time]),
]
获取价格历史API
@api_view([GET])
def product_price_history(request, product_id):
history = PriceHistory.objects.filter(product_id=product_id).order_by(-change_time)[:20]
serializer = PriceHistorySerializer(history, many=True)
return Response(serializer.data)
```
四、性能优化策略
1. 多级缓存策略:
- 本地缓存(Caffeine/Guava)存储热点商品价格
- Redis分布式缓存存储全量价格数据
- 数据库作为最终数据源
2. 价格计算预加载:
- 用户访问商品列表时预加载价格
- 使用Batch API减少请求次数
3. 异步更新机制:
- 价格变更通过消息队列异步处理
- 定时任务批量更新接近生效时间的规则
4. 数据分片:
- 按商品类别或ID范围分片存储价格数据
- 水平扩展价格服务实例
五、前端展示实现
```react
// React价格显示组件示例
function PriceDisplay({ productId, initialPrice }) {
const [price, setPrice] = useState(initialPrice);
const [priceHistory, setPriceHistory] = useState([]);
const [showHistory, setShowHistory] = useState(false);
useEffect(() => {
// 订阅价格更新
const eventSource = new EventSource(`/api/prices/stream?productId=${productId}`);
eventSource.onmessage = (e) => {
const data = JSON.parse(e.data);
if (data.type === PRICE_UPDATE) {
setPrice(data.newPrice);
// 可选:添加价格变动动画
}
};
return () => eventSource.close();
}, [productId]);
const fetchPriceHistory = async () => {
const response = await fetch(`/api/products/${productId}/price-history`);
const history = await response.json();
setPriceHistory(history);
};
return (
¥{price.toFixed(2)}
{priceHistory.length > 0 && (
)}
{showHistory && (
价格变动记录
{priceHistory.map((item, index) => (
{item.changeTime}: {item.oldPrice} → {item.newPrice}
{item.changeReason}
))}
)}
);
}
```
六、测试与监控
1. 测试策略:
- 单元测试:价格计算逻辑
- 集成测试:价格服务与缓存、数据库交互
- 性能测试:模拟高并发价格查询
- 混沌工程:模拟缓存失效、数据库故障等场景
2. 监控指标:
- 价格查询QPS
- 缓存命中率
- 价格计算耗时
- 价格变更通知延迟
3. 告警规则:
- 价格计算错误率 > 0.1%
- 缓存命中率 < 90%
- 价格更新延迟 > 5秒
七、部署与扩展
1. 容器化部署:
- 使用Docker部署价格服务
- Kubernetes管理服务实例
2. 灰度发布:
- 新价格规则先在部分用户或商品上测试
- 逐步扩大范围
3. 多区域部署:
- 跨区域缓存同步
- 考虑数据本地化要求
通过以上方案,小象买菜系统可以实现高效、准确的动态价格展示功能,同时保证系统的高可用性和可扩展性。