個人最近總結了一下redis的知識如下,可能有的東西寫的比較雜,只是爲了自我總結一下。
- redis簡介
-
什麼是redis
Redis的的是完全開源免費的,遵守BSD協議,是一個高性能的鍵值數據庫。是當前最熱門的的的NoSql數據庫之一,也被人們稱爲數據結構服務器。Redis以內存作爲數據存儲介質,所以讀寫數據的效率極高,遠遠超過數據庫。以設置和獲取一個256字節字符串爲例,它的讀取速度可高達110000次/s,寫速度高達81000次/s。
Redis跟memcache不同的是,儲存在Redis中的數據是持久化的,斷電或重啓後,數據也不會丟失。因爲Redis的存儲分爲內存存儲、磁盤存儲和log文件三部分,重啓後,Redis可以從磁盤重新將數據加載到內存中,這些可以通過配置文件對其進行配置,正因爲這樣,Redis才能實現持久化。
Redis支持主從模式,可以配置集羣,這樣更利於支撐起大型的項目,這也是Redis的一大亮點。 -
redis到底有多快
Redis採用的是基於內存的採用的是單進程單線程模型的 KV 數據庫,由C語言編寫,官方提供的數據是可以達到100000+的QPS(每秒內查詢次數)。這個數據不比採用單進程多線程的同樣基於內存的 KV 數據庫 Memcached 差。 -
redis爲什麼這麼快
1、完全基於內存,絕大部分請求是純粹的內存操作,非常快速。數據存在內存中,類似於HashMap,HashMap的優勢就是查找和操作的時間複雜度都是O(1);
2、數據結構簡單,對數據操作也簡單,Redis中的數據結構是專門進行設計的;
3、採用單線程,避免了不必要的上下文切換和競爭條件,也不存在多進程或者多線程導致的切換而消耗 CPU,不用去考慮各種鎖的問題,不存在加鎖釋放鎖操作,沒有因爲可能出現死鎖而導致的性能消耗;
4、使用多路I/O複用模型,非阻塞IO;
5、使用底層模型不同,它們之間底層實現方式以及與客戶端之間通信的應用協議不一樣,Redis直接自己構建了VM 機制 ,因爲一般的系統調用系統函數的話,會浪費一定的時間去移動和請求;
以上幾點都比較好理解,下邊我們針對多路 I/O 複用模型進行簡單的探討:
(1)多路 I/O 複用模型
多路I/O複用模型是利用 select、poll、epoll 可以同時監察多個流的 I/O 事件的能力,在空閒的時候,會把當前線程阻塞掉,當有一個或多個流有 I/O 事件時,就從阻塞態中喚醒,於是程序就會輪詢一遍所有的流(epoll 是隻輪詢那些真正發出了事件的流),並且只依次順序的處理就緒的流,這種做法就避免了大量的無用操作。
這裏“多路”指的是多個網絡連接,“複用”指的是複用同一個線程。採用多路 I/O 複用技術可以讓單個線程高效的處理多個連接請求(儘量減少網絡 IO 的時間消耗),且 Redis 在內存中操作數據的速度非常快,也就是說內存內的操作不會成爲影響Redis性能的瓶頸,主要由以上幾點造就了 Redis 具有很高的吞吐量。 -
redis爲什麼是單線程的
官方FAQ表示,因爲Redis是基於內存的操作,CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機器內存的大小或者網絡帶寬。既然單線程容易實現,而且CPU不會成爲瓶頸,那就順理成章地採用單線程的方案了(畢竟採用多線程會有很多麻煩!),並且正是由於在單線程模式的情況下已經很快了,就沒有必要在使用多線程了!
- 安裝
1、下載對應版本的壓縮包,上傳到對應的linux服務器上,解壓縮
下載地址https://redis.io/
2、解壓tar -zxvf redis-5.0.5.tar.gz
3、redis是由C語言編寫的,它的運行需要C環境,所以編譯前需安裝 gcc
yum install gcc-c++
4、編譯:進入解壓後的 redis-5.0.5 目錄,執行 make 命令(稍慢)
5、安裝:進入 src 目錄後執行 make install(很快)
6、修改redis 的核心配置文件 redis.conf
(1) 註釋掉 bind 127.0.0.1 這一行(解決只能特定網段連接的限制)
(2) 將 protected-mode 屬性改爲 no (關閉保護模式,不然會阻止遠程訪問)
(3) 將 daemonize 屬性改爲 yes (這樣啓動時就在後臺啓動)
(4) 設置密碼(可選,個人建議還是設個密碼)
修改完成後,wq保存並退出(先按Esc,接着輸入 :wq)
7、進入到src目錄下直接輸入redis-server …/etc/redis.conf啓動redis
使用redis-cli可以進入redis客戶端,設置的密碼的話,需要輸入相應的密碼。
8、也可以下載可視化工具連接RedisDesktopManager連接redis
下載地址https://github.com/qishibo/AnotherRedisDesktopManager/releases
- redis基本知識點
redis數據結構:
Redis支持五種數據類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
1、String類型是二進制安全的,意思是redis的String可以包含任何數據。比如jpg圖片或者序列化的對象。string 類型的值最大能存儲 512MB
2、Redis hash 是一個鍵值(key=>value)對集合,Redis hash 是一個 string 類型的 field 和 value 的映射表,hash 特別適合用於存儲對象,每個 hash 可以存儲 232 -1 鍵值對(40多億)
3、List Redis 列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)列表最多可存儲 232 - 1 元素 (4294967295, 每個列表可存儲40多億)。lpush runoob mongodb 、、
4、Redis 的 Set 是 string 類型的無序集合,集合是通過哈希表實現的,所以添加,刪除,查找的複雜度都是 O(1),根據集合內元素的唯一性,第二次插入的元素將被忽略,集合中最大的成員數爲 232 - 1(4294967295, 每個集合可存儲40多億個成員)。
sadd key member
smembers runoob
5、zset(sorted set:有序集合),不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來爲集合中的成員進行從小到大的排序。zset的成員是唯一的,但分數(score)卻可以重複。zadd zset 0 test
阿斯蒂芬打算
1、redisTemplate.opsForValue().setIfAbsent(key, value)
如果鍵不存在則新增,存在則不改變已經有的值。
2、redisTemplate.opsForValue().getAndSet(key, value)
獲取輸出舊值,修改舊值
1、2可以一起使用實現redis的分佈式鎖 - 結合SpringBoot使用redis
4.1. 添加pom依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
4.2 在application.properties中加入redis配置
#-------------redis配置------------
# Redis數據庫索引(默認爲0)
#spring.redis.database=0
# Redis服務器地址
spring.redis.host=xxxxxxxxx
# Redis服務器連接端口
spring.redis.port=6379
# Redis服務器連接密碼(默認爲空)
spring.redis.password=redis
# 連接池最大連接數(使用負值表示沒有限制)
spring.redis.jedis.pool.max-active=8
# 連接池最大阻塞等待時間(使用負值表示沒有限制,s)
spring.redis.jedis.pool.max-wait=-1
# 連接池中的最大空閒連接
spring.redis.jedis.pool.max-idle=8
# 連接池中的最小空閒連接
spring.redis.jedis.pool.min-idle=0
# 連接超時時間(毫秒)
spring.redis.timeout=1000
4.3. 初始化配置類
package com.zyu.springandmybatis.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
@Configuration
public class RedisConfig {
@Bean
@ConditionalOnMissingBean(name = "redisTemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)
{
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(jackson2JsonRedisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
@Bean
@ConditionalOnMissingBean(StringRedisTemplate.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)
{
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
}
4.4 創建一個service測試使用redisTemplate往redis服務器中存數據取數據
package com.zyu.springandmybatis.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.*;
@Service
public class RedisService {
@Autowired
RedisTemplate redisTemplate;
// 測試redis
//存String類型數據
public void setToRedis(){
redisTemplate.opsForValue().set("testString","testString");
String test= (String) redisTemplate.opsForValue().get("testString");
System.out.println(test);
}
//存Hash類型數據
public void setHash(){
Map<String,String> map=new HashMap<>();
map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
map.put("key4","value4");
map.put("key5","value5");
redisTemplate.opsForHash().putAll("map1",map);
Map<String,String> resultMap= redisTemplate.opsForHash().entries("map1");
List<String> reslutMapList=redisTemplate.opsForHash().values("map1");
Set<String>resultMapSet=redisTemplate.opsForHash().keys("map1");
String value=(String)redisTemplate.opsForHash().get("map1","key1");
System.out.println("value:"+value);
System.out.println("resultMapSet:"+resultMapSet);
System.out.println("resultMap:"+resultMap);
System.out.println("resulreslutMapListtMap:"+reslutMapList);
}
//存List類型數據
public void setList(){
List<String> list1=new ArrayList<String>();
list1.add("a1");
list1.add("a2");
list1.add("a3");
List<String> list2=new ArrayList<String>();
list2.add("b1");
list2.add("b2");
list2.add("b3");
redisTemplate.opsForList().leftPush("listkey1",list1);
redisTemplate.opsForList().rightPush("listkey2",list2);
redisTemplate.opsForList().leftPushAll("list",list1);
List<String> resultList1=(List<String>)redisTemplate.opsForList().leftPop("listkey1");
List<String> resultList2=(List<String>)redisTemplate.opsForList().rightPop("listkey2");
System.out.println("resultList1:"+resultList1);
System.out.println("resultList2:"+resultList2);
}
//存set類型數據
public void setSet(){
Set<String> set1=new HashSet<String>();
set1.add("set1");
set1.add("set2");
set1.add("set3");
redisTemplate.opsForSet().add("set1",set1);
Set<String> resultSet =redisTemplate.opsForSet().members("set1");
System.out.println("resultSet:"+resultSet);
}
}
4.5 創建一個controller訪問服務
package com.zyu.springandmybatis.controller;
import com.zyu.springandmybatis.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value = "redis")
public class RedisController {
@Autowired
RedisService redisService;
@RequestMapping(value = "/setString")
public void setToRedis(){
redisService.setToRedis();
}
@RequestMapping(value = "/set")
public void set(){
redisService.setSet();
}
@RequestMapping(value = "/hash")
public void hash(){
redisService.setHash();
}
@RequestMapping(value = "/list")
public void list(){
redisService.setList();
}
}
4.6 也可以使用註解
要先在啓動類中加入@EnableCaching // 開啓緩存註解
1、@Cacheable(cacheNames= “”)能夠達到緩存方法的返回對象的效果。
value 或 cacheNames 屬性做鍵,key 屬性則可以看作爲 value 的子鍵, 一個 value 可以有多個 key 組成不同值存在 Redis 服務器。
2、@CachePut緩存新增的或更新的數據到緩存,其中緩存名稱爲people,數據的key是person的id。
3、@CacheEvict從緩存people中刪除key爲id的數據。
配合redis來做緩存
done