MongoDB - mongo 的数据监听

目录

一、 基于主从复制机制的oplog进行信息获取

1-1 mongodb单实例开启oplog

1-2 oplog的基本操作

1-3 基于pymongo的简单操作

1-3-1 oplog 对象获取

1-3-2 mongo 时间戳处理

1-3-3 多条件查询

1-4 Python 监控脚本实现

1-5 Tornado WS + Oplog watcher 的简单实现

二、 基于自定义log进行监听

三、在数据进行存储的时候触发后续执行(耦合)


一、 基于主从复制机制的oplog进行信息获取

1-1 mongodb单实例开启oplog

MongoDB 单机开启Oplog

OPLOG 官方文档

MongoDB - mongo 的数据监听_第1张图片

replication:
  oplogSizeMB: 50
  replSetName: rs

MongoDB - mongo 的数据监听_第2张图片

rs.initiate({ _id: "副本集名称", members: [{_id:0,host:" 服务器的IP : Mongo的端口号 "}]})
​
rs.initiate({ _id: "rs", members: [{_id:0,host:"127.0.0.1:27017"}]})

!!注意:如果数据库的数据量不大,并且长时间初始这种过渡状态(SECONDARY或OTHER),去看实例的日志,也显示无进展,此时可以考虑重启服务。

MongoDB - mongo 的数据监听_第3张图片MongoDB - mongo 的数据监听_第4张图片

1-2 oplog的基本操作

  • rs.printReplicationInfo() 查看 oplog 的状态,输出信息包括 oplog 日志大小,操作日志记录的起始时间。
  • db.getReplicationInfo() 可以用来查看oplog的状态、大小、存储的时间范围。

MongoDB - mongo 的数据监听_第5张图片

  • db.oplog.rs.find() 查看oplog所有信息对象
  • db.oplog.rs.findOne() 查看oplog最新的一条数据
  • ts:8字节的时间戳,由4字节unix timestamp + 4字节自增计数表示。

    • 在选举(如master宕机时)新primary时,会选择ts最大的那个secondary作为新primary。

  • op:1字节的操作类型

    • i-insert、u-update、d-delete、c-db cmd、db-声明当前数据库 (其中ns 被设置成为=>数据库名称+ ‘.’))n -no op,即空操作,其会定期执行以确保时效性 。

  • ns:操作所在的namespace,即操作的位置

    • 集合操作:db.$cmd - "ns" : "test.$cmd"

    • 文档操作:db.collection - "ns" : "test.testtable"

  • o:操作所对应的document,即当前操作的内容(比如更新操作时要更新的的字段和值)

    • 操作集合:{“操作类型”:“集合名”} - {“drop”:“collname”}

    • 操作文档:{“_id”:objectid("……"),"字段名":”新值“}

      { "_id" : ObjectId("5ced025109424945184f9012"), "test" : "hello document new" } }

  • o2: 在执行更新操作时的where条件,仅限于update时才有该属性

MongoDB - mongo 的数据监听_第6张图片

1-3 基于pymongo的简单操作

1-3-1 oplog 对象获取

# 获取oplog
conn = pymongo.MongoClient()
oplog = conn.local.oplog.rs
print(oplog.find_one())
# {'ts': Timestamp(1562125608, 1), 'h': 6404608878882061907, 'v': 2, 'op': 'n', 'ns': '', 'o': {'msg': 'initiating set'}}
​

1-3-2 mongo 时间戳处理

# ts处理 -官方文档- http://api.mongodb.com/python/current/api/bson/timestamp.html
new_record = oplog.find_one()
ts = new_record['ts']
print(ts)  # Timestamp(1562125608, 1)
print(type(ts)) # 
print(ts.as_datetime()) # 2019-07-03 03:46:48+00:00
print(ts.time) # 1562125608
print(ts.inc)  # 1
​
# 通过time.time() + arrow 获取对应时间戳
import arrow
def time2timestamp(t):
    a = arrow.get(t)
    return a.timestamp
