Adblocker
Redis笔记
分享
Redis笔记
NoSQL
NoSQL(Not Only SQL ),意即“不仅仅是SQL”,泛指非关系型的数据库。 NoSQL 不依赖业务逻辑方式存储,而以简单的key-value模式存储。⦁ 不遵循SQL标准。⦁ 不支持ACID。⦁ 远超于SQL的性能。NoSQL适用场景⦁ 对数据高并发的读写⦁ 海量数据的读写⦁ 对数据高可扩展性的Redis是NoSQL类型的数据库
为什么会使用到NoSQL数据库?
技术的分类
1、解决功能性的问题:Java、Jsp、RDBMS、Tomcat、HTML、Linux、JDBC、SVN2、解决扩展性的问题:Struts、Spring、SpringMVC、Hibernate、Mybatis3、解决性能的问题:NoSQL、Java线程、Hadoop、Nginx、MQ、ElasticSearch
发展
随着Web2.0的时代的到来,用户访问量大幅度提升,同时产生了大量的用户数据。加上后来的智能移动设备的普及,所有的互联网平台都面临了巨大的性能挑战。
用户的访问量过大会造成服务器的cup及内存的压力,而服务器去读取数据会造成数据库的IO压力。
解决CPU及内存压力,就有负载均衡Nginx之类的技术。
解决数据库的IO压力,就有了缓存数据库Redis
:::
Redis
Redis是一个开源的key-value存储模式的非关系型数据库。
⦁ 五大数据类型,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。⦁ 这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。⦁ 在此基础上,Redis支持各种不同方式的排序。⦁ 数据都是缓存在内存中。⦁ Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件。⦁ 在此基础上实现了master-slave(主从)同步。
Redis的安装
Redis官方网站 Redis中文官方网站http://redis.iohttp://redis.cn/Redis安装运行(linux系统)Redis安装(Windows环境下Redis安装 不推荐)官方推荐使用linux系统,Windows的版本停止更新了。
Redis相关知识
●端口6379
●默认16个数据库,类似数组下标从0开始,初始默认使用0号库
○使用命令select 来切换数据库。如: select 8
○统一密码管理,所有库同样密码。
●Redis是单线程+多路IO复用技术 (版本更新之后有多线程了,redis6)
○多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用select和poll函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。得到就绪状态后进行真正的操作可以在同一个线程里执行,也可以启动线程执行(比如使用线程池)(基于操作系统的介绍)
○我的理解就是,多个客人找redis黄牛买票,redis黄牛去联系cup车站,有票就卖给redis黄牛,没票cup车站可以做其他的事情,redis黄牛和客人继续等待(描述的不是很准确大概是这样)
常用五大数据类型
redis键(key)操作
- keys 查看当前库所有key(匹配: keys 1)
- exists key 判断某个key是否存在
- type key 查看你的key是什么类型
- del key 删除指定的key数据
- unlink key 根据value选择非阻塞删除(仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作)
- expire key 设置过期时间
- ttl key查看key还有多少时间过期(-2代表已经过期,-1表示永不过期)
- dbsize查看当前数据库的key的数量
- flushdb清空当前库
- flushall通杀全部库
String(Redis字符串)
string是redis最基本的类型,一个key对应一个value
string类型是二进制安全的。意味着redis的string可以包含任何数据,比如jpg图片或者序列化的对象
string类型是redis最基本的数据类型,一个redis中字符串最多可以是512M
常用命令
- set 添加键值对
- get 获取值
- append 来给当前键值对追加一个值,追加到原值的末尾
- stelen 获得值的长度
- setnx 只有在key不存在时 设置key的值
- incr 将key中储存的数字值增1,只能对数字值操作,如果为空,新增值为1
- decr 将key中储存的数字值减1,只能对数字值操作,如果为空,新增值为-1
- incrby/decrby <步长>将key中储存的值增减,自定义步长就是加减多少。
- mset 同时设置一个或多个key-value对
- mget 同时获取一个或多个value
- msetnx 同时设置一个或多个键值对,当且仅当所有给定key都不存在
- getrange <起始位置><结束位置> 获得值的范围,类似Java中的substring,前包,后包
- setrange <起始位置> 用value覆写key所存储的字符串值,从<起始位置>开始(索引从0开始)
- setex <过期时间> 设置键值的用时,设置过期时间,单位秒
- getset 以新换旧,设置了新值同时获得旧值
原子性:
所谓原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何context switch(切换到另一个进程)
1、在单线程中,能够在单条指令中完成的操作都可以认为是“原子操作”(注意这里有引号),因为中断只能发生于指令之间
2、在多线程中,不能被其他进程打断的操作就叫原子操作
Redis单命令的原子性主要得益于Redis的单线程
数据结构
string的数据结构为简单动态字符串,是可以修改的字符串,内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配。
如图中所示,内部为当前字符串实际分配的空间capacity 一般要高于实际字符串长度len,当字符串长度小于1M时,扩容都是加倍现有的空间,如果超过1M,扩容一次只会多扩1M的空间,需要注意的是,字符串最大长度为512M
List(Redis列表)
redis列表是简单的字符串列表,按照插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾部(右边)
他的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间节点的性能会较差。
常用命令
- lpush/rpush 从左边/右边插入一个或多个值
- lrange 按照索引下标获得元素(从左到右)
- lrange 0 -1 看查该key下的所有元素
- lpop/rpop 从左边/右边吐出一个值 。 值在健在,值光健亡
- rpoplpush 从key1列表右边吐出一个值,插到key2列表左边
- lindex 按照索引下标获得元素(从左到右)
- llen 获得列表长度
- linsert before 在value的后面插入插入值
- lrem 从左边删除n个value
- lset 将列表key下标为index的值替换为value
数据结构
list的数据结构为快速链表quickList
首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表
他将所有的元素紧挨着一起存储,分配的是一块连续的内存
当数据量比较多的时候才会改成quicklist
因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里寸的只是int类型的数据,结构上还需要两个额外的指针prev和next
Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。
Sit(Redis集合)
redis set 对外提供的功能于list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时。set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的
redis的set是string类型的无序集合,他底层其实是一个value为null的哈希表,所以添加,删除,查找的复杂度都是O(1)
常用命令
- sadd ... 将一个或多个member元素加入到集合key中,已经存在的menmber元素将被忽略
- smenmbers 取出该集合的所有值
- sismember 判断集合key是否含有该value值,有1,无0
- scard 返回该集合的元素个数
- srem ...删除集合中的某些元素
- spop随机从该集合中吐出一个值
- srandmember 随机从该集合中取出n个值,不会从集合中删除
- smove value把集合从一个值从一个集合移动到另一个集合
- sinter 返回两个集合的交集元素
- sunion 返回两个集合的并集元素
- sdiff 返回两个集合的差集元素,1有2没有
数据结构
Set数据结构是dict字典,字典是用哈希表实现的。
Java中HashSet的内部实现使用的是HashMap,只不过所有的value都指向同一个对象。Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值。
Hash(Redis哈希)
redis hash是一个键值对集合
redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象
类似Java里面的map<String,Object>
常用命令
- hset 给key集合中的field键赋值value
- hget从集合取出value
- hmset ..批量设置hash的值
- hexists查看哈希表key中,给定域是否存在
- hkeys 列出该hash集合的所有field
- hvals列出该hash集合的所有value
- hincrby 为哈希表key中的域field的值加上增量
- hsetnx 将哈希表key中的域field的值设置为value,当且仅当域field不存在
数据结构
Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则hashtable
ZSet(Redis有序集合Sorted Set)
redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合,不同之处是有序集合的每个成员都关联了一个score(评分、权重),这个score被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是score可以是重复的。
因为元素是有序的,所以你也可以很快的根据score或者position来获取一个范围的元素。
访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。
常用命令
- zadd 将一个或多个member元素及其score加入到有序集key中
- zrange[WITHSCORES]返回有序集key中,下标在start和stop之间的元素带WITHSCORES,可以让分数一起和值返回到结果集
- zrangebyscore key minmax [withscore] [limit offset count]返回有序集key中,所有score值介于min和max之间(包括等于min或max)的成员。有序集成员按score值递增(从小到大)次序排列
- zrevrangebyscore key maxmin [withscores] [limit offset count] 同上,改为从大到小
- zincrby 为元素的score加上增量
- zrem 删除该集合下,指定值的元素
- zount 统计该集合,分数区间内的元素个数
- zrank 返回该值在集合中的排名,从0开始
数据结构
zset底层使用了两个数据结构
1、hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。
2、跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。
跳跃表
有序集合在生活中比较常见,例如根据成绩对学生排名,根据得分对玩家排名等。对于有序集合的底层实现,可以用数组、平衡树、链表等。数组不便元素的插入、删除;平衡树或红黑树虽然效率高但结构复杂;链表查询需要遍历所有效率低。
Redis采用的是跳跃表。跳跃表效率堪比红黑树,实现远比红黑树简单。
2、实例
对比有序链表和跳跃表,从链表中查询出51
(1) 有序链表
要查找值为51的元素,需要从第一个元素开始依次查找、比较才能找到。共需要6次比较。
(2) 跳跃表
从第2层开始,1节点比51节点小,向后比较。21节点比51节点小,继续向后比较,后面就是NULL了,所以从21节点向下到第1层在第1层,41节点比51节点小,继续向后,61节点比51节点大,所以从41向下在第0层,51节点为要查找的节点,节点被找到,共查找4次。(我自己的理解就是跳一个进行比较,比目标值小就又跳一个比较,比目标值大就比较前一个值。)从此可以看出跳跃表比有序链表效率要高