# Day29 Golang 鍵值資料庫 Redis 介紹與安裝 `Redis`是 `Remote Dictionary Server`的簡寫,意思為遠端字典Server。 字典Dictionary 即是`Key-Value`對照表。 ![Redis](https://i.imgur.com/DFIJ55W.png) Redis存放資料的速度極快,是物理層面上的快,因為**Redis對記憶體(Memory)進行操作**。 用以下數量級打個比方,會比較有感覺 假如`磁碟(Disk、Storage)` 的讀寫速度是1、容量10000。 那麼... `記憶體(Mem、RAM)` 的讀寫速度會是100、容量是100, `CPU快取(Cache)`的讀寫速度是10000、容量是1。 之前提到的MySQL資料庫是對硬碟進行讀寫, Redis將資料存放於記憶體中的特點為:讀寫速度比存放於磁碟快、但容量較小,且資料在斷電就揮發(Volatile)不見了(若沒及時寫進磁碟中的話) 若有**短時間內大量存取**的需求,卻又不想如此頻繁的對硬碟讀寫,這種場合可以使用`Redis資料庫`暫時存放資料,等一段時間後再一齊寫入硬碟裡。 # 安裝Redis Redis與`MySQL`同樣是資料庫,分成Server端與Client端,只是存放資料的形式不同。 ### Windows 安裝Redis 到[**Github下載**](https://github.com/tporadowski/redis/releases) .msi安裝檔案, 接著下一步、勾選加入PATH環境變數 ![ADD PATH](https://i.imgur.com/NyrYkKY.png) 預設會將Redis Server開啟成一項 `Windows服務` ![Windows Service](https://i.imgur.com/h4scTrU.png) Server端有了,再來啟動一個`CMD`來執行 Client端 $ redis-cli ### MacOS 安裝Redis 用`Homebrew`來快速方便的安裝 $ brew install redis 啟動Redis Server 端 $ redis-server 再另外起一個Terminal來執行Client $ redis-cli ### Docker 安裝Redis 把container命名為redis_test $ docker run --name redis_test -d -p 6379:6379 redis 執行Client端 $ docker exec -it redis_test /bin/bash # redis-cli (要結束Redis的話) $ docker container rm -f redis_test (如果Windows上出現 `the input device is not a TTY. If you are using mintty, try prefixing the command with 'winpty'`的錯誤,將terminal改用CMD再試一次。) --- Redis Server端預設使用 `6379 port`。 成功啟動Redis Server後的畫面,直接畫一個Redis的圖樣出來。 ![Redis Server](https://i.imgur.com/2CNeEgj.png) 此時對Client端下指令: PING PONG (乒乓球?) 如同在Go語言中 用指令操作`map結構`一般,非常的簡便。 > SET test 123 > GET test ![操作](https://i.imgur.com/h2razrZ.png) 隨便設幾個`Key-Value`來玩玩吧~ --- # Redis 基本指令:查詢 ### 【Keys 查詢指令】 是不是忘記自己下過哪些變數名稱了、怕怕的? 可利用KEYS指令,透過 `pattern`(正規表達式) 來查詢。 > KEYS * Keys指令的時間複雜度為`O(n)`,會佔用Redis單線程、卡到後面讀寫指令, 在**程式開發、測試時**可以使用,但在大型正式運行的伺服器中千萬別使用`KEYS`相關指令, 查詢時若大批的資料湧進會造成堵塞、炸裂。建議改用`SCAN`指令來查詢。 ### 【Scan 查詢指令】 在當前的Redis資料庫中進行迭代。 一開始先下`SCAN 0`,之後看他回傳的數值 接著繼續SCAN迭代下去。 > SCAN 0 此時若第一個回傳值為"15" > SCAN 15 持續步驟直到第一個回傳值為"0" ### 【Type 查詢類型】 忘記這個Key對應到的是甚麼物件類型了? 查詢test的類型 > TYPE test --- Redis鍵值資料庫中也有分格式,常用到的格式有: 1. 【字串 String】:可存放數字、字串。 2. 【哈希 Hash、Hashmap】:可存放 Hashmap 或稱Dictionary(Key-Value對照表)。 3. 【列表 List】:有順序的列表,可從列表左端或右端操作、新增刪除。 4. 【集合 Set】:存放唯一且不重複的項目。 5. 【有序集和 Sorted-Set】:存放唯一不重複項目,透過`Score`分數來排序,是個極度有趣的格式。 所有的指令在 [Redis官網](https://redis.io/commands) 都有詳細記載,真的夭壽多。 以下會快速導覽、稍微熟悉一下Redis指令用法。 # Redis 基本指令:新增、取得、刪除 ## 【String 數值、字串】 雖然是字串,但實際上可以放數字。 #### 【SET 設置】 設置 test1的值為123 > SET test1 123 設置 test1的值為字串 > SET test1 "Hello Redis" 此筆資料10秒後自動過期(Expired)、刪除。免費的倒數計時器,天殺的太方便啦 > SET test1 "123" EX 10 #### 【INCR、DECR 遞增減】 test1加1、test1減1 > INCR test1 > DECR test1 #### 【INCRBY、DECRBY 加減法】 test1加50、test1減50 > INCRBY test1 50 > DECRBY test1 50 #### 【StrLen 字串長度】 返回test1字串的長度 > STRLEN test1 #### 【Append】 透過append在字尾新增字串hello,接著返回字串總長度 > APPEND test "hello" #### 【GET 取得】 > GET test1 ## 【List 列表】 將a塞入list1之中 > LPUSH list1 hello > `LPUSH`: 往左側(頭)塞入元素a,若無list1則自動建立一個新的 > `RPUSH`: 往右側(尾)塞入元素a,若無list1則自動建立一個新的 > `LPUSHX`:若無list1則塞入失敗,不會自動建立 一次塞多個值進list1 > LPUSH list1 b c d a a a 將list1最左側(頭)的元素POP彈出 > LPOP list1 看 list1 之中 第0到100的元素(含0含100) > LRANGE list1 0 100 若要查看所有元素可使用:`LRANGE list1 0 -1`。 Index -1 代表最後一個項目 ## 【Hash、HashMap 哈希表】 `Hash`即為 一組Key對應到一組Value HSET 設 hash1表裡面的 `h1`鍵 值為123 > HSET hash1 h1 123 HMSET 設置`hashmap`(一次設多個HSET) > HMSET hash1 h2 234 h3 345 h4 456 取得hash1表中的 `h1` 的值 > HGET hash1 h1 取得hash1表中全部的鍵值 > HGETALL hash1 > 在Redis中 **不支援巢狀Hash**(hash中不能再設hash), > 可以用`Serialize` 或 將兩個`Hash Table`當成 key:value 對應來達成 > 或者使用`ReJSON`(Redis JSON),可方便儲存Json格式 ## 【Set 集合】 `Set 集合`裡面的內容,是唯一且不重複的。 譬如學生的 **學號** > SADD set1 "S00001" > SADD set1 "S00002" "S00003" "S00004" "S00005" ... > SCARD set1 返回集合總數量 > SDIFF set1 返回、列出不同的Set ## 【Sorted-Set 有序集合】 有`Score 分數`的集合。 可以想像成:考完期中考的學生,各自都會對應到一個分數。 **分數可重複,學生不能重複** S00001 拿到了99分 S00002 拿到了3分 S00003 也拿到了3分 > ZADD exam 99 "S00001" > ZADD exam 3 "S00002" > ZADD exam 3 "S00003" 若加上`XX`的話,只會更新已存在的值,若無鍵 則不會新增。 老師也想來考試,但沒有在名單上 不給你考勒~ > ZADD exam XX 100 "Teacher" 改成`NX`則相反:只新增鍵、不會更新已存在的 查看來考試的學生數量 > ZCARD exam 查看`S00001`的分數 > ZSCORE exam S00001 有幾個人分數落在0~10分的 > ZCOUNT exam 0 20 印出所有人的 排名(從低分印到高分) > ZRANGE exam 0 -1 印所有人的 排名與分數(從低分印到高分) > ZRANGE exam 0 -1 WITHSCORES 把 `S00001`的分數+3分,直接變102分突破天際啦! > ZINCRBY exam 3 S00001 --- # 在Golang中使用Redis 程式可以辦到很多事情嘛,我們一樣可以透過 Golang程式 來模擬 Redis Client端的執行。 而在golang github社群中有兩個主流的Redis函式庫。 [**Go-Redis**](https://github.com/go-redis/redis) 與 [**RediGo**](https://github.com/gomodule/redigo) > Oh My God! > 這兩個命名真的非常像,一個把go放前面、一個把go放後面,常常搞混... 在這裡會介紹`go-redis`這一個星星數稍微多一點點的項目。 (希望不會發生哪天星星數被追過去了...這樣還要改文章)