print(time2timestamp(time.time())) # 1562138596
​
# time 时间戳转 mongodb 时间戳
now = time2timestamp(time.time())
mongo_time = Timestamp(now, 1)
myquery = {"ts": {"$lt": t}}
n = oplog.find_one(myquery)

1-3-3 多条件查询

mongodb 多条件查询 - 官方文档

# db.inventory.find( { $and: [ { price: { $ne: 1.99 } }, { price: { $exists: true } } ] } )
# ts 大于,并且,ns 等于
query = {"$and": [{"ts": {"$gt": t}}, {"ns": {"$eq": "test.testtable"}}]}

1-4 Python 监控脚本实现

利用Mongo数据库的oplog机制实现准实时数据操作监控

实现思路总结

  • 当前时间戳作为临界点,截取脚本之间内的数据对象(例,脚本60s执行一次,则获取与当前时间相差60s内的数据对象)
  • 对数据对象组,根据对应op(操作类型)和ns(操作对象),过滤出监控对象
  • 定时执行脚本
import time
import arrow
import pymongo
from bson import Timestamp
​
​
class OplogWatcher:
    def __init__(self, ):
        self.oplog = pymongo.MongoClient('mongodb://localhost:27017/').local.oplog.rs
​
    def get_all_date(self):
        '''
        无过滤,获取所有数据,慎用
        :return: date list ;[{},{}]
        '''
        data = self.oplog.find()
        data_list = [i for i in data]
        return data_list
​
    def data_time_filter(self, poll_time=60):
        '''
        根据推前时间,获取符合时间区间的对象
        :param poll_time: 时间区间,默认为60s
        :return: 数据对象列表 [{},{}]
        '''
        now_timestamp = self.time2timestamp(time.time())
        time_offline = now_timestamp - poll_time
        offline_mongotime = Timestamp(time_offline, 1)
        # 获取时间区间内的数据,即大于等于时间下限 - 时间区间:[offline,now]
        mongo_query = {"ts": {"$gte": offline_mongotime}}
        data = self.oplog.find(mongo_query)
        data_list = [i for i in data]
        return data_list
​
    def data_ns_filter(self, data_list, ns):
        '''
        处理数据列表,根据ns进行分对象监听
        :param data_list: 数据列表[{},{}]
        :param ns: 监视对象 str类型,"db.doc" or "db"
        :return:过滤后的数据列表 [{},{}]
        '''
        if '.' in ns:
            ns_filter = ns
        else:
            ns_filter = '%s.$cmd' % ns
        filter_list = []
        for data in data_list:
            if data['ns'] == ns_filter:
                filter_list.append(data)
        return filter_list
​
    def data_op_filter(self, data_list, op_types):
        '''
        根据操作类型进行过滤
        :param data_list:数据列表 [{}、{}]
        :param op_types: list,[i,u,d,c,db,n]
        :return:过滤后的数据字典 [{}、{}]
        '''
        filter_list = []
        for data in data_list:
            if data['op'] in op_types:
                filter_list.append(data)
        return filter_list
​
    def time2timestamp(self, t):
        a = arrow.get(t)
        return a.timestamp
​
​
if __name__ == '__main__':
    ow = OplogWatcher()
    # data_all_list = ow.get_all_date()
    # print(data_all_list)
    data_all_list = ow.data_time_filter()
    ns_filter_list = ow.data_ns_filter(data_all_list, 'test.testtable')
    op_filter_list = ow.data_op_filter(ns_filter_list, ['i', 'u'])
    # print(op_filter_list)
    if op_filter_list:
        print('业务逻辑')

1-5 Tornado WS + Oplog watcher 的简单实现

WebSocket - Tornado 的基本实现总结

二、 基于自定义log进行监听

三、在数据进行存储的时候触发后续执行(耦合)

你可能感兴趣的:(NoSQL)