Redis介紹及Jedis基礎操作



1.Redis簡介

    Redis 是一個開源(BSD許可)的,內存中的數據結構存儲系統,它可以用作數據庫、緩存和消息中間件。 它支持多種類型的數據結構,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 與範圍查詢, bitmaps, hyperloglogs 和 地理空間(geospatial) 索引半徑查詢。 Redis 內置了 複製(replication),LUA腳本(Lua scripting), LRU驅動事件(LRU eviction),事務(transactions) 和不同級別的 磁盤持久化(persistence), 並通過 Redis哨兵(Sentinel)和自動 分區(Cluster)提供高可用性(high availability)。Redis 是完全開源免費的,遵守BSD協議,是一個高性能的key-value數據庫。

    Redis 與其他 key - value 緩存產品有以下三個特點:

  1. Redis支持數據的持久化,可以將內存中的數據保存在磁盤中,重啓的時候可以再次加載進行使用。
  2. Redis不僅僅支持簡單的key-value類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。
  3. Redis支持數據的備份,即master-slave模式的數據備份。

2.Redis優勢

  1. 性能極高 – Redis能讀的速度是110000次/s,寫的速度是81000次/s 。
  2. 豐富的數據類型 – Redis支持二進制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數據類型操作。
  3. 原子 – Redis的所有操作都是原子性的,意思就是要麼成功執行要麼失敗完全不執行。單個操作是原子性的。多個操作也支持事務,即原子性,通過MULTI和EXEC指令包起來。
  4. 豐富的特性 – Redis還支持 publish/subscribe, 通知, key 過期等等特性。
  5. Redis運行在內存中但是可以持久化到磁盤,所以在對不同數據集進行高速讀寫時需要權衡內存,因爲數據量不能大於硬件內存。在內存數據庫方面的另一個優點是,相比在磁盤上相同的複雜的數據結構,在內存中操作起來非常簡單,這樣Redis可以做很多內部複雜性很強的事情。同時,在磁盤格式方面他們是緊湊的以追加的方式產生的,因爲他們並不需要進行隨機訪問。

3.linux環境下安裝Redis

    1.下載地址:http://redis.io/download,下載最新版本的linux版本Redis。

    2.本教程使用的最新文檔版本爲 4.0.6,下載文件後,上傳到linux服務器上面,並解壓安裝。

     操作指令爲:$ tar xzf redis-4.0.6.tar.gz     $ cd redis-4.0.6    $ make 

    3.make成功執行完後 redis- 4.0.6目錄會生成src 目錄,在一次執行命令:$ make install

         

    4.啓動redis服務,使用默認配置方式啓動:進入到redis-4.0.6/src目錄,執行啓動命令:redis-server 

    

    注意:這裏直接執行Redis-server 啓動的Redis服務,是在前臺直接運行的(效果如上圖),也就是說,執行完該命令後,如果Linux關閉當前會話,則Redis服務也隨即關閉。正常情況下,啓動Redis服務需要從後臺啓動,並且指定啓動配置文件。 

後臺啓動redis服務

  1. 首先編輯conf文件,將daemonize屬性改爲yes(表明需要在後臺運行),並指定ip地址,開放redis端口號:6379。操作指令爲:cd redis-4.0.6/ vi redis.conf
  2. 再次啓動redis服務,並指定啓動服務配置文件:  redis-server /usr/local/redis/etc/redis.conf    
  3. 在防火牆中開放端口:6379

     

    在本地電腦上,安裝一個redis客戶端連接工具,如:redisclient-win32.x86.1.5。利用連接工具可方便查看redis中設置的緩存數據,連接如圖所示:   

4.jedis操作Redis介紹

    jedis 是 Redis 官方首選的 Java 客戶端開發包,上手比較容易。jedis提供了以下三種操作方式:

  1. 單機單連接方式:此方式僅建議用於開發環境做調試用。
  2. 單機連接池方式:此方式適用於僅使用單個Redis實例的場景
  3. 多機分佈式+連接池方式:此方式適用規模較大的系統,往往會有多個Redis實例做負載均衡。並且還實現主從備份,當主實例發生故障時,切換至從實例提供服務。
  4. redis3.0推出JedisCluster。使用JedisCluster連接使用這種方式時,默認Redis已經進行了集羣處理,JedisCluster即針對整個集羣的連接.

 

 jedis操作redis模式

