2012年3月31日星期六

flush tables with read lock的一个潜在问题

    看了mysqlperformance的一篇关于flush tables with read lock的文章,里面提到了它可能引发一些问题。好了,现学现卖,分享给大家。
    现在很多的mysql备份工具在实现原理上都利用到了flush tables with read lock。这是为备份myisam表而设计的。像xtrabackup备份innodb表时并不会锁表,因为它也会备份在备份过程中新发生的事务日志,而对于myisam表的备份则是通过发出命令flush tables with read lock,然后拷贝myisam的相关表文件。那么在实际备份过程中可能会出现什么问题呢?答案是:有可能导致备份的时间严重的增长。下面来说说为什么会这样。
    flush tables with read lock,也就是将所有的脏页都要刷新到磁盘,然后对所有的表加上了读锁,于是这时候直接拷贝数据文件也就是安全的。但是如果你发出命令flush tables with read lock时,还有其他的操作,而起是很耗时的操作呢?先说写操作,这个FTWRL肯定是得等的,等写操作完成才能执行FTWRL,这个很好理解。那么对于其他的读操作呢?比如说在FLWRL发出之前有一个query:select count(*) from tb,那么FTWRL也得等待(show processlist可以看到 waiting for table flush)。你可能会说在mysql中读与读不是不会排斥的吗,为什么需要等待呢?因为FTWRL是要flush脏页的,只有这样才真的能保证数据一致性(比如说在xtrabackup备份myisam表的时候),而在select count(*) from tb执行的时候,因为所有的操作都是在内存中操作,所以此时还不能完全flush,因此FTWRL就得等待。或许你还会有疑问,select的页不是脏页,为什么FTWRL还要等待呢?难道mysql不能做得更完善点吗?我觉得mysql还不是不会做的这么简单吧,等待的原因是因为这个表很大,无法一次性将所有的页都读到内存中来,而query具有原子性,总不可能执行一般被堵塞吧,所以说还是得乖乖的让它执行然,所以FTWRL就得等待了。
    所以在利用xtrabackup、ibbackup这种备份工具的时候,也要考虑到这点。

2012年3月25日星期日

mysql报错:two many connections/two many open files的解决方法

最近在论坛里面看到有几个朋友都发帖求助,原因是mysql报错:
[ERROR] Error in accept: Two many open files。
而且这位朋友还说他并没有同时打开这么多文件,那么这是什么原因呢?

首先,我们需要了解的是,在linux里面打开文件是以文件描述符(FD,file descripter)的形式打开的,每打开一次文件,那么os就分配给你一个文件描述符,对于同一个文件如果有多个进程打开,那么就可以分配多个文件描述符。

好了,现在我们回到这个问题上,这位朋友说他并没有一次性打开这么多的文件,怎么会出现这个问题呢?刚才说了,每个进程打开同一个文件都可能分配一个独立的FD,而mysql正是这么做的,每个session开打的数据文件的描述符都是独立的,而对于索引文件则是所有的session贡献,我先将手册里面的原话贴出来:


MySQL is multi-threaded, so there may be many clients issuing queries for a given table simultaneously. To minimize the problem with multiple client sessions having different states on the same table, the table is opened independently by each concurrent session. This uses additional memory but normally increases performance. WithMyISAMtables, one extra file descriptor is required for the data file for each client that has the table open. (By contrast, the index file descriptor is shared between all sessions.)

好了,那你现在应该明白了,为什么并没有同时打开那么文件,但是却有那么多的文件描述符。弄清楚问题,那么现在就来解决这个问题。
首先是增大table_open_cache,具体用法参考手册上说明
然后根本解决方法是在os上增大mysqld这个线程的最大开打文件数,在linux里面可以通过编辑文件 /etc/security/limits.conf
然后里面的信息如下:

