点赞系统设计(微服务)

news/2025/1/12 14:23:40/

点赞业务是一个常见的社交功能,它允许用户对其他用户的内容(如帖子、评论、图片等)表示喜欢或支持。在设计点赞业务时,需要考虑以下几个方面:

一、业务需求

点赞业务需要满足以下特性:

  1. 通用:点赞业务在设计的时候不要与业务系统耦合,必须同时支持不同业务的点赞功能。
  2. 独立:点赞功能是独立系统,并且不依赖其它服务,这样才具备可迁移性。
  3. 并发:一些热点业务点赞会很多,所以点赞功能必须支持高并发。
  4. 安全:要做好并发安全控制,避免重复点赞。
二、实现思路

为了保证安全,避免重复点赞,我们需要保存每一次点赞记录。同时,因为业务方经常需要根据点赞数量排序,因此每个业务的点赞数量也需要记录下来。

三、技术架构

在实现点赞业务时,主要用到了以下技术和工具:

  • 该点赞业务实现通过微服务架构、数据库存储、Redis 缓存、消息队列和定时任务等技术,实现了通用、独立、高并发和安全的点赞功能。
  • 通过 Nacos 进行服务的配置管理和服务发现,确保服务的可扩展性和配置的灵活性。
  • 采用 RabbitMQ 进行消息的异步传递,实现了点赞操作和点赞数更新的解耦,同时使用 Feign 实现服务间通信,方便不同服务调用点赞服务。
  • 利用 Redis 优化高并发读写操作,通过定时任务定期将 Redis 中的点赞数同步到数据库,确保数据的最终一致性。
四、数据库表设计

点赞的数据结构分两部分,一是点赞记录,二是与业务关联的点赞数。点赞数与具体业务表关联在一起记录,比如互动问答的点赞,就在问答表中记录点赞数。学员笔记点赞,自然是在笔记表中记录点赞数。

点赞表设计如下:

create database tj_remark;
use tj_remark;CREATE TABLE IF NOT EXISTS `liked_record` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键id',`user_id` bigint NOT NULL COMMENT '用户id',`biz_id` bigint NOT NULL COMMENT '点赞的业务id',`biz_type` VARCHAR(16) NOT NULL COMMENT '点赞的业务类型: qa-回答 note-笔记',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`),UNIQUE KEY `idx_biz_user` (`biz_id`,`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='点赞记录表';
五、微服务设计:

模块创建:创建一个独立的微服务来处理点赞业务。
依赖管理:添加必要的依赖,如数据库驱动、Redis、MQ等。
配置文件:配置服务的端口、数据库连接、缓存配置、消息队列配置等。
启动类:创建启动类,配置服务的基本信息和扫描路径。
代码生成:使用代码生成工具生成基本的代码框架和数据库操作类。

六、接口设计:
  1. 点赞/取消点赞接口
    • 接口路径/like
    • 请求方法POST
    • 请求参数
      • bizId:业务ID,标识被点赞的对象
      • bizType:业务类型,如qa表示问答,note表示笔记等
    • 响应:无返回值,200表示成功
  2. 查询是否点赞接口
    • 接口路径/isLiked
    • 请求方法GET
    • 请求参数
      • bizId:业务ID,标识被查询的对象
      • bizType:业务类型,如qa表示问答,note表示笔记等
    • 响应
      • liked:布尔值,表示用户是否已经点赞该对象

这些接口将满足用户点赞和查询点赞状态的需求。

七、业务流程

我们先梳理一下点赞业务的几点需求:

  • 用户不能重复点赞
  • 点赞就新增一条点赞记录,取消点赞就删除记录
  • 点赞数由具体的业务方保存,需要通知业务方更新点赞数

由于业务方的类型很多,比如互动问答、笔记、课程等,所以通知方式必须是低耦合的,这里建议使用MQ来实现。

当点赞或取消点赞后,点赞数发生变化,我们就发送MQ通知。整体业务流程如图:

新增点赞功能实现

● 逻辑说明:
○ 接收 LikeRecordFormDTO 作为请求参数,包含业务信息。
○ addLikeRecord 方法根据 recordDTO 的 liked 属性判断是点赞还是取消点赞操作,调用 liked 或 unliked 方法。
○ liked 方法先检查用户是否已点赞,若未点赞则保存点赞记录;unliked 方法则删除用户的点赞记录。
○ 操作成功后,通过 RabbitMqHelper 发送 MQ 消息,通知其他服务点赞数发生了变化,消息发送到指定的交换器和路由键,内容包含业务 id 和点赞次数。

监听点赞数变更

● 在相关业务服务(如 tj-learning)中添加 MQ 监听器,监听点赞数变更的消息并更新数据库。
● 逻辑说明:
○ 使用 @RabbitListener 监听特定交换器和路由键的消息。
○ 收到消息后,将消息中的点赞数更新到相应业务表中,如 InteractionReply 表。

查询点赞状态功能实现

● 逻辑说明:
○ 接收一个业务 id 列表作为参数。
○ 通过 lambdaQuery 查询用户对这些业务是否已点赞。
○ 最终将用户已点赞的业务 id 以集合形式返回。

暴露 Feign 接口

在 tj-api 模块中定义 RemarkClient 作为 Feign 客户端,用于其他微服务调用点赞服务:

java">@FeignClient(value = "remark-service", fallbackFactory = RemarkClientFallback.class)
public interface RemarkClient {//批量查询我的点赞状态@GetMapping("/likes/list")Set<Long> getLikedIds(@RequestParam("bizIds") List<Long> bizIds);
}

