本文主要介绍使用MongoDB C驱动读取分布式MongoDB集群时遇到的坑,主要在读取优先级和匹配tag上;同时简单介绍Python驱动、Node.js驱动、Mongoose驱动如何使用读取优先级和匹配tag。
前提:MongoDB集群为 replica set shard,部署可以参考:MongoDB搭建Replica Set Shard Cluster步骤。 读取优先级和tag相关知识可参考官方文档:read-preference.

1 MongoDB C 驱动编译安装

(1)下载最新的MongoDB C Driver ,https://github.com/mongodb/mongo-c-driver/releases,下载发布版本,当前为mongo-c-driver-1.3.0 
(2)解压编译:
./configure --prefix=/home/users/cswuyg/test_mongodb/mongo_c_13/install  --enable-example --enable-ssl=no --enable-static
make
make install
注1:如果gcc不在默认路径下,需要把它加入到环境变量PATH中。
注2:我不使用ssl所以disable掉。

3 使用C驱动

简单的CRUD文档都有demo,就不多说了。
比较旧版本的libmongoc可能会有这样的提示:
mongoc驱动出现info提示:Unexpectedly connected to sharded cluster
这个是因为libmongoc要求必须有两个以上的mongos地址,mongoc_client_new加上地址就行,eg:
mongoc_client_t* client = mongoc_client_new("mongodb://xxx:27030,yyy:27030/?w=1"); 

3 遇到的坑

在使用MongoDB C Driver时,发现无法使用nearest模式读取数据,而可以count到数据。也就是
mongoc_collection_count 成功了,而mongoc_collection_find却失败了。
 
我们的应用部署在四地机房,不设置nearest而使用其它参数会导致数据读取耗时从5ms下降到60ms,我又不希望大集群拆散成小集群(为了容灾、在线数据更新),所以,这个问题要解决。
重新编译驱动,打开trace日志:
./configure --prefix=/home/users/cswuyg/test_mongodb/mongo_c_13/install  --enable-example --enable-ssl=no --enable-static --enable-tracing
再编译测试代码,跑起来。
查看到日志里有这样的trace信息:
 
关键字:Failed to call say, no good nodes in
google一下,确定是由于tag所致,驱动文档里并没有告知需要设置tag,这是坑1。
加上一个空的tag解决:
  1. mongoc_read_prefs_t* read_prefs = mongoc_read_prefs_new(MONGOC_READ_NEAREST);
  2. bson_t* tag = bson_new();
  3. mongoc_read_prefs_add_tag(read_prefs, tag);
  4. bson_destroy(tag);
  5. mongoc_cursor_t* cursor = mongoc_collection_find(collection, MONGOC_QUERY_NONE, , , , query, NULL, read_prefs); 
接着,我想试试tag,让某个应用只访问某地机房,又遇到问题:
  1. bson_t* tag = bson_new();
  2. BSON_APPEND_UTF8(tag, "location", "bj");
  3. mongoc_read_prefs_add_tag(read_prefs, tag);
  4. bson_destroy(tag);
这样子使用一直无法通过,找到源码里的test代码,才知道必须有一个NULL结尾,tag要这样子写:
  1. bson_t* tag = bson_new();
  2. BSON_APPEND_UTF8(tag, "location", "bj");
  3. mongoc_read_prefs_add_tag(read_prefs, tag);
  4. mongoc_read_prefs_add_tag(read_prefs, NULL);
  5. bson_destroy(tag);
这是坑2。
api文档中没有提及,文档中也没有相应的demo提醒,只能从源码中找到测试代码查看到使用方法。
这两个问题在网络上没有搜索到很直接的解答,所以掉坑里了。更多的人可能是通过uri来使用优先读取功能,所以不会碰到这个问题。所以,这里是使用uri的demo:
 C代码都比较长,不放在博客,demo代码见github:test_c_driver.cpp 

4 其它驱动

相比之下,MongoDB的Python驱动或者Node驱动要友好得多。
Python 驱动
  1. #!/home/work/bin/python
  2. # test find with tag_set
  3. # cswuyg @ 2014.7.18
  4. # install pymongo pre.
  5.  
  6. import pymongo
  7. import time
  8.  
  9. REMOTE_ADDRESS = "xxxxhost"
  10. REMOTE_PORT = 27030
  11. def _test_find():
  12. f_w = open("test", 'w')
  13. #client = pymongo.MongoClient(REMOTE_ADDRESS, 27030, readPreference='nearest')
  14. rpre = pymongo.read_preferences.Secondary(tag_sets = [{'location': 'gz'}])
  15. client = pymongo.MongoClient(REMOTE_ADDRESS, REMOTE_PORT, read_preference=rpre) # 注意这里的read_preference
  16. s = time.time()
  17. docs = client.myapp.myuser.find({'name': 'cswuyg'})
  18. with open('tmp.txt', 'w') as f_w:
  19. for item in docs:
  20. f_w.write(str(item))
  21. f_w.write('\n')
  22.  
  23. e = time.time()
  24. print(e - s)
  25.  
  26. if __name__ == "__main__":
  27. _test_find()
