?
一,什么是Redis
Redis是一个使用C语言开发的一个开源的高性能数据库,以键值对的形式存储,Redis将数据放到内存中, 读取速度快,所以被广泛应用。
二,Redis的下载和安装
下载地址: https://redis.io/download/
2.1在虚拟机中安装C语言环境
由于Redis是C语言开发的,安装Redis需要C语言环境。
yum install gcc-c++
2.2 安装
将安装包拷到/usr/upload目录下解压
tar -zxvf redis-3.0.0.tar.gz
进入到解压后的目录进行编译
cd /usr/upload/redis-3.0.0
make
安装到指定目录
make install PREFIX=/usr/local/redis
2.3 启动
- 前端启动
直接运行bin/redis-server将以前端模式启动。
cd /usr/local/redis/bin
./redis-server
缺点: 命令窗口关闭会导致redis-server进程结束(前端启动的关闭方法:1,ctrl + c 2, 关闭命令窗口) 2. 后端启动
1,拷贝配置文件
cp /usr/upload/redis-3.0.0/redis.conf /usr/local/redis/bin
2,修改配置文件
vim /usr/local/redis/bin/redis.conf
daemonize yes
3,启动
./redis-server redis.conf
4,关闭
./redis-cli shutdown
5,链接
./redis-cli
三,Redis的基本命令
keys *:查看所有key
expire和ttl:设置和查看key的失效时间(秒)
incr和decr:自增和自减
exists:判断key值是否存在
select (0~15): 切换数据库,一个redis实例最多可提供16个数据库,下标从**0**到**15**,
客户端默认连接第0号数据库,也可以通过select选择连接哪个数据库,redis不支持修改数据库的名称,
只能通过select 0、select 1...选择数据库。
FLUSHALL --清空所有数据库的所有数据
FLUSHDB --清空当前所在数据库的数据
四,Redis的五种数据类型
string ----> key value
赋值:set key value
取值:get key
删除:del key
自增自减:incr key decr key
hash ----> key (key value) (key value)…
赋值:HSET key key value
取值:HGET key field
删除:HDEL key field
list ----> key value value…
元素有顺序,可重复
赋值:lpush/rpush key value value...
lpush 在数据的左边添加新数据
rpush 在数据的右边添加新数据
取值:lrange k 0 -1
删除:lrem key num value num指删除几个
set ----> key value value …
元素无顺序,不能重复
赋值:sadd key value value...
取值: smembers key
删除: srem key value
zset ----> zadd key score1 value1 (score2 value2)…
元素有顺序,不能重复
赋值: zadd key score1 value1 (score2 value2)...
取值: zrange key 0 -1 withscores
删除: zrem key num value
127.0.0.1:6379> zadd set1 1 2 3 4 5 6
(integer) 3
127.0.0.1:6379> zrange zset1 0 -1
(empty list or set)
127.0.0.1:6379> zrange zset1 0 -1 withscores
(empty list or set)
127.0.0.1:6379> zadd zset2 2 a 3 b 4 c
(integer) 3
127.0.0.1:6379> zrange zset2 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> zrange zset2 0 -1 withscores
1) "a"
2) "2"
3) "b"
4) "3"
5) "c"
6) "4"
五,Redis的持久化
Redis的高性能是由于其将所有数据都存储在了内存中,而内存在断电后会丢失所有数据,为了使Redis在重启后仍能够保证数据不丢失,需要将数据从内存同步到硬盘中,就是持久化。
RDB持久化
RDB方式是通过快照完成的,当符合一定条件时Redis会自动将内存中的数据发起快照并保存到硬盘中。 RDB是Redis默认使用的持久化方式,在redis.conf配置文件中有以下配置
save 900 1 #900秒内容如果超过1个key被修改,则发起快照保存
save 300 10 #300秒内容如超过10个key被修改,则发起快照保存
save 60 10000 #表示60秒内如果超过10000个key被修改,则发起快照保存
优点:不影响性能
缺点:不能保证数据的完整性
AOF持久化
AOF持久化,是将Redis执行的命令记录到日志文件中,当启动Redis时会从持久化的日志文件中恢复数据。
redis.conf开启AOF
appendonly yes
AOF持久化策略
# appendfsync always
appendfsync everysec
# appendfsync no
优点: 可以保证数据的完整性 缺点: 会影响性能,AOF文件会比较大,
两种持久化方案的对比
AOF文件更新频率要比RDB高,且AOF要比RDB恢复数据慢
AOF会比RDB更安全,但是文件会更大
RDB的性能要比AOF好
如果RDB和AOF都开启了,则优先加载AOF.
六,主从复制
持久化保证了即使redis服务重启也会丢失数据,因为redis服务重启后会将硬盘上持久化的数据恢复到内存中,但是当redis服务器的硬盘损坏了可能会导致数据丢失,如果通过redis的主从复制机制就可以避免这种单点故障。
主从配置
主redis无需配置
修改从redis的redis.conf配置文件,添加主的IP和端口
slaveof <masterip> <masterport>
主从复制过程
复制过程说明:
1、 slave 服务启动,slave 会建立和master 的连接,发送sync 命令。
2、master启动一个后台进程将数据库快照保存到RDB文件中
3、master 就发送RDB文件给slave
4、slave 将文件保存到磁盘上,然后加载到内存恢复
5、master把缓存的命令转发给slave
注意:主死了,从只能读
七,Redis集群
1,Redis集群的架构
(1)所有的redis节点彼此互联(PING-PONG机制),节点的fail是
通过集群中超过半数的节点检测失效时才生效.
也就是说集群至少需要三台。
(2)存取数据时连接任一节点都可以,但集群中有一个节点fail整个集群都会fail
原因是:
Reids集群中内置了16384个哈希槽,当需要在集群中防止一个值时,
会先对key使用crc16算法计算,然后对16384进行求余,获得[0~16383]。
这样,每个key都会对应一个哈希槽,redis会根据集群的数量将哈希槽进行大致均等的
分配到各个节点。因此当集群中的任意一个节点挂掉都会导致部分哈希槽丢失,
导致整个集群失效。
2,Redis集群的搭建
由于上述原因,所以Redis集群中至少应该有三个节点,为了保证集群的高可用,每个节点需要有一台备用机,也就是说一个高可用的Redis集群至少需要6台服务器。 在此,通过使用一台虚拟机运行6个Redi实例来模拟分布式环境 2.1 集群搭建环境 使用ruby脚本搭建集群,需要安装ruby。
yum install ruby
yum install rubygems
gem install redis-3.0.0.gem
2.2创建Redis实例 搭建伪分布式,需要6个redis实例放到/usr/local/redis-cluster目录下,并且运行在不同的端口7001-7006。 注意:必须删除dump.rdb和appendonly.aof文件 修改redis.conf配置文件
cluster-enabled yes
2.3启动每个实例 2.4使用ruby脚本搭建集群
./redis-trib.rb create --replicas 1 192.168.25.153:7001 192.168.25.153:7002 192.168.25.153:7003 192.168.25.153:7004 192.168.25.153:7005 192.168.25.153:7006
# 1 表示每个节点有一台备份
[root@localhost src]# ./redis-trib.rb create --replicas 1 192.168.25.153:7001 192.168.25.153:7002 192.168.25.153:7003 192.168.25.153:7004 192.168.25.153:7005 192.168.25.153:7006
>>> Creating cluster
Connecting to node 192.168.25.153:7001: OK
Connecting to node 192.168.25.153:7002: OK
Connecting to node 192.168.25.153:7003: OK
Connecting to node 192.168.25.153:7004: OK
Connecting to node 192.168.25.153:7005: OK
Connecting to node 192.168.25.153:7006: OK
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
192.168.25.153:7001
192.168.25.153:7002
192.168.25.153:7003
Adding replica 192.168.25.153:7004 to 192.168.25.153:7001
Adding replica 192.168.25.153:7005 to 192.168.25.153:7002
Adding replica 192.168.25.153:7006 to 192.168.25.153:7003
M: 2e48ae301e9c32b04a7d4d92e15e98e78de8c1f3 192.168.25.153:7001
slots:0-5460 (5461 slots) master
M: 8cd93a9a943b4ef851af6a03edd699a6061ace01 192.168.25.153:7002
slots:5461-10922 (5462 slots) master
M: 2935007902d83f20b1253d7f43dae32aab9744e6 192.168.25.153:7003
slots:10923-16383 (5461 slots) master
S: 74f9d9706f848471583929fc8bbde3c8e99e211b 192.168.25.153:7004
replicates 2e48ae301e9c32b04a7d4d92e15e98e78de8c1f3
S: 42cc9e25ebb19dda92591364c1df4b3a518b795b 192.168.25.153:7005
replicates 8cd93a9a943b4ef851af6a03edd699a6061ace01
S: 8b1b11d509d29659c2831e7a9f6469c060dfcd39 192.168.25.153:7006
replicates 2935007902d83f20b1253d7f43dae32aab9744e6
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join.....
>>> Performing Cluster Check (using node 192.168.25.153:7001)
M: 2e48ae301e9c32b04a7d4d92e15e98e78de8c1f3 192.168.25.153:7001
slots:0-5460 (5461 slots) master
M: 8cd93a9a943b4ef851af6a03edd699a6061ace01 192.168.25.153:7002
slots:5461-10922 (5462 slots) master
M: 2935007902d83f20b1253d7f43dae32aab9744e6 192.168.25.153:7003
slots:10923-16383 (5461 slots) master
M: 74f9d9706f848471583929fc8bbde3c8e99e211b 192.168.25.153:7004
slots: (0 slots) master
replicates 2e48ae301e9c32b04a7d4d92e15e98e78de8c1f3
M: 42cc9e25ebb19dda92591364c1df4b3a518b795b 192.168.25.153:7005
slots: (0 slots) master
replicates 8cd93a9a943b4ef851af6a03edd699a6061ace01
M: 8b1b11d509d29659c2831e7a9f6469c060dfcd39 192.168.25.153:7006
slots: (0 slots) master
replicates 2935007902d83f20b1253d7f43dae32aab9744e6
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
[root@localhost redis-cluster]#
2.5连接 集群搭建完成后,可以通过连接任意一台redis来连接集群(所有的redis节点彼此互联(PING-PONG机制))
cluster info #打印集群的信息
cluster nodes #列出集群当前已知的所有节点(node),以及这些节点的相关信息
八,Spring Data
1.1.Spring Data 介绍
Spring Data是一个用于简化数据库访问的开源框架。其主要目标是使得对数据的访问变得方便快捷,包含多个子项目:
-
Spring Data JDBC- 对JDBC的Spring Data存储库支持。 -
Spring Data JPA - 对JPA的Spring Data存储库支持。 -
Spring Data MongoDB - 对MongoDB的基于Spring对象文档的存储库支持。 -
Spring Data Redis - 从Spring应用程序轻松配置和访问Redis。 … …
1.2.Spring Data Redis 介绍
Spring Data Redis 是属于 Spring Data 下的一个模块,作用就是简化对于 redis 的操做。
spring-data-redis针对jedis提供了如下功能:
-
提供了一个高度封装的“RedisTemplate”类,里面封装了对于Redis的五种数据结构的各种操作,包括: - redisTemplate.opsForValue():操作字符串
- redisTemplate.opsForHash():操作hash
- redisTemplate.opsForList():操作list
- redisTemplate.opsForSet():操作set
- redisTemplate.opsForZSet():操作zset
-
SpringBoot2.x后RedisTemplate采用是lettuce(基于netty采用异步非阻塞式lO)进行通信,大并发下比jedis效率更高。 -
RedisTemplate模板使用序列化器操作redis数据,预定义的序列化方案有: 1,StringRedisSerializer :key或value是字符串时使用 2,JdkSerializationRedisSerializer :pojo <----> 字节码 , 为乱码 3,GenericJackson2JsonRedisSerializer :pojo <----> json 不乱码
1.3 RedisTemplate使用
引入依赖
<!-- Spring Data Redis的启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
修改配置文件
spring:
redis:
cluster:
nodes:
- 192.168.204.131:7001
- 192.168.204.131:7002
- 192.168.204.131:7003
- 192.168.204.131:7004
- 192.168.204.131:7005
- 192.168.204.131:7006
jedis:
pool:
max-active: 20 #连接池最大连接数
max-idle: 10 #连接池中的最大空闲连接
min-idle: 5 # 连接池中的最小空闲连接
添加配置
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> getRedisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
return template;
}
}
测试
import com.bjpowernode.RedisApp;
import com.bjpowernode.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = {RedisApp.class})
public class RedisTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void testSetStr(){
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
redisTemplate.opsForValue().set("str", "张三丰");
}
@Test
public void testGetStr(){
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
String str = (String) redisTemplate.opsForValue().get("str");
System.out.println(str);
}
@Test
public void testSetPojo(){
User user = new User();
user.setId(1);
user.setName("张三丰");
user.setAge(140);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
redisTemplate.opsForValue().set("user", user);
}
@Test
public void testGetPojo(){
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
User user = (User) redisTemplate.opsForValue().get("user");
System.out.println(user);
}
@Test
public void testSetPojo2(){
User user = new User();
user.setId(1);
user.setName("张三丰");
user.setAge(140);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.opsForValue().set("user2", user);
}
@Test
public void testGetPojo2(){
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
User user2 = (User) redisTemplate.opsForValue().get("user2");
System.out.println(user2);
}
@Test
public void testSetStr2(){
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.opsForValue().set("str2", "张三丰");
}
@Test
public void testGetStr2(){
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
String str2 = (String) redisTemplate.opsForValue().get("str2");
System.out.println(str2);
}
@Test
public void testSetPojo3(){
User user = new User();
user.setId(1);
user.setName("张三丰");
user.setAge(140);
redisTemplate.opsForValue().set("user3", user);
}
@Test
public void testGetPojo3(){
User user3 = (User) redisTemplate.opsForValue().get("user3");
System.out.println(user3);
}
}
设置通用序列化器
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory){
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(factory);
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
return redisTemplate;
}
}
|