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

Go語言基于HTTP的內存緩存服務的實現

 更新時間:2022年08月25日 11:41:50   作者:N3ptune  
這篇文章主要介紹了Go語言基于HTTP的內存緩存服務,本程序采用REST接口,支持設置(Set)、獲取(Get)和刪除(Del)這3個基本操作,同時還支持對緩存服務狀態(tài)進行查詢,需要的朋友可以參考下

所有的緩存數據都存儲在服務器的內存中,因此重啟服務器會導致數據丟失,基于HTTP通信會將使開發(fā)變得簡單,但性能不會太好

緩存服務接口

本程序采用REST接口,支持設置(Set)、獲取(Get)和刪除(Del)這3個基本操作,同時還支持對緩存服務狀態(tài)進行查詢。Set操作是將一對鍵值對設置到服務器中,通過HTTP的PUT方法進行,Get操作用于查詢某個鍵并獲取其值,通過HTTP的GET方法進行,Del操作用于從緩存中刪除某個鍵,通過HTTP的DELETE方法進行,同時用戶可以查詢緩存服務器緩存了多少鍵值對,占據了多少字節(jié)

創(chuàng)建一個cache包,編寫緩存服務的主要邏輯

先定義了一個Cache接口類型,包含了要實現的4個方法(設置、獲取、刪除和狀態(tài)查詢)

package cache
type Cache interface {
	Set(string, []byte) error
	Get(string) ([]byte, error)
	Del(string) error
	GetStat() Stat
}

緩存服務實現

綜上所述,這個緩存服務實現起來還是比較容易的,使用Go語言內置的map存儲鍵值,使用http庫來處理HTTP請求,實現REST接口

定義狀態(tài)信息

定義了一個Stat結構體,表示緩存服務狀態(tài):

type Stat struct {
	Count     int64
	KeySize   int64
	ValueSize int64
}

Count表示緩存目前保存的鍵值對數量,KeySize和ValueSize分別表示鍵和值所占的總字節(jié)數

實現兩個方法,用來更新Stat信息:

func (s *Stat) add(k string, v []byte) {
	s.Count += 1
	s.KeySize += int64(len(k))
	s.ValueSize += int64(len(v))
}
func (s *Stat) del(k string, v []byte) {
	s.Count -= 1
	s.KeySize -= int64(len(k))
	s.ValueSize -= int64(len(v))
}

緩存增加鍵值數據時,調用add函數,更新緩存狀態(tài)信息,對應地,刪除數據時就調用del,保持狀態(tài)信息的正確

實現Cache接口

下面定義一個New函數,創(chuàng)建并返回一個Cache接口:

func New(typ string) Cache {
	var c Cache
	if typ == "inmemory" {
		c = newInMemoryCache()
	}
	if c == nil {
		panic("unknown cache type " + typ)
	}
	log.Println(typ, "ready to serve")
	return c
}

該函數會接收一個string類型的參數,這個參數指定了要創(chuàng)建的Cache接口的具體結構類型,這里考慮到以后可能不限于內存緩存,有擴展的可能。如果typ是"inmemory"代表是內存緩存,就調用newInMemoryCache,并返回

如下定義了inMemoryCache結構和對應New函數:

type inMemoryCache struct {
	c     map[string][]byte
	mutex sync.RWMutex
	Stat
}
 
func newInMemoryCache() *inMemoryCache {
	return &inMemoryCache{
		make(map[string][]byte),
		sync.RWMutex{}, Stat{}}
}

這個結構中包含了存儲數據的map,和一個讀寫鎖用于并發(fā)控制,還有一個Stat匿名字段,用來記錄緩存狀態(tài)

下面一一實現所定義的接口方法:

func (c *inMemoryCache) Set(k string, v []byte) error {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	tmp, exist := c.c[k]
	if exist {
		c.del(k, tmp)
	}
	c.c[k] = v
	c.add(k, v)
	return nil
}
 
func (c *inMemoryCache) Get(k string) ([]byte, error) {
	c.mutex.RLock()
	defer c.mutex.RLock()
	return c.c[k], nil
}
 
func (c *inMemoryCache) Del(k string) error {
	c.mutex.Lock()
	defer c.mutex.Unlock()
	v, exist := c.c[k]
	if exist {
		delete(c.c, k)
		c.del(k, v)
	}
	return nil
}
 