# /etc/security/limits.conf
#
#Each line describes a limit for a user in the form:
#
#<domain>        <type>  <item>  <value>
#
#Where:
#<domain> can be:
#        - an user name
#        - a group name, with @group syntax
#        - the wildcard *, for default entry
#        - the wildcard %, can be also used with %group syntax,
#                 for maxlogin limit
#
#<type> can have the two values:
#        - "soft" for enforcing the soft limits
#        - "hard" for enforcing hard limits
#
#<item> can be one of the following:
#        - core - limits the core file size (KB)
#        - data - max data size (KB)
#        - fsize - maximum filesize (KB)
#        - memlock - max locked-in-memory address space (KB)
#        - nofile - max number of open files
#        - rss - max resident set size (KB)
#        - stack - max stack size (KB)
#        - cpu - max CPU time (MIN)
#        - nproc - max number of processes
#        - as - address space limit
#        - maxlogins - max number of logins for this user
#        - maxsyslogins - max number of logins on the system
#        - priority - the priority to run user process with
#        - locks - max number of file locks the user can hold
#        - sigpending - max number of pending signals
#        - msgqueue - max memory used by POSIX message queues (bytes)
#        - nice - max nice priority allowed to raise to
#        - rtprio - max realtime priority
#
#<domain>      <type>  <item>         <value>
#

这个里面可以对进程需要的很多资源进行配置,比如说我们现在需要就是onfile这个选项
open file
而且我们有两种配置方式,第一是针对用户组的形式,第二具体用户的形式
比如有mysql用户
mysql        soft    nofile          131072
上面就限制了mysql用户最大的打开文件数。同时可以通过ulimit命令来查看这些信息。

但有时候,我们遇到的不是two many open files 而是 two many connections,这个就是并发的连接数,通过修改参数mysql的max_connections来解决,但是需要注意的是当这个参数增大的时候,同时可能会引发two many open files的问题,原因上面已经解释过了。

自己并没有遇到过这个问题,只是简单模拟了一下,如果有错误,欢迎指正。


2012年3月24日星期六

shell命令 2>&1

在unix高级环境编程第三章的习题有一个问题:
./a.out > outfile 2>&1  # 1
./a.out 2&1 > outfile  # 2
问这两者有什么区别。

这个首先的说明几点:
1.在unix和类unix(linux之类)中以文件描述符的形式打开一个文件,这个文件描述符是一个非负数。
2.0代表标准输入,1代表标准输出,2代表标准错误输出
3.默认的情况下是1 所以> equal 1>,比如我们用文件描述符5打开了一个文件a,可以写成5>
4.shell命令的执行是从左往右

那么现在来看这两者有什么区别
对于第一条shell,首先是将a.out的内容标准输出,然后通过>(等价于1>,所以只对标准输出起作用)重定向到outfile,然后2>&1说明标准错误输出也往标准输出去,而由于之前标准输出以及重定向到了outfile,所以这里的错误输出也会重定向到outfile。

再看第二天shell,首先是a.out到标准输出,然后2>&1,所以标准错误输出也重定向到保准输出(注意此时的标准输出没有被重定向,所以默认是终端上),然后 > outfile ,这个说明此时再将标准输出到outfile,但是请注意标准错误输出2>不会也跟着被重定向到outfile,因为更改标准输出重定向在2>&1的后面。

至此你明白了吧,不信你可以自己试试这个结果,比如按照我下面的:

angbosen@db-9:~/shell-comand$ echo "aaa" > out.file 2>&1
angbosen@db-9:~/shell-comand$ cat out.file
aaa
angbosen@db-9:~/shell-comand$ echo "aaa" 2>&1 > out2.file
angbosen@db-9:~/shell-comand$ cat out2.file
aaa
angbosen@db-9:~/shell-comand$ cmd "aaa" 2>&1 > out2.file
-bash: cmd: command not found
hangbosen@db-9:~/shell-comand$ cmd "aaa" > out.file 2>&1
angbosen@db-9:~/shell-comand$ cat out.file
-bash: cmd: command not found

理解了吧,真的挺有意思的。


2012年3月23日星期五

mysql空用户(user列为空)带来的影响


今天搭建一个测试环境时,遇到了一个很隐蔽的问题。有必要分享一下

| user | password                                  | host               |
+------+-------------------------------------------+--------------------+
| root | *81F5E21E35407D884A6CD4A731AEBFB6AF209E1B | localhost          |1
| root |                                           | db-2.photo.xxx.org |2
| root |                                           | 127.0.0.1          |3
| root |                                           | ::1                |4
|      |                                           | localhost          |5
|      |                                           | db-2.photo.xxx.org |6
| sys  | *xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx    | db-2.photo.xxx.org |7
...
...
如上图所示,这个里面存在着两个用户名为空的情况。然后问题就是由此而起。

