ロード バランシングを向上させるために、mongo レプリカ セットのプライマリ ノードと 2 つのセカンダリ ノードからの読み取りを構成しようとしています。3 つのノードはそれぞれ、ip1、ip2、ip3 の IP アドレスを持つ異なるマシン上にあります。
私のGoLang
サイトは、 2 つの URLとmartini
を持つ Web サーバーです。/insert
/get
package main
import (
"github.com/go-martini/martini"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
"net/http"
)
const (
dialStr = "ip1:port1,ip2:port2,ip3:port3"
dbName = "test"
collectionName = "test"
elementsCount = 1000
)
var mainSessionForSave *mgo.Session
func ConnectToMongo() {
var err error
mainSessionForSave, err = mgo.Dial(dialStr)
mainSessionForSave.SetMode(mgo.Monotonic, true)
if err != nil {
panic(err)
}
}
func GetMgoSessionPerRequest() *mgo.Session {
var sessionPerRequest *mgo.Session
sessionPerRequest = mainSessionForSave.Copy()
return sessionPerRequest
}
func main() {
ConnectToMongo()
prepareMartini().Run()
}
type Element struct {
I int `bson:"I"`
}
func prepareMartini() *martini.ClassicMartini {
m := martini.Classic()
sessionPerRequest := GetMgoSessionPerRequest()
m.Get("/insert", func(w http.ResponseWriter, r *http.Request) {
for i := 0; i < elementsCount; i++ {
e := Element{I: i}
err := collection(sessionPerRequest).Insert(&e)
if err != nil {
panic(err)
}
}
w.Write([]byte("data inserted successfully"))
})
m.Get("/get", func(w http.ResponseWriter, r *http.Request) {
var element Element
const findI = 500
err := collection(sessionPerRequest).Find(bson.M{"I": findI}).One(&element)
if err != nil {
panic(err)
}
w.Write([]byte("get data successfully"))
})
return m
}
func collection(s *mgo.Session) *mgo.Collection {
return s.DB(dbName).C(collectionName)
}
コマンドを使用してこのGoLang
サイトを実行し、go run site.go
要求された実験を準備しhttp://localhost:3000/insert
ます。約 1 分後にテスト データが挿入されました。
次に、セカンダリ ノードとプライマリ ノードからの読み取りのテストを開始しましたattacker.go
。
package main
import (
"fmt"
"time"
vegeta "github.com/tsenart/vegeta/lib"
)
func main() {
rate := uint64(4000) // per second
duration := 4 * time.Second
targeter := vegeta.NewStaticTargeter(&vegeta.Target{
Method: "GET",
URL: "http://localhost:3000/get",
})
attacker := vegeta.NewAttacker()
var results vegeta.Results
for res := range attacker.Attack(targeter, rate, duration) {
results = append(results, res)
}
metrics := vegeta.NewMetrics(results)
fmt.Printf("99th percentile: %s\n", metrics.Latencies.P99)
}
実行すると、毎秒4000go run attacker.go
回URL をリクエストしました。攻撃者が作業している間、私は 3 つのサーバーをすべて開き、コマンドを実行してリソースの消費を監視しました。PRIMARY ノードは、CPU が約 80% の高負荷状態にあることを示しています。SECONDARIESは落ち着いていました。http://localhost:3000/get
htop
なんで?
使っていたのでmgo.Monotonic
...
mainSessionForSave.SetMode(mgo.Monotonic, true)
... 私はすべてのノードから読み取ることを期待していました:ip1, ip2, ip3
そして、すべてのノードを同じ負荷と同じ CPU 消費で監視することを期待していました。しかし、そうではありません。何を間違って設定しましたか? 実際mgo.Monotonic
、私の場合は機能しておらず、PRIMARYノードからのみ読み取ります。