func (c *inMemoryCache) GetStat() Stat {
	return c.Stat
}

Set函數的作用是設置鍵值到map中,這要在上鎖的情況下進行,首先判斷map中是否已有此鍵,之后用新值覆蓋,過程中要更新狀態(tài)信息

Get函數的作用是獲取指定鍵對應的值,使用讀鎖即可

Del同樣須要互斥,先判斷map中是否有指定的鍵,如果有則刪除,并更新狀態(tài)信息

實現HTTP服務

接下來實現HTTP服務,基于Go語言的標準HTTP包來實現,在目錄下創(chuàng)建一個http包

先定義Server相關結構、監(jiān)聽函數和New函數:

type Server struct {
	cache.Cache
}
 
func (s *Server) Listen() error {
	http.Handle("/cache/", s.cacheHandler())
	http.Handle("/status", s.statusHandler())
	err := http.ListenAndServe(":9090", nil)
	if err != nil {
		log.Println(err)
		return err
	}
	return nil
}
 
func New(c cache.Cache) *Server {
	return &Server{c}
}

Server結構體內嵌了cache.Cache接口,這意味著http.Server也要實現對應接口,為Server定義了一個Listen方法,其中會調用http.Handle函數,會注冊兩個Handler分別用來處理/cache/和status這兩個http協議的端點

Server.cacheHandler和http.statusHandler返回一個http.Handler接口,用于處理HTTP請求,相關實現如下:

要實現http.Handler接口就要實現ServeHTTP方法,是真正處理HTTP請求的邏輯,該方法使用switch-case對請求方式進行分支處理,處理PUT、GET、DELETE請求,其他都丟棄

package http
 
import (
	"io/ioutil"
	"log"
	"net/http"
	"strings"
)
 
type cacheHandler struct {
	*Server
}
 
