【MongoDB】使用 MongoDB 存储日志、审批、MQ等数据的案例及优点
文章目录
- 使用MongoDB存储日志数据
- 使用MongoDB存储MQ数据
- 使用MongoDB存储审批数据
- 队列与MongoDB的差异
更多相关内容可查看
在 64 位系统上,使用 ext4 文件系统,文件大小可以达到 16TB(这只是文件系统层面的限制,实际情况还会受到磁盘空间等因素影响)。MongoDB 单个文档大小限制在 16MB(这是为了保证性能和避免过度复杂的文档结构)
使用MongoDB存储日志数据
示例如下:这是一个在单据中进行操作的日志记录,根据这种形式,在生产系统异常或者业务单据出问题的时候,可以根据这个记录来找到对应的人员的具体操作来进行复现或者排查问题
{
"_id": {
"$oid": "63e5a63468e6eb0c443122d9"
},
"code": "YON-CUSTOMER002",
"sender": "FT-CODE",
"receiver": "YON-BASIC",
"status": "70",
"indexinfo": "63e5a63368e6eb0c443122d8",
"ticket": "1105B6A44C61455B3C1D58865D0CBE16",
"logtime": {
"$date": "2023-02-10T02:04:36.148Z"
},
"runtime": 0,
"accessdata": {
"senderContenttype": "JSON",
"sender": "FT-CODE",
"receiver": "YON-BASIC",
"uiRequest": false,
"acscode": "YON-CUSTOMER002",
"data": "{\"ufinterface\":{\"account\":\"01\",\"bill\":{\"billhead\":{\"code\":\"CC2210140006\",\"custprop\":\"0\",\"custstate\":\"1\",\"enablestate\":\"2\",\"ename\":\"123\",\"issupplier\":\"N\",\"legalbody\":\"\",\"memo\":\"\",\"name\":\"测试待审的编码是什么样\",\"pk_areacl\":\"\",\"pk_billtypecode\":\"FT-CODE.Ccode.InfoChange\",\"pk_country\":\"HKG\",\"pk_custclass\":\"0\",\"pk_financeorg\":\"\",\"pk_format\":\"ZH-CN\",\"pk_group\":\"01\",\"pk_org\":\"01\",\"pk_supplier\":\"\",\"pk_timezone\":\"P0800\",\"registerfund\":\"\",\"shortname\":\"\",\"taxpayerid\":\"\",\"tel1\":\"\"},\"id\":\"CC2210140006\"},\"billtype\":\"customer\",\"groupcode\":\"01\",\"isexchange\":\"Y\",\"orgcode\":null,\"receiver\":null,\"replace\":\"Y\",\"roottag\":\"bill\",\"sender\":\"default\"}}",
"head": {
"urlParams": {},
"requestHead": {
"access_token": "cff458a25a7d7cf2de7770477aae9d27",
"signature": "04b8f3732ff1c3fe7aa4772686cabf9fd80f839db72d622dca4119b2a9399a03",
"client_id": "N9"
}
},
"parameters": {},
"disableReplaceUserSession": false
},
"responsedata": "{\"success\":true,\"data\":{\"ufinterface\":{\"filename\":\"customer186391138490000default.xml\",\"billtype\":\"customer\",\"sender\":\"default\",\"replace\":\"Y\",\"roottag\":\"sendresult\",\"isexchange\":\"Y\",\"sendresult\":[{\"bdocid\":\"CC2210140006\",\"filename\":\"customer186391138490000default.xml\",\"resultdescription\":\"单据 CC2210140006 开始处理...\\n单据 CC2210140006 处理完毕!\\n\",\"resultcode\":\"1\",\"content\":\"1001A1100000000G4YZP\"}],\"successful\":\"Y\"}},\"code\":\"1000000000\",\"message\":\"0\",\"errorStack\":null}",
"timeelapsed": {
"$numberLong": "852"
},
"modifydate": {
"$date": "2023-02-10T02:04:36.148Z"
},
"_class": "snsoft.acs.vo.AccessLog"
}
通过MongoDB存日志信息的好处
:其灵活的数据模型可轻松适应多样且多变的日志结构,高效写入性能得益于高并发写入
支持与异步写入
机制,能快速处理大量日志且不阻塞应用;强大查询功能借助丰富查询语言和索引优化
,可按多种条件精准检索
;数据可扩展性通过水平分片方便存储增长,副本集保障高可用性
,即便面对海量日志数据,也能保证系统稳定、查询便捷且数据安全可靠,有效满足日志存储与管理需求。
使用MongoDB存储MQ数据
案例背景:
假设有一个电商平台,包含订单处理系统、库存管理系统、物流配送系统等多个子系统。这些子系统之间需要进行大量的数据交互与协作,并且要求数据具有一定的持久化和可追溯性,以应对系统故障、数据统计与分析等需求。因此,引入消息队列(MQ)来解耦各个子系统之间的通信,并选择 MongoDB 作为 MQ 数据的存储介质。
场景一:订单状态更新消息存储与处理
- 数据流转:当用户在电商平台下单后,订单处理系统会生成一条包含订单详细信息(如订单号、用户信息、商品信息、订单金额等)以及初始订单状态(如已提交)的消息,并将其发送到 MQ 中。
- MongoDB 存储:这条消息会被 MQ 消费者接收后,存储到 MongoDB 的一个专门用于存储订单消息的集合中。在 MongoDB 中,该消息以文档形式存储,例如:
{
"messageId": "123456789",
"orderId": "987654321",
"user": {
"userId": "user123",
"username": "John Doe",
"email": "johndoe@example.com"
},
"products": [
{
"productId": "prod1",
"productName": "Product A",
"quantity": 2
},
{
"productId": "prod2",
"productName": "Product B",
"quantity": 1
}
],
"orderStatus": "Submitted",
"timestamp": "2024-01-15T10:00:00Z"
}
- 后续处理:库存管理系统订阅了 MQ 中的订单消息,当它从 MongoDB 中获取到该订单消息后,会根据订单中的商品信息进行库存扣减操作。如果库存扣减成功,库存管理系统会向 MQ 发送一条库存更新成功的消息,同时更新 MongoDB 中该订单消息的状态为“库存已扣减”。物流配送系统则会根据订单状态的变化,在合适的时候安排商品配送,并将配送信息也更新到 MongoDB 中的订单消息文档中。这样,通过 MongoDB 存储 MQ 数据,各个子系统可以方便地获取订单消息的历史状态和详细信息,便于数据统计、订单跟踪以及故障排查。
场景二:用户行为数据收集与分析
- 数据收集:电商平台的前端会收集用户的各种行为数据,如浏览商品、添加购物车、搜索关键词等行为信息。这些数据会被封装成消息发送到 MQ 中。
- MongoDB 存储:MQ 消费者将这些用户行为消息存储到 MongoDB 的用户行为数据集合中。例如:
{
"behaviorId": "abcdefg",
"userId": "user456",
"action": "Browse",
"productId": "prod3",
"timestamp": "2024-01-15T10:30:00Z"
}
- 分析利用:数据分析师可以定期从 MongoDB 中查询和提取这些用户行为数据,进行数据分析和挖掘。例如,通过分析用户浏览商品的历史数据,可以为用户推荐相关的商品,提高用户购买转化率;或者通过分析用户搜索关键词的趋势,调整平台的商品营销策略。由于 MongoDB 提供了丰富的查询功能和灵活的数据模型,数据分析师可以方便地根据不同的分析需求构建查询条件,快速获取所需的用户行为数据子集,并进行相应的分析处理。
场景三:系统异常消息记录与监控
- 异常捕获与发送:在电商平台各个子系统运行过程中,如果发生异常情况(如数据库连接失败、网络超时、业务逻辑错误等),系统会将异常信息封装成消息发送到 MQ 中。
- MongoDB 存储:MQ 消费者将这些异常消息存储到 MongoDB 的异常消息集合中,例如:
{
"errorId": "hijklmn",
"system": "Inventory Management",
"errorMessage": "Database connection refused",
"timestamp": "2024-01-15T11:00:00Z"
}
- 监控与处理:运维团队可以通过定期查询 MongoDB 中的异常消息集合,及时发现系统中出现的异常情况,并采取相应的措施进行修复。同时,通过对异常消息的统计和分析,可以发现系统中存在的潜在问题和薄弱环节,提前进行优化和改进,提高系统的稳定性和可靠性。
使用 MongoDB 存储 MQ 数据在电商平台这样的复杂系统中具有重要意义,它能够有效地解耦各个子系统之间的通信,保证数据的持久化和可追溯性,并且方便各个业务环节对数据进行处理、分析和利用,从而提升整个系统的性能、可靠性和业务价值。
使用MongoDB存储审批数据
示例:tasklist中就是多个节点的审批信息,可以看到在存审批信息的同时,会存很多信息,例如商户id,岗位,部门,公司,组织,人员,时间,审批意见等等信息,通过这种json格式可以很直观的看出来更多的层级结构
{
"_id": {
"$oid": "643752438d135646505d14b0"
},
"apprsign": 1,
"bcode": "BD2135",
"corpbcode": "C00004",
"cuicode": "C000000002",
"innercode": "C000000002000000000331",
"kvmap": {
"outercode": "JY23040004"
},
"modifydate": {
"$date": "2023-04-13T05:26:06.920Z"
},
"opensheeturl": "UIID:JYT-TRD.TX.Ship.JYTSalShipDetail",
"outercode": "JY23040004",
"predate": {
"$date": "2023-04-12T09:43:11.000Z"
},
"sheetcode": "JYT-TRD.TX.Ship.JYTSalShip",
"smdate": {
"$date": "2023-04-13T05:24:48.593Z"
},
"smucode": "C00000000200003",
"status": "30",
"taskid": "JYT-TRD.TX.Ship.JYTSalShip.C000000002000000000331",
"version": 0,
"wcode": "D614506",
"wfcode": "JY002",
"tasklist": [
{
"cuicode": "C000000002",
"gwcode": "G0005",
"idx": 1,
"modifier": "C00000000200003",
"modifydate": {
"$date": "2023-04-13T05:25:41.902Z"
},
"performdate": {
"$date": "2023-04-13T05:25:41.982Z"
},
"performexpl": "同意",
"performhost": "127.0.0.1",
"performshost": "BF-RUN-ALL",
"performstat": 1537,
"performucode": "C00000000200003",
"pidx": 0,
"puid": "10",
"rflags": 2621440,
"rmode": 1,
"sheetcode": "JYT-TRD.TX.Ship.JYTSalShip",
"sheetvcode": "JY23040004",
"submitdate": {
"$date": "2023-04-13T05:25:11.737Z"
},
"submitmode": 0,
"submitucode": "C00000000200003",
"submitucode1": "C00000000200003",
"submituidx0": 0,
"taskflag": 2,
"taskid": "JYT-TRD.TX.Ship.JYTSalShip.C000000002000000000331",
"taskname": "外销出运单-交货单",
"tasktitle": "外销出运单",
"tasktype": 0,
"ucode": "C00000000200496",
"uidx": 1,
"version": 0,
"wfcode": "JY002",
"wfuid": "3020"
},
{
"cuicode": "C000000002",
"gwcode": "G0003",
"idx": 2,
"modifier": "C00000000200003",
"modifydate": {
"$date": "2023-04-13T05:26:02.077Z"
},
"performdate": {
"$date": "2023-04-13T05:26:02.167Z"
},
"performexpl": "同意",
"performhost": "127.0.0.1",
"performshost": "BF-RUN-ALL",
"performstat": 1537,
"performucode": "C00000000200003",
"pidx": 1,
"puid": "3020",
"rflags": 2621440,
"rmode": 0,
"sheetcode": "JYT-TRD.TX.Ship.JYTSalShip",
"sheetvcode": "JY23040004",
"submitdate": {
"$date": "2023-04-13T05:25:41.902Z"
},
"submitmode": 0,
"submitucode": "C00000000200003",
"submitucode0": "C00000000200496",
"submitucode1": "C00000000200003",
"submituidx0": 1,
"taskflag": 2,
"taskid": "JYT-TRD.TX.Ship.JYTSalShip.C000000002000000000331",
"taskname": "外销出运单-预对货",
"tasktitle": "外销出运单",
"tasktype": 0,
"ucode": "C00000000200520",
"uidx": 1,
"version": 0,
"wfcode": "JY002",
"wfuid": "3030"
},
{
"cuicode": "C000000002",
"gwcode": "G0005",
"idx": 3,
"modifier": "C00000000200003",
"modifydate": {
"$date": "2023-04-13T05:26:06.920Z"
},
"performdate": {
"$date": "2023-04-13T05:26:06.995Z"
},
"performexpl": "同意",
"performhost": "127.0.0.1",
"performshost": "BF-RUN-ALL",
"performstat": 1537,
"performucode": "C00000000200003",
"pidx": 2,
"puid": "3030",
"rflags": 2097152,
"rmode": 1,
"sheetcode": "JYT-TRD.TX.Ship.JYTSalShip",
"sheetvcode": "JY23040004",
"submitdate": {
"$date": "2023-04-13T05:26:02.077Z"
},
"submitmode": 0,
"submitucode": "C00000000200003",
"submitucode0": "C00000000200520",
"submitucode1": "C00000000200003",
"submituidx0": 1,
"taskflag": 2,
"taskid": "JYT-TRD.TX.Ship.JYTSalShip.C000000002000000000331",
"taskname": "外销出运单-海运确认",
"tasktitle": "外销出运单",
"tasktype": 0,
"ucode": "C00000000200496",
"uidx": 1,
"version": 0,
"wfcode": "JY002",
"wfuid": "3040"
},
{
"cuicode": "C000000002",
"gwcode": "G0003",
"idx": 4,
"modifier": "C00000000200003",
"modifydate": {
"$date": "2023-04-13T05:26:06.920Z"
},
"performstat": 0,
"pidx": 3,
"puid": "3040",
"rflags": 0,
"rmode": 0,
"sheetcode": "JYT-TRD.TX.Ship.JYTSalShip",
"sheetvcode": "JY23040004",
"submitdate": {
"$date": "2023-04-13T05:26:06.920Z"
},
"submitmode": 0,
"submitucode": "C00000000200003",
"submitucode0": "C00000000200496",
"submituidx0": 1,
"taskflag": 1,
"taskid": "JYT-TRD.TX.Ship.JYTSalShip.C000000002000000000331",
"taskname": "外销出运单-派车前对货",
"tasktitle": "外销出运单",
"tasktype": 0,
"ucode": "C00000000200520",
"uidx": 1,
"version": 0,
"wfcode": "JY002",
"wfuid": "3050"
}
],
"displaytext": null,
"odate": null,
"finishdate": {
"$date": "2023-04-13T06:33:21.115Z"
}
}
存审批数据的优势:
-
水平扩展方便
- 随着审批业务的增长,数据量可能会急剧增加。MongoDB支持水平扩展,通过分片(Sharding)技术可以将数据分布在多个服务器上。例如,当审批流数据量达到一定程度,可以将不同部门的审批数据分布到不同的分片服务器上,这样可以有效地处理大量的审批数据,提高系统的存储和处理能力。
-
应对高并发读写场景
- 在审批系统中,可能会同时有多个用户发起审批流程或者查询审批进度。MongoDB能够很好地应对这种高并发读写的情况。它使用了内存映射文件(mmap)等技术来提高读写性能,并且可以通过配置副本集(Replica Set)来实现读写分离,将读操作分布到多个副本节点上,减轻主节点的压力,提高系统的整体并发性能。
-
丰富的查询语法
- MongoDB提供了强大的查询语言,对于审批流数据的查询非常方便。例如,可以轻松地查询某个审批流程的状态、某个审批人的所有审批记录、某个时间段内的审批流程等。如查询所有部门经理张三审批过的采购审批流程:
db.approvalProcess.find({ "steps.approver": "张三", "processName": "采购审批" });
- 它支持多种查询操作符,如
$in
、$gt
、$lt
、$regex
等,可以根据不同的业务需求灵活地构建查询条件。
-
索引优化查询性能
- 为了提高查询效率,可以为经常查询的字段建立索引。例如,为审批流程的
processId
、processName
和steps.approver
等字段建立索引:
db.approvalProcess.createIndex({ "processId": 1, "processName": 1, "steps.approver": 1 });
- 这样在进行相关查询时,可以大大加快查询速度,提高系统的响应性能。
- 为了提高查询效率,可以为经常查询的字段建立索引。例如,为审批流程的
-
副本集保障数据安全和高可用
- MongoDB的副本集机制可以自动复制数据到多个节点。在审批系统中,这意味着即使某个节点出现故障,其他副本节点仍然可以提供数据服务,保证审批业务的连续性。例如,一个包含主节点和两个副本节点的副本集,当主节点发生故障时,副本节点可以自动选举出新的主节点,确保系统的正常运行。
-
数据一致性保障
- 副本集可以通过配置不同的写策略来保证数据一致性。例如,可以选择“多数派写确认(w:majority)”策略,确保在大多数副本节点确认写入成功后才返回成功信息,这样可以有效避免数据丢失和不一致的情况。
队列与MongoDB的差异
以下是对于这个问题的回答:
一、数据持久化和可靠性方面
-
队列的局限性
- 消息队列(MQ)主要用于在不同系统组件之间传递消息,它侧重于消息的传递和异步处理。大多数消息队列采用内存存储或者基于临时文件的存储方式来缓存消息。例如,像RabbitMQ默认将消息存储在内存中(虽然也有持久化配置选项),如果服务器突然断电或者MQ进程意外崩溃,还在队列中的消息可能会丢失。
- 消息队列的重点是确保消息的高效传递,对于消息的长期存储和数据备份没有像数据库那样强大的机制。它不能很好地提供复杂的备份策略、数据恢复功能以及数据完整性保证。
-
MongoDB的优势
- MongoDB是一个专业的数据库管理系统,它具有强大的数据持久化功能。当我们把订单状态更新消息存储到MongoDB中时,这些数据会被持久化存储到磁盘上,并且MongoDB会有一系列的数据备份和恢复机制,如副本集(Replica Set)可以确保数据在多个节点上进行备份,即使某个节点出现故障,数据也不会丢失。
- 对于像订单这种关键业务数据,数据的完整性和可靠性至关重要。MongoDB可以通过事务(在支持事务的版本中)或者文档级别的原子操作来保证数据在存储过程中的一致性,防止数据出现不一致的情况,比如防止部分订单状态更新成功而另一部分失败的情况。
二、数据查询和分析方面
-
队列的局限性
- 消息队列的查询功能相对较弱。它主要是为了按照一定的顺序(如先进先出)传递消息,虽然可以根据消息的某些属性(如消息ID、消息类型等)进行简单的查找,但对于复杂的查询操作,如查询特定时间段内的所有订单状态更新消息、查询某个用户的所有订单状态变化历史等,消息队列很难满足这样的需求。
- 而且消息队列一般不提供像数据库那样的索引机制来优化查询性能。如果我们要在消息队列中进行复杂的数据统计和分析,会非常困难。
-
MongoDB的优势
- MongoDB提供了丰富的查询语言。我们可以使用它方便地查询各种订单状态更新消息,例如,可以使用
$gt
和$lt
操作符来查询在某个时间范围(如过去一天、过去一周)内的订单状态更新消息,或者使用$in
操作符来查询包含特定订单状态(如已支付、已发货)的消息。 - 还可以为经常查询的字段(如订单号、用户ID、订单状态等)建立索引,大大提高查询速度。此外,MongoDB的数据模型是文档型的,非常适合存储像订单状态更新这样的复杂数据结构。我们可以方便地在一个文档中存储订单的所有相关信息以及其状态变化历史,便于进行数据挖掘和分析,例如分析订单状态转换的平均时间、不同状态下的订单数量分布等。
- MongoDB提供了丰富的查询语言。我们可以使用它方便地查询各种订单状态更新消息,例如,可以使用
三、系统间解耦和协作方面
-
队列的角色和局限性
- 消息队列在系统间解耦方面起到了关键作用,它使得各个系统(如订单处理系统、库存管理系统、物流配送系统)能够异步通信。但是,它只是一个消息传递的中间件,当一个系统需要获取另一个系统已经处理过的历史消息或者状态时,消息队列不能很好地提供这种功能。
- 例如,库存管理系统可能需要查看某个订单之前的状态更新历史来核对库存扣减是否正确,消息队列很难满足这种需要查看历史消息状态的需求。
-
MongoDB的优势
- 当把订单状态更新消息存储到MongoDB后,各个系统可以方便地从数据库中获取订单状态更新的历史记录。这有助于系统之间更好地协作,例如,物流配送系统可以根据订单状态更新的历史记录来调整配送计划,客服系统可以查询订单状态更新历史来回答用户关于订单状态的询问。MongoDB在这里起到了一个数据中心的作用,使得不同系统可以共享和利用订单状态更新数据,进一步增强了系统间的解耦和协作。