即时通讯在医疗环境中的应用:聊天记录的存储与管理

2024-10-03
来源:网络整理

背景

即时通讯(IM),也就是我们常说的IM,其实在很多业务场景中都有或多或少的应用,有些是核心,有些是辅助。

既然是聊天,就不可避免地会产生聊天记录,而且随着人数的增加和时间的推移,聊天记录很容易出现爆发式增长,这实际上给存储带来了很大的压力。

举个大家都熟悉的例子,如果你几分钟不看群聊,再打开就会发现99+条未读消息。

即时通讯技术也适用于医疗环境。

患者到线下医院就医时,必然会与医生产生问答。对于系统来说,这些问题和答案实际上就是聊天记录。

如果把这个场景放到网上,就跟我们平常在微信上聊天一样。

说了这么多,大概的背景已经交代完了,那么我们就来看看聊天记录存储的选择。

技术选型

既然要存储,肯定会有很多选择,包括关系型数据库、非关系型数据库等。

当然,这很大程度上与具体的业务场景相关。没有业务场景,基本上就是一句空话。

医患关系中的聊天记录是非常核心的内容,必须长期保存。它们不会丢失并且可以查询。

而且这些聊天记录与某次咨询是强相关的,所以单独取出几条聊天记录是没有意义的,因为它们没有关联,不能串联起来。

根据以往的经验,在一次会诊中,医患之间的聊天记录大多在50条以下,超过50条的也不在少数。

这可能与其他 IM 场景不同。

当业务开始时,很大概率数据会存储在单库单表中。但这种情况下,单表很容易达到千万、上亿的级别。

后面我们面临的基本上就是分库分表的操作。

分库分表基本上就是根据咨询次数进行哈希,然后放入不同库的不同表中。

这里就会有一个不确定的因素,会分多少个库、多少个表?

分多了,就缺钱;分多了,就缺钱;分多了,就缺钱。如果你分了一点,当再次达到幅度时,你就必须再次分,并开始一场大战。这时候最怕的就是哈希规则被违反。

所以如果你选择的话,在中后期确实会感觉有些力不从心。线性扩展对于这个领域来说还是非常重要的。

如果想要做小的改动,避免分库分表,可以尝试 TiDB,但是它所需要的配置对于中小企业来说是无法接受的,有 80% 以上的概率会通过离开。

/zh/tidb/sta…

聊天保存微信记录的软件_微信聊天记录保存_聊天记录保存

它是一个分布式、无中心、弹性和可扩展的数据库,基于分布式设计和数据模型。

/文档//...

为什么要考虑选择?对于上面提到的医患场景,严格来说,是多写少读。查询基本上只会根据咨询号码。这个是比较清楚的。

2017年,有一篇博客描述了他们如何存储数十亿条消息记录,比较详细。

/如何-…

事实上,他们选择数据库的要求符合大部分IM相关的问题。

老黄也是从这里受到启发,认识了这个数据库。

如果经常比较的话,应该是一个在国内流行,一个在国外流行。

您可以看一下这个比较,以了解两者之间的异同:...

如果选择使用它,那么数据模型的设计一定是各个方面最重要的一步。如果这一步做得不好,基本上就是灾难级别的,玩起来基本上就没啥乐趣了。

所以医患关系中的聊天模式其实是比较简单的。

CREATE TABLE IF NOT EXISTS messages( inq_id text, send_time bigint, sender_id text, sender_role tinyint, msg_type tinyint, msg_body text, PRIMARY KEY (inq_id, send_time) ) WITH CLUSTERING ORDER BY (send_time ASC)

与普通的IM群聊相比,这个咨询号()可以认为是一个群聊,一个频道。

为什么没有消息ID之类的字段?多来源,非自研,无实际意义。

我们来看看C#中如何操作。这里我们使用提供的r客户端。

写:

var cluster = Cassandra.Cluster.Builder() .AddContactPoints("127.0.0.1") .WithDefaultKeyspace("messaging") .Build(); var inqId = "xxxxxx"; var sendTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); var senderId = "xxxx"; var senderRole = 1; var msgType = 1; var msgBody = "zzzz"; string INSERT_SQL = @" INSERT INTO messages(inq_id, send_time, sender_id, sender_role, msg_type, msg_body) VALUES (?, ?, ?, ?, ?, ?) "; var session = cluster.Connect(); var stmt = session.Prepare(INSERT_SQL).Bind(inqId, sendTime, senderId, senderRole, msgType, msgBody)); session.Execute(stmt);

读:

var cluster = Cassandra.Cluster.Builder() .AddContactPoints("127.0.0.1") .WithDefaultKeyspace("messaging") .Build(); var inqId = "xxxxxx"; string GET_MSG_SQL = @" SELECT * FROM messages WHERE inq_id = ? "; var session = cluster.Connect(); var stmt = session.Prepare(GET_MSG_SQL).Bind(inqId); var rowset = session.Execute(stmt); Console.WriteLine("患者\t\t\t\t\t医生"); foreach (var row in rowset) { // 解析从 cassandra 中返回的行 var msg_body = row.GetValue<string>("msg_body"); var sender_role = row.GetValue<sbyte>("sender_role"); if (sender_role == 0) { Console.WriteLine($"{msg_body}\t\t\t\t\t"); } else { Console.WriteLine($"\t\t\t\t\t{msg_body}"); } }

写在最后

存储的选择其实有点棘手。根据不同的应用场景,找到几种更适合当前场景的解决方案,然后选择一种成本不是那么高的方案。

聊天记录的存储还是有一定的优势的。它可以应对高速数据增长,而无需在业务代码层进行太多适配。部署比较简单,没有特殊的依赖,运维成本也比较低。

分享