1. 程式人生 > >Redis叢集架構環境搭建及jedis開發

Redis叢集架構環境搭建及jedis開發

1、下載redis

2、安裝redis

  • 上傳安裝檔案到伺服器的/usr/local目錄下
  • 解壓tar –zxvf redis-4.0.9.tar.gz
  • 進入redis目錄,cd redis-4.0.9安裝:make && make install

3、redis叢集配置

1)在/usr/local建立redis_cluster資料夾 

2)進入到redis_cluster建立 9000、9001、9002、9003、9004、9005六個資料夾

3)在redis-4.0.9目錄下找到redis.conf,複製redis.conf檔案到9000、9001、9002、9003、9004、9005

4)修改9000、9001、9002、9003、9004、9005目錄下的redis.conf配置(每個節點下的檔案都需要修改,可以使用vi命令去修改,也可以在本地改好,在上傳到伺服器)

port  9000                                     //埠9000、9001、9002、9003、9004、9005      

bind  192.168.145.177                      //預設ip為192.168.145.177需要改為其他節點機器可訪問的ip 否則建立叢集時無法訪問對應的埠,無法建立叢集

daemonize    yes                       //redis後臺執行

pidfile /var/run/redis_9000.pid       //pidfile檔案對應9000、9001、9002、9003、9004、9005

cluster-enabled  yes               //

開啟叢集  把註釋#去掉

cluster-config-file  nodes_7000.conf  //叢集的配置 9000、9001、9002、9003、9004、9005

cluster-node-timeout  15000        //請求超時  預設15秒,可自行設定

appendonly  yes                  //aof日誌開啟  有需要就開啟,它會每次寫操作都記錄一條日誌 

4、啟動redis

在/usr/local目錄下執行下面程式(redis-server這個命令在/usr/local/bin下面)

./bin/redis-server redis_cluster/9000/redis.conf

./bin/redis-server redis_cluster/9001/redis.conf

./bin/redis-server redis_cluster/9002/redis.conf

./bin/redis-server redis_cluster/9003/redis.conf

./bin/redis-server redis_cluster/9004/redis.conf

./bin/redis-server redis_cluster/9005/redis.conf

批量停止redis命令:pkill -9 redis

5、redis叢集

redis執行環境需要ruby,因此需先按照ruby執行環境。

5.1、安裝執行環境ruby

1)安裝ruby

命令:yum -y install ruby ruby-devel rubygems rpm-build

2)安裝rvm

命令:curl -L get.rvm.io | bash -s stable

第一次會失敗,彈出需要公鑰,然後

執行一下 gpg2 --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3

後面的這個串,每臺機器都不一樣,具體操作,看報錯的資訊。

再執行一次curl -L get.rvm.io | bash -s stable,即可安裝rvm成功。

3)source環境,讓rvm可用

source /usr/local/rvm/scripts/rvm

4)rvm list known檢視可用的ruby

[ruby-]1.8.6[-p420]

[ruby-]1.8.7[-head] # security released on head

[ruby-]1.9.1[-p431]

[ruby-]1.9.2[-p330]

[ruby-]1.9.3[-p551]

[ruby-]2.0.0[-p648]

[ruby-]2.1[.10]

[ruby-]2.2[.7]

[ruby-]2.3[.4]

[ruby-]2.4[.1]

5)rvm install 2.4.1  選最新的安裝

6)編譯環境

gem install redis

7)安裝rubygems

yum install -y rubygems
注意:如果yum用不了,需要先安裝yum
https://jingyan.baidu.com/article/ed2a5d1f5a9fbe09f6be17ea.html

5.2、建立叢集

命令:

/usr/local/redis-4.0.9/src/redis-trib.rb create --replicas  1  192.168.145.177:9000 192.168.145.177:9001 192.168.145.177:9002 192.168.145.177:9003 192.168.145.177:9004 192.168.145.177:9005

--replicas 1表示為叢集的master節點建立1個副本。那麼6個例項裡,有三個master,有三個是slave。
提示Can I set the above configuration? (type 'yes' to accept): 
輸入yes

即可

5.2驗證叢集

在目錄/usr/local下,輸入

命令:./bin/redis-cli -h 192.168.145.177 -p 9000 -c

輸入:cluster info檢視叢集資訊

輸入:cluster nodes檢視叢集節點

測試:set test neusoft

get test

5.3驗證叢集容災情況

1)檢視redis程序:ps –ef|grep redis

