手撕分布式緩存---HTTP Server搭建

??經過了前兩個章節的學習,分布式緩存的存儲與新增我們已經實現了,并且對其做了高可用處理。本章節我們剝離和緩存強相關的邏輯,開始搭建一個HTTP服務器,畢竟緩存數據庫搭建完之后別人沒法訪問也是沒有用處的。這一章節我們重點學習go原生的HTTP標準庫


前文鏈接

手撕分布式緩存之一 | 定義緩存結構體與實現底層功能函數
手撕分布式緩存之二 | 互斥鎖的優化


系列目錄

  • (1)HTTP Server 的搭建
    • (1.1)前言
    • (1.2)HTTP 核心數據結構的構造及初始化函數的實現
    • (1.3)單節點HTTP Server核心Get方法的實現
    • (1.4)代碼實現及解釋

(1)HTTP Server 的搭建

(1.1)前言

??通過本篇文章可以學習到 go 語言原生的 HTTP Server 的使用,雖然不像成熟的Web框架那樣,方法、機制都很完全,但是通過學習底層的功能實現,對于我們整體項目結構搭建是非常重要的。如果將go語言、go衍生技術(gin,MiddleWare等)等一系列相關的技術看做一整個項目結構,那么哪些技術我們要實現哪些功能呢?這些功能做出來實際上使用的人有多少呢?能給我們帶來多少價值?這些問題具象來看的話是與我們開發人員息息相關的,因此我們有必要去學習這種看似吃力不討好實際卻會給我們帶來很深遠的收益的知識。

(1.2)HTTP 核心數據結構的構造及初始化函數的實現

??go語言的HTTP服務為我們提供了 ListenAndServe(addr string, handler Handler) error 這個方法,handler是HTTP服務的主體處理函數,任何實現了 ServeHTTP 方法的對象都可以作為handler的值傳遞給ListenAndServe 方法。該方法除了handler參數還需要接收一個addr,用來標識服務啟動的地址和端口,這個也是服務啟動之后其他請求者訪問的域名。因此我們可以定義一個數據結構HTTPPool,里面有屬性 self string 和 basePath string,self是就是上面說的addr,basePath是用于區分服務器上其他服務的請求Url,避免重復,比如我們可以默認 /_geecache/ 作為我們請求URI(統一資源標識符)第一級的值

(1.3)單節點HTTP Server核心Get方法的實現

??在1.2小節我們解釋了HTTP的核心數據結構,這一小節我們討論下HTTP服務的核心服務ServeHTTP。在前言中我們概括性的討論了go的HTTP原生包(下稱HTTP原生包)與成熟框架是有區別的,從相關的代碼中(gin和geeCache的相關實現中)了解到,HTTP原生包對于方法的直接操作只有ServeHTTP方法,也就是說如果只使用HTTP原生包構建HTTP Server,所有的請求都是由 ServeHTTP 方法首先處理的,而例如Gin框架,可以將方法綁定在URI上,在路由注冊之后,可以通過URI訪問與其綁定的功能方法;從HTTP原生包來看,我能想到的實現Gin這一功能的方法是,在ServeHTTP方法中通過判斷請求的URI的值與if語句過濾來實現不同的URI訪問不同的功能函數。
??HTTP Get方法的實現并不復雜,主要流程還是調用下層我們封裝的Get方法(如何封裝的可以閱讀 分布式系列 的前兩章內容)。

(1.4)代碼實現及解釋

自定義默認的URI第一級的值 和 定義HTTP的核心數據結構

  • 自定義URI的第一級的值為 _geecache ,使用下劃線開頭的值用作區分重復的可能性更低,因此我們使用下劃線開頭。
// this is the defaultPath, user it to distinguish geeCache Project and other Project.
const defaultBasePath = "/_geecache/"type HTTPPool struct {// this peer's base URL, e.g. self is "https://example.net:8000"self     stringbasePath string
}// NewHTTPPool initializes an HTTP pool of peers.
func NewHTTPPool(self string) *HTTPPool {return &HTTPPool{self:     self,basePath: defaultBasePath,}
}

核心功能Get函數的實現

  • 在通過URI獲取GroupName之前,首先判斷URI的第一級值是否與defaultPath一致
  • 通過strings.SplitN根據 **字符 \ ** 進行截取,并獲得groupName 和 key
  • 調用下層已經實現的函數功能,以從中獲取key對應的value
  • 使用 w.Write(view.ByteSlice()),返回給 請求者一個 copy的對象,避免返回給請求者原對象后遭到惡意修改嗎,view.ByteSlice() 的具體實現在上一章節有具體說明和實現 。
