2. 技术选型与架构设计:后端框架选择、消息队列选型、数据库设计原则

好,咱们进入第二章。这一章说白了,就是决定整个消息通知模块的「骨架」该怎么搭。我见过不少项目,一开始没想清楚技术选型,结果后面改得痛不欲生。所以这一章,咱们把后端框架、消息队列、数据库设计这几个核心问题,一次性聊透。

2.1 后端框架选择:Django 还是 Flask?

这个问题,几乎每个做 Python 后端的人都会纠结。我个人习惯是这么判断的:项目规模大、团队人多、需要快速出活,选 Django;项目轻量、高度定制、追求极致性能,选 Flask。

拿咱们这个 OA 系统消息通知模块来说,我建议选 Django。为什么?

  • 自带 Admin 后台:消息记录、模板管理、用户配置,直接开箱即用。我记得之前用 Flask 做类似功能,光写个后台管理页面就花了两天。
  • ORM 成熟稳定:咱们要处理用户、消息、通知记录这些复杂关系,Django ORM 的关联查询、事务支持都非常顺手。
  • 中间件机制:消息鉴权、日志记录、频率限制,都可以通过中间件优雅实现。
小提示:如果你非要选 Flask,也不是不行。但要做好心理准备——消息通知模块涉及定时任务、WebSocket、多队列消费,这些在 Flask 里都得自己搭轮子。我在项目中遇到过团队用 Flask 硬撑,最后代码里塞满了全局变量和线程管理,维护成本直线上升。

当然,Django 也不是没缺点。它比较「重」,启动慢,ORM 有时候会生成一些奇怪的 SQL。但说实话,对于 OA 系统这种企业级应用,这点代价完全可以接受。

2.2 消息队列选型:Redis 还是 RabbitMQ?

消息队列,是消息通知模块的「心脏」。选错了,后面会非常难受。

咱们先看两个选项的特点:

特性 Redis RabbitMQ
定位 内存数据库,支持消息队列 专业消息中间件
消息持久化 支持(但性能有损耗) 原生支持,可靠性高
消息确认机制 无原生 ACK 支持 ACK、重试、死信队列
复杂度 简单,学习成本低 中等,需要理解 Exchange、Binding 等概念
适用场景 轻量级、高吞吐、允许少量丢消息 金融级、必须保证消息不丢、复杂路由

我的建议是:优先选 Redis。原因有三:

  1. OA 系统消息通知,对消息可靠性要求没那么高。偶尔丢一条通知,用户刷新一下页面就看到了,不会造成经济损失。
  2. Redis 部署简单。很多项目本来就在用 Redis 做缓存,直接复用就行,不用额外维护一套 RabbitMQ 集群。
  3. 性能足够。Redis 的 List 和 Pub/Sub 模式,处理每秒几千条消息完全没问题。
注意:如果你要用 Redis 做消息队列,千万别用 Pub/Sub!Pub/Sub 模式的消息不会持久化,消费者挂了消息就丢了。一定要用 List + BRPOP 或者 Stream 模式。我曾经见过一个项目,上线第一天就因为 Pub/Sub 丢消息被用户投诉了。

那什么时候选 RabbitMQ?嗯,如果你要处理跨系统的消息通知,比如 OA 系统要发消息给 ERP、CRM,而且每条消息都必须落地,那 RabbitMQ 更合适。不过咱们这个课程,先以 Redis 为主。

2.3 数据库设计原则

数据库设计,是消息通知模块的「地基」。地基没打好,后面查询慢、扩展难,哭都来不及。

我总结了几条核心原则:

2.3.1 读写分离,按场景设计表

消息通知模块,典型的「写多读少」。用户发一条消息,可能几百上千人读。所以,写操作要快,读操作要灵活

我一般会设计三张核心表:

  • 消息主表(message):存消息的标题、内容、发送时间、发送人等。每条消息只存一次。
  • 用户消息关联表(user_message):存哪个用户收到了哪条消息,以及是否已读、是否删除等状态。
  • 消息模板表(message_template):存通知模板,比如「您的请假申请已通过」这种固定格式。

你想想看,如果我把用户状态直接塞到消息主表里,那一条消息发 1000 个人,就得存 1000 条重复记录。数据量一上来,查询就炸了。

2.3.2 合理使用索引

索引不是越多越好。我见过有人给每个字段都加了索引,结果写入速度慢得像蜗牛。

对于消息通知模块,重点给这几个字段加索引:

  • user_id:用户查自己的消息,这是最频繁的查询。
  • is_read:查未读消息时用。
  • created_at:按时间排序时用。
核心原则:联合索引优于单列索引。比如 (user_id, is_read, created_at) 这个联合索引,可以覆盖 90% 的查询场景。

2.3.3 考虑数据归档

消息通知数据,增长非常快。一个 500 人的公司,每天发 10 条通知,一年就是 180 万条记录。如果不做归档,数据库迟早扛不住。

我的做法是:按时间分表。比如每个月一张表,或者每季度一张表。查询时根据时间范围路由到对应的表。

嗯,这里要注意,分表之后,跨表查询会变复杂。所以建议在应用层做路由,而不是依赖数据库的联邦查询。

2.3.4 预留扩展字段

消息通知的格式,未来可能会变。比如今天只支持文本,明天要支持图片、链接、甚至小程序卡片。

所以,我习惯在消息主表里加一个 extra_data 字段,类型是 JSON。这样以后加新字段,不用改表结构,直接往 JSON 里塞数据就行。

-- 示例:消息主表结构
CREATE TABLE message (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    content TEXT NOT NULL,
    sender_id INT NOT NULL,
    message_type VARCHAR(50) DEFAULT 'text',
    extra_data JSON,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_sender_time (sender_id, created_at)
);

好了,技术选型和架构设计就聊到这儿。下一章,咱们开始动手搭建开发环境,把 Django 项目跑起来。