☰
PHP客服系统源码实战:朵米3.5架构解析、部署与二次开发避坑指南
2026/10/22 21:21:52 网站建设 项目流程

简介:朵米3.5客服系统源码2023正式版是基于PHP+MySQL开发的全功能客户服务解决方案,面向需要搭建在线客服、统一沟通渠道与客户关系管理场景的中小企业及个人开发者。系统支持在线聊天、邮件、电话等多渠道接入,通过智能分流快速将客户请求分派至合适的客服人员,配合丰富的数据分析与报告功能,可帮助企业了解客户需求并持续优化服务。整个资源包共2000个文件,以js、html、css等前端资源构建交互界面,配合php后端逻辑、sql数据库脚本以及json/xml配置项,另含md说明文档、sh部署脚本等辅助内容,压缩包整体大小43.85MB。压缩包内附完整站点源码、数据库入库文件以及《朵米3.5客服系统安装搭建配置文档v3.docx》,详细说明运行目录、伪静态规则、数据库参数修改等关键步骤,可帮助使用者在宝塔面板+Nginx+PHP7.1-7.3+MySQL5.6-5.7环境中快速完成部署。当前已有384人学习下载,适合作为客服系统二次开发、功能扩展或生产环境搭建的参考范例。

1. 看到“朵米3.5客服系统源码2023正式版”先别急着装:这套源码真正值钱在哪?

看到“朵米3.5客服系统源码2023正式版”这串标题,我先说个反直觉的判断:这套东西最值钱的不是那个能聊天的客服面板,而是它把即时会话、工单、消息存储三条链路揉进了一个 PHP 项目里。不少团队拿它当在线聊天窗口用,对话结束就关页面,数据全躺在 MySQL 里睡大觉;换个思路把它当成接收业务表单、派发工单、沉淀对话记录的中枢,能省下自建客服系统两三个月的开发量,前提是知道它在哪儿使劲、在哪儿会翻车。这篇笔记适合三类人:想本地跑通演示的、准备接进现有业务做二次开发的,以及线上已经跑着、正被各种小毛病折磨的。不列功能清单,直接讲架构、部署、状态机和避坑。

2. 先看懂朵米3.5的架构再动手:PHP 后端、消息通道与数据模型

动手改代码之前,先把链路图在脑子里画出来。朵米 3.5 这类客服源码,不管界面做得多花哨,所有功能最后都能归一到三个对象上:访客发起的「会话」、会话里流动的「消息」,以及需要跨人跨天跟踪的「工单」。很多开发者上手就翻消息表,想着把聊天记录改成自己想要的格式,其实会话的状态机才是客服系统的灵魂,状态没理清,消息和工单都会跟着乱。

2.1 一套源码里三层职责:会话、工单与消息谁管谁

会话是一次完整的服务过程,有生命周期:访客点开对话窗口是「排队中」,客服点接入变成「服务中」,对话结束进入「已结束」。消息是会话里的流水账,每条消息必须挂在某个会话 ID 下面。工单则是从会话里抽出来的任务,比如“退款审核”“技术排查”,它可以跨多个会话持续跟进,不随聊天窗口关闭而消失。

这套源码里常见的设计是三个维度分开管理,代码里通常用一组常量来标识会话状态,类似下面这种结构:

<?php // 会话状态常量定义,二次开发时统一引用,不要直接写数字 define('SESSION_STATUS_QUEUE', 0); // 排队中,等待客服接入 define('SESSION_STATUS_WORK', 1); // 服务中,客服已接入 define('SESSION_STATUS_HOLD', 2); // 挂起,等待访客回复超时 define('SESSION_STATUS_CLOSED', 3); // 已结束,正常关闭 define('SESSION_STATUS_TRANSFER', 4);// 转接中,会话在客服间转移 // 判断当前会话是否允许接收新消息 function session_can_message(int $status): bool { // 只有服务中和挂起状态允许继续收发消息 return in_array($status, [ SESSION_STATUS_WORK, SESSION_STATUS_HOLD, ], true); }

逻辑说明:状态常量是整个客服流转的地基,所有接口在读写消息前都会先过session_can_message这道闸门。排队中或已结束的会话如果收到消息,要么进留言队列,要么直接拒绝,不能写进正常消息表。参数说明:状态值用 0-4 的整数而不是字符串,是为了节省索引空间、方便比对;in_array第三个参数传true开启严格模式,避免字符串"1"被误判成整数 1。