参考文档:http://api.mongodb.org/python/current/examples/high_availability.html
 
MongoDB Node 原生驱动 
  1. /*
  2. * 测试 mongodb 驱动 耗时
  3. * cswuyg @ 2015.12.29
  4. */
  5. "use strict";
  6. var mongodb = require('mongodb');
  7. var assert = require('assert');
  8. var fs = require('fs');
  9. var url = 'mongodb://xxxhost:27030/myapp?w=1&readPreference=nearest&readPreferenceTags=location:bj'; //在uri上设置读取优先级和tag
  10.  
  11. var findDocuments = function(collection, callback) {
  12. collection.find({'name': 'cswuyg'}).limit(1).toArray(function(err, docs) {
  13. callback(docs);
  14. });
  15. }
  16.  
  17. mongodb.MongoClient.connect(url, function(err, db) {
  18. assert.equal(null, err);
  19. console.log("Connected correctly to server");
  20. var col = db.collection('myuser');
  21. var s = new Date().getTime();
  22. findDocuments(col, function(docs) {
  23. var writerStream = fs.createWriteStream('tmp.txt');
  24. writerStream.write(JSON.stringify(docs[0]), 'UTF8');
  25. writerStream.end();
  26. var e = new Date().getTime();
  27. console.log(e - s);
  28. });
  29. });
 
Node Mongoose 驱动
可以在Schema层面、Query层面设置读取模式,没看到可以像原生驱动那样在uri中指定读取模式。
但是,我实际测试的时候,发现如果使用的是MongoS,则在schema上指定tag无效,它始终去找最近的那个实例。而且必须在createConnection中指定option参数{mongos: true},否则在Query层面指定的tag也会无效。所以最终解决方案就是必须加上mongos:true,且在Query层面指定读取优先级。
  1. /*
  2. * * 测试 mongoose 耗时
  3. * * cswuyg @ 2015.12.29
  4. * */
  5. "use strict";
  6.  
  7. var mongoose = require('mongoose');
  8. var fs = require('fs');
  9. var connect = mongoose.createConnection('mongodb://xxxhost:27030, yyyhost:27030/myapp', {mongos: true}); //注意mongos
  10.  
  11. var schema = {name: {type: String}};
  12. var colSchema = new mongoose.Schema(schema, {collection: 'myuser'});
  13. var model = connect.model('myuser', colSchema);
  14.  
  15. setTimeout(function() {
  16. var s = new Date().getTime();
  17. var query = new mongoose.Query({'name': 'cswuyg'}).read('n', [{location:'nj'}]); //Query层面设置读取优先级和tag
  18. model.find(query).exec(function(err, doc) {
  19. var writerStream = fs.createWriteStream('output.txt');
  20. writerStream.write(doc.toString(), 'UTF8');
  21. writerStream.end();
  22. var e = new Date().getTime();
  23. console.log(e - s);
  24. });
  25.  
  26. }, 1000);
  27.  
  28. setTimeout(function() {
  29. var s = new Date().getTime();
  30. var query = new mongoose.Query({'name': 'cswuyg'}).read('n', [{location:'nj'}]);
  31. model.find(query).exec(function(err, doc) {
  32. var writerStream = fs.createWriteStream('output.txt');
  33. writerStream.write(doc.toString(), 'UTF8');
  34. writerStream.end();
  35. var e = new Date().getTime();
  36. console.log(e - s);
  37. });
  38.  
  39. }, 2000);
参考文档:
 
ps1 耗时比较:
上面谈到到4中驱动C、Python 、Node的两个驱动性能接近,在我的测试中都是20ms左右。异步模式的驱动因为回调,所以会有lazy处理的效果,要setTimeout才能得到query耗时。
ps2 MongoDB集群配置和运维:
MongoDB集群设置相关的可以看下我之前的两篇分享: MongoDB使用小结:一些不常见经验分享  & MongoDB使用小结:一些常用操作分享
 
 

