Redis

1 篇文章 0 订阅

一、Redis概述

1.1 、NoSQL(非关系型数据库)分类

1.1.1 键值(Key-Value)

  • 这一类数据库主要会使用到一个哈希表.
  • 这个表中有一个特定的键和一个指针指向特定的数据。
  • Key/value模型 优势在于简单、易部署。
  • 但是如果DBA只对部分值进行查询或更新的时候,Key/value就显得效率低下了。

1.1.2 列存储数据库

这部分数据库通常是用来应对分布式存储的海量数据。
	键仍然存在,但是它们的特点是指 向了多个列。这些列是由列家族来安排的。
	如:Cassandra, HBase, Riak.

1.1.3 文档型数据库

  • 文档型数据库的灵感是来自于Lotus Notes办公软件的,而且它同第一种键值存储相类似 BSON====>JSON {“id”:”21”,name:”xa”,} {“id”:”22”,name:”xa”,age:23} 事务支持不友好
  • collection document
    该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如JSON。文档型数据库可 以看作是键值数据库的升级版,允许之间嵌套键值。而且文档型数据库比键值数据库的查询效率更高。
    如:CouchDB, MongoDb. 国内也有文档型数据库SequoiaDB,已经开源。

1.1.4 图形(Graph)数据库 图片 音频 视频 文件服务器

  • 图形结构的数据库同其他行列以及刚性结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上。
  • NoSQL数据库没有标准的查询语言(SQL),因此进行数据库查询需要制定数据模型。许多NoSQL数据库都有REST式的数据接口或者查询API。
    如:Neo4J, InfoGrid, Infinite Graph.

1.2 Redis 简介

Redis 开源,
      基于内存键值存储=>拥有持久化机制(磁盘)。
	  用于(1)数据库缓存  (2)消息中间件
特点:
	Redis 高性能key/value内存型数据库
	Redis 支持丰富的数据类型如(String,list,set,zset,hash)
	Redis 支持持久化
	Redis 单线程,单进程  效率高  (不支持并发操作)
	
Redis与memcahed对比:
	共同点:
		底层都是使用C语言编写,都是基于key-value 内存存储
    不同点:
    	Memcahed支持的数据类型,比较简单(String,Object)
		Redis支持的数据类型比较丰富(String,List,set,zset,hash)
	
		Memcahed默认一个值的最大存储不能超过1M
		Redis一个值的最大存储1G
	
		Memcahed中存储的数据不能持久化,一旦断电,立即丢失
		Redis中存储的数据可以持久化
		
		Memcahed 多线程,支持并发访问 数据安全 锁
		Redis 单线程,并发时串行执行,将单进程单线程效率发挥到最大

		Memcahced自身不支持集群环境 (使用中间件)
		Redis3.0版本之后自身开始提供集群环境支持

二、Redis的安装

2.1 单节点安装

1 下载redis
2.将下载redis资料包上传到Linux中将压缩包在linux系统中解压
3.解压完,解压目录中执行make即可(需要yum install -y gcc来支持编译)make MALLOC=libc 
4.编译完成后make install PREFIX=/usr/redis安装
5.启动redis服务 ./redis-server /opt/install/redis/bin/redis.conf 启动成功看到如下画面
6.redis的服务的默认端口是6379
7、客户端连接redis服务,使用 ./redis-cli –p 6379 连接redis的服务端
8.关闭服务
[root@localhost bin]# ./redis-cli shutdown

在这里插入图片描述

  • 核心配置修改
    在这里插入图片描述

2.2 集群安装

三、基本指令

3.1 String类型的操作

  • 命令说明
keys */ flushAll
			set 	设置一个key/value 
			get 	根据key获得对应的value 
			
			mset 	一次设置多个key value 
			mget 	一次获得多个key的value 
			getset 	获得原始key的值,同时设置新值 
			strlen 	获得对应key存储value的长度 
			append 	为对应key的value追加内容 
			getrange 	截取value的内容 getrange key 0 7 (不改变原值)
			
			setex 	设置一个key存活的有效期(秒) 
			psetex 	设置一个key存活的有效期(豪秒)
			
			setnx 	存在不做任何操作,不存在添加
			msetnx 	可以同时设置多个key,只有有一个存在都不保存
			
			decr (不存在则创建)	进行数值类型的-1操作 
			Decrby  (不存在则创建)	根据提供的数据进行减法操作 
			Incr (不存在则创建)	进行数值类型的+1操作 
			incrby (不存在则创建)	根据提供的数据进行加法操作 
			Incrbyfloat (保留17位)	根据提供的数据加入浮点数 

