【go語言學習筆記】05 Go 語言實戰

文章目錄

    • 一、 RESTful API 服務
      • 1. RESTful API 定義
        • 1.1 HTTP Method
        • 1.2 RESTful API 規范
      • 2. RESTful API 風格示例
      • 3. RESTful JSON API
      • 4. Gin 框架
        • 4.1 導入 Gin 框架
        • 4.2 使用 Gin 框架
          • 4.2.1 獲取特定的用戶(GET)
          • 4.2.2 新增一個用戶(POST)
          • 4.2.3 刪除一個用戶(DELETE)
          • 4.2.4 修改一個用戶的名字(PATCH)
    • 二、 RPC 跨平臺服務
      • 1. 定義
      • 2. Go語言中的RPC
        • 2.1 服務端
        • 2.2 客戶端
      • 3. 基于 HTTP 的RPC
      • 3. JSON RPC 跨平臺通信
        • 3.1 基于 TCP 的 JSON RPC
        • 3.2 基于 HTTP的JSON RPC
    • 三、Go 語言的發展前景

一、 RESTful API 服務

在做項目開發的時候,要善于借助已經有的輪子,讓自己的開發更有效率,也更容易實現。

1. RESTful API 定義

RESTful API 是一套規范,它可以規范如何對服務器上的資源進行操作。和 RESTful API 和密不可分的是 HTTP Method。

1.1 HTTP Method

HTTP Method最常見的就是POST和GET,其實最早在 HTTP 0.9 版本中,只有一個GET方法,該方法是一個冪等方法,用于獲取服務器上的資源。

在 HTTP 1.0 版本中又增加了HEAD和POST方法,其中常用的是 POST 方法,一般用于給服務端提交一個資源,導致服務器的資源發生變化。

隨著網絡越來越復雜,在 HTTP1.1 版本的時候,支持的方法增加到了 9 個,新增的方法有 HEAD、OPTIONS、PUT、DELETE、TRACE、PATCH 和 CONNECT。下面是它們各自的作用:

  1. GET 方法可請求一個指定資源的表示形式,使用 GET 的請求應該只被用于獲取數據。
  2. HEAD 方法用于請求一個與 GET 請求的響應相同的響應,但沒有響應體。
  3. POST 方法用于將實體提交到指定的資源,通常導致服務器上的狀態變化或副作用。
  4. PUT 方法用于請求有效載荷替換目標資源的所有當前表示。
  5. DELETE 方法用于刪除指定的資源。
  6. CONNECT 方法用于建立一個到由目標資源標識的服務器的隧道。
  7. OPTIONS 方法用于描述目標資源的通信選項。
  8. TRACE 方法用于沿著到目標資源的路徑執行一個消息環回測試。
  9. PATCH 方法用于對資源應用部分修改。

HTTP 規范針對每個方法都給出了明確的定義,所以使用的時候也要盡可能地遵循這些定義,這樣在開發中才可以更好地協作。

1.2 RESTful API 規范

RESTful API 規范就是基于 HTTP Method 規范對服務器資源的操作,同時規范了 URL 的樣式和 HTTP Status Code。

在 RESTful API 中,使用的主要是以下五種 HTTP 方法:

  1. GET,表示讀取服務器上的資源;
  2. POST,表示在服務器上創建資源;
  3. PUT,表示更新或者替換服務器上的資源;
  4. DELETE,表示刪除服務器上的資源;
  5. PATCH,表示更新 / 修改資源的一部分。

以上 HTTP 方法在 RESTful API 規范中是一個操作,操作的就是服務器的資源,服務器的資源通過特定的 URL 表示。

(1)GET 方法的示例

HTTP GET https://www.flysnow.org/users
HTTP GET https://www.flysnow.org/users/123

上例中

  • 第一個表示獲取所有用戶的信息;
  • 第二個表示獲取 ID 為 123 用戶的信息。

(2) POST 方法的示例

HTTP POST https://www.flysnow.org/users

該示例表示創建一個用戶,通過 POST 方法給服務器提供創建這個用戶所需的全部信息。

這里 users 是個復數。

(3)PUT 方法的示例

HTTP PUT https://www.flysnow.org/users/123