在本机(服务器,db-2.photo.xxx.org) mysql -usys -ppass -h`hostname` 或者 mysql -usys -ppass -h`hostname -i` 都提示无法连接。此时配置文件里面没有 --skip-name-resolve这个参数(DNS解析用的)而用户表里面明明有这个sys@db-2.photo.xxx.org 而且密码也对了啊?起初没有注意到这个空用户,没想到它的陷阱,搞了很久也没连上,后来只好请老大了,老大过来一看,直接drop user ''@db-2.photo.xxx.org(删掉这个空用户,老大V5),然后再连,OK 搞定。

这是什么原因呢?
因为mysql在验证权限的时候,首先是验证host列,如果host列在验证user列,再password列,而现在按照我之前的连接语句:按照host列首先找到第6行,然后发现这行的user列为空(空匹配所有用户名),所以匹配到了这条记录,然后发现这条记录的密码为空,而我的连接语句里面有密码,那么就会报错。

好了,你可能会说要是我在连接的时候 -h指定的是ip地址,而不是域名(db-2.photo.xxx.org)那么不就不会匹配到了这条记录么?但是我在前面说了--skip-name-resolve这个参数我没有指定,那么就会DNS解析,将域名解析成IP地址。所以还是会被匹配到的。于是我的连接语句改为 mysql -usys  -h`hostname -i` 或者  mysql -usys  -h`hostname` 此时就可以连接成功,但是请注意,虽然可以连接成功,但是实际上这个连上去的用户多大权限,也就是空用户所具有的权限。而且,我后来模拟的时候,将第6行的存放顺序(物理磁盘上)和第7行反过来(这个可以通过optimize 一下table,然后顺序插入两条用户记录解决,虽然不能说绝对的成功,因为插在磁盘上的哪个位置不是我们能控制的,但是除非你RP败坏,可能会出现后插入的记录在物理磁盘上反而在前面)然后再进行前面的连接测试  mysql -usys -ppass  -h`hostname -i` 或者  mysql -usys  -ppass -h`hostname`, ok没问题了。同时如果将上面的连接语句去掉 -p选项,那么就是密码错误,也不会再去判断第7行了(已经调换顺序的第7行)

所以解决办法就是:
1.刚装好mysql后就直接删除那个空用户
2.连接的时候,-h+ip连接,且在配置文件里面指定 --skip-name-resolve,这样同时还能消除DNS解析带来的性能影响

另外,如果直接指定了socket的话,也不会存在这个问题,此时连接就是通过socket,而不是tcp/ip。 同时,如果你在别的机器上连接肯定也没问题,因为空用户默认的host就是主机地址。

不明白mysql5.5为什么这样设计,在mysql5.1里面就没有这个空用户。

2012年3月20日星期二

正确理解innodb参数innodb_thread_concurrency


    看了这篇文章,曾经一度对innodb_thread_concurrency这个概念产生了混淆,先来回顾一下当时自己的错误理解:
首先查看了系统的信息,
innodb_thread_concurrency               | 8

--------
FILE I/O
--------
I/O thread 0 (thread id: 18578) state: waiting for completed aio requests (insert buffer thread)
I/O thread 1 (thread id: 18579) state: waiting for completed aio requests (log thread)
I/O thread 2 (thread id: 18580) state: waiting for completed aio requests (read thread)
I/O thread 3 (thread id: 18581) state: waiting for completed aio requests (read thread)
I/O thread 4 (thread id: 18582) state: waiting for completed aio requests (read thread)
I/O thread 5 (thread id: 18583) state: waiting for completed aio requests (read thread)
I/O thread 6 (thread id: 18584) state: waiting for completed aio requests (write thread)
I/O thread 7 (thread id: 18585) state: waiting for completed aio requests (write thread)
I/O thread 8 (thread id: 18586) state: waiting for completed aio requests (write thread)
I/O thread 9 (thread id: 18587) state: waiting for completed aio requests (write thread)

show engine innodb status出来的结果就有10 IO个线程,而innodb_thread_concurrency却为8
这是为什么呢?原来这个innodb_thread_concurrency指的是mysql调用innodb的线程最大并发数,大家知道由于mysql特有的插件式存储引擎架构,先上mysql架构图:


    所以上层要使用innodb存储引擎的时候,肯定是mysql开启线程去调用innodb存储引擎进行相关工作,所以这里的innodb_thread_concurrency指的就是innodb接受mysql线程调用的最大线程数,而不是在innodb内部工作的线程数。之前用show engine innodb status显示的线程就是innodb内部的线程。
    OK,问题解决了,顺便还提一句,还有一个参数thread_concurrency 这个代表的什么呢?