2)關閉一臺主redis,殺掉9001程序:kill -9 12783

3)再次進入9000的redis例項,檢視現有的redis叢集節點情況。

./bin/redis-cli -h 192.168.145.177 -p 9000 –c

cluster nodes

可以看到9001已經fail了,現在少了一臺主redis。

4)啟動9001,檢測9001

/usr/local/redis-4.0.9/src/redis-trib.rb check 192.168.145.177:9001

檢視叢集節點資訊:

9001變成從redis,9004變為主redis

6、jedis開發

6.1、Maven依賴

<dependency>

    <groupId>redis.clients</groupId>

    <artifactId>jedis</artifactId>

    <version>2.8.2</version>

</dependency>

6.2、編碼

  RedisCacheUtil(Redis快取操作類)

import org.apache.log4j.Logger;
import org.codehaus.jackson.type.TypeReference;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Redis快取操作類
 *
 * @author: alex
 * @time: 2018-06-04
 * @version: 1.0
 */
public class RedisCacheUtil {

    private static Logger log = Logger.getLogger(RedisCacheUtil.class);

    /**
     * 存放String型別的值
     *
     * @param key   key值
     * @param value value值
     * @throws Exception
     */
    public void setString(String key, String value) throws Exception {
        try {
            RedisConfigUtil.getJedisCluster().set(key, value);
        } catch (Exception e) {
            log.error(e);
            throw new Exception("儲存String物件的值出錯");
        }
    }

    /**
     * 獲取String型別的值
     *
     * @param key key值
     * @return 取得對應值
     * @throws Exception
     */
    public String getString(String key) throws Exception {
        String value = null;
        try {
            value = RedisConfigUtil.getJedisCluster().get(key);
        } catch (Exception e) {
            log.error(e);
            throw new Exception("獲取String物件的值出錯");
        }
        return value;
    }

    /**
     * 設定物件
     *
     * @param key    key值
     * @param object 物件
     * @throws Exception
     */
    public void setObject(String key, Object object) throws Exception {
        try {
            String json = JsonConvertUtil.objectConvertJSON(object);
            RedisConfigUtil.getJedisCluster().set(key, json);
        } catch (Exception e) {
            log.error(e);
            throw new Exception("儲存Object物件的值出錯");
        }
    }

    /**
     * 獲取物件
     *
     * @param key  key值
     * @param type 獲取物件的型別
     * @return 物件型別
     * @throws Exception
     */
    public Object getObject(String key, TypeReference<?> type) throws Exception {
        Object obj = null;
        try {
            if (RedisConfigUtil.getJedisCluster().exists(key)) {
                String json = RedisConfigUtil.getJedisCluster().get(key);
                obj = JsonConvertUtil.jsonConvertObject(json, type);
            }
        } catch (Exception e) {
            log.error(e);
            throw new Exception("獲取Object物件的值出錯");
        }
        return obj;
    }

    /**
     * 根據key、field取hash值,轉換為物件
     *
     * @param key
     * @param field
     * @return
     * @throws Exception
     */
    public Object hGet(String key, String field, TypeReference<?> type) throws Exception {
        try {
            if (RedisConfigUtil.getJedisCluster().exists(key)) {
                String json = RedisConfigUtil.getJedisCluster().hget(key, field);
                return JsonConvertUtil.jsonConvertObject(json, type);
            }
            return null;
        } catch (Exception e) {
            log.error(e);
            throw new Exception("獲取Hash時出錯");
        }
    }

    /**
     * 取key對應的所有hash,返回hashmap
     *
     * @param key
     * @return
     * @throws Exception
     */
    public Map hGetAll(String key) throws Exception {
        try {
            if (RedisConfigUtil.getJedisCluster().exists(key)) {
                return RedisConfigUtil.getJedisCluster().hgetAll(key);
            }
            return null;
        } catch (Exception e) {
            log.error(e);
            throw new Exception("獲取HashAll時出錯");
        }
    }

    /**
     * 存放到快取中,並設定失效時間
     *
     * @param key    key值
     * @param object 實體
     * @param min    失效時間
     * @throws Exception
     */
    public void setObjectByExpire(String key, Object object, int min) throws Exception {
        int seconds = min * 60;
        try {
            String json = JsonConvertUtil.objectConvertJSON(object);
            RedisConfigUtil.getJedisCluster().set(key, json);
            RedisConfigUtil.getJedisCluster().expire(key, seconds);
        } catch (Exception e) {
            log.error(e);
            throw new Exception("儲存Object物件的值並設定失效時間操作出錯");
        }
    }

