点赞系统设计(微服务)

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

一、业务需求

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

  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 客户端,用于其他微服务调用点赞服务:

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

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

@Slf4j
public class RemarkClientFallback implements FallbackFactory<RemarkClient> {
    @Override
    public RemarkClient create(Throwable cause) {
        log.error("查询点赞服务异常", cause);
        return new RemarkClient() {
            @Override
            public 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 消息,更新其他服务的点赞数。
@Component
@Slf4j
public class LikedTimesTask {
    @Autowired
    private ILikedRecordService likedRecordService;

    @XxlJob("checkLikedTimes")
    public ReturnT<String> checkLikedTime(String param) {
        log.info("开始同步点赞次数");
        likedRecordService.readLikedTimesAndSendMQ();
        return ReturnT.SUCCESS;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/952870.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络原理一>UDP协议详解

UDP和TCP都是应用层中的重要协议&#xff0c;如果做基础架构开发&#xff0c;会用得多一些。 这一篇我们先简单聊一下的UDP TCP格式呈现&#xff1a; 我们知道UDP是一种无连接&#xff0c;面向数据报&#xff0c;全双工&#xff0c;不可靠传输特性的网络协议。 基本格式如图…

时空笔记:CBEngine(微观交通模拟引擎)

CBEngine 是一个微观交通模拟引擎&#xff0c;可以支持城市规模的道路网络交通模拟。CBEngine 能够快速模拟拥有数千个交叉路口和数十万辆车辆的道路网络交通。 以下内容基本翻译自CBEngine — CBLab 1.0.0 documentation 1 模拟演示 1.0 模拟演示结构 config.cfg 定义了 roa…

金融项目实战 04|JMeter实现自动化脚本接口测试及持续集成

目录 一、⾃动化测试理论 二、自动化脚本 1、添加断言 1️⃣注册、登录 2️⃣认证、充值、开户、投资 2、可重复执行&#xff1a;清除测试数据脚本按指定顺序执行 1️⃣如何可以做到可重复执⾏&#xff1f; 2️⃣清除测试数据&#xff1a;连接数据库setup线程组 ①明确…

20250112面试鸭特训营第20天

更多特训营笔记详见个人主页【面试鸭特训营】专栏 250112 1. TCP 和 UDP 有什么区别&#xff1f; 特性TCPUDP连接方式面向连接&#xff08;需要建立连接&#xff09;无连接&#xff08;无需建立连接&#xff09;可靠性可靠的&#xff0c;提供确认、重传机制不可靠&#xff0c…

导出文件,能够导出但是文件打不开

背景&#xff1a; 在项目开发中&#xff0c;对于列表的查询&#xff0c;而后会有导出功能&#xff0c;这里导出的是一个excell表格。实现了两种&#xff0c;1.导出的文件&#xff0c;命名是前端传输过去的&#xff1b;2.导出的文件&#xff0c;命名是根据后端返回的文件名获取的…

马斯克的Grok-2 Beta APP在苹果应用商店上限了,Grok-2安装尝鲜使用教程

马斯克的Grok-2 Beta APP 已经上线苹果商城了&#xff0c;移动端的Grok挺好用的&#xff01;无需登录即可使用&#xff01; &#xff08;文末有安装教程&#xff09; 实测之后&#xff0c;Grok-2 绘画方面个人感觉比GPT-4的绘画还要强一些。而且速度还挺快&#xff0c;可以多次…

《机器学习》——sklearn库中CountVectorizer方法(词频矩阵)

CountVectorizer方法介绍 CountVectorizer 是 scikit-learn 库中的一个工具&#xff0c;它主要用于将文本数据转换为词频矩阵&#xff0c;而不是传统意义上的词向量转换&#xff0c;但可以作为词向量转换的一种基础形式。用于将文本数据转换为词频矩阵&#xff0c;它是文本特征…

CV 图像处理基础笔记大全(超全版哦~)!!!

一、图像的数字化表示 像素 数字图像由众多像素组成&#xff0c;是图像的基本构成单位。在灰度图像中&#xff0c;一个像素用一个数值表示其亮度&#xff0c;通常 8 位存储&#xff0c;取值范围 0 - 255&#xff0c;0 为纯黑&#xff0c;255 为纯白。例如&#xff0c;一幅简单的…

支持向量回归(SVR:Support Vector Regression)用于A股数据分析、预测

简单说明 支持向量回归是一种用来做预测的数学方法,属于「机器学习」的一种。 它的目标是找到一条「最合适的线」,能够大致描述数据点的趋势,并允许数据点离这条线有一定的误差(不要求所有点都完全落在这条线上)。 可以把它想象成:找到一条「宽带」或「隧道」,大部分…

ollama教程(window系统)

前言 在《本地大模型工具哪家强&#xff1f;对比Ollama、LocalLLM、LM Studio》一文中对比了三个常用的大模型聚合工具优缺点&#xff0c;本文将详细介绍在window操作系统下ollama的安装和使用。要在 Windows 上安装并使用 Ollama&#xff0c;需要依赖 NVIDIA 显卡&#xff0c…

Flink系统知识讲解之:容错与State状态管理

Flink系统知识之&#xff1a;容错与State状态管理 状态在Flink中叫作State&#xff0c;用来保存中间计算结果或者缓存数据。根据是否需要保存中间结果&#xff0c;分为无状态计算和有状态计算。对于流计算而言&#xff0c;事件持续不断地产生&#xff0c;如果每次计算都是相互…

DolphinScheduler自身容错导致的服务器持续崩溃重大问题的排查与解决

01 问题复现 在DolphinScheduler中有如下一个Shell任务&#xff1a; current_timestamp() { date "%Y-%m-%d %H:%M:%S" }TIMESTAMP$(current_timestamp) echo $TIMESTAMP sleep 60 在DolphinScheduler将工作流执行策略设置为并行&#xff1a; 定时周期调度设置…

ASP.NET Core 实现微服务 - Elastic APM

这次要给大家介绍的是Elastic APM &#xff0c;一款应用程序性能监控组件。APM 监控围绕对应用、服务、容器的健康监控&#xff0c;对接口的调用链、性能进行监控。在我们实施微服务后&#xff0c;由于复杂的业务逻辑&#xff0c;服务之间的调用会像蜘蛛网一样复杂。有了调用链…

25/1/12 嵌入式笔记 学习esp32

了解了一下位选线和段选线的知识&#xff1a; 位选线&#xff1a; 作用&#xff1a;用于选择数码管的某一位&#xff0c;例如4位数码管的第1位&#xff0c;第2位&#xff09; 通过控制位选线的电平&#xff08;高低电平&#xff09;&#xff0c;决定当前哪一位数码管处于激活状…

IMX6U Qt 开发环境

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言 一、交叉编译 1. 安装通用 ARM 交叉编译工具链 2. 安装 Poky 交叉编译工具链 二、编译出厂源码 1. U-boot 2. 内核和模块 3. 编译出厂 Qt GUI 综合 Demo 前言…

【Oracle专栏】2个入参,生成唯一码处理

Oracle相关文档&#xff0c;希望互相学习&#xff0c;共同进步 风123456789&#xff5e;-CSDN博客 1.背景 业务需要&#xff1a;2个参数&#xff0c;如 aidbankid &#xff0c;两个值是联合主键&#xff0c;需要生成一个固定唯一码&#xff0c;长度有限制32位&#xff0c;为了…

跨界融合:人工智能与区块链如何重新定义数据安全?

引言&#xff1a;数据安全的挑战与现状 在信息化驱动的数字化时代&#xff0c;数据已成为企业和个人最重要的资产之一。然而&#xff0c;随着网络技术的逐步优化和数据量的爆发式增长&#xff0c;数据安全问题也愈变突出。 数据安全现状&#xff1a;– 数据泄露驱动相关事件驱…

给DevOps加点料:融入安全性的DevSecOps

从前&#xff0c;安全防护只是特定团队的责任&#xff0c;在开发的最后阶段才会介入。当开发周期长达数月、甚至数年时&#xff0c;这样做没什么问题&#xff1b;但是现在&#xff0c;这种做法现在已经行不通了。 采用 DevOps 可以有效推进快速频繁的开发周期&#xff08;有时…

CDP中的Hive3之Hive Metastore(HMS)

CDP中的Hive3之Hive Metastore&#xff08;HMS&#xff09; 1、CDP中的HMS2、HMS表的存储&#xff08;转换&#xff09;3、HWC授权 1、CDP中的HMS CDP中的Hive Metastore&#xff08;HMS&#xff09;是一种服务&#xff0c;用于在后端RDBMS&#xff08;例如MySQL或PostgreSQL&a…

【算法】判断一个链表是否为回文结构

问&#xff1a; 给定一个单链表的头节点head&#xff0c;请判断该链表是否为回文结构 例&#xff1a; 1 -> 2 -> 1返回true&#xff1b;1 -> 2 -> 2 -> 1返回true&#xff1b;15 -> 6 -> 15返回true 答&#xff1a; 笔试&#xff1a;初始化一个栈用来…