// ServeHTTP handle all http requests
func (p *HTTPPool) ServeHTTP(w http.ResponseWriter, r *http.Request) {// 1. judge the first layer of uri is defaultBasePath.if !strings.HasPrefix(r.URL.Path, p.basePath) {panic("HTTPPool serving unexpected path: " + r.URL.Path)}// begin from the defaultPath, then start to split the rest of uri and get groupName from this operationparts := strings.SplitN(r.URL.Path[len(p.basePath):], "/", 2)// 2. judge the structure have two layers, first is groupName, second is key// the structure is  /<basepath>/<groupname>/<key>if len(parts) != 2 {http.Error(w, "bad request", http.StatusBadRequest)return}// 3. get GroupName and keygroupName := parts[0]key := parts[1]// 4. call Underlying interface to get Groupgroup := GetGroup(groupName)if group == nil {http.Error(w, "no such group: "+groupName, http.StatusNotFound)return}// 5. call Underlying interface to get key-valueview, err := group.Get(key)if err != nil {http.Error(w, err.Error(), http.StatusInternalServerError)return}w.Header().Set("Content-Type", "application/octet-stream")// return key-valuew.Write(view.ByteSlice())
}

HTTP Server 服務的啟動(main函數的編寫),參數的聲明

  • db 用于驗證GetterFunc方法是否生效。
  • 2<<10是二進制左移10位,對應的十進制為4096。
  • http.ListenAndServe 是服務的啟動代碼。
// not necessary, just is a test demo in here
var db = map[string]string{"Tom":  "630","Jack": "589","Sam":  "567",
}func main() {// 2<<10 means Binary Left Shift 10 bits, its value is 2048// GetterFunc can ignore the data's addition, cause it initialize the group scores, and state the maxBytesgeecache.NewGroup("scores", 2<<10, geecache.GetterFunc(func(key string) ([]byte, error) {log.Println("[SlowDB] search key", key)if v, ok := db[key]; ok {return []byte(v), nil}return nil, fmt.Errorf("%s not exist", key)}))addr := "localhost:9999"peers := geecache.NewHTTPPool(addr)log.Println("geecache is running at", addr)// log the ListenAndServe's errorlog.Fatal(http.ListenAndServe(addr, peers))
}

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

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

相關文章

ElasticSearch應用場景以及技術選型[ES系列] - 第496篇

歷史文章&#xff08;文章累計490&#xff09; 《國內最全的Spring Boot系列之一》 《國內最全的Spring Boot系列之二》 《國內最全的Spring Boot系列之三》 《國內最全的Spring Boot系列之四》 《國內最全的Spring Boot系列之五》 《國內最全的Spring Boot系列之六》 M…

PDF控件Spire.PDF for .NET【轉換】演示:將 PDF 轉換為 Excel

PDF是一種通用的文件格式&#xff0c;但它很難編輯。如果您想修改和計算PDF數據&#xff0c;將PDF轉換為Excel將是一個理想的解決方案。在本文中&#xff0c;您將了解如何使用Spire.PDF for .NET在 C# 和 VB.NET 中將 PDF 轉換為 Excel。 Spire.Doc 是一款專門對 Word 文檔進行…

【華為數據之道學習筆記】3-10元數據管理架構及策略

元數據管理架構包括產生元數據、采集元數據、注冊元數據和運 維元數據。 產生元數據&#xff1a; 制定元數據管理相關流程與規范的落地方案&#xff0c;在IT產品開發過程中實現業務元數據與技術元數據的連接。 采集元數據&#xff1a; 通過統一的元模型從各類IT系統中自動采集元…

多線程(初階九:線程池)

目錄 一、線程池的由來 二、線程池的簡單介紹 1、ThreadPoolExecutor類 &#xff08;1&#xff09;核心線程數和最大線程數&#xff1a; &#xff08;2&#xff09;保持存活時間和存活時間的單位 &#xff08;3&#xff09;放任務的隊列 &#xff08;4&#xff09;線程工…

Axure的安裝以及簡單使用

目錄 Axure簡介 是什么 有什么用 Axure的優缺點 優點&#xff1a; 缺點&#xff1a; 安裝 漢化 Axure的使用 工具欄 頁面 ?編輯 添加子頁面 ?編輯 Axure簡介 是什么 Axure是一款著名的原型設計工具。它允許用戶創建交互式線框圖、流程圖、原型和其他設計文檔&…

「Verilog學習筆記」脈沖同步電路

專欄前言 本專欄的內容主要是記錄本人學習Verilog過程中的一些知識點&#xff0c;刷題網站用的是牛客網 timescale 1ns/1nsmodule pulse_detect(input clk_fast , input clk_slow , input rst_n ,input data_in ,output dataout );reg data_level, dat…

第十一章 React 封裝自定義組件

一、專欄介紹 &#x1f30d;&#x1f30d; 歡迎加入本專欄&#xff01;本專欄將引領您快速上手React&#xff0c;讓我們一起放棄放棄的念頭&#xff0c;開始學習之旅吧&#xff01;我們將從搭建React項目開始&#xff0c;逐步深入講解最核心的hooks&#xff0c;以及React路由、…

【NLP】RAG 應用中的調優策略

? 檢索增強生成應用程序的調優策略 沒有一種放之四海而皆準的算法能夠最好地解決所有問題。 本文通過數據科學家的視角審視檢索增強生成&#xff08;RAG&#xff09;管道。它討論了您可以嘗試提高 RAG 管道性能的潛在“超參數”。與深度學習中的實驗類似&#xff0c;例如&am…

關于jinja2高版本api變化導致notebook導出html失敗的問題