3.2 List类型的操作

在这里插入图片描述

  • 命令说明
	lpush 	将某个值加入到一个key列表头部 
	rpush 	将某个值加入到一个key列表末尾 
	
	lpushx 	同lpush,但是必须要保证这个key存在
	rpushx 	同rpush,但是必须要保证这个key存在 
	
	lpop 	返回和移除列表的最左第一个元素 
	rpop 	返回和移除列表的最右第一个元素 
	
	lrange 	获取某一个下标区间内的元素 (0,-1 所有 最左 最上)
	llen 	获取列表元素个数 
	
	lset 	设置某一个指定索引的值(索引必须存在)
	lindex 	获取某一个指定索引位置的元素 
	
	lrem 	删除重复元素 
	ltrim 	保留列表中特定区间内的元素
	linsert 在某一个元素之前,之后插入新元素 
	

3.3 SET类型的操作

在这里插入图片描述

	sadd 		为集合添加元素 
	smembers 	显示集合中所有元素 无序 
	scard 		返回集合中元素的个数 
	spop 		随机返回一个元素 
	srem 		从集合中删除一个元素 
	sismember 	判断一个集合中是否含有这个元素 
	srandmember 随机返回元素
	
	smove 		从一个集合中向另一个集合移动元素 
	 
	sdiff 		去掉第一个集合中其它集合含有的相同元素
	sinter 		求交集 
	sunion 		求和集 

3.4 ZSET类型的操作

在这里插入图片描述

  • 3 4 20 不是下标,是分数
	zadd 	添加一个有序集合元素 
	zcard 	返回集合的元素个数 
	zrange 	返回一个范围内的元素 
	zrangebyscore 	按照分数查找一个范围内的元素 
	zrank 	返回排名
	zrevrank 	倒序排名
	zscore 	显示某一个元素的分数 
	zrem 	移除某一个元素
	zincrby 	给某个特定元素加分

3.5 HASH类型的操作

在这里插入图片描述

	hset 	设置一个key/value对   hset key id 1/
	hget 	获得一个key对应的value 
	hgetall 	获得所有的key/value对 
	hdel 	删除某一个key/value对 
	hexists 	判断一个key是否存在
	hkeys 	获得所有的key 
	hvals 	获得所有的value 
	hmset 	设置多个key/value 
	hmget 	获得多个key的value 
	hsetnx 	设置一个不存在的key的值
	hincrby 	为value进行加法运算
	hincrbyfloat 	为value加入浮点值

四、Redis中的持久化机制

4.1 快照持久化

在这里插入图片描述

  • a) 快照持久化也是redis中的默认开启的持久化方案, 根据redis.conf中的配置,快照将被写入dbfilename指定的文件里面(默认是dump.rdb文件中)

  • b)根据redis.conf中的配置,快照将保存在dir选项指定的路径上
    在这里插入图片描述
    在这里插入图片描述

  • 创建快照的几种方式

 1、客户端使用BGSAVE命令: 来创建一个快照,
	 	当接收到客户端的BGSAVE命令时
	 	redis会调用fork¹来创建一个子进程,然后子进程负责将快照写入磁盘中,
	 	而父进程则继续处理命令请求。

	名词解释 : fork当一个进程创建子进程的时候,底层的操作系统会创建该进程的一个副本,
	在类unix系统中创建子进程的操作会进行优化:在刚开始的时候,
	父子进程共享相同内存,直到父进程对内存进行了写之后,
	对被写入的内存的共享才会结束服务。
	
