史上最详细Redis---你想知道的都有

认识redis

redis是一个开源的底层第用ANSI C语言编写的key-value型存储数据库,可用于缓存,事件发布订阅,高速队列等场景

redis支持数据类型

redis支持丰富的数据类型,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。 

redis使用场景

1、缓存数据

最常用,对经常需要查询且变动不是很频繁的数据 常称作热点数据。

2、消息队列

相当于消息订阅系统,比如ActiveMQ、RocketMQ。如果对数据有较高一致性要求时,还是建议使用MQ)

3、计数器

数据统计的需求非常普遍,比如统计点击率、点赞率,收藏数,分享数等,redis具有原子性,可以避免并发问题

4、电商网站信息

大型电商平台初始化页面数据的缓存。比如去哪儿网购买机票的时候首页的价格和你点进去的价格会有差异。

5、热点数据

比如新闻网站实时热点、微博热搜等,需要频繁更新。总数据量比较大的时候直接从数据库查询会影响性能

6、会话缓存
此外,还可以考虑使用 Redis 进行会话缓存。例如,将 web session 存放在 Redis 中。 

7、访问频率
出于减轻服务器的压力或防止恶意的洪水攻击的考虑,需要控制访问频率,例如限制 IP 在一段时间的最大访问量。

单节点服务器通常是这样的

 

加入缓存是这样的

数据库层直接与缓存进行交互,如果缓存中有数据直接返回客户端,如果没有才会从MySql中去查询。从而减小了数据库的压力,提升了效率

Redis为什么会这么快

1、Redis是纯内存操作,需要的时候需要我们手动持久化到硬盘中

2、Redis是单线程,从而避开了多线程中上下文频繁切换的操作。

3、Redis数据结构简单、对数据的操作也比较简单

4、使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求

5、使用多路I/O复用模型,非阻塞I/O

多路I/O复用: I/O 多路复用技术是为了解决进程或线程阻塞到某个 I/O 系统调用而出现的技术,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪,就是这个文件描述符进行读写操作之前),能够通知程序进行相应的读写操作

Redis的性能极高,读的速度是110000次/s,写的速度是81000次/s,支持事务,支持备份,丰富的数据类型。

任何事情都是两面性,Redis也是有缺点的:

1、由于是内存数据库,所以单台机器存储的数据量是有限的,需要开发者提前预估,需要及时删除不需要的数据。

2、当修改Redis的数据之后需要将持久化到硬盘的数据重新加入到内容中,时间比较久,这个时候Redis是无法正常运行的。

对比redis与Memcached

网络模型

  • memcached是多线程,非阻塞IO复用的网络模型,
  • redis使用单线程的IO复用模型,单线程可以将速度优势发挥到最大

 支持数据类型

  • memcached使用key-value形式存储和访问数据,在内存中维护一张巨大的HashTable,使得对数据查询的时间复杂度降低到O(1),保证了对数据的高性能访问。 
  • redis与memcached相比,比仅支持简单的key-value数据类型,但是还提供了list,set,zset,hash等数据结构的存储,补偿了memcached的key-value存储的不足;

内存管理机制 

  • Memcached默认使用Slab Allocation机制管理内存,其主要思想是按照预先规定的大小,将分配的内存分割成特定长度的块以存储相应长度的key-value数据记录,以完全解决内存碎片问题。
  • Memcached使用预分配的内存池的方式,使用slab和大小不同的chunk来管理内存,Item根据大小选择合适的chunk存储,内存池的方式可以省去申请/释放内存的开销,并且能减小内存碎片产生,但这种方式也会带来一定程度上的空间浪费,并且在内存仍然有很大空间时,新的数据也可能会被剔除
  • Redis的内存管理主要通过源码中zmalloc.h和zmalloc.c两个文件来实现的。Redis为了方便内存的管理,在分配一块内存之后,会将这块内存的大小存入内存块的头部 
  • Redis使用现场申请内存的方式来存储数据,并且很少使用free-list等方式来优化内存分配,会在一定程度上存在内存碎片,Redis跟据存储命令参数,会把带过期时间的数据单独存放在一起,并把它们称为临时数据,非临时数据是永远不会被剔除的,即便物理内存不够,导致swap也不会剔除任何非临时数据(但会尝试剔除部分临时数据),这点上Redis更适合作为存储而不是cache。

数据存储及持久化 

  • memcached 不支持内存数据的持久化操作,所以重启之后之前所有的数据就不在了,所有的数据都以in-memory的形式存储。
  • redis支持持久化操作。所以重启之后之前的数据后还在,redis提供了两种不同的持久化方法来讲数据存储到硬盘里面,一种是快照(snapshotting),它可以将存在于某一时刻的所有数据都写入硬盘里面。另一种方法叫只追加文件(append-only file, AOF),它会在执行写命令时,将被执行的写命令复制到硬盘里面

数据一致性问题

  •  Memcached提供了cas命令,可以保证多个并发访问操作同一份数据的一致性问题
  • Redis没有提供cas 命令,并不能保证这点,不过Redis提供了事务的功能,可以保证一串 命令的原子性,中间不会被任何操作打断。

