ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

Mysql占用内存过高 数据全在缓存?

2021-07-05 11:02:43  阅读:360  来源: 互联网

标签:缓存 buffer 缓冲 cache 全在 内存 Mysql 数据


Mysql占用内存过高 数据全在缓存?

top
合计(G) 说明
VIRT 14.236 进程申请的虚拟内存大小,申请不意味着分配,该值与实际内存消耗关系不大。
RES 1.9747 进程常驻内存,包含进程间共享内存。
SHR 0.0171 进程间共享内存,该值是推算出来的,存在误差,意义不大。

内存分为全局内存和线程内存

全局内存

  • innodb_buffer_pool_size Innodb 在mysql启动的时候一次性分配整个内存给bufferpool。占得比重很大,要重点关注。这个内存和你数据库访问量connections无关。如果你的数据访问量不大,但内存占用很高的话,就要要重点关注buffer pool相关的参数。
  • key_buffer_size。如果数据里面有很多myisam的表。这个参数就需要重点关注。所有相关表的请求都会占用到这块内存。

线程内存

首先这些参数并不是固定的,max_connections * 参数的值 然后加起来就可能是线程占用的缓存大小。如果你的访问量很大,连接数很多。下面参数就可能影响内存的占用。
每个参数都对应一种数据操作,所以你需要思考业务场景和sql代码到底哪一种操作多一些。

read_buffer_size 顺序读rows
sort_buffer_size 对表排序 sort by
read_rnd_buffer_size 随机读rows where条件多的
join_buffer_size 表关联join多的
tmp_table_size 临时表,通常是单行数据大,而且table整体很大的

什么是buffer/cache?

buffer和cache是两个在计算机技术中被用滥的名词,放在不通语境下会有不同的意义。在Linux的内存管理中,这里的buffer指Linux内存的:Buffer cache。这里的cache指Linux内存中的:Page cache。

翻译成中文可以叫做缓冲区缓存和页面缓存。在历史上,它们一个(buffer)被用来当成对io设备写的缓存,而另一个(cache)被用来当作对io设备的读缓存,这里的io设备,主要指的是块设备文件和文件系统上的普通文件。

但是现在,它们的意义已经不一样了。在当前的内核中,page cache顾名思义就是针对内存页的缓存,说白了就是,如果有内存是以page进行分配管理的,都可以使用page cache作为其缓存来管理使用。

当然,不是所有的内存都是以页(page)进行管理的,也有很多是针对块(block)进行管理的,这部分内存使用如果要用到cache功能,则都集中到buffer cache中来使用。

(从这个角度出发,是不是buffer cache改名叫做block cache更好?)然而,也不是所有块(block)都有固定长度,系统上块的长度主要是根据所使用的块设备决定的,而页长度在X86上无论是32位还是64位都是4k。

明白了这两套缓存系统的区别,就可以理解它们究竟都可以用来做什么了。

什么是page cache?

Page cache主要用来作为文件系统上的文件数据的缓存来用,尤其是针对当进程对文件有read/write操作的时候。

如果你仔细想想的话,作为可以映射文件到内存的系统调用:mmap是不是很自然的也应该用到page cache?在当前的系统实现里,page cache也被作为其它文件类型的缓存设备来用,所以事实上page cache也负责了大部分的块设备文件的缓存工作。

Buffer与Cache 有何区别

cache是为了弥补高速设备和低速设备的鸿沟而引入的中间层,最终起到加快访问速度的作用。
而buffer的主要目的是进行流量整形,把突发的大数据较小规模的I/O整理成平稳的小数量较大规模的 I/O,以减少响应次数(比如从网上下电影,你不能下一点点数据就写一下硬盘,而是积攒一定量的数据以后一整块一起写,不然硬盘都要被你玩坏了)。

这两者还是有相关性的。首先cache是缓存,buffer是缓冲,虽然翻译有那么一个字的不同,但这不是重点。
为了说明这个问题,让我将他们分开来说:read cache(读缓存),read buffer(读缓冲),write cache(写缓存),write buffer(写缓冲)。
无论缓存还是缓冲,其实本质上解决的都是读写速度不匹配的问题,从这个角度,他们非常相似。

首先讨论读缓存跟读缓冲。读缓存跟读缓冲的最大区别在于,读缓存的目标数据是始终有效的,如果不从缓存中读取,也可以直接读取实际数据,只不过实际数据读取会慢一些,当这个数据在缓存中,读取速度将会变快。当一个缓存中的数据被多次读取,实际上就减少了该数据从慢速设备中读取的量,这就存在某种算法去选择「什么数据需要保存在cache中」,因为尽可能多的让cache命中能提高性能。先进入cache的数据不一定先被读取,甚至说进入cache的数据有可能永远不被读取就被清除了,因此read cache呈现出非常明显的随机访问特性。

