redis深入学习笔记

redis的底层使用的是c++

java如何跨语言调用redis?
Clients客户端概念。redis的java客户端有哪些?
Jedis/jredis/rjc/jedisplus/redisclient  redis官方首选Jedis,官方唯一推荐,特点:支持redis cluster(redis3.0后的集群)


Jedis jedis = new Jedis("localhost", 6379);
        jedis.set("zdd", "fly2021");
        System.out.println(jedis.get("zdd"));
redis的技术本质:
客户端调用服务端(网络通讯的概念)java--网络通讯--c++

客户端:
1.transfer传输层   tcp/ip三次握手,安全性,java的实现有socket长链接,http短连接,这里使用的是socket长链接。
2.message protocol 消息协议层   链接建立后
3.api 操作层

QPS百万级redis:

transfer拆解:

消息协议层:暴力获取redis协议
协议如下:
*3  --数组3
$3    --字符3
SET
$3     --字符3
zdd
$7    --字符7
fly2021

官网文档Redis Protocol sepicification 的规范:RESP是我们客户端调用服务端的一个通讯协议。
Resp:
用单行回复,回复的第一个字节将是“+”
错误消息,回复的第一个字节将是“-”
整型数字,回复的第一个字节将是“:”
批量回复,回复的第一个字节将是“$”   字符串
多个批量回复,回复的第一个字节将是“*”  --数组


每一个命令的结束都是换行
+ok表示set成功

Redis原理:
常识:
磁盘:1.寻址 ms级 2带宽:G/M

内存:1.寻址 ns 2.带宽:很大
磁盘比内存寻址慢了10万倍。

I/O buffer:成本问题
磁盘与磁道有扇区,一扇区512Byte。如果一个区域足够小,会造成成本变大。索引成本。

格式化磁盘时,可以使用4k,操作系统无论读多少,都是最小4k

随着文件变大,速度变慢:访问硬盘成为瓶颈即 IO成为瓶颈

因此后面的问题都是为了解决磁盘的瓶颈。

然后到数据库,数据库的数据存储使用data page,每个4k,定义小会影响性能,定义更大没有影响,查找时一个个4k遍历
建立索引:data page 4k

关系型数据库建表时:必须给出schema,即给出表的每一列的类型,字节宽度。存时倾向于行级存储。

数据和索引都是存储在磁盘的。
在内存内准备b+tree

索引和数据都存在磁盘。

内存内只存树干。这样只需要在内存中找到索引,并获取索引命中的数据放入内存,因此获取速度极快。  大大降低IO次数及寻址次数

如果数据表内数据很大,性能会降低?
:如果表有索引,增删改变慢。查询速度1.如果一个或少量查询,依然很快。2.并发大的时候会受磁盘宽带影响速度(每查一批数据放入到内存一次)

极端:SAP公司的HANA内存级别的关系型数据库。(数据在磁盘和内存体积不一样,内存内无需指针)

因此折中方案为:缓存。
基础常识:1.冯诺依曼体系的硬件 2.以太网 tcp/ip的网络

https://db-engines.com/en/   数据库网站。 架构师:技术选型,技术对比

redis.io 

扩展:memcached,redis取代了其。因为mc的value没有类型概念。  
json 可以表示很复杂的数据结构。
世界上3中数据表示:
1.k = a k =1
2.k= [1,2,3] k=[a,x,f]
3.k={x=y} k=[{}, {}]
客户端如果想从缓存kv中取出value中的某一个元素。
memcahce需要返回所有的value到client,server 网卡IO,client端要有实现的代码去解码
redis,类型不是很重要,redisserver对每种类型都有自己的方法。 index(), lpop

根据(计算是向数据移动的):memcache的计算是放在客户端client去解析json的。而redis是直接在redisserver就完成计算的。


安装linux版本redis
...

redis是单进程,单线程,单实例,并发很多的请求,如何变得很快的呢?
多个客户端请求,通过tcp到达linux内核kernel。会有很多的socket。

所有的操作请求都是有顺序的,顺序处理。每连接内的命令顺序
内核与redis之间使用的同步非阻塞多路复用epoll。来遍历连接,谁有数据处理谁。

epoll的数据驱动并不是真正的数据驱动。

