mongo 返回EOF错误

很多事情仅仅的是严肃的提出问题都感觉很难,更何况还得要先发现它。

Question

描述

项目中使用:github.com/globalsign/mgo这个库,在一次主从切换之后,mongo后续的操作都失败了, 错误信息输出:EOF

引用网上遇到同样问题的其他描述:

The problem I have is, when the connection to the mongodb server fails (the server drops the connection sometimes or mongodb server fails), then my pointer to the session variable doesn't work anymore. Even if the internet connection comes back, mgo driver doesn't reconnect anymore, instead of this I get the error (when I do Find().One() method call):"EOF"

解决思路

  1. Call Refresh on the session, which makes it discard (or put back in
    the pool, if the connection is good) the connection it’s holding, and
    pick a new one when necessary.
  2. Instead of using a single session, use many by calling session.Copy
    when you need a new session, and then call session.Close when you’re
    done with it. This will also mean you’re using multiple connections to
    the database, when necessary.

按照这个思路,在mongo启动的时候,设置一个定时ping检查。当error返回io.EOF时执行Refresh操作。

主从切换就会出现这个问题吗?发现并不是。下面的重现的尝试

搭建replica set

参考这里Use only docker and docker-compose to create a MongoDB Replica Set创建docker-compose.yml文件。

稍稍对文件做了修改,指定了ports命令,以达到本地可以访问容器内mongo的目。

测试

循环1000次来执行读操作,在读操作执行的过程中,关闭掉PRIMARY节点,强制触发主从选举。很遗憾,服务短暂不可用之后,恢复正常了

type People struct {
	FirstName string `json:"firstname"`
	LastName  string `json:"lastname"`
}

func TestCheckComplete(t *testing.T) {
	session, err := mgo.DialWithTimeout("mongodb://127.0.0.1:27017,127.0.0.1:27018,127.0.0.1:27019/admin?replicaSet=rs0", time.Second)
	if err != nil {
		panic(err)
	}
	session.SetSyncTimeout(time.Second)

	var actionLog People
	for i := 0; i <= 1000; i ++ {
		// show progress
		fmt.Print(".")
		
		if err := session.DB("dev").C("people").Find(bson.M{"firstname": "Nic"}).One(&actionLog); err != nil {
			if err == io.EOF {
				fmt.Println("the error equal io.EOF")
			}
			if err.Error() == "EOF" {
				fmt.Println("the error.Error() equal io.EOF")
			}
			fmt.Println(err)
		}
	}
}

docker-compose.yml

ports vs expose

ports暴露容器端口到主机的任意端口或指定端口。当我们想在本地访问docker内服务时,就需要使用这个命令。比如:

ports:
  - "27018:27017"     # 绑定宿主27018端口端口到容器21017端口

expose 声明运行时容器打算使用的端口,这只是一个声明,在运行时应用并不会因为这个声明就会开启这个端口。只有在使用 docker run -P 时,才会自动基于规则映射EXPOSE的端口。

expose:
    - 27017

entrypoint

entrypoint用于指定容器启动程序和参数。当指定了entrypoint之后,cmd的含义就发生变化了,不再是直接运行命令,而是将cmd的内容作为参数传递给entrypoint指令。这里的cmd主要代指容器名后面追加的参数。

<entrypoint> "<cmd>"

docker-compose.yml中的示例代码,用于初始化mongo的配置。

creator:
    build: creator
    entrypoint: ["mongo","--host","mongo1","--port","27017","--eval", 'rs.initiate( { _id : "rs0",members: [{ _id: 0, host: "mongo1:27017" },{ _id: 1, host: "mongo2:27017" },{ _id: 2, host: "mongo3:27017" }   ]})']
    depends_on:
      - mongo1
      - mongo2
      - mongo3

depends_on

depends_on用来定义服务间的依赖关系,creator要落后于mongo1-3的启动

docker command

# 查看容器的日志
docker logs -f <container-id>

# 获取当前容器的信息
docker container ls -a

# 启动容器
docker-compose -f docker-compose.yml up

# 进去容器里面
docker exec -it <contrainer-id> bash

# 关闭容器
docker container stop <container-id>

mongo command

