mysql缓存机制——写缓存篇

    前一篇的博客对innodb的读缓存做了解读。
    那么innodb是否只有对读取做了优化呢?
    对于我所从事的网络游戏业务而言,的确是一个读多写少的场景,但是并不意味着所有场景都是如此。
    首先的一点,数据库需要保证安全性,所以每一次写入数据库的时候,都会产生redo log,用来在数据库崩溃的时候进行回滚,同时,如果开启了binlog,那么数据库也会在每一条sql语句执行之后记录一条binlog,binlog是直接写入磁盘的,但是binlog是有自己的机制去管理的,与写操作的效率无关,这里可以排除其影响
    这里探究的是数据落盘的原理:
    我们知道,数据库拥有读缓存的功能,部分页会被从磁盘读到内存中来,那么当一个页在内存中时,发生了写操作,这个时候应该如何处理呢?
    当要修改的数据页在内存中时,数据库采用的方式是将数据写入内存中,而不是直接写入磁盘中,然后再将redo log写入到磁盘。那么当这个数据页被从缓存中淘汰的时候,这些“脏数据页”就会被同步地写入磁盘,等于是将这期间发生的n次的落盘合并成了一次落盘。因为redo log是落盘的,所以即使数据库崩溃,缓存中的数据页全部丢失,也可以通过redo log将这些数据页找回来
    (redo log是数据库用来在崩溃的时候进行数据恢复的日志,redo log的写入策略可以通过参数控制,并不一定是每一次写操作之后立即落盘redo log,在部分参数下,redo log可能是每秒集中写入一次,也有可能采取其他落盘策略,但是无论采用什么方式,redo log的量都是不会减少的,与数据写入的覆盖性不同,后一条redo log是不会覆盖前一条的,而是增量形式的,因此写redo log的操作,等同于是对磁盘某一小块区域的顺序I/O,而不像数据落盘一样随机在磁盘里写入,需要磁盘在多个地方移动磁头。所以redo log的落盘是IO操作当中消耗较少的一种,比数据直接刷回磁盘要优很多)
    那么当一个页不在内存中时,发生了写操作,这个时候应该如何处理呢?
    正常思路是将这个页读到内存中,然后对其进行写操作,然后再进行一次正常的内存写操作和redo log的磁盘写操作。但是对于写多读少的业务,每一次写操作不命中内存就需要一次磁盘读操作,这显然会影响性能。
    innodb对这里的写入操作进行了优化:写操作并不会立即写入到磁盘,而是只记录缓冲变更,等未来数据从磁盘真正被读出来的时候,才会将缓冲变更合并到缓冲池里,这种做法可以有效减少写操作时候的磁盘读取,提高数据库性能,这里对于数据变更的缓存区,就是写缓冲
    写缓冲等于是将写操作没有命中缓存的情况转化为了命中缓存的情况,由于redo log依然是按策略落盘的,可以理解为数据是安全的,而写缓存的数据也不是长期保留在缓存里的,数据库有策略定期将写缓存中的数据写入磁盘的操作,这里的写缓冲写入策略可以由数据库参数控制(有的采取定时写入,有的采取满则写入,也有的采取闲时写入)
    注意:当数据库全都是唯一索引的时候,写缓冲是没有办法工作的,因为不将所有数据都读出来,没有办法判断这次写操作是否合法,是否符合唯一索引的条件
    相关参数:innodb_change_buffer_max_size:写缓冲占整个缓冲池的大小比例,默认25%,对于写多读少的业务,才需要调大这个参数,对于读多写少的业务,可以调小该数值
    innodb_change_buffering:配置使用写缓冲的操作类型,可选all、none、update、deletes等

你可能感兴趣的:(mysql)