epoll插曲:
服务器内核kernel ----连接----客户端。所有连接先到达内核。每个连接存在标识符。服务器通过一个进程通过一个read(read是用户行为,在内核执行)从内核去读每一个标识符fd。因为socket在这个时期是阻塞的blocking。因此多个请求需要计算机开多个线程通过每一个的read去读一个标识符。即BIO。 一个线程的成本 1MB,可调节。1.CPU只有一颗,线程多了,调度成本cpu浪费;2.线程的内存成本。

任何进程都会有他的io标识符。

内核进化后:

内核中的socket可以是非阻塞的。文件标识符是nonblock。一个线程一个read遍历所有的fd,无数据下一个,有数据则处理数据(轮询发生在用户空间)。  同步非阻塞时期。  NIO,如果有1000个fd,代表用户进程轮询调用1000次内核,存在成本问题。

内核发展:

内核内增加一个系统调用select,服务器线程通过select调用内核内的select(用户行为,内核执行),只获取有无数据状态返回给计算机,服务器再通过NIO去遍历读取所有有数据的fd,减少调用内核次数(轮询发生在用户空间)。 多路复用的NIO。   线程/进程的select与read均发生在jvm内,jvm由c++

 多路复用NIO的问题:

       fd数据内核态<-->用户态的互相转换,由于在jvm内属于不同的内存区域,需要fd相关数据传参传递,即互相拷贝。

 如果存在一个共享空间,通过内核的mmap实现。共享空间是jvm的一部分,也是服务器内核的一部分。

共享空间的增删改的操作在内核完成,查询是内核和jvm都可以查

共享空间内:红黑树,链表

用户空间有1000个fd,fd全部写入共享空间的红黑树,就不需要在jvm的私有地址内存放。内核就可以直接从这个空间内看到有多个文件标识符。有数据的都放到链表内,再由read来读取链表,不需要fd数据互相在两个空间拷贝。epoll 非阻塞多路复用NIO

jvm线程通过create epfd调用epoll的mmap创建共享空间,ctl遍历所有的fd数据放入到共享空间,再通过线程的增删改查命令,调用内核的相应的增删改查方法操作共享空间内的fd数据,返回给线程后,线程再调用内核执行read的NIO读取操作,遍历读取共享空间内的fd数据。

多路IO复用技术

另外多路IO复用技术类似于拨开关,多个任务通过拨开关的方式共用一条线程,哪个任务需要了开关就拨到哪个任务,避免了CPU在不同的线程中切换,提高效率。

I/O复用模型
1.select/poll
老李去火车站买票,委托黄牛,然后每隔6小时电话黄牛询问,黄牛三天内买到票,然后老李去火车站交钱领票。
耗费:往返车站2次,路上2小时,黄牛手续费100元,打电话17次
2.epoll
老李去火车站买票,委托黄牛,黄牛买到后即通知老李去领,然后老李去火车站交钱领票。
耗费:往返车站2次,路上2小时,黄牛手续费100元,无需打电话
 

redis的使用

 redis默认16个库,可以通过 -n 库number来设置库,默认为0号库

select 8 表示选择9号库

help @<xxx> 可以查看操作帮助哦

type key 获取value类型

Object encoding key 返回用于存储与键关联的值的内部表示的类型。

 String类型:

String类型分为三种:字符串,数值,bitmap(位图,二进制运算很重要))

字符串类型

set key value nx  分布式锁的set命令,不存在key才能新增

set key value xx 存在key才能修改

mget key1 key2  同时取多个key

apend key1 "a" 追加字符

getRange key1 6 "a"  偏移量截取value, 偏移量使用正反向索引

setrange key1 6 "a" 从第六个字符修改为a

strlen key获取value长度

数值类型

数值计算:incr key 增1  incrby key 2 增2  incrByfloat 加小数 decr 减与加同操作, decrby 自定义减操作

数值计算可应用于抢购秒杀,详情页下规避并发情况对数据库的事务操作

 注意:redis基于二进制安全,只取字节流。redis -cli --raw 如果没有--raw启动使用redis,redis只能识别ASC码超出ASC码就按十六进制显示。带--raw可以触发编码集的格式化。

 

 

 长度是不会变化的,key3的utf8依然长度为3,key2为2.

redis底层按字节存储,key做了编码优化。redis本身是没有数据类型的。

 getset方法一次连接两个操作,减少连接次数。

