DFS最佳实践之MongoDB-GridFS存储通话录音

一、引言
由于业务需求的井喷,对于系统服务的要求越来越高,为了满足系统稳定性、可靠性和可扩展上的发展,以及大量录音数据的分布式存储,为此开发Recdumper录音文件转储服务,将本地磁盘文件上传至MongoDB文件系统GridFS进行存储。Recdumper可配置工作目录,也就是存放录音的根目录。Recdumper会定时扫描该目录,将指定后缀的录音文件上传至MongoDB数据库。另外Recdumper提供Restful接口供系统使用,目的是告知Recdumper需要上传数据库的本地录音文件绝对路径。
注: 所有需要保留的数据均以ObjectID生成规则生成uuid作为文件名保存。
 
二、写入
  1. 定义restful接口,給其他服务调用。支持POST请求,body中包含文件所在路径。实现上采用libevent作为http服务端。
  1. 可支持配置文件的方式,定时遍历录音根目录,将数据存入MongoDB以年月日命名的db表中。
  2. 商定了由外部服务生成ObjectID,使用mongo-c-driver时,定制化修改了ObjectID的生成方式,使用外部传入字符串作为ObjectID,并将ObjectID作为GridFS文件名。
  3. 要留意配置的账号,需要 赋予用户所有数据库的读写权限readWriteAnyDatabase)。如果新建账户,可以这样写:
db.createUser( {user: "admin",pwd: "123456",roles: [ { role: "readWriteAnyDatabase", db: "admin" } ]})
 
 
三、读取
Openresty作为多媒体文件的服务端,以开源lua-resty-moongoo模块和lua脚本处理请求消息,从MongoDB读取录音文件并应答。openresty配置参考:
location ~ ^/records/([-_a-zA-Z0-9/]+).mp3{                                                         
           set $audio_name $1;                                                                          
              content_by_lua_file /usr/local/openresty/record_http_srv.lua;                                
          }
 
四、集群(Replica Sets)
  1. 概览
所有数据库都无法摆脱环境故障的影响。复制提供了一种防备故障的方式。除了避免故障,复制对于数据持久化功能也非常重要。但是要注意的是,虽然可复制集群是冗余的,但是它也无法取代备份机制。备份是过去某个时间点上数据库数据的快照,可复制集群通常是最新的。在通常的规则下,备份是必须的,即使运行了复制机制也需要启动备份。换句话说,备份是为了预防逻辑故障,比如突发性数据丢失或者数据冲突。生产环境下,一定要启用复制和日志功能,除非可以接受数据丢失。
  1. 可复制集(Replica sets)
可复制节点推荐使用的最小配置包含3个节点,在最小配置下,3个节点中的2个节点为第一级别,作为mongod实例。每个都可以作为可复制集的主节点,而且都有数据的完整拷贝。集合中的第3个节点,作为裁判,它不需要复制数据,仅仅作为观察者服务器,裁判是轻量级的MongoDB服务器,它只参与主节点选举,但是不会复制任何数据。
 