MongoDB 驱动以及分布式集群读取优先级设置的更多相关文章

  1. 2020重新出发,NOSQL,MongoDB分布式集群架构

    MongoDB分布式集群架构 看到这里相信你已经掌握了 MongoDB 的大部分基本知识,现在在单机环境下操作 MongoDB 已经不存在问题,但是单机环境只适合学习和开发测试,在实际的生产环境中,M ...

  2. spring-session实现分布式集群session的共享

    前言 HttpSession是通过Servlet容器创建和管理的,像Tomcat/Jetty都是保存在内存中的.但是我们把应用搭建成分布式的集群,然后利用LVS或Nginx做负载均衡,那么来自同一用户 ...

  3. spring-session实现分布式集群session的共享(转)

    原文: https://www.cnblogs.com/youzhibing/p/7348337.html HttpSession是通过Servlet容器创建和管理的,像Tomcat/Jetty都是保 ...

  4. mongodb的分布式集群(2、副本集)

    概述        副本集是主从复制的一种,是一种自带故障转移功能的主从复制.攻克了上述主从复制的缺点.实现主server发生问题后.不需人为介入.系统自己主动从新选举一个新的主server的功能. ...

  5. mongodb的分布式集群(4、分片和副本集的结合)

    概述 前面3篇博客讲了mongodb的分布式和集群,当中第一种的主从复制我们差点儿不用,没有什么意义,剩下的两种,我们不论单独的使用哪一个.都会出现对应的问题.比較好的一种解决方式就是.分片和副本集的 ...

  6. mongodb分布式集群搭建手记

    一.架构简介 目标单机搭建mongodb分布式集群(副本集 + 分片集群),演示mongodb分布式集群的安装部署.简单操作. 说明在同一个vm启动由两个分片组成的分布式集群,每个分片都是一个PSS( ...

  7. YCSB测试HBase远程完全分布式集群

    写在前面 本文只讲一个很简单的问题,YCSB对HBase集群的测试.虽然网上有很多介绍YCSB测试HBase的文章,但都是针对本地HBase伪分布式集群的.大家都知道,稍微正式一些的压测都会要求测试客 ...

  8. MongoDB 3.0 常见集群的搭建(主从复制,副本集,分片....)

      一.mongodb主从复制配置 主从复制是mongodb最常用的复制方式,也是一个简单的数据库同步备份的集群技术,这种方式很灵活.可用于备份,故障恢复,读扩展等. 最基本的设置方式就是建立一个主节 ...

  9. elasticsearch 口水篇(5)es分布式集群初探

    es有很多特性,分布式.副本集.负载均衡.容灾等. 我们先搭建一个很简单的分布式集群(伪),在同一机器上配置三个es,配置分别如下: cluster.name: foxCluster node.nam ...

随机推荐

  1. switch case

    Console.WriteLine("1土豆"); Console.WriteLine("2玉米"); Console.WriteLine("3小麦& ...

  2. git无法定位程序输入点libiconv

    使用git clone时,报以下错误: 解决方案: 将git\bin\下的libiconv-2.dll复制到\git\libexec\git-core\下即可

  3. js跳转

    window.location.reload(); //刷新当前页,参数保留

  4. Codeigniter文件上传类型不匹配错误

    Codeigniter的文件上传类方便了我们使用PHP来处理文件上传的操作,使用起来非常简单,如下:   $config['upload_path'] = './uploads/'; $config[ ...

  5. VBA中方法传参

    将变量做为参数传递给方法 Sub Test() Dim a As Integer a = Add a Debug.Print a '引用传递,a的值发生了变化,输出101 End Sub Functi ...

  6. iOS全军覆没!分分钟教你徒手破解iPhone

    http://iphone.tgbus.com/news/class/201503/20150304141407.shtml 破解id密码的最新dns 218.59.181.182

  7. 【译】css动画里的steps()用法详解

    原文地址:http://designmodo.com/steps-c... 原文作者:Joni Trythall 我想你在css 动画里使用steps()会和我一样有很多困惑.一开始我不清楚怎样使用它 ...

  8. java.lang.InstantiationException-反射机制

    package com.test.classtest; public class test { public static void main(String[] args) throws Except ...

  9. 实验一 DOS

    实验一.DOS实验 一.           实验目的 DOS(Disk Operating System)是一个使用得十分广泛的磁盘操作系统,就连眼下流行的Windows9x/ME系统都是以它为基础 ...

  10. linux下安装mysql5.7.17及简单配置

    原文:http://www.th7.cn/db/mysql/201612/218745.shtml 1.mysql5.7.17安装在/usr/local/mysql目录里面,也可以安装在其他地方 (安 ...