I'am Ian

技术小企鹅的家

通用优化方案

 使用多个较小的表,而不是用一个大表,对查询缓存有帮助。这种设计方式使失效策略工作在一个较好的
颗粒度上。但是不要让这个想法过度影响架构设计,因为其他的因素能轻易抵消它的好处。
 成批地进行写入操作,而不是逐个执行,会有效率得多。因为这种方法只会引起一次失效操作。
 我们已经注意到在让缓存失效或清理一个大型缓存的时候,服务器可能会挂起相当长时间。至少在MySQL5.1
之前的版本中是这样。一个容易的解决办法就是不要让query_cache_size 太大,256MB 已经太大了。
 不能在数据库或表的基础上控制查询缓存,但是可以使用SQL_CACHE 和SQL_NO_CACHE 决定是否缓存查询。
也可以基于某个连接来运行或禁止缓存,可以通过用适当的值设定query_cache_size 来开启或关闭对
某个连接的缓存。
 对于很多写入任务的应用程序,关闭查询缓存也许能改进性能。这样做可以消除缓存那些很快就会失效的
查询所带来的开销。要记住在禁用的时候需要把query_cache_ size 设置到0,这样就不会消耗任何内
存。
如果想让大多数查询都不使用缓存,但是有少部分查询能从缓存中极大地受益,这时可以将全局变量
query_cache_type 设置为DEMAND,然后在想使用缓存的查询后面添加SQL_CACHE。尽管这会造成更多的工作,
但是可以细粒度地控制缓存。相应地,如果想缓存大部分查询,只排除其中一小部分,就可以使用SQL_NO_CACHE。

mysqldump是非常重要的MySQL备份工具。然而在长年累月的使用过程中,TAOBAO多次出现了因mysqldump意外终止而导致备份失败的情况。
以下是我们经常遇到的问题:

1、Lost connection to MySQL server at ‘reading initial communication packet’:
这个主要是因为DNS不稳定导致的。如果做了网络隔离,MySQL处于一个相对安全的网络环境,那么开启skip-name-resolve选项将会最大程度避免这个问题。

2、Lost connection to MySQL server at ‘reading authorization packet’:
从MySQL获取一个可用的连接是多次握手的结果。在多次握手的过程中,网络波动会导致握手失败。增加connect_timeout可以解决这个问题;然而增加connect_timeout并不能防止网络故障的发生,反而会引起MySQL线程占用。最好的解决办法是让mysqldump重新发起连接请求。

3、Lost connection to MySQL server during query:
这个问题具备随机性,而淘宝MySQL的应用场景决定了我们无法多次备份数据以便重现问题。
然而我们注意到这个问题一般会在两种情况下会发生。一种是mysqldump **** | gzip ****;另外一种是mysqldump **** > /nfs-file
注意,不管是gzip还是nfs都有一种特点,那就是它们影响了mysqldump的速度。从这个角度思考,是不是mysqldump从MySQL接受数据包的速度不够快导致Lost connection to MySQL server during query错误呢?

