认识Redis:
Redis是一种基于键值对(key-value)的NoSQL数据库,不像memcache只支持单一数据结构
Redis提供了多种数据结构: string(字符串)、hash(哈希)、List(列表)、set(集合)、zset(有序集合)
除此之外,在string的基础上扩展了 Bitmaps(位图)、HyperLogLog、GEO(地理信息定位)
Redis提供了RDB和AOF机制进行数据持久化,在断电或者机器故障的情况下,保证数据"不丢失"
除此之外,还提供了发布订阅、Lua脚本、键过期等附加功能
更重要的一点就是,Redis特别快(官方给的数字是读写每秒10w)
总之,Redis强大到就像一把瑞士军刀,很多场景都可以使用Redis
Redis快的原因:
> redis是基于内存的,内存的读写速度非常快
> Redis是C语言开发的,一版来说C语言实现的程序 "距离" 操作系统更近,执行速度更快
> redis是单线程的,省去了很多上下文切换线程和抢占锁的时间
> redis使用多路复用技术,可以处理并发的连接。非阻塞IO 内部实现采用epoll,采用了epoll+自己实现的简单的事件框架。
epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性,绝不在io上浪费一点时间
客户端通信协议:
* 客户端和服务端的通信是基于TCP
* Redis制定了RESP(Redis序列化协议),这种协议简单高效,即能被机器识别,又容易被人类识别
* 例如:
客户端发送 set hello redis ,按照RESP的标准,客户端就会把它封装成如下格式
*3\r\n$3\r\nSET\r\n$5\r\nhello\r\n$5\r\nworld\r\n
\r\n表示回车换行的意思,我们手动把它换行一下:
*3
$3
SET
$5
hello
$5
world
这就是客户端执行的 set hello redis 命令
服务端回复 : +OK
* Redis返回结果其实是有多种类型的:
状态回复:在RESP中,第一个字节为 "+"
错误回复:在RESP中,第一个字节为 "-"
整数回复:在RESP中,第一个字节为 ":"
字符串回复:在RESP中,第一个字节为 "$"
多个字符串回复:在RESP中,第一个字节为 "*"
注: JAVA客户端Jedis就是基于RESP协议(在TCP协议的基础上构建的)
为什么Redis使用单线程
1.不需要各种锁的性能消耗
Redis的数据结构并不全是简单的Key-Value,还有list,hash等复杂的结构,这些结构有可能会进行很细粒度的操作,
比如在很长的列表后面添加一个元素,在hash当中添加或者删除一个对象。
这些操作可能就需要加非常多的锁,导致的结果是同步开销大大增加。
总之,在单线程的情况下,就不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗。
2.减少CPU消耗
采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU。
Redis单线程的优劣势
优势:
代码更清晰,处理逻辑更简单
不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗
不存在多进程或者多线程导致的切换而消耗CPU
劣势:
无法发挥多核CPU性能(因为是单线程,所以一个核就可以满足了,如果服务器是多核CPU,显然不能发挥多核的优势)
弥补方式:可以通过在单机开多个Redis实例来完善(每个核对应一个Redis实例,具体要做成集群还是多个单实例,根据自己公司业务决定)