手册上有解释:This variable is specific to Solaris systems,而且在mysql5.6.1中就被废弃了

2012年3月18日星期日

[转载]运维必须要知道的几个Linux服务器监控命令


总结得相当全面,留下来以便查找

有些 Linux 发行版会提供 GUI 程序来进行系统的监控,例如 SUSE Linux 就有一个非常棒而且专业的工具 YaST,KDE 的 KDE System Guard 同样很出色。当然,要使用这些工具,你必须在服务器跟前进行操作,而且这些 GUI 的程序占用了很多系统资源,所以说,尽管 GUI 用来做基本的服务器健康状态监测挺好,但如果你想知道真正发生什么,请关掉 GUI 开始命令行之旅吧。

你应该只在需要的时候去启动 GUI ,不用的时候关掉它。如果要让服务器保持最佳性能,你应该将 Linux 服务器的运行级别 runlevel 设置为 3 ,就是控制台模式,当你需要图形化桌面的时候使用 startx 命令来启动它。

如果你的服务器启动后就直接进入图形界面,你需要修改配置 /etc/inittab 找到 initdefault 一样,将 id:5:initdefault 修改为 id:3:initdefault。

如果你没找到 /etc/inittab 文件,那就创建一个新的,文件内容增加 id:3 这么一行。这样下次服务器启动的时候就不会进入图形界面。如果你不想等到服务器重启的时候才生效,你可以执行 init 3 这个命令。

一旦你的服务器是在控制台模式下运行,你就可以开始我们接下来的内容。

iostat

iostat 命令用来显示存储子系统的详细信息,通常用它来监控磁盘 I/O 的情况。要特别注意 iostat 统计结果中的 %iowait 值,太大了表明你的系统存储子系统性能低下。

meminfo 和 free

Meminfo 可让你获取内存的详细信息,你可以使用 cat 和 grep 命令来显示 meminfo 信息:
# cat /proc/meminfo
另外你可以使用 free 命令来显示动态的内存使用信息,free 只是给你大概的内存信息,而 meminfo 提供的信息更加详细。

mpstat

mpstat mpstat是MultiProcessor Statistics的缩写,是实时系统监控工具。其报告与CPU的一些统计信息,这些信息存放在/proc/stat文件中。在多CPUs系统里,其不但能查看所有CPU的平均状况信息,而且能够查看特定CPU的信息。

netstat

Netstat 和 ps 命令类似,是 Linux 管理员基本上每天都会用的工具,它显示了大量跟网络相关的信息,例如 socket 的使用、路由、接口、协议、网络等等,下面是一些常用的参数:

1-a Show all socket information
2-r Show routing information
3-i Show network interface statistics
4-s Show network protocol statistics
nmon

Nmon, 是 Nigel's Monitor 的缩写,是一个使用很普遍的开源工具,用以监控 Linux 系统的性能。Nmon 监控多个子系统的性能数据,例如处理器的使用率、内存使用率、队列、磁盘I/O统计、网络I/O统计、内存页处理和进程信息。Nmon 也提供了一个图形化的工具。

要运行 nmon,你可以在命令行中启动它,然后选择要监控的子系统,这些子系统都对应有一个快捷键,例如输入 c 可查看 CPU 信息,m用于查看内存,d用来查看磁盘信息等,你也可以使用 -f 命令将 nmon 的执行结果保存到一个 CSV 文件中,便于日后分析。

在每日的监控工作中,我发现 nmon 是我最常用的工具。

pmap

pmap 命令用来报告每个进程占用内存的详细情况,可用来看是否有进程超支了,该命令需要进程 id 作为参数。

ps 和 pstree

ps 和 pstree 命令是 Linux 系统管理员最好的朋友,都可以用来列表正在运行的所有进程。ps 告诉你每个进程占用的内存和 CPU 处理时间,而 pstree 显示的信息没那么详细,但它以树形结构显示进程之间的依赖关系,包括子进程信息。一旦发现某个进程有问题,你可以使用 kill 来杀掉它。

