MongoDB日志存储系统配置底层存储系统
模式设计
一个典型的Web服务器访问日志包含访问来源、用户、访问的资源地址、访问结果、用户使用的系统及浏览器类型等信息。
127、0.0.1 frank [10/Oct/2000:13:55:36 0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "[http://www.example.com/start.html](http://www.example.com/start.html)" "Mozilla/4.08 [en] (Win98; I ;Nav)"
最简单的方法是将每行日志存储为一个单独的文档,如下所示:
{ _id: ObjectId('4f442120eb03305789000000'), line: '127.0.0.1 frank [10/Oct/2000:13:55:36 0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "[http://www.example.com/start.html](http://www.example.com/start.html)" "Mozilla/4.08 [en] (Win98; I ;Nav)"' }
这种方法虽然简单,但分析起来较为麻烦,更好的方法是提取出各个字段的值并存储在MongoDB文档中。
{ _id: ObjectId('4f442120eb03305789000000'), host: "127.0.0.1", logname: null, user: 'frank', time: ISODate("20001010T20:55:36Z"), path: "/apache_pb.gif", request: "GET /apache_pb.gif HTTP/1.0", status: 200, response_size: 2326, referrer: "[http://www.example.com/start.html](http://www.example.com/start.html)", user_agent: "Mozilla/4.08 [en] (Win98; I ;Nav)" }
如果某些字段对数据分析没有帮助,可以过滤掉以减少存储消耗,不需要存储user
、request
和status
字段,最终可能如下所示:
{ _id: ObjectId('4f442120eb03305789000000'), host: "127.0.0.1", time: ISODate("20001010T20:55:36Z"), path: "/apache_pb.gif", referer: "[http://www.example.com/start.html](http://www.example.com/start.html)", user_agent: "Mozilla/4.08 [en] (Win98; I ;Nav)" }
写日志
日志存储服务需要支持大量日志写入,可以使用writeConcern
来控制日志写入能力。
db.events.insert({ host: "127.0.0.1", time: ISODate("20001010T20:55:36Z"), path: "/apache_pb.gif", referer: "[http://www.example.com/start.html](http://www.example.com/start.html)", user_agent: "Mozilla/4.08 [en] (Win98; I ;Nav)" }, { writeConcern: { w: 0 } })
如果要达到最高写入吞吐,可以指定writeConcern
为{w: 0}
,对于重要日志(如计费凭证),可以使用更安全的writeConcern
级别,如{w: 1}
或{w: "majority"}
,还可以考虑批量写入以提高写入效率:
db.events.insert([doc1, doc2, ...])
查询日志
日志按上述方式存储后,可以按照各种查询需求进行查询。
// 查询所有访问/apache_pb.gif的请求 q_events = db.events.find({'path': '/apache_pb.gif'})
如果这种查询非常频繁,可以针对path
字段建立索引以提高查询效率:
db.events.createIndex({path: 1})
还可以查询某一天的所有请求:
q_events = db.events.find({'time': { '$gte': ISODate("20161219T00:00:00.00Z"),'$lt': ISODate("20161220T00:00:00.00Z")}})
通过在time
字段上建立索引,可以加速这类查询:
db.events.createIndex({time: 1})
数据分片
当写日志的服务节点越来越多时,日志存储的服务需要保证可扩展的日志写入能力和海量的日志存储能力,这时可以使用MongoDB的分片功能来扩展,将日志数据分散存储到多个shard中,分片策略可以根据实际需求定制,以平衡写入性能和查询效率。
FAQs
Q1: 如何优化MongoDB中的日志查询效率?
A1: 为了优化MongoDB中的日志查询效率,可以在经常查询的字段上建立索引,如果经常根据路径查询日志,可以在path
字段上建立索引;如果经常根据时间查询日志,可以在time
字段上建立索引,这样可以显著提高查询速度。
Q2: 如何在MongoDB中实现安全的日志写入?
A2: 为了确保日志的安全写入,可以使用更安全的writeConcern
级别。{w: 1}
表示至少有一个副本节点确认写操作,{w: "majority"}
表示大多数副本节点确认写操作,这些设置可以提高日志写入的安全性,防止数据丢失。