mongo EOF
Posted by 付辉 on Saturday, April 27, 2019 共1178字
很多事情仅仅的是严肃的提出问题都感觉很难,更何况还得要先发现它。
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"
解决思路
- 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.
- 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()