該示例表示要更新 / 替換 ID 為 123 的這個用戶,在更新的時候,會通過 PUT 方法提供更新這個用戶需要的全部用戶信息。這里 PUT 方法和 POST 方法不太一樣的是,從 URL 上看,PUT 方法操作的是單個資源,比如這里 ID 為 123 的用戶。

如果要更新一個用戶的部分信息,使用 PATCH 方法更恰當。

(4)DELETE 方法的示例

HTTP DELETE https://www.flysnow.org/users/123

DELETE 方法的使用和 PUT 方法一樣,也是操作單個資源,這里是刪除 ID 為 123 的這個用戶。

2. RESTful API 風格示例

Go 語言的一個很大的優勢,就是可以很容易地開發出網絡后臺服務,而且性能快、效率高。Golang 提供了內置的 net/http 包處理 HTTP 請求,讓開發者可以比較方便地開發一個 HTTP 服務。

一個簡單的 HTTP 服務的 Go 語言實現代碼如下所示:

func main() {http.HandleFunc("/users",handleUsers)http.ListenAndServe(":8080", nil)
}
func handleUsers(w http.ResponseWriter, r *http.Request){fmt.Fprintln(w,"ID:1,Name:張三")fmt.Fprintln(w,"ID:2,Name:李四")fmt.Fprintln(w,"ID:3,Name:王五")
}

這個示例運行后,在瀏覽器中輸入 http://localhost:8080/users, 就可以看到如下內容信息:

ID:1,Name:張三
ID:2,Name:李四
ID:3,Name:王五

這并不是一個 RESTful API,因為使用者不僅可以通過 HTTP GET 方法獲得所有的用戶信息,還可以通過 POST、DELETE、PUT 等 HTTP 方法獲得所有的用戶信息,這顯然不符合 RESTful API 的規范。

對以上示例進行修改,使它符合 RESTful API 的規范,修改后的示例代碼如下所示:

func handleUsers(w http.ResponseWriter, r *http.Request){switch r.Method {case "GET":w.WriteHeader(http.StatusOK)fmt.Fprintln(w,"ID:1,Name:張三")fmt.Fprintln(w,"ID:2,Name:李四")fmt.Fprintln(w,"ID:3,Name:王五")default:w.WriteHeader(http.StatusNotFound)fmt.Fprintln(w,"not found")}
}

該示例修改了 handleUsers 函數,在該函數中增加了只在使用 GET 方法時,才獲得所有用戶的信息的判斷,其他情況返回 not found。

3. RESTful JSON API

在項目中最常見的是使用 JSON 格式傳輸信息,也就是提供的 RESTful API 要返回 JSON 內容給使用者。

用上面的示例改造成可以返回 JSON 內容的方式,示例代碼如下所示:

//數據源,類似MySQL中的數據
var users = []User{{ID: 1,Name: "張三"},{ID: 2,Name: "李四"},{ID: 3,Name: "王五"},
}
func handleUsers(w http.ResponseWriter, r *http.Request){switch r.Method {case "GET":users,err:=json.Marshal(users)if err!=nil {w.WriteHeader(http.StatusInternalServerError)fmt.Fprint(w,"{\"message\": \""+err.Error()+"\"}")}else {w.WriteHeader(http.StatusOK)w.Write(users)}default:w.WriteHeader(http.StatusNotFound)fmt.Fprint(w,"{\"message\": \"not found\"}")}
}
//用戶
type User struct {ID intName string
}

從以上代碼可以看到,這次的改造主要是新建了一個 User 結構體,并且使用 users 這個切片存儲所有的用戶,然后在 handleUsers 函數中把它轉化為一個 JSON 數組返回。這樣,就實現了基于 JSON 數據格式的 RESTful API。

運行這個示例,在瀏覽器中輸入 http://localhost:8080/users,可以看到如下信息:

[{"ID":1,"Name":"張三"},{"ID":2,"Name":"李四"},{"ID":3,"Name":"王五"}]

4. Gin 框架

雖然 Go 語言自帶的 net/http 包,可以比較容易地創建 HTTP 服務,但是它也有很多不足:

  • 不能單獨地對請求方法(POST、GET 等)注冊特定的處理函數;
  • 不支持 Path 變量參數;
  • 不能自動對 Path 進行校準;
  • 性能一般;
  • 擴展性不足;
  • ……

