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