亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Go語(yǔ)言基于HTTP的內(nèi)存緩存服務(wù)的實(shí)現(xiàn)

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

所有的緩存數(shù)據(jù)都存儲(chǔ)在服務(wù)器的內(nèi)存中,因此重啟服務(wù)器會(huì)導(dǎo)致數(shù)據(jù)丟失,基于HTTP通信會(huì)將使開(kāi)發(fā)變得簡(jiǎn)單,但性能不會(huì)太好

緩存服務(wù)接口

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

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

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

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

緩存服務(wù)實(shí)現(xiàn)

綜上所述,這個(gè)緩存服務(wù)實(shí)現(xiàn)起來(lái)還是比較容易的,使用Go語(yǔ)言內(nèi)置的map存儲(chǔ)鍵值,使用http庫(kù)來(lái)處理HTTP請(qǐng)求,實(shí)現(xiàn)REST接口

定義狀態(tài)信息

定義了一個(gè)Stat結(jié)構(gòu)體,表示緩存服務(wù)狀態(tài):

type Stat struct {
	Count     int64
	KeySize   int64
	ValueSize int64
}

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

實(shí)現(xiàn)兩個(gè)方法,用來(lái)更新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))
}

緩存增加鍵值數(shù)據(jù)時(shí),調(diào)用add函數(shù),更新緩存狀態(tài)信息,對(duì)應(yīng)地,刪除數(shù)據(jù)時(shí)就調(diào)用del,保持狀態(tài)信息的正確

實(shí)現(xiàn)Cache接口

下面定義一個(gè)New函數(shù),創(chuàng)建并返回一個(gè)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
}

該函數(shù)會(huì)接收一個(gè)string類型的參數(shù),這個(gè)參數(shù)指定了要?jiǎng)?chuàng)建的Cache接口的具體結(jié)構(gòu)類型,這里考慮到以后可能不限于內(nèi)存緩存,有擴(kuò)展的可能。如果typ是"inmemory"代表是內(nèi)存緩存,就調(diào)用newInMemoryCache,并返回

如下定義了inMemoryCache結(jié)構(gòu)和對(duì)應(yīng)New函數(shù):

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

這個(gè)結(jié)構(gòu)中包含了存儲(chǔ)數(shù)據(jù)的map,和一個(gè)讀寫鎖用于并發(fā)控制,還有一個(gè)Stat匿名字段,用來(lái)記錄緩存狀態(tài)

下面一一實(shí)現(xiàn)所定義的接口方法:

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函數(shù)的作用是設(shè)置鍵值到map中,這要在上鎖的情況下進(jìn)行,首先判斷map中是否已有此鍵,之后用新值覆蓋,過(guò)程中要更新?tīng)顟B(tài)信息

Get函數(shù)的作用是獲取指定鍵對(duì)應(yīng)的值,使用讀鎖即可

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

實(shí)現(xiàn)HTTP服務(wù)

接下來(lái)實(shí)現(xiàn)HTTP服務(wù),基于Go語(yǔ)言的標(biāo)準(zhǔn)HTTP包來(lái)實(shí)現(xiàn),在目錄下創(chuàng)建一個(gè)http包

先定義Server相關(guān)結(jié)構(gòu)、監(jiān)聽(tīng)函數(shù)和New函數(shù):

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結(jié)構(gòu)體內(nèi)嵌了cache.Cache接口,這意味著http.Server也要實(shí)現(xiàn)對(duì)應(yīng)接口,為Server定義了一個(gè)Listen方法,其中會(huì)調(diào)用http.Handle函數(shù),會(huì)注冊(cè)兩個(gè)Handler分別用來(lái)處理/cache/和status這兩個(gè)http協(xié)議的端點(diǎn)

Server.cacheHandler和http.statusHandler返回一個(gè)http.Handler接口,用于處理HTTP請(qǐng)求,相關(guān)實(shí)現(xiàn)如下:

要實(shí)現(xiàn)http.Handler接口就要實(shí)現(xiàn)ServeHTTP方法,是真正處理HTTP請(qǐng)求的邏輯,該方法使用switch-case對(duì)請(qǐng)求方式進(jìn)行分支處理,處理PUT、GET、DELETE請(qǐng)求,其他都丟棄

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實(shí)現(xiàn)如下:

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請(qǐng)求,調(diào)用GetStat方法得到緩存狀態(tài)信息,將其序列化為JSON數(shù)據(jù)后寫回