通过mongo shell进入主节点的数据库,执行复制集初始化命令
rs.initiate( {
   _id : "COOL",
   members: [
      { _id: 0, host: "192.168.71.137:27017" },
      { _id: 1, host: "192.168.71.137:27018" },
      { _id: 2, host: "192.168.71.137:27019" }
   ]
})
查看复制集状态:
COOL:SECONDARY> rs.status()
{
    "set" : "COOL",
    "date" : ISODate("2020-06-15T09:10:10.347Z"),
    "myState" : 2,
    "term" : NumberLong(1),
    "syncingTo" : "192.168.71.137:27018",
    "syncSourceHost" : "192.168.71.137:27018",
    "syncSourceId" : 1,
    "heartbeatIntervalMillis" : NumberLong(2000),
    "majorityVoteCount" : 2,
    "writeMajorityCount" : 2,
    "optimes" : {
        "lastCommittedOpTime" : {
            "ts" : Timestamp(1592212192, 1),
            "t" : NumberLong(1)
        },
        "lastCommittedWallTime" : ISODate("2020-06-15T09:09:52.622Z"),
        "readConcernMajorityOpTime" : {
            "ts" : Timestamp(1592212192, 1),
            "t" : NumberLong(1)
        },
        "readConcernMajorityWallTime" : ISODate("2020-06-15T09:09:52.622Z"),
        "appliedOpTime" : {
            "ts" : Timestamp(1592212192, 1),
            "t" : NumberLong(1)
        },
        "durableOpTime" : {
            "ts" : Timestamp(1592212192, 1),
            "t" : NumberLong(1)
        },
        "lastAppliedWallTime" : ISODate("2020-06-15T09:09:52.622Z"),
        "lastDurableWallTime" : ISODate("2020-06-15T09:09:52.622Z")
    },
    "lastStableRecoveryTimestamp" : Timestamp(1592212191, 5),
    "lastStableCheckpointTimestamp" : Timestamp(1592212191, 5),
    "electionParticipantMetrics" : {
        "votedForCandidate" : true,
        "electionTerm" : NumberLong(1),
        "lastVoteDate" : ISODate("2020-06-15T09:09:51.633Z"),
        "electionCandidateMemberId" : 1,
        "voteReason" : "",
        "lastAppliedOpTimeAtElection" : {
            "ts" : Timestamp(1592212180, 1),
            "t" : NumberLong(-1)
        },
        "maxAppliedOpTimeInSet" : {
            "ts" : Timestamp(1592212180, 1),
            "t" : NumberLong(-1)
        },
        "priorityAtElection" : 1,
        "newTermStartDate" : ISODate("2020-06-15T09:09:51.637Z"),
        "newTermAppliedDate" : ISODate("2020-06-15T09:09:52.610Z")
    },
    "members" : [
        {
            "_id" : 0,
            "name" : "192.168.71.137:27017",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 572,
            "optime" : {
                "ts" : Timestamp(1592212192, 1),
                "t" : NumberLong(1)
            },
            "optimeDate" : ISODate("2020-06-15T09:09:52Z"),
            "syncingTo" : "192.168.71.137:27018",
            "syncSourceHost" : "192.168.71.137:27018",
            "syncSourceId" : 1,
            "infoMessage" : "",
            "configVersion" : 1,
            "self" : true,
            "lastHeartbeatMessage" : ""
        },
        {
            "_id" : 1,
            "name" : "192.168.71.137:27018",
            "health" : 1,
            "state" : 1,
            "stateStr" : "PRIMARY",
            "uptime" : 28,
            "optime" : {
                "ts" : Timestamp(1592212192, 1),
                "t" : NumberLong(1)
            },
            "optimeDurable" : {
                "ts" : Timestamp(1592212192, 1),
                "t" : NumberLong(1)
            },
            "optimeDate" : ISODate("2020-06-15T09:09:52Z"),
            "optimeDurableDate" : ISODate("2020-06-15T09:09:52Z"),
            "lastHeartbeat" : ISODate("2020-06-15T09:10:08.604Z"),
            "lastHeartbeatRecv" : ISODate("2020-06-15T09:10:09.637Z"),
            "pingMs" : NumberLong(0),
            "lastHeartbeatMessage" : "",
            "syncingTo" : "",
            "syncSourceHost" : "",
            "syncSourceId" : -1,
            "infoMessage" : "",
            "electionTime" : Timestamp(1592212191, 1),
            "electionDate" : ISODate("2020-06-15T09:09:51Z"),
            "configVersion" : 1
        },
        {
            "_id" : 2,
            "name" : "192.168.71.137:27019",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            "uptime" : 28,
            "optime" : {
                "ts" : Timestamp(1592212192, 1),
                "t" : NumberLong(1)
            },
            "optimeDurable" : {
                "ts" : Timestamp(1592212192, 1),
                "t" : NumberLong(1)
            },
            "optimeDate" : ISODate("2020-06-15T09:09:52Z"),
            "optimeDurableDate" : ISODate("2020-06-15T09:09:52Z"),
            "lastHeartbeat" : ISODate("2020-06-15T09:10:08.604Z"),
            "lastHeartbeatRecv" : ISODate("2020-06-15T09:10:08.604Z"),
            "pingMs" : NumberLong(0),
            "lastHeartbeatMessage" : "",
            "syncingTo" : "192.168.71.137:27018",
            "syncSourceHost" : "192.168.71.137:27018",
            "syncSourceId" : 1,
            "infoMessage" : "",
            "configVersion" : 1
        }
    ],
    "ok" : 1,
    "$clusterTime" : {
        "clusterTime" : Timestamp(1592212192, 1),
        "signature" : {
            "hash" : BinData(0,"AAAAAAAAAAAAAAAAAAAAAAAAAAA="),
            "keyId" : NumberLong(0)
        }
    },
    "operationTime" : Timestamp(1592212192, 1)
}
 
 
 
五、备份
复制提供了数据的冗余备份,并在多个服务器上存储数据副本,提高了数据的可用性, 并可以保证数据的安全性。备份则是为了应对灾难,当出现故障时,良好的备份可以节约大量的恢复时间。
对于备份 MongoDB 数据库,有一些通用的规则,如下所示:
  • 使用 mongodump mongorestore
  • 复制原始数据文件
  • 使用 MMS 备份
 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值