func (h *cacheHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	key := strings.Split(r.URL.EscapedPath(), "/")[2]
	if len(key) == 0 {
		w.WriteHeader(http.StatusBadRequest)
		return
	}
	switch r.Method {
	case http.MethodPut:
		b, _ := ioutil.ReadAll(r.Body)
		if len(b) != 0 {
			e := h.Set(key, b)
			if e != nil {
				log.Println(e)
				w.WriteHeader(http.StatusInternalServerError)
			}
		}
		return
	case http.MethodGet:
		b, e := h.Get(key)
		if e != nil {
			log.Println(e)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
		if len(b) == 0 {
			w.WriteHeader(http.StatusNotFound)
			return
		}
		w.Write(b)
		return
	case http.MethodDelete:
		e := h.Del(key)
		if e != nil {
			log.Println(e)
			w.WriteHeader(http.StatusInternalServerError)
		}
		return
	default:
		w.WriteHeader(http.StatusMethodNotAllowed)
	}
}
 
func (s *Server) cacheHandler() http.Handler {
	return &cacheHandler{s}
}

同理,statusHandler實現如下:

package http
 
import (
	"encoding/json"
	"log"
	"net/http"
)
 
type statusHandler struct {
	*Server
}
 
func (h *statusHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodGet {
		w.WriteHeader(http.StatusMethodNotAllowed)
		return
	}
	b, e := json.Marshal(h.GetStat())
	if e != nil {
		log.Println(e)
		w.WriteHeader(http.StatusInternalServerError)
		return
	}
	w.Write(b)
}
 
func (s *Server) statusHandler() http.Handler {
	return &statusHandler{s}
}

該方法只處理GET請求,調用GetStat方法得到緩存狀態(tài)信息,將其序列化為JSON數據后寫回

測試運行

編寫一個main.main,作為程序的入口:

package main
import (
	"cache/cache"
	"cache/http"
	"log"
)
 
func main() {
	c := cache.New("inmemory")
	s := http.New(c)
	err := s.Listen()
	if err != nil {
		log.Fatalln(err)
	}
}

發(fā)起PUT請求,增加數據:

$ curl -v localhost:9090/cache/key -XPUT -d value
*   Trying 127.0.0.1:9090...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 9090 (#0)
> PUT /cache/key HTTP/1.1
> Host: localhost:9090
> User-Agent: curl/7.68.0
> Accept: */*
> Content-Length: 5
> Content-Type: application/x-www-form-urlencoded
> 
* upload completely sent off: 5 out of 5 bytes
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Date: Thu, 25 Aug 2022 03:19:47 GMT
< Content-Length: 0
< 
* Connection #0 to host localhost left intact

查看狀態(tài)信息:

$ curl localhost:9090/status
{"Count":1,"KeySize":3,"ValueSize":5}

查詢:

$ curl localhost:9090/cache/key
value

到此這篇關于Go語言基于HTTP的內存緩存服務的文章就介紹到這了,更多相關Go內存緩存服務內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • 如何控制Go編碼JSON數據時的行為(問題及解決方案)

    如何控制Go編碼JSON數據時的行為(問題及解決方案)

    今天來聊一下我在Go中對數據進行 JSON 編碼時遇到次數最多的三個問題以及解決方法,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友參考下吧
    2020-02-02
  • Go語言實現機器大小端判斷代碼分享

    Go語言實現機器大小端判斷代碼分享

    這篇文章主要介紹了Go語言實現機器大小端判斷代碼分享,本文直接給出實現代碼,需要的朋友可以參考下
    2014-10-10
  • Go 1.13中errors包的新變化示例解析

    Go 1.13中errors包的新變化示例解析

    這篇文章主要為大家介紹了Go 1.13中errors包的新變化示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • 基于Golang設計一套可控的定時任務系統(tǒng)

    基于Golang設計一套可控的定時任務系統(tǒng)

    這篇文章主要為大家學習介紹了如何基于Golang設計一套可控的定時任務系統(tǒng),文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-07-07
  • Go語言學習之將mp4通過rtmp推送流媒體服務的實現方法

    Go語言學習之將mp4通過rtmp推送流媒體服務的實現方法

    對音視頻一直是小白,決定沉下心來,好好研究一下音視頻知識,下面這篇文章主要給大家介紹了關于Go語言學習之將mp4通過rtmp推送流媒體服務的實現方法,需要的朋友可以參考下
    2022-12-12
  • golang語言中wasm 環(huán)境搭建的過程詳解

    golang語言中wasm 環(huán)境搭建的過程詳解

    將 golang 打包為 WASM,通常有兩種打包方式,一種是 golang 自帶的,另外是使用 tinygo ,接下來通過本文給大家介紹golang語言中wasm 環(huán)境搭建的過程,感興趣的朋友一起看看吧
    2021-11-11
  • Golang實現http文件上傳小功能的案例

    Golang實現http文件上傳小功能的案例

    這篇文章主要介紹了Golang實現http文件上傳小功能的案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • 詳解如何用Golang處理每分鐘100萬個請求

    詳解如何用Golang處理每分鐘100萬個請求

    在項目開發(fā)中,我們常常會遇到處理來自數百萬個端點的大量POST請求,本文主要介紹了Golang實現處理每分鐘100萬個請求的方法,希望對大家有所幫助
    2023-04-04
  • Golang?Template實現自定義函數的操作指南

    Golang?Template實現自定義函數的操作指南

    這篇文章主要為大家詳細介紹了Golang如何利用Template實現自定義函數的操作,文中的示例代碼簡潔易懂,感興趣的小伙伴可以跟隨小編一起學習一下
    2025-02-02
  • go?Cobra命令行工具入門教程

    go?Cobra命令行工具入門教程

    Cobra是一個用Go語言實現的命令行工具并且現在正在被很多項目使用,例如:Kubernetes、Hugo和Github?CLI等,通過使用Cobra,我們可以快速的創(chuàng)建命令行工具,特別適合寫測試腳本,各種服務的Admin?CLI等,本文重點給大家介紹go?Cobra命令行工具,感興趣的朋友一起看看吧
    2022-06-06

最新評論

二连浩特市| 民乐县| 东山县| 颍上县| 沿河| 九江县| 汨罗市| 寻乌县| 荆州市| 乾安县| 德钦县| 阳信县| 湟中县| 民权县| 石嘴山市| 宝山区| 尖扎县| 磐安县| 梨树县| 香河县| 平谷区| 富川| 峨眉山市| 伊宁县| 太康县| 丽水市| 龙山县| 沧州市| 黑龙江省| 吉首市| 越西县| 得荣县| 芜湖市| 区。| 莱芜市| 庆元县| 广西| 罗城| 邵武市| 安宁市| 祁东县|