1.Redis简介
Redis 是一种基于键值对(key-value)的NoSQL数据库,与很多键值对数据库不同的是,Redis中的值可以是有string(字符串)、hash(哈希)、list(列表)、set(集合)、zset(有序集合)等多种数据结构和算法组成,因此Redis可以满足很多的应用场景,而且因为Redis会将所有数据都存放在内存中,所以它的读写性能非常惊人。不仅如此,Redis还可以将内存中的数据利用快照和日志的形式保存在硬盘上,这样在发生类似断电或者机器故障的时候,内存中的数据也不会丢失。所以,熟练使用Redis已经成为开发人员的一个必备技能。
2.Redis特性
2.1速度快
- Redis将所有数据都存放到内存中。
- Redis是用C语言实现,执行速度相对较快。
- Redis使用单线程架构,预防了多线程可能产生的竞争问题。
2.2基于键值对的数据结构服务器
Redis中主要提供了5种数据结构:字符串、哈希、列表、集合、有序集合,这样不仅能便于在许多应用场景的开发,同时也能够提高开发效率。
2.3丰富的功能
- 提供了键过期功能,可以用来实现缓存。
- 提供了发布订阅功能,可以用来实现消息系统。
- 提供了流水线(Pipeline)功能,减少网络开销。
- 支持Lua脚本功能,可以利用Lua创造出新的Redis命令。
2.4持久化
Redis提供了两种持久化方式:RDB和AOF,可以将内存的数据保存到内存中。
2.5主从复制
Redis提供了复制功能,实现了多个相同数据的Redis副本。
2.6高可用和分布式
Redis Sentinel能够保证Redis节点的故障发现和故障自动转移。Redis还提供了集群Redis Cluster,提供了高可用、读写和容量的扩展性。
3.Redis全局命令
- keys *:查看所有键。
- dbsize:键总数。
dbsize命令在计算键总数时,直接获取Redis内置的键总数变量,时间复杂度是O(1)。而keys命令会遍历所有键,时间复杂度是O(n)。
- exists key:检查键是否存在,如果存在则返回1,不存在则返回0
- del key:删除成功,返回删除键的个数,删除一个不存在的键,就会返回0
- expire key seconds:对键添加过期时间,当超过过期时间后,会自动删除键。ttl命令会返回键的剩余过期时间,它有三种返回值:大于等于0的整数表示键剩余的过期时间,-1表示键没设置过期时间,-2表示键不存在。
- type key:键的数据结构类型。
4.单线程架构
Redis使用了单线程架构和I/O多路复用模型来实现高性能的内存数据库服务。客户端发送一条命令到服务端不会被立刻执行,所有命令都会进入一个队列中,然后逐个被执行。那么为什么单线程还会那么快呢?首先纯内存访问,其次Redis使用epoll作为I/O多路复用技术的实现,最后是单线程避免了线程切换和竞态产生的消耗。但是单线程也会有一个问题:对于每个命令的执行时间是有要求的,如果某个命令执行时间过长,会造成其他命令的阻塞,所以Redis是面向快速执行场景的数据库。
5.字符串
字符串类型是Redis最基础的数据结构。它能表达3种值的类型,分别是字符串,整数,浮点数。
5.1常用命令
操作 | 描述 |
---|---|
set key value | 设置键值对,返回结果为OK代表设置成功。 |
setnx key value | 如果键存在,那么setnx失败,返回结果为0,根据setnx的特性只有一个客户端能设置成功,它可以作为分布式锁的一种实现方案。 |
setex key seconds value | 将值 value 关联到 key ,并将 key 的生存时间设为 seconds (以秒为单位)。如果 key 已经存在, setex 命令将覆写旧值。 setex 是一个原子性(atomic)操作,关联值和设置生存时间两个动作会在同一时间内完成,该命令在 Redis 用作缓存时,非常实用。 |
incr key | 将指定key的内容加1 |
decr key | 将指定key的内容减1 |
incrby key increment | 将指定key的内容增加给定的值,例如:incrby key 100 将key对用的数字型value增加100 |
decrby key decrement | 将指定key的内容减少给定的值 |
incrbyfloat key increment | 将指定key的内容减少给定的浮点值 |
append key value | 将指定字符串内容添加到指定key对应的value之后 |
strlen key | 获取字符串value的长度 |
setrange key offset value | 将指定字符串内容覆盖,指定key对应的value,从指定位置开始覆盖。![]() |
getrange key start end | 对字符串value做范围截取。![]() |
5.2内部数据结构
在Redis内部,String类型value内部以int,sds作为存储结构。int用来存放整型数据,sds存放字节/字符串和浮点类型数据。
typedef struct sdshdr{ unsigned int len; unsigned int free; char buf[];}
buf数组存储了字符串的内容,结构如图所示
此时sds的bufSize为8,len字段值为5,而free为2。buf中free区域的引入提升了sds对于字符串处理的性能,减少了处理过程中可能遇到的内存申请和释放的次数。
5.3典型使用场景
- 缓存功能,如图所示是比较典型的缓存使用场景,其中Redis作为缓存层,Mysql作为存储层,绝大部分请求的数据都是从Redis中获取。
伪代码如下所示
UserInfo getUserInfo(String key){ value = redis.get(key); UserInfo userInfo; if(value!=null){ userInfo = deserialize(value); }else{ userInfo = db.get(key); if(userInfo !=null){ redis.setex(key,3600,serialize(userInfo)); } } return userInfo;}
- 计数功能,例如使用Redis作为视频播放数计数的基础组件,用户每播放一次视频,相应的视频播放数就会自增1:redis.incr(key)。
- 共享session,可以使用Redis将用户的Session进行集中管理,每次用户更新或者查询登陆信息都直接从Redis中集中获取。
6.总结
本篇文章我们简单介绍了Redis的特性和全局命令,并对其中一种String数据结构进行了分析,下篇文章我们会对其他几种数据结构进行详细分析。
参考资料
《Redis开发与运维》《深入分布式缓存:从原理到实战》