2.2 为什么是 PHP + MySQL,而不是常驻内存服务:这套源码的取舍边界

常见做法是分两条腿走路:普通 HTTP 请求走 PHP-FPM,处理登录、历史记录、工单管理等非实时操作;另起一个独立的 CLI 常驻进程监听消息端口,负责 WebSocket 长连接和消息推送。朵米 3.5 这种体量的项目,一般就是这种 PHP-FPM + CLI 常驻进程的组合,而不是全部跑在 Swoole 常驻服务里。

为什么不推荐把整套系统改成 Swoole 常驻?核心原因有三个。一是兼容性,PHP 常驻服务对全局变量、静态变量的处理方式和 FPM 完全不同,线上改造成本高。二是维护门槛,客服系统的代码通常由业务团队维护,让所有人习惯常驻内存的编程模型,培训成本不小。三是收益不明显,客服场景的并发远低于通用 IM,100 个客服同时在线的团队已经是中大型规模,这个量级下瓶颈在 MySQL 写入,不在 PHP 进程模型。

方案适合规模主要成本稳定性
PHP-FPM + CLI 消息进程10-100 客服消息进程需单独守护高,进程挂了可自动拉起
Swoole 常驻服务1000+ 连接团队学习成本、内存泄漏排查中,需要更精细的运维

参数边界:如果你预估同时在线客服超过 200 人,或者单日消息量超过 20 万条,这套 PHP 方案的 MySQL 写入会成为瓶颈,那时候再考虑迁移消息通道不迟。规模没到这个量级之前,稳定优先。

2.3 核心数据表关系:从访客到一条消息要穿过几张表

打开数据库,常见的数据结构大致是五张核心表:访客表、客服表、会话表、消息表、工单表。访客表记录匿名访客的唯一标识,客服表记录坐席账号,会话表把访客和客服串起来,消息表存聊天流水,工单表存需要跟进的任务。它们的关系是一对多嵌套:一个访客可以发起多个会话,一个会话下面挂多条消息,多个会话可以归并到一个工单。