同时定义 RemarkClientFallback 作为服务降级处理:

java">@Slf4j
public class RemarkClientFallback implements FallbackFactory<RemarkClient> {@Overridepublic RemarkClient create(Throwable cause) {log.error("查询点赞服务异常", cause);return new RemarkClient() {@Overridepublic Set<Long> getLikedIds(List<Long> bizIds) {return null;}};}
}
调用

在查询回复或者评论的时候远程调用点赞微服务查询是否点过赞

八、优化思路

高并发读的优化:1. 优化SQL和代码 2. 添加缓存

高并发写的优化:1. 优化SQL和代码 2. 变同步写为异步写 3. 合并写请求

  • 引入 Redis 缓存 ○ 使用 Redis 存储点赞记录和点赞数,以应对高并发问题。
    ○ 存储点赞记录使用 Set 数据结构,存储点赞数使用 ZSet 数据结构。
    ○ 点赞操作(addLikeRecord)通过 Redis 的 SADD 或 SREM 命令操作点赞记录,统计点赞数使用 SCARD 命令。

  • 使用定时任务 ○ 创建定时任务类 LikedTimesTask,使用 @XxlJob 注解,调用 readLikedTimesAndSendMQ 方法。
    ○ 该方法从 Redis 中读取点赞数,转换数据后发送 MQ 消息,更新其他服务的点赞数。
    • 该方法从 Redis 中读取点赞数,转换数据后发送 MQ 消息,更新其他服务的点赞数。
java">@Component
@Slf4j
public class LikedTimesTask {@Autowiredprivate ILikedRecordService likedRecordService;@XxlJob("checkLikedTimes")public ReturnT<String> checkLikedTime(String param) {log.info("开始同步点赞次数");likedRecordService.readLikedTimesAndSendMQ();return ReturnT.SUCCESS;}
}

http://www.ppmy.cn/news/1562530.html

相关文章

《拉依达的嵌入式\驱动面试宝典》—计算机网络篇(一)

《拉依达的嵌入式\驱动面试宝典》—计算机网络篇(一) 你好,我是拉依达。 感谢所有阅读关注我的同学支持,目前博客累计阅读 27w,关注1.5w人。其中博客《最全Linux驱动开发全流程详细解析(持续更新)-CSDN博客》已经是 Linux驱动 相关内容搜索的推荐首位,感谢大家支持。 《…

基于华为ENSP的OSPF不规则区域划分深入浅出(5)

本篇技术博文摘要 &#x1f31f; OSPF不规则区域划分及其问题解决方案涉及多个技术手段&#xff0c;包括隧道、虚链路和路由重发布等。合理的网络设计和配置对于避免网络中出现的环路问题至关重要。通过多进程双向重发布等方式&#xff0c;能够有效地优化路由协议的互通性和网络…

人工智能之基于阿里云快速搭建Llama-3.2-11B-Vision-Instruct

人工智能之基于阿里云快速搭建Llama-3.2-11B-Vision-Instruct 需求描述 基于阿里云搭建图片生成文字模型&#xff0c;模型名称&#xff1a;LLM-Research/Llama-3.2-11B-Vision-Instruct使用上述模型输入图片生成文字&#xff0c;模型路径 业务实现 阿里云配置 阿里云配置如…

数据库事务:确保数据一致性的关键机制

1. 什么是数据库事务 定义&#xff1a;事务&#xff08;Transaction&#xff09;是数据库管理系统中的一个逻辑工作单元&#xff0c;用于确保一组相关操作要么全部成功执行&#xff0c;要么全部不执行&#xff0c;从而维护数据的一致性和完整性。重要性&#xff1a;在多用户环…

iOS实际开发中使用Alamofire实现多文件上传(以个人相册为例)

引言 在移动应用中&#xff0c;图片上传是一个常见的功能&#xff0c;尤其是在个人中心或社交平台场景中&#xff0c;用户经常需要上传图片到服务器&#xff0c;用以展示个人风采或记录美好瞬间。然而&#xff0c;实现多图片上传的过程中&#xff0c;如何设计高效的上传逻辑并…

夯实前端基础之HTML篇

知识点概览 HTML部分 1. DOM和BOM有什么区别&#xff1f; DOM&#xff08;Document Object Model&#xff09; 当网页被加载时&#xff0c;浏览器会创建页面的对象文档模型&#xff0c;HTML DOM 模型被结构化为对象树 用途&#xff1a; 主要用于网页内容的动态修改和交互&…

宝塔安装mongodb后,写脚本监控运行状态,关闭后自动重启

最近项目用上了mongodb&#xff0c;但是每天晚上 mongodb都回自动关闭&#xff0c;没办法 只能写个监视服务的脚本 在关闭的话就直接重启&#xff0c;创建个计划任务&#xff0c;每三分钟执行一次 # 检查mongo是否还在进程中 countps aux|grep mongo| grep -v grep |wc -l echo…

Cisco认证是Cisco公司建立的网络技术证书体系

思科认证体系是由Cisco公司建立的分为3个层次的网络技术证书体系&#xff0c;随着Cisco产品线的扩大和市场份额的不断提升&#xff0c;Cisco产品从当初仅有的 Cisco路由器和Cisco交换机发展到现在的6大方向&#xff1a;路由交换&#xff0c;网络设计&#xff0c;网络安全&#…