基于以上這些不足,出現了很多 Golang Web 框架,如 Mux,Gin、Fiber 等,其中使用最多是 Gin 框架。

4.1 導入 Gin 框架

Gin 框架是一個在 Github 上開源的 Web 框架,封裝了很多 Web 開發需要的通用功能,并且性能也非常高,可以很容易地寫出 RESTful API。

Gin 框架其實是一個模塊,也就是 Go Mod,所以采用 Go Mod 的方法引入即可。

安裝代碼如下:

$ go get -u github.com/gin-gonic/gin

導入代碼如下:

import "github.com/gin-gonic/gin"

4.2 使用 Gin 框架

用 Gin 框架重寫上面的示例,修改的代碼如下所示:

func main() {r:=gin.Default()r.GET("/users", listUser)r.Run(":8080")
}
func listUser(c *gin.Context)  {c.JSON(200,users)
}

相比 net/http 包,Gin 框架的代碼非常簡單,通過它的 GET 方法就可以創建一個只處理 HTTP GET 方法的服務,而且輸出 JSON 格式的數據也非常簡單,使用 c.JSON 方法即可。

最后通過 Run 方法啟動 HTTP 服務,監聽在 8080 端口。運行這個示例,在瀏覽器中輸入 http://localhost:8080/users,看到的信息和通過 net/http 包實現的效果是一樣的。

4.2.1 獲取特定的用戶(GET)

如果要獲得特定用戶的信息,需要使用的是 GET 方法,并且 URL 格式如下所示:

http://localhost:8080/users/2

以上示例中的 2 是用戶的 ID,也就是通過 ID 來獲取特定的用戶。

通過 Gin 框架 Path 路徑參數可以實現這個功能,示例代碼如下:

func main() {//省略沒有改動的代碼r.GET("/users/:id", getUser)
}
func getUser(c *gin.Context) {id := c.Param("id")var user Userfound := false//類似于數據庫的SQL查詢for _, u := range users {if strings.EqualFold(id, strconv.Itoa(u.ID)) {user = ufound = truebreak}}if found {c.JSON(200, user)} else {c.JSON(404, gin.H{"message": "用戶不存在",})}
}

在 Gin 框架中,路徑中使用冒號表示 Path 路徑參數,比如示例中的 :id,然后在 getUser 函數中可以通過 c.Param(“id”) 獲取需要查詢用戶的 ID 值。

Param 方法的參數要和 Path 路徑參數中的一致,比如示例中都是 ID。

運行這個示例,通過瀏覽器訪問 http://localhost:8080/users/2,就可以獲得 ID 為 2 的用戶,輸出信息如下所示:

{"ID":2,"Name":"李四"}

假如我們訪問一個不存在的 ID,得到的結果如下所示:

? curl http://localhost:8080/users/99
{"message":"用戶不存在"}%
4.2.2 新增一個用戶(POST)

根據 RESTful API 規范,實現新增使用的是 POST 方法,并且 URL 的格式為 http://localhost:8080/users ,向這個 URL 發送數據,就可以新增一個用戶,然后返回創建的用戶信息。

使用 Gin 框架實現新增一個用戶,示例代碼如下:

func main() {//省略沒有改動的代碼r.POST("/users", createUser)
}
func createUser(c *gin.Context) {name := c.DefaultPostForm("name", "")if name != "" {u := User{ID: len(users) + 1, Name: name}users = append(users, u)c.JSON(http.StatusCreated,u)} else {c.JSON(http.StatusOK, gin.H{"message": "請輸入用戶名稱",})}
}

以上新增用戶的主要邏輯是獲取客戶端上傳的 name 值,然后生成一個 User 用戶,最后把它存儲到 users 集合中,達到新增用戶的目的。

在這個示例中,使用 POST 方法來新增用戶,所以只能通過 POST 方法才能新增用戶成功。

運行這個示例,通過如下命令發送一個新增用戶的請求,查看結果:

? curl -X POST -d 'name=小明' http://localhost:8080/users
{"ID":4,"Name":"小明"}
4.2.3 刪除一個用戶(DELETE)

刪除一個用戶比較簡單,它的 API 格式和獲取一個用戶一樣,但是 HTTP 方法換成了DELETE。示例代碼如下所示:

func main() {//省略沒有修改的代碼r.DELETE("/users/:id", deleteUser)
}
func deleteUser(c *gin.Context) {id := c.Param("id")i := -1//類似于數據庫的SQL查詢for index, u := range users {if strings.EqualFold(id, strconv.Itoa(u.ID)) {i = indexbreak}}if i >= 0 {users = append(users[:i], users[i+1:]...)c.JSON(http.StatusNoContent, "")} else {c.JSON(http.StatusNotFound, gin.H{"message": "用戶不存在",})}
}

這個示例的邏輯就是注冊 DELETE 方法,達到刪除用戶的目的。刪除用戶的邏輯是通過ID 查詢:

  • 如果可以找到要刪除的用戶,記錄索引并跳出循環,然后根據索引刪除該用戶;
  • 如果找不到要刪除的用戶,則返回 404。
4.2.4 修改一個用戶的名字(PATCH)

修改和刪除一個用戶非常像,實現代碼如下所示:

func main() {//省略沒有修改的代碼r.PATCH("/users/:id",updateUserName)
}
func updateUserName(c *gin.Context) {id := c.Param("id")i := -1//類似于數據庫的SQL查詢for index, u := range users {if strings.EqualFold(id, strconv.Itoa(u.ID)) {i = indexbreak}}if i >= 0 {users[i].Name = c.DefaultPostForm("name",users[i].Name)c.JSON(http.StatusOK, users[i])} else {c.JSON(http.StatusNotFound, gin.H{"message": "用戶不存在",})}
}

邏輯和刪除的差不多的,只不過這里使用的是 PATCH方法。

二、 RPC 跨平臺服務

1. 定義

RPC,也就是遠程過程調用,是分布式系統中不同節點調用的方式(進程間通信),屬于 C/S 模式。RPC 由客戶端發起,調用服務端的方法進行通信,然后服務端把結果返回給客戶端。

RPC的核心有兩個:通信協議序列化。在 HTTP 2 之前,一般采用自定義 TCP 協議的方式進行通信,HTTP 2 出來后,也有采用該協議的,比如流行的gRPC。

序列化反序列化是一種把傳輸內容編碼和解碼的方式,常見的編解碼方式有 JSON、Protobuf 等。

在大多數 RPC的架構設計中,都有ClientClient StubServerServer Stub這四個組件,Client 和 Server 之間通過 Socket 進行通信。RPC 架構如下圖所示:
在這里插入圖片描述
RPC 調用的流程:

  1. 客戶端(Client)調用客戶端存根(Client Stub),同時把參數傳給客戶端存根;
  2. 客戶端存根將參數打包編碼,并通過系統調用發送到服務端;
  3. 客戶端本地系統發送信息到服務器;
  4. 服務器系統將信息發送到服務端存根(Server Stub);
  5. 服務端存根解析信息,也就是解碼;
  6. 服務端存根調用真正的服務端程序(Sever);
  7. 服務端(Server)處理后,通過同樣的方式,把結果再返回給客戶端(Client)。

RPC 調用常用于大型項目,也就是常說的微服務,而且還會包含服務注冊、治理、監控等功能,是一套完整的體系。

2. Go語言中的RPC

在 Go SDK 中,已經內置了 net/rpc 包來幫助開發者實現 RPC。簡單來說,net/rpc 包提供了通過網絡訪問服務端對象方法的能力。

在實際的項目開發中,使用Go 語言自帶的 RPC 框架并不多,比較常用的是Google的gRPC 框架,它是通過Protobuf 序列化的,是基于 HTTP/2 協議的二進制傳輸,并且支持很多編程語言,效率也比較高。

2.1 服務端

一個 RPC 示例的服務端代碼如下所示:

package server
type MathService struct {
}
type Args struct {A, B int
}
func (m *MathService) Add(args Args, reply *int) error {*reply = args.A + args.Breturn nil
}

在以上代碼中:

  • 定義了MathService,用于表示一個遠程服務對象;
  • Args 結構體用于表示參數;
  • Add 這個方法實現了加法的功能,加法的結果通過 replay這個指針變量返回。

定義好服務對象就可以把它注冊到暴露的服務列表中,以供其他客戶端使用了。在Go 語言中,要注冊一個RPC 服務對象可以通過 RegisterName 方法,示例代碼如下所示:

package main
import ("server""log""net""net/rpc"
)
func main()  {rpc.RegisterName("MathService",new(server.MathService))l, e := net.Listen("tcp", ":1234")if e != nil {log.Fatal("listen error:", e)}rpc.Accept(l)
}

以上示例代碼中,通過 RegisterName 函數注冊了一個服務對象,該函數接收兩個參數:

  1. 服務名稱(MathService);
  2. 具體的服務對象,也就是剛剛定義好的MathService 這個結構體。

然后通過 net.Listen 函數建立一個TCP 鏈接,在 1234 端口進行監聽,最后通過 rpc.Accept 函數在該 TCP 鏈接上提供 MathService 這個 RPC 服務。現在客戶端就可以看到MathService這個服務以及它的Add 方法了。

在 net/rpc 這個RPC框架時,要想把一個對象注冊為 RPC 服務,可以讓客戶端遠程訪問,那么該對象(類型)的方法必須滿足如下條件:

  • 方法的類型是可導出的(公開的);
  • 方法本身也是可導出的;
  • 方法必須有 2 個參數,并且參數類型是可導出或者內建的;
  • 方法必須返回一個 error 類型。

總結來說該方法的格式如下所示:

func (t *T) MethodName(argType T1, replyType *T2) error

這里面的 T1、T2都是可以被 encoding/gob 序列化的。

  • 第一個參數 argType 是調用者(客戶端)提供的;
  • 第二個參數 replyType是返回給調用者結果,必須是指針類型。

2.2 客戶端

代碼如下所示:

package main
import ("fmt""server""log""net/rpc"
)
func main()  {client, err := rpc.Dial("tcp",  "localhost:1234")if err != nil {log.Fatal("dialing:", err)}args := server.Args{A:7,B:8}var reply interr = client.Call("MathService.Add", args, &reply)if err != nil {log.Fatal("MathService.Add error:", err)}fmt.Printf("MathService.Add: %d+%d=%d", args.A, args.B, reply)
}

在以上實例代碼中,首先通過 rpc.Dial 函數建立 TCP 鏈接。TCP 鏈接建立成功后,就需要準備遠程方法需要的參數,也就是示例中的args 和 reply。參數準備好之后,就可以通過 Call 方法調用遠程的RPC 服務了。Call 方法有 3 個參數,它們的作用分別如下所示:

  1. 調用的遠程方法的名字,這里是MathService.Add,點前面的部分是注冊的服務的名稱,點后面的部分是該服務的方法;
  2. 客戶端為了調用遠程方法提供的參數,示例中是args;
  3. 為了接收遠程方法返回的結果,必須是一個指針,也就是示例中的 &reply,這樣客戶端就可以獲得服務端返回的結果了。

3. 基于 HTTP 的RPC

RPC 除了可以通過 TCP 協議調用之外,還可以通過HTTP 協議進行調用,而且內置的net/rpc 包已經支持,修改以上示例代碼支持 HTTP 協議的調用,服務端代碼如下所示:

func main() {rpc.RegisterName("MathService", new(server.MathService))rpc.HandleHTTP()//新增的l, e := net.Listen("tcp", ":1234")if e != nil {log.Fatal("listen error:", e)}http.Serve(l, nil)//換成http的服務
}

客戶端修改的代碼如下所示:

func main()  {client, err := rpc.DialHTTP("tcp",  "localhost:1234")//省略了其他沒有修改的代碼
}

可以看到,只需要把建立鏈接的方法從 Dial 換成 DialHTTP 即可。

Go 語言 net/rpc 包提供的 HTTP 協議的 RPC 還有一個調試的 URL,運行服務端代碼后,在瀏覽器中輸入 http://localhost:1234/debug/rpc 回車,即可看到服務端注冊的RPC 服務,以及每個服務的方法,如下圖所示:
在這里插入圖片描述
如上圖所示,注冊的 RPC 服務、方法的簽名、已經被調用的次數都可以看到。

3. JSON RPC 跨平臺通信

以上實現的RPC 服務是基于 gob 編碼的,這種編碼在跨語言調用的時候比較困難,當前在微服務架構中,RPC 服務的實現者和調用者都可能是不同的編程語言,因此實現的 RPC 服務要支持多語言的調用。

3.1 基于 TCP 的 JSON RPC

