Linux系統配置Redis+Redis叢集
Redis 簡介:
Redis 是一個開源(BSD許可)的,key-value儲存的.記憶體中的資料結構儲存系統,它可以用作資料庫、快取和訊息中介軟體。 它支援多種型別的資料結構,如 字串(strings), 雜湊(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 與範圍查詢, bitmaps, hyperloglogs 和 地理空間(geospatial) 索引半徑查詢。 Redis 內建了 複製(replication),LUA指令碼(Lua scripting), LRU驅動事件(LRU eviction),事務(transactions) 和不同級別的 磁碟持久化(persistence), 並通過 Redis哨兵(Sentinel)和自動 分割槽(Cluster)提供高可用性(high availability)。
結果:讀的速度是110000次/s,寫的速度是81000次/s
將redis.tar 放在linux系統裡面解壓:
tar -zxvf redis-3.2.8.tar.gz
編譯/和安裝redis
在redis的根目錄下執行make/make install
[root@iZwz9c6jlipu33po7lw2kgZ redis-3.2.8]# make
[root@iZwz9c6jlipu33po7lw2kgZ redis-3.2.8]# make install
Redis 啟動:
1.redis-server
2.redis-server &
3.redis-server redis.conf
4.redis-cli -p 6379 shutdown
redis-cli shutdown
kill -9 8386
5.redis-cli -p 6379 進入控制檯
修改Redis配置檔案:
[root@iZwz9c6jlipu33po7lw2kgZ redis-3.2.8]# vim redis.conf
-
**關閉IP繫結 **61行
-
關閉保護模式
-
開啟後臺啟動
-
修改PID位置
-
修改持久化檔案路徑
-
修改記憶體策略
##通過配置檔案的方式 啟動redis
[root@iZwz9c6jlipu33po7lw2kgZ redis-3.2.8]# redis-server redis.conf
Redis中持久化策略說明
因為redis中儲存的資料都在記憶體中,當斷電/宕機.快取中的資料都會被清空.如果redis中沒有配置持久化策略,安全性不夠完善.
策略說明:
1.RDB方式
該方式是redis預設選擇的持久化策略
特點:持久化的效率更高,定期持久化可能會丟失資料
2.AOF方式
該方式需要通過配置檔案手動開啟
特點:持久化效率低,每秒持久化/每次操作持久化,保證資料儘可能不丟失
持久化步驟:
1.當用戶set操作時,redis中的資料會新增/更新
2.這時根據使用者選擇的持久化的策略.自動的進行資料持久化操作.以下以RDB模式為例.
3.定期會將redis中全部的資料通過xxx.RDB檔案的方式儲存.
4.如果redis伺服器宕機重啟時,首先會載入持久化檔案xxx.RDB.恢復記憶體中的資料.
5.當用戶使用redis時,這時redis記憶體中已經恢復了資料,為使用者繼續提供服務.
RDB模式:
1.RDB持久化策略
save 900 1
save 300 10
save 60 10000
1.在15分鐘內,如果使用者執行了一次set操作則持久化一次
2.在5分鐘內,如果使用者執行了10次set操作則持久化一次
3.在5分鐘內,如果使用者執行了10000set操作則持久化一次
持久化檔名稱配置
在237行可以修改持久化檔案的名稱
修改持久化檔案的位置
總結:
如果使用redis服務時,如果允許丟失小部分資料,則使用RDB模式,因為它的效率是最高的。
AOF模式:
1.開啟AOF模式
說明:如果在配置檔案中開啟AOF模式,則redis中的RDB模式將不生效.
2.持久化檔名稱
持久化策略:
說明:
AOF模式是記錄使用者的執行的過程.將使用者的全部的操作步驟,以檔案的形式進行記錄.當redis伺服器重新啟動時,會根據AOF檔案中的步驟,重新執行一次.最終實現資料的恢復.
appendfsync always
appendfsync everysec
appendfsync no
always:使用者每次操作都是追加到aof檔案中
everysec:每秒記錄使用者的操作步驟
no:不記錄
持久化檔案位置
總結:
AOF模式相當於記錄了使用者的執行過程.從而實現了資料的持久化.預設的條件下AOF模式採用每秒備份.保證資料的有效性.但是效率低於RDB.
AOF檔案較大,需要的執行時間較長.
Redis中記憶體策略說明
1.定義redis中最大記憶體
LRU演算法:
記憶體管理的一種頁面置換演算法,對於在記憶體中但又不用的資料塊(記憶體塊)叫做LRU,作業系統會根據哪些資料屬於LRU而將其移出記憶體而騰出空間來載入另外的資料。
記憶體優化手段
volatile-lru -> 將設定超時時間的資料並且其中使用較少的資料進行刪除
allkeys-lru -> 將redis中全部key進行LRU篩選,之後進行刪除
volatile-random -> 設定了超時間的資料,隨機刪除
allkeys-random -> 全部的key隨機刪除
volatile-ttl -> 將已經設定了超時時間的資料,按照存活時間排序,將馬上要過期的資料進行刪除.
noeviction -> 不做任何操作,將報錯資訊返回給使用者.
.修改優化策略
Redis常用命令:
String型別
## Hash型別:
List型別:
說明:Redis中的List集合是雙端迴圈列表,分別可以從左右兩個方向插入資料.
List集合可以當做佇列使用,也可以當做棧使用
佇列:存入資料的方向和獲取資料的方向相反
棧:存入資料的方向和獲取資料的方向相同
Redis事務命令:
說明:redis中操作可以新增事務的支援.一項任務可以由多個redis命令完成,如果有一個命令失敗導致入庫失敗時.需要實現事務回滾.
操作簡單例項:
匯入依賴包:
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<!--新增spring-datajar包 -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.4.1.RELEASE</version>
</dependency>
<dependency><!-- fastJson json轉換工具 -->
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.5</version>
</dependency>
操作redis資料庫
public class TestRedisString {
/**
* 步驟:
* 1.連線Redis IP:埠
*/
@Test
public void test01(){
Jedis jedis = new Jedis("192.168.126.169", 6379);
jedis.set("1ii", "好好學習,OJBK");
System.out.println(jedis.get("1ii"));
}
//操作Hash
@Test
public void test02(){
Jedis jedis = new Jedis("192.168.126.169", 6379);
jedis.hset("user", "id", "100");
jedis.hset("user", "name", "9班");
Map<String,String> userMap = jedis.hgetAll("user");
System.out.println(userMap);
}
@Test
public void testList(){
Jedis jedis = new Jedis("192.168.126.169", 6379);
jedis.lpush("List1", "1,2,2,2,2,2","2","3");
System.out.println(jedis.rpop("List1"));
System.out.println(jedis.rpop("List1"));
}
}
物件轉換為String
ObjectMapper objectMapper = new ObjectMapper();
String userJSON =
objectMapper.writeValueAsString(user);
System.out.println(userJSON);
//將json串轉化為java物件
User user1 = objectMapper.readValue(userJSON, User.class);
System.out.println(user1.toString());
String listJSON =
objectMapper.writeValueAsString(strList);
System.out.println(listJSON);
//將JSON轉化為List集合
List<String> jsonList =
objectMapper.readValue(listJSON, List.class);
例項2:
public class App
{
public static void main( String[] args )
{
System.out.println( "Hello World!" );
}
@Test
public void testReadRedis() throws Exception{
ObjectMapper objectMapper= new ObjectMapper();
//取值物件
Jedis jedis= new Jedis("119.23.224.88", 6379);
//lpop 取值
String s1 = jedis.lpop("s2");
Student student1 = objectMapper.readValue(s1, Student.class);
System.out.println(student1.toString());
String s2=jedis.lpop("s1");
Student student2 = objectMapper.readValue(s2, Student.class);
System.out.println(student2.toString());
//hset 取值
String hs1 = jedis.hget("h1", "s1");
String hs2 = jedis.hget("h1", "s2");
Student student3 = objectMapper.readValue(hs1, Student.class);
Student student4 = objectMapper.readValue(hs2, Student.class);
hs1=jedis.hget("h2", "s1");
hs2=jedis.hget("h2", "s2");
Student student5 = objectMapper.readValue(hs1, Student.class);
Student student6 = objectMapper.readValue(hs2, Student.class);
System.out.println(student3);
System.out.println(student4);
System.out.println(student5);
System.out.println(student6);
}
@Test
public void testRedis(){
Student s1= new Student();
s1.setAddress("湖南省牛逼市虎頭山");
s1.setAge(26);
s1.setBrithday(new Date());
s1.setFristName("王");
s1.setLastName("飛起");
s1.setGender("男");
Student s2= new Student();
s2.setAddress("湖南省牛逼市虎頭山");
s2.setAge(29);
s2.setBrithday(new Date());
s2.setFristName("王");
s2.setLastName("白起");
s2.setGender("女");
ObjectMapper objectMapper= new ObjectMapper();
Jedis jedis= new Jedis("119.23.224.88", 6379);
try {
String s1JSON= objectMapper.writeValueAsString(s1);
String s2JSON= objectMapper.writeValueAsString(s2);
//有序對列存值
jedis.lpush("s1", s1JSON );
jedis.lpush("s2", s2JSON);
//hset 存值 key值為 hashmap的名字 field 引數 為hashmap的key 值 value 為value
jedis.hset("h1", "s1", s1JSON);
jedis.hset("h1", "s2", s2JSON);
jedis.hset("h2", "s1", s1JSON);
jedis.hset("h2", "s2", s2JSON);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
@Test
public void testRedisArays(){
Jedis jedis=new Jedis("119.23.224.88", 6379);
jedis.set("9797", "丟你老母");
String value=jedis.get("9797");
System.out.println(value);
}
}
class Student{
private String fristName;
private String lastName;
private Integer age;
private Date brithday;
private String address;
private String gender;
@Override
public String toString() {
return "Student{" +
"fristName='" + fristName + '\'' +
", lastName='" + lastName + '\'' +
", age=" + age +
", brithday=" + brithday +
", address='" + address + '\'' +
", gender='" + gender + '\'' +
'}';
}
public String getFristName() {
return fristName;
}
public void setFristName(String fristName) {
this.fristName = fristName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Date getBrithday() {
return brithday;
}
public void setBrithday(Date brithday) {
this.brithday = brithday;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
Redis叢集實現:
叢集特點:
說明:redis叢集實質上將redis分片和redis哨兵的機制進行整合.redis叢集中每個節點多可以與其他節點進行通訊.同時叢集內部有心跳檢測.如果節點發生宕機的現象.由所在叢集的全部伺服器負責推選.保證服務的正常執行.如果全部的從節點宕機,並且這時主節點宕機那麼整個叢集才會奔潰.
叢集規模定義:
原則:一般叢集中的主節點的數量一定是奇數個.目的防止出現平票現象(腦裂)
-
建立資料夾
在redis 跟目錄下建立cluster資料夾後新增7000-7008文化夾
-
匯入配置檔案:
將redis.conf檔案分別匯入7000-7008資料夾中 -
修改redis.conf配置檔案
1.關閉ip繫結
2.關閉保護模式
3.修改埠號
4.開啟後臺啟動
5.修改PID位置
6.修改持久化檔案路徑
7.修改記憶體策略
8.開啟叢集
9.開啟叢集的日誌檔案
10.設定推選時間
分別修改配置檔案:
編輯redis啟動指令碼檔案:
啟動Redis
sh start.sh
實現叢集搭建:
使用ruby工具管理redis叢集.
參考Ruby安裝教程:
./redis-trib.rb create --replicas 2 176.53.5.94:7000 176.53.5.94:7001 176.53.5.94:7002 176.53.5.94:7003 176.53.5.94:7004 176.53.5.94:7005 176.53.5.94:7006 176.53.5.94:7007 176.53.5.94:7008
replicas 2:代表一個主節點有2臺從機
自己購買的伺服器再搭建完集群后需要:
伺服器搭建叢集需把Redis的監聽視窗也開啟;一般為10000+埠號
叢集的部分程式碼實現:
redis.properties 配置檔案
#最小空閒數
redis.minIdle=100
#最大空閒數
redis.maxIdle=300
#最大連線數
redis.maxTotal=1000
#客戶端超時時間單位是毫秒
redis.timeout=5000
#最大建立連線等待時間
redis.maxWait=1000
#是否在從池中取出連線前進行檢驗,如果檢驗失敗,則從池中去除連線並嘗試取出另一個
redis.testOnBorrow=true
#redis cluster
redis.cluster0=119.23.224.88:7000
redis.cluster1=119.23.224.88:7001
redis.cluster2=119.23.224.88:7002
redis.cluster3=119.23.224.88:7003
redis.cluster4=119.23.224.88:7004
redis.cluster5=119.23.224.88:7005
redis.cluster6=119.23.224.88:7006
redis.cluster7=119.23.224.88:7007
redis.cluster8=119.23.224.88:7008
Redis配置類:
@Configuration
@PropertySource("classpath:property/redis.properties") // 讀取redisCluter配置檔案
public class AppRedisConfig {
/**
* redis連線池
* @param maxIdle 最大空閒數 int 毫秒
* @param maxWait 最大建立連線等待時間 int 毫秒
* @param testOnBorrow 是否取出前在連線池中校驗 boolean
* @param maxTotal 最大連線數 int 毫秒
* @param minIdle 最小空閒數 int 毫秒
* @return
*/
@Bean("jedisPoolConfig")
public JedisPoolConfig newJedisPoolConfig(@Value("${redis.maxIdle}") int maxIdle,
@Value("${redis.maxWait}") long maxWait
,@Value("${redis.testOnBorrow}") boolean testOnBorrow
,@Value("${redis.maxTotal}") int maxTotal
,@Val