msetNx,不存在key才批量set,有一个key存在,则该笔操作所有key都失败。

select与epoll的对比:

bitmap类型:

help setbin

setbit:同时存在字节索引和二进制位

例:k1的value只有一个字节,二进制位为8个

setbit k1 1 1 表示将k1的value的二进制位为1的位置,改为1   asci转码为@

setbit k1 7 1 长度仍然是1,没有超出1个字节                 asci转码为A

setbit k1 9 1 超出一个字节                                        asci转码为A@ (因为超出一个字节长度后,会开辟一个字节为00000000,然后修改二进制位9为1)

字符集标准为ascii,其它为扩展字符集。扩展:其它字符集不再对ascii重编码。字节流以0开头,为ascii码,其它的需要取两个或者三个才能确定编码类型。

bitpos:寻找第一个二进制位

 bitpos k1 1 0 0 寻找二进制1,从字节索引0到0中寻找

bitpos k1 1 1 1 从字节索引1到1中寻找二进制数1 返回的是二进制1在整个字符中的二进制位位置。

bitcount :统计二进制1出现的次数

 bitcount k1 0 1 在字节索引0到1中统计二进制1的次数

bitop:二进制运算

bitop and k3 k1 k2  对k1和k2的二进制数进行与运算,结构存入k3

同样还有or 或操作。

位图应用场景:

1.统计用户登录天数,且窗口随机(时间范围随机,如十一前后一周等等)。

懒做法:数据库记录用户登录记录。

通过数据库统计的方式,浪费内存空间,且查询效率低。

每一天对应一个二进制位,一年按400个二进制位。400/8 = 50个字节。50个字节可以最大情况记录用户全年365天的登录状态。

setbit zhangsan 1 1 表示个张三第二天登录了

setbit zhangsan 7 1  第八天登录

setbit zhangsan 364 1

Strlen zhangsan = 46个字节  这样全年的登录情况都以46个字节存储在redis中。

一个字节代表8天,想知道用户十一前后一周有没有登录。只需要统计这个字节索引范围内的1的数量,即 bitcount zhangsan (365减去十一在该年的天数-7)/8  (365减去十一在该年的天数+7)/8

高效,且节省内存1000万用户一年的登录记录内存为400+M。

2.假如京东618做活动,凡是登录,就会送礼物。需求:假设有两亿用户,库存至少需要多少货物? 

用户分为僵尸用户,冷热用户/忠诚用户

关键在于活跃用户统计。

活跃用户统计,随机窗口:如 1~2号活跃用户统计

setbit 20210701 1 1   ---A用户一号登录

setbit 20210702 1 1 ----A用户2号再次登录

setbit 20210702 7 1 ----B用户2号登录

bitop or countkey 20210701 20210702 给这两天做与运算,有一为一。

再统计所有的二进制1.

bitcount countkey 0 -1 就可以得到去重的活跃用户数

List,Set,Zset,Map使用略(各种存储类型的应用场景)

list场景:消息队列,阻塞队列,栈。

Set:统计交集,如微信朋友圈点赞人展示。A用户和B用户看到的朋友交集。

        随机数抽奖。

 Zset:
Map:

ZSet是怎么排序的?增删改查的速度

skipList跳跃表:

Redis的NIO

Redis的发布订阅的使用:

publish xxxx hello 向通道内推送消息

subscribe xxxx 需要开启该监控才能看到推送的消息

redis事务:

redis的事务无法回滚。

redis的模块儿扩展:布隆过滤器:用于解决缓存穿透。

布隆过滤器:bf 命令

作用:当缓存穿透时,所有请求都压到数据库,会给数据库造成压力。

每个商品用bitmap来标记,通过多个算法计算出商品的位置,在bitmap对应位置上设置为1.

查询时,多个算法计算位置,只有全部位置的bitmap值为1,才确认商品存在。

注意:概率解决问题,无论函数有多少,都无法解决函数碰撞的问题。1%的误差概率

实现方式:客户端实现布隆算法,自己承载bitmap,redis只做缓存

2.客户端只有布隆算法。redis维护bitmap

3.客户端什么都不做,redis来加载布隆算法和维护bitmap

其它模块:counting bloom, cukcoo过滤器,布谷鸟过滤器。

缓存与数据库有什么区别?

1.缓存数据不重要。

2.缓存不是全量数据