2、客户端使用SAVE命令;来创建一个快照, 都可以生成快照。即dump.rdb 文件
	接收到SAVE命令的redis服务器,在快照创建完毕之前,将不再响应任何其他的命令.
	注意:创建完毕之前,redis处于阻塞状态,无法对外服务
	
3、当redis通过shutdown指令接收到关闭服务器的请求时,会执行一个save命令,阻塞所有的客户
   端, 不再执行客户端执行发送的任何命令,并且在save命令执行完毕之后关闭服务器
	>shutdown 客户端窗口执行命令。 等价 [root@localhost bin]# ./redis-cli shutdown

4、redis 配置自定义 save 策略
		时间 请求数  执行save

缺点:都会丢数据。 

4.2 AOF 持久化机制

  • 在redis的默认配置中AOF持久化机制 是没有开启的
  • AOF持久化会将被执行的写命令写到AOF的文件末尾,以此来记录数据发生的变化,
  • 因此只要redis从头到尾执行一次AOF文件所包含的所有写命令,
  • 就可以恢复AOF文件的记录的数据集.
  • 开启AOF持久化机制,需要修改redis.conf的配置文件,
	通过修改redis.conf配置中appendonly yes来开启AOF持久化 
	通过appendfilename指定日志文件名字(默认为:appendonly.aof) 存放位置为快照存放位置
	通过appendfsync指定日志记录频率
  • AOF 日志记录频率的选项
	选项 	同步频率 
	always 		每个redis写命令都要同步写入硬盘,严重降低redis速度 
	everysec 	每秒执行一次同步显式的将多个写命令同步到磁盘 
	no 	由操作系统决定何时同步 
	

  • 为了兼顾数据安全和写入性能,用户可以考虑使用everysec选项,让redis每秒一次的频率对AOF文件进行同步;redis每秒同步一次AOF文件时性能和不使用任何持久化特性时的性能相差无几,而通过每秒同步一次AOF文件,redis可以保证,即使系统崩溃,用户最多丢失一秒之内产生的数据(推荐使用这种方式)

4.3 AOF文件的重写

  • AOF 的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用incr test命令100次,文件中必须保存全部的100条命令,其实有99条都是多余的。因为要恢复数据库的状态其实文件中保存一条set test 100就够了。为了压缩aof的持久化文件Redis提供了AOF重写机制

  • 重写 aof 文件的两种方式

	执行BGREWRITEAOF命令
	配置redis.conf中的auto-aof-rewrite-percentage选项

4.3.1 BgReWriteAOF命令

  • 收到此命令redis将使用与快照类似的方式将内存中的数据 以命令的方式保存到临时文件中,最后替换原来的文件。
	具体过程如下:
	1、redis调用fork ,现在有父子两个进程子进程根据内存中的数据进性类似快照的操作。.
	2、子进程往临时文件中,写入重建数据库状态的命令。
	3、父进程继续处理client请求,除了把写命令写入到原来的aof文件中。同时把收到的写命令缓存起来。这样就能保证如果子进程重写失败的话并不会出问题。
	4、当子进程把快照内容写入已命令方式写到临时文件中后,子进程发信号通知父进程。然后父进程把缓存的写命令也写入到临时文件。
	 5、父进程可以使用临时文件替换老的aof文件,并重命名,后面收到的写命令也开始往新的aof文件中追加。

  • 注意 : 重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,替换原有的文件这点和快照有点类似。(AOF重写过程完成后会删除旧的AOF文件,删除一个体积达几十GB大的旧的AOF文件可能会导致系统随时挂起 )

4.3.2配置redis.conf中的auto-aof-rewrite-percentage选项

  • AOF重写也可以使用auto-aof-rewrite-percentage 100 和auto-aof-rewrite-min-size 64mb来自动执行BGREWRITEAOF.
  • 说明: 如果设置auto-aof-rewrite-percentage值为100和auto-aof-rewrite-min-size 64mb,并且启用的AOF持久化时,那么当AOF文件体积大于64M,并且AOF文件的体积比上一次重写之后体积大了至少一倍(100%)时,会自动触发,如果重写过于频繁,用户可以考虑将auto-aof-rewrite-percentage设置为更大

