🗨️ 评论缓存设计
1. 业务场景
在高并发系统中,评论经常被查看与点赞,我们在展示评论列表的时候,按点赞数和评论时间综合排序,对于评论业务,应该如何设计缓存策略?
2.技术选型
评论是一种需要持久化的数据,主储存靠考虑使用 TiDB 等高性能关系数据库,通过合理的表设计来解决缓存大 key 的问题。
1️⃣ 评论主题表 Comment Topic
作用:评论的“桶”,即评论的整体信息。
sql
comment_topic
- topic_id # 视频 / 帖子 / 商品
- comment_count # 总评论数统计
- hot_count # 热度评分
- status # 状态等其它字段为什么要单独一层?
评论总数、关闭评论、风控
快速判断:有没有评论
避免每次都扫评论表这是“评论的元数据层”
2️⃣ 评论索引表 Comment Index
存放评论的索引与树形结构,表示评论的回复、父子等关系
sql
comment_index
- topic_id # 主题id,根据业务决定,比如视频评论就是视频编号
- comment_id # 评论记录id
- parent_id # 父评论id,如果为 0 即为顶级评论
- order_key # 排序字段等
- root # 回复评论,如果为 0 即为非回复评论不存 content,一条记录非常小,专门为:分页/排序/层级业务设计
3️⃣ 评论内容表 Comment Content
sql
comment_content
- comment_id # 评论id
- user_id # 用户id
- content # 文本内容
- extra # 图片 / 表情 / @这一层的特点为 IO 重、字段多、更新少,天然适合缓存
3.总结
这套技术架构核心在表设计上,将评论内容与评论结构进行了解耦,在实际实现的时候,我们只缓存评论内容,可以考虑使用异步编排来进一步优化整体响应时间。
实例-租车网站
1. 主题表 (这里是车辆信息)
评论主题表为评论区的主题聚合信息,即评论对应的实体。
sql
-- 车辆信息表
CREATE TABLE `car`
(
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`brand_id` bigint unsigned NOT NULL COMMENT '品牌ID',
`name` varchar(50) NOT NULL COMMENT '车辆名',
`number` varchar(50) NOT NULL COMMENT '车牌号',
`min_rental_days` int NOT NULL COMMENT '最小租赁天数',
`daily_rent` decimal(10, 2) NOT NULL COMMENT '日租金(人民币元)',
`car_type` varchar(50) DEFAULT NULL COMMENT '车型',
`power_type` varchar(50) DEFAULT NULL COMMENT '动力类型',
`purchase_time` date DEFAULT NULL COMMENT '车辆购买日期',
`horsepower` int DEFAULT NULL COMMENT '马力',
`torque` int DEFAULT NULL COMMENT '最大扭矩',
`fuel_consumption` int DEFAULT NULL COMMENT '百公里油耗(L/100km)',
`endurance` int DEFAULT NULL COMMENT '理论续航km',
`description` varchar(1536) DEFAULT NULL COMMENT '描述',
`size` varchar(50) DEFAULT NULL COMMENT '尺寸,长×宽×高',
`seat` int DEFAULT NULL COMMENT '座位数',
`weight` int DEFAULT NULL COMMENT '车重(kg)',
`volume` int DEFAULT NULL COMMENT '储物容积(L)',
`acceleration` decimal(4, 1) DEFAULT NULL COMMENT '百公里加速(s)',
`images` varchar(1536) DEFAULT NULL COMMENT '图片url列表,逗号分隔,最多9张图片',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '车辆状态:0=正常,1=不可租',
`hot_score` int NOT NULL DEFAULT '0' COMMENT '热度评分',
`avg_score` int NOT NULL DEFAULT '0' COMMENT '车辆用户平均评分',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` tinyint NOT NULL DEFAULT '0' COMMENT '逻辑删除:0=正常,1=已删除',
PRIMARY KEY (`id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_0900_ai_ci COMMENT ='车辆信息表';2. 评论索引表
评论索引表只构建评论的结构索引,不储存实际的评论细节。
sql
-- 评论索引表
CREATE TABLE `comment_index`
(
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_id` bigint unsigned NOT NULL COMMENT '对应用户ID',
`car_id` bigint unsigned NOT NULL COMMENT '对应车辆ID',
`parent_comment_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '父级评论id,默认0即为顶级评论',
`follow_comment_id` bigint unsigned NOT NULL DEFAULT '0' COMMENT '回复评论id,默认0即非回复评论',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` tinyint NOT NULL DEFAULT '0' COMMENT '逻辑删除:0=正常,1=已删除',
PRIMARY KEY (`id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_0900_ai_ci COMMENT ='评论索引表';3. 评论详情表
评论详情再储存具体的评论数据,实现了评论结构和评论内容的解耦,这样的话,可以很好的防止在缓存过程中出现大 key 的问题。
sql
-- 评论详情表
CREATE TABLE `comment_detail`
(
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`index_id` bigint unsigned NOT NULL COMMENT '对应索引ID',
`content` varchar(1024) NOT NULL COMMENT '评论内容',
`like_count` int unsigned NOT NULL DEFAULT '0' COMMENT '点赞数',
`score` int unsigned DEFAULT NULL COMMENT '近期订单评分',
`extra_images` JSON DEFAULT NULL COMMENT '评论图片URL列表(JSON数组)',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` tinyint NOT NULL DEFAULT '0' COMMENT '逻辑删除:0=正常,1=已删除',
PRIMARY KEY (`id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_0900_ai_ci COMMENT ='评论详情表';4. 外部关联表
引入一个额外的业务背景:如果用户对于某个车辆,有完成且打分的订单,用户评论会额外显示最近一次的订单的打分。
具体的业务实现如下:
用户发送评论时,查询数据库,如果评论的车辆之前有订单评分分数,把最近的一次订单评分插入到评论详情的 score 字段中 (create_time desc,limit 1)。即,一个当时评分的快照。
sql
-- 订单表
CREATE TABLE `rental_order`
(
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_id` bigint unsigned NOT NULL COMMENT '对应用户ID',
`car_id` bigint unsigned NOT NULL COMMENT '对应车辆ID',
`trade_no` varchar(255) NOT NULL COMMENT '支付宝订单编号',
`start_rental_time` date NOT NULL COMMENT '车辆起租日期',
`end_rental_time` date NOT NULL COMMENT '车辆还车日期',
`price` decimal(10, 2) NOT NULL COMMENT '订单总额(人民币元)',
`address` varchar(255) NOT NULL COMMENT '取还车地址',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '订单状态:0=新建/待支付,1=已支付,2=租赁中,3=已完成,4=已取消 5=待退款 6=已退款',
`score` int DEFAULT NULL COMMENT '订单评分0-10,计入车辆均分',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`deleted` tinyint NOT NULL DEFAULT '0' COMMENT '逻辑删除:0=正常,1=已删除',
PRIMARY KEY (`id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8mb4
COLLATE = utf8mb4_0900_ai_ci COMMENT ='订单信息表';