    /**
     * 獲取快取資訊
     *
     * @param key  key值
     * @param type 實體型別
     * @return 獲取的物件
     * @throws Exception
     */
    public Object getExistObject(String key, TypeReference<?> type) throws Exception {
        try {
            if (RedisConfigUtil.getJedisCluster().exists(key)) {
                String json = RedisConfigUtil.getJedisCluster().get(key);
                return JsonConvertUtil.jsonConvertObject(json, type);
            }
            return null;
        } catch (Exception e) {
            log.error(e);
            throw new Exception("獲取Object物件的值並設定失效時間操作出錯");
        }
    }


    /**
     * 判斷快取中是否存在此key
     *
     * @param key key值
     * @return true存在,false不存在
     * @throws Exception
     */
    public boolean isExists(String key) throws Exception {
        boolean flag = false;
        try {
            flag = RedisConfigUtil.getJedisCluster().exists(key);
        } catch (Exception e) {
            log.error(e);
            throw new Exception("判斷快取中是否存在此key時出錯");
        }
        return flag;
    }

    /**
     * 根據key值刪除快取內容
     *
     * @param key key值
     * @throws Exception
     */
    public void deleteByKey(String key) throws Exception {
        try {
            if (RedisConfigUtil.getJedisCluster().exists(key)) {
                RedisConfigUtil.getJedisCluster().del(key);
            }
        } catch (Exception e) {
            log.error(e);
            throw new Exception("刪除此key時出錯");
        }
    }

    /**
     * 將相同key值放入到連結串列中
     *
     * @param key    key值
     * @param object 物件
     * @throws Exception
     */
    public void setList(String key, Object object) throws Exception {
        try {
            String json = JsonConvertUtil.objectConvertJSON(object);
            RedisConfigUtil.getJedisCluster().rpush(key, json);
        } catch (Exception e) {
            log.error(e);
            throw new Exception("儲存列表物件的值出錯");
        }
    }

    /**
     * 獲取列表物件
     *
     * @param key  key值
     * @param type 獲取物件的型別
     * @return 物件型別
     * @throws Exception
     */
    public List<Object> getList(String key, TypeReference<?> type) throws Exception {
        try {
            List<Object> list = new ArrayList<Object>();
            Long size = RedisConfigUtil.getJedisCluster().llen(key);
            List<String> bis = RedisConfigUtil.getJedisCluster().lrange(key, 0, size.intValue() - 1);
            for (String bi : bis) {
                Object obj = JsonConvertUtil.jsonConvertObject(bi, type);
                list.add(obj);
            }
            return list;
        } catch (Exception e) {
            log.error(e);
            throw new Exception("獲取列表物件出錯");
        }
    }

    /**
     * 儲存物件到set集合中,去掉重複資料
     *
     * @param key    key值
     * @param object 物件
     * @throws Exception
     */
    public void setSadd(String key, Object object) throws Exception {
        try {
            String json = JsonConvertUtil.objectConvertJSON(object);
            RedisConfigUtil.getJedisCluster().sadd(key, json);
        } catch (Exception e) {
            log.error(e);
            throw new Exception("儲存物件到set集合中出錯");
        }
    }

    /**
     * 獲取所有set集合中的物件
     *
     * @param key  key值
     * @param type 獲取物件的型別
     * @return 物件型別
     * @throws Exception
     */
    public List<Object> getSmembers(String key, TypeReference<?> type) throws Exception {
        try {
            List<Object> list = new ArrayList<Object>();
            java.util.Set<String> bis = RedisConfigUtil.getJedisCluster().smembers(key);
            for (String bi : bis) {
                Object obj = JsonConvertUtil.jsonConvertObject(bi, type);
                list.add(obj);
            }
            return list;
        } catch (Exception e) {
            log.error(e);
            throw new Exception("獲取所有set集合中的物件出錯");
        }
    }
}

RedisConfigUtil(Redis配置類)

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;

import java.util.LinkedHashSet;
import java.util.Set;

public class RedisConfigUtil {

    private static JedisCluster jedisCluster = null;

    private static Set<HostAndPort> nodes = null;

    private static JedisPoolConfig poolConfig = new JedisPoolConfig();