(1)事務方式(Transactions)

    所謂事務,即一個連續操作,是否執行是一個事務,要麼完成,要麼失敗,沒有中間狀態。而redis的事務很簡單,他主要目的是保障,一個client發起的事務中的命令可以連續的執行,而中間不會插入其他client的命令,也就是事務的連貫性。

   測試截圖

 

(2)管道(Pipelining)

   管道是一種兩個進程之間單向通信的機制。那再redis中,爲何要使用管道呢?有時候,需要採用異步的方式,一次發送多個指令,並且,不同步等待其返回結果。這樣可以取得非常好的執行效率。管道模式測試代碼:

複製代碼
  @Test
    public void jedisPipelined() {
        Jedis jedis = new Jedis("192.168.210.128", 6379);
        Pipeline pipeline = jedis.pipelined();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++) {
            pipeline.set("p" + i, "p" + i);
        }
        List<Object> results = pipeline.syncAndReturnAll();
        long end = System.currentTimeMillis();
        System.out.println("Pipelined SET: " + ((end - start)/1000.0) + " seconds");
        jedis.disconnect();
    }
複製代碼

   注意:事務和管道都是異步模式。在事務和管道中不能同步查詢結果。如下代碼操作爲非法操作:

複製代碼
Transaction tx = jedis.multi();  
 for (int i = 0; i < 100000; i++) {  
     tx.set("t" + i, "t" + i);  
 }  
   System.out.println(tx.get("t1000").get());  //不允許  
   List<Object> results = tx.exec();  
複製代碼

(3)管道中調用事務

    在某種需求下,需要異步執行命令,但是,又希望多個命令是有連續的,所以可採用管道加事務的調用方式。jedis是支持在管道中調用事務的。

(4)分佈式直連同步調用與分佈式連接池同步調用

    這個是分佈式直接連接,並且是同步調用,每步執行都返回執行結果。如果,分佈式調用代碼是運行在線程中,那麼分佈式直連同步調用方式就不合適了,因爲直連方式是非線程安全的,這個時候需使用選擇連接池調用。案例代碼:

複製代碼
//分佈式直接鏈接並同步調用
public void jedisShardNormal() {  
    List<JedisShardInfo> shards = Arrays.asList(  
            new JedisShardInfo("localhost",6379),  
            new JedisShardInfo("localhost",6380));  
   
    ShardedJedis sharding = new ShardedJedis(shards);  
   
    long start = System.currentTimeMillis();  
    for (int i = 0; i < 100000; i++) {  
        String result = sharding.set("sn" + i, "n" + i);  
    }  
    long end = System.currentTimeMillis();  
    System.out.println("Simple@Sharing SET: " + ((end - start)/1000.0) + " seconds");  
   
    sharding.disconnect();  
}  
//分佈式結合線程池使用
public void jedisShardSimplePool() {  
    List<JedisShardInfo> shards = Arrays.asList(  
            new JedisShardInfo("localhost",6379),  
            new JedisShardInfo("localhost",6380));  
   
    ShardedJedisPool pool = new ShardedJedisPool(new JedisPoolConfig(), shards);  
   
    ShardedJedis one = pool.getResource();  
   
    long start = System.currentTimeMillis();  
    for (int i = 0; i < 100000; i++) {  
        String result = one.set("spn" + i, "n" + i);  
    }  
    long end = System.currentTimeMillis();  
    pool.returnResource(one);  
    System.out.println("Simple@Pool SET: " + ((end - start)/1000.0) + " seconds");  
   
    pool.destroy();  
}  
複製代碼

(5)分佈式直連異步調用與分佈式連接池異步調用

    操作與同步相對,案例代碼如下:

複製代碼
//分佈式連接池異步調用測試 線程池使用
public void jedisShardPipelinedPool() {  
    List<JedisShardInfo> shards = Arrays.asList(  
            new JedisShardInfo("localhost",6379),  
            new JedisShardInfo("localhost",6380));  
   
    ShardedJedisPool pool = new ShardedJedisPool(new JedisPoolConfig(), shards);  
   
    ShardedJedis one = pool.getResource();  
   
    ShardedJedisPipeline pipeline = one.pipelined();  
   
    long start = System.currentTimeMillis();  
    for (int i = 0; i < 100000; i++) {  
        pipeline.set("sppn" + i, "n" + i);  
    }  
    List<Object> results = pipeline.syncAndReturnAll();  
    long end = System.currentTimeMillis();  
    pool.returnResource(one);  
    System.out.println("Pipelined@Pool SET: " + ((end - start)/1000.0) + " seconds");  
    pool.destroy();  
}  
複製代碼

(6)安全線程連接池(JedisPool)   

   注意Jedis對象並不是線程安全的,在多線程下使用同一個Jedis對象會出現併發問題。爲了避免每次使用Jedis對象時都需要重新構建,Jedis提供了JedisPoolJedisPool是基於Commons Pool 2實現的一個線程安全的連接池。

複製代碼
//線程池模式使用測試:   
   JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
    jedisPoolConfig.setMaxTotal(10);
    JedisPool pool = new JedisPool(jedisPoolConfig, "localhost", 6379);

    Jedis jedis = null;
    try{
        jedis = pool.getResource();
        jedis.set("pooledJedis", "hello jedis pool!");
        System.out.println(jedis.get("pooledJedis"));
    }catch(Exception e){
        e.printStackTrace();
    }finally {
        //還回pool中
        if(jedis != null){
            jedis.close();
        }
    }
    pool.close();
複製代碼

(7)多機分佈式集合連接池使用

    此方式適用規模較大的系統,往往會有多個Redis實例做負載均衡。並且還實現主從備份,當主實例發生故障時,切換至從備用實例提供服務。如服務器1掛掉後,可用服務器2繼續支撐redis緩存處理。測試代碼:

複製代碼
**
 * Description:  多機分佈式+連接池方式:
 * Copyright:  2018 CSNT. All rights reserved.
 * Company:CSNT
 *
 * @author wangling
 * @version 1.0
 */
public class MultipleJedisPoolTest {

    static JedisPoolConfig config;
    static ShardedJedisPool sharedJedisPool;

    static {
        // 生成多機連接List
        List<JedisShardInfo> shards = new ArrayList<JedisShardInfo>();
        shards.add( new JedisShardInfo("127.0.0.1", 6379) );
        shards.add( new JedisShardInfo("192.168.210.128", 6379) );

        // 初始化連接池配置對象
        config = new JedisPoolConfig();
        config.setMaxIdle(10);
        config.setMaxTotal(30);
        config.setMaxWaitMillis(2*1000);
        // 實例化連接池
        sharedJedisPool = new ShardedJedisPool(config, shards);

    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        // 從連接池獲取Jedis連接
        ShardedJedis shardedJedisConn = sharedJedisPool.getResource();
        shardedJedisConn.set("Lemon", "Hello,my name is Lemon");
        System.out.println(shardedJedisConn.get("Lemon"));
        // 釋放連接
        close(shardedJedisConn, sharedJedisPool);

}
    private static void close(ShardedJedis shardedJedis,ShardedJedisPool sharedJedisPool){
        if(shardedJedis!=null &&sharedJedisPool!=null){
            sharedJedisPool.returnResource(shardedJedis);
        }
        if(sharedJedisPool!=null){
            sharedJedisPool.destroy();
        }
    }
}
複製代碼

5.Redis常用命令

1 連接操作命令

  • quit:關閉連接(connection)
  • auth:簡單密碼認證
  • help cmd: 查看cmd幫助,例如:help quit

2 持久化

  • save:將數據同步保存到磁盤
  • bgsave:將數據異步保存到磁盤
  • lastsave:返回上次成功將數據保存到磁盤的Unix時戳
  • shutdown:將數據同步保存到磁盤,然後關閉服務

3 遠程服務控制

  • info:提供服務器的信息和統計
  • monitor:實時轉儲收到的請求
  • slaveof:改變複製策略設置
  • config:在運行時配置Redis服務器