为了定位到问题,我搭建了一个测试环境:
test@192.168.0.1:3306
CREATE TABLE `test` (
`id` bigint(20) NOT NULL auto_increment,
`b` varchar(2000) default NULL,
`c` varchar(2000) default NULL,
`d` varchar(2000) default NULL,
`e` varchar(2000) default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

insert into test(b,c,d,e) values (lpad(’a’,1900,’b’), lpad(’a’,1900,’b’), lpad(’a’,1900,’b’), lpad(’a’,1900,’b’));
多次复制数据使测试环境达到一定数据量。

192.168.0.2:
编写一个c++程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <stdio.h>
#include <mysql.h>

using namespace std;

int main()
{
MYSQL conn;
MYSQL_RES *result;
MYSQL_ROW row;
my_bool reconnect = 0;

mysql_init(&conn);
mysql_options(&conn, MYSQL_OPT_RECONNECT, &reconnect);

if(!mysql_real_connect(&conn, “192.168.0.1″, “test”, “test”, “test”, 3306, NULL, 0))
{
fprintf(stderr, “Failed to connect to database: %s\n”, mysql_error(&conn));
exit(0);
}
else
{
fprintf(stdout, “Success to connect\n”);
}

mysql_query(&conn, “show variables like ‘%timeout%’”);
result = mysql_use_result(&conn);
while(row=mysql_fetch_row(result))
{
fprintf(stdout, “%-10s: %s\n”, row[0], row[1]);
}
mysql_free_result(result);
fprintf(stderr, “\n”);

mysql_query(&conn, “select SQL_NO_CACHE * from test.test);
result = mysql_use_result(&conn);
while((row=mysql_fetch_row(result))!=NULL)
{
fprintf(stderr, “Error %d: %s\n”, mysql_errno(&conn), mysql_error(&conn));
fprintf(stdout, “%s\n”, row[0]);
sleep(100);
}
fprintf(stderr, “Error %d: %s\n”, mysql_errno(&conn), mysql_error(&conn));
mysql_free_result(result);
mysql_close(&conn);
return 1;
}

在这段代码里,sleep函数用来模拟NFS的网络延迟和gzip的运算时间。执行一段时间之后,Lost connection to MySQL server during query出现了,程序意外终止。在数据处理足够快的情况下,又会是怎样的结果?

将sleep的时间改为1,重新编译后发现程序能够完整跑完。根据《MySQL Timeout解析》上对net_write_timeout的解释,我们可以发现,mysqldump处理数据过慢(NFS、gzip引起)会导致MySQL主动断开连接,此时mysqldump就会报Lost connection to MySQL server during query错误。经过多次测试,确定这个错误是由于net_write_timeout设置过短引起。

今天在项目遇到了一个问题,ie6下png图片经过之前的处理办法,form表单里面的元素不能正常点击,增加了position:relative也没有得到解决。用下面一个例子来说明问题,看一段html代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<style>
.div1 {
        position:absolute;
        width:300px;
        height:300px;
        left:50px;
        top:80px;
        background-image:url(aaa.png);
}
</style>
<div class="div1">
<form>
<input type="radio" />
</form>
</div>

上面的代码ie6下,png图片显示有问题,经过修改如下,ie6下图片正常显示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<style>
.div1 {
        position:absolute;
        width:300px;
        height:300px;
        left:50px;
        top:80px;
        background-image:url(aaa.png);
        _background: none;
        _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='scale', src='/images/aaa.png');
}
</style>
<div class="div1">
<form>
<input type="radio" />
</form>
</div>

但是表单元素没有办法点击,后来经过查看资料和实践,发现增加一个div可以解决问题,如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<html>
<head>
<style>
.div1 {
    position:absolute;
    width:300px;
    height:300px;
    left:50px;
    top:80px;
}
.div2 {
    width:300px;
    height:300px;
    background-image:url(aaa.png);
    _background: none;
    _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='scale', src='/images/aaa.png');
}
</style>
</head>
<body>
<div class="div1">
<div class="div2">
<form>
<input type="radio"/>
</form>
</div>
</div>
</body>
</html>

上面解决的原因其实是
在添加滤镜的div上面不能有任何定位相关的css,只能有显示相关的css,所以我们将定位和显示拆分开,增加专门的wrapper层来做filter

在之前一个项目中,由于访问流量过大,造成了数据库压力非常大,从下面多方面去减低了数据库压力
首先判断数据库是由于读操作还是写操作,通过processlist看出insert出现很多lock,发现写操作过于频繁,由于不是innodb引擎,插入的时候会将整个table锁掉,然后更新一个表示全部行数的字段(也正是如此,才让myisam引擎可以在select count(*)操作的时候瞬间返回答案)。然后不是在插入过于频繁的情况下,这样的锁表并不会引起多大的问题,但是并发一高,造成了连续性的lock,恶性循环。
首先修改数据库的引擎,将MYISAM改成INNODB
ALTER TABLE t ENGINE = INNODB
再次查询当前隔离级别
SELECT @@tx_isolation,发现是可重复读级别,进行降低
set global transaction isolation level read committed,关于mysql的锁和隔离级别会在另外的文章中详细讨论
执行之后发现,丢失连接现象大幅度降低,而且数据库不出现lock现象,插入速度很快,满足了应用写的操作。但是应用读操作还是有出现问题。

continue reading…

假定之前div的css是
{ float:left; width:196px; height:302px; background-image:url(images/tosh_10.png); background-repeat:no-repeat;}

  1. 增加ie6下的css hack:_background:none;
  2. 增加滤镜:_filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=’true’, sizingMethod=’scale’, src=”/images/tosh_10.png”);

这里需要注意的是,滤镜图片的链接需要是绝对路径。

如果div中有需要点击的链接,则需要对div里面的链接做操作

例如div结构为
<div id=”aaa”>
    <a href=”xxxx”></a>
</div>

将<a>标签外面套上一个div,然后增加div的style position:relative
这样链接就可以出发click事件了

I'am Ian is Digg proof thanks to caching by WP Super Cache