MySQL数据库的内存结构
Mysql服务器就一个这么大的内存段,但是又得为各个客户端提供服务。内存是如何进行分配和调度呢?
首先服务器会将内存分为很多类的信息,并且进行管理和运行。
第一个就是Thread Handler,线程处理的一段内存,因为服务器是多线程的,是面向多个客户端的。当有一个客户连接进来的时候,就会在内存空间开辟一段专属的内存提供处理环境。每一个客户端连接进来就会分配一个线程专门为客户端服务。如果超过了最大的连接数就会排队等待。
如在mysql线程池里面开了十个池子。假使最大的连接数为十个。当有一堆用户连接进来的时候那么会为用户分配线程。当达到最大连接数的时候,其他用户只能等待,如果有连接释放了其他用户就可以得到分配。
内存上面由服务器维护的很小很小一段缓冲,将每一个建立好的每一个线程的句柄,相当于银行服务的窗口。会将其缓冲下来,当缓冲没有满的时候,当有一个客户端断开了,那么这个线程就会重新放到缓存里面去。
有一百个线程,有一个专门的内存段,很小很小的缓冲cache,cache里面保存了每一个线程使用了哪一个地址段和地址空间有多大。这使得可以快速的访问到线程。假设cache里面可以容纳100个线程。当100个线程里面有一个客户端断开了连接,就会将为断开客户服务的线程信息插入到cache里面。内存段从哪里开始到哪里结束会作为信息插入到cache里面。当另外一个用户连接的时候就会在cache里面将刚刚那个空的线程分配给连接的用户。就复用空线程的内存地址段就行了。
如果缓存的空间还没有满的话,客户断开,就会将曾经使用过的线程放到缓存里面,为将来提供重用。如果线程不空,有一个客户连接进来,就从缓冲池里面拿一个线程给客户使用。
这样就避免了开辟太多的线程造成内存的浪费。
服务器会用一些其他的处理过程来保存我们的信息。如数据缓冲,避免了频繁的访问磁盘。磁盘是要寻道的,从内寻道到外寻道的环节是寻道的时间。数据在磁盘上是以同心圆的方式一圈圈发布出来的,磁头要从垂直状态寻道从里到外,有一个偏移的过程,这个偏移的过程就是寻找数据花费的时间。这个就是耗时的部分,瓶颈部分。
硬盘在逻辑上被划分为磁道、柱面以及扇区.
盘片被划分成一系列同心环,圆心是盘片中心,每个同心环叫做一个磁道,所有半径相同的磁道组成一个柱面。磁道被沿半径线划分成一个个小的段,每个段叫做一个扇区,每个扇区是磁盘的最小存储单元。为了简单起见,我们下面假设磁盘只有一个盘片和一个磁头。
当需要从磁盘读取数据时,系统会将数据逻辑地址传给磁盘,磁盘的控制电路按照寻址逻辑将逻辑地址翻译成物理地址,即确定要读的数据在哪个磁道,哪个扇区。 为了读取这个扇区的数据,需要将磁头放到这个扇区上方,为了实现这一点,磁头需要移动对准相应磁道,这个过程叫做寻道,所耗费时间叫做寻道时间,然后磁盘 旋转将目标扇区旋转到磁头下,这个过程耗费的时间叫做旋转时间。
即一次访盘请求(读/写)完成过程由三个动作组成:
1)寻道(时间):磁头移动定位到指定磁道
2)旋转延迟(时间):等待指定扇区从磁头下旋转经过
3)数据传输(时间):数据在磁盘与内存之间的实际传输
服务器为了避免经常去磁盘上读取表数据会建立各种缓存保存信息。
(1)赋权表缓存:当一个用户发出查询向mysql的服务端的mysqld进程。这个时候mysqld就会检查是否人人都会对某张表具有select权限。所以第一件事情就是去检查mysql数据库里面的表,因为mysql数据库里面存放了用户的权限。在mysql数据库里面查询到该用户有权限,会去对应的数据表里面找数据块,将信息反馈给客户端。当用户第二次又来查询同一张表的时候又要去mysql数据库里面查询该用户是否具有权限。如果不用缓存就要去磁盘上面读取表里面的数据块做校验,这样会产生io,这样性能不高。对于有几十万个人上线的应用的话,那么数据库的性能是极其的低下。可能每秒并发的连接达到数千以上,磁盘会被不停的被访问到。所以当用户第一次向服务端发出请求,会将用户的权限,以及哪台主机可以连接进来,访问哪个数据库,那张表,哪个列,是否可以进行读写操作等等这些信息都会被缓存到内存。这只需要很少的内存。
如一个root用户第一次发出一条语句到服务端
这里有许多权限,在保存在内存的时候不会将权限的英文名称保存到内存里面,而是用1,0二进制的形式表示权限是否具有,可能一比特都不到,这样就节省了空间。如果有255个权限,那么通过1,0表示,2的八次方就可以表示,即一个字节就可以表示。
所以即使有成千上万个用户,并不需要耗费许多许多内存,一旦将权限表的信息存储进了内存,当用户发起第一次连接的时候,就在mysql内存里面形成了一张权限表。用户要select就在权限表里面进行快速的检测是否有select权限。有select权限就可以去数据库里面拿数据了。
(2)键值缓存:这个和索引机制有关,可以将索引查过的信息缓存。先查索引,这个数据找到之后再去找对应的数据块,提高访问效率。
(3)表的缓存:将曾经打开过的表,这些表是怎么定义的,也将其缓存进去。也就是说表有一个.frm的文件,里面有哪些字段以及字段是多长,这些信息也缓存到内存里面。当第二次查询的时候从缓存里面查找字段就可以了。也避免去磁盘上渡.frm文件。当有很多很多人去查同一张表的时候,由于内存里面有该表的定义,所以直接从内存里面读取表结构就行了。没有打开的表不会将其缓存进去,不会将不常用的表缓存进去。所以表缓存就是将用户打开的表,把这个表的结构进行缓存。
推荐阅读