sar

sar 程序是系统监控工具里的瑞士军刀。该程序包含三个工具:sar 用来显示数据,sa1 和 sa2 用来收集数据并保存。sar 可用来显示 CPU 使用率、内存页数据、网络 I/O 和传输统计、进程创建活动和磁盘设备的活动详情。sar 和 nmon 最大的不同就是 sar 跟适合用作长期的监控,而 nmon 可以让你快速的了解系统当前状态。

strace

strace 经常被认为是程序员调试的工具,但不止如此。它可以记录进程进行系统调用的详情,因此它也是一个非常好的诊断工具,例如你可以使用它来找出某个程序正在打开某个配置文件。
Strace 也有一个缺陷,但它在跟踪某个进程时会让该进程的性能变得非常差,因此请谨慎使用。

tcpdump

Tcpdump 是一个简单、可靠的网络监控工具,用来做基本的协议分析,看看那些进程在使用网络以及如何使用网络。当然,如果你要获取跟详细的信息,你应该使用 Wireshark (下面我们会介绍).

top

top 命令显示当前的活动进程,默认它是按消耗 CPU 的厉害程度进行排序,每5秒钟刷新一次列表,你也可以选择不同的排序方式,例如 m 是按内存占用方式进行排序的快捷键。

uptime

uptime 命令告诉你这台服务器从开机启动到现在已经运行了多长时间了。同时也包含了从启动到现在服务器的平均负载情况。

vmstat

你可以使用 vmstat 来监控虚拟内存,一般 Linux 上的开发者喜欢使用虚拟内存来获得最佳的存储性能。该命令报告关于内核线程、虚拟内存、磁盘、陷阱和 CPU 活动的统计信息。由 vmstat 命令生成的报告可以用于平衡系统负载活动。系统范围内的这些统计信息(所有的处理器中)都计算出以百分比表示的平均值,或者计算其总和。

Wireshark

Wireshark, 前身是 Ethereal ,是一个网络协议检测程序,让您经由程序抓取运行的网站的相关资讯,包括每一封包流向及其内容、资讯可依操作系统语系看出,方便查看、监控TCP session动态等等.

这里罗列的是大多数最有价值的 Linux 监控程序,如果你全都能够熟练运用,那么你肯定在linux管理方面非常得心应手了。

2012年3月14日星期三

innodb_thread_concurrency


看了这篇文章,曾经一度对innodb_thread_concurrency这个概念产生了混淆,先来回顾一下当时自己的错误理解:
首先查看了系统的信息,
innodb_thread_concurrency               | 8

--------
FILE I/O
--------
I/O thread 0 (thread id: 18578) state: waiting for completed aio requests (insert buffer thread)
I/O thread 1 (thread id: 18579) state: waiting for completed aio requests (log thread)
I/O thread 2 (thread id: 18580) state: waiting for completed aio requests (read thread)
I/O thread 3 (thread id: 18581) state: waiting for completed aio requests (read thread)
I/O thread 4 (thread id: 18582) state: waiting for completed aio requests (read thread)
I/O thread 5 (thread id: 18583) state: waiting for completed aio requests (read thread)
I/O thread 6 (thread id: 18584) state: waiting for completed aio requests (write thread)
I/O thread 7 (thread id: 18585) state: waiting for completed aio requests (write thread)
I/O thread 8 (thread id: 18586) state: waiting for completed aio requests (write thread)
I/O thread 9 (thread id: 18587) state: waiting for completed aio requests (write thread)

show engine innodb status出来的结果就有10 IO个线程,而innodb_thread_concurrency却为8
这是为什么呢?原来这个innodb_thread_concurrency指的是mysql调用innodb的线程最大并发数,大家知道由于mysql特有的插件式存储引擎架构,先上mysql架构图:


所以上层要使用innodb存储引擎的时候,肯定是mysql开启线程去调用innodb存储引擎进行相关工作,所以这里的innodb_thread_concurrency指的就是innodb接受mysql线程调用的最大线程数,而不是在innodb内部工作的线程数。之前用show engine innodb status显示的线程就是innodb内部的线程。
OK,问题解决了,顺便还提一句,还有一个参数thread_concurrency 这个代表的什么呢?
手册上有解释:This variable is specific to Solaris systems,而且在mysql5.6.1中就被废弃了