而读缓冲buffer的数据则不是始终有效,而是实时生成的数据流,每当buffer满或者主动flush buffer的时候触发一次读取,对于小数据,这样可以减少读取次数,对于大数据,这可以控制单次读取的数据量。换句话说,无论数据量大还是小,单次读取数据量都按照buffer尺寸进行归一化了。通常来说,先喂给buffer的数据一定会先被读取,所有buffer的数据几乎一定会被读取,这是很明显的顺序访问特性。
【注】从上面的情况看到,读缓存以及读缓冲很明确的反应出了我所说的表面特性。而其本质特性在于cache的目标是减少读取总量每次cache命中都减小了读取总量。而buffer并不能减少读取总量,只能规整化每次读取数据的尺寸大小。

说到write cache跟write buffer?

我们先说write buffer,write buffer是read buffer的对应,对于小数据的写入,它需要填满write buffer再进行一次写入,对于大数据,大数据会被分割到buffer尺寸的大小分批写入。因此,write buffer 的用处在于使得每次写入的数据量相对固定。如果一次写入4k对某个设备来说效率最高,那么把buffer定为4k,小数据积攒到4k写一次,大数据分割到每个碎片4k多次写入,这样就是write buffer的用处。最后我们来说write cache。所谓write cache,就是要设法减少写入次数。也就是说,如果某些数据需要产生多次写入,那么使用cache就可以只将最终数据写入,导致最终写入数据减少。在实际应用中,我们有时会使用到write buffer跟write cache的合体形态。buffer本身需要规整尺寸,与此同时,buffer还允许多次随机写入,使得多次写入的数据只用写入最后一次,这属于cache的特性。BT软件使用的写缓存往往具有类似特性,因而这种形态它同时既是buffer又是cache。正因为在写入场合buffer跟cache没有那么明显的分界,所以才会有产生buffer跟cache究竟有啥区别的疑问。

简单结论:

  1. Buffer不是缓存,国内常用的翻译是缓冲区。
  2. 其次,大部分场景中,Buffer是特指内存中临时存放的IO设备数据——包括读取和写入;而Cache的用处很多——很多IO设备(例如硬盘、RAID卡)上都有Cache,CPU内部也有Cache,浏览器也有Cache。
  3. Buffer并非用于提高性能,而Cache的目的则是提高性能。
  4. 涉及到IO设备读写的场景中,Cache的一部分本身就是Buffer的一种。如果说某些场合Buffer可以提升IO设备的读写性能,只不过是因为Buffer本身是Cache系统的一部分,性能提升来自于Cache机制。
  5. Buffer占用的内存不能回收,如果被强行回收会出现IO错误。Cache占用的内存,除实现Buffer的部分外都可以回收,代价则是下一次读取需要从数据的原始位置(通常是性能更低的设备)读取。
  6. 在IO读写过程中,任何数据的读写都必然会产生Buffer,但根据Cache算法,可能会有相当部分数据不会被Cache。

把整个MySQL加载进内存中_MySQL中的这个池子,读取极快

Mysql 中数据是要落盘的,这点大家都知道。读写磁盘速度是很慢的,尤其和内存比起来更是没的说。但是,我们平时在执行 SQL 时,无论写操作还是读操作都能很快得到结果,并没有预想中的那么慢。

可能你会说我有索引啊,有索引当然快了。但是铁子,索引文件也是存储在磁盘上的,查找过程会产生磁盘 I/O。如果同时对某行数据进行多次操作,那岂不是要重复产生很多次磁盘 IO 吗?

可能你想到了,那我把数据存在内存里不就可以了吗?内存速度比磁盘快,这准没毛病。没错,那该怎么存呢? 这就是我们今天所要讲的主题——缓冲池(buffer pool)。

初识缓冲池

上边我们提到过了,执行 SQL 对某一行进行操作时,总不能每次都直接进行磁盘操作吧。这样是极其损害硬盘的,而且读取速度很慢。所以有一个缓冲地带————缓冲池。简单来说就是一块内存区域。它就是为了访问数据时避免每次都去磁盘读取,把最常访问的数据放在缓存里,提高数据的访问速度。看一下缓冲池在整个MySQL架构里处于什么样的地位,有一个整体的认识。

它的内部组成部分。在缓冲池中,除数据页和索引页外还有多种类型:

缓冲池的应用

当执行一条SQL时它有什么作用?
如果是读操作,要查找的数据所在的数据页在内存中时,则将结果返回。否则会把对应的数据页加载到内存中,然后再返回结果。
对于写操作,如果要修改的行所在的数据页 在内存中,则修改后返回对应的结果。如果不在内存中,则会从磁盘里将该行所对应的数据页读到内存中再进行修改。
到这里已经知道,为何操作磁盘慢,但执行SQL不慢。是因为缓存池的存在,很大程度上减少了磁盘I/O带来的开销。

缓冲池的预读机制