3.缓存应随着访问而变化

4.存储的为热数据

redis做为缓存时的使用的问题:

缓存应随着访问而变化。

保存热数据,内存是瓶颈。

1.key的有效期。

         设置有效期,set key value ex 有效期s   查看有效期时间, ttl key

        倒计时 expire

        定时

        注意:不设置过期时间,通过expire来设置倒计时,再更新key时,会取消倒计时。

        到时清理有两种方式:被动和主动

        被动清理:到期不会自动清除,在用户下一次调用该key时清除。

        主动清理:随机确认20个key,判断是否超过25%的key过期,如果达到25%,则遍历所有key进行过期清理

2.内存满了后,的回收策略。LRU算法多久没有使用,LFU最少使用次数

Redis的内存持久化

RDB:快照,保存的是二进制文件,恢复比较快。

存在时点问题。 

1.redis在执行RDB时,redis通过fork()(系统调用),开辟一个redis数据关系(指向数据的指针)的子进程(不会复制数据),通过copyOnWrite内存机制,持久化到磁盘,写入的是子进程数据,不会产生时点冲突。父进程对数据的修改,子进程看不到,也不会改该子进程的数据指向指针。

方式:

1.save 阻塞方式 (关机维护时可以用save)

2.bgsave: fork的异步非阻塞

3.配置文件中给出bgsave的规则:如下图

持久化地址:dir

弊端:不支持拉链,永远只有一个dump.db.

        丢失数据问题:redis宕机会丢失到上一次rdb的数据。

优点:类须于java中的序列化,恢复的速度相对快

补充知识点:

LINUX管道:

        1.衔接上一个命令的输出做为后一个命令的输入

        2.管道会触发创建子进程, |前后两个子进程

Redis的fork():

使用linux的时候,父子进程。

正常情况下:父进程的数据,子进程看不到。

通过export,可以让子进程看到父进程的数据。

通过导出环境变量的方式,子进程的修改不会影响父进程的数据。父进程的修改也不会破坏子进程。

创建子进程的速度两个因素:

redis父进程,内存数据10G。

1.速度

2.内存空间

fork(): 速度快,内存小。

redis内存在虚拟地址,计算机存在所有进程共用的物理内存。

redis的所有key,都会存映射到物理内存的地址。

 

 copyonwrite 写时复制

创建子进程,并不发生复制。创建进程变快了。

AOF:redis的写操作记录到文件中(指令日志)

优点:丢失数据少

redis中rdb和aof可以同时开启,如果开启了aof,只会用aof恢复。

4.0版本以后:AOF中包含RDB全量,增加记录新的写操作。

场景:redis运行了10年,redis挂掉,AOF多大,恢复要多久?如果只有两个k重复增删10年。

AOF数据量10T。如果恢复的话,可能要5年左右。

AOF缺点:

        1.体量无限变大,恢复慢   可以通过设计一个方案让日志或AOF足够小。也可以通过hdfs或其它方式。4.0以前:重写,删除抵消的命令,合并重复的命令。最终也是一个纯指令的文件。

4.0以后:重写:将老的数据RDB到AOF文件中将增量的以指令的方式Append到AOF

redis内存写数据库会触发IO:可以调整三种写io的级别:NO,Always, 每秒。

Redis的AFK原理:

单机redis单进程,持久化通过RDB或AOF。

单机,单节点,单实例的问题:

1.单点故障

2.容量有限

3.连接压力

AFK:

x轴主备:全量镜像的  ,可以解决单点故障的问题。  ----主从

Y轴:数据分开。把不同的业务分到不同的实例。 ----分片

Z轴:按照优先级,逻辑再拆分,把不同的数据分到不同的z轴实例

X轴问题:主备模式,备份到备机,存在数据一致性问题!

 强一致性会破坏redis的可用性问题。

如果容忍数据丢失一部分,可以采用异步非阻塞方式:

 3.可以通过消息队列实现主备复制:最终一致性

在这种模式中,当主机中的数据发生改变后,会阻塞式的将修改数据的消息传递给一个消息中间件。然后马上将确认消息回复给客户端。

集群中的其他备机会消化消息队列中的消息。

这种方法可以快速的给予客户端响应,集群也会在未来的某一刻达到数据一致性,我们称之为最终一致性

 注意:最终一致性方案,在消息队列未完成备机消费情况下,主机挂掉,从备机取得数据会得到不一致的数据。

