Redis本质上一个数据库
与Memcached类似的NoSQL型数据库,但是他的数据可以持久化的保存在磁盘上,解决了服务重启后数据不丢失的问题
他的值可以是string(字符串)、list(列表)、hash(哈希)、set(集合)或者是zset(有序集合)
所有的数据类型都具有push/pop、add/remove、执行服务端的并集、交集、两个sets集中的差别等等操作,这些操作都是具有原子性的
Redis还支持各种不同的排序能力
用C语言开发的一个开源的Key/Value的NoSQL数据库
Redis支持绝大部分主流的开发语言,如:C、Java、C#、PHP、Perl、Python、Lua、Erlang、Ruby等等
redis默认使用6379端口。
Redis能读的速度是110000次/s,写的速度是81000次/s 。
Redis的所有操作都是原子性的,(之所以是原子性的,是因为Redis是单线程的。)
优点:
(1) 速度快,因为数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1)
(2) 支持丰富数据类型,支持string,list,set,sorted set,hash,bitmap,HyperLogLog
(3) 支持持久化,避免服务器重启丢失
(4) 单线程并且提供了原子操作,合理使用可以有效避免线程安全问题
redis数据类型
string
string是最简单的数据类型,一个key对应一个value,string类型是二进制安全的,redis的string可以包含任何数据,如jpg图片或者序列化的对象
hash
hash是一个string类型的field和value的映射表,它的添加、删除操作都是0(1)(平均)。hash特别适合存储对象,相较于把对象的每个字段存成单个string类型,存储在hash类型中占用更少内存,并且方便存取整个对象。
list
lists是链表结构操作中的key可以理解为链表的名称,redis中的list类型其实就是一个每个子元素都是string类型的双向链表,我们可以通过push、pop操作链表的头部或者尾部添加删除元素,这样list即可以作为栈也可以作为队列。
set
它是string类型的无序集合,set通过hash table实现的,不能够有重复的元素,添加,删除和查找的复杂度都是0(1).对集合我们可以取并集,交集,差集。通过这些操作我们可以实现sns中的好友推荐和blog的tag功能。
可以存储2的32次方减1个元素
zset(sorted set)
有序集合,利用这一属性可以在添加或修改元素时指定元素,每次指定后,zset会按照新的值调整顺序,可以理解为有两列的mysql表,一列存value,一列存顺序,操作中的key可以理解为zset的名字。默认按照score进行从小到大排序.不能够有重复的元素
可以存储2的32次方减1个元素
bitmap
位图,位图并不是一个新的数据类型,它其实是使用了字符串类型比如用户签到统计,月活跃用户数统计等等业务场景都适合用位图实现,位图的目的是节省空间,在适当的场景下使用可以很大程度上节省空间,但是使用不当的话反而适得其反。因为bitmap其实就是一个string,因此位图的空间法则和string的空间分配法则一致:当字符串长度小于 1M 时,扩容都是加倍现有的空间,如果超过 1M,扩容时一次只会多扩 1M 的空间。需要注意的是字符串最大长度为 512M。
redis中所有数据都是二进制形式存储的。redis支持一个setbit和getbit操作,它支持在某个key的value上直接对某个二进制位操作,每个二进制位都只有0和1两种状态,正好可以表示用户是否活跃两种状态。
HyperLogLog
Redis 在 2.8.9 版本添加了 HyperLogLog 结构。
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
HyperLogLog 是不精确的去重计数方案,虽然不精确但是也不是非常不精确,标准误差是 0.81%.关于该算法的介绍https://blog.csdn.net/firenet1/article/details/77247649
什么是基数?
比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素个数)为5。 基数估计就是在误差可接受的范围内,快速计算基数。
redis的应用场景
缓存(数据查询、短连接、新闻内容、商品内容等等)。(最多使用)
分布式集群架构中的session分离。分布式会话,session共享
聊天室的在线好友列表。
任务队列。(秒杀、抢购、12306等等)
应用排行榜。使用sorted set能实现排行榜。根据分数排行,可以对分数进行increment
网站访问统计。
数据过期处理(可以精确到毫秒)
取最新n个数据的操作
计数器应用使用incr命令
分布式锁,使用setnx命令封装或使用redisson封装好的
社交网络:点赞、踩、关注/被关注、共同好友等是社交网站的基本功能,可以使用set结构计算交差并集
最新列表
Redis列表结构,LPUSH可以在列表头部插入一个内容ID作为关键字,LTRIM可用来限制列表的数量,这样列表永远为N个ID,无需查询最新的列表,直接根据ID取到对应的内容即可。
可以利用lrange命令,做基于redis的分页功能,性能极佳,用户体验好。
构建消息系统
redis的java客户端
Redisson,Jedis,lettuce等等
Jedis是Redis的Java实现的客户端,其API提供了比较全面的Redis命令的支持;
Redisson实现了分布式和可扩展的Java数据结构,提供很多分布式相关操作服务,例如,分布式锁,分布式集合,可通过Redis支持延迟队列。和Jedis相比,功能较为简单,不支持字符串操作,不支持排序、事务、管道、分区等Redis特性。Redisson的宗旨是促进使用者对Redis的关注分离,从而让使用者能够将精力更集中地放在处理业务逻辑上。
Redisson中的方法则是进行比较高的抽象,每个方法调用可能进行了一个或多个Redis方法调用。
基于Netty实现,采用非阻塞IO,性能高
Lettuce:高级Redis客户端,用于线程安全同步,异步和响应使用,支持集群,Sentinel,管道和编码器。目前springboot默认使用的客户端。
伸缩性:
Jedis:使用阻塞的I/O,且其方法调用都是同步的,程序流需要等到sockets处理完I/O才能执行,不支持异步。Jedis客户端实例不是线程安全的,所以需要通过连接池来使用Jedis。
Jedis仅支持基本的数据类型如:String、Hash、List、Set、Sorted Set。
Redisson:基于Netty框架的事件驱动的通信层,其方法调用是异步的。Redisson的API是线程安全的,所以可以操作单个Redisson连接来完成各种操作。
Redisson不仅提供了一系列的分布式Java常用对象,基本可以与Java的基本数据结构通用,还提供了许多分布式服务,其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service)。
Lettuce:基于Netty框架的事件驱动的通信层,其方法调用是异步的。Lettuce的API是线程安全的,所以可以操作单个Lettuce连接来完成各种操作。
redis快的原因
Redis是纯内存数据库,一般都是简单的存取操作,线程占用的时间很少,时间的花费主要集中在IO上,所以读取速度快。
Redis使用的是非阻塞IO,使用多路I/O复用模型,通过单线程来处理多个链接请求,减少网络IO的耗时。
Redis采用了单线程的模型,保证了每个操作的原子性,也减少了线程的上下文切换和竞争。
在单线程的情况下,就不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。