【分佈式架構之旅 理論篇】Redis入門

###前言redis

昨天和室友去包夜,玩了一夜的LOL,跪了一整夜,可是很開心。從S1末開始玩LOL的我,到如今仍是青銅,真是菜的摳腳。最近負能力滿滿的,惟有睡覺和學習纔可解憂愁。今天也看了慕課網上面的《Redis入門》,來記一下學習筆記。(寫這篇文章開頭的時候應該是一個星期以前)算法

DNA.png


###NoSQL概述shell

  • NoSQL就是Not Only SQL的意思,是非關係型數據庫。數據庫

  • 爲何須要NoSQL?vim

    • High performance - 高併發讀寫數組

    • Huge Storage - 海量數據的高效率存儲和訪問緩存

    • High Scalability & High Availability - 高可擴展性和高可用性安全

  • NoSQL數據庫的四大分類bash

    • 鍵值(Key - Value)存儲:優勢是快速查詢,缺點存儲的數據缺乏結構化。服務器

    • 列存儲:優勢是查詢比較快,擴展性比較強,缺點是功能相對侷限。

    • 文檔數據庫:對應的產品就是MongoDB。對數據結構要求不是特別嚴格,查詢性能不能特別高,缺乏統一查詢的語法。

    • 圖形數據庫:優勢是利用圖結構相關的算法,缺點是須要對整個圖進行結算才能得出結果,不能做爲分佈式的解決方案。

image.png

  • 如今來講說NoSQL的特色,美滋滋。
    • 易擴展
    • 靈活的數據模型
    • 高可用
    • 大數據量,高性能

###Redis的概述

  • 高性能鍵值對數據庫,支持的鍵值數據類型:

    • 字符串類型 - String

    • 列表類型 - Set

    • 有序集合類型 - Sorted Set

    • 散列類型 - Hash

    • 集合類型 - List

  • Redis的應用場景

    • 緩存

    • 任務隊列

    • 網站訪問統計

    • 應用排行榜

    • 分佈式集羣架構中的session分離


###Redis在Linux上的使用 能夠看我這篇文章【Linux學習】 Redis經常使用的一些指令


###Jedis的入門

  • 咱們要在Java平臺上使用redis,確定須要Jedis這個客戶端。首先在pom文件中引入Jedis的依賴
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
		<dependency>
			<groupId>redis.clients</groupId>
			<artifactId>jedis</artifactId>
			<version>2.9.0</version>
		</dependency>
複製代碼
  • 普通方式建立Jedis對象。
public void methodOne() {
        Jedis jedis = new Jedis("100.64.84.47", 6379);
        jedis.set("name", "cmazxiaoma");
        String value = jedis.get("name");
        System.out.println(value);
        jedis.close();
    }
複製代碼
  • 經過線程安全的鏈接池來建立Jedis對象。
public void methodTwo() {
        //得到鏈接池的配置對象
        JedisPoolConfig config = new JedisPoolConfig();
        //設置最大鏈接數
        config.setMaxTotal(30);
        //設置最大空閒鏈接數
        config.setMaxIdle(10);
        //得到鏈接池
        JedisPool jedisPool = new JedisPool(config, "100.64.84.47", 6379);

        Jedis jedis = null;

        try {
            jedis = jedisPool.getResource();
            String value = jedis.get("name");
            System.out.println(value);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }

            jedisPool.close();
        }
    }
}
複製代碼
  • 編寫測試類。
public class JedisDemo1Test {
    private JedisDemo1 demo;

    @Before
    public void setUp() {
        demo = new JedisDemo1();
    }

    @Test
    public void methodOne() throws Exception {
        demo.methodOne();
    }

    @Test
    public void methodTwo() throws Exception {
        demo.methodTwo();
    }

}
複製代碼
  • 運行Test Case,測試成功。

    image.png

  • 咱們在Xshell軟件,輸入get name指令,也能夠看到輸出cmazxiaoma

    image.png


###Redis的數據結構

####String

  • Key定義的注意點:

    • 不要過長。
    • 不要太短。
    • 統一的命名規範。
  • 存儲String

    • 二進制安全的,存入和獲取的數據相同。
    • Value最多能夠容納的數據長度是512M
  • 存儲String經常使用的命令:

    • 賦值

      image.png

    • 取值

      image.png

    • 刪除

      image.png

    • 數值增減

