異常情況描述com.mongodb.MongoSocketReadException: Prematurely reached end of stream
一、異常發生場景
當使用mongodb的一主一從一備節點構建的集羣,使用java代碼連接集羣時候,測試主節點master和備用節點slave切換的時候;
2019-10-23 20:21:05,972 WARN [org.mongodb.driver.connection] - Got socket exception on connection [connectionId{localValue:4, serverValue:15}] to 172.19.32.142:27017. All connections to 172.19.32.142:27017 will be closed.
com.mongodb.MongoSocketReadException: Prematurely reached end of stream
at com.mongodb.connection.SocketStream.read(SocketStream.java:88)
at com.mongodb.connection.InternalStreamConnection.receiveResponseBuffers(InternalStreamConnection.java:494)
at com.mongodb.connection.InternalStreamConnection.receiveMessage(InternalStreamConnection.java:224)
at com.mongodb.connection.UsageTrackingInternalConnection.receiveMessage(UsageTrackingInternalConnection.java:96)
at com.mongodb.connection.DefaultConnectionPool$PooledConnection.receiveMessage(DefaultConnectionPool.java:440)
at com.mongodb.connection.WriteCommandProtocol.receiveMessage(WriteCommandProtocol.java:262)
at com.mongodb.connection.WriteCommandProtocol.execute(WriteCommandProtocol.java:104)
at com.mongodb.connection.InsertCommandProtocol.execute(InsertCommandProtocol.java:67)
at com.mongodb.connection.InsertCommandProtocol.execute(InsertCommandProtocol.java:37)
at com.mongodb.connection.DefaultServer$DefaultServerProtocolExecutor.execute(DefaultServer.java:168)
at com.mongodb.connection.DefaultServerConnection.executeProtocol(DefaultServerConnection.java:289)
at com.mongodb.connection.DefaultServerConnection.insertCommand(DefaultServerConnection.java:118)
at com.mongodb.operation.MixedBulkWriteOperation$Run$2.executeWriteCommandProtocol(MixedBulkWriteOperation.java:465)
at com.mongodb.operation.MixedBulkWriteOperation$Run$RunExecutor.execute(MixedBulkWriteOperation.java:656)
at com.mongodb.operation.MixedBulkWriteOperation$Run.execute(MixedBulkWriteOperation.java:411)
at com.mongodb.operation.MixedBulkWriteOperation$1.call(MixedBulkWriteOperation.java:177)
at com.mongodb.operation.MixedBulkWriteOperation$1.call(MixedBulkWriteOperation.java:168)
at com.mongodb.operation.OperationHelper.withConnectionSource(OperationHelper.java:426)
at com.mongodb.operation.OperationHelper.withConnection(OperationHelper.java:417)
at com.mongodb.operation.MixedBulkWriteOperation.execute(MixedBulkWriteOperation.java:168)
at com.mongodb.operation.MixedBulkWriteOperation.execute(MixedBulkWriteOperation.java:74)
at com.mongodb.Mongo.execute(Mongo.java:845)
at com.mongodb.Mongo$2.execute(Mongo.java:828)
at com.mongodb.MongoCollectionImpl.executeSingleWriteRequest(MongoCollectionImpl.java:550)
at com.mongodb.MongoCollectionImpl.insertOne(MongoCollectionImpl.java:317)
at com.mongodb.MongoCollectionImpl.insertOne(MongoCollectionImpl.java:307)
at mongotest.TestMongoDBReplSet.main(TestMongoDBReplSet.java:39)
二、原因分析
Got socket exception on connection [connectionId{localValue:4, serverValue:15}] to 172.19.32.142:27017. All connections to 172.19.32.142:27017 will be closed.
這段代碼錯誤提示表明:主備容災切換之後,原來的master不再提供寫服務,寫服務轉移到另外一臺機器中,此時java驅動連接元信息中沒有感知到這種變化,集羣中改變的元信息沒有同步到當前的mongodb連接池中的連接中,導致連接失敗!
三、解決方案
原始連接的java代碼,沒有加上try-catch{},導致主備切換之後出現錯誤,現在加上之後,一斤可以正常的瞭解上集羣了。
package mongotest;
import com.mongodb.*;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import java.util.ArrayList;
import java.util.List;
/**
* 描述: java連接mongdb集羣;測試高可用性
* @author: fangchangtan
* @version 創建時間:2018年11月26日 下午7:45:29
*/
public class TestMongoDBReplSet1 {
public static void main(String[] args) {
ArrayList<ServerAddress> arrayList = new ArrayList<>();
//mongpdb的java連接配置爲一個集羣模式
List<ServerAddress> addresses = new ArrayList<ServerAddress>();
ServerAddress address1 = new ServerAddress("172.19.32.141" , 27017);
ServerAddress address2 = new ServerAddress("172.19.32.141" , 27027);
ServerAddress address3 = new ServerAddress("172.19.32.141" , 27037);
addresses.add(address1);
addresses.add(address2);
addresses.add(address3);
// 3.用來做mongo複製集的基本配置
MongoClientOptions.Builder builder = new MongoClientOptions.Builder();
// //線程等待連接變爲可用的最長時間.
// builder.maxWaitTime(20000);
// //連接超時時間,必須大於0
// builder.connectTimeout(1000 * 5);
// //設置服務器選擇超時(以毫秒爲單位),它定義驅動程序在拋出異常之前等待服務器選擇成功的時間
// //值爲0表示如果沒有可用的服務器,它將立即超時。 負值意味着無限期等待
// builder.serverSelectionTimeout(1000 * 30);
// // 4.自動重連
// // 7.每個連接上的線程數
// builder.threadsAllowedToBlockForConnectionMultiplier(50);
// builder.maxConnectionIdleTime(5000);//set the max wait time in (ms)
MongoClient mongoClient = new MongoClient(addresses,builder.build());
MongoDatabase database = mongoClient.getDatabase("test");
MongoCollection<Document> collection = database.getCollection("testdb");
for (int i = 0; i < 1000; i++) {
System.out.println("==========================");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//向集羣中插入文檔數據
// collection.insertOne(new Document("name","dog"+i));
try {
collection.deleteMany(new BasicDBObject("_id", new BasicDBObject("$ne", null)));
collection.insertOne(new Document("name","dog"+i));
}catch (MongoSocketException e){
System.out.println("++++++++++++++++++++++");
System.out.println(e);
mongoClient = new MongoClient(addresses,builder.build());
}
//查詢集羣中的數據記錄
FindIterable<Document> find = collection.find();
MongoCursor<Document> iterator = find.iterator();
while (iterator.hasNext()) {
final Document document = iterator.next();
System.out.println(document);
}
}
}
}
小夥伴們:如果解決了你的問題,麻煩給點個贊! 本人最新需要你的鼓勵!-V-