我们可以看出来,只要不存在或减少磁盘 I/O,执行速度自然就会变快。那么对于加载数据页这种无法避免的磁盘 I/O 来说是否有更好的方式呢?既然避免不了,那减少磁盘 I/O 的次数总可以吧?
这就是我们要讲的 Mysql 中「预读」的新特性,它是 Innodb 通过在缓冲池中提前读取多个数据页来优化 I/O 的一种方式。因为磁盘读写的时候,是按照页的方式来读取的(你可以理解为固定大小的数据,例如一页数据为 16K),每次至少读入一页的数据,如果下次读取的数据就在页中,就不用再去磁盘上读取了,从而减少了磁盘 I/O。

可以在命令行通过如下命令查看对应的页大小:

show variables like 'innodb_buffer_pool_size';

缓冲池的空间管理

缓存池这么好,为何不把所有的数据都放在缓存池里面呢?

  • 缓存的数据容易丢失
  • 缓存池也是有大小限制的(通过参数的设置)

如果所有的数据页都存在缓存里,那我怎么管理这些数据页呢?当我新写入的数据超过了这个缓存池设定的大小,会不会把其他数据页挤出去?

传统 LRU 淘汰法

缓冲池是基于传统的 LRU 方法来进行缓存页管理的,我们先来看下如果使用 LRU 是如何管理的。

LRU,全称是 Least Recently Used,中文名字叫作「最近最少使用」。从名字上就很容易理解了。

这里分两种情况:

  • 缓存页已在缓冲池中

这种情况下会将对应的缓存页放到 LRU 链表的头部,无需从磁盘再进行读取,也无需淘汰其它缓存页。
如下图所示,如果要访问的数据在 6 号页中,则将 6 号页放到链表头部即可,这种情况下没有缓存页被淘汰。

  • 缓存页不在缓冲池中

缓存页不在缓冲中,这时候就需要从磁盘中读入对应的数据页,将其放置在链表头部,同时淘汰掉末尾的缓存页
如下图所示,如果要访问的数据在 60 号页中,60 号页不在缓冲池中,此时加载进来放到链表的头部,同时淘汰掉末尾的 17 号缓存页。

是不是看上去很简单,同时也能满足缓冲池淘汰缓存页的方法?但是我们来思考几个问题:

  • 预读失效

上面我们提到了缓冲池的预读机制可能会预先加载相邻的数据页。假如加载了 20、21 相邻的两个数据页,如果只有页号为 20 的缓存页被访问了,而另一个缓存页却没有被访问。此时两个缓存页都在链表的头部,但是为了加载这两个缓存页却淘汰了末尾的缓存页,而被淘汰的缓存页却是经常被访问的。这种情况就是预读失效,被预先加载进缓冲池的页,并没有被访问到,这种情况是不是很不合理。

  • 缓冲池污染

还有一种情况是当执行一条 SQL 语句时,如果扫描了大量数据或是进行了全表扫描,此时缓冲池中就会加载大量的数据页,从而将缓冲池中已存在的所有页替换出去,这种情况同样是不合理的。这就是缓冲池污染,并且还会导致 MySQL 性能急剧下降。

冷热数据分离

这样看来,传统的 LRU 方法并不能满足缓冲池的空间管理。因此,Msyql 基于 LRU 设计了冷热数据分离的处理方案。

也就是将 LRU 链表分为两部分,一部分为热数据区域,一部分为冷数据区域。

当数据页第一次被加载到缓冲池中的时候,先将其放到冷数据区域的链表头部,1s(由 innodb_old_blocks_time 参数控制) 后该缓存页被访问了再将其移至热数据区域的链表头部。

为什么要等 1s 后才将其移至热数据区域呢?你想想,如果数据页刚被加载到冷数据区就被访问了,之后再也不访问它了呢?这不就造成热数据区的浪费了吗?要是 1s 后不访问了,说明之后可能也不会去频繁访问它,也就没有移至热缓冲区的必要了。当缓存页不够的时候,从冷数据区淘汰它们就行了。
另一种情况,当我的数据页已经在热缓冲区了,是不是缓存页只要被访问了就将其插到链表头部呢?不用我说你肯定也觉得不合理。热数据区域里的缓存页是会被经常访问的,如果每访问一个缓存页就插入一次链表头,那整个热缓冲区里就异常骚动了,你想想那个画面。

那咋整呢?Mysql 中优化为热数据区的后 3/4 部分被访问后才将其移动到链表头部去,对于前 1/4 部分的缓存页被访问了不会进行移动。

MySQL配置参数优化

关于MySQL配置文件优化参数这里不多赘述....本文详细解说了缓存、缓冲及个别参数
MySQL优化-innodb重要参数优化

标签:缓存,buffer,缓冲,cache,全在,内存,Mysql,数据
来源: https://www.cnblogs.com/homjun/p/14971443.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有