序言
夏日炎炎,无风。从空调房间出来,再到接近四十度的高温,这个过程,缓存预热了解一下……
为什么要用缓存?因为追求性能,因为要追求极致的用户体验。
缓存理论
1、缓存适合的场景
缓存,就是将一些需要读取数据放在磁盘或者内存中,由于是追求速度,从而一般放在内存中。
在读取数据的时候,一般是从关系型数据库中读取数据,在数据库层面也可以进行各种优化,例如读性能不足,那么可以添加几个从库,从而数据库的一主多从;例如写性能不足,那么可以分库分表。
在有些场景中,要使用缓存,是因为无法解决读的速度,例如count(*)
的操作,无论从数据库的层面如何优化,都不可能提高;还有一种就是sql的执行本身就必须消耗很多资源和时间,例如各种关联查询子查询,这些时候,都可以将这些数据放在缓存当中,从而大大的减轻数据库的压力。
2、缓存穿透问题
在使用缓存的时候,第一个问题就是缓存穿透的问题,就是使用了缓存和没使用缓存是一样的,应用程序到缓存中查询数据,发现数据么有,那么就去数据库查询,在这里,穿透了缓存,缓存没起到保护数据库的作用。
在爬虫爬取网页的时候,每个分页都会爬取,而对于缓存的分页数据,一般只缓存了热点数据,也就是前几页的数据在缓存当中,如果全部爬取,那么就会造成缓存不命中,导致查询数据库;还有一种就是故意搜索一些不存在的关键字,而这些搜索的结果都没有数据,在数据库中也不存在数据,从而造成缓存穿透。
此种解决方法就是:当用户进行第一次查询的时候发现结果为空,那么可以将结果放在缓存中,设置一个短暂的过期时间,从而可以缓解穿透的问题;而对于爬虫的爬取数据,只能进行监控,然后进行访问的IP,依旧只能缓解,不能完全解决。
3、缓存雪崩的问题
缓存雪崩指的是当缓存失效之后,从而引起系统性能的急剧下降,导致数据库不可用从而系统挂掉。
缓存最关键的地方就是内存,当内存满了之后,会有各种策略将缓存进行失效,在分布式环境下,如果有一个缓存失效,而恰好这个缓存是一个热点数据,前端有10个应用都需要访问这个缓存,并且TPS很高的话,那么全部的线程都会去访问数据库,从而能直接将数据库拖垮。
应对缓存雪崩,有很多策略,例如可以设置两个缓存的key,而具有不同的失效时间,当key1失效之后,访问key2,然后更新key1和key2;可以使用分布式锁,从而当应用发现缓存失效之后,拿到锁的线程才去更新缓存;可以使用消息通知机制,当应用发现缓存失效之后,发送消息,然后后台线程进行更新缓存,后台线程会检测缓存中是否存在缓存,如果存在就不更新;专门用一个后台线程来更新缓存,快速的检测缓存是否存在,然后更新缓存,此种也可以解决缓存不一致的问题。
4、缓存命名和失效时间
在使用缓存的时候,都需要一个key,那么这个key怎么命名呢?key太长,占用内存,会使得缓存中能存储的数据减少;key一般的命名规则可以为SQL:1782,表示为这是缓存一个sql的结果,然后用冒号分割,然后表示为缓存的编号,可以为各种sql条件的hash后的结果,这种命名规则的好处就是,在每次在缓存里查询的时候,可以使用通配符,从而可以查询到有多少个缓存在系统中。
缓存的失效时间,这个和业务强相关,对于一些时效性比较高的数据,就不能放在缓存当中,而对于一些不经常变化的数据,可以放在缓存当中,例如一天,缓存主要是应对读多写上的应用,从而大部分的数据例如在搜索的结果的分页数据,这种实时性无须太高,可以放在缓存当中。。。主要看业务的容忍程度,也影响到一部分的用户体验,可能我放入了缓存,更新了,刷新下,还没有更新。
5、缓存预热和缓存热点问题
缓存预热,在系统宕机刚上线的时候,流量全部涌入,而此时缓存中还没有缓存数据,从而可能导致直接压垮数据库,从而在应用程序启动之后,要进行缓存预热,最简单的方法就是点点界面,然后搜索一下结果;最好的方式,就是写一个后台线程,进行缓存预热,在这个后台线程里,会将常用的热点数据都直接加载进缓存当中。
缓存热点,当使用的是缓存集群的时候,如果缓存分布的有问题,那么可能一台缓存服务器承担了大部分的压力,而另外一些缓存服务器则没有压力,从而也有可能导致缓存雪崩,直接压垮一台缓存服务器,上线,又压垮一台,死循环。。。
在进行缓存数据的时候,需要分析热点数据,并且要分析缓存的数据量的大小,否则无论是网络还是内存,都可能造成缓存雪崩的潜在影响点。
redis主备
reids是一个键值存储的内存cache或者持久化存储,用redis做缓存是简单的。而redis再此时也无需持久化机制,从而直接在容器中使用。
两条指令运行一个redis的主从缓存,配置文件使用默认的配置文件,在master的配置文件中修改bind即可,在slave的配置文件中,修改bind和slaveof即可。
如何来检测这个redis是ok?用容器来运行一个测试redis的功能,执行的效果如下所示:
专门使用一个testredis的容器来运行一个测试任务,在正常的情况下,容器的退出码为0,当redis异常的时候,容器的退出码为1,从而可以在生产中进行功能性测试,当然,你也可以进行自动修复,例如拉起失败的redis容器即可。
检测脚本的内容:
在运行这个测试容器的时候,需要注意的是,要使用host的网络,如下所示:
以后要进行运行测试容器的时候,只要start这个容器即可。
此种过程进行优化,例如使用一个脚本,就直接创建master,slave和测试容器,还能进一步将master和slave分布在不同的机器上,还能进一步直接创建sentinel进行自动切换和故障转移,还能直接创建一个redis cluster模式。
在使用config rewrite写入配置文件的时候,注意selinux可能会阻止你写入配置文件。
在使用的缓存策略为noeviction的时候,那么一旦可用内存使用完毕,就会显示OOM,内存超过了最大使用内存,默认配置并不会使用LRU算法。
在查看键的数量的时候,切记keys是高危指令,会阻塞所有的请求,影响生产环境的服务,不信?到生产上试试,指令为keys *。
在查看大量键的时候,使用scan指令,每次返回一个游标,相当于分页查看咯。
在进行转储的时候,不要用save指令,切记要使用bgsave和bgrewriteaof,虽然这两个不会阻塞服务,其实也会阻塞,不过时间很短,主要耗费的时间在fork的时候,400ms了解一下。。。fork一般需要多少ms?求解
闲聊
缓存命中率?不可能的。。。这辈子都不可能命中的……
依稀记得有人挑战,但是我忘记了是个具体什么样的问题。其实捍卫不捍卫真的无所谓,不捍卫自己的观点在于,暴露对方的无知,如果捍卫我自己的观点,那就会暴露自己的无知,当然,一般我都是先表现出我的无知,这样才能引入新奇的观点,否则,一无所获。
再谈自动化运维,有人说,你就两个命令的事儿,你还费劲巴拉的写成一个界面,写成一个按钮,有意思么,有意思,相当有意思。
防止误操作,这是主要功能,自动化平台承担大部分责任,封装所有的高危操作指令,可以进行二次确认。
权限控制,哪些人能使用这个,哪些人不能使用。
一台机器两个指令,三台你试试,三百台你试试,三千台呢?
有的时候,感觉思维层次不同,不想解释,解释就是掩饰
一个缓存系统,能玩多久?能玩很久很久。
一个系统,里面包含着无数个小系统,缓存系统?可以用redis和memcache,你怎么选?
一个系统,里面又包含着无数的知识点,redis是单进程单线程的服务,那么那些会阻塞服务?在客户端请求过来,tcp连接满了怎么办?参数backlop是否要响应增加?
一个系统,要追求高可用,高性能,那么就会引入其他的组件,例如使用sentinel达成高可用,使用redis cluster来进行搭建,使用前端的各种中间件。
一个系统的配置,又包含了各种样的东西,redis的持久化有两种,一种是rdb,一种是aof,有何区别,哪种更好?如果持久化会丢失数据否?丢失多久的数据可以接受?
一个系统的构成,各种各样的方式,如何进行主备复制?sentinel如何来检测master是否宕机?sentinel为何要用3个或者5个节点?
子子孙孙无穷尽也,可能很多时候,都碰不到这种场景?高并发,不可能的,这辈子都不可能的,风都么有,备用知识命中率,了解一下。