若是屬性不存在的話,那麼integer類型默認爲0

image.png

若是name屬性的值不能轉換成integer類型,那麼會拋出ERR is not an integer or out of range異常。

image.png

decr指令也是同樣的。

image.png

  • 擴展命令 incrbydecrby也是同樣的,很簡單。
    image.png

append指令能夠拼接字符串。

image.png

若是append key cmazxiaoma。這個key不存在的話,首先會建立這個key,而後存入cmazxiaoma內容,接着輸出cmazxiaoma

image.png


####Hash

  • 賦值,可使用hset myhash key value單一賦值、hmset myhash key value key value屢次賦值。

    image.png

  • 取值,能夠用hget myhash key單一取值、hmget myhash key key 多個取值、hgetall取出全部key所對應的值。

    image.png

  • 刪除 ,能夠用hdel myhash key刪除單一的key

    image.png

hdel myhash key key刪除多個的key

image.png

del myhash刪除myhash中全部的key

image.png

  • 數值增減,hincrby myhash key 100

    image.png

  • 使用hexists myhash key 判斷key是否在myhash中存在,存在返回1,不存在返回0

    image.png

  • hlen myhash獲取myhash中存在key的數量。

    image.png

  • hkeys myhash獲取myhash中全部的key

    image.png

  • hvals myhash獲取myhash中全部的values

    image.png


####List

  • 存儲list:

    • ArrayList使用數組方式
    • LinkedList使用雙向鏈表方式
  • 兩端添加

    • 使用lpush a b c 命令在左端添加,那麼c確定是在最左端。
      image.png
    • 使用rpush a b c命令在右端添加,那麼c確定是在最右端。
      image.png
  • 兩端彈出

    • 使用lpop mylist彈出mylist中頭部元素、rpop mylist2彈出mylist2尾部中的元素。它們都是3
      image.png
    • 咱們接着來查看mylistmylist2
      image.png
  • 查看列表

    • 使用lrange mylist 0 5來查看mylist列表,mylist插入的方式從頭結點開始添加的,那麼輸出確定是321abc
      image.png
    • 使用lrange mylist2 0 5查看mylist2列表,mylist2插入的方式是從最右端添加的,那麼輸出確定是abc123
      image.png

image.png

  • 獲取列表元素的個數

    • 使用llen mylist命令
      image.png
  • 擴展命令

    • 使用lpushx mylist x,使插入的元素在頭部位置。

      image.png

    • 使用rpushx mylist x,使插入的元素在尾部位置。

      image.png

    • 使用lrem mylist count elementcount表明是刪除的次數,element表明是須要刪除的元素。若是count > 0 表明刪除的方式從頭至尾,刪除countelementcount < 0表明刪除的方式從尾到頭,刪除countelement。若是count = 0,刪除mylist中全部和element相同的元素。

      image.png
      image.png

    • lrem mylist 2 test1

      image.png

    • lrem mylist -2 test1

      image.png

    • lrem mylist 0 cmazxiaoma

      image.png

    • 在某一個下標位置插入元素。lset mylist index element

      image.png

    • 在目標元素以前插入指定的元素。linsert mylist before helloworl before_helloworld

      image.png
      image.png

    • 在目標元素以後插入指定的元素。linsert mylist helloworld after after_helloworld

      image.png

    • 彈出mylist中最後一個元素,並插入到mylist中的頭部。rpoplpush mylist mylist

      image.png

    • rpoplpush使用場景

      image.png