測(cè)試運(yùn)行

編寫一個(gè)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請(qǐng)求,增加數(shù)據(jù):

$ 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

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

相關(guān)文章

  • Golang中http包的具體使用

    Golang中http包的具體使用

    Go語(yǔ)言內(nèi)置的net/http包十分優(yōu)秀,提供了http客戶端和服務(wù)器的實(shí)現(xiàn),本文主要介紹了Golang中http包的具體使用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-05-05
  • Golang實(shí)踐指南之獲取目錄文件列表

    Golang實(shí)踐指南之獲取目錄文件列表

    在搭建項(xiàng)目中一般都會(huì)有確定項(xiàng)目根目錄的絕對(duì)路徑的需求,下面這篇文章主要給大家介紹了關(guān)于Golang實(shí)踐指南之獲取目錄文件列表的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-01-01
  • Go 語(yǔ)言中的空接口(推薦)

    Go 語(yǔ)言中的空接口(推薦)

    這篇文章主要介紹了Go 語(yǔ)言中的空接口的實(shí)現(xiàn)方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • 用go語(yǔ)言實(shí)現(xiàn)WebAssembly數(shù)據(jù)加密的示例講解

    用go語(yǔ)言實(shí)現(xiàn)WebAssembly數(shù)據(jù)加密的示例講解

    在Web開(kāi)發(fā)中,有時(shí)候?yàn)榱颂嵘踩孕枰獙?duì)數(shù)據(jù)進(jìn)行加密,由于js代碼相對(duì)比較易讀,直接在js中做加密安全性較低,而WebAssembly代碼不如js易讀,本文提供一個(gè)用go語(yǔ)言實(shí)現(xiàn)的WebAssembly數(shù)據(jù)加密示例,需要的朋友可以參考下
    2024-03-03
  • Go語(yǔ)言在終端打開(kāi)實(shí)現(xiàn)進(jìn)度條處理數(shù)據(jù)方法實(shí)例

    Go語(yǔ)言在終端打開(kāi)實(shí)現(xiàn)進(jìn)度條處理數(shù)據(jù)方法實(shí)例

    這篇文章主要介紹了Go語(yǔ)言在終端打開(kāi)實(shí)現(xiàn)進(jìn)度條處理數(shù)據(jù)方法實(shí)例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • Golang加權(quán)輪詢負(fù)載均衡的實(shí)現(xiàn)

    Golang加權(quán)輪詢負(fù)載均衡的實(shí)現(xiàn)

    負(fù)載均衡器在向后端服務(wù)分發(fā)流量負(fù)載時(shí)可以使用幾種策略。本文主要介紹了Golang加權(quán)輪詢負(fù)載均衡,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • Go語(yǔ)言sync.Pool對(duì)象池使用場(chǎng)景基本示例

    Go語(yǔ)言sync.Pool對(duì)象池使用場(chǎng)景基本示例

    這篇文章主要為大家介紹了Go語(yǔ)言sync.Pool對(duì)象池使用場(chǎng)景的基本示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • golang常用庫(kù)之gorilla/mux-http路由庫(kù)使用詳解

    golang常用庫(kù)之gorilla/mux-http路由庫(kù)使用詳解

    這篇文章主要介紹了golang常用庫(kù)之gorilla/mux-http路由庫(kù)使用,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Go語(yǔ)言中錯(cuò)誤處理的方式總結(jié)

    Go語(yǔ)言中錯(cuò)誤處理的方式總結(jié)

    這篇文章會(huì)結(jié)合?errors?中的函數(shù),來(lái)討論一下?Go?中常見(jiàn)的?error?使用方式,文中的示例代碼講解詳細(xì),具有一定的學(xué)習(xí)價(jià)值,需要的可以了解一下
    2023-07-07
  • Golang中runtime的使用詳解

    Golang中runtime的使用詳解

    這篇文章主要介紹了Golang中runtime的使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08

最新評(píng)論