A replica set in MongoDB is a group of mongod processes that maintain the same data set. Replica sets provide redundancy and high availability, and are the basis for all production deployments. This section introduces replication in MongoDB as well as the components and architecture of replica sets. The section also provides tutorials for common tasks related to replica sets.

// Returns:	A document with status information.
// 查看当前mongo的主从节点配置
rs.status()

// This allows the current connection to allow read operations to run on secondary members.
// 当在SECONDARY节点上执行show dbs失败时执行
rs.slaveOk()

总结

亲爱的朋友,记得关注公众号啊!
在这里插入图片描述

### 回答1: 使用Mongotemplate返回指定字段,可以使用Mongotemplate中的project方法。在项目方法中,可以使用ProjectionOperation来指定要返回的字段。例如: Query query = new Query(); query.addCriteria(Criteria.where("name").is("张三")); ProjectionOperation project = Aggregation.project("name", "age"); Aggregation aggregation = Aggregation.newAggregation(project); List<Map<String,Object>> result = mongoTemplate.aggregate(aggregation, collectionName, Map.class).getMappedResults(); 这个查询将返回名字和年龄在数据库中为“张三”的人的信息。 ### 回答2: Mongotemplate是Spring Data MongoDB提供的一个核心类,它为我们封装了MongoDB的操作方法,让我们可以方便地进行CRUD操作。Mongotemplate返回指定字段的方法是通过使用Projection来实现的。 ProjectionMongoDB的一个特性,它可以指定查询结果文档中需要返回的字段。在Mongotemplate中,我们可以使用Query对象的fields方法指定Projection,将需要返回的字段加入到Projection中。 例如,我们有一个Person实体类,它有id、name、age、gender、address等属性。我们可以使用如下代码查询并返回只包含id和name的Person数据: ``` Query query = new Query(); query.fields().include("id", "name"); List<Person> persons = mongoTemplate.find(query, Person.class); ``` 在这个例子中,我们通过Query对象的fields方法指定Projection,使用include方法将需要返回的字段id和name加入到Projection中。然后,使用mongoTemplate的find方法查询数据,并将返回结果转换为Person类的List对象。 除了使用include方法指定需要返回的字段之外,我们还可以使用exclude方法指定不需要返回的字段,也可以使用elemMatch方法指定查询嵌套文档字段的Projection。 总的来说,Mongotemplate返回指定字段的方法就是通过Projection来实现的,即使用Query对象的fields方法指定Projection,将需要返回的字段加入到Projection中。在实际开发中,我们可以根据具体的业务需求来选择合适的Projection方法,以达到优化查询性能、提高查询效率的目的。 ### 回答3: MongoTemplate是Spring Data MongoDB提供的一种操作MongoDB的工具,它提供了一系列方法可以方便地对MongoDB进行操作。通过MongoTemplate返回指定字段需要通过指定查询条件和投影条件来实现。 查询条件是指MongoDB中的查询条件,它可以是一个满足MongoDB语法的查询条件对象或文档。投影条件是指查询结果中应该包含的字段。MongoDB的投影操作可以利用字典文档的形式来指定需要返回的字段。MongoTemplate中提供了projection方法来实现这一功能,它需要传入一个ProjectionOperation对象用来指定需要返回的字段。 ProjectionOperation是一个MongoDB Projection操作的工具类,它提供了一些方法用来构造ProjectionOperation对象。其中,include和exclude方法可以指定需要返回或不返回的字段。当指定需要返回的字段时,可以使用不同的方式来指定:include(“fieldName”)用来指定单个字段,include(fields…)用来指定多个字段。当指定不需要返回的字段时,exclude(“fieldName”)用来指定单个字段,exclude(“fieldName1”, “fieldName2”)用来指定多个字段。 最后,可以通过MongoTemplate的find方法来执行查询,该方法需要传入一个Query对象和一个Class<T>类型的参数。Query对象用来指定查询条件,Class<T>类型的参数用来指定查询结果的类型。当指定了ProjectionOperation对象后,查询结果将会按照投影条件中的字段返回,而不是返回所有字段。 综上所述,通过MongoTemplate返回指定字段需要完成以下步骤: 1. 构造查询条件和投影条件; 2. 使用ProjectionOperation对象指定需要返回的字段; 3. 使用find方法执行查询,结果将按照投影条件中的字段返回
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值