Redis是内存数据库,主要存储方式是key-value模型。

在说Redis之前我们先看一下key-values数据存储的ranking。

redis之父 redis是nio_redis


截止到发文前最新出炉的排名状况,Redis在key-value数据存储仓库,依然高居头名。

这里还要提及一个常识性的知识,数据从硬盘中检索的速度是ms(毫秒)级,数据从内存中检索的速度是ns(纳秒)级,二者效率相差10万倍左右。那么你会说了我们可不可以把业务的所有数据放到内存啊?不是开玩笑的真有公司这么干了,是SPA公司开发的HANA数据库,这个数据库采用内存存储数据,但是价格十分的昂贵,都是钱啊!!!说到这里我们又会考虑能不能考虑一种折中的方案,我们将少量的数据放到内存,大部分的数据还依然放到硬盘中这样是否可行?so,缓存就应运而生了。

早期很有名的缓存技术是memcached,也一直处在不可撼动的地位。直到redis从2009年发布第一个稳定版开始,慢慢的撼动了memcache的地位,直到今天渐渐被取代。

一、redis和Memcached对比
redis的value有类型的概念。redis的value可以存五种数据类型,String字符串类型、hashHash散列类型、List集合类型、Set集合类型、Sorted Set有序集合。Memcached没有数据类型的概念。说到这里首先会想到json格式,比如我们往redis和Memcached中分别存储放一个 key=“test” value为List集合的对象。而客户端只需要list集合中某一个值,Memcached就需要把list整个集合对象返回给客户端,然后客户端将这个对象解析后再取出List集合中的某一个值。大大浪费了网路传输上的带宽。redis数据存在类型的概念,不需要将整个value的值传输给客户端client,而是redis server层就帮忙做了解析后,在传给客户端,我们称之为计算向数据移动。

二、Redis的 IO模型——epoll模型多路复用NIO

redis之父 redis是nio_redis_02


这里引入两个概念,mmap(共享内存)和零拷贝(sendfile),这些都是操作系统内核帮我们做的事情。

第一,mmap是用户态和内核态的共享内存空间。例如上图,在用户态的时候我们有个文件描述符epfd,当我们调用内核态将epfd传递进去后,通过mmap,内核就和用户态使用同个epfd来监听数据。
第二,零拷贝的概念是当数据到达内核后,用户态要来拉取数据进行操作,不用在用户态独立在开辟个空间存这些数据,内核态和用户态共享这块内存空间。对应内核态提供的接口是sendfile.

epoll是这样做的,用户态把fd传递给内核态,内核态提供mmap共享内存空间,知道用户态需要监听哪些数据。mmap里面主要有两大块,红黑树结构来存fd,链表来存内核监听到哪些fd有数据,用户态一直监听mmap空间中链表,只要有数据把链表中的fd拿出来,再调用内核的read方法读取数据。这里使用零拷贝技术,所以不用把内核空间拷贝到用户空间,性能得到提高。

三、Value五大数据数据类型(开发中常用)

备注:redis存储是字节流 为了保证二进制安全;正向索引和逆向索引 例如[1,2,3] 从左开始索引为 0,1,2为正向索引,从右开始索引为-3,-2,-1为逆向索引。

1.String

String类型下又可以细分为三种类型。

①字符串类型(String)

redis命令:

set key value;

get key value;

append key value;(追加一个字符串)

setrange key offset value;(从偏移量 offset 开始做覆盖)

getrange key start end;(符串的截取范围由 start 和 end 两个偏移量决定)

strlen;查看字符长度

②数值(Integer)

incr key 给给定的key值+1

这种方式是一种全局的计数器,那么10笔并发请求,9笔会被拒绝,注意9笔只能被拒绝,因为通过计数器的方式,你无法判断第一笔请求什么时候会被处理结束,所以你无法处理超时以及获取上一笔请求结果。这个方便是方便,适用场景抢购,秒杀,规避了并发下对数据库的事务操作,完全由redis内存操作代替。

③位图(bitMap)

bitmap,位图,即是使用bit。 redis字符串是一个字节序列。

1 Byte = 8 bit

redis之父 redis是nio_数据_03


备注:对二进制位做操作;这里还要插入一个基本知识是

Setbit key offset;(对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit))

bitcount key [start] [end];

例如:一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 start 或 end 参数,可以让计数只在特定的位上进行。start 和 end 参数的设置,都可以使用负数值:比如 -1 表示最后一个位,而 -2 表示倒数第二个位,start、end 是指bit组的字节的下标数,二者皆包含。

如上 K1 【01000001 01000000 00000000 00100001】,对应【0,1,2,3】

bitcount K1 1 2 : 统计下标1、2字节组中bit=1的个数,即01000000 00000000

–》bitcount K1 1 2   --》1

bitpos

2.List

3.hash

4.Set

5.sorted Set