What is a seed server?

384 views
Skip to first unread message

Darko Luketic

unread,
Jan 26, 2015, 11:16:22 AM1/26/15
to mgo-...@googlegroups.com
From
http://godoc.org/gopkg.in/mgo.v2#Dial

"Dial establishes a new session to the cluster identified by the given seed server(s). The session will enable communication with all of the servers in the cluster, so the seed servers are used only to find out about the cluster topology."

I have 3 replica sets on 3 servers and each replica set is a shard.
Each server has a mongos instance listening on :27017.

1. Is a mongos instance a seed server? (I'm asking because the term seed server isn't mentioned anywhere in the sharding documentation of mongodb)
2. Do I need to specify all 3 mongos at Dial() or DialWithInfo() to achieve better performance or is it enough to just have the local mongos in there?

Next,
"This method is generally called just once for a given cluster. Further sessions to the same cluster are then established using the New or Copy methods on the obtained session. This will make them share the underlying cluster, and manage the pool of connections appropriately"

So I Dial() to the local mongos and receive a *mgo.Session.

mainsession, _ := mgo.Dial("") // simplified
This is a permanent connection that lasts as long as the mongos instance is up and running or the Go program ends.
Then, in some handler I call mainsession.New() or Copy()
What if meanwhile mongos gets restarted and the mainsession connection is lost?
Will New() fail, will Copy() fail?
And, can I prematurely close the mainsession connection (if New()/Copy() don't fail)?
If I understood correctly, New() or Copy() as opposed to Clone() are used so the mongodb listener doesn't block requests over a previously established, long running connection. true/false?

In the past, with 1 local mongod instance, I had a permanent connection and would send or retireve data on this connection in all handlers. However when mongod was restarted the Go program also had to be restarted, because it lost its connection. So I went to Dial()ing the local mongod on each new request in each handler. And that works with a local mongod but I'm unsure how to proceed with multiple mongos that form shards out of replica sets, 1 mongos listening on each server.

My take on it is to connect to the local mongos instance only ( since I guess it has the same info as the other instances) and call Copy() in each handler, because I have each copy of a Go program on each of the 3 servers listening on a specific port with nginx in front doing load balancing, and in the back they talk to mongodb (or 1 mongos).

Gustavo Niemeyer

unread,
Feb 2, 2015, 1:34:16 AM2/2/15
to mgo-...@googlegroups.com, in...@icod.de
On Mon Jan 26 2015 at 2:16:22 PM Darko Luketic <in...@icod.de> wrote:
"Dial establishes a new session to the cluster identified by the given seed server(s). The session will enable communication with all of the servers in the cluster, so the seed servers are used only to find out about the cluster topology."

As described in the sentence itself, those that are used to find out about cluster topology. The driver will talk to other servers not in the initial list if it finds out about them while interacting with the seed servers to discover the full cluster topology.

This behavior is tweakable by settings. For example, Direct mode will prevent servers not in the provided seed list from being contacted.
 
I have 3 replica sets on 3 servers and each replica set is a shard.
Each server has a mongos instance listening on :27017.

1. Is a mongos instance a seed server? (I'm asking because the term seed server isn't mentioned anywhere in the sharding documentation of mongodb) 
2. Do I need to specify all 3 mongos at Dial() or DialWithInfo() to achieve better performance or is it enough to just have the local mongos in there?

In terms of performance it shouldn't matter, but it may be worth specifying more than one to make sure the application is still available if one of them falls down.
 
Next,
"This method is generally called just once for a given cluster. Further sessions to the same cluster are then established using the New or Copy methods on the obtained session. This will make them share the underlying cluster, and manage the pool of connections appropriately"

So I Dial() to the local mongos and receive a *mgo.Session.

mainsession, _ := mgo.Dial("") // simplified
This is a permanent connection that lasts as long as the mongos instance is up and running or the Go program ends.

It's a permanent session, not a permanent connection. If the session is in Eventual mode, or is has its Refresh method called, it will put the socket in use back into the pool, and pick a new one (potentially the same one) when next used for a remote operation.
  
Then, in some handler I call mainsession.New() or Copy()
What if meanwhile mongos gets restarted and the mainsession connection is lost?
Will New() fail, will Copy() fail?

No, they won't.

The only issue to watch out in that situation is that if mainsession itself is used for remote operations before the connection is lost, it'll be flagged as in error so that the application can acknowledge that error before moving forward. The error on mainsession will only go away when its Refresh method is called, or it is closed (in which case no further operations on that specific session will take place).

And, can I prematurely close the mainsession connection (if New()/Copy() don't fail)?

Yes, that's fine. There's no hierarchical relationship between sessions. They're all independent.
 
If I understood correctly, New() or Copy() as opposed to Clone() are used so the mongodb listener doesn't block requests over a previously established, long running connection. true/false?

Yes, that's one of the main reasons to use it.

In the past, with 1 local mongod instance, I had a permanent connection and would send or retireve data on this connection in all handlers. However when mongod was restarted the Go program also had to be restarted, because it lost its connection.

The Go *program* did not lose its connection, the session did, thus there's no need to restart it all. The session was in an error state because the application needs to acknowledge that the specific connection in use was broken, and that's done either by calling Refresh or closing the session as described above.
 
So I went to Dial()ing the local mongod on each new request in each handler. And that works with a local mongod but I'm unsure how to proceed with multiple mongos that form shards out of replica sets, 1 mongos listening on each server.

The situation is the same.
 
My take on it is to connect to the local mongos instance only ( since I guess it has the same info as the other instances) and call Copy() in each handler, because I have each copy of a Go program on each of the 3 servers listening on a specific port with nginx in front doing load balancing, and in the back they talk to mongodb (or 1 mongos).

Yeah, that should be fine.

Good set of questions. I'll see if I can improve the documentation to clarify some of these points further.

Darko Luketic

unread,
Feb 2, 2015, 7:02:31 PM2/2/15
to mgo-...@googlegroups.com, in...@icod.de
Thanks for the answers, Gustavo.

Follow up question.
How do I know that a session is in an error state aka. needs refreshing? If error != nil when a query is "ran"?
If so which error type is returned?

Gustavo Niemeyer

unread,
Feb 3, 2015, 1:49:34 AM2/3/15
to mgo-...@googlegroups.com, Darko Luketic
On Tue, Feb 3, 2015 at 2:02 AM, Darko Luketic <in...@icod.de> wrote:
> Thanks for the answers, Gustavo.
>
> Follow up question.
> How do I know that a session is in an error state aka. needs refreshing? If
> error != nil when a query is "ran"?
> If so which error type is returned?

It's easy to structure the code so you don't really have to know if
the session is in an error state or not. Most applications will have
either a main loop, or will be handling a series of requests/jobs/etc.
When starting to handle a new requests, Copy a master session into a
new one, and Close when done. Alternatively, if the application has a
main loop, just Refresh when entering the loop.

With that in place, conventional Go code that returns an error when
appropriate should just work.


gustavo @ http://niemeyer.net

Darko Luketic

unread,
Feb 4, 2015, 10:41:02 AM2/4/15
to mgo-...@googlegroups.com, in...@icod.de
Additionally following code, to illustrate:

package main

import (
    "fmt"
    "gopkg.in/mgo.v2"
    "gopkg.in/mgo.v2/bson"
    "log"
    "net/http"
)

const (
    mgoDBName = "testmgo"
    mgoCName  = "test"
)

var (
    ms *mgo.Session
)

type MainHandler struct{}

type Record struct {
    Name string
    Last string
}

func main() {
    var e error
    ms, e = mgo.Dial("localhost")
    if e != nil {
        log.Fatalln(e.Error())
    }
    defer closeMainMGOSession()
    c := ms.DB(mgoDBName).C(mgoCName)
    rc := new(Record)
    rc.Name = "Darko"
    rc.Last = "Luketic"
    if e := c.Insert(rc); e != nil {
        log.Println(e.Error())
    }

    h := new(MainHandler)
    http.Handle("/", h)
    http.ListenAndServe(":8080", nil)
}

func closeMainMGOSession() {
    if e := ms.DB(mgoDBName).DropDatabase(); e != nil {
        log.Fatalln(e.Error())
    }
    ms.Close()
}

func (h *MainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    c := ms.DB(mgoDBName).C(mgoCName)
    rc := new(Record)
    if e := c.Find(bson.M{"name": "Darko"}).One(rc); e != nil {
        http.Error(w, e.Error(), 500)
        return
    }
    fmt.Fprintln(w, rc)
}

-----------------
go run main.go
curl http://localhost:8080/
systemctl restart mongodb.service
curl http://localhost:8080/

result EOF

###########

However

replace with this

func (h *MainHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    lms := ms.Copy() // note the difference
    c := lms.DB(mgoDBName).C(mgoCName) // note the difference
    rc := new(Record)
    if e := c.Find(bson.M{"name": "Darko"}).One(rc); e != nil {
        http.Error(w, e.Error(), 500)
        return
    }
    fmt.Fprintln(w, rc)
}

---------------

go run main.go
curl http://localhost:8080/
systemctl restart mongodb.service
curl http://localhost:8080/

result &{Darko Luketic}

Note for readers:
Create main session
use Copy() in handler or handlefunc
1 or multiple mongos act as if they were 1 mongod
a seed server is a replica member, different context than sharding
Reply all
Reply to author
Forward
0 new messages