實現跨語言 RPC 服務的核心在于選擇一個通用的編碼,這樣大多數語言都支持,比如常用的JSON。在 Go 語言中,實現一個 JSON RPC 服務非常簡單,只需要使用 net/rpc/jsonrpc 包即可。

以上面的示例為例,改造成支持 JSON的RPC 服務,服務端代碼如下所示:

func main() {rpc.RegisterName("MathService", new(server.MathService))l, e := net.Listen("tcp", ":1234")if e != nil {log.Fatal("listen error:", e)}for {conn, err := l.Accept()if err != nil {log.Println("jsonrpc.Serve: accept:", err.Error())return}//json rpcgo jsonrpc.ServeConn(conn)}
}

從以上代碼可以看到,相比 gob 編碼的RPC 服務,JSON 的 RPC 服務是把鏈接交給了jsonrpc.ServeConn這個函數處理,達到了基于 JSON 進行 RPC 調用的目的。

JSON RPC 的客戶端代碼修改的部分如下所示:

func main()  {client, err := jsonrpc.Dial("tcp",  "localhost:1234")//省略了其他沒有修改的代碼
}

從以上代碼可以看到,只需要把建立鏈接的 Dial方法換成 jsonrpc 包中的即可。

3.2 基于 HTTP的JSON RPC

Go 語言內置的jsonrpc 并沒有實現基于 HTTP的傳輸,需要自己實現,這里參考 gob 編碼的HTTP RPC 實現方式,來實現基于 HTTP的JSON RPC 服務。

RPC 服務端代碼如下所示:

func main() {rpc.RegisterName("MathService", new(server.MathService))//注冊一個path,用于提供基于http的json rpc服務http.HandleFunc(rpc.DefaultRPCPath, func(rw http.ResponseWriter, r *http.Request) {conn, _, err := rw.(http.Hijacker).Hijack()if err != nil {log.Print("rpc hijacking ", r.RemoteAddr, ": ", err.Error())return}var connected = "200 Connected to JSON RPC"io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")jsonrpc.ServeConn(conn)})l, e := net.Listen("tcp", ":1234")if e != nil {log.Fatal("listen error:", e)}http.Serve(l, nil)//換成http的服務
}

以上代碼的實現基于 HTTP 協議的核心,即使用 http.HandleFunc 注冊了一個 path,對外提供基于 HTTP 的 JSON RPC 服務。在這個 HTTP 服務的實現中,通過Hijack方法劫持鏈接,然后轉交給 jsonrpc 處理,這樣就實現了基于 HTTP 協議的 JSON RPC 服務。

客戶端調用的代碼如下所示:

func main()  {client, err := DialHTTP("tcp",  "localhost:1234")if err != nil {log.Fatal("dialing:", err)}args := server.Args{A:7,B:8}var reply interr = client.Call("MathService.Add", args, &reply)if err != nil {log.Fatal("MathService.Add error:", err)}fmt.Printf("MathService.Add: %d+%d=%d", args.A, args.B, reply)}// DialHTTP connects to an HTTP RPC server at the specified network address// listening on the default HTTP RPC path.func DialHTTP(network, address string) (*rpc.Client, error) {return DialHTTPPath(network, address, rpc.DefaultRPCPath)}// DialHTTPPath connects to an HTTP RPC server// at the specified network address and path.func DialHTTPPath(network, address, path string) (*rpc.Client, error) {var err errorconn, err := net.Dial(network, address)if err != nil {return nil, err}io.WriteString(conn, "GET "+path+" HTTP/1.0\n\n")// Require successful HTTP response// before switching to RPC protocol.resp, err := http.ReadResponse(bufio.NewReader(conn), &http.Request{Method: "GET"})connected := "200 Connected to JSON RPC"if err == nil && resp.Status == connected {return jsonrpc.NewClient(conn), nil}if err == nil {err = errors.New("unexpected HTTP response: " + resp.Status)}conn.Close()return nil, &net.OpError{Op:   "dial-http",Net:  network + " " + address,Addr: nil,Err:  err,}}

以上這段代碼的核心在于通過建立好的TCP 鏈接,發送 HTTP 請求調用遠程的HTTP JSON RPC 服務,這里使用的是 HTTP GET 方法。

三、Go 語言的發展前景

Go 語言就是為云而生的編程語言,所以在云原生的時代,它就具備了天生的優勢:易于學習、天然的并發、高效的網絡支持、跨平臺的二進制文件編譯等。

CNCF(云原生計算基金會)對云原生的定義是:

  • 應用容器化;
  • 面向微服務架構;
  • 應用支持容器的編排調度。

對于這三點有代表性的 Docker、K8s 以及 istio 都是采用 Go 語言編寫的,所以 Go 語言在云原生中發揮了極大的優勢。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/37925.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/37925.shtml
英文地址,請注明出處:http://en.pswp.cn/news/37925.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【前端 | CSS】align-items與align-content的區別

align-items 描述 CSS align-items 屬性將所有直接子節點上的 align-self 值設置為一個組。align-self 屬性設置項目在其包含塊中在交叉軸方向上的對齊方式 align-items是針對每一個子項起作用,它的基本單位是每一個子項,在所有情況下都有效果&…

SpringBoot復習:(31)Controller中返回的對象是如何轉換成json字符串給調用者的?

首先,SpringBoot自動裝配了HttpMessageConvertersAutoConfiguration這個自動配置類 而這個自動配置類又通過Import注解導入了JacksonHttpMessageConvertersConfiguration類, 在這個類中配置了一個類型為MappingJackson2HttpMessageConverter類型的bean…

vant van-tabs van-pull-refresh van-list 標簽欄+上拉加載+下拉刷新

<template><div class"huibj"><div class"listtab"><!--頂部導航--><div class"topdh"><topnav topname"余額明細"></topnav></div><!--Tab 標簽--><van-tabs v-model"…

Python教程(9)——Python變量類型列表list的用法介紹

列表操作 創建列表訪問列表更改列表元素增加列表元素修改列表元素刪除列表元素 刪除列表 在Python中&#xff0c;列表&#xff08;list&#xff09;是一種有序、可變的數據結構&#xff0c;用于存儲多個元素。列表可以包含不同類型的元素&#xff0c;包括整數、浮點數、字符串等…

配置 yum/dnf 置您的系統以使用默認存儲庫

題目 給系統配置默認存儲庫&#xff0c;要求如下&#xff1a; YUM 的 兩 個 存 儲 庫 的 地 址 分 別 是 &#xff1a; ftp://host.domain8.rhce.cc/dvd/BaseOS ftp://host.domain8.rhce.cc/dvd/AppStream vim /etc/yum.repos.d/redhat.repo [base] namebase baseurlftp:/…

C語言快速回顧(一)

前言 在Android音視頻開發中&#xff0c;網上知識點過于零碎&#xff0c;自學起來難度非常大&#xff0c;不過音視頻大牛Jhuster提出了《Android 音視頻從入門到提高 - 任務列表》&#xff0c;結合我自己的工作學習經歷&#xff0c;我準備寫一個音視頻系列blog。C/C是音視頻必…

Rabbitmq延遲消息

目錄 一、延遲消息1.基于死信實現延遲消息1.1 消息的TTL&#xff08;Time To Live&#xff09;1.2 死信交換機 Dead Letter Exchanges1.3 代碼實現 2.基于延遲插件實現延遲消息2.1 插件安裝2.2 代碼實現 3.基于延遲插件封裝消息 一、延遲消息 延遲消息有兩種實現方案&#xff…

2016年,進了百度

昨在深圳出差&#xff0c;與微信里的朋友吃了個便飯&#xff0c;他是今年四月份加的我微信&#xff08;gaoyang677&#xff09;&#xff0c;他的經歷很有意思&#xff0c;經他許可&#xff0c;分享給大家。 2012年時候&#xff0c;他大學畢業來到深圳&#xff0c;進了廠子&…

vue3 setup+Taro3 調用原生小程序自定義年月日時分多列選擇器,NutUI改造

vue3 setupTaro3 調用原生小程序自定義年月日時分多列選擇器&#xff0c;NutUI改造 NutUI 有日期時間選擇器&#xff0c;但是滑動效果太差&#xff0c;卡頓明顯。換成 原生小程序 很順暢 上代碼&#xff1a; <template><view><pickermode"multiSelector&…

2023牛客暑期多校訓練營9-J Puzzle: Star Battle

2023牛客暑期多校訓練營9-J Puzzle: Star Battle https://ac.nowcoder.com/acm/contest/57363/J 文章目錄 2023牛客暑期多校訓練營9-J Puzzle: Star Battle題意解題思路代碼 題意 解題思路 出題人都說是詐騙題&#xff08;&#xff0c;可以發現滿足每行每列恰好有 n n n個星…

python數據結構和算法

python數據結構和算法 參考 python圖解算法 選擇/快速排序 哈希表 廣度優先搜索算法 迪杰斯特拉算法 貪婪算法 動態規劃 K-鄰近算法 計算機科學是解決問題的研究。計算機科學使用抽象作為表示過程和數據的工具。抽象的數據類型允許程序員通過隱藏數據的細節來管理問題領域的…

【解決】Kafka Exception thrown when sending a message with key=‘null‘ 異常

問題原因&#xff1a; 如下圖&#xff0c;kafka 中配置的是監聽域名的方式&#xff0c;但程序里使用的是 ip:port 的連接方式。 解決辦法&#xff1a; kafka 中配置的是域名的方式&#xff0c;程序里也相應配置成 域名:port 的方式&#xff08;注意&#xff1a;本地h…

機器學習筆記之優化算法(十三)關于二次上界引理

機器學習筆記之優化算法——關于二次上界引理 引言回顧&#xff1a;利普希茲連續梯度下降法介紹 二次上界引理&#xff1a;介紹與作用二次上界與最優步長之間的關系二次上界引理證明過程 引言 本節將介紹二次上界的具體作用以及它的證明過程。 回顧&#xff1a; 利普希茲連續…

uniapp 微信小程序 訂閱消息

第一步&#xff0c;需要先去小程序官方挑選一下訂閱模板拿到模板id 訂閱按鈕在頭部導航上&#xff0c;所以 <u-navbar :bgColor"bgColor"><view class"u-nav-slot" slot"left" click"goSubscribe"><image :src"g…

阿里社招一面記錄

一輪電話面試&#xff0c;一個半小時&#xff0c;昨天晚上面試的&#xff0c;今早面試官打電話約了二面&#xff08;為啥是一面面試官:&#xff09; 自我介紹 工作經歷&#xff0c;項目經歷項目挑兩個介紹一下 這里介紹了一個偏技術的基于Mysql搭建的olap系統&#xff0c;數據…

綜述:計算機視覺中的圖像分割

一、說明 這篇文章是關于圖像分割的探索&#xff0c;這是解決計算機視覺問題&#xff08;如對象檢測、對象識別、圖像編輯、醫學圖像分析、自動駕駛汽車等&#xff09;的重要步驟之一。讓我們從介紹開始。 二、圖像分割介紹 圖像分割是計算機視覺中的一項基本任務&#xff0c;涉…

【Maven】SpringBoot項目使用maven-assembly-plugin插件多環境打包

SpringBoot項目使用maven-assembly-plugin插件多環境打包 1.創建SpringBoot項目并在pom.xml文件中添加maven-assembly-plugin配置 <!-- 多環境配置 --><profiles><!-- 開發環境 --><profile><id>dev</id><properties><prof…

新一代分布式融合存儲,數據場景All In One

1、摘要 2023年5月11日&#xff0c;浪潮信息全國巡展廣州站正式啟航。會上&#xff0c;重磅發布新一代分布式融合存儲AS13000G7&#xff0c;其采用極致融合架構設計理念&#xff0c;實現同一套存儲滿足四種非結構化數據的“All In One”高效融合&#xff0c;數據存力提升300%&a…

基于WebSocket的在線文字聊天室

與Ajax不同&#xff0c;WebSocket可以使服務端主動向客戶發送響應&#xff0c;本案例就是基于WebSocket的一個在線聊天室&#xff0c;不過功能比較簡單&#xff0c;只能滿足文字交流。演示如下。 案例學習于b站up主&#xff0c;鏈接 。這位up主講的非常清楚&#xff0c;值得去學…

item_get_sales-獲取TB商品銷量詳情

一、接口參數說明&#xff1a; item_get_sales-獲取商品銷量詳情&#xff0c;點擊更多API調試&#xff0c;請移步注冊API賬號點擊獲取測試key和secret 公共參數 請求地址: https://api-gw.onebound.cn/taobao/item_get_sales 名稱類型必須描述keyString是調用key&#xff08…