-- 会话表,核心关联表,几乎所有查询都从这里出发 CREATE TABLE `chat_session` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, `visitor_id` INT UNSIGNED NOT NULL COMMENT '访客ID,关联访客表', `worker_id` INT UNSIGNED NOT NULL DEFAULT 0 COMMENT '客服ID,0表示未接入', `status` TINYINT NOT NULL DEFAULT 0 COMMENT '状态,见PHP常量定义', `channel` TINYINT NOT NULL DEFAULT 1 COMMENT '渠道来源:1网页 2小程序 3APP', `created_at` DATETIME NOT NULL, `accepted_at` DATETIME DEFAULT NULL COMMENT '客服接入时间,用于计算响应时长', `closed_at` DATETIME DEFAULT NULL COMMENT '结束时间', `source_url` VARCHAR(500) DEFAULT '' COMMENT '访客发起对话的页面地址', PRIMARY KEY (`id`), KEY `idx_visitor` (`visitor_id`, `created_at`), KEY `idx_worker_status` (`worker_id`, `status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会话表';

字段说明里最容易被忽略的是accepted_at。很多团队做“首次响应时长”统计时发现数据不对,就是因为接入时间没有在客服点“接入”按钮那一瞬间写库,而是用消息表里第一条客服消息的时间替代,遇到客服先打字后点接入就全算错了。source_url看起来不起眼,但它是事后排查“哪个页面转化率低、哪个页面投诉多”的关键线索,二次开发时不要随手丢掉。

3. 本地跑通朵米 3.5 的最小部署路径:LNMP 与三处必改配置

拿到源码第一步不是急着看代码,而是先把环境对齐。朵米 3.5 这类 PHP 客服系统,最常见的部署环境是 LNMP,也就是 Linux + Nginx + MySQL + PHP。用 Docker 跑也行,但生产环境我一般建议直接装在裸机上,少一层网络转发就少一个排查变量。下面这套路径我反复走过很多遍,照着做基本半小时内能跑起来。

3.1 环境准备与源码放置:PHP 版本和扩展先对齐

先确认 PHP 版本和扩展。这套源码按 2023 正式版的常见依赖,PHP 7.4 是最稳妥的选择,PHP 8.0 以上部分老代码会有兼容问题,后面避坑章节会专门讲。必要扩展包括pdo_mysql、redis(如果做队列)和mbstring。

# 查看当前PHP版本和已安装扩展 php -v php -m | grep -E 'pdo_mysql|mbstring|redis' # 如果扩展缺失,以Debian/Ubuntu为例安装 sudo apt-get install -y php7.4-cli php7.4-fpm php7.4-mysql php7.4-mbstring # 装完后确认扩展已加载 php -m | grep pdo_mysql

逻辑说明:这套源码靠 PDO 连 MySQL,mbstring处理中文消息的截断和编码转换,少了这两个扩展会在访客发中文消息时出现乱码或直接白屏。参数说明:php7.4这个版本号要和你系统里的实际版本对应,在 CentOS 上包名通常是php74-php-mysqlnd这种带前缀的写法,装之前先yum list installed | grep php看清楚再动手。

3.2 建库导表与 Nginx 站点配置:伪静态和消息端口一起解决

源码上传到站点目录后,第一件事是建库导表。很多预打包源码会带一个install.sql或db.sql,直接用命令行导入比用 phpMyAdmin 上传大文件可靠得多。

# 创建数据库并导入初始表结构 mysql -uroot -p -e "CREATE DATABASE IF NOT EXISTS duomi_chat DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" mysql -uroot -p duomi_chat < /var/www/duomi/db/install.sql # 确认核心表已生成 mysql -uroot -p -e "USE duomi_chat; SHOW TABLES;"

导入完成后配置 Nginx。客服系统和普通博客最大的区别是:页面请求走 PHP-FPM,消息推送走独立的 WebSocket 端口,两者在 Nginx 里要分开处理。

# /etc/nginx/conf.d/duomi.conf server { listen 80; server_name chat.example.com; root /var/www/duomi/public; # 入口目录,按实际源码结构调整 index index.php; # 业务接口全部走PHP-FPM location / { try_files $uri $uri/ /index.php?$query_string; } location ~ \.php$ { include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; fastcgi_pass unix:/run/php/php7.4-fpm.sock; } # 消息推送的WebSocket路径,反代到CLI常驻进程端口 location /ws { proxy_pass http://127.0.0.1:8280; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 3600s; } }

逻辑说明:根路径先按静态文件找,找不到再交给index.php做路由分发。/ws专门转发长连接流量,proxy_read_timeout必须设大,否则 Nginx 默认 60 秒就会切断 WebSocket 连接,导致客服那边“明明在线却收不到消息”。参数说明:8280端口要和源码里消息进程的实际监听端口一致,如果改端口,Nginx 和源码配置必须同步修改。

3.3 三处必改参数:内存、超时、连接数

每次部署新环境,我拿到手的第一件事就是改这三处,不改后面必出问题。第一处是php.ini里的资源限制;第二处是 MySQL 的连接数;第三处是消息进程的守护方式。

; /etc/php/7.4/fpm/php.ini memory_limit = 256M ; 客服系统页面加载历史消息列表时比较吃内存,128M容易超限 max_execution_time = 60 ; 导出聊天记录、批量操作工单时防止脚本被掐断 post_max_size = 64M ; 上传图片、文件作为附件时会用到,太小会静默失败 upload_max_filesize = 50M

MySQL 端,默认的max_connections在客服这种长连接场景下经常不够。每个客服工作台会同时占用一个 HTTP 连接和一个 WebSocket 连接,加上后台定时任务,100 个客服在线就能吃掉两三百个连接。建议至少改成 512。

# /etc/mysql/mysql.conf.d/mysqld.cnf [mysqld] max_connections = 512 wait_timeout = 300 interactive_timeout = 600

参数说明:wait_timeout调小的目的是让死连接快速释放,避免 MySQL 被“僵尸连接”占满。最后一步,消息进程必须用守护方式启动,不能直接nohup扔后台完事,否则进程一崩消息通道就静默罢工了。

# 使用systemd守护消息进程,假设入口脚本是 start_chat_server.php cat > /etc/systemd/system/duomi-chat.service <<'EOF' [Unit] Description=Duomi Chat Message Server After=network.target mysql.service [Service] WorkingDirectory=/var/www/duomi ExecStart=/usr/bin/php /var/www/duomi/bin/chat_server.php Restart=always RestartSec=3 [Install] WantedBy=multi-user.target EOF systemctl daemon-reload systemctl enable --now duomi-chat

逻辑说明:Restart=always保证进程挂了 3 秒内自动拉起,这是客服系统最不能省的一道防线。我见过很多团队把消息进程挂在前台终端里,一关 SSH 窗口客服就集体掉线,改成 systemd 托管之后这类问题彻底消失。

4. 二次开发绕不开的三块硬骨头:状态机、消息顺序与工单流转

部署跑通只是开始,真正常被拉去改需求的是这三块:会话状态机、消息入库顺序、工单流转逻辑。这三块改不好,线上就会出现“客服明明接了单却收不到消息”“用户发最后一句没存上”“工单莫名其妙消失了”等灵异现象。多数时候不是源码 bug,而是改代码的人没搞懂内部约定。

4.1 会话状态机:排队、接入、转接、结束的状态迁移

会话状态机的核心约束是:非法迁移不能发生。已结束的会话不能被重新接入,排队中的会话不能被直接关闭。常见的实现是写一个专门的状态迁移函数,所有入口统一调它。

<?php // 统一状态迁移入口,禁止在业务代码里直接UPDATE状态字段 function session_transition(int $sessionId, int $newStatus, int $operatorId): bool { // 读取当前会话信息,这里应走缓存减少DB压力 $session = get_session_by_id($sessionId); $old = (int)$session['status']; // 状态迁移合法性映射:只允许以下流转 $allowed = [ SESSION_STATUS_QUEUE => [SESSION_STATUS_WORK, SESSION_STATUS_CLOSED], SESSION_STATUS_WORK => [SESSION_STATUS_HOLD, SESSION_STATUS_TRANSFER, SESSION_STATUS_CLOSED], SESSION_STATUS_HOLD => [SESSION_STATUS_WORK, SESSION_STATUS_CLOSED], SESSION_STATUS_TRANSFER => [SESSION_STATUS_WORK, SESSION_STATUS_CLOSED], ]; if (!isset($allowed[$old]) || !in_array($newStatus, $allowed[$old], true)) { // 记录非法迁移日志,便于追查是谁在绕过状态机 log_states("illegal_transition", $sessionId, $old, $newStatus, $operatorId); return false; } return update_session_status($sessionId, $newStatus); }

逻辑说明:$allowed数组画出了状态迁移的“白名单”,比如排队中可以直接关闭(访客取消咨询),但不能直接转接,因为还没接入的会话没有可转接的客服。所有外部入口,包括客服点击“接入”“转接”“结束”,最终都调session_transition,而不是各自 UPDATE 数据库。参数说明:$operatorId必须传,出问题时要能追溯到“谁在什么时间把会话从什么状态改成了什么状态”,这是客服系统审计的基本要求。

4.2 消息入库与推送的顺序:先落库再广播,顺序反了会丢消息

这是客服系统最典型的翻车点。新手喜欢先推送 WebSocket 再写数据库,觉得这样消息送达快。但推送是有可能失败的:客户端断网、服务端进程重启、中间链路超时,任何一步出错,这条消息就人间蒸发了。正确的顺序是先落库、再推送。

<?php function send_message(int $sessionId, string $content, int $senderType): array { // 第一步:写入消息表,拿到自增ID作为消息唯一标识 $msgId = insert_message($sessionId, $content, $senderType, time()); // 第二步:推送WebSocket,带上刚生成的msgId $pushResult = ws_push_to_session($sessionId, [ 'msg_id' => $msgId, 'content' => $content, 'sender_type' => $senderType, 'ts' => time(), ]); // 第三步:推送失败时写入待补偿队列,由定时任务重推 if (!$pushResult) { push_fail_queue_add($msgId, $sessionId); } return ['msg_id' => $msgId, 'pushed' => $pushResult]; }

逻辑说明:先 insert 后 push,推送失败还有数据库这条底账,定时任务可以捞出来重推;如果先 push 后 insert,推送成功但 insert 失败,客户端能看到消息,刷新页面后消息却消失了,用户会坚定地认为你们系统吞消息。参数说明:$senderType区分访客和客服,推送时客户端要根据这个字段决定消息气泡显示在左边还是右边,传反了会出现客服自己发的消息显示在访客侧。

4.3 工单流转:把聊天记录变成可跟踪的任务

工单的价值在于把“聊过的事情”变成“要做的事情”。常见逻辑是:客服在会话界面点“创建工单”,系统把当前会话的关键信息快照到工单表,并关联会话 ID。这里有坑:很多新手工单只存了工单标题和内容,没存访客 ID 和会话 ID,过几天想回头看上下文,发现根本连不回去。

<?php function create_ticket_from_session(int $sessionId, int $workerId, string $title, string $content): int { // 获取会话关联的访客信息和原始诉求摘要 $session = get_session_by_id($sessionId); $visitorId = $session['visitor_id']; // 同一访客同一会话不重复建单,避免客服手抖连点 $exists = find_ticket_by_session_id($sessionId); if ($exists) { return (int)$exists['id']; } $ticketId = insert_ticket([ 'session_id' => $sessionId, 'visitor_id' => $visitorId, 'worker_id' => $workerId, 'title' => $title, 'content' => $content, 'status' => 0, // 0待处理 1处理中 2已完成 3已关闭 'created_at' => date('Y-m-d H:i:s'), ]); // 创建后自动把会话状态置为挂起,聊天窗口提示“已创建工单” session_transition($sessionId, SESSION_STATUS_HOLD, $workerId); return $ticketId; }

逻辑说明:session_id是工单回溯上下文的关键外键,visitor_id是为了跨会话聚合同一个人的所有工单。创建成功后把会话置为挂起而不是结束,是因为用户可能还要补充信息,挂起状态下访客可以继续回复。参数说明:工单状态建议用整数状态机管理,不要直接 UPDATE,和会话状态机同理,否则工单流转记录一查一个乱。

5. 避坑清单:部署朵米 3.5 最常见的五个翻车现场

这套源码我前后经手过不少部署和二次开发,踩过的坑和帮别人排过的坑都集中在这五个点上。每一条都是“现象 - 原因 - 解决”的结构,排查顺序也是我验证过的,按这个顺序走能少走两小时弯路。

5.1 排查顺序:日志、端口、会话表三件套

遇到“客服收不到消息”“访客发了消息没反应”之类的问题,别急着翻源码,先按下面三步定位,通常十分钟内能找到方向。

# 第一步:看消息进程有没有活着,端口有没有在监听 netstat -tlnp | grep 8280 systemctl status duomi-chat # 第二步:看PHP日志里有没有报错 tail -f /var/log/php7.4-fpm.log # 第三步:看数据库里最新几条消息是否落库了 mysql -uroot -p duomi_chat -e "SELECT id, session_id, content, created_at FROM chat_message ORDER BY id DESC LIMIT 5;"

逻辑说明:第一步排除进程层问题,第二步排除代码层报错,第三步确认数据是否进了库。如果消息落库了但客户端收不到,问题在推送链路;如果没落库,问题在入站处理。参数说明:8280换成你实际配置的端口,日志路径也随发行版不同而不同,CentOS 上通常是/var/log/php-fpm/www-error.log。

5.2 现象一:客服工作台一直“连接中”或一直转圈

这是最高频的问题。现象是客服登录后台能看到会话列表,但点进去一直转圈,或者右上角状态永远是“连接中”。原因通常是 WebSocket 握手失败,大部分情况是 Nginx 没配置好Upgrade头,少部分是消息进程监听端口被防火墙挡住。

解决办法:先确认服务端端口可达,再确认 Nginx 的/ws反代配置。我在 3.2 节里写的proxy_set_header Connection "upgrade"是重点,少一行握手就失败。很多系统默认带了 Nginx,但默认配置里没有这段 WebSocket 专有设置,直接套用就会踩坑。

5.3 现象二:最后一条消息偶发丢失,用户记录里查不到

现象是用户说“我发了消息客服没回”,后台查消息记录里确实没有那条。原因大概率是消息推送到客户端了但没入库。很多团队为了省时间会临时改代码“先 push 后 insert”,或者消息处理进程异常退出导致后续流程中断。

解决办法:按 4.2 节的顺序重构,先落库再推送,并且给消息表加一个“推送补偿”的扫描任务,每五分钟扫一次消息表,把推送状态为失败的消息重推一遍。这个补偿机制能兜住绝大多数偶发丢失。

5.4 现象三:高版本 PHP 下页面白屏或函数报错

现象是安装文档明明写着“支持 PHP 7.0-8.0”,但用 PHP 8.1 跑起来直接白屏。查日志看到类似call_user_func传参方式变化、each()函数被移除之类的问题。这是因为这套源码按 2023 年之前的老写法写的,某些内置函数和传参规则在 PHP 8 里被废弃或严格化了。

解决办法:如果只是演示,装 PHP 7.4 最省事;如果生产环境已有 PHP 8.2 且不能降级,需要全局排查each()、create_function()这类老函数,把它们替换成等价的现代写法。这是一个体力活,但不用改业务逻辑,纯兼容层改动。

5.5 现象四:数据库连接被打满,MySQL 报 too many connections

现象是早晨一上班,客服系统集体报错,MySQL 提示连接数超限。原因有两层:一是工作台每个标签页都会建一个长连接,客服开了多个标签页就把连接数翻倍;二是 MySQL 的默认连接数只有 151,按 100 个客服算完全不不够分。

解决办法:先把max_connections调到 512 以上,再把客服端的 WebSocket 连接做单例复用,一个浏览器只保持一个长连接,不要每个会话标签页各连一次。最后监控show processlist里的Sleep线程,如果大量堆积,调低wait_timeout到 120 秒左右。

5.6 现象五:定时任务不触发,工单超时无人管

现象是工单设置了“24 小时未响应自动升级”,但从来没见升级过。原因是源码里的定时任务依赖系统的 cron,而部署时根本没有配 crontab。这类源码一般会在文档里提一句“将以下命令加入 crontab”,但很多人只看安装步骤就跳过去了。

# 每5分钟执行一次消息补偿 */5 * * * * php /var/www/duomi/bin/compensate_message.php # 每10分钟执行一次工单超时扫描 */10 * * * * php /var/www/duomi/bin/ticket_timeout_check.php systemctl reload crond

参数说明:定时任务的执行频率要和业务需求匹配,工单超时扫描不建议超过 15 分钟一次,否则用户等很久没反馈;消息补偿也不要短于 30 秒,太频繁会把数据库拖垮。

6. 进阶:把朵米 3.5 的会话记录变成运营指标

部署稳定、二次开发告一段落之后,这套源码还能再挖一层价值:把聊天记录转成可量化指标。客服系统每天产生大量会话数据,很多团队只用来“查记录”,浪费了。这里说两个最实用、也最容易算错的操作。

先算首次响应时长。这个指标的算法是:访客发出第一条消息的时间,到客服接入会话的时间,取差值。注意用的是chat_session.accepted_at减去chat_message里该会话第一条访客消息的created_at,不是客服第一条回复的时间。

SELECT s.id AS session_id, TIMESTAMPDIFF(SECOND, first_msg.created_at, s.accepted_at) AS first_response_seconds FROM chat_session s LEFT JOIN ( SELECT session_id, MIN(created_at) AS created_at FROM chat_message WHERE sender_type = 0 -- 0访客 1客服 GROUP BY session_id ) first_msg ON first_msg.session_id = s.id WHERE s.accepted_at IS NOT NULL AND s.created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY) ORDER BY first_response_seconds DESC LIMIT 50;

逻辑说明:sender_type = 0滤掉客服消息,取每个会话里最早的访客消息时间做基准;TIMESTAMPDIFF直接算秒数,方便后续按分钟聚合。如果发现大量会话的响应时间是负数,说明接入时间记录有问题,回到 2.3 节检查accepted_at是否正确写入。

第二个习惯是历史消息归档。客服系统跑半年后,消息表轻松破百万行,统计查询会越来越慢,影响线上写入。我一般会在数据库里给chat_message建分区,按月分区,或者每季度把三个月前的数据迁移到独立的归档库。业务代码不需要改,查询历史记录时路由到归档库即可。很多团队拖到慢查询告警才处理,那时表已经 500 万行了,凌晨全表扫描把 CPU 跑满,客服体验瞬间崩塌。

最后分享一个习惯:每次发布版本前,我会在测试环境跑一遍“消息补偿模拟”——手动断开一个客服的 WebSocket,然后发一条消息,等 5 分钟,看重推任务能不能把消息补上。这套系统最怕的不是功能缺失,而是数据悄悄丢了用户还不知道。把数据完整性的验证脚本固化到发布流程里,比什么都重要。这个习惯救过我很多次,希望也能帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询