####Set 和List類型不一樣的是,Set集合中不容許出現重複的元素。

  • 添加/刪除元素

    • 添加 sadd myset a b c,若是咱們重複添加相同的元素,確定是不成功的。好比sadd myset a
      image.png
    • 刪除 srem myset a,刪除myset中的a元素。
      image.png
    • 查看myset中的元素。smembers myset
      image.png
    • 查看指定元素是不是myset中的成員。sismember myset a,返回0表明不存在,返回1表明存在。
      image.png
  • 得到集合中的元素, smembers myset

  • 集合中的差集運算,sdiff myset2 mysetmyset2中元素有b,c,dmyset中元素有b,c。它們之間的差集運算結果應該爲d

    image.png

    • 集合中的交集運算,sinter myset2 myset,應該輸出cb

      image.png

    • 集合中的並集運算,sunion myset2 myset,應該輸出cbd

      image.png

  • 擴展命令

    • scard myset 查看myset有多少個元素。

      image.png

    • srandmember myset 隨機返回myset中的一個元素。

      image.png

    • sdiffstore new_myset myset2 mysetmysetmyset2差集元素的結果存儲到new_myset中。(sinterstore, sunionstore也是同樣的用法)

      image.png

  • Set使用場景

    • 跟蹤一些惟一性的數據。
    • 用於維護數據對象之間的關聯關係。

####SortedSet SortedSet中的成員在集合中的位置是有序的。

  • 添加元素 zadd mysort 70 cmazxiaoma 80 xiaoma 100 doudou

    image.png

  • 得到元素

    • zcard mysort 得到mysort中全部元素的個數

      image.png

    • 得到mysortnamecmazxiaoma對應的成績。zscore mysort cmazxiaoma

      image.png

  • 刪除元素,zrem mysort cmazxiaoma deli doudou xiaoma

    image.png

  • 範圍查詢 zrange mysort 0 -1,輸出的key是按成績正序排列。

    image.png

    • 若是輸出的數據項要帶上成績的話,指令應該是zrange mysort 0 -1 withscores

      image.png

    • 若是輸出的數據項想按成績逆序排序,那麼就應該zrevrange mysort 0 -1 withscores

      image.png

    • 若是想按排名範圍進行刪除的話,那麼應該zremrangebyrank mysort 0 2

      image.png

    • 若是想按成績範圍進行刪除的話,那麼應該zremrangebyscore mysort 0 10。顧名思義刪除成績在0-10以內的數據項。

      image.png

  • 擴展命令

    • 查看分數在0-10以內的學生信息,zrangebyscore mysort 0 10 withscores

      image.png

    • 查看分數在0-100以內且在第1行-第2行的學生信息。zrangebyscore mysort 0 100 withiscores limit 0 2

      image.png

    • cmazxiaoma的成績加100分。zincrby mysort cmazxiaoma 100

      image.png

    • 查當作績0-10之間的學生的個數。zcount mysort 0 10

      image.png

  • Sorted Set使用場景

    • 如大型在線遊戲積分排行榜

    • 構建索引數據


###Redis中的通用命令

  • key * 獲取全部redis中的key

    image.png

  • keys my* 獲取全部redis中以my開頭的key

    image.png

  • exists mylist 查看redis中是否存在mylist,0表明不存在,1表明存在。

    image.png

  • rename name new_name 給名字爲name的數據結構重命名爲new_name

    image.png

  • expire new_name 10 設置redisnew_name過時時間,經過ttl new_name看到其距離過時的時間。

    image.png

  • type mylist,能夠查看mylist對應的數據結構類型。

    image.png


###Redis的事務

  • Redis相關的特性:

    • 多數據庫

    • Redis事務

  • 一個Redis最多能夠提供16個數據庫,下標分別是0-15。客戶端默認鏈接的是第0號數據。咱們能夠經過select index來選擇數據庫。

    image.png

  • 咱們想把第0號的數據庫中某些key移動到第1號數據庫裏面,那麼咱們該怎麼作呢。經過move cmazxiaoma_test_mayday_5 1就能夠完成。

    image.png

  • 咱們能夠經過multiexecdiscard來完成事務操做。事務執行期間,Redis不會爲其餘客戶端提供任何服務,以保證事務中的全部命令原子執行。multi至關於開啓事務,exec至關於提交,discard至關於回滾。

  • 首先咱們在第一個客戶端進行以下操做。咱們在第一個客戶端開啓了事務,在事務中咱們incr num 2次,按理來講,get num 應該等於4

    redis第一個客戶端.png

  • 咱們在第二個客戶端輸入get num,發現num仍是2。那麼證實了咱們的結論:事務執行期間,Redis不會爲其餘客戶端提供任何服務,以保證事務中的全部命令原子執行。

    image.png

  • 若是咱們在第一個客戶端提交了事務。

    image.png

  • 接着咱們在第二個客戶端get num,發現能夠num的值獲得了更新。

    image.png

  • 咱們能夠演示一下回滾操做,首先set user cmazxiaoma,接着開啓事務,在事務中set user xiaoma,而後進行回滾操做,發現 get user 依然是cmazxiaoma

    image.png


