nginx freebsd 官方网站优化

OS & Hardware
FreeBSD 7.1
AMD64, dual-core CPU
4GB RAM
Purpose
Web server & reverse proxy
Load description
45K inactive keep-alive connections
HTTP request is about 5,000 req/s, mostly small static files, all are cached by VM
System config
/boot/loader.conf:

vm.kmem_size=1844M
kern.maxbcache=64M
kern.ipc.maxpipekva=4M

/etc/sysctl.conf:

kern.ipc.nmbjumbop=192000
kern.ipc.nmbclusters=229376
kern.ipc.maxsockets=204800
net.inet.tcp.maxtcptw=163840
kern.maxfiles=204800

kern.ipc.somaxconn=4096

Retrieved from “http://wiki.nginx.org/FreeBSDOptimizations”

[翻译][注解]Innodb Performance Optimization Basics

原文链接地址如下:http://www.mysqlperformanceblog.com/2007/11/01/innodb-performance-optimization-basics/
这篇文章写于2007年11月
翻译参考了这篇译稿:http://yahoon.blog.51cto.com/13184/76592
推荐详细阅读原作者的这篇演讲稿
Innodb性能优化基础
面试别人的时候我喜欢问一个基础的问题:如果你有一个16G内存,专用于mysql大型innodb的数据库服务器,
对于典型的web负载,你应该怎样调整mysql的设置?有趣的是其中大多数并不能提出任何有益的建议。
所以我决定公布答案,并且我很乐意在硬件,操作系统和应用方面谈谈基础的一些优化。
这篇文章的标题是‘Inodb性能优化基础’,所以这里面的是一些普遍的准则,适用于很多的应用场景,
当然最佳的设置要依据具体的应用而定。

硬件
如果你的Innodb数据库很大,那么内存是最重要的。现在16-32G的内存性价比就不错。
From CPU standpoint 2*Dual Core CPUs seems to do very well, while with even just two Quad Core CPUs scalability issues can be observed on many workloads.
CPU方面,两个双核的CPU,似乎就不错了,而即使只有两个四核心CPU的可扩展性问题都可以观察到很多的工作量,但是这跟应用也有很大的关系。(这里翻译的很别扭,大家看原文)
第三是IO系统--DAS和RAID是很好的选择.一般来说6-8块硬盘就够了,有时可能需要更多。同时注意新的2.5″的SAS硬盘,小却速度快。RAID10对于数据存储和主要是读的场合下十分合适。需要冗余性的话RAID5也不错,但注意对于RAID5的随机写操作。

操作系统

首先--运行64位的操作系统。现在不少有大内存的服务器,上面还跑着32位的操作系统。建议不要这么做。
如果系统是linux,对数据库的目录使用LVM可以获得更高效的备份。
ext3文件系统大部分情况下都不会出问题,如果碰到问题的话,试试XFS。
如果你使用innodb_file_per_table而且表很多的话可以使用noatime和nodiratime选项,但是这样做效果不是很大。
同时注意给系统留出足够的内存,防止mysql和系统发生内存竞争导致被交换出内存。

MYSQL 的Innodb 设置

(关于更多更详细的参数说明,请参考这里(中文文档))
最重要的地方有:

innodb_buffer_pool_size 设为内存的70%-80%都是安全的。我在一个16G的服务器上把它设成12G。
UPDATE: 如果你想了解更多的细节,请查看tuning innodb buffer pool
innodb_log_file_size 这取决于你需要的出错恢复速度。256M是合理的恢复时间和良好性能之间不错的一个平衡值。
innodb_log_buffer_size=4M 大多数情况4M就够了。如果你有大量的事务处理,这个数值可以增加一点儿。
innodb_flush_log_at_trx_commit=2 如果你不是很关心ACID,可以容许在系统完全崩溃的情况下丢失最后一两秒的事务,那么可以设置这个值为2。它可以极大的提高短的写事务的效率。
innodb_thread_concurrency=8 即使目前的InnoDB可扩展性修复后,对并发的支持也是有限的。这个值取决于你的程序,可能高或者低一些。8是可以接受的默认值。
innodb_flush_method=O_DIRECT 避免双缓冲(double buffering)和降低swap的压力,大多数情况下可以提高性能。但是注意如果你RAID cache不够的话,写IO的操作会有麻烦。
innodb_file_per_table 如果你的表不多可以使用这个选项。这样你就不会有不受控的innodb主表空间的增长,这个主表空间是不能重新定义的。这个选项在4.1版中引入,现在可以放心使用。
查看你的程序是否可以运行在READ-COMMITED 隔离模式下,如果可以,就可以设为默认的transaction-isolation=READ-COMMITTED。这个选项有一些性能的优势,特别是在5.0,5.1版本的行级复制方面。
还有很多的参数选项需要调整,今天我们就只关注关于和Innodb相关的。其他的可以参考 tuning other options 和 MySQL Presentations.

