使用Golang和MongoDB構建微服務
image
根據 umermansoor github的 Python
版本的微服務改造成 Golang
版本
一共有4個微服務
- Movie Service: 是關於電影的基本資料,標題、評分等
- ShowTimes Service: 關於電影發行日期的資訊
- Booking Service: 關於電影的訂閱的資訊
- User Service: 使用者的資訊
源碼 Github
要求
API和文檔
各個服務之間相互獨立,單獨的路由和單獨的資料庫,各個服務之間的通訊是通過 HTTP JSON
,每個服務的API的返回結果也是JSON類型,可以參考 使用Golang和MongoDB構建 RESTful API,提取出各個服務之間共同的東西,獨立於服務之外,供服務調用
helper/utils.go
func ResponseWithJson(w http.ResponseWriter, code int, payload interface{}) { response, _ := json.Marshal(payload) w.Header().Set("Content-Type", "application/json") w.WriteHeader(code) w.Write(response)}
models/models.go
type User struct { Id string `bson:"_id" json:"id"` Name string `bson:"name" json:"name"`}type Movie struct { Id string `bson:"_id" json:"id"` Title string `bson:"title" json:"title"` Rating float32 `bson:"rating" json:"rating"` Director string `bson:"director" json:"director"`}type ShowTimes struct { Id string `bson:"_id" json:"id"` Date string `bson:"date" json:"date"` Movies []string `bson:"movies" json:"movies"`}type Booking struct { Id string `bson:"_id" json:"id"` Name string `bson:"name" json:"name"` Books []BookInfo `bson:"books" json:"books"`}type BookInfo struct { Date string `bson:"date" json:"date"` Movies []string `bson:"movies" json:"movies"`}type Result struct { Name string `json:"name"` Books []ResultInfo `json:"books"`}type ResultInfo struct { Date string `json:"date"` Movies []Movie `json:"movies"`}
dao/db.go
,具體的請參考 對 mgo關於MongoDB的基礎操作的封裝
func Insert(db, collection string, docs ...interface{}) error { ms, c := connect(db, collection) defer ms.Close() return c.Insert(docs...)}func FindOne(db, collection string, query, selector, result interface{}) error { ms, c := connect(db, collection) defer ms.Close() return c.Find(query).Select(selector).One(result)}...
服務
各個服務具體的邏輯具體的參考 使用Golang和MongoDB構建 RESTful API
- User Service(port 8000)
- Movie Service(port 8001)
- ShowTimes Service(port 8002)
- Booking Service(port 8003)
服務通訊
查詢某個使用者的訂閱的電影資訊時,需要先通過 User Service
服務查詢這個使用者,根據使用者名稱通過 Booking Service
查詢使用者的訂閱資訊,然後通過 Movie Service
服務查詢對應的電影的資訊,都是通過 HTTP
通訊
params := mux.Vars(r) name := params["name"] var user models.User if err := dao.FindOne(db, collection, bson.M{"_id": name}, nil, &user); err != nil { helper.ResponseWithJson(w, http.StatusBadRequest, "invalid request") return } res, err := http.Get("http://127.0.0.1:8003/booking/" + name) if err != nil { helper.ResponseWithJson(w, http.StatusBadRequest, "invalid request by name "+name) return } defer res.Body.Close() result, err := ioutil.ReadAll(res.Body) if err != nil { helper.ResponseWithJson(w, http.StatusBadRequest, "invalid request of booking by name "+name) return } var booking models.Booking var resResult models.Result resResult.Name = name var resInfo models.ResultInfo if err := json.Unmarshal(result, &booking); err == nil { for _, book := range booking.Books { resInfo.Date = book.Date for _, movie := range book.Movies { res, err := http.Get("http://127.0.0.1:8001/movies/" + movie) if err == nil { result, err := ioutil.ReadAll(res.Body) if err == nil { var movie models.Movie if err := json.Unmarshal(result, &movie); err == nil { resInfo.Movies = append(resInfo.Movies, movie) } } } } resResult.Books = append(resResult.Books, resInfo) } helper.ResponseWithJson(w, http.StatusOK, resResult) } else { helper.ResponseWithJson(w, http.StatusBadRequest, "invalid request") }