    static {
        nodes = new LinkedHashSet<HostAndPort>();
        nodes.add(new HostAndPort("192.168.145.177", 9000));
        nodes.add(new HostAndPort("192.168.145.177", 9001));
        nodes.add(new HostAndPort("192.168.145.177", 9002));
        nodes.add(new HostAndPort("192.168.145.177", 9003));
        nodes.add(new HostAndPort("192.168.145.177", 9004));
        nodes.add(new HostAndPort("192.168.145.177", 9005));
        // 最大連線數
        poolConfig.setMaxTotal(1);
        // 最大空閒數
        poolConfig.setMaxIdle(1);
        // 最大允許等待時間,如果超過這個時間還未獲取到連線,則會報JedisException異常:
        poolConfig.setMaxWaitMillis(60000);
    }

    public static JedisCluster getJedisCluster() {
        if(jedisCluster == null) {
            jedisCluster = new JedisCluster(nodes, poolConfig);
        }
        return jedisCluster;
    }
}

json轉換類JsonConvertUtil

import org.apache.log4j.Logger;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;

import java.io.IOException;

/**
 * JSON轉換
 * @author: alex
 * @time: 2018-06-04
 * @version: 1.0
 */
public class JsonConvertUtil {

    private static Logger log = Logger.getLogger(JsonConvertUtil.class);

    /**
     * 物件轉換為JSON
     * @param obj
     * @return
     */
    public static String objectConvertJSON(Object obj) {
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.writeValueAsString(obj);
        } catch (IOException e) {
            log.error("物件轉換為JSON出錯", e);
        }

        return null;
    }
    /**
     * 物件轉換為JSON
     * @param obj
     * @return
     */
    public static String toJSON(Object obj) {
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.writeValueAsString(obj);
        } catch (IOException e) {
            log.error("物件轉換為JSON出錯", e);
        }

        return null;
    }
    /**
     * json轉換為物件
     * @param json
     * @param
     * @return
     */
    public static Object jsonConvertObject(String json,TypeReference<?> type){
        Object obj = null;
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.readValue(json, type);
        } catch (IOException e) {
            log.error("JSON轉換為物件出錯", e);
        }

        return obj;
    }
    /**
     * json轉換為物件
     * @param json
     * @param
     * @return
     */
    public static Object jsonConvertObject(String json,Class<?> clazz){
        Object obj = null;
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            return objectMapper.readValue(json, clazz);
        } catch (IOException e) {
            log.error("JSON轉換為物件出錯", e);
        }
        return obj;
    }
}

測試類:

import com.google.gson.reflect.TypeToken;
import org.codehaus.jackson.type.TypeReference;


public class RedisTest {

    public static void main(String[] args) {
        RedisCacheUtil redisUtil = new RedisCacheUtil();
        try {
//            redisUtil.setObject("test","alex");
//            redisUtil.getObject("test",  new TypeReference<String>() {});
            redisUtil.setString("test", "hello world!");
            System.out.println(redisUtil.getString("test"));
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

6.3、執行報錯

No reachable node in cluster

原因:訪問不了redis叢集資訊。

解決辦法:

1)關閉防火牆:

systemctl stop firewalld

2)安裝iptables:

yum install -y iptables

yum install iptables-services

3)編輯可訪問埠:

vi /etc/sysconfig/iptables

增加的位置很重要,不能改變順序

-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

-A INPUT -p icmp -j ACCEPT

-A INPUT -i lo -j ACCEPT

-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT

-A INPUT -m state --state NEW -m tcp -p tcp --dport 9000 -j ACCEPT

-A INPUT -m state --state NEW -m tcp -p tcp --dport 9001 -j ACCEPT

-A INPUT -m state --state NEW -m tcp -p tcp --dport 9002 -j ACCEPT

-A INPUT -m state --state NEW -m tcp -p tcp --dport 9003 -j ACCEPT

-A INPUT -m state --state NEW -m tcp -p tcp --dport 9004 -j ACCEPT

-A INPUT -m state --state NEW -m tcp -p tcp --dport 9005 -j ACCEPT

-A INPUT -j REJECT --reject-with icmp-host-prohibited

-A FORWARD -j REJECT --reject-with icmp-host-prohibited

4)重啟

systemctl restart iptables.service

or

service iptables restart

7、參考文件

https://www.cnblogs.com/yingchen/p/6763524.html

https://www.cnblogs.com/kangoroo/p/7657616.html

https://blog.csdn.net/appleyk/article/details/78325499

https://blog.csdn.net/wojiushifeng1992/article/details/729040