4.4 两种持久化方案的总结

  • AOF持久化既可以将丢失的数据的时间降低到1秒(甚至不丢失任何数据)
  • 两种持久化方案既可以同时使用,又可以单独使用,在某种情况下也可以都不使用,具体使用那种持久化方案取决于用户的数据和应用决定
  • 无论使用AOF还是快照机制持久化,将数据持久化到硬盘都是有必要的,除了持久化外,用户还应该对持久化的文件进行备份(最好备份在多个不同地方)
  • 注意 :
    这个问题实际上并没有这么简单,因为redis会不断将执行的写命令记录到AOF文件中,所以随着redis运行,AOF文件的体积会不断增大,在极端情况下甚至会用完整个硬盘,
  • 还有redis重启重新执行AOF文件记录的所有写命令的来还原数据集,AOF文件体积非常大,会导致redis执行恢复时间过长

五、Redis集群的搭建

  • Redis在3.0后开始支持Cluster(模式)模式,目前redis的集群支持节点的自动发现,
    支持slave-master选举和容错,支持在线分片(sharding)等特性
  • Redis的集群架构图
    在这里插入图片描述
  • .Redis的集群细节
  • 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议,优化传输速度和带宽.
  • 节点的fail是通过集群中超过半数的节点检测失效时才生效.(一般基数节点)
  • 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
  • redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value

  • redis容错架构图
    在这里插入图片描述
  • 如果半数以上master节点与master节点通信超过(cluster-node-timeout),认为当前master节点挂掉
  • 当集群不可用时,所有对集群的操作做都不可用,收到((error) CLUSTERDOWN The cluster is down)错误
  • 注意:
 如果集群任意master挂掉,且当前master没有slave.集群进入fail状态,
 	也可以理解成进群的slot映射[0-16383]不完成时进入fail状态.
 如果进群超过半数以上master挂掉,无论是否有slave集群进入fail状态
 
  • 判断一个是集群中的节点是否可用,是集群中的所用主节点选举过程,如果半数以上的节点认为当前节点挂掉,那么当前节点就是挂掉了,所以搭建redis集群时建议节点数最好为奇数.

  • 搭建集群至少需要三个主节点,三个从节点,至少需要6个节点

六、分布式锁

  • 定义:保证同一时间只能有一个客户端对共享资源进行操作
  • 要求
	1、不会发生死锁。 即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续
其他客户端能加锁
	2、具有容错性。 只要大部分的Redis节点正常运行,客户端就可以加锁和解锁
	3、解铃还须系铃人。 加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了

分布式锁实现大致分为三种, RedisZookeeper、数据库

6.1 分布式锁场景一

  • 向 Redis 中添加一个 lockKey 锁标志位, 如果添加成功则能够继续向下执行扣减优惠券数量操作, 最后再释放此标志位
    在这里插入图片描述

6.2 分布式锁场景二加expire

  • 场景一基于 setnx 命令实现分布式锁的可能发生死锁
  • 线程1在成功获取锁后, 执行流程时异常结束, 没有执行释放锁操作, 这样就会 产生死锁
  • 解决死锁(如果方法执行异常导致的线程被回收, 那么可以将解锁操作放到 finally 块中)
  • 如果获得锁的线程在执行中, 服务被强制停止或服务器宕机, 锁依然不会得到释放.
Redis 的 锁标志位加上过期时间 就能很好的防止死锁问题

在这里插入图片描述

6.3 场景三

  • 处理如果在客户端加锁成功后, 还没有设置过期时间时宕机
  • 对锁标志位 & 添加过期时间命令 保证一个原子性, 要么一起成功, 要么一起失败
  • 从 Redis 2.6.12 版本起, 提供了可选的 字符串 set 复合命令
	SET key value [expiration EX seconds|PX milliseconds] [NX|XX]
可选参数如下:
	EX: 设置超时时间,单位是秒
	PX: 设置超时时间,单位是毫秒
	NX: IF NOT EXIST 的缩写,只有 KEY不存在的前提下 才会设置值
	XX: IF EXIST 的缩写,只有在 KEY存在的前提下 才会设置值

