缓存类型:
1.InnoDB 缓冲池
2.MyISAM 键缓存
3.线程缓存
4.表缓存
5.数据字典(InnoDB的表缓存)
MySQL的IO:
1.InnoDB的IO
事务日志
InnoDB 怎么打开和刷新日志以及数据文件
2.MyISAM的IO
lock tables 延迟写入;
delay_key_write;
InnoDB 表空间:
独立表空间;
共享表空间;
双写缓冲;
配置MySQL 并发
1.Innodb 并发配置
并发值 = cpu 数量 * 磁盘数量 * 2;
两段处理 : 1.休眠10000微妙
2.持有一定的票据
2.MyISAM 并发配置
插入发生在末尾才能并发
基于工作负载的配置:
1.优化blog和text的场景
2.优化排序(Filesorts)
1.MySQL 配置的工作原理
1.找出mysql的配置文件
1.which mysqld
2./usr/sbin/mysqld --help --verbose | grep -A 1 -i 'default options'
2.语法,作用域和动态性
配置项设置都使用小写,单词之间用下划线或者横线隔开。下面是等价的:
log-error=/var/log/mysqld.log
log_error=/var/log/mysqld.log
配置项可以有多个作用域。有些设置是服务器级的(全局作用域),有些对每个连接是不同的(会话作用域),剩下的一些是对象级的。
许多会话级别变量跟全局变量相等,可以以为是默认值。如果改动会话级变量,它只会影响改动的当前连接,当连接关闭的时候所有的
参数变更都会失效。
除了在配置文件中设置变量,很多变量也可以在服务器运行时修改。mysql把这些视为动态配置变量。
set sort_buffer_size = <value>;
set GLOBAL sort_buffer_size = <value>;
set @@sort_buffer_size := <value>;
set @@session.sort_buffer_size := <value>;
set @@global.sort_buffer_size := <value>;
如果动态的设置了变量,要注意mysql关闭时可能丢失这些设置。
如果在服务器运行时修改了变量的全局值,这个值对当前会话和任何已经存在的会话都不起效果,这是因为会话的变量值是在连接创建时,
从全局值初始化来的。在每次变更之后,应该检查 show global variables 的输出,确认已经按照期望变更了。
有些变量使用了不同的单位,所以必须知道每个变量的正确单位。
许多变量可以通过使用后缀指定单位,如 1M 表示 100w 字节。然后,这只能在配置文件或者作为命令行参数时有效。当使用 sql的 set
设置命令时,必须使用数字 1048576,或者 1024 * 1024 这样的表达式。但在配置文件时不能使用表达式。
有个特殊的值可以通过 set 命令赋给变量 : DEFAULT。把这个值赋给会话级变量可以把变量设置为全局值,把它赋给全局变量可以设置为编译
内置的默认值。当需要重置会话级变量的值回到连接刚打开的时候,这是很有用的。建议不要对全局变量这么用,因为可能它做的不是你期望的,它
不会把值设置到服务器刚启动那个值。
3.设置变量的副作用
动态变量设置可能导致意外的结果,例如从缓冲中刷新脏块。务必小心那些可以在线修改的设置,因为它们可能导致数据库做大量的工作。
join_buffer_size //每一个关联分配的关联缓冲
table_cache //表可以被缓存的数量
key_buffer_size //一次性为键缓冲区分配所指定的空间,然后操作系统不会立刻分配内存,而是等到用的时候才真正分配。
table_cache_size(缓存的表数量) //不会立即生效,直到下次有线程打开表才有效果。当有线程打开表时,mysql 会检查这个值。如果值大于缓冲中表的数量,线程
可以把最新打开的表放入缓存;如果值比缓冲中的表数小,mysql将从缓冲中删除不常使用的表。
thread_cache_size(缓存的线程数量) //不会立即生效,直到下次有连接被关闭时产生效果。当有连接被关闭时,mysql检查缓存中是否还有其他空间来缓存线程。如果有
空间,则缓存该线程以备下次连接重用;如果没有空间,它将销毁该线程不再缓存。
query_cache_size //mysql启动时,一次性分配并初始化这块内存。如果修改这个值,mysql会立即删除所有缓存的查询,重新分配这块内存到指定大小,并重新初始化,可能
会花费较长的时间,在完成初始化之前服务器都无法提供服务,因为mysql在逐个轻量缓存的查询,不是一次性全部删掉。
read_buffer_size //mysql只有在查询需要使用时才会为该缓存分配内存,并且会一次性分配该参数到指定大小。
read_rnd_buffer_size //mysql只有在查询需要使用时才会为该缓存分配内存,并且只会分配需要的内存大小而不是全部指定的大小。
sort_buffer_size //mysql只有查询需要做排序操作时才会为该缓存分配内存,立刻分配到指定大小。
2.my.cnf 配置
[mysqld]
#general
#数据存储路径
datadir = /var/lib/mysql
#不要把socket文件和 pid 文件放到mysql编译默认位置
socket = /var/lib/mysql/mysql.sock
pid_file = /var/lib/mysql/mysql.pid
user = mysql
port = 3308
default_storage_engine = InnoDB
#InnoDB
#缓冲池大小,设置为服务器内存的 75%~80%
innodb_buffer_pool_size = <value>
innodb_log_file_size = <value> //该参数决定着mysql事务日志文件(ib_logfile0)的大小
innodb_file_per_table = 1
innodb_flush_method = O_DIRECT
#MyISAM
key_buffer_size = <value>
#logging
log_error = /var/lib/mysql/mysql-error.log
slow_query_log = /var/lib/mysql-slow.log
#other
tmp_table_size = 32M
max_heap_table_size = 32M
query_cache_type = 0
query_cache_size = 0
max_connections = <value>
thread_cache = <value>
table_cache = <value>
open_files_limit = 65535
[client]
socket = /var/lib/mysql/mysql.sock
port = 3306
//有一个更好的办法设置缓冲池大小
1.从服务器内存总量开始
2.减去操作系统的内存占用,如果mysql不是唯一运行在这个服务器上的程序,还需要扣掉其他程序可能占用的内存
3.减去mysql自身需要的内存,例如为每个查询操作分配的一些缓冲
4.减去足够让操作系统缓冲InnoDB日志文件的内存,至少是足够缓冲最近经常访问的部分。
5.减去其他配置的mysql缓冲和缓冲需要的内存,例如MyISAM的键缓存,或者查询缓存
6.除以105%,这差不多接近InnoDB管理缓冲池增加的自身管理开销
7.把结果四舍五入,向下取一个合理的数值。
3.检查mysql服务器状态的变化
//每个60s,查看服务器状态的增量变化
mysqladmin -u root -p extended-status -ri60
4.配置内存的使用
1.mysql可以使用多少内存
mysql 是单进程多线程的运行模式,32位Linux内核通常限制任意进程可以使用的内存量在2.5GB~2.7GB范围内。
2.每个连接需要的内存
mysql保持一个连接(线程)只需要少量的内存。你需要为高峰时期执行的大量查询预留好足够的内存。
3.为操作系统保留内存
操作系统也需要保留足够的内存给它工作。如果没有虚拟内存正在交换到磁盘,就是表明操作系统内存足够的最佳迹象。至少应该
为操作系统保留1GB~2GB的内存,建议以总内存的 5% 作为基准.
4.为缓存分配内存
如果服务器只运行mysql,所有不需要为操作系统以及查询处理保留的内存都可以作为mysql缓存。
相比其他,mysql需要为缓存分配更多的内存,它使用缓存来避免磁盘的访问。
下面是我们认为对大部分情况来说最重要的缓存:
1.InnoDB 缓冲池
2.InnoDB 日志文件和MyISAM数据的操作系统缓存
3.MyISAM 键缓存
4.查询缓存
5.无法手工配置的缓存,例如二进制日志和表定义文件的操作系统缓存
5.InnoDB 缓冲池
如果大部分都是InnoDB表,InnoDB缓冲池或者比其他任何东西都需要内存。InnoDB缓冲池不仅仅是缓存索引:它还会缓存行的数据,自适应哈希索引,插入
缓冲,锁,以及其他内部数据结构。InnoDB还使用缓冲池来帮助延迟写入,这样就可以合并多个写入操作,然后一起顺序地写回。总之,InnoDB严重依赖缓冲池。
很大的缓冲池也会带来一些挑战,例如,预热和关闭都会花费很长时间。如果有很多脏页在缓冲池里,InnoDB关闭时可能会花费较长时间,因为在关闭之前需要
把脏页写回数据文件。
6.MyISAM 键缓存
MyISAM的键缓存也被称为键缓冲,默认只有一个键缓存,但也可以创建多个。不像InnoDB和其他存储引擎,MyISAM自身只缓存索引,不缓存数据。
//得到索引存储占用的空间
select sum(INDEX_LENGTH) from information_schema.tables where ENGINE = 'MyISAM' ;
my.conf
key_buffer_1.key_buffer_size = 1G;
key_buffer_2.key_buffer_size = 1G;
//将表映射到对应的缓冲区
cache index t1,t2 in key_buffer_1;
//把表的索引预载入到缓冲中
load index into cache t1,t2;
//计算缓冲区的使用率
100 - ((Key_blocks_unused * key_cache_block_size) * 100 / key_buffer_size)
//从磁盘读取索引的请求次数
mysqladmin -u root -p extended-status -ri10 | grep -i 'key_reads'
MyISAM 使用操作系统缓存来缓存数据文件,通常数据文件比索引大。因此,把更多的内存保留给操作系统缓存而不是键缓存是有意义的。
即使,没有使用MyISAM表,依然需要将 key_buffer_size 设置为较小的值,例如32M,mysql服务器有时会在内部使用MyISAM表,例如 group by 语句
可能会使用 MyISAM 表做临时表。
7.线程缓存
线程缓存保存那些当前没有与连接关联但是准备为后面新的连接服务的线程。当一个新的连接创建时,如果缓存中有线程存在,MySQL从缓存中删除一个线程,并且
把它分配给这个新的连接。当连接关闭时,如果线程缓存还有空间的话,mysql又会把线程放回缓存。如果没有空间,就销毁这个线程。只要mysql在缓存里还有空闲
的线程,它就可以迅速的响应连接请求,因为这样就不用为每个连接创建新的线程了。
thread_cache_size 变了指定了mysql可以保存在缓存中的线程数。一般不需要配置这个值,除非服务器有很多连接请求。可以查看 threads_created 状态
的变量。一个好的观察方法是,观察 Threads_connected 变量并且设置 thread_cache_size 足够大以便能处理业务压力正常的波动。例如 threads_connected
通常保持在 100~120,则可以设置缓存大小为20.
8.表缓存
表缓存和线程缓存的概念是相似的,但存储的对象是表。每个在缓存中的对象包含相关表 .frm 文件的解析结果,加上一些其他数据。准确的说,在对象里的其他数据
的内容依赖于表的存储引擎。例如,MyISAM是表的数据和索引的文件描述符。对于 Merge 表则可能是多个文件描述符,因为 Merge表可以有很多的底层表。
表缓存设计是服务器和存储引擎之间分离不彻底的产物,属于历史问题。表缓存对InnoDB的重要性就小了很多,因为InnoDB不依赖它做那么多事情。尽管如此,InnoDB
也能从缓存中解析的 .frm 文件中获益。
在mysql5.1 版本中,表缓存分离成2部分:一个是打开表的缓存,一个是表定义缓存(通过 table_open_cache 和 table_definition_cache 变量来配置)。
9.InnoDB 数据字典
InnoDB 有自己的表缓存,可以称为表定义缓存或者数据字典,在目前的mysql版本中还不能对它进行定义。当InnoDB打开一个表时,就增加了一个对应的对象到数据字典。
每张表可能占用4kb或者更多内存。当表关闭的时候也不会从数据字典中移除它们。
因此,随着时间的推移,服务器可能发现内存泄漏,导致数据字典中的元素不断的增长。但这不是真的内存泄漏,只是没有对数据字典实现任何一种缓存过期策略。
另外一个性能问题是第一次打开表时会计算统计信息,这需要很多IO操作,所以代价比较高。相比MyISAM,InnoDB 没有将统计信息持久化,而是在每次打开表时重新计算,
在打开之后,每个一段时间或者遇到触发事件,也会重新统计信息。如果有很多表,服务器可能会花费数个小时来启动并完全预热,这个时候服务器可能会花费更多的时间在等待
IO操作,而不是做其他的事情。
5.配置MySQL的IO行为
通常保证数据立刻并且一致的写到磁盘是很昂贵的。如果能够冒险一点磁盘写可能没有真正持久化到磁盘的风险,就可以增加并发性和IO等待,但是必须决定可以容忍多大的风险。
1.InnoDB的IO配置
InnoDB 不仅允许控制怎么恢复,还允许控制怎么打开和刷新数据(文件),这会对恢复和整体性能产生巨大影响。尽管可以影响它的行为,InnoDB的恢复流程实际上还是自动的,
并且经常在 InnoDB 启动时运行。
InnoDB 事务日志
InnoDB 使用日志来减少提交事物时的开销。因为日志中已经记录了事务,就无需在每个事务提交时把缓冲池的脏块刷新到磁盘中。事务修改的数据和索引通常会映射到表空间的随机
位置,所以刷新这些变更到磁盘需要很多随机IO。InnoDB假设使用的是常规磁盘(机械磁盘),随机IO比顺序IO要昂贵很多,业务一个IO请求需要把磁头移到正确的位置,然后等待磁盘上
读取需要的部分,再转到开始位置。
InnoDB 用日志把随机IO变成顺序IO。一旦日志安全写到磁盘,事务就持久化了,及时变更还没有写到数据文件。如果一些糟糕的事情发生了,InnoDB可以重放日志并且恢复已经提交的
事务。
当然,InnoDB最后还是必须把变更写到数据文件,因为日志有固定的大小。InnoDB的日志是环形方式写的:当写到日志的尾部,会重新跳转到开头继续写,但不会覆盖还没应用到数据文件
的日志记录,因为这样做会清掉已经提交的事务的唯一持久化记录。
InnoDB 使用一个后台线程智能的刷新这些变更到数据文件。
通过观察 innodb_os_log_written 状态的变化来查看InnoDB对日志文件写出了多少数据。show status like 'innodb_os_log_written'; 一个好的经验法则是,查看10~100s
间隔的数字,然后记录峰值。可以用这个来判断日志缓冲是否设置的正好。
InnoDB 怎么刷新日志缓冲。当InnoDB把日志缓冲刷新到磁盘文件时,会先使用一个 Mutex 锁住缓冲区,刷新到所需要的位置,然后移动剩下的条目到缓冲区前面。当Mutex释放时,可能有
超过一个事务已经准备好刷新起日志记录。InnoDB有一个 Group Commit 功能,可以在一个IO操作内提交多个事务。
日志缓冲必须被刷新到持久化存储,以确保提交的事务完全被持久化了。如果和持久化相比更在乎性能,可以修改 innodb_flush_log_at_trx_commit 变量来控制日志缓冲刷新的频繁程度。
可能的设置如下:
0 :把日志缓冲写到文件,并且每秒刷新一次,但是事务提交时不做任何事情
1 :将日志缓冲写到日志文件,并且每次事务提交时都会刷新到持久化存储。这是默认的,该设置能保证不会丢失任何已经提交的事务,除非磁盘或者操作系数是伪刷新。
2 :每次提交时把日志缓冲写到日志文件,但是不刷新。InnoDB每秒做一次刷新。0与2最重要的不同是(也是2为什么更合适),如果mysql进程挂了,2不会丢失任何事务,
但如果整个服务器挂了,则还是可能会丢失一些事务。
了解清楚 '把日志缓冲写到日志文件' 和 '把日志刷新到持久化存储' 之间的不同是很重要的。在大部分操作系统中,把缓冲写到日志只是简单的把数据从InnoDB的内存缓冲转移到了操作系统
的缓存,也就是内存里,并没有真的把数据写到了持久化存储。
因此,如果mysql 挂了,0和2通常会导致最多丢失一秒的数据,因为数据只是存在于操作系统的缓存。我们说的通常,因为不论如何 InnoDB会每秒尝试刷新日志文件到磁盘,但在一些场景下,
也可能丢失超过1s的事务,例如当刷新被推迟了。
与此相反,把日志刷新到持久化存储意味着InnoDB请求操作系统把数据刷出缓存,并且确认写到磁盘了。这是一个阻塞IO的调用,直到数据被完全写回才会完成。因为写数据到磁盘比较慢,当
innodb_flush_log_at_trx_commit 被设置为1时,可能明显的降低InnoDB每秒可以提交的事务数。
有时硬盘控制器或者操作系统假装做了刷新,其实只是把数据放到了另外一个缓存。
高性能事务处理需要的最佳配置是 innodb_flush_log_at_trx_commit 设置为1并且把日志文件放到一个有电池保护的写缓存的 RAID 卷中,这兼顾了安全和速度。
InnoDB 怎么打开和刷新日志以及数据文件:
使用 innodb_flush_method 选项可以配置InnoDB如何跟文件系统互相作用。从名字看来,会以为只是影响InnoDB怎么写数据,实际上还影响了 InnoDB如何读数据。可能的值:
1.fdatasync
这在非windows系统上的默认值:InnoDB用fsync()来刷新数据和日志文件。InnoDB通常使用fsync()替代fdatasync()。fdatasync()跟fsync相似,但只是刷新文件的
数据,而不包括元数据(最后的修改时间等等)。因此,fsync()会导致更多的IO。
使用fsync的缺点是操作系统至少会在自己的缓存中缓冲一些数据。
2.O_DIRECT
InnoDB对数据文件使用 O_DIRECT 标记或者 directio() 函数,这依赖于操作系统。
这个设置依然使用了 fsync()来刷新文件到磁盘,但是会通知操作系统不要缓存数据,也不要预读。这个选项完全关闭了操作系统缓存,并且使所有的读和写都直接通过存储设备,
避免了双重缓冲。
在大部分系统上,这个实现用 fcntl() 调用设置文件描述符 O_DIRECT 标记。
3.ALL_O_DIRECT
这个选项在 MariaDB中可用。它使得服务器在打开日志文件时,也能使用标准的MySQL中打开数据文件的方式(O_DIRECT)。
4.O_SYNC
这个选项使日志文件调用 open() 函数时设置 O_SYNC 标记。它使得所有的写同步---换个说法,只有数据写到磁盘后写操作才返回。这个选项不影响数据文件。
O_DSYNC 标记和 O_DIRECT 标记不同之处在于 O_SYNC 没有禁用操作系统层的缓存。因此,它没有避免双重缓冲,并且它没有使写操作直接到磁盘。用了O_SYNC标记,
它在缓存中写数据,然后发送到磁盘。
5.async_unbuffered
windows下的默认值。
6.unbuffered
只对 windows 有效。
7.normal
只对 windows 有效。
8.Nosync 和 littlesync
只为开发使用。
6.InnoDB 表空间
InnoDB把数据存储在表空间,本质上是由一个或者多个磁盘文件组成的虚拟文件系统。InnoDB用表空间实现了很多功能,病不只是存储表和索引。它还保存了回滚日志,插入缓冲,
双写缓冲,以及其他内部数据结构。
配置表空间:通过 innodb_data_file_path 配置项可以定制表空间文件。这些文件都放在 innodb_data_home_dir 指定的目录下。这是一个例子:
innodb_data_home_dir = /var/lib/mysql/
innodb_data_file_path = ibdata1:1G;ibdata2:1G;ibdata3:1G
这里在3个文件中创建了3GB的表空间。有时人们并不清楚可以使用多个文件分散驱动器的负载,像这样:
innodb_data_file_path = /disk1/ibdata1:1G;/disk2/ibdata2:1G;...
在这个例子中,表空间文件确实放在不同驱动器的不同目录中,InnoDB把这些文件首尾相连组合到一起。因此,通过这种方式并不能获得太多的收益,InnoDB先填满第一个文件,
当第一个文件满了再用第二个,如此循环;负载并没有真的按照希望的高性能方式分布。用raid控制器是分布负载的更聪明的方式。
为了允许表空间在超过了分配的空间时还能增长,可以像这样配置最后一个文件自动扩展:
...ibdata3:1G:autoextend
默认的行为是创建单个10MB的自动扩展文件。如果让文件自动扩展,那么最好的方式是给表空间大小设置一个上限,别让它扩展的太大,因为一旦扩展了,就不能收缩回来。
例如,下面的例子限制了自动扩展文件最多到2GB:
...ibdata3:1G:autextend:max:2G
管理一个单独的表空间可能有点麻烦,尤其是如果它是自动扩展的,并且希望回收空间时(因为这个原因,我们建议关闭自动扩展功能,至少设置一个合理的空间范围)。回收空间的
唯一方式是导出数据,关闭mysql,删除所有文件,修改配置,重启,让innodb创建新的数据文件,然后导入数据。
innodb_file_per_table 选项让innodb为每张表使用一个文件。它在数据字典存储为 '表名.idb' 的数据。这使得删除一张表时回收空间简单多了,并且可以容易的分散表到
不同的磁盘上。然后,把数据放到多个文件,总体来说可能导致更多的空间浪费,因为把单个innodb表空间的内部碎片浪费分布到了多个 .idb 文件。对于非常小的表,这个问题更大。
因为innodb的页大小是 16kb,即使表只有 1kb的数据,仍然至少需要16kb的磁盘空间。
即使打开了 innodb_file_per_table,依然需要为回滚日志和其他系统数据创建的共享表空间。没有把所有的数据存在其中是明智的做法,但最好还是关闭它的自动增长,因为无法
在不重新导入全部数据的情况下给共享表空间瘦身。
设置 innodb_file_per_table 也有不好的一面:更差的 drop table 性能。这可能导致显而易见的服务器端阻塞。原因如下:
1.删除表需要从文件系统层面去掉(删除)文件,这可能在某些文件系统(ext3)上会很慢。可以通过欺骗文件系统来缩短这个过程:把 .idb 文件链接到已给0字节的文件,然后手动
删除这个文件,而不用等待mysql来做。
2.当打开这个选项,每张表都在innodb中使用自己的表空间。结果是,移动表空间实际上需要innodb锁定和扫描缓冲池,查找属于这个表空间的页面,在一个有庞大的缓冲池的
服务器上做这个操作是非常慢的。
最终的建议是什么呢?我们的建议是使用 innodb_file_per_table 并且给共享表空间设置大小范围,这样可以过的舒服点。
7.双写缓冲
innodb 用双写缓冲来避免页没写完整所导致的数据损坏。当一个磁盘写操作不能完整的完成时,不完整的页写入就可能发生,16kb 的页可能只有一部分被写到磁盘上。双写缓冲在这种情况发生时,
保证数据完整性。
双写缓冲是表空间一个特殊的保留区域,在一些连续的块中足够保存100个页。本质上是一个最近回写的页面的备份拷贝。当innodb从缓冲池刷新页面到磁盘时,首先把它们写到双写缓冲,然后再把
它们写到其所属的数据区域中。这样保证每个页面的写入都是原子并持久化的。
这意味着每个页面都要写2遍?是的,但是因为innodb写页面到双写缓冲是顺序的,并且只调用一次 fsync()刷新到磁盘,所以实际上对性能的冲击是比较小的。
有些场景下,双写缓冲确实没有必要---例如,你也许想在备库上禁止双写缓冲。设置 innodb_doublewrite 为0,关闭双写缓冲。
8.其他IO配置项
sync_binlog 选项控制mysql 怎么刷新二进制日志到磁盘。默认是0,意味着 mysql并不刷新,由操作系统自己决定什么时候刷新缓存到持久化设备。如果这个值比0大,它指定了两次刷新到磁盘的
动作之间间隔多少次二进制日志写操作。把它设置为0和1意外的值是很罕见的。
如果没有设置sync_binlog为1,那么崩溃后可能导致二进制日志没有同步事务数据。这可能轻易地导致复制中断,并且使得及时恢复变得不可能。无论如何,可以把这个值设置为1来获得安全的保障。
像innodb日志文件一样,把二进制日志文件放到一个带有电池保护的写缓存的raid卷,可以极大的提升性能。
9.MyISAM 的IO配置
MyISAM 通常每次写操作之后就把索引变更刷新到磁盘。如果你打算在一张表上做很多修改,那么毫无疑问,批量操作会更快一些。一种办法是用 lock tables 延迟写入,直到解锁这些表。
通过设置 delay_key_write 变量,也可以延迟索引的写入。如果这么做,修改的键缓冲块直到表被关闭才会刷新。可能的配置如下:
OFF : MyISAM 每次写操作后刷新键缓冲中的脏块到磁盘,除非表被 lock tables 锁定了。
ON : 打开延迟键写入,但只是对 DELAY_KEY_WRITE 选项创建的表有效
ALL : 所有的MyISAM表都会使用延迟键写入
show variables like 'myisam_recover_options'; //打开这个选项通知mysql在表打开时,检查是否损坏,并且在找到问题时进行修复,可以设置的值如下:
default:
backup:
force:
quick:
10.配置MySQL并发
1.InnoDB 并发配置
innodb 有自己的 '线程调度' 控制线程怎么进入内核份数据,以及它们在内核中一次可以做哪些事情。最基本的限制并发的方式就是使用 innodb_thread_concurrency 变量,它会限制一次性可以
有多少个线程进入内核,0表示不限制。
并发值 = cpu 数量 * 磁盘数量 * 2
如果已经进入内核的线程超过了允许的数量,新的线程就无法进入内核。innodb 使用两段处理来尝试让线程尽可能高效的进入内核。两段策略减少了因操作系统调度引起的上下文切换。线程第一次休眠
innodb_thread_sleep_delay 微妙,然后再重试。如果它依然不能进入内核,则放入一个等待线程队列,让操作系统来处理。
第一阶段默认的休眠时间是 10000 微秒。当cpu有大量的线程在 '进入队列前的休眠'状态,因而没有被充分利用时,改变这个值在高并发环境里可能会有帮助。如果有大量小查询,默认值可能也太大了,
因而增加了10毫秒的查询延迟。
一旦线程进入内核,它就会有一定数量的'票据(Tickets)',可以让它免费的返回内核,不需要再做并发检查。innodb_concurrency_tickets 选项控制票据的数量。它很少修改,除非有很多运行时间
极长的查询。票据是按照查询授权的,不是按照事务。一旦查询完成,票据就销毁了。
除了缓冲池和其他结构的瓶颈,还有另一个提交阶段的并发瓶颈,这时候IO非常密集,因为需要做刷新操作。innodb_commit_concurrency 变量控制有多少个线程可以在同一时间提交。如果
innodb_thread_concurrency 配置得很低也有大量的线程冲突,那么这个选项可能会有帮助。
最后,有一个新的解决方案值得考虑:使用线程池来限制并发。
2.MyISAM 并发配置
在某些条件下,MyISAM 也允许并发插入和读取,这使得可以 '调度' 某些操作以尽可能减少产生阻塞。
理解 myisam 是怎么插入和删除行的。删除操作不会重新整理整个表,它们只是把行标记为删除,在表中留下'空洞'。myisam 倾向于在可能的时候填满这些空洞,在插入行时重新利用这些空洞。如果没有
空洞了,它就把新行插入表的末尾。
尽管myisam是表级锁,它依然可以一边读取,一边并发追加新行。这种情况下只能读取到查询开始时的所有数据,新插入的数据是不可见的。这样可以避免不一致读。
然后,若表中的某些数据变动了话,还是难以提供一致性读。mvcc是解决这个问题最流行的方法:一旦修改者创建了新版本,让就让读取者读数据的旧版本。可是 myisam 并不想 innodb 那样支持mvcc,
所以除非插入在表的末尾,否则不能支持并发插入。
通过设置 concurrent_insert 这个变量,可以配置myisam打开并发插入,可以配置如下值:
0 :myisam 不允许并发插入,所有插入都会对表加互斥锁
1 :这是默认值,只要表中没有空洞,myisam 就允许并发插入
2 : 这个值在mysql5.0 以及更新的版本中有效。它强制并发插入到表的末尾,及时表中有空洞。如果没有线程从表中读取数据,mysql将新行放到空洞里。使用这个设置通常会使得表更加碎片化。
如果合并操作可以更加高效,也可以配置mysql对一些操作进行延迟。可以通过 delay_key_write 变量延迟写索引。也可以让insert,replace,delete以及update 语句的优先级比select语句低,
设置 low_priority_updates 选项就可以了。可以让select获得相当好的并发。
11.基于工作负载的配置
1.优化blog和text的场景
服务器不能再临时表中存储blob值,因此,如果一个查询涉及blob值,又需要使用临时表---不管多小---它都会立即在磁盘上创建临时表。有2种方法解决:
1.通过 substring()函数把值转换为 varchar
2.或者让临时表更快一些(把它们放在基于内存的文件系统,tmpfs)
2.优化排序(Filesorts)
mysql有2种排序算法。如果查询中所有需要的列和 order by 的列总的大小超过 max_length_for_sort_data字节,则采用 two-pass。或者当任何需要的列---即使
没有被 order by 使用的列--是blob或者text,也会采用这个算法(可以使用 substring() 把这些)。
通过修改max_length_for_sort_data ,可以影响mysql选择使用哪种排序。因为single-pass 算法为每行需要排序的数据创建一个规定大小的缓冲,对于varchar列,
在和 max_length_for_sort_data 比较时,使用的是其定义的最大长度,而不是所存储数据的实际长度。这也是为什么我们建议只选择必要的列的一个原因。
当mysql必须排序blob或者text字段时,它只会使用前缀,然后忽略剩下部分的值。这是因为缓冲只能分配固定大小的结构体来保存要排序的值,然后从扩展存储空间中
恢复前缀到这个结构体中。使用max_sort_length变量可以指定这个前缀有多大。
12.完成基本配置
tmp_table_size 和 max_heap_table_size :
这2个设置控制使用 Memory 引起的内存临时表能使用多大的内存。如果隐式内存的临时表的大小超过这2个值,将会被转换为磁盘 MyISAM表,所以它的大小还可以继续增长。
临时表是一种并非自己创建,而是服务器创建,用于保存执行中的查询的中间结果的表。应该要把这2个变量设置为同样的值。但是要谨防太大。临时表最好保存在内存里,但是如果
它们被撑的很大,实际上还是让它们使用磁盘比较好,否则可能会让服务器内存溢出。
max_connections :
这个设置的作用就像一个紧急刹车,以保证服务器不会因为应用程序激增的链接而不堪重负。
观察 show status like 'Max_used_connections'; 这个是高水位标记,可以告诉你服务器连接是不是在某个时间点有个尖峰。如果这个值达到了 max_connections,
说明客户端至少被拒绝了一次。
thread_cache_size :
show status like 'Threads_connected'; 为 thread_cache_size 的 2~3倍
table_cache_size :
这个缓冲应该被设置的足够大,以避免总是需要重新打开和重新解析表的定义。你可以通过观察 Open_tables 的值及其在一段时间的变化来检查该变量。如果你看到 Open_tables
每秒变化很大,那么 table_cache 值可能不够大。
13.安全和稳定的设置
expire_logs_days :
如果启用了二进制日志,应该打开这个选项,可以让服务器在指定的天数之后清理旧的二进制日志。如果不启用,最终服务器的空间会被耗尽,导致服务器卡住或者崩溃。我们
建议把这个选项设置得足够从两个备份之前恢复。
max_allowed_packet :
这个设置防止服务器发送太大的包,也会控制多大的包可以被接收。
max_connect_errors :
如果有时网络短暂抽风了,或者应用配置出现错误,或者有另外的问题,如权限,在短暂的时间内不断的尝试连接,客户端可能会被列入黑名单,然后将无法连接,直到
再次刷新主机缓存。
skip_name_reslove :
这个选项禁用了另一个网络相关和鉴权认证相关的陷阱:dns查找。dns是mysql连接过程中的一个薄弱环节。要是dns有问题就悲剧了。
sql_mode :
这个设置可以接受多种多样的值来改变服务器行为。
下面的选项可以控制复制的行为:
read_only :
这个选项禁止没有特权的用户在备库做变更,只接受主库传过来的变更,不接受从应用来的变更。我们强烈建议把备库设置为只读模式。
skip_slave_start :
这个选项阻止mysql试图自动启动复制。
slave_net_timeout :
这个选项控制备库发现主库的连接已经失败并且需要重连之前等待的时间。
sync_master_info, sync_relay_log, sync_relay_log_info :
这些选项,在mysql5.5以及更新的版本中可用,解决了复制中备库长期存在的问题:不把它们状态文件同步到磁盘,所以服务器崩溃后可能需要人来猜测复制的位置
实际上在主库是哪个位置,并且可能在中继日志里有损坏。这些选项使得备库崩溃后,更容易从崩溃中恢复。默认不打开,因为它们会导致备库额外的fsync()操作。
overwrite_relay_log_info :
这个选项可以让innodb在事务日志中存储复制的位置,这完全是事务化的,并且不需要任何 fsync() 操作。
高级 InnoDB 设置 :
innodb :
如果把这个值设置为 FORCE,只有在 innodb 可以启动时,服务器才会启动。
innodb_autoinc_lock_mode :
这个选项控制 innodb 如何自动生成自增主键,某些情况下,例如高并发操作,自增主键可能是个瓶颈。如果有很多事务等待自增锁(可以在show engine innodb status)
看到,应该审视这个变量的设置。
innodb_buffer_pool_instances :
这个选项在 mysql5.5 和更新的版本中出现,可以把缓冲池切分为多段,这可能是高负载的多核机器上提升mysql可扩展性最重要的一个方式了。多个缓冲池分散了工作压力,所以
一些全局Mutex竞争就没那么大了。
innodb_io_capacity :
现在可以告诉innodb服务器有多大的IO能力。
innodb_read_io_threads, innodb_write_io_threads :
这些选项控制有多少后台线程可以被IO操作使用。
innodb_strict_mode :
这个设置让mysql在某些条件下把警告改成抛错,尤其是无效或者可能有风险的 create table 选项。
innodb_old_blocks_time :
1.MySQL 配置的工作原理
2.什么不该做
3.创建 MySQL 配置文件
4.配置内存使用
5.配置 MySQL 的 I/O 行为
- 配置 MySQL 并发
7.基于工作负载的配置
8.完成基本配置
9.安全和稳定的配置
10.高级InnoDB配置