1. redis<br />1. 为什么会出现redis:以前存储文件是放在硬盘上,寻址时间是ms(毫秒),当文件变大,进行全量扫描的时间变长了,寻址时间变长,不足以满足人们的需求,所以发明了redis(基于内存操做,寻址时间是ns(纳秒)),也就是磁盘的10w倍<br /> <br />2. 使用数据库:相比存放在磁盘上,还是比较快的,那么为什么就快了呢:分治+索引<br /> <br />3. 当数据库中的表数据量很大的时候,写是肯定会变慢的,因为索引结构需要调整,但是读不一定慢:当只有一个连接连接到数据库,客户端只发来一个简单的查询,且命中索引,那么查询还是毫秒级别的。如果是高并发的场景下,那么就变慢了:每个人都读取数据,每个人的数据都是独立的,那么就需要从磁盘中将数据返回放到内存中,这里会涉及到带宽吞吐量的问题,不能全部一次性读取到内存中,所以就会延迟,从而变慢<br /> <br />注意:以上几点说的都是如何解决全量扫描io问题,解决这个就会变快。<br /> <br />提问:1.redis是什么?<br />基于内存操做的worker线程是单线程的nosql数据库<br /> <br />2.redis的工作流程:这个是5.x之前的版本<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772556542-366373ce-837a-48b4-8b53-f43ba45e58f4.png#height=165&width=415)<br /> <br />4. redis和memcache:都是key-value格式的<br />1. redis是nosql的(key-value),不存在聚合的概念,只要关注自身就行了,而且是单线程的,也就是操做是原子的。<br />2. Redis6.x存在多线程的概念:工作线程负责计算,io线程负责读和写(数据存在堆中)<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772556832-d1ed0b3d-1853-43c2-9dab-dbd66fdb04d9.png#height=173&width=416)<br />3. redis支持5种数据类型,并且每种类型都有自己的api,而memcache只有一种数据类型<br />4. Memcache在读取的时候,需要全部读取,自行在客户端实现自己的序列化,而redis直接在服务器上完成并直接返回自己想要的数据<br />5. Redis的性能来自于nio和epoll,多路复用<br />6. Redis是高并发但串行执行的<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772557138-87fef270-f874-4eec-95e8-86bce51b6032.png#height=98&width=416)<br /> <br />缺点:单线程比较浪费cpu(现在基本上都是多核的)<br /> <br /> <br /> <br />redis的数据类型:如果想要学习操做命令,直接在客户端查看:help @String hash set list zset<br />1. String:操做字符串和数值和二进制的操做(bitmap)<br />使用场景:<br />1. session共享(string)<br />2. Token(string)<br />3. 对象/小文件:静态页面也可以直接存储在里面,或者静态资源(string)<br />4. 分布式锁(string)<br />5. 数值计算可以做秒杀,库存的扣减(数值)<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772557811-f8e617fc-f504-45bb-9e7f-4c694c9a4c98.png#height=183&width=283)<br />6. 位图的操做:bitmap:<br />1. 活跃用户数的统计<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772558404-0177674c-b375-4ef4-841b-0b360ec1b6c4.png#height=146&width=415)<br />2. 某个用户登录次数的统计<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772558896-7f653920-5db6-4613-b9c8-469d21959eef.png#height=176&width=415)<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772559428-dba729ed-174f-43e9-87a4-f901340bbbe4.png#height=165&width=415)<br /> 3.12306买票的优化:<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772559944-df2d4aae-206f-4a23-b667-15d50cfb8217.png#height=357&width=415)<br />补充:什么是二进制:<br /> <br />2. list:左右都可以插入数据,底层是双向链表:同方向是栈,异向是队列,lindex命令还能模拟数组<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772560465-7af160e7-4ff8-4e98-a799-fa899f24f601.png#height=157&width=414)<br />使用场景:<br /> 1.<br /> <br />3. hash:<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772560816-fb19af4d-d4a9-423e-8433-05c2377f2f85.png#height=337&width=415)<br />场景:1.将数据进行聚合存储:将不同请求的数据从各个不通过的服务中获取并聚合,客户端只需要一次io就能获取全部想要的数据(数据不是经常用的)<br /> <br /> <br />4. set:集合:去重且无序。不建议使用:大量数据获取的时候会影响带宽:如果必须使用建议单独使用一台服务器专门做集合的操做<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772561291-e6aee168-7c8d-4742-b872-7bf4e33a9566.png#height=107&width=415)<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772561537-0f3549b7-b69e-47df-aa3c-6a22c4879743.png#height=212&width=415)<br /> 使用场景:<br />1.推荐系统<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772561870-7e254758-e377-40fe-a593-cfa115fc7e55.png#height=190&width=415)<br /> <br />zset:有序集合:<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772562400-6582cb2d-345c-43ad-af67-89a62603419c.png#height=127&width=416)<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772562877-1c21257b-af65-4b9a-84d4-deb52a092a92.png#height=90&width=415)<br />使用场景:<br />1. 排行榜<br />2. a评论+分页(动态)<br /> <br />redis的持久化:4.x版本之后可以混合使用<br /> 快照rdb:定期存储(dump.rdb):快但缺失多:默认开启<br /> 日志aof:慢且冗余但丢失少<br /> <br />注意:aof持久化的配置:appendonly yes redis.conf<br /> <br />持久化策略:<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772563371-c57f27d7-190e-4184-a727-5346ec949027.png#height=189&width=487)<br />redis中的问题:<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772563874-b1d8e3bb-c517-461d-8528-b31fbc442440.png#height=117&width=414)<br />注意:这里的分片我们可以采用hash%4这种方式进行分片<br /> <br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772564167-417e2458-9a7d-44e9-a491-b6a34162337d.png#height=195&width=415)<br /> <br />1. 单点问题的数据强一致性问题:<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772564497-a47625c4-8153-4b9c-80e7-9ffe2f82355a.png#height=163&width=415)<br />1. 强一致性:客户端访问主redis,主redis先不回答客户端,将数据写给从redis,等从redis回复了ok,主redis再回复客户端:这个需要自己配置,当收到几个ok的情况下,主redis再去回复客户端<br />2. 弱一致性:直接给主写数据,不关心从节点是否同步数据成功,主要主节点成功就返回(redis默认采取的是弱一致性)<br /> <br /> <br />缓存穿透:数据库和redis都没有,黑客的攻击,假id的不断攻击:<br /> 解决方案:校验<br />缓存击穿:redis没有,数据库有,用户同时请求数据库,导致io过大<br /> 解决方案:设置为永不过期<br />缓存雪崩:redis中大量的key过期,导致大面积的请求数据库,导致数据库io过大<br /> 解决方案:随机过期时间/二级缓存<br /> <br />Sharding分片存储的思想:<br />1. 在客户端的代码中使用算法来统计将数据存储在哪个redis中<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772565054-03cac245-6a1e-4e8c-8e74-b5cbae01a44a.png#height=187&width=415)<br />2. 使用代理中间件<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772565560-f9247f62-e6d8-43a3-82e5-978305dd1b23.png#height=118&width=414)<br />3. redis自己提供了一个算法实现数据的存储的统计<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772566065-a1a866e3-040f-47a0-821e-c93bc480f2cd.png#height=202&width=415)<br />讲解:redis提供了一个巢位的概念,一个redis有16384个巢位:将巢位使用map映射进行分配<br />1. 客户端携带过来的key进行hash运算并取模16384,然后结合一个map映射,去放置最后的数据的具体位置:比如第一个map定义是0到10000放在这里,另外放10001到16384,当计算后是10002,那么就给客户端返回一个top,让客户端重新连接另外一台<br /> <br /> <br />redis集群原理讲解:<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772564167-417e2458-9a7d-44e9-a491-b6a34162337d.png#height=195&width=415)<br />1. 集群中节点的个数正常都是奇数个<br />2. 集群中主节点数过半宕机,则认为集群是失败的<br />3. 客户端只要连接任意一台节点就能获取其他节点的数据<br />4. 在redis集群中会有16384个hash巢,通过map映射分配到各个分片中,<br />5. 任意存入redis中的数据的key经过hash算法,再cr16算法后得到的值在0~16383之间<br />6. 每次存取值都会根据cr16算法得到的值去自己连接的redis节点中找,如果第一次没有命中,则第二次会直接重定向到对应的节点上去<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772566508-c3d19e08-f5c7-4bb2-953e-91905bf506b5.png#height=173&width=415)<br /> <br /> <br />redis集群的搭建:基于linux的安装步骤(后期改进为docker)<br />1. 因为redis是基于c语言开发的,需要安装依赖:yum install gcc-c++ -y<br />2. 因为集群的搭建过程中需要ruby语言,也安装一下:yum install ruby -y<br />yum install rubygems<br />3. 下载redis的安装包:`wget ``[https://download.redis.io/releases/redis-6.0.9.tar.gz](https://download.redis.io/releases/redis-6.0.9.tar.gz)`<br />4. 解压:tar -zxf redis-6.0.9.tar.gz<br />5. 使用安装包将redis安装到指定路径下:<br />1. 进入到redis安装包:cd redis-6.0.9<br />2. 进入安装包目录之后执行编译命令:make<br />注意:执行编译命令得时候会报错,几乎都是环境依赖问题: 升级gcc<br /> 1.yum -y install centos-release-scl<br /> 2.yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils<br /> 3.scl enable devtoolset-9 bash<br /> 然后重新执行编译命令:make<br /> <br />3. 编译完成之后将其安装到指定目录下:make install PREFIX=/usr/local/redis<br />4. 执行安装测试命令:make test(这个步骤完全可以省略)<br />5. 将解压包路径下的redis.conf移动到redis的安装目录的bin目录下:主要目的是方便管理而已<br />以上单机版本得redis就安装好了<br /> redis启动校验:进入安装目录的bin目录:./redis-server redis.conf<br /> redis客户端连接:进入安装目录的bin目录:./redis-cli<br /> <br />注意:1.linux的top命令也可以查看运行中的服务<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772566761-9471ace1-1dd9-46c0-9b95-c2b15590a649.png#height=58&width=415)<br /> 2.redis的配置文件的位置:<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772567136-387abd17-8a54-4797-8777-e938d8234f69.png#height=25&width=415)<br /> <br /> <br />集群的搭建:<br /> 1.主要工作:<br /> 1.安装redis的几个服务器<br /> 2.每个节点需要开启集群<br /> 3.需要用ruby语言将每个节点串联起来(5.x版本以下需要,5.x及以后就直接不需要了)<br /> <br /> 2.集群搭建的详细步骤:在单机版本的基础之上<br />1.开启集群模式:编辑redis的配置文件:redis.conf<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772567633-917a26d2-8d47-423e-880a-da0eb9fdeca2.png#height=106&width=487)<br />2. 启动各个服务:后台启动模式:daemonize yes<br />3. <br /> 1, 5.x版本以前的版本:在任意一台redis集群的节点上执行ruby脚本,实现redis多主多从并实现hash巢的分配:<br />在解压路径下的src目录下执行脚本:<br />./redis-trib.rb create --replicas 1 192.168.74.211:6379 192.168.74.212:6379 192.168.74.213:6379 192.168.74.214:6379 192.168.74.215:6379 192.168.74.216:6379<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772568130-de0612cf-a107-4108-a50b-4d6cba896f24.png#height=80&width=487)<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772570709-f4df8fe4-e805-4fb5-8c2b-3e84ce45f64c.png#height=179&width=486) <br /> <br />2.5.x及以后的版本:直接使用客户端连接命令就好:_./redis-cli --cluster create --cluster-replicas 1_ 192.168.74.219:6379 192.168.74.215:6379 192.168.74.214:6379 192.168.74.218:6379 192.168.74.220:6379 192.168.74.221:6379<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772571243-530381ba-6a5f-4a18-b434-fc85918e79eb.png#height=200&width=487)<br /> <br />注意:在我们创建集群的时候可能会发生redis无法远程连接问题:<br /> 查看当前redis的运行id号,并杀死进程:ps -aux |grep redis kill -9 xxx<br />1. 保护模式设置为no<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772571429-97d863b8-93e5-44f3-ae70-97f63a858aac.png#height=59&width=251)<br />2. 注释掉绑定的ip:127.0.0.1<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772571785-02cfed37-1a95-4d81-95e7-594b8e2116ad.png#height=171&width=487)<br /> <br /> <br />在idea搭建的java项目中如何连接集群进行使用:直接添加配置就可以使用了<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772572021-6776443d-75d0-4767-896d-c0b02eeba7bf.png#height=201&width=397)<br /> <br />集群中的哨兵策略:监控redis的健康状态并实现redis的主从切换:哨兵本身也存在集群模式<br /> <br />注意:每个redis节点都需要一个哨兵<br /> <br />节点哨兵的搭建:<br />1. 找到解压路径的sentinel.conf配置文件,修改配置文件并复制到安装路径的bin目录下<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772572304-271a9741-53ab-4f05-b38a-901ce66d5a07.png#height=83&width=488)<br />2.开启哨兵模式:进入安装路径的bin目录下:./redis-sentinel sentinel.conf <br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772572531-e25826c1-a621-4a33-8e60-9413f735afb9.png#height=177&width=487)<br /> <br />注意:这里的哨兵是需要在主节点启动与监控<br /> <br />项目实战中的缓存架构:<br />![](https://cdn.nlark.com/yuque/0/2020/png/2499550/1607772572839-686b6a6a-44a9-489e-a05b-3726fe3f00ad.png#height=134&width=487)<br />缓存同步的实现:canal实现同步:先复制数据库数据,然后同步数据到各个缓存中<br /> <br />