最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

go zero微服務(wù)高在請求量下如何優(yōu)化

 更新時間:2022年07月05日 16:51:58   作者:kevinwan  
這篇文章主要為大家介紹了go zero微服務(wù)高在請求量下的優(yōu)化處理,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

引言

前兩篇文章我們介紹了緩存使用的各種最佳實踐,首先介紹了緩存使用的基本姿勢,分別是如何利用go-zero自動生成的緩存和邏輯代碼中緩存代碼如何寫,接著講解了在面對緩存的穿透、擊穿、雪崩等常見問題時的解決方案,最后還重點講解了如何保證緩存的一致性。

因為緩存對于高并發(fā)服務(wù)來說實在是太重要了,所以這篇文章我們還會繼續(xù)一起學(xué)習(xí)下緩存相關(guān)的知識。

本地緩存

當我們遇到極端熱點數(shù)據(jù)查詢的時候,這個時候就要考慮本地緩存了。熱點本地緩存主要部署在應(yīng)用服務(wù)器的代碼中,用于阻擋熱點查詢對于Redis等分布式緩存或者數(shù)據(jù)庫的壓力。

在我們的商城中,首頁Banner中會放一些廣告商品或者推薦商品,這些商品的信息由運營在管理后臺錄入和變更。這些商品的請求量非常大,即使是Redis也很難扛住,所以這里我們可以使用本地緩存來進行優(yōu)化。

在product庫中先建一張商品運營表product_operation,為了簡化只保留必要字段,product_id為推廣運營的商品id,status為運營商品的狀態(tài),status為1的時候會在首頁Banner中展示該商品。

