日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
從Discord的做法中學(xué)習(xí)—使用Golang進(jìn)行請求合并

正如你可能之前看到的,Discord去年發(fā)布了一篇有價值的文章,討論了他們成功存儲了數(shù)萬億條消息。雖然有很多關(guān)于這篇文章的YouTube視頻和文章,但我認(rèn)為這篇文章中一個名為“數(shù)據(jù)服務(wù)為數(shù)據(jù)服務(wù)”的部分沒有得到足夠的關(guān)注。在這篇文章中,我們將討論Discord對數(shù)據(jù)服務(wù)的方法,并探討如何利用Golang的并發(fā)特性來減少特定情況下的數(shù)據(jù)庫負(fù)載。

公司主營業(yè)務(wù):網(wǎng)站建設(shè)、成都網(wǎng)站建設(shè)、移動網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)公司是一支青春激揚、勤奮敬業(yè)、活力青春激揚、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊有機(jī)會用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)公司推出原陽免費做網(wǎng)站回饋大家。

數(shù)據(jù)服務(wù)拯救熱分區(qū)

如你所知,消息和頻道是Discord中最常用的組件。讓我們想象一個場景:一個擁有50萬成員的頻道的管理員提到@everyone。會發(fā)生什么?成千上萬個同時的請求直接指向那個數(shù)據(jù)庫分區(qū),所有請求的目標(biāo)都是檢索相同的消息。這種模式重復(fù)發(fā)生,直到該分區(qū)無法回應(yīng)其他請求。

Discord引入了一個位于Python API和數(shù)據(jù)庫集群之間的中間服務(wù) — 他們稱之為數(shù)據(jù)服務(wù)。這個服務(wù)大致包含每個查詢一個gRPC端點,沒有任何業(yè)務(wù)邏輯。對Discord來說,這個服務(wù)的重要特性就是請求合并。

請求合并

正如我們之前討論過的,每當(dāng)在一個龐大的頻道中有提及時,就會有大量類似的請求直接指向數(shù)據(jù)庫分區(qū)。通過合并這些請求,如果多個用戶請求相同的數(shù)據(jù)庫行,我們可以將這些請求合并成一個選擇查詢,并執(zhí)行該查詢。

通過使用數(shù)據(jù)服務(wù)而不是直接連接到數(shù)據(jù)庫,我們可以實現(xiàn)許多令人興奮的功能,比如批量查詢,這些功能可以顯著減少數(shù)據(jù)庫開銷,并改善查詢的平均值,特別是第99百分位數(shù)。

使用Golang實現(xiàn)簡單的請求合并

與許多其他公司一樣,Discord使用Python作為其主要的后端語言。無論是微服務(wù)還是單體架構(gòu),后端服務(wù)通常直接連接到數(shù)據(jù)源進(jìn)行查詢。雖然Python確實是一種多功能語言,但在并發(fā)性方面存在一些不足。使用Python實現(xiàn)并發(fā)和高吞吐量的服務(wù)可能有些挑戰(zhàn),而性能與用C++、Rust和Golang等編譯語言編寫的類似服務(wù)相比,往往會較低。

在進(jìn)行任何操作之前,讓我們模擬一下提到的情況。假設(shè)服務(wù)總共收到了5,000個請求,其中并發(fā)數(shù)為1,000。

  • 總請求數(shù): 5,000
  • 并發(fā)數(shù): 1,000
  • 需要檢索的唯一消息數(shù): 100
type Message struct {
   gorm.Model

   Text string
   User string // some random properties that a message row may have
}


func generateRandomData(db *gorm.DB) {
 for i := 0; i < 100; i++ {
  msg := &messages.Message{Text: fmt.Sprintf("Message #%d", i)}
  db.Save(msg)
 }
}

我使用Gorm構(gòu)建了一個簡單的數(shù)據(jù)庫模型來表示Message(消息)表,然后向表中填充了100條虛擬消息。

e := echo.New()
e.GET("/randomMessage", func(c echo.Context) error {
   randomMessageID := rand.Intn(100)
   var msg messages.Message
   if err := db.Where("id=?", randomMessageID).First(&msg).Error; err != nil {
      return err
   }
   return c.JSON(200, msg)
})
e.Logger.Fatal(e.Start(":1323"))

我創(chuàng)建了一個簡單的端點來模擬對0到100之間的隨機(jī)ID進(jìn)行SELECT查詢?,F(xiàn)在我們可以對這個端點進(jìn)行基準(zhǔn)測試,模擬在這種情況下會發(fā)生什么。

img

  • 平均每秒請求數(shù) (RPS): 300
  • 平均響應(yīng)時間: 3.2秒
  • 50% 響應(yīng)時間: 546毫秒
  • 99% 響應(yīng)時間: 14.7秒

如果我們有10秒的超時策略,大約有2%的請求將收不到響應(yīng)?,F(xiàn)在讓我們改變代碼。Golang有一個名為“single flight”的內(nèi)置包。這個包提供了重復(fù)函數(shù)調(diào)用抑制機(jī)制。一般來說,你給它一個鍵和一個函數(shù),而不是多次運行該函數(shù),SingleFlight會暫時保持其他調(diào)用,直到第一次調(diào)用完成其請求并以相同的結(jié)果作出響應(yīng)。

var g = singleflight.Group{}
e.GET("/randomMessage", func(c echo.Context) error {
   randomMessageID := rand.Intn(100)
   msg, err, _ := g.Do(fmt.Sprint(randomMessageID), func() (interface{}, error) {
      var msg messages.Message
      if err := db.Where("id=?", randomMessageID).First(&msg).Error; err != nil {
         return nil, err
      }
      return &msg, nil
   })
   if err != nil {
      return err
   }
   return c.JSON(200, msg)
})

func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool)

Do 執(zhí)行并返回給定函數(shù)的結(jié)果,確保同一時間針對給定鍵只有一個執(zhí)行過程。如果出現(xiàn)重復(fù),重復(fù)的調(diào)用者會等待原始調(diào)用完成并接收相同的結(jié)果。返回值 shared 表示是否將 v 給了多個調(diào)用者。

現(xiàn)在讓我們重新運行模擬并比較結(jié)果。

  • 平均每秒請求數(shù) (RPS): 2309
  • 平均響應(yīng)時間: 433毫秒
  • 50% 響應(yīng)時間: 389毫秒
  • 99% 響應(yīng)時間: 777毫秒

正如你所看到的,僅使用了一個簡單的技術(shù)就將第99百分位數(shù)減少了14秒,新方法支持的每秒請求次數(shù)提高了7.6倍。

結(jié)論

從那時起我們就注意到,通過優(yōu)化數(shù)據(jù)庫查詢,可以大大提高應(yīng)用程序的整體性能。雖然我們討論的方法是情景性的,但Discord已經(jīng)使用了一年多,對他們有很大幫助。

你應(yīng)該知道,如果你使用數(shù)據(jù)服務(wù),你將面臨其他的復(fù)雜情況。例如,你可能會有多個數(shù)據(jù)服務(wù)實例,而你的Python API必須有一種機(jī)制將類似的請求發(fā)送到同一個實例。


當(dāng)前標(biāo)題:從Discord的做法中學(xué)習(xí)—使用Golang進(jìn)行請求合并
網(wǎng)頁URL:http://www.5511xx.com/article/cojgdse.html