http://www.percona.com/files/presentations/WEBINAR-MySQL-SSD.pdf
http://www.percona.com/files/presentations/WEBINAR-zero-downtime-schema-changes.pdf
相关的视频在http://www.percona.tv/上面找找看。。。。
http://www.percona.com/files/presentations/WEBINAR-MySQL-SSD.pdf
http://www.percona.com/files/presentations/WEBINAR-zero-downtime-schema-changes.pdf
相关的视频在http://www.percona.tv/上面找找看。。。。
使用pt-table-checksum检查主从复制是否正常
半个月前写过一篇文章,说了说《mysql主从需要注意的几个问题》。
其实对于一个小小的DBA来说,有时候是无法避免这些问题的。
于是我们就需要一个工具,来检查主从复制是否正常,是否出现了错误。
pt-table-checksum。
在主服务器上 checksum mysql数据库:
#pt-table-checksum --replicate=test.checksum --create-replicate-table --databases=mysql localhost TS ERRORS DIFFS ROWS CHUNKS SKIPPED TIME TABLE 04-24T16:06:45 0 0 0 1 0 0.099 mysql.columns_priv 04-24T16:06:45 0 0 32 1 0 0.100 mysql.db 04-24T16:06:45 0 0 0 1 0 0.096 mysql.event 04-24T16:06:45 0 0 0 1 0 0.096 mysql.func 04-24T16:06:45 0 0 38 1 0 0.102 mysql.help_category 04-24T16:06:45 0 0 452 1 0 0.106 mysql.help_keyword 04-24T16:06:46 0 0 993 1 0 0.096 mysql.help_relation 04-24T16:06:46 0 0 506 1 0 0.100 mysql.help_topic 04-24T16:06:46 0 0 0 1 0 0.099 mysql.host 04-24T16:06:46 0 0 0 1 0 0.104 mysql.ndb_binlog_index 04-24T16:06:46 0 0 0 1 0 0.107 mysql.plugin 04-24T16:06:46 0 1 1 1 0 0.115 mysql.proc 04-24T16:06:46 0 0 0 1 0 0.186 mysql.procs_priv 04-24T16:06:46 0 1 1 1 0 0.097 mysql.proxies_priv 04-24T16:06:47 0 0 0 1 0 0.097 mysql.servers 04-24T16:06:47 0 0 0 1 0 0.096 mysql.tables_priv 04-24T16:06:47 0 0 0 1 0 0.098 mysql.time_zone 04-24T16:06:47 0 0 0 1 0 0.097 mysql.time_zone_leap_second 04-24T16:06:47 0 0 0 1 0 0.100 mysql.time_zone_name 04-24T16:06:47 0 0 0 1 0 0.100 mysql.time_zone_transition 04-24T16:06:47 0 0 0 1 0 0.095 mysql.time_zone_transition_type 04-24T16:06:47 0 1 38 1 0 0.100 mysql.USER
只有在第一次运行的时候,需要 –create-replicate-table 选项,以后重复运行就不必了。
每个表的checksum值会保存到 test.checksum中,然后会被replicate到所有的从服务器。
然后就可以检测从服务器是否正常了。不过下面的命令依然是在主服务器上运行的:
$ pt-table-checksum --replicate=test.checksum --replicate-check-only --databases=mysql localhost
如果数据都一致的话,就不会有什么输出。否则可能会有下面的输出:
Differences ON ip-10-15-27-19 TABLE CHUNK CNT_DIFF CRC_DIFF CHUNK_INDEX LOWER_BOUNDARY UPPER_BOUNDARY mysql.USER 1 1 1
Ext3 Ext4这两种文件系统有一个特点,如果用的默认安装,
它会保留每个分区5%的空间,不允许非root用户使用。
事实上,我经手这么多服务器,从来都是保留5%,没有人会去改这个设置。
如果某个分区满了,可以释放这5%的空间,救个急总是OK的。
[root@db4 ~]# df -h Filesystem SIZE Used Avail Use% Mounted ON /dev/mapper/vg_centos-lv_root 30G 25G 3.4G 89% / tmpfs 3.9G 0 3.9G 0% /dev/shm /dev/sda1 243M 47M 183M 21% /boot /dev/mapper/vg_centos-lv_mysql 145G 145G 5.7M 100% /vol/mysql [root@db4 ~]# mount [..] /dev/mapper/vg_centos-lv_mysql ON /vol/mysql TYPE ext4 (rw,noatime,nodiratime) 可以看到是ext4的文件系统 [root@db4 ~]# dumpe2fs /dev/mapper/vg_centos-lv_mysql | grep 'Reserved block count' dumpe2fs 1.41.12 (17-May-2010) Reserved block COUNT: 1927884 保留了1927884个4KB的block。 正好是分区大小的5%。 [root@db4 ~]# tune2fs -m 0 /dev/mapper/vg_centos-lv_mysql tune2fs 1.41.12 (17-May-2010) Setting reserved blocks percentage TO 0% (0 blocks) [root@db4 ~]# df -h Filesystem SIZE Used Avail Use% Mounted ON /dev/mapper/vg_centos-lv_root 30G 25G 3.4G 89% / tmpfs 3.9G 0 3.9G 0% /dev/shm /dev/sda1 243M 47M 183M 21% /boot /dev/mapper/vg_centos-lv_mysql 145G 145G 7.3G 95% /vol/mysql 一下子又出来7个G的空间。
不过这种办法只能用一次~~
下次分区再满了,就去想其它办法吧。
另外,也应该搞个监控软件去监视分区的使用情况,尽早做出预警。
不太常见但是却很好用的linux工具
工具见这里:
http://kkovacs.eu/cool-but-obscure-unix-tools
最后一个cowsay 笑死人了。
还有dstat, 聚集了load average, network transfer, disk operation:
----total-cpu-usage---- ---paging-- ---load-avg--- ------memory-usage----- -net/total- ---procs--- --io/total- ---system-- ----tcp-sockets---- usr sys idl wai hiq siq| IN OUT | 1m 5m 15m | used buff cach free| recv send|run blk NEW| READ writ| INT csw |lis act syn tim clo 0 0 100 0 0 0| 0 0 |0.07 0.25 0.25| 866M 249M 537M 387M|1314B 180B| 0 0 0| 0 0 | 70 80 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.07 0.25 0.25| 866M 249M 537M 387M|1779B 1004B| 0 0 0| 0 0 | 84 78 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.07 0.25 0.25| 866M 249M 537M 387M| 904B 362B|1.0 0 1.0| 0 0 | 75 86 | 13 9 0 0 5 0 0 100 0 0 0| 0 0 |0.07 0.25 0.25| 866M 249M 537M 386M|2203B 1559B| 0 0 0| 0 0 | 180 127 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.07 0.25 0.25| 866M 249M 537M 386M| 260B 130B| 0 0 0| 0 0 | 53 66 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.07 0.25 0.25| 866M 249M 537M 387M| 52B 114B| 0 0 0| 0 0 | 54 77 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.07 0.25 0.25| 866M 249M 537M 387M|2271B 872B| 0 0 0| 0 0 | 94 79 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.07 0.25 0.25| 866M 249M 537M 387M| 52B 130B| 0 0 0| 0 0 | 54 74 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.07 0.25 0.25| 866M 249M 537M 387M|1126B 1254B| 0 0 0| 0 24.0 | 80 87 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.07 0.25 0.25| 866M 249M 537M 387M|1030B 130B| 0 0 0| 0 0 | 88 82 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.06 0.24 0.25| 866M 249M 537M 387M| 578B 114B| 0 0 0| 0 0 | 53 64 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.06 0.24 0.25| 866M 249M 537M 387M|1597B 890B| 0 0 0| 0 0 | 85 79 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.06 0.24 0.25| 866M 249M 537M 387M| 552B 114B| 0 0 0| 0 0 | 63 77 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.06 0.24 0.25| 866M 249M 537M 387M|1624B 1254B| 0 0 0| 0 0 | 81 75 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.06 0.24 0.25| 866M 249M 537M 387M| 478B 114B| 0 0 0| 0 0 | 67 73 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.06 0.24 0.25| 866M 249M 537M 387M| 418B 114B| 0 0 0| 0 0 | 59 74 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.06 0.24 0.25| 866M 249M 537M 387M|1265B 874B| 0 0 0| 0 0 | 82 73 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.06 0.24 0.25| 866M 249M 537M 387M| 758B 114B| 0 0 0| 0 0 | 60 80 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.06 0.24 0.25| 866M 249M 537M 387M|1236B 1255B| 0 0 0| 0 4.00 | 93 79 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.06 0.24 0.25| 866M 249M 537M 387M| 52B 130B| 0 0 0| 0 0 | 71 70 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.05 0.23 0.25| 866M 249M 537M 387M| 214B 114B| 0 0 0| 0 0 | 55 73 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.05 0.23 0.25| 866M 249M 537M 387M|1201B 890B| 0 0 0| 0 0 | 80 80 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.05 0.23 0.25| 866M 249M 537M 387M| 108B 114B| 0 0 0| 0 0 | 53 66 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.05 0.23 0.25| 866M 249M 537M 387M|1344B 1254B| 0 0 0| 0 10.0 | 119 85 | 13 7 0 0 5 0 0 100 0 0 0| 0 0 |0.05 0.23 0.25| 866M 249M 537M 387M| 172B 130B| 0 0 0| 0 8.00 | 80 82 | 13 7 0 0 5
dstat的更详细教程看这里:
http://dag.wieers.com/home-made/dstat/
[MODIFY@H209 ~]$ curl --head www.reddit.com HTTP/1.1 200 OK Content-TYPE: text/html; charset=UTF-8 Set-Cookie: reddit_first=%7B%22organic_pos%22%3A%201%2C%20%22firsttime%22%3A%20%22first%22%7D; DOMAIN=reddit.com; expires=Thu, 31 DEC 2037 23:59:59 GMT; Path=/ Server: '; DROP TABLE servertypes; -- Date: Thu, 17 May 2012 03:05:54 GMT Connection: keep-alive
看Server那一行。。。不知道是怎么搞出来的。
If you are using Apache mod_cgi to run PHP you may be vulnerable.
To see if you are, just add ?-s to the end of any of your URLs.
If you see your source code, you are vulnerable. If your site renders normally, you are not.
To fix this, update to PHP 5.3.12 or PHP 5.4.2.
据说这个bug存在至少8年了。。。
http://www.php.net/archive/2012.php#id2012-05-03-1
从mysqldump的备份中只恢复一张表
全部恢复当然简单了。
只恢复某个数据库的话,之前也总结过几个方法。
今天只讲如何从mysqldump的备份中恢复某张表:
先取出表结构:
# EXTRACT TABLE STRUCTURE FOR TABLE 'customer' sed -ne '1,/^-- \(Current\|Database\)/{/^\(--.*\)*\?$/d;p};/^-- Table.*`customer`/,/^-- \(Dumping\|Table\|Temporary\)/{/^\(--.*\)*\?$/d;/^DROP/d;p}' dump.SQL
取出数据:
# EXTRACT DATA dump FOR TABLE 'customer' sed -ne '1,/^-- \(Current\|Database\)/{/^\(--.*\)*\?$/d;p};/^-- Dumping.*`customer`/,/^-- \(Dumping\|Table\|Temporary\)/{/^\(--.*\)*\?$/d;p}' dump.SQL
还有一个shell脚本,既可以恢复某个库,也可以只恢复某张表:
http://www.dbasquare.com/downloads/
garfield ~ # ./extract.sh -f dump.sql -d redmine > redmine.sql garfield ~ # ./extract.sh -f dump.sql -d redmine -t workflows > redmine-workflows.sql
mysql主从需要注意的几个问题
1. 尽量不要使用stored procedures和triggers。
Stored procedures can behave strangely with statement based replication
2. 尽量不要使用temporary tables。
比如memory类型的表。有些程序就特别喜欢动态地创建和删除memory表。。
设想一下,某个slave挂掉了,重启服务器,memory类型的表都被清空了。。。
可以再看一下这篇文章:
http://scale-out-blog.blogspot.com/2012/04/replication-is-bad-for-mysql-temp.html
3. 尽量不要使用MyISAM类型的表。
InnoDB多好啊。
MyISAM不支持事务,表空间经常损坏,而且读写并发性能很低。
没有理由继续使用MyISAM啊。
4. 避免使用某些函数
比如 UUID() rand() 之类的函数,它们的结果都是不确定的。
5. 避免使用UPDATE … LIMIT …
以及 DELETE … LIMIT …
否则有可能死得很惨。 可以看看这篇文章:
http://www.dbasquare.com/2012/04/17/why-a-statement-can-be-unsafe-when-it-uses-limit-clause/
使用php class来处理htpasswd
在apache中可以使用.htpasswd文件来保护某些网页,只有登陆用户才可以访问到。
直接使用shell来创建 htpasswd文件,对于某些新手来说,确实有一点点难度。
今天找到一个php class,可以自动创建.htpasswd文件,哦,还有.htgroup。
/home/myuser/.htpasswd
user1:{SHA}kGPaD671VNU0OU5lqLiN/h6Q6ac= user2:{SHA}npMqPEX3kPQTo+x/+ZckHDrIcQI= user3:{SHA}q1Fh2LTUjjkncp11m0M9WUH5Zrw=
/home/myuser/.htgroup
admin: user2 editor: user1 user3 writer: user3
/home/myuser/public_html/example.com/member/.htaccess
AuthName "Members Area" AuthType Basic AuthUserFile /home/myuser/.htpasswd AuthGroupFile /home/myuser/.htgroup <Limit GET POST> require GROUP admin require GROUP writer </Limit>
只有user1 和 user3 可以访问到 http://example.com/member/。
下面是这两个class的代码:
class Htpasswd { private $file = ''; private $salt = 'AynlJ2H.74VEfI^BZElc-Vb6G0ezE9a55-Wj'; private function write($pairs = array()) { $str = ''; foreach ($pairs as $username => $password) { $str .= "$username:{SHA}$password\n"; } file_put_contents($this -> file, $str); } private function read() { $pairs = array(); $fh = fopen($this -> file, 'r'); while (!feof($fh)) { $pair_str = str_replace("\n", '', fgets($fh)); $pair_array = explode(':{SHA}', $pair_str); if (count($pair_array) == 2) { $pairs[$pair_array[0]] = $pair_array[1]; } } return $pairs; } private function getHash($clear_password = '') { if (!empty($clear_password)) { return base64_encode(sha1($clear_password, true)); } else { return false; } } public function __construct($file) { if (file_exists($file)) { $this -> file = $file; } else { die($file." doesn't exist."); return false; } } public function addUser($username = '', $clear_password = '') { if (!empty($username) && !empty($clear_password)) { $all = $this -> read(); if (!array_key_exists($username, $all)) { $all[$username] = $this -> getHash($clear_password); $this -> write($all); } } else { return false; } } public function deleteUser($username = '') { $all = $this -> read(); if (array_key_exists($username, $all)) { unset($all[$username]); $this -> write($all); } else { return false; } } public function doesUserExist($username = '') { $all = $this -> read(); if (array_key_exists($username, $all)) { return true; } else { return false; } } public function getClearPassword($username) { return strtolower(substr(sha1($username.$this -> salt), 4, 12)); } } class Htgroup { private $file = ''; private function write($groups = array()) { $str = ''; foreach ($groups as $group => $users) { $users_str = ''; foreach ($users as $user) { if (!empty($users_str)) { $users_str .= ' '; } $users_str .= $user; } $str .= "$group: $users_str\n"; } file_put_contents($this -> file, $str); } private function read() { $groups = array(); $groups_str = file($this -> file, FILE_IGNORE_NEW_LINES); foreach ($groups_str as $group_str) { if (!empty($group_str)) { $group_str_array = explode(': ', $group_str); if (count($group_str_array) == 2) { $users_array = explode(' ', $group_str_array[1]); $groups[$group_str_array[0]] = $users_array; } } } return $groups; } public function __construct($file) { if (file_exists($file)) { $this -> file = $file; } else { die($file." doesn't exist."); return false; } } public function addUserToGroup($username = '', $group = '') { if (!empty($username) && !empty($group)) { $all = $this -> read(); if (isset($all[$group])) { if (!in_array($username, $all[$group])) { $all[$group][] = $username; } } else { $all[$group][] = $username; } $this -> write($all); } else { return false; } } public function deleteUserFromGroup($username = '', $group = '') { $all = $this -> read(); if (array_key_exists($group, $all)) { $user_index = array_search($username, $all[$group]); if ($user_index !== false) { unset($all[$group][$user_index]); if (count($all[$group]) == 0) { unset($all[$group]); } $this -> write($all); } } else { return false; } } }
使用方法:
初始化:
$passwdHandler = new Htpasswd('/home/myuser/.htpasswd'); $groupHandler = new Htgroup('/home/myuser/.htgroup');
创建和删除用户:
// Add a user with name 'user1' and password 'I prefer to use passphrase rather than password.' if it doesn't exist in .htpasswd. $passwdHandler -> addUser('user1', 'I prefer to use passphrase rather than password.'); // Delete the user 'user1' if it exists in .htpasswd. $passwdHandler -> deleteUser('user1');
检测某用户是否存在于.htpasswd中:
// Check if user 'user1' exists in .htpasswd. if ($passwdHandler -> doesUserExist('user1')) { // User 'user1' exists. }
把某用户加入某组:
// Add user 'user1' to group 'admin' in .htgroup. Group will be automatically created if it doesn't exist. $groupHandler -> addUserToGroup('user1', 'admin');
从某组中删除某用户:
// Delete user 'user1' from group 'admin' in .htgroup. Group will be automatically removed if it doesn't contain any users. $groupHandler -> deleteUserFromGroup('user1', 'admin');
欢迎测试。
mysql中的线程threads简介
mysql使用多线程threads来做各种工作,比如mysql_install_db, flush myisam tables, replication, TCP/IP sockets,等等。
下面简单介绍几种线程:
1. main thread.
2. bootstrap thread
只用于mysql_install_db。
3. maintenance thread
occasionally flushes MyISAM tables to Disk.
Innodb也有自己的maintenance thread.
4. handle TCP/IP sockets threads
5. handle shared memory/named pipes connections threads
for Windows ONLY.
6. signal handler thread
7. shutdown thread
shutdown thread 由signal handler thread创建,在mysqld关闭的时候,它通过close_connections()函数关闭所有的连接。
8. delayed thread
用于MyISAM的delayed inserts.
9. two slave threads
用于replication, 其中一个线程连接到master并获取数据(IO线程), 另一个线程从relay log中读取到sql语句并执行(SQL线程)。