CAP理论与哨兵模式:

C:一致性

P:分区容错性

A:可用性

CAP理论:三个性质不能同时满足。

主备:客户端只能访问主机。

主从:客户端可以访问从机。

如何保证高可用:通过redis主从,可以通过手动来将从机设置为主机redis。

监控程序:哨兵模式。哨兵也是个集群,跟据CAP理论

为避免产生脑裂,设置为n/2 + 1太的势力范围来进行投票,保障了可用性和分区容错性,即AP理论。(单机redis采用CP模式)

Redis分片Sharding

主从复制,解决了redis的可用性问题。

跟据AKF,Y轴,存在容量问题!

解决方案:

数据角度:业务可以区分的话,客户端来决定操作不同的redis实例

数据无法拆分的角度:

1.算法区分 + 取模。即redis分片, sharding 客户端来操作。  弊端:取模的数必须固定,影响分布式下的扩展性。如果加redis服务器,需要重新设置取模数。

2.random区分。随机 (场景:发布订阅模式的消息队列,lpush进去list,客户端只需要rpop)

3.一致性hash算法:hash映射算法  CRC16位,CRC32位,FNV, Md5。

        没有取模的过程,hash环

一致性hash算法优点:加节点可以分担其它节点的压力,不会造成全局洗牌。

缺点:新增节点会造成一小部分数据不能命中,隐藏缓存击穿问题,给mysql增加压力(只能作为缓存使用)

方案:取后两个物理节点。

上面虽然解决了Y轴容量分片问题,但是不能作为数据库使用。

使用redis预分区,算法取模,多取模一点。然后在redis实例中每个实例映射多个hash值,增加一台实例,将之前的实例映射内的取模值以及数据一并分一些给新的redis实例

redis集群

redis集群内没有主从概念,所有的redis节点,都存在自己的算法取模范围和别的节点的取模范围,请求只需要进入其中任一个节点,就会定位到数据存在于哪个节点。

缺点:聚合操作很难实现事务。

hashtag,通过给不同的key设置为hash可计算出同样的数据来强行放到一个节点。

缓存击穿:某个key失效,大量访问进来

解决方案:采用setNx锁,并且设置过期时间,加上续命。第一个请求进来获取不到key,加锁(其它请求循环get(key)),然后通过数据库获取数据后,更新到redis后,释放锁,其它请求再从redis访问。

缓存穿透:key不存在,直接访问客户端

解决方案:1.布隆过滤器 2.设置key值为空

缓存雪崩:大量key同时失效,大量访问访问db

解决方案:1.对于无关时间点的数据,设置随机失效时间,避免同时失效

2.对于必须失效的数据,采用缓存击穿的方式来做。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Redis全套学习笔记.pdf》是一本关于Redis数据库的学习笔记,内容涵盖了Redis的基本概念、原理、操作、应用等方面的知识。 首先,Redis是一种开源的内存数据库,它具有高性能、高可用性和高扩展性的特点。它可以用于缓存、消息队列、实时排行榜等场景,广泛应用于Web应用开发、大数据存储和分析等领域。 在学习笔记中,首先介绍了Redis的基本概念,包括数据结构、持久化、单线程架构等方面的知识。数据结构包括字符串、哈希表、列表、集合和有序集合等,笔记详细介绍了它们的特点和使用方法。持久化方面,介绍了RDB快照和AOF日志两种持久化方式的原理和使用方法。同时,笔记也解释了为什么Redis选择单线程架构以及如何充分利用单线程的优势。 其次,学习笔记还包括了Redis的常用操作,例如数据的增删改查、事务和管道操作、过期时间设置等。这些操作是使用Redis进行开发和使用时必不可少的知识点,通过学习笔记可以快速掌握这些操作的使用方法。 此外,学习笔记还涉及了Redis的高级应用,如发布订阅、Lua脚本、事件通知等。这些高级应用可以帮助开发者更好地利用Redis的功能和特性,提升系统的性能和稳定性。 综上所述,《Redis全套学习笔记.pdf》是一本全面介绍Redis学习资料,通过学习这本笔记,读者可以了解Redis的基本概念和原理,掌握Redis的常用操作和高级应用,从而更好地使用Redis进行开发和应用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值