###Redis的持久化 Redis的性能體如今它把數據都保存在內存當中。咱們把內存中的數據同步到硬盤當中的操做稱之爲持久化。

  • Redis持久化方式:

    • RDB方式,在指定的時間內,把內存中的數據快照寫入到硬盤當中。

    • AOF方式,將以日誌的形式記錄服務器所處理的每個操做。當Redis服務器啓動之初,它會讀取該aof文件,會從新構建咱們的數據庫。保證咱們啓動以後,保證數據的完整性。

    • 無持久化,咱們能夠經過配置禁止Redis服務器的持久化,咱們認爲Redis就是緩存的一種機制了。

    • 同時使用。

  • RDB

    • 默認狀況下,每隔一段時間redis服務器程序會自動對數據庫作一次遍歷,把內存快照寫在一個叫作"dump.rdb"的文件裏,這個持久化機制叫作SNAPSHOT。有了SNAPSHOT後,若是服務器宕機,從新啓動redis服務器時,redis會自動加載"dump.rdb",將數據庫狀態恢復上一次SNAPSHOT的狀態。

    • Redis服務器初始化過程當中,設定了定時時間,每隔一段時間就會觸發持久化操做,進入定時事件處理程序中,就會fork出子進程來進行持久化操做。

    • Redis服務器預設了save指令,客戶端可要求服務器進程中斷服務,執行持久化操做。

    • 咱們能夠經過vim /etc/redis.conf打開配置文件,能夠看到如下配置。

      image.png

    • 同時咱們還能夠看到內存快照輸出在file文件名。

      image.png

    優缺點:

    • 若是數據集很大,RDB相對於AOF啓動效率很更高。

    • 若是想保證數據的高可用性,最大限度的避免數據的丟失,RDB將不是一個好的選擇。由於系統在定時持久化操做以前,還沒來得及在硬盤寫入數據就發生宕機的話,就形成了數據的丟失。

    • RDB經過fork出子線程來完成數據持久化操做,若是當數據集很大的時候,可能會致使服務器中止幾百ms,或者幾s

RDB.png

  • AOF(append only file):

  • 對於Redis服務器而言,其缺省的機制是RDB,若是須要使用AOF,則須要修改appendonly no改爲appendonly yesRedis在每一次收到數據修改的命令以後,都會將其追加到AOF文件中。在Redis下一次從新啓動時,須要加載AOF文件中的信息來構建最新的數據到內存中。

    image.png
    image.png

  • 能夠記錄服務器的全部寫操做。在服務器從新啓動時,會把全部的寫操做從新執行一遍從而實現數據的備份。當寫操做集過大(比原有的數據集還大),Redis會重寫寫操做集。

  • 帶來更好的數據安全性,有3種同步策略,每秒同步,每修改同步,不一樣步。 每秒同步也是異步完成的,效率也很是高。缺點是一旦系統發生宕機的現象,那麼這一秒中的修改的數據就會發生丟失。每修改同步,咱們能夠視爲同步持久化。每一次發生數據的變化,就會當即的記錄在磁盤,這種效率很低,可是很安全。

  • 採用append追加的模式,就算系統發生宕機,也不會影響咱們日誌文件中已經存在的內容。然而咱們本次操做中,只寫入了一半數據就出現了系統崩潰的問題。在Redis下一次啓動以前,咱們能夠經過"redis-check-aof --fix <filename>"命令來修復壞損的AOF文件,解決數據一致性的問題。

  • 對於相同數量的數據集而言,AOF文件一般要大於RDB文件。

  • AOF在運行效率上每每會慢於RDB

AOF.png

  • RDBAOF的區別 前者是保存了數據自己,然後者是記錄了數據的變動。

###尾言

這篇文章最後在網吧完成的,勿以善小而不爲。

相關文章
相關標籤/搜索