mongo_open 频繁打开 mongo 连接报错 SEVERE: Exception opening socket
脚本主要解释:ipport 是 5 个 mongodb 的 ip 和端口连接。从每个 mongo 读取 10 条数据(排序好的),再通过 A6 进行合并,合并之后再取 10 条数据出来。
当40 个线程(并发),每个线程连续请求 40 次,前半段不报错,后半段报错 SEVERE: Exception opening socket。
如果低于 40 现象不容易出现,出现概率低,测试的时候必须要 40 线程(并发)之上。
SEVERE: Exception opening socket 是在 C2 格子中报出来的错误。
这个错误只是在控制台打印了一下,集算器脚本还在继续执行,会造成返回数据为空。如果不看控制台很难发现这个问题,会造成数据缺失,给用户展示脏数据。
为了验证这个猜想:写了一段代码,频繁建立 mongo 和关闭 mongo,java 程序也会报出这个错误:
public static void main(String[] args) {
for (int i = 0; i < 50; i++) {
new Thread(new Runnable() {
@Override
public void run() {
String ip = SystemProperties.getMongoHost();
int port = SystemProperties.getMongoPort();
for (int j = 0; j < 1000; j++) {
MongoClient mongo = new MongoClient(ip, port);
MongoDatabase db = mongo.getDatabase("8a9e232962fcf6cc016324ed2ada1fb5");
MongoCollection<Document> mongoCollection = db.getCollection("dictionary");
Long count = mongoCollection.countDocuments(new BasicDBObject());
System.out.println(Thread.currentThread().getName()+"|"+count);
mongo.close();
}
}
}).start();
}
}
}
40 个线程同时访问都架不住,怎么解决这个问题呢?java 代码中是用链接池的概念来解决,打开一个 MongoClient,给 MongoClient 设置连接池数量,每次请求 mongo 都是通过这个 MongoClient 来处理,避免每次都会创建 MongoClient 和关闭 MongoClient。
集算器 mongo_open 用法支持连接池的概念吗?
下一版加上对 MongoClient 自带连接池的支持
您好,谢谢您的支持。现在生产环境请求高峰时期,程序会大量报错,这个优化什么时候上线?好尽快升级上去。
http://c.raqsoft.com.cn/article/1657099712711
试过这个?
连接失败时如果能返回错误,直接中断当前查询就行了。容量不够并发量时,本来也不可能保证都能正常返回,峰值时有请求失败是正常的
mongo_shell@dxe 和 mongo_shell@dx 写法,都是打印错误信息,返回 null,并没有抛出异常,终端 fork 函数
![imagepng]()
mongo_shell@dxe 和 mongo_shell@dx 写法,都是打印错误信息,返回 null,并没有抛出异常,fork 函数继续执行
https://mongodb.github.io/mongo-java-driver/4.8/apidocs/mongodb-driver-core/com/mongodb/ConnectionString.html
参见 mongodb 的连接串,支持参数 maxPoolSize
https://www.mongodb.com/docs/drivers/java/sync/v4.3/fundamentals/connection/connect/#std-label-connect-to-mongodb
这里有对 MongoClient 的说明:
You can connect to and communicate with MongoDB using the
MongoClient
class.Use the
MongoClients.create()
method to construct aMongoClient
. As eachMongoClient
represents a thread-safe pool of connections to the database, most applications only require a single instance of aMongoClient
, even across multiple threads. All resource usage limits, such as max connections, apply to individualMongoClient
instances.MongoClient 就是一个线程安全的连接池,正常情况下一个应用只需要 1 个,不需要不停的创建和关闭
咱们集算器的
MongoClient
就是在不停的创建和关闭,不是 a single instance。 这个问题新代码修复了。mongo 游标在并发高,query 查询数据大于 102 条的时候,当 mongo 游标一次没有获取完毕,第二次继续获取数据的时候,报错 SEVERE: Command failed with error 50738 (Location50738): ‘Cannot run getMore on cursor 18890810060, which was created in session d8d848d7-cf54-4f6b-8b8a-0dd42271aec6 - 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=, in session e3e97f35-60e3-4f32-a3a5-88e065bfdf27 - 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=’ on server 127.0.0.1:27019. The full response is {“ok”: 0.0, “errmsg”: “Cannot run getMore on cursor 18890810060, which was created in session d8d848d7-cf54-4f6b-8b8a-0dd42271aec6 - 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=, in session e3e97f35-60e3-4f32-a3a5-88e065bfdf27 - 47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=”, “code”: 50738, “codeName”: "Location507
测试的时候,query 查 10000 条,返回 mongo 游标。fork40 个线程,循环 100 遍,这会出现这种情况
spl 只提供函数,怎么用是写代码的事,代码中应该是一次创建,到处用,而且是可以多个线程同时复用
mongo 游标默认超时 10 分钟,可以在启动时使用如下命令提高超时
mongod –setParameter cursorTimeoutMillis=< num >
这个游标肯定不是超时的问题,fork40 个线程,跑 1 分钟就能出现 getMore 报错问题,明天我用集算器脚本写个测试用例吧。
多线程下让线程与 db 保持一一对应关系,此问题已经修改.
自己重写集算器 mongodb 驱动解决了
创建游标时显式指定会话应该可以解决这个问题
github 源码里每次创建游标都新创建会话,不知道并发时会话增多对性能有多大影响