应用程序的优化

如果原来是MyISAM,现在你可能需要对应用做一些修改。首先确保你在进行数据库更新的时候使用事务,这对数据一致性和性能都有好处。
其次如果你的应用有写操作的话要注意处理死锁问题。
第三你要重新检视你的表结构,尽可能利用Innodb的优势–簇集主键索引(clustering by primary key),在所有的索引里面有主键(所以要保持主键简短)。使用主键来快速查询(试着在joins时使用),large unpacked indexes (try to be easy on indexes)。(这一句不懂)
With these basic innodb performance tunings you will be better of when majority of Innodb users which take MySQL with defaults run it on hardware without battery backed up cache with no OS changes and have no changes done to application which was written keeping MyISAM tables in mind.
原文 http://moonbingbing.blogspot.com/2008/08/innodb-performance-optimization-basics.html

MySQL分表优化试验

我们的项目中有好多不等于的情况。今天写这篇文章简单的分析一下怎么个优化法。
这里的分表逻辑是根据t_group表的user_name组的个数来分的。
因为这种情况单独user_name字段上的索引就属于烂索引。起不了啥名明显的效果。

1、试验PROCEDURE.
DELIMITER $$
DROP PROCEDURE `t_girl`.`sp_split_table`$$
CREATE  PROCEDURE `t_girl`.`sp_split_table`()
BEGIN
  declare done int default 0;
  declare v_user_name varchar(20) default '';
  declare v_table_name varchar(64) default '';
  -- Get all users' name.
  declare cur1 cursor for select user_name from t_group group by user_name;
  -- Deal with error or warnings.
  declare continue handler for 1329 set done = 1;
  -- Open cursor.
  open cur1;
  while done <> 1
  do 
    fetch cur1 into v_user_name;
    if not done then
      -- Get table name.
      set v_table_name = concat('t_group_',v_user_name);
      -- Create new extra table.
      set @stmt = concat('create table ',v_table_name,' like t_group');
      prepare s1 from @stmt;
      execute s1;
      drop prepare s1;
      -- Load data into it.
      set @stmt = concat('insert into ',v_table_name,' select * from t_group where user_name = ''',v_user_name,'''');
      prepare s1 from @stmt;
      execute s1;
      drop prepare s1;
    end if;
  end while;
  -- Close cursor.
  close cur1;
  -- Free variable from memory.
  set @stmt = NULL;
END$$

DELIMITER ;
2、试验表。
我们用一个有一千万条记录的表来做测试。

mysql> select count(*) from t_group;
+----------+
| count(*) |
+----------+
| 10388608 | 
+----------+
1 row in set (0.00 sec)

表结构。
mysql> desc t_group;
+-------------+------------------+------+-----+-------------------+----------------+
| Field       | Type             | Null | Key | Default           | Extra          |
+-------------+------------------+------+-----+-------------------+----------------+
| id          | int(10) unsigned | NO   | PRI | NULL              | auto_increment | 
| money       | decimal(10,2)    | NO   |     |                   |                | 
| user_name   | varchar(20)      | NO   | MUL |                   |                | 
| create_time | timestamp        | NO   |     | CURRENT_TIMESTAMP |                | 
+-------------+------------------+------+-----+-------------------+----------------+
4 rows in set (0.00 sec)

索引情况。

mysql> show index from t_group;
+---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| Table   | Non_unique | Key_name         | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment |
+---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
| t_group |          0 | PRIMARY          |            1 | id          | A         |    10388608 |     NULL | NULL   |      | BTREE      |         | 
| t_group |          1 | idx_user_name    |            1 | user_name   | A         |           8 |     NULL | NULL   |      | BTREE      |         | 
| t_group |          1 | idx_combination1 |            1 | user_name   | A         |           8 |     NULL | NULL   |      | BTREE      |         | 
| t_group |          1 | idx_combination1 |            2 | money       | A         |        3776 |     NULL | NULL   |      | BTREE      |         | 
+---------+------------+------------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+
4 rows in set (0.00 sec)

PS:
idx_combination1 这个索引是必须的,因为要对user_name来GROUP BY。此时属于松散索引扫描!当然完了后你可以干掉她。
idx_user_name 这个索引是为了加快单独执行constant这种类型的查询。
我们要根据用户名来分表。

mysql> select user_name from t_group where 1 group by user_name;
+-----------+
| user_name |
+-----------+
| david     | 
| leo       | 
| livia     | 
| lucy      | 
| sarah     | 
| simon     | 
| sony      | 
| sunny     | 
+-----------+
8 rows in set (0.00 sec)

所以结果表应该是这样的。
mysql> show tables like 't_group_%';
+------------------------------+
| Tables_in_t_girl (t_group_%) |
+------------------------------+
| t_group_david                | 
| t_group_leo                  | 
| t_group_livia                | 
| t_group_lucy                 | 
| t_group_sarah                | 
| t_group_simon                | 
| t_group_sony                 | 
| t_group_sunny                | 
+------------------------------+
8 rows in set (0.00 sec)

3、对比结果。


mysql> select count(*) from t_group where user_name = 'david';
+----------+
| count(*) |
+----------+
|  1298576 | 
+----------+
1 row in set (1.71 sec)

执行了将近2秒。

mysql> select count(*) from t_group_david;
+----------+
| count(*) |
+----------+
|  1298576 | 
+----------+
1 row in set (0.00 sec)
几乎是瞬间的。

mysql> select count(*) from t_group where user_name <> 'david';
+----------+
| count(*) |
+----------+
|  9090032 | 
+----------+
1 row in set (9.26 sec)
执行了将近10秒,可以想象,这个是实际的项目中是不能忍受的。
mysql> select (select count(*) from t_group) - (select count(*) from t_group_david) as total;
+---------+
| total   |
+---------+
| 9090032 | 
+---------+
1 row in set (0.00 sec)
几乎是瞬间的。


我们来看看聚集函数。
对于原表的操作。

mysql> select min(money),max(money) from t_group where user_name = 'david';
+------------+------------+
| min(money) | max(money) |
+------------+------------+
|      -6.41 |     500.59 | 
+------------+------------+
1 row in set (0.00 sec)
最小,最大值都是FULL INDEX SCAN。所以是瞬间的。
mysql> select sum(money),avg(money) from t_group where user_name = 'david';
+--------------+------------+
| sum(money)   | avg(money) |
+--------------+------------+
| 319992383.84 | 246.417910 | 
+--------------+------------+
1 row in set (2.15 sec)
其他聚集函数的结果就不是FULL INDEX SCAN了。耗时2.15秒。

对于小表的操作。
mysql> select min(money),max(money) from t_group_david;
+------------+------------+
| min(money) | max(money) |
+------------+------------+
|      -6.41 |     500.59 | 
+------------+------------+
1 row in set (1.50 sec)
最大最小值完全是FULL TABLE SCAN,耗时1.50秒,不划算。以此看来。
mysql> select sum(money),avg(money) from t_group_david;
+--------------+------------+
| sum(money)   | avg(money) |
+--------------+------------+
| 319992383.84 | 246.417910 | 
+--------------+------------+
1 row in set (1.68 sec)

取得这两个结果也是花了快2秒,快了一点。

我们来看看这个小表的结构。
mysql> desc t_group_david;
+-------------+------------------+------+-----+-------------------+----------------+
| Field       | Type             | Null | Key | Default           | Extra          |
+-------------+------------------+------+-----+-------------------+----------------+
| id          | int(10) unsigned | NO   | PRI | NULL              | auto_increment | 
| money       | decimal(10,2)    | NO   |     |                   |                | 
| user_name   | varchar(20)      | NO   | MUL |                   |                | 
| create_time | timestamp        | NO   |     | CURRENT_TIMESTAMP |                | 
+-------------+------------------+------+-----+-------------------+----------------+
4 rows in set (0.00 sec)

明显的user_name属性是多余的。那么就干掉它。
mysql> alter table t_group_david drop user_name;
Query OK, 1298576 rows affected (7.58 sec)
Records: 1298576  Duplicates: 0  Warnings: 0

现在来重新对小表运行查询

mysql> select min(money),max(money) from t_group_david;
+------------+------------+
| min(money) | max(money) |
+------------+------------+
|      -6.41 |     500.59 | 
+------------+------------+
1 row in set (0.00 sec)

此时是瞬间的。
mysql> select sum(money),avg(money) from t_group_david;
+--------------+------------+
| sum(money)   | avg(money) |
+--------------+------------+
| 319992383.84 | 246.417910 | 
+--------------+------------+
1 row in set (0.94 sec)

这次算是控制在一秒以内了。

mysql> Aborted

小总结一下:分出的小表的属性尽量越少越好。大胆的去干吧。
本文出自 “上帝,咱们不见不散!” 博客,请务必保留此出处http://yueliangdao0608.blog.51cto.com/397025/107356

本文出自 51CTO.COM技术博客