CREATE TABLE `product_operation` (
  `id` bigint unsigned NOT NULL AUTO_INCREMENT,
  `product_id` bigint unsigned NOT NULL DEFAULT 0 COMMENT '商品id',
  `status` int NOT NULL DEFAULT '1' COMMENT '運營商品狀態(tài) 0-下線 1-上線',
  `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '創(chuàng)建時間',
  `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新時間',
  PRIMARY KEY (`id`),
  KEY `ix_update_time` (`update_time`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COMMENT='商品運營表';

本地緩存的實現(xiàn)比較簡單,我們可以使用map來自己實現(xiàn),在go-zero的collection中提供了Cache來實現(xiàn)本地緩存的功能,我們直接拿來用,重復(fù)造輪子從來不是一個明智的選擇,localCacheExpire為本地緩存過期時間,Cache提供了Get和Set方法,使用非常簡單

localCache, err := collection.NewCache(localCacheExpire)

先從本地緩存中查找,如果命中緩存則直接返回。沒有命中緩存的話需要先從數(shù)據(jù)庫中查詢運營位商品id,然后再聚合商品信息,最后回塞到本地緩存中。詳細代碼邏輯如下:

func (l *OperationProductsLogic) OperationProducts(in *product.OperationProductsRequest) (*product.OperationProductsResponse, error) {
  opProducts, ok := l.svcCtx.LocalCache.Get(operationProductsKey)
  if ok {
    return &product.OperationProductsResponse{Products: opProducts.([]*product.ProductItem)}, nil
  }
  pos, err := l.svcCtx.OperationModel.OperationProducts(l.ctx, validStatus)
  if err != nil {
    return nil, err
  }
  var pids []int64
  for _, p := range pos {
    pids = append(pids, p.ProductId)
  }
  products, err := l.productListLogic.productsByIds(l.ctx, pids)
  if err != nil {
    return nil, err
  }
  var pItems []*product.ProductItem
  for _, p := range products {
    pItems = append(pItems, &product.ProductItem{
      ProductId: p.Id,
      Name:      p.Name,
    })
  }
  l.svcCtx.LocalCache.Set(operationProductsKey, pItems)
  return &product.OperationProductsResponse{Products: pItems}, nil
}

使用grpurl調(diào)試工具請求接口,第一次請求cache miss后,后面的請求都會命中本地緩存,等到本地緩存過期后又會重新回源db加載數(shù)據(jù)到本地緩存中

~ grpcurl -plaintext -d '{}' 127.0.0.1:8081 product.Product.OperationProducts
{
  "products": [
    {
      "productId": "32",
      "name": "電風(fēng)扇6"
    },
    {
      "productId": "31",
      "name": "電風(fēng)扇5"
    },
    {
      "productId": "33",
      "name": "電風(fēng)扇7"
    }
  ]
}

注意,并不是所有信息都適用于本地緩存,本地緩存的特點是請求量超高,同時業(yè)務(wù)上能夠允許一定的不一致,因為本地緩存一般不會主動做更新操作,需要等到過期后重新回源db后再更新。所以在業(yè)務(wù)中要視情況而定看是否需要使用本地緩存。

自動識別熱點數(shù)據(jù)

首頁Banner場景是由運營人員來配置的,也就是我們能提前知道可能產(chǎn)生的熱點數(shù)據(jù),但有些情況我們是不能提前預(yù)知數(shù)據(jù)會成為熱點的。

所以就需要我們能自適應(yīng)地自動的識別這些熱點數(shù)據(jù),然后把這些數(shù)據(jù)提升為本地緩存。

我們維護一個滑動窗口,比如滑動窗口設(shè)置為10s,就是要統(tǒng)計這10s內(nèi)有哪些key被高頻訪問,一個滑動窗口中對應(yīng)多個Bucket,每個Bucket中對應(yīng)一個map,map的key為商品的id,value為商品對應(yīng)的請求次數(shù)。

接著我們可以定時的(比如10s)去統(tǒng)計當前所有Buckets中的key的數(shù)據(jù),然后把這些數(shù)據(jù)導(dǎo)入到大頂堆中,輕而易舉的可以從大頂堆中獲取topK的key,我們可以設(shè)置一個閾值,比如在一個滑動窗口時間內(nèi)某一個key訪問頻次超過500次,就認為該key為熱點key,從而自動地把該key升級為本地緩存。

緩存使用技巧

下面介紹一些緩存使用的小技巧

  • key的命名要盡量易讀,即見名知意,在易讀的前提下長度要盡可能的小,以減少資源的占用,對于value來說可以用int就盡量不要用string,對于小于N的value,redis內(nèi)部有shared_object緩存。
  • 在redis使用hash的情況下進行key的拆分,同一個hash key會落到同一個redis節(jié)點,hash過大的情況下會導(dǎo)致內(nèi)存以及請求分布的不均勻,考慮對hash進行拆分為小的hash,使得節(jié)點內(nèi)存均勻避免單節(jié)點請求熱點。
  • 為了避免不存在的數(shù)據(jù)請求,導(dǎo)致每次請求都緩存miss直接打到數(shù)據(jù)庫中,進行空緩存的設(shè)置。
  • 緩存中需要存對象的時候,序列化盡量使用protobuf,盡可能減少數(shù)據(jù)大小。
  • 新增數(shù)據(jù)的時候要保證緩存務(wù)必存在的情況下再去操作新增,使用Expire來判斷緩存是否存在。
  • 對于存儲每日登錄場景的需求,可以使用BITSET,為了避免單個BITSET過大或者熱點,可以進行sharding。
  • 在使用sorted set的時候,避免使用zrange或者zrevrange返回過大的集合,復(fù)雜度較高。
  • 在進行緩存操作的時候盡量使用PIPELINE,但也要注意避免集合過大。
  • 避免超大的value。
  • 緩存盡量要設(shè)置過期時間。
  • 慎用全量操作命令,比如Hash類型的HGETALL、Set類型的SMEMBERS等,這些操作會對Hash和Set的底層數(shù)據(jù)結(jié)構(gòu)進行全量掃描,如果數(shù)據(jù)量較多的話,會阻塞Redis主線程。
  • 獲取集合類型的全量數(shù)據(jù)可以使用SSCAN、HSCAN等命令分批返回集合中的數(shù)據(jù),減少對主線程的阻塞。
  • 慎用MONITOR命令,MONITOR命令會把監(jiān)控到的內(nèi)容持續(xù)寫入輸出緩沖區(qū),如果線上命令操作很多,輸出緩沖區(qū)很快就會溢出,會對Redis性能造成影響。
  • 生產(chǎn)環(huán)境禁用KEYS、FLUSHALL、FLUSHDB等命令。

結(jié)束語

已知的熱點緩存比較簡單,從數(shù)據(jù)庫中提前加載到內(nèi)存中即可,未知的熱點緩存我們需要自適應(yīng)的識別出熱點的數(shù)據(jù),然后把這些熱點的數(shù)據(jù)升級為本地緩存。最后介紹了一些實際生產(chǎn)中緩存使用的一些小技巧,在生產(chǎn)環(huán)境中要活靈活用盡量避免問題的產(chǎn)生。

代碼倉庫: https://github.com/zhoushuguang/lebron

項目地址: https://github.com/zeromicro/go-zero

本篇文章介紹了如何使用本地熱點緩存應(yīng)對超高的請求,熱點緩存又分為已知的熱點緩存和未知的熱點緩存,希望大家以后多多支持腳本之家!

相關(guān)文章

  • 關(guān)于golang高并發(fā)的實現(xiàn)與注意事項說明

    關(guān)于golang高并發(fā)的實現(xiàn)與注意事項說明

    這篇文章主要介紹了關(guān)于golang高并發(fā)的實現(xiàn)與注意事項說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • 詳解如何在golang鏡像中設(shè)置指定時區(qū)

    詳解如何在golang鏡像中設(shè)置指定時區(qū)

    這篇文章主要為大家詳細介紹了如何在golang鏡像中設(shè)置指定時區(qū),文中的示例代碼講解詳細,具有一定的借鑒價值,感興趣的可以了解一下
    2023-04-04
  • Go 結(jié)構(gòu)化日志slog入門與實戰(zhàn)指南 附避坑秘籍

    Go 結(jié)構(gòu)化日志slog入門與實戰(zhàn)指南 附避坑秘籍

    Go 1.21終于帶來了官方結(jié)構(gòu)化日志log/slog,本文將帶你從零上手 slog,并通過幾個小例子展示它如何讓日志變得更結(jié)構(gòu)化、可查詢、可維護,感興趣的朋友跟隨小編一起看看吧
    2026-02-02
  • Go語言標準庫sync.Once使用場景及性能優(yōu)化詳解

    Go語言標準庫sync.Once使用場景及性能優(yōu)化詳解

    這篇文章主要為大家介紹了Go語言標準庫sync.Once使用場景及性能優(yōu)化詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • golang time包做時間轉(zhuǎn)換操作

    golang time包做時間轉(zhuǎn)換操作

    這篇文章主要介紹了golang time包做時間轉(zhuǎn)換操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 在Go語言單元測試中解決HTTP網(wǎng)絡(luò)依賴問題

    在Go語言單元測試中解決HTTP網(wǎng)絡(luò)依賴問題

    在 Go 語言中,我們需要找到一種可靠的方法來測試 HTTP 請求和響應(yīng),本文將探討在 Go 中進行 HTTP 應(yīng)用測試時,如何解決應(yīng)用程序的依賴問題,以確保我們能夠編寫出可靠的測試用例,需要的朋友可以參考下
    2023-07-07
  • gin?session中間件使用及源碼流程分析

    gin?session中間件使用及源碼流程分析

    這篇文章主要為大家介紹了gin?session中間件使用及源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-10-10
  • 聊聊Golang中很好用的viper配置模塊

    聊聊Golang中很好用的viper配置模塊

    這篇文章主要介紹了Golang中很好用的viper配置模塊用法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • 使用GORM將PostgreSQL集成到Go框架中

    使用GORM將PostgreSQL集成到Go框架中

    在go中集成postgresql需使用gorm orm,步驟如下:安裝go和postgresql,安裝 gorm:go get -u gorm.io/gorm,配置數(shù)據(jù)庫連接字符串,定義模型類,遷移數(shù)據(jù)庫架構(gòu),使用 gorm 進行增刪改查操作,本指南將介紹如何使用 GORM(一個廣受歡迎的 ORM),將PostgreSQL集成到你的Go應(yīng)用中
    2024-08-08
  • go?doudou開發(fā)gRPC服務(wù)快速上手實現(xiàn)詳解

    go?doudou開發(fā)gRPC服務(wù)快速上手實現(xiàn)詳解

    這篇文章主要為大家介紹了go?doudou開發(fā)gRPC服務(wù)快速上手實現(xiàn)過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12

最新評論

泌阳县| 闵行区| 梁平县| 深水埗区| 新宁县| 库尔勒市| 日喀则市| 阳谷县| 句容市| 南投县| 武功县| 忻城县| 莱州市| 伊通| 柳江县| 沈阳市| 台中市| 长春市| 宣汉县| 满洲里市| 潞西市| 闸北区| 界首市| 安顺市| 尚义县| 南康市| 亚东县| 育儿| 鲁山县| 万州区| 格尔木市| 白玉县| 墨脱县| 平乐县| 中牟县| 南江县| 宁阳县| 淳化县| 深圳市| 永福县| 永定县|