Redis筆記整理(二):Java API使用與Redis分布式叢集環境搭建

來源:互聯網
上載者:User

標籤:資料庫   NoSQL   Redis   

[TOC]

Redis筆記整理(二):Java API使用與Redis分布式叢集環境搭建Redis Java API使用(一):單機版本Redis API使用

Redis的Java API通過Jedis來進行操作,因此首先需要Jedis的第三方庫,因為使用的是Maven工程,所以先給出Jedis的依賴:

<dependency>    <groupId>redis.clients</groupId>    <artifactId>jedis</artifactId></dependency>
基本程式碼範例

Redis能提供的命令,Jedis也都提供了,而且使用起來非常類似,所以下面只是給出了部分操作的代碼。

package com.uplooking.bigdata;import org.junit.After;import org.junit.Before;import org.junit.Test;import redis.clients.jedis.Jedis;import java.util.List;import java.util.Map;import java.util.Set;/** * Redis操作之java API *  jedis 是我們操作Redis的java api的入口 *  一個Jedis對象,就代表了一個Redis的串連 * CRUD */public class RedisTest {    private Jedis jedis;    private String host;    private int port;    @Before    public void setUp() {        host = "uplooking01";        port = 6379;        jedis = new Jedis(host, port);    }    @Test    public void testCRUD() {        //後去所有的key的集合        Set<String> keys = jedis.keys("*");//        jedis.select(index); 指定要執行操作的資料庫,預設操作的是0號資料        System.out.println(keys);        //string        System.out.println("**************String**************");        //刪除redis中的key nam1        Long del = jedis.del("nam1");        System.out.println(del == 1L ? "刪除成功~" : "刪除失敗~");        List<String> mget = jedis.mget("name", "age");        System.out.println(mget);        //hash        System.out.println("**************Hash**************");        Map<String, String> person = jedis.hgetAll("person");        //keyset        //entryset        for (Map.Entry<String, String> me : person.entrySet()) {            String field = me.getKey();            String value = me.getValue();            System.out.println(field + "---" + value);        }        //list        System.out.println("**************List**************");        List<String> seasons = jedis.lrange("season", 0, -1);        for (String season : seasons) {            System.out.println(season);        }        //set        System.out.println("**************Set**************");        Set<String> nosql = jedis.smembers("nosql");        for (String db : nosql) {            System.out.println(db);        }        //zset        System.out.println("**************Zset**************");        Set<String> website = jedis.zrange("website", 0, -1);        for (String ws : website) {            System.out.println(ws);        }    }    @After    public void cleanUp() {        jedis.close();    }}
JedisPool序列化工具類開發

前面的代碼是每次都建立一個Jedis的串連,這樣比較消耗資源,可以使用JedisPool來解決這個問題,同時為了提高後面的開發效率,可以基於JedisPool來開發一個工具類。

JedisUtil.java
package com.uplooking.bigdata.common.util.redis;import com.uplooking.bigdata.constants.redis.JedisConstants;import redis.clients.jedis.Jedis;import redis.clients.jedis.JedisPool;import redis.clients.jedis.JedisPoolConfig;import java.io.IOException;import java.util.Properties;/** * Redis Java API 操作的工具類 * 主要為我們提供 Java操作Redis的對象Jedis 模仿類似的資料庫連接池 * * JedisPool */public class JedisUtil {    private JedisUtil() {}    private static JedisPool jedisPool;    static {        Properties prop = new Properties();        try {            prop.load(JedisUtil.class.getClassLoader().getResourceAsStream("redis/redis.properties"));            JedisPoolConfig poolConfig = new JedisPoolConfig();            //jedis串連池中最大的串連個數            poolConfig.setMaxTotal(Integer.valueOf(prop.getProperty(JedisConstants.JEDIS_MAX_TOTAL)));            //jedis串連池中最大的空閑串連個數            poolConfig.setMaxIdle(Integer.valueOf(prop.getProperty(JedisConstants.JEDIS_MAX_IDLE)));            //jedis串連池中最小的空閑串連個數            poolConfig.setMinIdle(Integer.valueOf(prop.getProperty(JedisConstants.JEDIS_MIN_IDLE)));            //jedis串連池最大的等待連線時間 ms值            poolConfig.setMaxWaitMillis(Long.valueOf(prop.getProperty(JedisConstants.JEDIS_MAX_WAIT_MILLIS)));            //表示jedis的伺服器主機名稱            String host = prop.getProperty(JedisConstants.JEDIS_HOST);            String JEDIS_PORT = "jedis.port";            int port = Integer.valueOf(prop.getProperty(JedisConstants.JEDIS_PORT));            //表示jedis的服務密碼            String password = prop.getProperty(JedisConstants.JEDIS_PASSWORD);            jedisPool = new JedisPool(poolConfig, host, port, 10000);        } catch (IOException e) {            e.printStackTrace();        }    }    /**     * 提供了Jedis的對象     * @return     */    public static Jedis getJedis() {        return jedisPool.getResource();    }    /**     * 資源釋放     * @param jedis     */    public static void returnJedis(Jedis jedis) {        jedis.close();    }}
JedisConstants.java
package com.uplooking.bigdata.constants.redis;/** * 專門用於存放Jedis的常量類 */public interface JedisConstants {    //表示jedis的伺服器主機名稱    String JEDIS_HOST = "jedis.host";    //表示jedis的服務的連接埠    String JEDIS_PORT = "jedis.port";    //表示jedis的服務密碼    String JEDIS_PASSWORD = "jedis.password";    //jedis串連池中最大的串連個數    String JEDIS_MAX_TOTAL = "jedis.max.total";    //jedis串連池中最大的空閑串連個數    String JEDIS_MAX_IDLE = "jedis.max.idle";    //jedis串連池中最小的空閑串連個數    String JEDIS_MIN_IDLE = "jedis.min.idle";     //jedis串連池最大的等待連線時間 ms值    String JEDIS_MAX_WAIT_MILLIS = "jedis.max.wait.millis";}
redis.properties
################################################ redis的設定檔################################################表示jedis的伺服器主機名稱jedis.host=uplooking01###表示jedis的服務的連接埠jedis.port=6379###表示jedis的服務密碼jedis.password=uplooking###jedis串連池中最大的串連個數jedis.max.total=60###jedis串連池中最大的空閑串連個數jedis.max.idle=30###jedis串連池中最小的空閑串連個數jedis.min.idle=5###jedis串連池最大的等待連線時間 ms值jedis.max.wait.millis=30000

後面就可以非常方便地使用這個工具類來進行Redis的操作:

// 獲得Jedis連線物件Jedis jedis = JedisUtil.getJedis();// 釋放Jedis對象資源JedisUtil.returnJedis(jedis);
Redis分布式叢集環境搭建Redis叢集理論知識
   Redis叢集是一個分布式Redis儲存架構,可以在多個節點之間進行資料共用,解決Redis高可用、可擴充等問題。   Redis叢集提供了以下兩個好處   1.將資料自動切分(split)到多個節點   2.當叢集中的某一個節點故障時,redis還可繼續處理用戶端的請求   一個Redis叢集包含16384個雜湊槽(hash slot),資料庫中的每個資料都屬於這16384個雜湊槽中的一個。   叢集使用公式CRC16(key)%16384來計算key屬於哪一個槽。叢集中的每一個節點負責處理一部分雜湊槽。叢集中的主從複製   叢集中的每個節點都有1個到N個複製品,其中一個為主節點,其餘為從節點,如果主節點下線了,   叢集就會把這個主節點的一個從節點設定為新的主節點,繼續工作。這個叢集就不會因為一個主節點的下線而無法正常工作。   如果某一個主節點和它所有的從節點都下線的話,redis叢集就停止工作了。   Redis叢集不保證資料的強一致性,在特定的情況下,redis叢集會丟失已經執行過的命令。   使用非同步複製(asynchronous replication)是Redis叢集可能會丟失寫命令的其中一個原因,   有時候由於網路原因,如果網路斷開時間太長,redis叢集就會啟用新的主節點,之前發給主節點的資料聚會丟失。

上面的理論知識,在完成下面Reids主從複製環境和分布式環境的搭建後,相信會有非常直觀的理解。

Redis主從複製叢集安裝

這裡使用三台裝置,環境說明如下:

uplooking01 masteruplooking02 slaveuplooking03 slave即uplooking01為主從節點,02和03為從節點,主從節點主要負責寫,從節點主要負責讀,不能寫。另外在兩台從伺服器上還會配置使用密碼,測試一下使用密碼時的串連方式(注意主伺服器沒有設定密碼)。下面的配置會對這些需求有所體現。

uplooking01 redis.conf配置如下:

bind uplooking01daemonize yes(後台運行)logfile /opt/redis-3.2.0/logs/redis.log(記錄檔,目錄必須存在)

uplooking02 redis.conf配置如下:

bind uplooking02daemonize yes(後台運行)logfile /opt/redis-3.2.0/logs/redis.log(記錄檔,目錄必須存在)slave-read-only yesrequirepass uplookingslaveof uplooking01 6379

uplooking03 redis.conf配置如下:

bind uplooking03daemonize yes(後台運行)logfile /opt/redis-3.2.0/logs/redis.log(記錄檔,目錄必須存在)slave-read-only yesrequirepass uplookingslaveof uplooking01 6379

上面的配置完成後,在兩台從伺服器上分別啟動redis即完成了主從複製叢集的配置,需要注意如下問題:

1.認證的問題    如果需要串連uplooking02或者uplooking03,那麼需要加上密碼,否則無法完成認證。    有兩種方式:        可以在串連時就指定密碼:redis-cli -h uplooking03 -a uplooking        也可以先串連,到終端後再認證:auth uplooking2.資料讀寫的問題    讀:三台伺服器上都能完成資料的讀    寫:只能在主節點上完成資料的寫入3.Java API的使用問題    在前面使用的代碼中,如果串連的是從伺服器,則還需要配置密碼    以我們開發的JedisPool工具類為例,在建立JedisPool時需要指定密碼:    jedisPool = new JedisPool(poolConfig, host, port, 10000, password);
Redis分布式安裝部署

叢集說明:

1.前面搭建的只是主從複製的叢集,這意味著,資料在三台機器上都是一樣的,其目的只是為了讀寫分離,提高讀的效率    同時也可以起到冗餘的作用,主節點一旦出現故障,從節點可以替換,但顯然,這隻是叢集,而不是分布式。2.但是可能會出現一個問題,就是當資料量過大時,所有的資料都儲存在同一個節點上    (雖然兩台做了備份,但因為儲存的資料都是一樣的,所以看做一個節點),    單台伺服器的資料存放區壓力會很大,因此,可以考慮使用分布式的環境來儲存,這就是Redis的分布式叢集。    分布式:資料分成幾份儲存在不同的裝置上    叢集:對於相同的資料,都會有至少一個副本進行儲存。    這可以類比hadoop中的hdfs或者是kafka中的partition(topic可以設定partition數量和副本因子)3.在Redis中,搭建分布式叢集環境至少需要6個節點,因此出於裝置的考慮,這裡會在同一台裝置上操作    也就是說,這裡搭建的是偽分布式環境,3個為主節點,另外3個分別為其從節點,用來儲存其副本資料。    根據前面的理論知識,在分布式環境中,key值會進行如下的計算:        CRC16(16) % 16384    來計算key值屬於哪一個槽,而對於我們的環境,每個主節點的槽位元量大概是16384 / 3 = 5461
1.解壓安裝包
[[email protected] ~]$ mkdir -p app/redis-cluster[[email protected] ~]$ tar -zxvf soft/redis-3.2.0.tar.gz -C app/redis-cluster/
2.編譯安裝
[[email protected] ~]$ cd app/redis-cluster/redis-3.2.0/[[email protected] redis-3.2.0]$ pwd/home/uplooking/app/redis-cluster/redis-3.2.0[[email protected] redis-3.2.0]$ make[[email protected] redis-3.2.0]$ make install PREFIX=/home/uplooking/app/redis-cluster/redis-3.2.0
3.建立Redis節點
[[email protected] redis-cluster]$ mv redis-3.2.0/ 7000[[email protected] redis-cluster]$ cp -r 7000 7001[[email protected] redis-cluster]$ cp -r 7000 7002[[email protected] redis-cluster]$ cp -r 7000 7003[[email protected] redis-cluster]$ cp -r 7000 7004[[email protected] redis-cluster]$ cp -r 7000 7005
4.修改各個節點的配置

以7000為例:

daemonize   yes                             //配置redis後台運行bind    uplooking01                         //綁定主機uplooking01logfile "/home/uplooking/app/redis-cluster/7000/redis-7000.log"     //注意目錄要存在pidfile /var/run/redis-7000.pid             //pidfile檔案對應7000,7002,7003port    7000                                //連接埠cluster-enabled yes                         //開啟叢集  把注釋#去掉cluster-config-file nodes-7000.conf         //叢集的配置  設定檔初次開機自動產生cluster-node-timeout    15000               //請求逾時  設定15秒夠了appendonly  yes                             //aof日誌開啟  有需要就開啟,它會每次寫操作都記錄一條日誌

在其它的節點上,只需要修改為7001,7002…即可。

技巧:配置完成7000後,可以直接複製到其它節點,cp redis.conf ../7001,然後再充分利用vim中的1,$s///g將7000替換為其它數字,如7001等。

5.啟動各個節點

先建立一個大量啟動的指令碼:

[[email protected] redis-cluster]$ cat start-all.sh#!/bin/bashcd 7000bin/redis-server ./redis.confcd ..cd 7001bin/redis-server ./redis.confcd ..cd 7002bin/redis-server ./redis.confcd ..cd 7003bin/redis-server ./redis.confcd ..cd 7004bin/redis-server ./redis.confcd ..cd 7005bin/redis-server ./redis.confcd ..

然後再執行指令碼啟動。

6.查看服務
[[email protected] redis-cluster]$ ps -ef | grep redis500       1460     1  0 01:17 ?        00:00:01 bin/redis-server uplooking01:7000 [cluster]500       1464     1  0 01:17 ?        00:00:01 bin/redis-server uplooking01:7001 [cluster]500       1468     1  0 01:17 ?        00:00:01 bin/redis-server uplooking01:7002 [cluster]500       1472     1  0 01:17 ?        00:00:01 bin/redis-server uplooking01:7003 [cluster]500       1474     1  0 01:17 ?        00:00:01 bin/redis-server uplooking01:7004 [cluster]500       1480     1  0 01:17 ?        00:00:01 bin/redis-server uplooking01:7005 [cluster]500       3233  1018  0 01:53 pts/0    00:00:00 grep redis
7.建立叢集(核心)

現在就是要使用前面準備好的redis節點,將其串聯起來搭建叢集。官方提供了一個工具:redis-trib.rb($REDIS_HOME/src 使用ruby編寫的一個程式,所以需要安裝ruby):

$ sudo yum -y install ruby ruby-devel rubygems rpm-build 

再用gem這個命令安裝redis介面(gem是ruby的一個工具包):

gem install redis [ -v 3.2.0] #[]中為可選項制定具體的軟體版本# 在我安裝時,提示ruby版本需要>=2.2.2,但是上面接上redis介面的版本後就沒有問題了。

接下來運行一下redis-trib.rb:

[[email protected] 7000]$ src/redis-trib.rb create --replicas 1 192.168.56.101:7000 192.168.56.101:7001 192.168.56.101:7002 192.168.56.101:7003 192.168.56.101:7004 192.168.56.101:7005>>> Creating cluster>>> Performing hash slots allocation on 6 nodes...Using 3 masters:192.168.56.101:7000192.168.56.101:7001192.168.56.101:7002Adding replica 192.168.56.101:7003 to 192.168.56.101:7000Adding replica 192.168.56.101:7004 to 192.168.56.101:7001Adding replica 192.168.56.101:7005 to 192.168.56.101:7002M: 497bce5118057198afb0511cc7b88479bb0c3938 192.168.56.101:7000   slots:0-5460 (5461 slots) masterM: f0568474acad5c707f25843add2d68455d2cbbb2 192.168.56.101:7001   slots:5461-10922 (5462 slots) masterM: ebe86ea74af5612e6393c8e5c5b3363928a4b7b2 192.168.56.101:7002   slots:10923-16383 (5461 slots) masterS: c99c55ab3fcea2d65ca3be5b4786390a6e463ea2 192.168.56.101:7003   replicates 497bce5118057198afb0511cc7b88479bb0c3938S: 0a847801493a45d32487d701cd0fe37790d4b2f9 192.168.56.101:7004   replicates f0568474acad5c707f25843add2d68455d2cbbb2S: 7f9e4bec579fda23a574a62d362a04463140bbc2 192.168.56.101:7005   replicates ebe86ea74af5612e6393c8e5c5b3363928a4b7b2Can I set the above configuration? (type ‘yes‘ to accept): yes>>> Nodes configuration updated>>> Assign a different config epoch to each node>>> Sending CLUSTER MEET messages to join the clusterWaiting for the cluster to join......>>> Performing Cluster Check (using node 192.168.56.101:7000)M: 497bce5118057198afb0511cc7b88479bb0c3938 192.168.56.101:7000   slots:0-5460 (5461 slots) masterM: f0568474acad5c707f25843add2d68455d2cbbb2 192.168.56.101:7001   slots:5461-10922 (5462 slots) masterM: ebe86ea74af5612e6393c8e5c5b3363928a4b7b2 192.168.56.101:7002   slots:10923-16383 (5461 slots) masterM: c99c55ab3fcea2d65ca3be5b4786390a6e463ea2 192.168.56.101:7003   slots: (0 slots) master   replicates 497bce5118057198afb0511cc7b88479bb0c3938M: 0a847801493a45d32487d701cd0fe37790d4b2f9 192.168.56.101:7004   slots: (0 slots) master   replicates f0568474acad5c707f25843add2d68455d2cbbb2M: 7f9e4bec579fda23a574a62d362a04463140bbc2 192.168.56.101:7005   slots: (0 slots) master   replicates ebe86ea74af5612e6393c8e5c5b3363928a4b7b2[OK] All nodes agree about slots configuration.>>> Check for open slots...>>> Check slots coverage...[OK] All 16384 slots covered.

仔細查看其提示,會對Redis分布式叢集有一個更加清晰的理解。另外需要注意的是,由於redis-trib.rb 對網域名稱或主機名稱支援不好,故在建立叢集的時候要使用ip:port的方式。

8.測試
[[email protected] 7000]$ bin/redis-cli -h uplooking01 -p 7000 -cuplooking01:7000> set name xpleaf-> Redirected to slot [5798] located at 192.168.56.101:7001OK192.168.56.101:7001> get name"xpleaf"192.168.56.101:7001>[[email protected] 7000]$ bin/redis-cli -h uplooking01 -p 7004 -cuplooking01:7004> get name-> Redirected to slot [5798] located at 192.168.56.101:7001"xpleaf"192.168.56.101:7001>[[email protected] 7000]$ bin/redis-cli -h uplooking01 -p 7004 -cuplooking01:7004> set name yyh-> Redirected to slot [5798] located at 192.168.56.101:7001OK192.168.56.101:7001> get name"yyh"[[email protected] 7000]$ bin/redis-cli -h uplooking01 -p 7002 -cuplooking01:7002> keys *(empty list or set)uplooking01:7002> get name-> Redirected to slot [5798] located at 192.168.56.101:7001"yyh"

上面的測試可以充分說明下面幾個問題:

1.分布式    資料是分布式儲存的,根據key的不同會儲存到不同的主節點上。2.資料備份    從節點是作為備份節點的,跟前面的主從複製叢集一樣,只是用來讀資料,當需要寫或修改資料時,需要切換到主節點上。
Redis Java API使用(二):Cluster API使用

前面的代碼只適合操作單機版本的Redis,如果使用的是分布式的Redis叢集,那麼就需要修改一下代碼,這裡,我們直接開發一個工具類JedisClusterUtil,如下:

package com.uplooking.bigdata.common.util.redis;import redis.clients.jedis.*;import java.io.IOException;import java.util.HashSet;import java.util.Properties;import java.util.Set;/** * Redis Java API 操作的工具類 *  專門負責redis的cluster模式 */public class JedisClusterUtil {    private JedisClusterUtil() {}    private static JedisCluster jedisCluster;    static {        Set<HostAndPort> nodes = new HashSet<HostAndPort>();        nodes.add(new HostAndPort("uplooking01", 7000));        nodes.add(new HostAndPort("uplooking01", 7001));        nodes.add(new HostAndPort("uplooking01", 7002));        nodes.add(new HostAndPort("uplooking01", 7003));        nodes.add(new HostAndPort("uplooking01", 7004));        nodes.add(new HostAndPort("uplooking01", 7005));        jedisCluster = new JedisCluster(nodes);//得到的是redis的叢集模式    }    /**     * 提供了Jedis的對象     * @return     */    public static JedisCluster getJedis() {        return jedisCluster;    }    /**     * 資源釋放     * @param jedis     */    public static void returnJedis(JedisCluster jedis) {        try {            jedis.close();        } catch (IOException e) {            e.printStackTrace();        }    }}

在使用時需要注意的是,JedisCluster在使用mget等API操作時,是不允許同時在多個節點上擷取資料的,例如:List<String> mget = jedis.mget("name", "age");,如果name和age分別在不同的節點上,則會報異常,所以不建議使用此種方式來擷取資料。

Redis筆記整理(二):Java API使用與Redis分布式叢集環境搭建

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.