‘壹’ 如何处理查找,处理数据库的性能瓶颈
具体问题具体分析,举例来说明为什么磁盘IO成瓶颈数据库的性能急速下降了。
为什么当磁盘IO成瓶颈之后, 数据库的性能不是达到饱和的平衡状态,而是急剧下降。为什么数据库的性能有非常明显的分界点,原因是什么?
相信大部分做数据库运维的朋友,都遇到这种情况。 数据库在前一天性能表现的相当稳定,数据库的响应时间也很正常,但就在今天,在业务人员反馈业务流量没有任何上升的情况下,数据库的变得不稳定了,有时候一个最简单的insert操作, 需要几十秒,但99%的insert却又可以在几毫秒完成,这又是为什么了?
dba此时心中有无限的疑惑,到底是什么原因呢? 磁盘IO性能变差了?还是业务运维人员反馈的流量压根就不对? 还是数据库内部出问题?昨天不是还好好的吗?
当数据库出现响应时间不稳定的时候,我们在操作系统上会看到磁盘的利用率会比较高,如果观察仔细一点,还可以看到,存在一些读的IO. 数据库服务器如果存在大量的写IO,性能一般都是正常跟稳定的,但只要存在少量的读IO,则性能开始出现抖动,存在大量的读IO时(排除配备非常高速磁盘的机器),对于在线交易的数据库系统来说,大概性能就雪崩了。为什么操作系统上看到的磁盘读IO跟写IO所带来的性能差距这么大呢?
如果亲之前没有注意到上述的现象,亲对上述的结论也是怀疑。但请看下面的分解。
在写这个文章之前,作者阅读了大量跟的IO相关的代码,如异步IO线程的相关的,innodb_buffer池相关的,以及跟读数据块最相关的核心函数buf_page_get_gen函数以及其调用的相关子函数。为了将文章写得通俗点,看起来不那么累,因此不再一行一行的将代码解析写出来。
咱们先来提问题。buf_page_get_gen函数的作用是从Buffer bool里面读数据页,可能存在以下几种情况。
提问. 数据页不在buffer bool 里面该怎么办?
回答:去读文件,将文件中的数据页加载到buffer pool里面。下面是函数buffer_read_page的函数,作用是将物理数据页加载到buffer pool, 图片中显示
buffer_read_page函数栈的顶层是pread64(),调用了操作系统的读函数。
通过解析buf_wait_for_read函数的下层函数,我们知道其实通过首先自旋加锁pin的方式,超过设定的自旋次数之后,进入等待,等待IO完成被唤醒。这样节省不停自旋pin时消耗的cpu,但需要付出被唤起时的开销。
再继续扩展问题: 如果会话线程A 经过物理IO将数据页1001读入buffer之后,他需要修改这个页,而在会话线程A之后的其他的同样需要访问数据页1001的会话线程,即使在数据页1001被入读buffer pool之后,将仍然处于等待中。因为在数据页上读取或者更新的时候,同样需要上锁,这样才能保证数据页并发读取/更新的一致性。
由此可见,当一个高并发的系统,出现了热点数据页需要从磁盘上加载到buffer pool中时,造成的延迟,是难以想象的。因此排在等待热点页队列最后的会话线程最后才得到需要的页,响应时间也就越长,这就是造成了一个简单的sql需要执行几十秒的原因。
再回头来看上面的问题,mysql数据库出现性能下降时,可以看到操作系统有读IO。 原因是,在数据库对数据页的更改,是在内存中的,然后通过检查点线程进行异步写盘,这个异步的写操作是不堵塞执行sql的会话线程的。所以,即使看到操作系统上有大量的写IO,数据库的性能也是很平稳的。但当用户线程需要查找的数据页不在buffer pool中时,则会从磁盘上读取,在一个热点数据页不是非常多的情况下,我们设置足够大的innodb_buffer_pool的size, 基本可以缓存所有的数据页,因此一般都不会出现缺页的情况,也就是在操作系统上基本看不到读的IO。 当出现读的IO时,原因时在执行buf_read_page_low函数,从磁盘上读取数据页到buffer pool, 则数据库的性能则开始下降,当出现大量的读IO,数据库的性能会非常差。
‘贰’ 影响数据库性能的主要因素有哪些
1、1、调整数据结构的设计。这一部分在开发信息系统之前完成,程序员需要考虑是否使用ORACLE数据库的分区功能,对于经常访问的数据库表是否需要建立索引等。
2、2、调整应用程序结构设计。这一部分也是在开发信息系统之前完成,程序员在这一步需要考虑应用程序使用什么样的体系结构,是使用传统的Client/Server两层体系结构,还是使用Browser/Web/Database的三层体系结构。不同的应用程序体系结构要求的数据库资源是不同的。
3、3、调整数据库SQL语句。应用程序的执行最终将归结为数据库中的SQL语句执行,因此SQL语句的执行效率最终决定了ORACLE数据库的性能。ORACLE公司推荐使用ORACLE语句优化器(Oracle Optimizer)和行锁管理器(row-level manager)来调整优化SQL语句。
4、4、调整服务器内存分配。内存分配是在信息系统运行过程中优化配置的,数据库管理员可以根据数据库运行状况调整数据库系统全局区(SGA区)的数据缓冲区、日志缓冲区和共享池的大小;还可以调整程序全局区(PGA区)的大小。需要注意的是,SGA区不是越大越好,SGA区过大会占用操作系统使用的内存而引起虚拟内存的页面交换,这样反而会降低系统。
5、5、调整硬盘I/O,这一步是在信息系统开发之前完成的。数据库管理员可以将组成同一个表空间的数据文件放在不同的硬盘上,做到硬盘之间I/O负载均衡。
6、6、调整操作系统参数,例如:运行在UNIX操作系统上的ORACLE数据库,可以调整UNIX数据缓冲池的大小,每个进程所能使用的内存大小等参数。
实际上,上述数据库优化措施之间是相互联系的。ORACLE数据库性能恶化表现基本上都是用户响应时间比较长,需要用户长时间的等待。但性能恶化的原因却是多种多样的,有时是多个因素共同造成了性能恶化的结果,这就需要数据库管理员有比较全面的计算机知识,能够敏感地察觉到影响数据库性能的主要原因所在。另外,良好的数据库管理工具对于优化数据库性能也是很重要的。
ORACLE数据库性能优化工具
常用的数据库性能优化工具有:
1、1、ORACLE数据库在线数据字典,ORACLE在线数据字典能够反映出ORACLE动态运行情况,对于调整数据库性能是很有帮助的。
2、2、操作系统工具,例如UNIX操作系统的vmstat,iostat等命令可以查看到系统系统级内存和硬盘I/O的使用情况,这些工具对于管理员弄清出系统瓶颈出现在什么地方有时候很有用。
3、3、SQL语言跟踪工具(SQL TRACE FACILITY),SQL语言跟踪工具可以记录SQL语句的执行情况,管理员可以使用虚拟表来调整实例,使用SQL语句跟踪文件调整应用程序性能。SQL语言跟踪工具将结果输出成一个操作系统的文件,管理员可以使用TKPROF工具查看这些文件。
4、4、ORACLE Enterprise Manager(OEM),这是一个图形的用户管理界面,用户可以使用它方便地进行数据库管理而不必记住复杂的ORACLE数据库管理的命令。
5、5、EXPLAIN PLAN——SQL语言优化命令,使用这个命令可以帮助程序员写出高效的SQL语言。
ORACLE数据库的系统性能评估
信息系统的类型不同,需要关注的数据库参数也是不同的。数据库管理员需要根据自己的信息系统的类型着重考虑不同的数据库参数。
1、1、在线事务处理信息系统(OLTP),这种类型的信息系统一般需要有大量的Insert、Update操作,典型的系统包括民航机票发售系统、银行储蓄系统等。OLTP系统需要保证数据库的并发性、可靠性和最终用户的速度,这类系统使用的ORACLE数据库需要主要考虑下述参数:
l l 数据库回滚段是否足够?
l l 是否需要建立ORACLE数据库索引、聚集、散列?
l l 系统全局区(SGA)大小是否足够?
l l SQL语句是否高效?
2、2、数据仓库系统(Data Warehousing),这种信息系统的主要任务是从ORACLE的海量数据中进行查询,得到数据之间的某些规律。数据库管理员需要为这种类型的ORACLE数据库着重考虑下述参数:
l l 是否采用B*-索引或者bitmap索引?
l l 是否采用并行SQL查询以提高查询效率?
l l 是否采用PL/SQL函数编写存储过程?
l l 有必要的话,需要建立并行数据库提高数据库的查询效率
SQL语句的调整原则
SQL语言是一种灵活的语言,相同的功能可以使用不同的语句来实现,但是语句的执行效率是很不相同的。程序员可以使用EXPLAIN PLAN语句来比较各种实现方案,并选出最优的实现方案。总得来讲,程序员写SQL语句需要满足考虑如下规则:
1、1、尽量使用索引。试比较下面两条SQL语句:
语句A:SELECT dname, deptno FROM dept WHERE deptno NOT IN
(SELECT deptno FROM emp);
语句B:SELECT dname, deptno FROM dept WHERE NOT EXISTS
(SELECT deptno FROM emp WHERE dept.deptno = emp.deptno);
这两条查询语句实现的结果是相同的,但是执行语句A的时候,ORACLE会对整个emp表进行扫描,没有使用建立在emp表上的deptno索引,执行语句B的时候,由于在子查询中使用了联合查询,ORACLE只是对emp表进行的部分数据扫描,并利用了deptno列的索引,所以语句B的效率要比语句A的效率高一些。
2、2、选择联合查询的联合次序。考虑下面的例子:
SELECT stuff FROM taba a, tabb b, tabc c
WHERE a.acol between :alow and :ahigh
AND b.bcol between :blow and :bhigh
AND c.ccol between :clow and :chigh
AND a.key1 = b.key1
AMD a.key2 = c.key2;
这个SQL例子中,程序员首先需要选择要查询的主表,因为主表要进行整个表数据的扫描,所以主表应该数据量最小,所以例子中表A的acol列的范围应该比表B和表C相应列的范围小。
3、3、在子查询中慎重使用IN或者NOT IN语句,使用where (NOT) exists的效果要好的多。
4、4、慎重使用视图的联合查询,尤其是比较复杂的视图之间的联合查询。一般对视图的查询最好都分解为对数据表的直接查询效果要好一些。
5、5、可以在参数文件中设置SHARED_POOL_RESERVED_SIZE参数,这个参数在SGA共享池中保留一个连续的内存空间,连续的内存空间有益于存放大的SQL程序包。
6、6、ORACLE公司提供的DBMS_SHARED_POOL程序可以帮助程序员将某些经常使用的存储过程“钉”在SQL区中而不被换出内存,程序员对于经常使用并且占用内存很多的存储过程“钉”到内存中有利于提高最终用户的响应时间。
CPU参数的调整
CPU是服务器的一项重要资源,服务器良好的工作状态是在工作高峰时CPU的使用率在90%以上。如果空闲时间CPU使用率就在90%以上,说明服务器缺乏CPU资源,如果工作高峰时CPU使用率仍然很低,说明服务器CPU资源还比较富余。
使用操作相同命令可以看到CPU的使用情况,一般UNIX操作系统的服务器,可以使用sar –u命令查看CPU的使用率,NT操作系统的服务器,可以使用NT的性能管理器来查看CPU的使用率。
数据库管理员可以通过查看v$sysstat数据字典中“CPU used by this session”统计项得知ORACLE数据库使用的CPU时间,查看“OS User level CPU time”统计项得知操作系统用户态下的CPU时间,查看“OS System call CPU time”统计项得知操作系统系统态下的CPU时间,操作系统总的CPU时间就是用户态和系统态时间之和,如果ORACLE数据库使用的CPU时间占操作系统总的CPU时间90%以上,说明服务器CPU基本上被ORACLE数据库使用着,这是合理,反之,说明服务器CPU被其它程序占用过多,ORACLE数据库无法得到更多的CPU时间。
数据库管理员还可以通过查看v$sesstat数据字典来获得当前连接ORACLE数据库各个会话占用的CPU时间,从而得知什么会话耗用服务器CPU比较多。
出现CPU资源不足的情况是很多的:SQL语句的重解析、低效率的SQL语句、锁冲突都会引起CPU资源不足。
1、数据库管理员可以执行下述语句来查看SQL语句的解析情况:
SELECT * FROM V$SYSSTAT
WHERE NAME IN
('parse time cpu', 'parse time elapsed', 'parse count (hard)');
这里parse time cpu是系统服务时间,parse time elapsed是响应时间,用户等待时间
waite time = parse time elapsed – parse time cpu
由此可以得到用户SQL语句平均解析等待时间=waite time / parse count。这个平均等待时间应该接近于0,如果平均解析等待时间过长,数据库管理员可以通过下述语句
SELECT SQL_TEXT, PARSE_CALLS, EXECUTIONS FROM V$SQLAREA
ORDER BY PARSE_CALLS;
来发现是什么SQL语句解析效率比较低。程序员可以优化这些语句,或者增加ORACLE参数SESSION_CACHED_CURSORS的值。
2、数据库管理员还可以通过下述语句:
SELECT BUFFER_GETS, EXECUTIONS, SQL_TEXT FROM V$SQLAREA;
查看低效率的SQL语句,优化这些语句也有助于提高CPU的利用率。
3、3、数据库管理员可以通过v$system_event数据字典中的“latch free”统计项查看ORACLE数据库的冲突情况,如果没有冲突的话,latch free查询出来没有结果。如果冲突太大的话,数据库管理员可以降低spin_count参数值,来消除高的CPU使用率。
内存参数的调整
内存参数的调整主要是指ORACLE数据库的系统全局区(SGA)的调整。SGA主要由三部分构成:共享池、数据缓冲区、日志缓冲区。
1、 1、 共享池由两部分构成:共享SQL区和数据字典缓冲区,共享SQL区是存放用户SQL命令的区域,数据字典缓冲区存放数据库运行的动态信息。数据库管理员通过执行下述语句:
select (sum(pins - reloads)) / sum(pins) "Lib Cache" from v$librarycache;
来查看共享SQL区的使用率。这个使用率应该在90%以上,否则需要增加共享池的大小。数据库管理员还可以执行下述语句:
select (sum(gets - getmisses - usage - fixed)) / sum(gets) "Row Cache" from v$rowcache;
查看数据字典缓冲区的使用率,这个使用率也应该在90%以上,否则需要增加共享池的大小。
2、 2、 数据缓冲区。数据库管理员可以通过下述语句:
SELECT name, value FROM v$sysstat WHERE name IN ('db block gets', 'consistent gets','physical reads');
来查看数据库数据缓冲区的使用情况。查询出来的结果可以计算出来数据缓冲区的使用命中率=1 - ( physical reads / (db block gets + consistent gets) )。
这个命中率应该在90%以上,否则需要增加数据缓冲区的大小。
3、 3、 日志缓冲区。数据库管理员可以通过执行下述语句:
select name,value from v$sysstat where name in ('redo entries','redo log space requests');查看日志缓冲区的使用情况。查询出的结果可以计算出日志缓冲区的申请失败率:
申请失败率=requests/entries,申请失败率应该接近于0,否则说明日志缓冲区开设太小,需要增加ORACLE数据库的日志缓冲区。
‘叁’ 如何优化数据库的性能
--数据库性能调优
--1.聚集索引、主键
--2.尽量不要用临时表
--3.多多使用事务
--4.表设计要规范
--5.不要使用游标
--6.避免死锁
--7.不要打开大数据集
--8.最好不要select *
--9.不要使用text数据类型,用varchar
--10.不要给诸如“性别”列创建索引
--11.不要使用Insert插入大量的数据
--12.尽量用join代替where,因为where进行全表搜索
‘肆’ 怎样查出SQLServer的性能瓶颈
自定义性能监控
在这一点上,我假定你已经阅读了,或者至少浏览了所有监控步骤的建议。我猜你也许读了一些,但那些真正不适合于你。既然大部分的SQLServer安装稍微有点不同,那么这是有意义的。因此我建议你为你特定的环境自定义这个监控,添加或删除一些步骤使其更适合你的需求。
使用Word或Excel维护你的监控列表
当你对你的每一个SQLServer进行监控时,你需要一个方法去记录结果。当你有大量的选项时,从这一系列的文章里复制适合的监控列表到你的Word或Excel文档作为起点是比较快速的方法。你可能要为每个服务器创建一个单独的监控列表。如果你决定为你的监控表格使用Excel的话,你能输入所有的监控列表项目作为行,每一个监控的服务器作为单独的列。这样你能快速的查看每个SQLServer的结果。
设置SQLServer和数据库的优先级
如果你管理大量的SQLServer和数据库,你也许不知道从哪儿开始性能监控。理论上,你应该设置SQLServer和数据库的优先级,一些需要立即进行最多的性能监控,而其他的则不必进行那么多的监控。这会帮助你决定从哪儿开始。最可能的是,你将不会立即监控全部。相反,要在能监控的时候监控,按照从最重要到最不重要的顺序进行。
谨记性能监控的关键
当对SQLServer进行监控的时候
,记住目的是分辨并纠正容易的问题。但是,正如你所料,你将可能也分辨出一些更难于解决的问题。为了帮助你更好的管理有限的时间,你现在需要着眼于那些容易的问题,把困难的问题留到容易的问题先解决完之后。所以在你执行监控和分辨问题时,按照难易程度分类设置它们的优先级,将困难的问题留待你有足够时间处理它们的时候。
不要过早行动
当你执行监控时,你可能会急于对偶然遇到的问题进行纠正和修改。大多数情况下,那样做可能不是问题。但理论上,最好先执行监控,然后基于你的发现,决定正式动手解决你分辨出的问题,然后系统地实现它们。
一个推荐步骤,但或许会招来很多疑问
理想情况下,如有很多的时间,在服务器上执行一个性能基准是一个好的想法,然后执行监控,做任何需要的更改,再执行另一个性能基准去看看有什么情况发生。这会立即让你知道你所做的是否有帮助,大多数情况下,没有做正确的事。虽然这个建议被强烈的推荐,也许从时间来看不很实际。但如果你有时间的话,应该认真考虑。
另一个推荐步骤,但或许也会招来很多疑问
在执行监控之后,你也许发现在单个的SQLServer上所有需要的更改仅只有一两个,但在其他SQLServer上,也许需要做一打的更改。如果有那么的更改要做,不要立刻全部实现它们,仅仅一次一个或几个的更改也许是一个明智的选择。这样,你能够看看每个或每批更改对服务器产生的效果。如果你一次做了很多的更改,那么遇到问题时,你将不会知道是由哪个更改引起的问题,这要求你回滚所有的更改,然后一个一个的测试它们直到找到问题所在为止。
这个建议不会有太多疑问
如果你要做更改的服务器是有紧要事务的生产服务器,你要对你做的更改倍加小心。理论上,你应该在生产服务器应用更改之前在测试用的SQLServer上测试所有的更改。如果你不实践,那么每次仅做一个更改,确信如果有任何问题你知道怎样回滚更改。另外,试着选取一天中不很忙的时候做更改,万一有问题的话。
有一个取消计划
你因监控而做出的大多数更改应该能够很容易的回滚。但一些也许不那么容易。在那些情况下,你需要有一个万一需要的取消计划。例如,在你做出任何关键的更改之前备份系统和用户数据库。那样,即使出现问题,你也能将你的服务器恢复到更改之前的状态。我不是吓唬你不要做更改,但你总应该有所准备。
记录所有更改
当你基于性能监控做出更改时,确定你对所有的更改做了记录。这样,即使后来有什么问题,你也能更容易的找出错误所在。最容易记录下你的更改的方法可能就是把它们添加到你的监控表格里,或者其他你用来收集监控信息的文档里。
每年都要执行SQLServer的性能监控
许多SQLServer(并非全部)随着时间而改变。设置改变,打了SP补丁,甚至数据也改变了。所有的这些都会影响性能。确定你SQLServer最优性能的最好方法是做一个手工的性能监控。
‘伍’ 如何提高数据库性能,减少数据库服务器压力瓶颈一两个
如果是在本身配置上的原因(配置低,产品老化等),可以考虑增加配置,提高性能;如果是各种应用造成的资源浪费引起,那么可以对服务器做一些优化,关掉一些不必须要的应用。服务器厂商也就那么多个,比如国内的正睿、浪潮、曙光、联想等,国外的戴尔、惠普等
‘陆’ 有哪些手段可以查看mysql数据库性能瓶颈
通过sysbench的oltp_read_write测试来模拟业务压力、以此来给指定的硬件环境配置一份比较合理的MySQL配置文件。
环境介绍
硬件配置
软件环境
优化层级与指导思想
优化层级
MySQL数据库优化可以在多个不同的层级进行,常见的有:
SQL优化
参数优化
架构优化
日志先行 -- 一个事务能否成功提交的关键是日志是否成功落盘,与数据没有太大的关系;也就是说对写的优化可以表述为各方面的资源向写操作倾斜。
瓶颈分析 -- 通过show global status 的各个计数器的值基本上就能分析出当前瓶颈所在,再结合一些简单的系统层面的监控工具如top iostat 就能明确瓶颈。
整体性能是“读”&“写”之间的再平衡。
本文重点关注:参数优化
指导思想
‘柒’ 如何查看 mysql 性能瓶颈
通过sysbench的oltp_read_write测试来模拟业务压力、以此来给指定的硬件环境配置一份比较合理的MySQL配置文件。
环境介绍
硬件配置
软件环境
优化层级与指导思想
优化层级
MySQL数据库优化可以在多个不同的层级进行,常见的有:
SQL优化
参数优化
架构优化
日志先行 -- 一个事务能否成功提交的关键是日志是否成功落盘,与数据没有太大的关系;也就是说对写的优化可以表述为各方面的资源向写操作倾斜。
瓶颈分析 -- 通过show global status 的各个计数器的值基本上就能分析出当前瓶颈所在,再结合一些简单的系统层面的监控工具如top iostat 就能明确瓶颈。
整体性能是“读”&“写”之间的再平衡。
本文重点关注:参数优化
指导思想
‘捌’ 数据库写不进去数据,可能跟linux性能有关系吗
数据库写不进数据,不一定是和linux性能有关,一般如下几种可能:
1:数据库写入语句错误
2:数据库所在的磁盘满
3:数据库(表)被加锁
4:数据库性能到达瓶颈无法响应
5:linux性能到达瓶颈无法响应(一般是磁盘IO的瓶颈)
6:执行数据库写入的程序有问题
通过分析数据库日志,系统日志,写入程序的日志,可以分析出问题的。
‘玖’ 一个关系数据库系统的最大的性能瓶颈在哪方面
(30)[答案]B [考点]数据库设计基础 [评析] 此题为数据库的基本概念,如果你完全没学过数据库,可以对照办工软件的电子表格进行如下理解: 选择:我们根据某条件选择出一行或多行元组(一个元组即为二维表中的一行) 投影:按字段(也称属性,比如学生关系(学号,姓名,出生年月,性别),学号、姓名……都是属性)选取一列或多列(一个二维表中所有元组在某一列或几列上截取出来)。 连接:2个或2个以上的表连接组成一张新的表,通常有条件连接。比如学生关系(学号,姓名,系号),又有一张系表(系号,系名,主任),2张表可以合并为一张这样的表(学号,姓名,系号,系名,主任)
‘拾’ 数据库瓶颈方面什么技术提供了
接口响应时长过长
上个月我们经理把我叫了过去,说我们的产品的某些页面打开速度太慢了,要等好几秒。我十分惊讶,因为我把所有的功能都看过一遍的,没有哪个功能效率这么低下。我看了一下数据才明白,新客户的数据是老客户的数十倍,导致数据库查询时长翻了更多倍。
请求技术支撑
于是我找到技术中台负责人,希望他们能提供一套数据库缓存访问方案。当查询数据时不优先查询数据库,而是查询缓存来提高查询效率。得到的答复是近期太忙,没时间整这个。
团队自己做临时缓存
由于技术中台暂时没有时间来做支撑,所以我们团队只能暂时做一个临时缓存方案。于是我让我们团队的人员自行把高频查询并且不太会变动的数据,如部门结构和用户信息等数据,在查询的时候先从redis中读取,redis中没有的话再从数据库中读取并存入redis中。
这个流程看着没什么问题,但有非常重要的一点需要确认,就是如果数据库中的数据修改了,怎么去通知redis更新数据。换而言之,也就是如何保证缓存数据和数据库数据的一致性?
缓存数据一致性
其实这个问题上到软件,下到硬件工程师都会遇到,也都有不同的解决方案。因为我大学的专业是嵌入式系统,所以对于硬件的缓存也有所耳闻。如cpu需要保证自身的多级高速缓存间的数据一致性,以及缓存和内存间的数据一致性等。而我们软件因为查询数据的来源不同,所以对应的每级缓存也不同。
多级缓存概念
多级缓存或者多级存储这个概念可能不是很好理解,大致意思是说我们需要的数据,我们第一时间去哪里找,那么这个地方就叫做一级缓存。如果一级缓存没找到,再去找的地方就被称作二级缓存,以此类推。那为什么叫做缓存?大致是为了突出一个临时存储以及访问速度快的特点吧,大约就是数据暂缓存储区以及查找缓冲区的一个意思。
临时的两级存储框架
说回到我们的项目,我们将常访问的数据从数据库中复制到redis中一份,每次访问先从redis中读取,读不到再从数据库中读取。所以可以认为我们当前的一级缓存是redis,二级缓存是数据库。当数据量没有到非常庞大的时候,只要保证了缓存一致性,用这套方案也不会有什么问题。但如果从redis访问的数据频率过高,超过了redis所在服务器的带宽呢?
接入缓存框架的两个问题
第一个问题就是我最开始说的,数据一致性问题。第二个是刚提到的redis带宽成为瓶颈的问题。如果将我遇到的这两个问题更通用性地梳理一遍,那就是各级缓存间的数据一致性保证方法和缓存遇到瓶颈时如何去提升。
数据一致性方案
我能想到的有两种解决方案,第一种是定时刷新,第二种是修改通知。如果对于允许有读取到旧数据的场景,那么定时刷新肯定是比较好的方案,因为实现起来简单。但是如果不希望读到旧数据,那么就需要在数据被修改的时候通知到上一级缓存,让上一级缓存把旧数据删了。当下一次需要用到数据的时候,上一级缓存就会来重新获取数据并保存了。但是这种情况也有问题,如果不提前存到缓存中会导致第一次访问时过慢。如果提前存入缓存会导致当上一级缓存被清空时,大量请求数据会同时到达下一级缓存那里,造成拥塞。但这些也都是有对应的解决方案的。
缓存遇到瓶颈
还记得我们为什么要引入缓存么?因为数据库遇到了瓶颈。那引入的redis缓存遇到瓶颈了怎么办呢?同样的解决方案,引入更快速的缓存。但别忘了,一定要有保证数据一致性的方案。Redis这一级别的缓存,可以认为是放在内存中的,难道我们要引入比内存更高效的cpu的高速缓存么?我们软件也不具备这个权利啊。有一点我刚才有提到,redis瓶颈是因为带宽的原因,因为redis是一个用网线连接的“内存”。所以,我们可以使用的更高效的缓存就是本地内存。于是,后期的优化方案可以改为一级缓存为内存,二级缓存为redis,三级缓存为数据库。
最后
如果是以前,我一定会按照我的想法全部自己写一套缓存框架。但是后来发现我在大学时期自己想出来的一些好的框架,都有对应的更好用的开源框架(对于这个之后我可以专门写一篇博客)。之后到底是我们团队自己写,还是用现有的开源的框架,已经不重要了。重要的是我在这次遇到的这个问题中收获了自己的思考。