本實驗是整個分布式緩存開發的基礎實驗,主要會使用 Go 語言的內置庫完成一個單機版的緩存服務,后面會基於這個單機版的緩存服務來升級改造,逐步迭代成為一個分布式的緩存服務。本實驗會使用 Go 語言的 map 來開發一個緩存結構,並使用 sync 包來保證並發安全,最后使用 http 包來提供網絡服務。由於篇幅有限,這里僅展現map容器的使用,我會把后續和源代碼放在文章最后,大家自取哦~
知識點
- Go map 容器的使用
緩存的介紹
緩存的第一印象
我們先來看這樣一個問題:一個程序有 1TB 的數據都存在硬盤上,但其中只有 1GB 的數據會被頻繁地讀取,假設硬盤的讀取速度是 100MB/s,那么每一次讀取都會消耗 10 秒,有沒有什么辦法可以提高讀取的速度?
很明顯,這個問題是由於硬盤的速度太慢了,導致讀取時間太久,而且只是其中 1GB 數據會被頻繁地讀取,那我們能不能把這 1GB 的數據存到一個速度更快的地方,比如存到內存中,假設內存速度是 10GB/s,那么每一次讀取這 1GB 的數據就只需要 0.1 秒。可能有人會說,那為什么不把全部數據都存到內存中呢?當然可以,只要你有足夠大的內存,但是內存的價格要比硬盤高不少,整個程序的花費就會非常大,而且其他數據存進內存的意義不大。
如果要給這里的“內存”起一個名字,就可以叫它“緩存”了。我們不用去糾結緩存的概念是什么,更重要的是它解決了什么問題。
緩存的特點
還是從上面的問題入手,我們可以提取出兩個關鍵點:頻繁,速度。
這兩個關鍵點意味着緩存中的數據往往是會被反復讀取的,因為經常要讀取,所以要提高讀取的速度。另外,由於數據本身是存在硬盤上的,所以不管緩存中有沒有這些數據,程序都應該是正常運行的,當緩存中沒有數據的時候,需要去硬盤中讀取。如果程序修改了硬盤上的數據,緩存中的數據就沒有用了,屬於過時的數據,所以還需要去更新緩存。
所以,我們可以總結出緩存的特點:
- 速度很快(這個快是相對於被緩存的設備來說的)
- 數據可以丟失(甚至需要定期丟失)
- 容量有限(因為價格比較高)
map 的常用操作
map 的介紹
Go 語言的 map 是一種鍵值對的結構,每一個鍵值對都分為 key 和 value 兩個部分。在使用 map 的時候需要指定 key 和 value 的類型,其中 key 在 map 中是唯一的。下面讓我們來學習幾個 map 的常見操作:
在后面的示例內容中,我們只會給到對應功能的代碼,未給出完整程序,請自行補充 main 函數等內容。
map 的創建
func create() {
// map 的創建需要指定 key 和 value 的類型
// 其中 [] 中的類型是 key 的類型,[] 后面的類型是 value 的
// 1. 使用 make 創建 map
m1 := make(map[string]string)
fmt.Println(m1) // map[]
// 2. 直接創建 map
m2 := map[string]string{}
fmt.Println(m2) // map[]
// 3. 創建 map 的同時添加數據
m3 := map[string]string{
"key": "value",
}
fmt.Println(m3) // map[key:value]
}
運行截圖:
map 的增刪改查
func crud() {
// 創建 map
m := make(map[string]string)
fmt.Println(m) // map[]
// 添加數據
m["key"] = "value"
fmt.Println(m) // map[key:value]
// 修改數據
m["key"] = "newValue"
fmt.Println(m) // map[key:newValue]
// 查詢數據
// 第一個返回值是數據,第二個返回值表示 key 是否存在
value, ok := m["key"]
fmt.Println(value, ok) // newValue true
value, ok = m["not existed key"]
fmt.Println(value, ok) // false,這里的 value 是空字符串
// 刪除數據
delete(m, "key")
}
運行截圖:
map 的其他操作
func other() {
// 創建 map
m := map[string]int{
"a": 1,
"b": 3,
"c": 4,
"d": 2,
"e": 0,
}
// 遍歷 map 可以使用 for range
// 每一次遍歷 map 的順序可能都是不一樣的
for key, value := range m {
fmt.Println(key, value) // 亂序打印出 m 中的 key 和 value
}
// 查看 map 中的鍵值對個數
count := len(m)
fmt.Println(count) // 5
}
運行截圖:
第一個熱身實驗的第一部分就到這里啦。后續我們經過開發可以完成單機版緩存,之后會進行迭代,升級成分布式緩存。
怎么樣,是不是 so easy 啊,別急,后面我們會遇到各種各樣的難題,需要大家一起拿起“屠龍刀”去殺敵。
本章節代碼可以直接獲取:
wget
https://labfile.oss.aliyuncs.com/courses/2943/code1.zip