在这里插入图片描述

6.4 场景四 verify value

  • 创建辨别客户端身份的唯一值了, 将加锁及解锁归一化,
  • 代码相当于我们添加锁标志位时, 同时为每个客户端设置了 uuid 作为锁标志位的 val, 解锁时需要判断锁的 val 是否和自己客户端的相同, 辨别成功才会释放锁在这里插入图片描述
使用setnx、getset、expire、del这4个redis命令实现

	setnx 是『SET if Not eXists』(如果不存在,则 SET)的简写。 命令格式:SETNX key value;使用:只在键 key 不存在的情况下,将键 key 的值设置为 value 。若键 key 已经存在, 则 SETNX 命令不做任何动作。返回值:命令在设置成功时返回 1 ,设置失败时返回 0 。
	
	getset 命令格式:GETSET key value,将键 key 的值设为 value ,并返回键 key 在被设置之前的旧的value。返回值:如果键 key 没有旧值, 也即是说, 键 key 在被设置之前并不存在, 那么命令返回 nil 。当键 key 存在但不是字符串类型时,命令返回一个错误。
	
	expire 命令格式:EXPIRE key seconds,使用:为给定 key 设置生存时间,当 key 过期时(生存时间为 0 ),它会被自动删除。返回值:设置成功返回 1 。 当 key 不存在或者不能为 key 设置生存时间时(比如在低于 

   del 命令格式:DEL key [key …],使用:删除给定的一个或多个 key ,不存在的 key 会被忽略。返回值:被删除 key 的数量。

在这里插入图片描述

	A尝试去获取锁lockkey,通过setnx(lockkey,currenttime+timeout)命令,对lockkey进行setnx,将value值设置为当前时间+锁超时时间;
如果返回值为1,说明redis服务器中还没有lockkey,也就是没有其他用户拥有这个锁,A就能获取锁成功;
在进行相关业务执行之前,先执行expire(lockkey),对lockkey设置有效期,防止死锁。因为如果不设置有效期的话,lockkey将一直存在于redis中,其他用户尝试获取锁时,执行到setnx(lockkey,currenttime+timeout)时,将不能成功获取到该锁;
执行相关业务;
释放锁,A完成相关业务之后,要释放拥有的锁,也就是删除redis中该锁的内容,del(lockkey),接下来的用户才能进行重新设置锁新值。

七、Redis整合SpringBoot

7.1、 依赖

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis</artifactId>
      <version>1.5.7.RELEASE</version>
    </dependency>

7.2、key–value


 @Autowired
 StringRedisTemplate stringRedisTemplate;
 
  stringRedisTemplate.opsForValue().set("name","zhangsan");
  Object name = stringRedisTemplate.opsForValue().get("name");
  System.out.println(name);  //zhangsan

   //存活100秒 :ttl id 指令查看剩余存活秒速
  stringRedisTemplate.opsForValue().set("id","1",100, TimeUnit.SECONDS);

7.3、批量删除

//
List<String> strings = Arrays.asList("id", "name");
stringRedisTemplate.delete(strings);

7.4、 为key设置超时时间

//为已存在的key,设置超时时间
stringRedisTemplate.expire("name",100, TimeUnit.SECONDS);
stringRedisTemplate.getexpire("name");//100

7.5、list

Long aLong = stringRedisTemplate.opsForList().leftPush("names", "xiaohei");
stringRedisTemplate.opsForList().leftPushAll("names","xiaohei","xiaohei1","xiaohei2","xiaohei3","xiaohei4","xiaohei5");
List<String> names = stringRedisTemplate.opsForList().range("names", 0, -1);
for (String name : names) {
    System.out.println(name);
}

7.6、Set 集合 存取

      Long add = stringRedisTemplate.opsForSet().add("s1", "s2", "s3");
        Set<String> s1 = stringRedisTemplate.opsForSet().members("s1");

        for (String s : s1) {      
            System.out.println(s);
        }
        DataType s11 = stringRedisTemplate.type("s1");

        if (s11.equals(DataType.SET)){
            System.out.println("this is set");
        }

八、Redis做缓存在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值