集群管理不同 

  • Redis虽然支持数据的持久化,但是全内存毕竟才是其高性能的本质。作为基于内存的存储系统来说,机器物理内存的大小就是系统能够容纳的最大数据量。如果需要处理的数据量超过了单台机器的物理内存大小,就需要构建分布式集群来扩展存储能力。Redis更偏向于在服务器端构建分布式存储
  • Memcached是全内存的数据缓冲系统 ,Memcached只能采用客户端实现分布式存储,需要将数据拿到客户端来进行类似的修改再set回去。这大大增加了网络IO的次数和数据体积

通过一张图了解下Redis内部内存管理中是如何描述这些不同数据类型的:

preview

 

首先Redis内部使用一个redisObject对象来表示所有的key和value,redisObject最主要的信息如上图所示:

type代表一个value对象具体是何种数据类型,

encoding是不同数据类型在redis内部的存储方式,

比如:type=string代表value存储的是一个普通字符串,那么对应的encoding可以是raw或者是int,如果是int则代表实际redis内部是按数值型类存储和表示这个字符串的,当然前提是这个字符串本身可以用数值表示,比如:"123" "456"这样的字符串

redis数据类型的应用

String(字符串)
string是redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。
string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。
string类型是Redis最基本的数据类型一个redis中字符串value最多可以是512M

Hash(哈希)
Redis hash 是一个键值对集合。
Redis hash是一个string类型的fieldvalue的映射表,hash特别适合用于存储对象。
类似Java里面的Map<String,Object>

Redis的Hash内部存储方式,用户ID为key,value是一个Map,这个Map的key是成员的属性名,value是属性值,这样对数据的修改和存取都可以直接通过其内部Map的Key(Redis里称内部Map的key为field), 也就是通过 key(用户ID) + field(属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题


List(列表)
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)
它的底层实际是个链表

Set(集合)
Redis的Set是string类型的无序集合。它是通过HashTable实现实现的

zset(sorted set:有序集合)
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数
redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。 

redis发布订阅

Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息

Redis 客户端可以订阅任意数量的频道。

下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:

 

当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

 

 使用redis

Redis 键(key) 

 设置键值对:set myKey abc

取出键值对: get mykey 

 查询所有key:keys *

 判断某个key是否存在: exists key名   返回1-yes  返回 0 -no

 移除key: move key db   返回1-yes  返回 0 -no

 得到key的value : get key

  expire key 秒钟:为给定的key设置过期时间
  ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已过期,即已被删除

  type key 查看你的key是什么类型

String类型: 

设置键值对:set key value

将新的字符串value加入到原来key指向的字符串来: append key value

将key指向字符串长度:strlen  key

在原字段上加1: incr key

在原字段上减1decr key

在原字段上加上整数(increment) :incrby key increment

在原字段上减去整数(increment)decrby key increment

mset:同时设置一个或多个 key-value 对。
mget:获取所有(一个或多个)给定 key 的值。
msetnx:同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在,否则不生效 ,或者要么都不存在,直接生成

 设置字符串键值对

链表(List)

链表结构是 Redis 中一个常用的结构,它可以存储多个字符串,而且它是有序的
Redis 链表是双向的

使用链表结构就意味着读性能的丧失
链表只能从单个方向中去遍历所要节点
优势:在于插入和删除的便利
链表的数据节点是分配在不同的内存域的,并不连续,需要经常查找的,使用它性能并不佳,它只能从左到右或者从右到左的查找
和比对。

lpush: 从链表的左边插入
rpush: 从链表的右边插入
lrange :查看链表的节点值
lrange list start end          end=-1代表全部   0 -1 表示全部

 

lpop:删除左边的第一个节点,并且将其返回
rpop:删除右边第一个节点,并且将其返回

lindex,按照索引下标获得元素(从上到下)
lindex: lindex key index,索引从零开始,通过索引获取列表中的元素  

llen :求链表的长度,返回长度

lrem key 删N个value
* 从left往right删除2个值等于v1的元素,返回的值为实际删除的数量  如lrem list 2 3 就是删除两个3
* LREM list3 0 值,表示删除全部给定的值。零个就是全部值
lrem list 个数 节点值 

ltrim key 开始index 结束index,截取指定范围的值后再赋值给key  
ltrim:截取指定索引区间的元素,格式是ltrim list的key 起始索引 结束索引
【start end】 开区间 会把截取的内容保存在原来的list中,默认截取位置从0 开始 

rpoplpush 源列表 目的列表
移除列表的最后一个元素,并将该元素添加到另一个列表并返回
移除源列表的最后一个元素并且将其左插到目的列表中

lset key index value  如:lset list 0 a  将第一个元素修改为a
给index出的索引修改值

linsert key before/after 值1 值2  
在值1 前面/后面 插入值2 

Hash(哈希)

Redis的hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象 

同时设置多个field =>value: hmset key field1 value1 field2 value2

获取对应field的value: hget key field 

Set集合

Redis的Set是string类型的无序集合。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

添加一个 string 元素到 key 对应的 set 集合中

sadd key member  添加成功返回1,若元素已存在返回0,若 key 对应的 set 不存在则返回错误

查看set元素: smembers key

一个set中相同元素只能有一个,集合元素唯一性

 zset(sorted set:有序集合)

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

zset的成员是唯一的,但分数(score)却可以重复

添加元素到集合,元素在集合中存在则更新对应score: zadd key score member

按照score排序:zrangebyscore  (按照字母A-Z排序) 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值