1. 程式人生 > >Linux系統配置Redis+Redis叢集

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 
  1. **關閉IP繫結 **61行
    在這裡插入圖片描述

  2. 關閉保護模式
    在這裡插入圖片描述

  3. 開啟後臺啟動
    在這裡插入圖片描述

  4. 修改PID位置
    在這裡插入圖片描述

  5. 修改持久化檔案路徑
    在這裡插入圖片描述

  6. 修改記憶體策略
    在這裡插入圖片描述
    ##通過配置檔案的方式 啟動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叢集中每個節點多可以與其他節點進行通訊.同時叢集內部有心跳檢測.如果節點發生宕機的現象.由所在叢集的全部伺服器負責推選.保證服務的正常執行.如果全部的從節點宕機,並且這時主節點宕機那麼整個叢集才會奔潰.
叢集規模定義:
原則:一般叢集中的主節點的數量一定是奇數個.目的防止出現平票現象(腦裂)

  1. 建立資料夾
    在redis 跟目錄下建立cluster資料夾後新增7000-7008文化夾
    在這裡插入圖片描述

  2. 匯入配置檔案:
    將redis.conf檔案分別匯入7000-7008資料夾中

  3. 修改redis.conf配置檔案
    1.關閉ip繫結
    在這裡插入圖片描述
    2.關閉保護模式
    在這裡插入圖片描述
    3.修改埠號
    在這裡插入圖片描述
    4.開啟後臺啟動
    在這裡插入圖片描述
    5.修改PID位置
    在這裡插入圖片描述
    6.修改持久化檔案路徑
    在這裡插入圖片描述
    7.修改記憶體策略
    在這裡插入圖片描述
    8.開啟叢集
    在這裡插入圖片描述
    9.開啟叢集的日誌檔案
    在這裡插入圖片描述
    10.設定推選時間
    在這裡插入圖片描述

分別修改配置檔案:

編輯redis啟動指令碼檔案:

在這裡插入圖片描述

啟動Redis

sh start.sh

實現叢集搭建:

使用ruby工具管理redis叢集.
參考Ruby安裝教程:

https://www.cnblogs.com/lihaoyang/p/6906444.html

./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