最新jinja2版本已經到了3.1.2&#xff0c;但是nbconvert引用的應該是老版本&#xff0c;具體代碼報錯如下 Type "help", "copyright", "credits" or "license" for more information. >>> import nbconvert Traceback (most…

spark從表中采樣(隨機選取)一定數量的行

在Spark SQL中&#xff0c;你可以使用TABLESAMPLE來按行數對表進行采樣。以下是使用TABLESAMPLE的示例&#xff1a; SELECT * FROM table_name TABLESAMPLE (1000 ROWS);在這個示例中&#xff0c;table_name是你要查詢的表名。TABLESAMPLE子句后面的(1000 ROWS)表示采樣的行數…

axios 基礎的 一次封裝 二次封裝

一、平常axios的請求發送方式 修改起來麻煩的一批 代碼一大串 二、axios的一次封裝 我們會在src/utils創建一個request.js的文件來存放我們的基地址與攔截器 /* 封裝axios用于發送請求 */ import axios from axios/* (1)request 相當于 Axios 的實例對象 (2)為什么要有reque…

VSCode使用Remote-SSH連接服務器時報錯:無法與“***”建立連接: XHR failed.

關于VSCode的報錯問題&#xff1a;無法與“***”建立連接: XHR failed 問題描述問題理解解決方法手動在本地下載安裝包&#xff0c;然后手動傳到服務器端 問題描述 是的&#xff0c;我又踩坑了&#xff0c;而且這個弄了好久&#xff0c;也重新裝了VSCode軟件&#xff0c;好像結…

2024黑龍江省職業院校技能大賽暨國賽選拔賽“GZ031應用軟件系統開發”賽項賽題題庫

2024黑龍江省職業院校技能大賽暨國賽選拔賽 “GZ031應用軟件系統開發”賽項賽題題庫 2024黑龍江省職業院校技能大賽暨國賽選拔賽 應用軟件系統開發賽項&#xff08;高職組&#xff09; 賽題第1套 目錄 競賽說明 模塊一&#xff1a;系統需求分析 任務1&#xff1a;制造執行…

Kotlin之for循環的具體使用說明

我們用java進行Android開發過程中&#xff0c;經常會用到for循環&#xff0c;在Kotlin中也會經常用到&#xff0c;但是在最近使用Kotlin中我發現&#xff0c;在java中使用for循環不會有什么問題&#xff0c;但是在Kotlin中會出現問題&#xff0c;就是循環出出來的結果不一樣&am…

前端框架(Front-end Framework)和庫(Library)的區別

聚沙成塔每天進步一點點 ? 專欄簡介 前端入門之旅&#xff1a;探索Web開發的奇妙世界 歡迎來到前端入門之旅&#xff01;感興趣的可以訂閱本專欄哦&#xff01;這個專欄是為那些對Web開發感興趣、剛剛踏入前端領域的朋友們量身打造的。無論你是完全的新手還是有一些基礎的開發…

阿里云國際版CDN加速,如何判斷網站IP已加速?

將源站接入阿里云CDN服務后&#xff0c;您可以通過IP檢測功能&#xff0c;檢測客戶端請求實際訪問的IP是否為CDN加速節點IP&#xff0c;判斷加速是否生效。 應用場景 IP檢測的應用場景如下&#xff1a; 場景一&#xff1a;成功配置CDN后&#xff0c;您可以檢測客戶端請求實際…

Android popupwindow在低版本手機上無法顯示

所以我開始看各個參數&#xff0c;注意到了在我自定義popupwindow的builder下的&#xff1a;&#x1f447;&#x1f447; .showAsDropDown(mLinMain, 0, 0);就是這個&#xff0c;這時候我想到了屏幕的原點坐標是&#xff08;0&#xff0c; 0&#xff09;&#xff0c;所設置的p…

Postman高級應用——變量、流程控制、調試、公共函數、外部數據文件

Postman 提供了四種類型的變量 環境變量&#xff08;Environment Variable&#xff09; 不同的環境&#xff0c;使用不同的環境變量&#xff0c;例如&#xff1a;測試過程中經常會用到 測試環境&#xff0c;外網環境等 全局變量&#xff08;Global Variable&#xff09; 所有的…

12.使用 Redis 優化登陸模塊

目錄 1. 使用 Redis 優化登陸模塊 1.1 使用 Redis 存儲驗證碼 1.2 使用 Redis 存儲登錄憑證 1.3 使用 Redis 緩存用戶信息 1. 使用 Redis 優化登陸模塊 使用 Redis 存儲驗證碼&#xff1a;驗證碼需要頻繁的訪問與刷新&#xff0c;對性能要求較高&#xff1b;驗證碼不需要永…

【計算機網絡】序列化,反序列化和初識協議

目錄 ?編輯 一、概念 二、 序列化過程&#xff1a; 選擇序列化格式&#xff1a; 實現序列化代碼&#xff1a; JSON示例&#xff1a; Protocol Buffers示例&#xff1a; JSON編碼示例&#xff1a; 傳輸或存儲&#xff1a; 三、反序列化過程&#xff1a; 下面是反序列…