在很多时候,我们不是很在意cache和buffer这两个概念的区别,头脑中只有一个次“缓冲”。最近在看MySQL的优化,里面经常提及到cache和buffer这两个词,比如query_cache_size,table_open_cache,innodb_buffer_pool_size,join_buffer_size,key_buffer_size,read_buffer_size。
cache和buffer共同目的是提高系统I/O的效率。cache更偏重于读操作的效率,而buffer更多场合是提高写操作的效率。当然,对于cache和buffer,读和写都存在的。
cache:提高读取数据的效率,对于cache而言,经常存在“命中率”这个词与之对应。比如MySQL的query cache,如果出现相同的查询语句,则直接从cache中返回查询结果,即cache命中一次。MySQL不再去访问磁盘读取数据进行查询,减少磁盘的I/O次数。读取内存和读取磁盘的效率不可同日而语。现在的软件实现的缓存机制,如memcached,可以减少Web应用对MySQL服务的查询次数。buffer:经常使用的一个场景是,把要写入磁盘的数据放入预先申请好buffer(一块内存区),然后一次性写入磁盘。这样做的好处是把随机I/O转化成顺序I/O,减少磁头的寻道次数和移动次数,可以大幅度提高磁盘的I/O效率。
顺序I/O:从磁盘上连续的物理位置进行读写数据,磁头只需要一次寻址。随机I/O:从磁盘上不连续的物理位置进行读写数据,每次读写数据需要重新进行寻址,而磁盘操作最消耗时间的就是磁头的寻址操作。
MySQL的InnoDB存储引擎使用事务日志,当事务提交之后,不是立即把更新的数据写入到磁盘,而是写入到事务日志中(内存中)。一段时间之后,根据事务日志再把数据更新到磁盘页面中,这样可可以进行的连续页面写入操作,即把随机I/O转化成顺序I/O。而事务日志也不是每次都写入到磁盘上日志文件中,事务日志申请连续的物理空间,这样也是顺序I写入磁盘。事务日志持久化之后,内存的数据可以慢慢的刷回到磁盘中(flush)。这种预写式日志(write-ahead logging)修改数据需要写两次磁盘。buffer在MySQL中也可以用作读缓冲区,如read_buffer。对与每个线程而言,buffer是独占的,而cache经常可以在不同线程之间是共享的。cache存在共享的特性,因而cache的生命周期很长,如MySQL的线程缓冲池和查询缓冲池,减少MySQL服务器的开销。相比buffer的生存时间比较短,可能因为线程执行结束而释放掉。
在free、vmstat等t命令中显示的buffer和cache,它们都是占用内存:
buffer : 作为buffer cache的内存,是块设备的读写缓冲区,更靠近存储设备,或者直接就是disk的缓冲区。
cache: 作为page cache的内存, 文件系统的cache,是memory的缓冲区
总结来说, cache与buffer他们的使用目的。cache主要目的解决不同的物理设备读写速率差别很大一种缓存机制,如CPU与内存的速率差别很大,它们之间存在高速缓存;内存与硬盘的读写速率也差别也很大,存在磁盘高速缓存(disk cache)。特别是当从低速设备中读取数据的时候,cache能够提高系统的I/O效率,高速设备不必每次等待低速设备的数据传输。如cpu可以从高速缓存cache中取出需要的数据,如果不存在,再去内存RAM中读取数据。cache利用数据访问局部性原理。buffer主要是改变磁盘的数据写入方式。当有数据需要写入磁盘时,不是每次都立即进行,而是先把数据写入buffer,然后一起写入到磁盘中。这样可以把一些随机I/O变成顺序I/O,某些时候也可以减少磁盘(块设备)的I/O次数,提高磁盘的读写效率。