redis的使用和安裝,redis基礎和高級部分
在后端開發中,為了提高性能,對於一些經常查詢但是又不太變化的內容會使用redis,比如前端的列表展示項等,如果數據有變化也可以清空緩存,讓前端查一次數據庫,所以使用redis相對高效和靈活.本文主要對於redis在linux上的使用和安裝進行說明。
1.redis的安裝 2.redis常用的命令 3.在阿里雲上面安裝redis 4.在vwmare上安裝redis 5.利用jedis連接redis進行存入和輸出 6.redis的高可用,哨兵機制,主從復制(安裝三台redis服務器,一台主redis) 7.redis常見錯誤 8.redis持久化(AOF與RDB區別)
1.首先通過shell連接到阿里雲服務器。
2.輸入 yum -y install gcc 進行安裝redis
3.輸入命令: wget http://download.redis.io/releases/redis-3.2.9.tar.gz
4.輸入命令:
tar xzf redis-3.2.9.tar.gz
cd redis-3.2.9 make MALLOC=libc
5.啟動Redis服務
在redis安裝目錄下的redis.conf文件中的如下內容:默認安裝路徑是在/root/redis-3.2.9 下面
1、注釋掉redis安裝目錄下的redis.conf文件中的如下數據:bind 127.0.0.1,修改后為#bind 127.0.0.1 2、修改保護模式為非:默認為protected-mode yes ,修改后為protected-mode no 3、設置redis連接密碼:找到#requirepass foobared ,在下面添加requirepass 123456 然后啟動redis server:輸入指令src/redis-server redis.conf
還需要把阿里雲上的redis的6379的端口打開
常用指令
在以上過程中可能會需要重啟redis server,終止和重啟的命令如下:
1、終止,通過殺死redis的進程
kill -9 進程ID (解釋:-9的含義是強制殺死) 進程ID可以通過如下命令查詢: ps -ef | grep 'redis' ps aux | grep '6379' --- 查詢端口 kill -15 9886 --- 殺死重置 kill -9 9886 --- 強制殺死
在服務器開啟后可以開啟客戶端進行測試
啟動客戶端並測試
src/redis-cli
帶密碼的啟動方式
./redis-cli -h 127.0.0.1 -p 6379 -a 123456
-h 是主機IP地址
-p 是端口號
-a 是密碼
也可以直接通過代碼進行測試
6.通過jedis連接redis,通過java代碼實現存儲redis,並從redis當中取值
需要在marven當中加入
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
然后直接寫個測試類測試一下
測試代碼
package com.winter.utils.redis;
import org.junit.Test; import redis.clients.jedis.Jedis; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; public class TestRedis { private Jedis jedis; // @Before public void setup() { jedis = new Jedis("192.168.184.128", 6379);//連接服務器 jedis.auth("123456");//密碼 // } @Test public void test哨兵機制(){ Jedis jedis = new Jedis("192.168.184.128", 6379); // //權限認證,密碼設置的是123456 jedis.auth("123456"); jedis.set("name","我是192.168.184.128存在主服務器"); Jedis jedis1 = new Jedis("192.168.184.136", 6379); // //權限認證,密碼設置的是123456 jedis1.auth("123456"); String name1 = jedis1.get("name"); System.out.println("我是136從機"+name1); Jedis jedis2 = new Jedis("192.168.184.135", 6379); // //權限認證,密碼設置的是123456 jedis2.auth("123456"); String name2 = jedis2.get("name"); System.out.println("我是135從機"+name2); System.out.println("測試從機是否可寫"); try { jedis1.set("name2","測試從機是否可寫"); jedis2.set("name2","測試從機是否可寫"); System.out.println("測試不成功,135從機可以寫"); }catch (Exception e){ System.out.println("說明從機沒有寫的權限"); System.out.println("輸出結果"+e.getMessage()); } } /** * redis存儲字符串 */ @Test public void testString() { jedis.set("name", "xinxin");//向key-->name中放入了value-->xinxin System.out.println(jedis.get("name"));//執行結果:xinxin jedis.append("name", " is my lover"); //拼接 System.out.println(jedis.get("name")); jedis.del("name"); //刪除某個鍵 System.out.println(jedis.get("name")); //設置多個鍵值對 jedis.mset("name", "liuling", "age", "23", "qq", "476777XXX"); jedis.incr("age"); //進行加1操作 System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" + jedis.get("qq")); } /** * redis操作Map */ @Test public void testMap() { //-----添加數據---------- Map<String, String> map = new HashMap<String, String>(); map.put("name", "xinxin"); map.put("age", "22"); map.put("qq", "123456"); jedis.hmset("user", map); //取出user中的name,執行結果:[minxr]-->注意結果是一個泛型的List //第一個參數是存入redis中map對象的key,后面跟的是放入map中的對象的key,后面的key可以跟多個,是可變參數 List<String> rsmap = jedis.hmget("user", "name", "age", "qq"); System.out.println(rsmap); //刪除map中的某個鍵值 jedis.hdel("user", "age"); System.out.println(jedis.hmget("user", "age")); //因為刪除了,所以返回的是null System.out.println(jedis.hlen("user")); //返回key為user的鍵中存放的值的個數2 System.out.println(jedis.exists("user"));//是否存在key為user的記錄 返回true System.out.println(jedis.hkeys("user"));//返回map對象中的所有key System.out.println(jedis.hvals("user"));//返回map對象中的所有value Iterator<String> iter = jedis.hkeys("user").iterator(); while (iter.hasNext()) { String key = iter.next(); System.out.println(key + ":" + jedis.hmget("user", key)); } } /** * jedis操作List */ @Test public void testList() { //開始前,先移除所有的內容 jedis.del("java framework"); System.out.println(jedis.lrange("java framework", 0, -1)); //先向key java framework中存放三條數據 jedis.lpush("java framework", "spring"); jedis.lpush("java framework", "struts"); jedis.lpush("java framework", "hibernate"); //再取出所有數據jedis.lrange是按范圍取出, // 第一個是key,第二個是起始位置,第三個是結束位置,jedis.llen獲取長度 -1表示取得所有 System.out.println(jedis.lrange("java framework", 0, -1)); jedis.del("java framework"); jedis.rpush("java framework", "spring"); jedis.rpush("java framework", "struts"); jedis.rpush("java framework", "hibernate"); System.out.println(jedis.lrange("java framework", 0, -1)); } /** * jedis操作Set */ @Test public void testSet() { //添加 jedis.sadd("user", "liuling"); jedis.sadd("user", "xinxin"); jedis.sadd("user", "ling"); jedis.sadd("user", "zhangxinxin"); jedis.sadd("user", "who"); //移除noname jedis.srem("user", "who"); System.out.println(jedis.smembers("user"));//獲取所有加入的value System.out.println(jedis.sismember("user", "who"));//判斷 who 是否是user集合的元素 System.out.println(jedis.srandmember("user")); System.out.println(jedis.scard("user"));//返回集合的元素個數 } @Test public void test() throws InterruptedException { //jedis 排序 //注意,此處的rpush和lpush是List的操作。是一個雙向鏈表(但從表現來看的) jedis.del("a");//先清除數據,再加入數據進行測試 jedis.rpush("a", "1"); jedis.lpush("a", "6"); jedis.lpush("a", "3"); jedis.lpush("a", "9"); System.out.println(jedis.lrange("a", 0, -1));// [9, 3, 6, 1] System.out.println(jedis.sort("a")); //[1, 3, 6, 9] //輸入排序后結果 System.out.println(jedis.lrange("a", 0, -1)); } // @Test // public void testRedisPool() { // RedisUtil.getJedis().set("newname", "中文測試"); // System.out.println(RedisUtil.getJedis().get("newname")); // } }
application.yml
server:
port: 8081
spring:
datasource:
name: test url: jdbc:mysql://127.0.0.1:3306/mytest?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull username: root password: root # 使用druid數據源 # type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver filters: stat maxActive: 20 initialSize: 1 maxWait: 60000 minIdle: 1 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: select 'x' testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true maxOpenPreparedStatements: 20 redis: database: 0 host: 101.132.191.77 port: 6379 password: 123456 pool: max-idle: 8 min-idle: 0 max-active: 8 max-wait: -1 timeout: 5000 mybatis: mapper-locations: classpath:mapping/*.xml type-aliases-package: com.winter.model #pagehelper pagehelper: helperDialect: mysql reasonable: true supportMethodsArguments: true params: count=countSql ######################################################## ###Redis (RedisConfiguration) ######################################################## ###spring.redis.database=0 ###spring.redis.host=127.0.0.1 ###spring.redis.port=6379 ###spring.redis.password=123456 ###spring.redis.pool.max-idle=8 ###spring.redis.pool.min-idle=0 ###spring.redis.pool.max-active=8 ###spring.redis.pool.max-wait=-1 ###spring.redis.timeout=5000
redis的主從復制是什么?
redis的主從復制主要還是讀寫分離,一台主redis有讀和寫的權限,其他從機redis只有讀的權限,這樣做的好處是為了減輕redis主機的壓力。
redis的哨兵機制?
例:有3台redis,一台是主redis,2台是從機,開啟哨兵機制后,3台redis開啟后會發送心跳包到哨兵這里。如果主機掛了,那么哨兵會從另外2台從機這里選出一台作為主機(從原來只有讀權限升級為讀寫權限)
那如果3台都掛了怎么辦呢,一般企業會有備用機,或者利用keepalive的監聽重啟服務器。
哨兵的功能+keepalive重啟服務器功能=redis的高可用
為了進行redis的集群操作,需要安裝vwmare,然后安裝linux 64位系統進行測試。
這個安裝就不詳說了。安裝vwmare以后下載linux 64位鏡像,然后導入鏡像即可。說下我遇到的坑以及看到的有幫助網址。
Could not connect to '10.7.100.182' (port 22): Connection failed
Xshell遠程連接Linux服務器出錯——Could not connect to '114.214.166.5' (port 22): Connection failed.
主要問題可能為兩個:(1)sshd服務器沒有啟動;(2)防火牆問題 並且需要永久開啟sshd和關閉防火牆
步驟一:啟動sshd服務器
1,sshd服務安裝 2,[root@localhost /]# vi /etc/ssh/sshd_config Port 22 Protocol 2 PermitRootLogin yes 去掉這三行的注釋 最后一個重要!因為它是允許root用戶直接使用sshd服務登錄服務器的! 3,重新啟動sshd服務 [root@localhost /]# service sshd restart 4,設置sshd為系統自動啟動
chkconfig iptables off 永久性生效
chkconfig ip6tables off 防火牆還需要關閉ipv6的防火牆:
步驟二:關閉防火牆
chkconfig iptables off 永久性生效
虛擬機安裝以后可以進行克隆(需要先把服務器給關掉后才可以克隆)
原理就是主redis開啟以后保存內存快照發送到從服務器,因此從服務器里面就會有主服務器的數據
7.如何設置主redis和從redis?
修改從服務器redis中的 redis.conf文件 slaveof 192.168.33.130 6379 這個是主服務器的地址和端口,就是把從的和主的進行關聯 masterauth 123456--- 主redis服務器配置了密碼,則需要配置 通過redis-cli連接后輸入info命令查看role:master,role:slave可以查看主服務器和從服務器
到redis目錄下修改sentinel.conf(這個是哨兵的配置文件)
1.修改sentinel monitor mymaster 192.168.184.128 6379 1 這里的128是主redis,6379是端口號,1是投票,哨兵根據投票數選取一個從redis作為主服務器,一般都是設置為1. 不需要在主redis當中配置哨兵
2.sentinel down-after-milliseconds mymaster 5000 心跳檢測,5秒鍾沒訪問到就換服務器
3.sentinel parallel-syncs mymaster 2 最多有2個子節點,就是備份服務器
4.啟動的時候src/redis-server redis.conf
然后開啟客戶端sentinel.conf --sentinel & 要將redis,redis配置文件還有哨兵都開開來
8.redis事務
redis也有事務,就是主redis要提交以后,才能從從機上查到redis,redis事務平時用的極少
9.Redis持久化
什么是Redis持久化
什么是Redis持久化,就是將內存數據保存到硬盤。
Redis 持久化存儲 (AOF 與 RDB 兩種模式)
RDB 默認開啟,redis.conf 中的具體配置參數如下;主要是修改save這里
#dbfilename:持久化數據存儲在本地的文件 dbfilename dump.rdb #dir:持久化數據存儲在本地的路徑,如果是在/redis/redis-3.0.6/src下啟動的redis-cli,則數據會存儲在當前src目錄下 dir ./ ##snapshot觸發的時機,save ##如下為900秒后,至少有一個變更操作,才會snapshot ##對於此值的設置,需要謹慎,評估系統的變更操作密集程度 ##可以通過“save “””來關閉snapshot功能 #save時間,以下分別表示更改了1個key時間隔900s進行持久化存儲;更改了10個key300s進行存儲;更改10000個key60s進行存儲。 save 900 1 save 300 10 save 60 10000 ##當snapshot時出現錯誤無法繼續時,是否阻塞客戶端“變更操作”,“錯誤”可能因為磁盤已滿/磁盤故障/OS級別異常等 stop-writes-on-bgsave-error yes ##是否啟用rdb文件壓縮,默認為“yes”,壓縮往往意味着“額外的cpu消耗”,同時也意味這較小的文件尺寸以及較短的網絡傳輸時間 rdbcompression yes
AOF持久化
AOF 默認關閉,開啟方法,修改配置文件 reds.conf:appendonly yes
##此選項為aof功能的開關,默認為“no”,可以通過“yes”來開啟aof功能 ##只有在“yes”下,aof重寫/文件同步等特性才會生效 appendonly yes ##指定aof文件名稱 appendfilename appendonly.aof ##指定aof操作中文件同步策略,有三個合法值:always everysec no,默認為everysec appendfsync everysec ##在aof-rewrite期間,appendfsync是否暫緩文件同步,"no"表示“不暫緩”,“yes”表示“暫緩”,默認為“no” no-appendfsync-on-rewrite no ##aof文件rewrite觸發的最小文件尺寸(mb,gb),只有大於此aof文件大於此尺寸是才會觸發rewrite,默認“64mb”,建議“512mb” auto-aof-rewrite-min-size 64mb ##相對於“上一次”rewrite,本次rewrite觸發時aof文件應該增長的百分比。 ##每一次rewrite之后,redis都會記錄下此時“新aof”文件的大小(例如A),那么當aof文件增長到A*(1 + p)之后 ##觸發下一次rewrite,每一次aof記錄的添加,都會檢測當前aof文件的尺寸。 auto-aof-rewrite-percentage 100
AOF與RDB區別
RDB是要輸入一定次數時間才會存儲,速度快,但是可能會有漏的,不安全,AOF屬於String的append,每次存儲都會存在本地,不會漏,但是效率慢,安全
10.redis訂閱頻道
redis訂閱頻道的原理與我之前做的極光推送比較類似,原理就是前端有個頻道號和后端的頻道后一一匹配,然后后端把消息發送給極光服務器,告訴極光要發送消息給哪些有訂閱的手機。像極光的話還會把后端傳給他的消息推送到蘋果推送服務器上,再由蘋果服務器將消息推送給用戶。