4 對key操作的命令

  • exists(key):確認一個key是否存在
  • del(key):刪除一個key
  • type(key):返回值的類型
  • keys(pattern):返回滿足給定pattern的所有key
  • randomkey:隨機返回key空間的一個
  • keyrename(oldname, newname):重命名key
  • dbsize:返回當前數據庫中key的數目
  • expire:設定一個key的活動時間(s)
  • ttl:獲得一個key的活動時間
  • select(index):按索引查詢
  • move(key, dbindex):移動當前數據庫中的key到dbindex數據庫
  • flushdb:刪除當前選擇數據庫中的所有key
  • flushall:刪除所有數據庫中的所有key

5 String

  • set(key, value):給數據庫中名稱爲key的string賦予值value
  • get(key):返回數據庫中名稱爲key的string的value
  • getset(key, value):給名稱爲key的string賦予上一次的value
  • mget(key1, key2,…, key N):返回庫中多個string的value
  • setnx(key, value):添加string,名稱爲key,值爲value
  • setex(key, time, value):向庫中添加string,設定過期時間time
  • mset(key N, value N):批量設置多個string的值
  • msetnx(key N, value N):如果所有名稱爲key i的string都不存在
  • incr(key):名稱爲key的string增1操作
  • incrby(key, integer):名稱爲key的string增加integer
  • decr(key):名稱爲key的string減1操作
  • decrby(key, integer):名稱爲key的string減少integer
  • append(key, value):名稱爲key的string的值附加value
  • substr(key, start, end):返回名稱爲key的string的value的子串

6 List

  • rpush(key, value):在名稱爲key的list尾添加一個值爲value的元素
  • lpush(key, value):在名稱爲key的list頭添加一個值爲value的 元素
  • llen(key):返回名稱爲key的list的長度
  • lrange(key, start, end):返回名稱爲key的list中start至end之間的元素
  • ltrim(key, start, end):截取名稱爲key的list
  • lindex(key, index):返回名稱爲key的list中index位置的元素
  • lset(key, index, value):給名稱爲key的list中index位置的元素賦值
  • lrem(key, count, value):刪除count個key的list中值爲value的元素
  • lpop(key):返回並刪除名稱爲key的list中的首元素
  • rpop(key):返回並刪除名稱爲key的list中的尾元素
  • blpop(key1, key2,… key N, timeout):lpop命令的block版本。
  • brpop(key1, key2,… key N, timeout):rpop的block版本。
  • rpoplpush(srckey, dstkey):返回並刪除名稱爲srckey的list的尾元素,並將該元素添加到名稱爲dstkey的list的頭部

7 Set

  • sadd(key, member):向名稱爲key的set中添加元素member
  • srem(key, member) :刪除名稱爲key的set中的元素member
  • spop(key) :隨機返回並刪除名稱爲key的set中一個元素
  • smove(srckey, dstkey, member) :移到集合元素
  • scard(key) :返回名稱爲key的set的基數
  • sismember(key, member) :member是否是名稱爲key的set的元素
  • sinter(key1, key2,…key N) :求交集
  • sinterstore(dstkey, (keys)) :求交集並將交集保存到dstkey的集合
  • sunion(key1, (keys)) :求並集
  • sunionstore(dstkey, (keys)) :求並集並將並集保存到dstkey的集合
  • sdiff(key1, (keys)) :求差集
  • sdiffstore(dstkey, (keys)) :求差集並將差集保存到dstkey的集合
  • smembers(key) :返回名稱爲key的set的所有元素
  • srandmember(key) :隨機返回名稱爲key的set的一個元素

8 Hash

  • hset(key, field, value):向名稱爲key的hash中添加元素field
  • hget(key, field):返回名稱爲key的hash中field對應的value
  • hmget(key, (fields)):返回名稱爲key的hash中field i對應的value
  • hmset(key, (fields)):向名稱爲key的hash中添加元素field
  • hincrby(key, field, integer):將名稱爲key的hash中field的value增加integer
  • hexists(key, field):名稱爲key的hash中是否存在鍵爲field的域
  • hdel(key, field):刪除名稱爲key的hash中鍵爲field的域
  • hlen(key):返回名稱爲key的hash中元素個數
  • hkeys(key):返回名稱爲key的hash中所有鍵
  • hvals(key):返回名稱爲key的hash中所有鍵對應的value
  • hgetall(key):返回名稱爲key的hash中所有的鍵(field)及其對應的value

6.參考網址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章