2011年7月14日星期四

淘宝技术嘉年华 - iDataForum

7 月 10 日 idataforum

吸取了昨天的教训,早上不急不慢的把早餐吃好后才晃悠过去。到达会场时,时间还尚早。看了下周围的同学,大多都是低头,或是相邻的在窃窃私语着。

 



依照惯例,上午还是主论坛

 


下午有三个分论坛
分论坛一 —— MySQL


分论坛二 —— NoSQL


分论坛三

 


本来,也打算对参加的每场做下备注,但写完周晓方老师的那场后,脑子里空白的很。拼命搜索记忆,结果也为零。后面就干脆把已写下来的全部删除,做个引导的目录就算了吧。

或许,我是真的在患失忆症,也许也因为其他的一些原因,影响了整个的记忆。

2011年7月13日星期三

淘宝技术嘉年华 - TCon

幸好,我所在的组没有其他人报名参加这次 2011 淘宝技术嘉年华 的活动,否则,从经济的角度来说,以我女生尴尬的身份,估计是很难被批准的。

这次的技术嘉年华,把之前单独举行已在业界较出名的 D2, idataforum 集合到一块儿,再加上还有后面推出的不需报名的 淘宝技术专场,Node 沙龙,圆桌会议 ......等等可以说在那两天会前会后,莫干山路上见到的来来往往的行人,都是来参加这次会议的。之下就大概记录下参加的两天的会议行程。

7 月 9 日 TCon 分会场

之前,有看到公告说是 8 点开始签到, 因为一些耽搁,等我 8:45 匆匆忙忙到达会场的时候,见里面寥寥几人, 都在低头翻着签到时所发的资料。 这有点让我惊讶,不致这么少吧。后面,陆陆续续的人进来,终至满场后旁边还零零散散的站着好些。原来,是大家到得较晚而已。(会后,从围脖上得知,里面还是有些打酱油的,因为隔壁 淘宝技术专场爆场,好多后面赶过去的同学无法挤入会场,不得不转战我们这边)。

 


上午是主会场,9:45 时才开始,先淘宝网的 张建锋/行癫 致辞,很简短, 但有提出测试中的一些问题,如:测试行业平台化和自动化的挑战;测试人员安排;测试与开发流程的关系;保证研发效率和产品质量是测试的目的等。

 


之后,是淘宝的 夏林娜/郭芙 做介绍,主题是《 Testing Business in Taobao》 。她提出测试有 『器』,『术』,『道』 (其实,我很期望她能对这三个做些具体的解析)。之后,用一登录的界面做示例,为了增加与听众的互动,于是提问,『谁能说说这一登录界面需要做哪些方面的测试?』。但效果甚微,因为回答的同学有些紧张,只说需要做 UI 方面,然后 SQL 注入等等的测试。这样一来,加上 她本身好像也有点紧张?,话题一下扩散,等再回来,总感觉不在状态。
slides 很少,但其中 这一张图(图 1),让我印象深刻,因为之前我并不是测试人员,甚至,连边都挨不上。而这张图,让我对所需要做的测试内容,有了一大概的轮廓。


图1



部分提问整理:
Q: 淘宝安全方面是怎样测试的?
A: 基本的安全方面的测试,有一扫描工具 STC (Security Test Center)。
Q: 做白盒?
A: 白盒测试。
Q 在代码更新时,这个工具什么时候开始检测, 是 STC 也管理代码?
A: 是手工将更新的代码的 SVN 地址 提交到 STC, STC 再开始检测。

Q:怎样展开测试,或者是做好测试?(问题记不太清了,看笔记,意思大概是这样)
A:最主要是要对产品有整体的了解。然后,做测试要做到 5W1H。5W是, Why, 为什么要做这个测试; What,要做那些方面的测试; Who,由谁去做测试; When,什么时候做测试,一般由当时场景,开发人员定义;1H 是 How, 即怎样做测试,根据需求准备好测试用例,再执行。(数数,是不是少了个 『W』,拉下的那个是 Which,根据测试用例的重要性,哪个先做,或者 Where ,哪个地方重要些,先测?我自圆其说的解释好像都说得通。也许,在她的答案中,这两个 W 都不是她的 W)。

Q:对于测试的结果要怎样评估?
A:折中,主要是在产品开发前期, PM ,QA 等沟通好,定下一产品上线的标准。

Q: 在采用敏捷开发模式的方式下,测试怎样分工,然后对于研发工具,流程建设方面能否给些建议?
A:测试人员对于业务和技术都要想当程度上的了解, 然后, 敏捷项目的管理理念 scrum,就注重 Team 的建设。(这个回答记录的不是很清楚,但我想,这里是否给出的是:测试人员除了需要对于业务和技术方面的了解,更多还要有团队的精神)。

会后感想:这场好像演讲者准备得并不是很充分,有点敷衍的感觉。

 


Google 日本 的 Matt Devore 做的 《NativeDriver--Testing tool for multiple platforms》 是上午主会场 的最后一场。
忍不住先八卦下,Matt 上台后,大家都有点兴奋,尤其我自己,见到外国友人,现已是很稀松平常的事,但要见到 Google 的开发人员,可不是件容易的事,更何况,我还是 Google 的 粉丝。『大家好』,这是 Matt 说的第一句话,是中文。所有人听到后都情不自禁的鼓起了掌,还伴随着很 Happy 的笑声。最主要是心里头一块石头落地,不用听英文的演讲啊~~~可惜,这话过后,没高兴几秒钟,Matt 在继续用中文自我介绍完后,接着就说道:『我的中文还不是很好,所以这里还是用英文演讲...』,顿时,会场空中飘过一阵唉声。

八卦完,回到正题。这个议题主要是 Matt 介绍他负责开发的 NativeDriver,该工具是使用原生 UI 而不是浏览器 UI 的自动化测试框架,它主要用于 Android 应用程序的功能测试。目前已有 Andriod, iOS, Windows 版本。

会后感想:这场演讲下来,气氛变得有点沉闷,Matt 也好像是比较严肃之人,除开始那一句中文逗笑大家后, 之后,整个会场就都只有他的讲话声。然后,因为期间也没有同声翻译,或者做下解说,能听懂英文的还好,听不懂的,就我周围,好几个人都已昏昏入睡。好在结束时有一同学提问,在 Matt 反问后,那同学条件反射的回答『是』,会场才回到了了自由闲适的气氛。

而且,这个议题放在这里,个人感觉不是很合适,虽然都提到测试,但『此』测试『非彼』测试。另外,英文,可真是一个令人羞愧的问题,大多数的我们可与英文耳鬓厮磨了十几年啊,可连听个没有很多词汇的演讲都是如此吃力,就更别提『说』了(后面,见到一同学与 Matt 用英文自由的交谈,哇,顿时让我心声膜拜之意。心中也暗暗在想,这次回去后,要努力好好练习听说,别再『两天打渔三天晒网』)。

还有,不得不提一句有关于上午主会场的主持人,每个演讲者下去后发表的所谓的『评语』,听来要多做作就有做作,还有三个字,就不说了。

 


下午有分三个分论坛,每个分论坛又都有三场。当时报名我报的是分论坛二,而纵观每个分论坛的第一场,我是心仪于分论坛三,但最后『死』脑筋的我还是乖乖的呆在了分论坛二中(后面得知,其实是完全可以串场的,当然这又是后话了)。

第一场是趋势科技的张力做演讲, 主题是《我不是赤裸的羔羊––Web应用的安全性测试方法》。他先是列举了今年前面几起『有名的』在安全事故,如索尼的 SQL 注入, Google store 的 XSS 跨站攻击等。然后介他们所采用的发现应用程序漏洞的模糊测试,从识别威胁路径到识别威胁,到将威胁做笛卡尔乘积按优先级排序筛选后转化为测试用列,最后执行测试,并对测试做评估,中间还穿插了下 SQL 注入的演示实验。

会后感想:这场整个下来,感觉就好象一直围绕于 SQL 注入,并没真正的将『有关 Web 应用安全方面的测试方法』这个主题展开。演示实验时,还注意到提到 Web 提交的方式,他犹豫的说还有 POST(实例中是 GET) 等,这个『等』字实在有点让我惊讶(或许,是太紧张)。另外,演讲人本来应该也是想打造轻松活泼的气氛,所以 slides 里头几张在解说 『羔羊与恶狼』,以及还有 『地球很危险,我们还是回火星吧』 类似的动画图片。但可能真的他本人气场不够强大,以至现场飘过一声声尴尬的笑声。

 


中场休息过后,第二场开始。这场是腾讯的@吴凯华/jeremywu 带来的《腾讯互联网测试实践技术分享》,主要介绍了目前腾讯测试管理体系建设成果, 自动化+全方位电子流管理体系;全研发闭环流程;完善的计划、任务、用例、需求、度量统计等管理;其中创建的每个测试用例都需要评审,且 QA 评审时必须给出评审建议;评估项目风险时需要 coding 人员,产品以及测试人员一起来把控;度量需要根据项目团队,而不是根据组织,它是单元测试 + Code Review + 持续集成的工作。然后,还有介绍到一些他们使用到的工具如 testlink(测试管理平台), CI(持续集成平台), JSCoverage(自动检测加载的 JS), 这些都是开源,但他们都已进行过二次开发。

会后感想:这场真是太火爆,整个会场的空地都或站或坐着从论坛一和论坛二过来的同学(也是从这里,我才知道是可以串场的)。演讲完后的提问时间,同学们的兴致也很高,但主要都是围绕着度量和评估。应该是之前都有着这方面的困扰,所以想籍此机会多取点『经』吧。但怎么说,这真是个太大的命题,而且每个公司的组织结构也都不一样,兴许在『此』公司很好的管理方法,在『彼』公司并不一定行得通。

 


分论坛二的最后一场,是同济大学软件学院的@朱少民带来的《如何让缺陷无处藏身——谈软件可测试性》,主要介绍是如何让开发的软件具有可测试性,这其中提到需要分层、可定制等;根据需求建模,再由此生成测试用例;以及是在代码修改或是重构时,同样做到使软件具有可测试性。

部分问题整理
Q:对需求建模,是不是要求测试在产品策划前期就需要参与?
A:测试要测试产品的业务和功能,这就说明,产品策划阶段肯定是需要参与的。

Q:进行白盒测试,这说明是不是在开发期间,测试同样也是需要参与?
A:如果进行白盒测试,这代表需要清楚代码的结构,所以,最好是参与。

Q:测试人员对于设计模式,设计规则也要了解?
A:最好是测试,开发能互换角色,这样,测试的清楚开发的规则,而开发的,通过测试,能了解在开发中需要注意的各种问题。

Q:如何保证软件业务或是功能的完整?
A: 建个 checklist 。

Q:目前,管理软件方面基本上都是有以结果为导向的,有没有以过程导向的管理软件,包括国内外?
A:就我所了解,是还没有的,不如,我们合作开发一款吧。(这个回答让大家很 欢乐的笑了)

会后感想:不知道是不是因为整个社会浮躁的气氛,以至于大家都追求最直接的结果,就如最后那个问题中所提到的那样,以结果为导向。对于这场偏理论性方面的演讲,好大部分同学在会场要么堂而皇之的穿梭,要么窃窃私语或是昏睡或是干脆堂而皇之的离开,很少静下心来认认真真的听讲。不得不说,这样的心态,真是我们的一大悲哀。

 



另外分论坛一和三中老师和其演讲主题:

  • 朱磊 《大型互联网产品的性能原理分析与优化技巧》

  • 邱鹏/Ricky Qiu 《懒人的幸福生活 –––– 无人值守性能测试》

  • @王德山/耿电《大型性能评测模型和线上压测风险控制》

  • @倪生华 《分层自动化测试体系与持续集成实践》

  • 陈睿/竹权 《低碳淘宝,测试先行——淘宝核心系统软件测试实践》

  • 吴光安 《微软是如何测试的——云计算专场 》



这天下来,脑子还是有点疲劳,最主要原因是我测试方面的知识可以说是空白,每场都如同海绵吸水般,根本来不及消化。这里做下整理,希望在以后的工作中能快点上手。还有真的真的,英语急待提高,那场英文的演讲我听得多吃力只有自己清楚。

2011年6月12日星期日

MySQL 连接

所谓连接查询,就是通过连接,使查询的数据从多个表中检索取得。在 SELECT 的 FROM 子句中写上所有有关的表名,就可以得到由几个表中的数据组合而成的查询结果。连接条件可在 FROMWHERE 子句中指定,WHEREHAVING 子句可包含其搜索条件,以供进一步筛选连接之后的结果集。 目前可实现的连接有:自然连接(Natural Join),内连接(Inner Join), 外连接(Outer Join), 交叉连接(Cross Join) etc.

JOIN USING 可按照指定的列实现表的等值连接。设有两个表t1, t2 具有相同的列 a, b, c, d, 如果不是对全部相同列做连接,而是是对列 a, b 做连接,可写成 t1 JOIN t2 USING(a,b)
JOIN ON 可按照更一般性条件实现表的等值连接。eg: t1(a, b), t2(a, c), 可写成 t1 JOIN t2 ON t1.a = t2.a
USING 后用于连接的列,也可用保留字 ON 指定, eg: ... USIGN(a)... 等价于 ... ON t1.a = t2.a..., 使用两者在结果集上体现的不同请见注 1

示例表 t1, t2, 其数据如下:
[sql]
mysql> SELECT * FROM t1;
+---+------+
| a | b |
+---+------+
| 1 | a |
| 3 | c |
| 5 | e |
| 7 | g |
+---+------+
4 rows in set (0.00 sec)
mysql> SELECT * FROM t2;
+---+------+
| a | c |
+---+------+
| 2 | b |
| 4 | d |
| 6 | f |
| 7 | g |
+---+------+
4 rows in set (0.00 sec)
[/sql]

自然连接

[sql]
mysql> SELECT * FROM t1, t2 WHERE t1.a = t2.a;
+---+------+---+------+
| a | b | a | c |
+---+------+---+------+
| 7 | g | 7 | g |
+---+------+---+------+
1 row in set (0.00 sec)
[/sql]

内连接

[sql]
mysql> SELECT * FROM t1 INNER JOIN t2 USING (a);
+---+------+------+
| a | b | c |
+---+------+------+
| 7 | g | g |
+---+------+------+
1 row in set (0.00 sec)
[/sql]
它等价于:SELECT * FROM t1, t2 WHERE t1.a = t2.a; or SELECT * FROM t1 INNER JOIN t2 ON t1.a = t2.a;

外连接

外连接是连接的扩展。一般连接操作的结果表由符合连接条件的匹配元组连接起来的新元组构成,其余不符合连接条件的非匹配元组则被丢弃。外连接允许在结果表中保留非匹配元组,空缺部分填以NULL。其作用是在做连接操作时避免丢失信息。外连接有 3 类:
1 左外连接(Left Outer Join)。连接运算谓词为LEFT [OUTER] JOIN,其结果表中保留左关系的所有元组。eg:
[sql]
mysql> SELECT * FROM t1 LEFT JOIN t2 USING(a);
+---+------+------+
| a | b | c |
+---+------+------+
| 1 | a | NULL |
| 3 | c | NULL |
| 5 | e | NULL |
| 7 | g | g |
+---+------+------+
4 rows in set (0.00 sec)
[/sql]
等价于:SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a;

2 右外连接(Right Outer Join)。连接运算谓词为RIGHT [OUTER] JOIN, 其结果表中保留右关系的所有元组。MySQL 对其的优化策略见注 2

3 全外连接(Full Outer Join)。连接运算谓词为FULL [OUTER] JOIN, 其结果表中保留左右关系的所有元组。 MySQL 中, FULL JOIN... USING的结果集和INNER JOIN ... USING的结果集相同,且 MySQL 不支持 FULL OUTER JOIN。eg:
[sql]
mysql> SELECT * FROM t1 FULL JOIN t2 USING(a);
+---+------+------+
| a | b | c |
+---+------+------+
| 7 | g | g |
+---+------+------+
1 row in set (0.00 sec)

mysql> SELECT * FROM t1 FULL OUTER JOIN t2 USING(a);
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'OUTER JOIN t2 USING(a)' at line 1
[/sql]

交叉连接

交叉连接等同于做笛卡尔积。
[sql]
mysql> SELECT * FROM t1 CROSS JOIN t2;
+---+------+---+------+
| a | b | a | c |
+---+------+---+------+
| 1 | a | 2 | b |
| 3 | c | 2 | b |
| 5 | e | 2 | b |
| 7 | g | 2 | b |
| 1 | a | 4 | d |
| 3 | c | 4 | d |
| 5 | e | 4 | d |
| 7 | g | 4 | d |
| 1 | a | 6 | f |
| 3 | c | 6 | f |
| 5 | e | 6 | f |
| 7 | g | 6 | f |
| 1 | a | 7 | g |
| 3 | c | 7 | g |
| 5 | e | 7 | g |
| 7 | g | 7 | g |
+---+------+---+------+
16 rows in set (0.00 sec)
[/sql]
它等价于:SELECT * FROM t1, t2; or SELECT * FROM t1 INNER JOIN t2;


注:

  • USING 和 ON 显示的结果说明
    为了使 MySQL 在解析 NATURAL JOINJOIN ... USING SQL 时采用 SQL 2003 的标准,从 MySQL 5.0.12 开始,这两种 SQL 的解析都有做调整, NATURAL JOIN 时, 查询结果中只会显示单独的唯一一列, 即 t1.a, t2.2 两列做自然连接后在结果中只有一列 a (= COELSCE(t1.a, t2.a)); 而 JOIN ... USING时,对 USING 中 指定使用做连接的列,查询结果中也只会显示单独的唯一一列, JOIN ... USING形式的变体如 LEFT JOIN ... USING, RIGHT JOIN ... USING 等解析优化也是采用同样的处理。除此之后,其他的连接方式还是遵照以前的规则。详细说明,可查看如下引用部分或MySQL 官方文档 JOIN Syntax一节。

    Join Processing Changes in MySQL 5.0.12
    Beginning with MySQL 5.0.12, natural joins and joins with USING, including outer join variants, are processed according to the SQL:2003 standard. The goal was to align the syntax and semantics of MySQL with respect to NATURAL JOIN and JOIN ... USING according to SQL:2003. However, these changes in join processing can result in different output columns for some joins. Also, some queries that appeared to work correctly in older versions must be rewritten to comply with the standard.


    The single result column that replaces two common columns is defined using the coalesce operation. That is, for two t1.a and t2.a the resulting single join column a is defined as a = COALESCE(t1.a, t2.a), where:
    COALESCE(x, y) = (CASE WHEN V1 IS NOT NULL THEN V1 ELSE V2 END)
    If the join operation is any other join, the result columns of the join consists of the concatenation of all columns of the joined tables. This is the same as previously.

    [sql]
    mysql> SELECT * FROM t1 LEFT JOIN t2 USING (a);
    +---+------+------+
    | a | b | c |
    +---+------+------+
    | 1 | a | NULL |
    | 3 | c | NULL |
    | 5 | e | NULL |
    | 7 | g | g |
    +---+------+------+
    4 rows in set (0.01 sec)

    mysql> SELECT * FROM t1 LEFT JOIN t2 ON t1.a = t2.a;
    +---+------+------+------+
    | a | b | a | c |
    +---+------+------+------+
    | 1 | a | NULL | NULL |
    | 3 | c | NULL | NULL |
    | 5 | e | NULL | NULL |
    | 7 | g | 7 | g |
    +---+------+------+------+
    4 rows in set (0.01 sec)
    [/sql]

  • 2右外连接的优化策略
    右外连接 SQL 在解析阶段都会转换为只包含左外连接的 SQL,一般遵循如下这样的转换方式:

    T1, ...) RIGHT JOIN (T2,...) ON P(T1,...,T2,...) =
    (T2, ...) LEFT JOIN (T1,...) ON P(T1,...,T2,...)

    有关其详细信息,请参考 MySQL 的官方文档7.3.1.10. Outer Join Simplification

    At the parser stage, queries with right outer joins operations are converted to equivalent queries containing only left join operations. In the general case, the conversion is performed according to the following rule:
    T1, ...) RIGHT JOIN (T2,...) ON P(T1,...,T2,...) =
    (T2, ...) LEFT JOIN (T1,...) ON P(T1,...,T2,...)

    通过EXPLAIN EXTENDED, SHOW WARNINGS, 查看 MySQL 解析优化后的右外连接:
    [sql]
    mysql> EXPLAIN EXTENDED SELECT * FROM t1 RIGHT JOIN t2 USING (a);
    +----+-------------+-------+--------+---------------+---------+---------+-----------+------+----------+-------+
    | id | select_type | table | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
    +----+-------------+-------+--------+---------------+---------+---------+-----------+------+----------+-------+
    | 1 | SIMPLE | t2 | ALL | NULL | NULL | NULL | NULL | 4 | 100.00 | |
    | 1 | SIMPLE | t1 | eq_ref | PRIMARY | PRIMARY | 4 | test.t2.a | 1 | 100.00 | |
    +----+-------------+-------+--------+---------------+---------+---------+-----------+------+----------+-------+
    2 rows in set, 1 warning (0.00 sec)

    mysql> SHOW WARNINGS;
    +-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Level | Code | Message |
    +-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    | Note | 1003 | select `test`.`t2`.`a` AS `a`,`test`.`t2`.`c` AS `c`,`test`.`t1`.`b` AS `b` from `test`.`t2` left join `test`.`t1` on((`test`.`t1`.`a` = `test`.`t2`.`a`)) where 1 |
    +-------+------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+
    1 row in set (0.00 sec)

    [/sql]

2011年6月10日星期五

May 2011 and Before Part III


  • 淘宝褚霸:leveldb性能分析和表现 http://t.cn/hDNi6Y

  • Nagios手册

  • grep 'test_string' filename.txt > /tmp/test.txt 表示将 filename.txt 中包含有 test_string 字符串行的定向输出到 /tmp 下 test.txt 文件中。

  • cp /usr/local/share/aclocal /usr/share

  • ps aux | grep 'application name'

  • 25 条 SSH 命令和技巧 [技巧] | Wow!Ubuntu http://t.cn/h4g30w

  • PDF 下载:最牛B的 Linux Shell 命令 [新闻] | Wow!Ubuntu http://t.cn/h47S1R

  • 石展:推荐神器:dstat,全能Linux系统信息#监控工具#,可直接替换vmstat, iostat, netstat ,nfsstat, ifstat等系统工具,监控cpu、disk 、mem、load、interrupt、net、proc、CS.... 界面见图也很美观. ubuntu下直接sudo apt-get install dstat ; redhat下wget http://t.cn/h1QrIy 安装即可 (tks Frost)

  • 淘宝褚霸:latencytop深度了解你的Linux系统的延迟 http://t.cn/hB2enj


  • 我对后端优化的一些感想关键字:优化, 响应时间,吞吐量,vmstat & iostat & netstat & tcprstat, strace & oprofile & systemtap, aspersa & latencytop & top, 空查询, Bloom filter etc。

  • 陈庆吉chenqj:写了两篇Facebook技术体系的介绍 http://t.cn/h4dkV0 http://t.cn/h4dkVR 都不算深入,大牛就别看了。

  • 唐福林:所谓服务,应该不分内外的 //@fishermen:对于内部调用者不能完全信任,至少增加一个内部appkey,便于跟踪、统计,同时在需要的时候可以轻松增加限制//@TimYang:内部公有服务如果没有管理机制哪些人调了确实很难跟踪,要升级或者纠错都找不到调用方在哪里。//@TimYang:淘宝的服务框架演变过程,林昊写的 http://t.cn/hGJ6wJ

  • Sina App Engine 数据存储服务架构 关键字:Apache, MySQL, PHP, Memecache etc, 有时间可看看。

  • IT技术博客大学习:《几种常见的基于Lucene的开源搜索解决方案对比》 几种常见的基于Lucene的开源搜索解决方案对比 ... http://t.cn/hBmVz5


  • 淘叔度:nginx-0.9.5里面把listen的backlog由511调整为-1了。原因:linux内核里面listen系统调用的backlog是int型,但是在里面处理时会把它先转换成一个unsigned int再和系统设置的最大backlog进行比较,取二者的最小值。所以-1保证了永远取系统的最大值。backlog本来就是个hint值,系统默认是128。

  • suxiaoyong:再接上条: 8. 使用redis作为队列; 9. 尽量存储json数据,减少序列化开销; 10. 使用Mysql HandleSocket作为key value存储,cpu显著下降; 11. 数据过滤等交java中间件去做,减少数据库操作复杂性; 12. sns feed对数据完整性要求不高,必要时可以丢弃舍弃部分数据。//@suxiaoyong:接上条: 4. 在数据sharding时,对名博和普通用户分别处理; 5. sharding时采用两级分组,加强灵活性; 6. 使用DRBD做mysql实时同步; 7. 内容分发时,对于当前在线用户,使用redis的list作为cache,解决频繁请求时的刷新问题(相对于memcached也减少了内部通讯数据量);//@suxiaoyong:今天飞信首席架构师 @steadwater 关于sns feed的分享很不错,总结了一下,大概这些内容,不对的地方请补充: 1. 消息异步写入; 2. 推拉结合,对于粉丝多的用户用拉,普通用户用推,展示数据时进行合并; 3. 普通用户的事件尽量保证实时性,名博可以异步处理;


  • 可视化的数据结构和算法

  • 林信良常见算法笔记


  • ReflectionMethod PHP class, 获得指定的类的所有方法信息,详细信息,可PHP官方文档

  • 时蝇喜箭:深入理解PHP内核(TIPI)项目,也参考cnbeta文章: http://t.cn/IDa34O //@黄药师DE极致:转发微博@KimiChen:TIPI是一个开源项目,项目的初衷是为了分享有关PHP内部实现的方方面面,详情请点击http://t.cn/htWk9Y,强烈推荐之!

  • Faster Ruby


  • Node JS 资料

  • 我为什么向后端推荐 Node JS

  • node.js调研与服务性能测试


  • 惊喜就在这里

  • 关于前端 无意中发现的这个网站。

  • IE 6 调用 gzip 压缩后 Javascript 不能执行的问题, 出现这个 BUG 有可能是:服务器没有设置被请求文件(javascript)expries,cache-control; 服务器开启了 chunked encoding 模式; 通过 javascript 的 src 调用方式或者 AJAX 请求 javascript 文件等,解决是header 中:
    Cache-Control必须设置为 maxage=time 的格式, maxage 是指生存缓存生效时间, 1 为 1 秒;
    Expires 必须要设置,它的时间稍大于 Date(页面请求时间)即可;
    Pragma 必须设置为 public。

  • @Huihoo:Graffiti Markup Language (.gml) http://t.cn/hnJVu 涂鸦标记语言是基于XML的开放文件格式,用于存储涂鸦数据。互联网上很需要有一个大大的涂鸦墙,让我们有绘画的自由,思想表达的自由,精神发泄的自由。

  • 2010-12-30 MySQL 5.5正式版发布。

  • CSDN云计算:2011-03-17,据MongoDB官网消息,MongoDB v1.8.0已经发布。这是在2010年8月1.6版发布后的又一个版本。此次1.8版修复以往版本中的一些错误,并加入了许多新特性。 http://t.cn/IDtsI5

  • 淘叔度:Nginx是穷人家的孩子,品学兼优,任劳任怨,年级成绩第一的保持者,月薪要求1千块;Apache是地主家的孩子,多才多艺,班上的优秀学生干部,但抗压能力不够,月薪要求1万块;JBoss是富二代,后台很硬,见多识广,不能承受高压力且工作效率也不高,月薪要求3万块。作为老板的你会聘用哪个?

  • ora600ebay:DBA 1.0 掌握某主流商用RDBMS,例如Oracle。 DBA 2.0 = DBA 1.0+OS+Storage+Network+Application。 DBA 3.0 = DBA 2.0+MySQL (or Postgres etc)+NoSQL+Programmer。DBA 1.0/2.0 是Database management oriented, 而DBA 3.0是Data service oriented. DBA 1.0/2.0 是应用技术,DBA 3.0是创造技术。

  • jackbillow:Twitter也从syslog-ng转向了scribe,使用Hadoop来存储和分析数据。

  • 程序员幽默:【对程序员最具影响的,每个程序员都应该阅读的书籍】第1名《代码大全》第2名《程序员修炼之道》第3名《计算机程序的构造和解释》第4名《C程序设计语言》第5名《算法导论》第6名《重构:改善既有代码的设计》第7名《人月神话》第8名《设计模式》....全文见图或http://t.cn/h1HKmz

May 2011 and Before Part II



  • MangoDB doc

  • Foursqure: 使用 MongoDB Replica Sets 的三种架构
    在原有的 Master/Slave 机制上添加一台 arbiter;
    一个 Primary 用于写,多个 Secondary 用于读和一个 Secondary 用于备份;
    MongoDB 经典配置,上层是 Auto-Sharding, 每个 Sharding 结点 又是一个 Replica Sets。

  • tullyliu:内存占完后的,插入性能完全处于不可预测的状态,甚至会时快时慢,这个实在太无法接受了//@NinGoo:在@realzyy 的测试中,mongodb数据超过内存需要用到磁盘的时候,写入性能会有很大的下降,这是mmap的方式可以预期的。问题在于,每隔10s左右会有一个几乎跌到0的波动,原因尚待查证。



  • redis 运维的一些知识点

  • TimYang:1台机启动了2个Redis端口,另外两台机来测试写100字节,1台client跑到7万/秒, 一台client跑到9万/秒,加起来这台服务器每秒跑了16万次, 99.9%请求小于1ms。

  • Redis指令中文手册

  • Redis 容量及使用规划

  • TimYang:squid以文件操作为主,主要目的是静态化,当年开发时操作系统虚拟内存概念也没成熟。而Redis整个架构就是内存模型,所以如果app只使用操作系统内存,让操作系统来决定哪些是冷门的再swap,设计上是最自然的 //@童剑:主要看作者实现的如何了,Squid 不也是自己实现对象从内存到磁盘的交换吗,也挺好的。//@TimYang:再说下Redis数据需要全部放在RAM的问题,一个系统中热点数据的访问占总量一般小于20%,如果RAM要为这大部分冷门数据买单则是一种极大浪费。Redis VM设计思想就是把冷门数据交换到磁盘上,为热点数据腾出更多RAM空间。不过Redis绕过OS自己实现一套虚拟内存也具争议性。

  • TimYang:嗯,我的问题,强设了一下 echo 1 > /proc/sys/net/ipv4/tcp_tw_reuse phpredis 每秒也能跑个1万多次 //@淘一啸:回复@淘叔度:多谢指点,一直没有认真研究状态图中的异常情况。不知道有没有方法能够通过程序来逐个验证。 //@淘叔度:我之前写过的一篇文章供参考:http://t.cn/hGjHeL//@TimYang:Which PHP Library to use with Redis? The Benchmark, 赢家是phpredis http://t.cn/hGlxWf。

  • yangwm:一个不错的redis presentation, http://t.cn/hGvsSl

  • TimYang:The (Redis) cluster project is currently not ready: even if we have a pretty clear design, and many networking level code for gossip and failure detection, it will take some more month to be released, and more time to be a stable release. 这就是用C开发分布式网络程//@摇摆巴赫:redis 作者新博客提出presharding的临时解决方案,早在这篇博客之前,杨教授 @TimYang 也提出过MPSS也正是这个想法,hash is easy,rehash is hard,我们可能每天都碰到类似的问题 here's the simple solution , http://t.cn/h5G4nQ

  • iammutex:深入Redis内部-Redis 源码讲解 http://t.cn/h5dG1r 非常好的讲 Redis 内部实现及源码的文章~原文:http://t.cn/htpyGq

  • ackbillow:通过快照方式做replication在master数据量大时,整个过程会遇到一些问题,同时每次连接都才需要完整的一个快照。//@丹臣:今天配置了redis replication复制环境,redis salve异常挂掉,因为master有许多变更没有接收到,当slave重启后,会与master进行一次全同步,来保障数据的一致性。我实验的数据量很小,同步相当快。

  • 丹臣:@内涵帝,hset,减少了key储存的个数,在实际使用过程中,同一个key多个value值本来就要序列化的,一个key也只存一次的,并且value变长了,这样所需要的hash table管理结构就会减少,自然管理消耗的memory就会减少。本次测试用例是,数据长度太小,条数太多,导致管理空间成本很大//@丹臣:在有内存的情况下,redis每秒可以达到5w次tps get key[10bytes] value[10bytes],但19148251万object*(10bytes key length+10bytes value length)/1024/1024=365M,而redis-master用了3.3G的内存,管理结构成本相当大。http://t.cn/h1njF8

  • TimYang:更快的io设备写snapshot,其他都不是瓶颈。另外重启加载速度跟cpu相关。//@Birkoff:对@timyang 说:请教一下TimYang,Redis不开启VM的情况下,性能更多的取决于?1:更高频率的CPU 2:更大的CPU L2Cache 3:更快的内存?如何才能最大限度的发挥多核CPU的特性,提高Redis的处理能力?


  • TimYang:虽然LinkedIn经常发垃圾邮件,但是对其技术还是挺尊敬,Kafka, LinkedIn开源的pubsub的消息队列系统,其news feed也跑在这个系统上。 http://t.cn/hbjQIb。

May 2011 and Before Part I


  • ALTER TABLE tbl_name DROP PRIMARY KEY;, DROP INDEX idx_name ON tbl_name

  • MySQL HandleSocket技术在 SNS Feed存储中的应用

  • 为 MySQL 设置查询超时

  • Monitoring MySQL IO Latency with performance_schema

  • The fource categories of NoSQL databases

  • How to handler 1000's of concurrent users on a 360MB VPS

  • FriendFeed Use MySQL 虽然已经是比较老的文章了,但还是值得一看。

  • MySQL 允许驼峰形式命令,my.cnf 中 mysqld 部分加入lower_case_table_names=2, 官方文档

  • MySQL binlog的地雷 5.1版本后,MySQL引入了基于ROW方式的binlog格式,不同于Statement方式的是,ROW方式记录了变更的内容,而不仅仅是SQL。

  • hellodba:推荐:《面向程序员的数据库访问性能优化法则》,作者是我们部门的架构师,即浅显易懂,又很有深度。http://t.cn/hbxlM9

  • 淘宝褚霸:MySQL的IO调优是个大工程,从Mysql->Innodb->Filesystem->Page/buffer->IO 调度器->raid一整条线路。

  • skip-name-reslove

  • 唐福林:UTF-8 String, mysql client latin1, mysql connect latin1, mysql db table utf-8, 存进去的中文,jdbc 怎么调参数,查出来还是乱码。 @Timyang 指示:convert(unhex(hex(convert(name using latin1))) using utf8) as name 太神奇了!

  • 时蝇喜箭:【关注】Stack Overflow 架构更新 (每月PV到9千5百万)http://t.cn/httWMr 有一节关于经验教训的,令人注目的一条:“Full Text Search in SQL Server is very badly integrated, buggy, deeply incompetent, so they went to Lucene.”

  • sagasw大连程序员 :分享 Designing for Error (2) http://t.cn/h5iVdJ http://t.cn/htwNUo

  • jackbillow:Nick Kallen提到的几个设计思想:1. 没有银弹,所有的解决方案都是暂时的。2.可扩展性涉及分区,索引(不仅仅指的db中key的概念)和复制。3.所有的数据都在内存里,磁盘仅仅是落地。4.预估能解决一些问题,但很多问题也不是前期设计能预料的。5.尽可能的使用本地化策略譬如:cache本地化或就近访问。

  • ylinn:回复@NinGoo:可以设置直接使用remote 内存,避免swap //@NinGoo:间在mysql等大内存环境下,NUMA个节点间的内存使用难以均衡,在其他节点还有可用内存的情况下,某个节点内存不足也可能导致swap的产生,而swap是数据库头疼的大问题之一。//@Fenng:NUMA架构对DB产生的问题,是MySQL扩展性的绊脚石之一

  • FusionioChina:Facebook 的mySQL 大拿关于Mastering innoDB diagnostics. http://t.cn/hdmJES

  • 唐福林:原来 memcache 也就只检查 50 个key,学习了//@唐福林:@zhangwei217245 @摇摆巴赫 @TimYang Redis 默认的 LRU 算法,只检查 3 个key,从中间挑一个最长时间未使用的就删除?//@唐福林:Redis这么使用LRU? LRU and minimal TTL algorithms are not precise algorithms but approximated algorithms (in order to save memory), so you can select as well the sample size to check. For instance for default Redis will check three keys and pick the one that was used less recently

  • fengyuncrawl:#数据分布算法#1)Round-Robin法 2)Hash法 3)Range法 4)Replicate法。目前还没有一种数据分布方法能够优化所有情况的数据查询,另外,就算能找到一种良好的数据分布策略在系统初始的情况下达到最优,但是随着系统的运行,数据不断更新这种最优平衡一定会被打破。根据实际情况选择合适动态分布策略

  • tb丁原:同等硬件环境下,相比redis,tair,search,oceanbase,hbase等,oracle,mysql性能看起来总是差了一些,其实不管什么软件,设计思路上不外乎内存读写,顺序读写,顺序写随机读,随机写顺序读,随机读随机写这几种,还能有什么?

  • 微软中国MSDN:【批量操作SQL数据】我们在已经建好触发器的表中对数据进行一个批量更新操作的时候,系统会提示我们无法完成操作,这个时候就需要我们先将触发器停掉,然后再进行UPDATE操作,完后再开启触发器。alter table tablename disable trigger all 批处理的SQL语句 alter table tablename enable trigger all。

2011年6月3日星期五

设计模式 and OOD

推荐两篇值得仔细阅读的关于架构方面的文章,都是出自 Code Porject 上的 Al-Farooque Shubho 之手。


这两篇文章,倪大虾 同学已经翻译,看中文,移步这里:

2011年6月2日星期四

MySQL 压力测试工具 mysqlslap

FROM: MySQL 压力测试工具 mysqlslap

从 5.1.4 开始,MySQL 自带有一个压力测试工具 mysqlslap, 它通过模拟多个并发客户端访问 MySQL 来执行测试,使用起来非常简单。通过mysqlslap --help可以获得可用的选项,这里列一些主要的参数,更详细的说明参考官方手册

  • --auto-generate-sql, -a 自动生成测试表和数据。

  • --auto-generate-sql-load-type=type 测试语句的类型。取值包括:read,key,write,update和mixed(默认)。

  • --number-char-cols=N, -x N 自动生成的测试表中包含多少个字符类型的列,默认 1。

  • --number-int-cols=N, -y N 自动生成的测试表中包含多少个数字类型的列,默认 1。

  • --number-of-queries=N 总的测试查询次数(并发客户数×每客户查询次数)。

  • --query=name,-q 使用自定义脚本执行测试,eg: 可以调用自定义的一个存储过程或者 SQL 语句来执行测试。

  • --create-schema 指定测试的数据库。

  • --commint=N 多少条 DML 后提交一次。

  • --compress, -C 如果服务器和客户端支持都压缩,则压缩信息传递。

  • --concurrency=N, -c N 并发量,也就是模拟多少个客户端同时执行 SELECT。可指定多个值,以逗号或者--delimiter参数指定的值做为分隔符。

  • --engine=engine_name, -e engine_name 创建测试表所使用的存储引擎,可指定多个。

  • --iterations=N, -i N 测试执行的迭代次数。

  • --detach=N执行 N 条语句后断开重连。

  • --debug-info, -T打印内存和CPU的信息。

  • --only-print 只打印测试语句而不实际执行。

  • --defaults-file=mysql_configuration_file_directory 配置文件存放位置。

  • --socket=socket_directory, -S socket_directory socket文件位置。



测试的过程需要生成测试表和测试数据,mysqlslap 会自动生成一个名为 mysqlslap 的 schema,如果已经存在则先删除。可用--only-print来打印实际的测试过程。
[bash]
[root@localhost bin]# /usr/local/mysql/bin/mysqlslap -a --only-print
[/bash]

DROP SCHEMA IF EXISTS `mysqlslap`;
CREATE SCHEMA `mysqlslap`;
use mysqlslap;
CREATE TABLE `t1` (intcol1 INT(32) ,charcol1 VARCHAR(128));
INSERT INTO t1 VALUES (1804289383,'mxvtvmC9127qJNm06sGB8R92q2j7vTiiITRDGXM9ZLzkdekbWtmXKwZ2qG1llkRw5m9DHOFilEREk3q7oce8O3BEJC0woJsm6uzFAEynLH2xCsw1KQ1lT4zg9rdxBL');
......
DROP SCHEMA IF EXISTS `mysqlslap`;

可以看出,最后会删除一开始创建的 schema,so, 整个测试完成后不会在数据库中留下痕迹。
假如执行一次测试,分别模拟 50 和 100 个并发,都执行 1000 次查询,那么:
[bash]
[root@localhost bin]# /usr/local/mysql/bin/mysqlslap -a --concurrency=50,100 --number-of-queries=1000 --debug-info
[/bash]

Benchmark
Average number of seconds to run all queries: 0.676 seconds
Minimum number of seconds to run all queries: 0.676 seconds
Maximum number of seconds to run all queries: 0.676 seconds
Number of clients running queries: 50
Average number of queries per client: 20

Benchmark
Average number of seconds to run all queries: 0.922 seconds
Minimum number of seconds to run all queries: 0.922 seconds
Maximum number of seconds to run all queries: 0.922 seconds
Number of clients running queries: 100
Average number of queries per client: 10


User time 0.17, System time 0.40
Maximum resident set size 0, Integral resident set size 0
Non-physical pagefaults 1653, Physical pagefaults 0, Swaps 0
Blocks in 0 out 0, Messages in 0 out 0, Signals 0
Voluntary context switches 14740, Involuntary context switches 6135

Voluntary context switches 7319, Involuntary context switches 681

上结果可以看出,50 和 100 个并发分别得到一次测试结果(Benchmark),并发数越多,执行完所有查询的时间越长。为了准确起见,可以多迭代测试几次:
[bash]
[root@localhost bin]# /usr/local/mysql/bin/mysqlslap -a --concurrency=50,100 --number-of-queries=1000 --iterations=5 --debug-info
[/bash]

Benchmark
Average number of seconds to run all queries: 0.833 seconds
Minimum number of seconds to run all queries: 0.803 seconds
Maximum number of seconds to run all queries: 0.865 seconds
Number of clients running queries: 50
Average number of queries per client: 20

Benchmark
Average number of seconds to run all queries: 0.980 seconds
Minimum number of seconds to run all queries: 0.948 seconds
Maximum number of seconds to run all queries: 1.007 seconds
Number of clients running queries: 100
Average number of queries per client: 10


User time 1.03, System time 2.35
Maximum resident set size 0, Integral resident set size 0
Non-physical pagefaults 7148, Physical pagefaults 0, Swaps 0
Blocks in 0 out 0, Messages in 0 out 0, Signals 0
Voluntary context switches 115255, Involuntary context switches 4125


测试同时不同的存储引擎的性能进行对比:
[bash]
[root@localhost bin]# /usr/local/mysql/bin/mysqlslap -a --concurrency=50,100 --number-of-queries=1000 --iterations=5 --engine=myisam,innodb --debug-info
[/bash]

Benchmark
Running for engine myisam
Average number of seconds to run all queries: 0.781 seconds
Minimum number of seconds to run all queries: 0.766 seconds
Maximum number of seconds to run all queries: 0.800 seconds
Number of clients running queries: 50
Average number of queries per client: 20

Benchmark
Running for engine myisam
Average number of seconds to run all queries: 0.908 seconds
Minimum number of seconds to run all queries: 0.880 seconds
Maximum number of seconds to run all queries: 0.929 seconds
Number of clients running queries: 100
Average number of queries per client: 10

Benchmark
Running for engine innodb
Average number of seconds to run all queries: 0.897 seconds
Minimum number of seconds to run all queries: 0.858 seconds
Maximum number of seconds to run all queries: 0.929 seconds
Number of clients running queries: 50
Average number of queries per client: 20

Benchmark
Running for engine innodb
Average number of seconds to run all queries: 1.189 seconds
Minimum number of seconds to run all queries: 1.086 seconds
Maximum number of seconds to run all queries: 1.306 seconds
Number of clients running queries: 100
Average number of queries per client: 10


User time 2.02, System time 4.24
Maximum resident set size 0, Integral resident set size 0
Non-physical pagefaults 14556, Physical pagefaults 0, Swaps 0
Blocks in 0 out 0, Messages in 0 out 0, Signals 0
Voluntary context switches 172917, Involuntary context switches 52011

100 个并发时,InnoDB 引擎,运行 1000 句 SQL 平均要需要 1.189 秒;而对于 MyISAM, 为 0.908 秒。

测试自定义 SQL:
[bash]
[root@localhost bin]# /usr/local/mysql/bin/mysqlslap --defaults-file=/usr/local/mysql/etc/my.cnf --create-schema=hstestdb --concurrency=50,100 --number-of-queries=1000 --iterations=5 --query="SELECT * FROM hstestdb.hstesttbl WHERE k='k2'" --debug-info -u root -p -S /usr/local/mysql/tmp/mysql.sock
Enter password:
[/bash]

Benchmark
Average number of seconds to run all queries: 0.271 seconds
Minimum number of seconds to run all queries: 0.256 seconds
Maximum number of seconds to run all queries: 0.288 seconds
Number of clients running queries: 50
Average number of queries per client: 20

Benchmark
Average number of seconds to run all queries: 0.324 seconds
Minimum number of seconds to run all queries: 0.292 seconds
Maximum number of seconds to run all queries: 0.333 seconds
Number of clients running queries: 100
Average number of queries per client: 10


User time 0.22, System time 0.63
Maximum resident set size 0, Integral resident set size 0
Non-physical pagefaults 4355, Physical pagefaults 0, Swaps 0
Blocks in 0 out 0, Messages in 0 out 0, Signals 0
Voluntary context switches 16691, Involuntary context switches 2837

PHP extension for interfacing with MySQL Handler Socket

有关于 HandlerSocket 的介绍、性能及其安装,可参考Using SQL as NoSQL。而 PHP extension for interfacing with MySQL Handler Socket,实际上这里php-handlersocket有整体的介绍,包括其安装、使用方法。现在纯粹是因为自己测试时犯了一很基础的错误,所以,罚自己多敲点字。

安装


[bash]
[root@localhost php-handlersocket]# /usr/local/php/bin/phpize
[root@localhost php-handlersocket]# ./configure --with-php-config=/usr/local/php/bin/php-config
[root@localhost php-handlersocket]# make
[root@localhost php-handlersocket]# make install
[/bash]
说明:
1 编译时需要 libhsclient 库(libhsclient - HandlerSocket client library)。
2 安装成功时,在 PHP 的 extension dir 生成一名为 handlersocket.so,将extension=handlersocket.so加入 php.ini, 重启 PHP 服务。

HandlerSocket Class methods


HandlerSocket::construct

创建一 HandlerSocket Object。
[php]
HandlerSocket::__construct ( string $host, string $port [, array $options ] )
[/php]
参数:

  • $host MySQL 服务器 host name。

  • $port HandlerSocket 的端口地址。


返回值:
返回 HandlerSocket Object。

HandlerSocket::openIndex

在对数据库表做任何的增删改查操作前,必须先选择一索引。
[php]
public bool HandlerSocket::openIndex ( int $id, string $db, string $table, string $index, string $fields )
[/php]
参数:

  • $id HandlerSocket ID; 1 SELECT, 2 UPDATE, 3 INSERT, 4 DELETE。

  • $db 数据库名

  • $table 表名

  • $index 索引名, 可以是手动创建的索引名。这个参数可为空,一般指定时是用于 SELECT,eg: 指定为主键:HandlerSocket::PRIMARY

  • $fields 字段名(多个字段名,用逗号分隔),可为空。


返回值:
成功时返回 TRUE, 反之亦然。

HandlerSocket::executeSingle

在表上做增删改查操作。
[php]
public mixed HandlerSocket::executeSingle ( int $id, string $op, array $fields [, int $limit, int $skip, string $modop, array $values, array $filters, int $invalues_key, array $invalues ] )
[/php]
参数:

  • $id HandlerSocket ID; 1 SELECT, 2 UPDATE, 3 INSERT, 4 DELETE。

  • $op 操作符,有如下可选项, '=', '>=', '<=', '>', '<', '+'。

  • $fields 查询中所用到的字段,数组,其长度必须等于或小于指定的列数。

  • $limit 最多影响的行数(最开始根据这个函数名称有在怀疑这个参数,测试时发现,如果存在满足条件的多条记录时,会根据这个参数指定的值返回记录数)。

  • $skip 在检索记录前忽略掉的行数。

  • $modop 指定修改操作,可选值:'U', 'D'。

  • $values 数组,用于做 UPDATE 操作时指定修改的值。

  • $filters 过滤的选项。

  • $invalues_key ? (enabled : 0 / disabled : -1).

  • $invalues IN options


返回值:
返回做对应操作时的执行结果。

HandlerSocket::executeMulti

在一次调用中执行多个操作,即多个 HandlerSocket::executeSingle 的合并。
[php]
public mixed HandlerSocket::executeMulti ( array $requests )
[/php]
参数:

  • $requrest 多组 executeSingle 参数,用数组的形式体现。


注意:
等同于:HandlerSocket::executeSingle($requests00, $requests01, ...), HandlerSocket::executeSingle($requests10, ...) ...
返回结果:
返回做对应操作时的执行结果。

HandlerSocket::executeUpdate

To update a record from a table using an index.
[php]
public mixed HandlerSocket::executeUpdate ( int $id, string $op, array $fields, array $values [, int $limit, int $skip, array $filters, int $invalues_key, array $invalues ] )
[/php]
参数:

  • $id HandlerSocket ID; 2 UPDATE 。

  • $op 操作符,有如下可选项, '=', '>=', '<=', '>', '<', '+'。

  • $fields 查询中所用到的字段,数组,其长度必须等于或小于指定的列数。

  • $values UPDAET 时指定修改的值。

  • $limit 最多影响的行数。

  • $skip 在检索记录前忽略掉的行数。

  • $filters 过滤的选项。

  • $invalues_key ? (enabled : 0 / disabled : -1).

  • $invalues IN options


注意:
等同于:HandlerSocket::executeSingle($id, $op, $fields, $limit, $skip, 'U', $values, $filters, $invalues_key, $invalues)
返回值:
返回做对应操作时的执行结果。

HandlerSocket::executeDelete

To delete a record from a table using an index.
[php]
public mixed HandlerSocket::executeDelete ( int $id, string $op, array $fields [, int $limit, int $skip, array $filters, int $invalues_key, array $invalues ] )
[/php]
参数:

  • $id HandlerSocket ID; 4 DELETE 。

  • $op 操作符,有如下可选项, '=', '>=', '<=', '>', '<', '+'。

  • $fields 查询中所用到的字段,数组,其长度必须等于或小于指定的列数。

  • $limit 最多影响的行数。

  • $skip 在检索记录前忽略掉的行数。

  • $filters 过滤的选项。

  • $invalues_key ? (enabled : 0 / disabled : -1).

  • $invalues IN options


注意:
等同于:HandlerSocket::executeSingle($id, $op, $fields, $limit, $skip, 'D', NULL, $filters, $invalues_key, $invalues)
返回值:
返回做对应操作时的执行结果。

HandlerSocket::executeInsert

To insert a record from a table using an index.
[php]
public mixed HandlerSocket::executeInsert ( int $id, array $values )
[/php]
参数:

  • $id HandlerSocket ID; 3 INSERT 。

  • $values HandlerSocket::openIndex 指定的字段参数所对应的值,但是以数组的形式体现。


注意:
等同于:HandlerSocket::executeSingle($id, '+', $values, 0, 0, NULL, NULL, NULL) ,第三个参数中指定的值必须和在此之前调用 HandlerSocket::openIndex 时第五个参数指定的字段对应。
返回值:
返回做对应操作时的执行结果。

HandlerSocket::getError

取得最近一次的错误信息。
[php]
public string HandlerSocket::getError ( void )
[/php]
返回值:
返回最近的错误信息(时间上)。

Example


测试表 schema:
[sql]
CREATE TABLE `hstesttbl` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`k` char(6) DEFAULT NULL,
`v` char(6) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_hstesttbl_k` (`k`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
[/sql]

[php]
$host = 'localhost';
$port = 9998;
$port_wr = 9999;
$dbname = 'hstestdb';
$table = 'hstesttbl';

//GET
$hs = new HandlerSocket($host, $port);
if (!($hs->openIndex(1, $dbname, $table, HandlerSocket::PRIMARY, 'k,v'))) {
echo $hs->getError(), PHP_EOL;
die();
}

$retval = $hs->executeSingle(1, '=', array('k1'), 1, 0);
var_dump($retval);

$retval = $hs->executeMulti(
array(
array(1, '=', array('k1'), 1, 0),
array(1, '=', array('k2'), 1, 0)
)
);
var_dump($retval);
unset($hs);


//UPDATE
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(2, $dbname, $table, '', 'v'))) {
echo $hs->getError(), PHP_EOL;
die();
}

if ($hs->executeUpdate(2, '=', array('k1'), array('V1'), 1, 0) === false) {
echo $hs->getError(), PHP_EOL;
die();
}

unset($hs);


//INSERT
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(3, $dbname, $table, '', 'k,v'))) {
echo $hs->getError(), PHP_EOL;
die();
}

if ($hs->executeInsert(3, array('k2', 'v2')) === false) {
echo $hs->getError(), PHP_EOL;
}
if ($hs->executeInsert(3, array('k3', 'v3')) === false) {
echo 'A', $hs->getError(), PHP_EOL;
}
if ($hs->executeInsert(3, array('k4', 'v4')) === false) {
echo 'B', $hs->getError(), PHP_EOL;
}

unset($hs);


//DELETE
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(4, $dbname, $table, '', ''))) {
echo $hs->getError(), PHP_EOL;
die();
}

if ($hs->executeDelete(4, '=', array('k2')) === false) {
echo $hs->getError(), PHP_EOL;
die();
}
[/php]

PS: 因为建立测试表时忘记指定存储引擎为 InnoDB, 测试 INSERT 操作时,怎样都是失败。后面为了验证问题的出处,用 perl 的 API 做同样的测试操作,结果也是失败。查看表结构后,修改储存引擎为 InnoDB,才成功。只是这个问题的错误信息太难理解,就几个数字,在没找到答案之前,害我还去查看了下 HandlerSocket 的源代码,当然,没有从中得到任何的提示。

2011年5月31日星期二

推荐《探索推荐引擎的秘密》系列

FROM: 推荐《探索推荐引擎的秘密》系列

最近推荐引擎成为显学,主要原因应该是电子商务的蓬勃发展。头些日子和图灵的两位老师吃饭,我甚至了解到因为推荐引擎以及机器学习领域的日渐火爆,图灵出的线性代数最近销量都很好,更别提大家现在到处都可以看到这个领域相关的招聘。我最近的创业项目iApp4Me其实也是一个推荐引擎的应用,我关注这个领域有很长一段时间了。这个领域还很新,还有很多未知的可能性,非常有意思。

不过在我关注的过程中,我发现很多人其实对什么是推荐引擎一知半解,这有点像5-6年前的技术界对搜索引擎的理解一样,那时候有人曾在CSDN言之凿凿的说Google其实用的就是Mysql无非是服务器多,而且管理员水平高而已。虽然大多数的高校的计算机专业都有信息检索课程,但是很多甚至是名校的毕业生也说不清楚搜索引擎是怎么回事儿。

事实上技术界开始对搜索引擎技术大规模的扫盲是从lucene这个开源软件的出现以后开始的,在这个问题上某Cutting同学居功至伟。后来也是在他组织下Lucene项目组开发孵化出来了Google的MapRuduce架构的开源实现Hadoop。在Yahoo、在阿里巴巴以及全世界很多公司和组织中Hadoop都起到了很大的作用。后来,lucene项目组还孵化了Mahout,一个基于Hadoop和Lucene的机器学习、推荐引擎项目。现在推荐引擎的实践中,这个Mahout这个项目也起到了很大的作用。值得推荐的相关开源项目还有weka,Javaml,numpy等。

当然光有这些开源项目也是不够的,如果你完全不理解推荐引擎的理论,你也很难玩转它。今天我发现了IBM开发者社区近期出现了一组文章《探索推荐引擎的秘密》,写的很好,可以算作非常好的这个领域的综述的文章,非常适合给不了解或者一知半解的人建立概念,所以在这里推荐给大家。


PS:
前几日,titan 推荐我看这篇日志,当然,重点还是文中提到的 IBM 开发者社区推出的关于推荐引擎的系列文章。推荐系统,去年有一阵子看过一些文章,但到此刻,基本上都已归还给作者,so, 现在将其转载过来,以备自己“捡”起来时资料的查找。

还有这篇文章 智能推荐系统 ,很值得一看。

Web 开发人员速查卡

FROM: Web开发人员速查卡

无论你是多牛的程序员,你都无法记住所有的东西。而很多时候,查找某些知识又比较费事。所以,网上有很多Cheat Sheets,翻译成小抄也好 ,速查卡也好,总之就是帮你节省 时间的。之前给大家介绍过Web设计的速查卡25个jQuery的编程小抄,还有程序员小抄大全,今天转一篇开发人员的速查卡,源文在这里。下面的文章我就不翻译了。

HTML Cheat Sheet




CSS Cheat Sheets




Adobe Flash Cheat Sheets




ASP Cheat Sheets




PHP Cheat Sheets




MySQL Cheat Sheets




JavaScript Cheat Sheets




jQuery Cheat Sheets




Unicode Cheat Sheets




XML Cheat Sheets




mod_rewrite and .htaccess Cheat Sheets


2011年5月29日星期日

Super Smack

Super Smack 是一个强大的压力测试工具,支持 MySQL, PostgreSQL, Oracle。最开始的版本是由Sasha Pachev写成,由Jeremy Zawodny在维护,而现在,是
Tony Bourke
在维护,根据 Tony Bourke 的 开发 log 来看,2005-08-30 后,super smack 就已经停止发布新的版本,但这并不妨碍我们现在继续使用它(这个工具的开发者和维护者很伟大)。


安装


安装有点点麻烦,主要是编译时会出现一些问题。
[bash]
[root@localhost tmp]# wget http://vegan.net/tony/supersmack/super-smack-1.3.tar.gz
[root@localhost tmp]# tar xvzf super-smack-1.3.tar.gz
[root@localhost super-smack-1.3]# ./configure --prefix=/usr/local/super-smack --with-mysql --with-mysql-lib=/usr/local/mysql/lib/mysql --with-mysql-include=/usr/local/mysql/include/mysql
[root@localhost super-smack-1.3]# make
[root@localhost super-smack-1.3]# make install
[/bash]
说明

1 编译时,必须指定它所支持的数据库管理系统,否则会报如下错误。

......
configure: error:

You should include support for at least one database!

Reconfigure with one or more of:
--with-mysql
--with-pgsql
--with-oracle

2 选择支持 MySQL 后, 在 MySQL 编译安装的情况下时, 也需要在编译参数中指定 MySQL 的 lib。
3 编译时,dictionary.h 和 super-smack.cc 报错:

......
dictionary.h:93: error: ‘strlen’ was not declared in this scope
super-smack.cc:126: error: ‘strlen’ was not declared in this scope

在 super smack 源代码的 src 目录,找到 dictionary.h, super-smack.cc,分别加上#include <string.h>
4 编译时,query.cc 报错

query.cc:200: error: cast from ‘char*’ to ‘unsigned int’ loses precision
query.cc:200: error: cast from ‘char*’ to ‘unsigned int’ loses precision
query.cc:219: error: cast from ‘char*’ to ‘unsigned int’ loses precision
query.cc:219: error: cast from ‘char*’ to ‘unsigned int’ loses precision

在 super smack 源代码的 src 目录, 找到 query.cc文件,将上面指定的 200, 219 行中的unsigned int改为unsigned long

用其测试 MySQL 之前奏


1 看 Makefile 才知道, smack 文件是放在 /usr/share/smacks 这个目录下(开始并不知道源代码中有一份), 产生的数据文件是在/var/smack-data目录下
[bash]
...
SMACKS_DIR = /usr/share/smacks
DATADIR = /var/smack-data
...
[/bash]

2 根据 MySQL 的参数对应修改 /usr/share/smacks 目录下的 select-key.smack 和 update-select.smack 文件。包括 user, host, db, pass, 还有,最重要的 socket 路径。

3 未将 super smack 的 bin 目录加入 PATH 时,则还需:
[bash]
gen_data_file "gen-data -n 90000 -f %12-12s%n,%25-25s,%n,%d";
#改为
gen_data_file "./gen-data -n 90000 -f %12-12s%n,%25-25s,%n,%d";
#或者直接
gen_data_file "/usr/local/super-smack/bin/gen-data -n 90000 -f %12-12s%n,%25-25s,%n,%d";
[/bash]

4 因为在 select-key.smack 和 update-select.smack 文件中指定的数据文件是 words.dat, 而安装默认情况下 words.dat 为空文件:
[bash]
[root@localhost smack-data]# ls -al
total 5320
drwxr-xr-x 2 root root 4096 May 26 18:12 .
drwxr-xr-x 24 root root 4096 May 26 17:25 ..
-rw-r--r-- 1 root root 5421337 May 26 17:25 .. http_auth.dat
-rw-r--r-- 1 root root 0 May 26 17:25 .. words.dat
[/bash]
所以,需将 select-key.smack 和 update-select.smack 文件中指定的数据 words.dat 改为 http_auth.dat(其实为了统一,最好也是 http_auth.dat,因为文件中指定测试的表名是 http_atuh)。

当然,为了不修改,也可以在开始先执行如下命令:
[bash]
[root@localhost bin]# /usr/local/super-smack/bin/gen-data -n 90000 -f %12-12s%n,%25-25s,%n,%d > /var/smack-data/words.dat
[/bash]


5 将 /usr/share/smacks 下文件 copy 到 /usr/local/super-smack/bin/ 目录下:
[bash]
[root@localhost super-smack]# cp /usr/share/smacks/* bin/
[/bash]

运行


[bash]
[root@localhost bin]# ./super-smack -d mysql select-key.smack 20 1000
Query Barrel Report for client smacker1
connect: max=2204ms min=1ms avg= 221ms from 20 clients
Query_type num_queries max_time min_time q_per_s
select_index 40000 0 0 5017.26
[/bash]
参数:

  • -d 指定测试的数据库管理系统的类型。

  • 20 20 个线程

  • 1000 每个线程 1000 个查询


实际上,还有-D参数来指定数据文件,默认路径如前面提到是 /var/smack-data, 这个路径需跟 select-key.smack 和 update-select.smack 指定的一致。

返回结果:

  • max=2204ms min=1ms avg= 221ms from 20 clients 连接的最大、最小及平均花费时间。

  • q_per_s|5017.26 QPS,每秒请求处理数

  • 40000, 脚本中,对查询次数做了翻倍处理, 所以, 20 × 1000 x 2 = 40,000.

2011年5月25日星期三

Install PHP 5.3 using source code

compile configuration
[bash]
./configure \
--prefix=/usr/local/php --with-config-file-path=/usr/local/php/etc \
--with-mysql=/usr/local/mysql --with-mysqli=/usr/local/mysql/bin/mysql_config \
--with-freetype-dir \
--with-jpeg-dir \
--with-png-dir \
--with-zlib \
--with-libxml-dir \
--enable-xml \
--disable-debug \
--disable-rpath \
--enable-safe-mode \
--enable-bcmath \
--enable-shmop \
--enable-sysvsem \
--enable-inline-optimization \
--without-sqlite \
--with-curlwrappers \
--enable-mbregex \
--enable-mbstring \
--with-mcrypt \
--enable-cgi \
--enable-fpm --with-fpm-user=www --with-fpm-group=www
[/bash]

2011年5月23日星期一

Libtool library used but `LIBTOOL' is undefined

Install HandlerSocket 时,报如下错误:

handlersocket/Makefile.am:3: Libtool library used but `LIBTOOL' is undefined


(Solution) Libtool library used but `LIBTOOL' is undefined这里有提到类似的问题,解决办法很简单,合并文件后,删除多余的,然后创建一符号链接。

This is caused because FreeBSD renames the default tools, like aclocal to aclocal19. When aclocal is run, it looks for files in its FreeBSD set directory,
/usr/local/share/aclocal19 but most normal apps, like libtool, install to /usr/local/share/aclocal. The solution? Simple! Just merge the contents into one
directory, delete the other, and create a symlink!

当然,也可以直接:
[bash]
cp -R /usr/local/share/aclocal /usr/share/
[/bash]

vim 正则匹配

:%s/(\d\+,//gc 匹配 (123, , (1,
:%s/test=\(\d\+\)/test=\1/gc \1 匹配第一个 \( \) 的部分 \2 以此类推

jQuery Tab

FROM: jQuery idTabs

推荐一 jQuery 实现 Tab 的插件,代码很简短,而且调用也非常简单。head 加上:
[html]
<script type="text/javascript" src="jquery.idTabs.min.js"></script>
[/html]

class="idTabs" element 中,任何<a href="#tabs">以这种形式调用,被点击时都会显示对应 id="tab" element 中的内容。如下:

[html]
<ul class="idTabs">
<li><a href="#jquery">jQuery</a></li>
<li><a href="#official">Tabs 3</a></li>
</ul>
<div id="jquery">If you haven't checked out ...</div>
<div id="official">idTabs is only a simple ...</div>
[/html]
demo

PHP proxy

[php]
$requestUrl = 'http://request-url.com';
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $requestUrl);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_TIMEOUT, '300');
curl_setopt($curl, CURLOPT_PROXY, 'proxy-ip:proxy:port');
curl_exec($curl);
curl_close($curl);
[/php]

跳出.each()

[js]
$.each(objs, function(i, n) {
if(n.attr('checked') == true) {
return false;
}
});
[/js]

return false 跳出 jQuery .each().

换到新的公司后,有专门的前端工程师,以至于之前知道的 JS 也都忘记。而最近做内部沟通系统时,一切需要自己实现,才又捡起来。

Using MySQL as a NoSQL

FROM: Using MySQL as a NoSQL - A story for exceeding 750,000 qps on a commodity server

由于 MySQL 的局限性,很多站点都采用了 MySQL+Memcached 的架构。另外一些站点放弃 MySQL 而采用 NoSQL,比如 TokyoCabinet/Tyrant 等。不可否认,在做一些简单查询 (尤其 PK 查询) 的时候,NoSQL 比 MySQL 要快很多很多。而且网站上的绝大多数查询都是这样的简单查询。

像其他大规模的公司一样,DeNA 也面临过类似的问题。但最后我们采用的是一完全不同的方法, 仅使用了 MySQL。我们仍然使用 Memcached 做前端缓存(例如,预处理 HTML, 数量/摘要 信息),但在后端,既没有使用 Memcached 缓存任何记录,也没有使用 NoSQL,这是为什么呢?因为与其他的 NoSQL 产品相比,我们的 MySQL 能得到更好的性能。 在我们的基准测试中,一普通的 MySQL/InnoDB 5.1 服务器达到了 750,000+ QPS,生产环境中的性能当然更不列外。或许,你们很难相信这个数字,但这是事实。我将在以下分享我们的经验。

(作者经历)2010-08,我离开了 Oracle, 现在任职于日本最大社交游戏平台供应商之一的 DeNA。

SQL 真的适合做 PK 查询?


在每秒中,需要做多少次的 PK 查询了?在 DeNA 公司的应用中,经常要进行 PK 查询。比如根据 user id 取出 userinfo,根据 diary id 取出日志内容, 对于这样的需求,不用说,Memcached 和 NoSQL 都相当适合。在简单的多线程 "Memcached GET"基准测试中,很可能每秒进行 400,000 次 get 操作,即使 Memcached client 在不同的服务器。在一台 Nehalem box 2.5GHz x 8 核 CPU, Broadcom 四端口千兆网卡的服务器上,最新的 libMemcached 和 Memcached 每秒可达到 420,000 次 get 操作。

在 MySQL 下, 每秒可作多少次的 PK 查询呢, 我们可用 sysbench, super-smack or mysqlslap 等来进行基准测试
[bash]
[matsunobu@host ~]$ mysqlslap --query="select user_name,.. from test.user where user_id=1" \
--number-of-queries=10000000 --concurrency=30 --host=xxx -uroot
[/bash]

通过如下命令,很快就得知 InnoDB 的 QPS 大概为 100,000, 几乎只有 Memcached 的 1/4.
[bash]
[matsunobu@host ~]$ mysqladmin extended-status -i 1 -r -uroot \
| grep -e "Com_select"
[/bash]


...
| Com_select | 107069 |
| Com_select | 108873 |
| Com_select | 108921 |
| Com_select | 109511 |
| Com_select | 108084 |
| Com_select | 108483 |
| Com_select | 108115 |
...


看上去, 100, 000+ QPS 也不是太差,但为什么 MySQL 比 Memcached 差这么多呢,MySQL 到底在做什么呢。从 vmstat 的统计信息得知, %user 和 %system 的数据都非常高.
[bash]
[matsunobu@host ~]$ vmstat 1
[/bash]


r b swpd free buff cache in cs us sy id wa st
23 0 0 963004 224216 29937708 58242 163470 59 28 12 0 0
24 0 0 963312 224216 29937708 57725 164855 59 28 13 0 0
19 0 0 963232 224216 29937708 58127 164196 60 28 12 0 0
16 0 0 963260 224216 29937708 58021 165275 60 28 12 0 0
20 0 0 963308 224216 29937708 57865 165041 60 28 12 0 0


再看 Oprofile 输出,可知 CPU 消耗的出去:

samples % app name symbol name
259130 4.5199 mysqld MYSQLparse(void*)
196841 3.4334 mysqld my_pthread_fastmutex_lock
106439 1.8566 libc-2.5.so _int_malloc
94583 1.6498 bnx2 /bnx
284550 1.4748 ha_innodb_plugin.so.0.0.0 ut_delay
67945 1.1851 mysqld _ZL20make_join_statisticsP4JOINP10TABLE_LISTP4ItemP16st_dynamic_array
63435 1.1065 mysqld JOIN::optimize()
55825 0.9737 vmlinux wakeup_stack_begin
55054 0.9603 mysqld MYSQLlex(void*, void*)
50833 0.8867 libpthread-2.5.so pthread_mutex_trylock
49602 0.8652 ha_innodb_plugin.so.0.0.0 row_search_for_mysql
47518 0.8288 libc-2.5.so memcpy
46957 0.8190 vmlinux .text.elf_core_dump
46499 0.8111 libc-2.5.so malloc


MySQL 的 SQL 解析阶段,有调用 MYSQLparse() 和 MYSQLlex(); 查询优化阶段,调用 make_join_statistics() 和 JOIN::optimize()。很明显,主要耗资源的是SQL 层,而不是 InnoDB 存储层。与 Memcached/NoSQL 比起来,MySQL 还要额外做一些工作:

  • Parsing SQL statements 解析 SQL.

  • Opening, locking tables 打开并锁定表.

  • Making SQL execution plans SQL 执行计划.

  • Unlocking, closing tables 解锁并关闭表.




另外,MySQL 还必须要做大量的并发控制,比如在发送/接收网络数据包的时候,fcntl() 就要被调用很多次; Global mutexes 比如 LOCK_open,LOCK_thread_count 也被频繁地取得/释放。所以, 在 Oprofile 的输出中,排在第二位的是 my_pthread_fastmutex_lock()。并且 %system 占用的 CPU 相当高(28%)。

其实 MySQL 开发团队和外围的开发团体已意识到大量并发控制对性能的影响,MySQL5.5 中已经解决了一些问题。未来的 MySQL 版本中,应该会越来越好。

还有一个大的问题是,%user 达到了60%。互斥量的争夺导致 %system 上增,而不是 %user,即使 MySQL 内部关于互斥量的的问题都得到修复,还是很难达到我们所期望的 300,000 QPS.也许,会有人提到使用 HANDLER ,但是因为在解析 SQL时,opening/closing table 还是必须的,所以对于提高吞吐量,它还是只能爱莫能助。



在完全内存操作的情况时, CPU的效率非常重要


如果只有一小部分数据进入内存,那么 SQL 带来的消耗可以忽略不计。很简单,因为磁盘的 I/0 操作所带来的消耗会要大,这种情况下时,就不需要太过的去考虑 SQL 所带来的消耗。

但是,在大多数的 hot MySQL 服务器中, 大部分的数据都是因为全部载入至内存中而变的只受 CPU 的限制。Profiling 的结果就类似上所述的那样: SQL 层消耗了大量的资源。假设,需要做大量的 PK 查询(i.e. SELECT x FROM t WHERE id=?)或者是做 LIMIT 的范围查询, 即使有 70-80% 都是在同一张表中做 PK 查询(仅仅只是查询条件中给定的值不同,即 value 不同而已), MySQL 还是每次需要去做 parse/open/lock/unlock/close, 这对我们来说,是非常影响效率的。


NDBAPI


到底有没有好的方法来减少 MySQL SQL 层的 CPU 资源/争夺呢? 如果使用 MySQL Cluster, NDBAPI 不失为一个很好的解决办法。 在我还是 MySQL/Sun/Oracle 的顾问时,就见到过很多客户对SQL Node + NDB performance 感到非常不爽,但当他们用了 NDBAPI 客户端后,发现性能调提高了 N 倍。当然,在 MySQL Cluster 中是可以同时使用 NDBAPI 和 SQL 的,但在做频繁的访问模式时还是推荐使用 NDBAPI,而在 ad-hoc 或者 查询不频繁的情况下使用 SQL + MySQL + NDB。

以快捷的速度访问 API, 这正是我们需要的,但同时我们也想在 ad_hoc 或者复杂的查询的情况时还是使用 SQL. 像其他的 web service, DeNA 使用的是 InnoDB, 转为 NDB,这并不是一件容易的事情,因为内置InnoDB 即不支持 SQL 也不支持网络层的服务。

HandlerSocket —— 一个采用 NoSQL 网络协议的MySQL插件


最好的办法可以是在 MySQL 的内部,实现一以 MySQL plugin 的形式存在的 NoSQL 的网络服务。它侦听在某端口来接收采用 NoSQL 协议/API 的通讯, 然后通过 MySQL 内部的存储引擎 API 来直接访问 InnoDB。这种方法的理念类似于 NDBAPI, 但是它可以做到与 InnoDB 通讯。

这个理念最初是去年由 Kazuho OkuCybozu Labs 上提出的,他曾写过采用 Memcached protocols 通讯的MyCached UDF。而我的大学同学实现了另外一个插件 -- HandlerSocket, 下面图描述了 HandlerSocket 具体做了哪些工作:
mysql_HandlerSocket.png

图1 What is Hanldersocket?


因为 HandlerSocket 是以 MySQL daemaon plugin 形式存在,所以在应用中可把 MySQL 当 NoSQL 使用. 它最大的功能是实现了与存储引擎交互,比如 InnoDB,而这不需要任何的 SQL 方面的开销. 访问 MySQL 的 table 时,当然她也是需要 open/close table 的,但是 它并不是每次都去 open/close table, 因为它会将以前访问过的 table 保存下来以供来是使用,而 opening/closing tables 是最耗资源的,而且很容易引起互斥量的争夺,这样一来,对于提高性能,非常有效。在流量变小时, HandlerSocket 会 close tables, 所以,它不会阻塞 administrative commands (DDL).


它与MySQL + Memcached 的区别在哪呢? 对比图1 和图2 ,可从中看出其不同点。图2 展示了典型的 MySQL + Memecached 的使用. 因为 Memcached 的 get 操作比 MySQL 的内存中/磁盘上的主键查询要快很多,所以 Memcached 用于缓存数据库记录。如果 HandlerSocket 的查询速度能和 Memcached 媲美,我们就不需要使用 Memcached 来缓存记录。
mysql_memcached.png

图2 Common architecture pattern for MySQL + memcached


使用 HandlerSocket


举一个例子,假设有一 user 表,通过 user_id 来获取用户信息:
[sql]
CREATE TABLE user
(
user_id INT UNSIGNED PRIMARY KEY,
user_name VARCHAR(50),
user_email VARCHAR(255),
created DATETIME
)
ENGINE=InnoDB;
[/sql]

用 SELECT 语句获取用户信息
[sql]
mysql> SELECT user_name, user_email, created FROM user WHERE user_id=101;
+---------------+-----------------------+---------------------+
| user_name | user_email | created
| +---------------+-----------------------+---------------------+
| Yukari Takeba | yukari.takeba@dena.jp | 2010-02-03 11:22:33
| +---------------+-----------------------+---------------------+
1 row in set (0.00 sec)
[/sql]

下面我们来看看如何使用 HandlerSocket 完成同样的事情.

安装 HandlerSocket

HandlerSocket具体安装步骤请参考这里,基本步骤如下:

  • 1 下载HandlerSocket

  • 2 编译 HandlerSocket(客户端和服务端)

  • [bash]
    [root@localhost handlersocket]# ./autogen.sh
    [root@localhost handlersocket]# ./configure --with-mysql-source=mysql-source-dir --with-mysql-bindir=mysql-server-bin-dir
    [root@localhost handlersocket]# make
    [root@localhost handlersocket]# make install
    [/bash]

  • 3 安装 HandlerSocket
    将如下内容添加至 MySQL 配置文件 my.cnf
    [bash]
    [mysqld]
    loose_handlersocket_port = 9998
    # the port number to bind to (for read requests)
    loose_handlersocket_port_wr = 9999
    # the port number to bind to (for write requests)
    loose_handlersocket_threads = 16
    # the number of worker threads (for read requests)
    loose_handlersocket_threads_wr = 1
    # the number of worker threads (for write requests)
    open_files_limit = 65535
    # to allow handlersocket accept many concurrent
    # connections, make open_files_limit as large as
    # possible.
    [/bash]
    以 root 身份登录 MySQL
    [sql]
    mysql> INSTALL PLUGIN 'handlersocket' soname 'handlersocket.so';
    [/sql]
    重启 MySQL 服务。


因为 HandlerSocket是 MySQL 插件,所以可以象使用其它插件,如 InnoDB, Q4M 和 Spider 那样使用它,即不需要修改 MySQL 源代码,MySQL 最好是 5.1 或更高版本,编译 HandlerSocket 时需要 MySQL 源码和 MySQL bin 库。
书写 HandlerSocket 客户端代码

目前已提供 C++ 和 perl 调用的客户端库,下面是使用 perl 调用的实例代码:
[perl]
#!/usr/bin/perl

use strict;
use warnings;
use Net::HandlerSocket;

#1. establishing a connection
my $args = { host => 'ip_to_remote_host', port => 9998 };
my $hs = new Net::HandlerSocket($args);

#2. initializing an index so that we can use in main logics.
# MySQL tables will be opened here (if not opened)
my $res = $hs->open_index(0, 'test', 'user', 'PRIMARY',
'user_name,user_email,created');
die $hs->get_error() if $res != 0;

#3. main logic
#fetching rows by id
#execute_single (index id, cond, cond value, max rows, offset)
$res = $hs->execute_single(0, '=', [ '101' ], 1, 0);
die $hs->get_error() if $res->[0] != 0;
shift(@$res);
for (my $row = 0; $row < 1; ++$row) {
my $user_name= $res->[$row + 0];
my $user_email= $res->[$row + 1];
my $created= $res->[$row + 2];
print "$user_name\t$user_email\t$created\n";
}

#4. closing the connection
$hs->close()
[/perl]

[perl]
#!/usr/bin/perl

use strict;
use warnings;
use Net::HandlerSocket;

#1. establishing a connection
my $args = { host => 'ip_to_remote_host', port => 9998 };
my $hs = new Net::HandlerSocket($args);

#2. initializing an index so that we can use in main logics.
# MySQL tables will be opened here (if not opened)
my $res = $hs->open_index(0, 'test', 'user', 'PRIMARY',
'user_name,user_email,created');
die $hs->get_error() if $res != 0;

#3. main logic
#fetching rows by id
#execute_single (index id, cond, cond value, max rows, offset)
$res = $hs->execute_single(0, '=', [ '101' ], 1, 0);
die $hs->get_error() if $res->[0] != 0;
shift(@$res);
for (my $row = 0; $row < 1; ++$row) {
my $user_name= $res->[$row + 0];
my $user_email= $res->[$row + 1];
my $created= $res->[$row + 2];
print "$user_name\t$user_email\t$created\n";
}

#4. closing the connection
$hs->close();
[/perl]
上面代码是通过 user_id=101 条件在 user 表获取用户 user_name, user_email和 created 信息,得到的结果应该和之前在 MySQL client 查询出来的结果一样。
[bash]
[matsunobu@host ~]$ perl sample.pl
Yukari Takeba yukari.takeba@dena.jp 2010-02-03 11:22:33
[/bash]
对于大多数Web应用程序而言,保持轻量级的 HandlerSocket 连接是一个很好的做法(持续连接),让大量的请求可以集中于主要逻辑(上面代码中的#3部分)。
HandlerSocket 协议是一个小尺寸的基于文本的协议,和 Memcached 文本协议类似,可以使用 telnet 通过 HandlerSocket 获取数据。
[bash]
[matsunobu@host ~]$ telnet 192.168.1.2 9998
Trying 192.168.1.2...
Connected to xxx.dena.jp (192.168.1.2).
Escape character is '^]'.
P 0 test user PRIMARY user_name,user_email,created
0 1
0 = 1 101
0 3 Yukari Takeba yukari.takeba@dena.jp 2010-02-03 11:22:33
[/bash]


基准测试


现在是时候展示基准测试结果,使用上面的 user 表,从多线程远程客户端测试了执行主键查询操作的次数,所有用户数据都装入到内存中(我测试了 100 万行),也用类似的数据测试了 Memcached(我使用 libMemcached 和 Memcached_get() 获取用户数据),在 MySQL SQL 测试中,我使用了的是传统的 SELECT 语句: "SELECT user_name, user_email, created FROM user WHERE user_id=?", Memcached 和 HandlerSocket 客户端代码均使用 C/C++ 编写,所有客户端程序都位于远程主机上,通过 TCP/IP 连接到 MySQL/Memcached。最高的吞吐量情况如下:

approx qps server CPU util
MySQL via SQL 105,000 %us 60% %sy 28%
Memcached 420,000 %us 8% %sy 88%
MySQL via HandlerSocket 750,000 %us 45% %sy 53%


HandlerSocket的吞吐量比使用传统 SQL 时高出 7.5, 而且 %us 也只有使用传统 SQL 时的3/4, 这说明 MySQL 的 SQL 层是非常耗资源的,如果能跳过这一层,性能肯定会大大提升。有趣的是,MySQL 使用 HandlerSocket 时的速度比使用 Memcached 也要快 178%,并且 Memcached 消耗的 %sy 资源也更多。所以虽然 Memcached 是一个很好的产品,但仍然有优化的空间。

下面是oprofile输出内容,是在 MySQL HandlerSocket 测试期间收集到的,在核心操作,如网络数据包处理,获取数据等的 CPU 资源消耗(bnx2是一个网络设备驱动程序)。

samples % app name symbol name
984785 5.9118 bnx2 /bnx2
847486 5.0876 ha_innodb_plugin.so.0.0.0 ut_delay
545303 3.2735 ha_innodb_plugin.so.0.0.0 btr_search_guess_on_hash
317570 1.9064 ha_innodb_plugin.so.0.0.0 row_search_for_mysql
298271 1.7906 vmlinux tcp_ack
291739 1.7513 libc-2.5.so vfprintf
264704 1.5891 vmlinux .text.super_90_sync

248546 1.4921 vmlinux blk_recount_segments
244474 1.4676 libc-2.5.so _int_malloc
226738 1.3611 ha_innodb_plugin.so.0.0.0 _ZL14build_template P19row_prebuilt_structP3THDP8st_tablej
206057 1.2370 HandlerSocket.so dena::hstcpsvr_worker::run_one_ep()
183330 1.1006 ha_innodb_plugin.so.0.0.0 mutex_spin_wait
175738 1.0550 HandlerSocket.so dena::dbcontext:: cmd_find_internal(dena::dbcallback_i&, dena::prep_stmt const&, ha_rkey_function, dena::cmd_exec_args const&)
169967 1.0203 ha_innodb_plugin.so.0.0.0 buf_page_get_known_nowait
165337 0.9925 libc-2.5.so memcpy
149611 0.8981 ha_innodb_plugin.so.0.0.0 row_sel_store_mysql_rec
148967 0.8943 vmlinux generic_make_request


因为 HandlerSocket 是运行于 MySQL 内部,直接与 InnoDB 交互,所以,可以使用常见的 SQL 命令,如 SHOW GLOBAL STATUS 获得统计信息,Innodb_rows_read 达到了 750000+ 是值得一看的。
[bash]
$ mysqladmin extended-status -uroot -i 1 -r | grep "InnoDB_rows_read"
...
| Innodb_rows_read | 750192 |
| Innodb_rows_read | 751510 |
| Innodb_rows_read | 757558 |
| Innodb_rows_read | 747060 |
| Innodb_rows_read | 748474 |
| Innodb_rows_read | 759344 |
| Innodb_rows_read | 753081 |
| Innodb_rows_read | 754375 |
...
[/bash]

测试用机的详细信息如下:


















型号戴尔PowerEdge R710
CPUNehalem 8核,E5540@2.53GHz
内存32GB(所有数据都装入缓冲池)
MySQL5.1.50 InnoDB
Memcached/libMemcached1.4.5(Memcached),0.44(libMemcached)
NetworkBoradcom NetXtreme II BCM5709 1000Base-T(内建四端口,使用了其中三个)

Memcached 和 HandlerSocket 都做了网络 I/O 限制,当我测试单个端口时,HandlerSocket 的 QPS 为 260000,而 Memcached 为 220000。 

HandlerSocket 的特点和优势


如下所述,HandlerSocket 有其自己的特点和优势,而其中一些对我们来说, 是真的很给力.
支持多种查询模式

HandlerSocket 目前支持 主键/唯一性查询,非唯一性索引查询,范围扫描,LIMIT 和 INSERT/UPDATE/DELETE,但还不支持未使用任何索引的操作。另外,multi_get()(类似于in(1,2,3), 只需一次网络往返)还可获取多行数据。到这里可查询详细信息。

处理大量并发连接

HandlerSocket 连接是轻量级的,因为 HandlerSocket 采用epoll()worker-thread/thread-pooling 架构,而 MySQL 内部线程的数量是有限的(可以由 my.cnf中的 handlersocket_threads参数控制),所以即使建立上千万的网络连接到 HandlerSocket,它的稳定性也不会受到任何影响(消耗太多的内存,会造成巨大的互斥竞争等其他问题,如bug#26590bug#33948bug#49169)。

及其优秀的性能

HandlerSocket,如上所描述, 相对于其它 NoSQL 阵容,性能表现一点也不逊色。事实上,我还未曾见过哪个 NoSQL 产品在一台普通服务器上可达到 750000+ 次查询。它不仅没有调用与 SQL 相关的函数,还优化了网络/并发相关的问题。

  • 更小的网络数据包
    和传统 MySQL 协议相比,HandlerSocket 协议更简短,因此整个网络的流量更小。

  • 运行有限的 MySQL 内部线程数
    参考上面的内容。

  • 将客户端请求分组
    当大量的并发请求抵达 HandlerSocket 时,每个工作线程尽可能多地聚集请求,然后同时执行聚集起来的请求和返回结果。这样,通过牺牲一点响应时间,而大大地提高性能。例如,你可以得到以下好处,如果有人感兴趣,我会在今后的文章中对它们加以深入的解释。
    减少fsync()调用的次数.
    减少复制延迟.



无重复缓存

当使用 Memcached 缓存 MySQL/InnoDB 记录时,在 Memcached 和 InnoD B缓冲池中均缓存了这些记录,因此效率非常低(内存仍然很贵). 而采用 HandlerSocket插件, 由于它访问 InnoDB 存储引擎,记录缓存在 InnoDB 缓冲池中,这样,其它 SQL 语句就可以重复使用它。

无数据不一致的现象

由于数据只存储在一个地方(InnoDB 内),不像使用 Memcached 时,需要在 Memcached 和 MySQL 之间检查数据一致性。

崩溃安全

后端存储是 InnoDB,它是事务性和崩溃安全的,即使有设置innodb-flush-log-at-trx-commit!=1,在服务器崩溃时也只会丢掉 < 1s 内的数据。

可从 MySQL 客户端使用 SQL

在许多情况下,人们仍然希望使用 SQL(如生产摘要报告),这就是为什么我们不能使用嵌入式 InnoDB 的原因,大多数 NoSQL 产品都不支持 SQL 接口,HandlerSocket 仅仅是一个 MySQL 插件,可以从 MySQL 客户端发送 SQL 语句,但当需要高吞吐量时,最好使用 HandlerSocket。

从 MySQL获益

因为 HandlerSocket 运行于 MySQL 内部,因此所有 MySQL 操作,如 SQL,在线备份,复制,通过 Nagios/EnterpriseMonitor 监控等都是支持的,HandlerSocket 获得可以通过普通的 MySQL 命令监控,如SHOW GLOBAL STAUTSSHOW ENGINE INNODB STATUSSHOW PROCESSLIST等.

不需要修改/重建 MySQL

因为 HandlerSocket 是一个插件,所以它支持 MySQL 社区版和企业服务器版,而无需对 MySQL 做出任何修改就可以使用。

独立于存储引擎

虽然我们只测试了5.1和5.5 InnoDB 插件,但 HandlerSocket 可以和任何存储引擎交互。

注意事项和限制


需要学习HandlerSocket API

尽管它很容易使用,但仍然需要学习如何与 HandlerSocket 交互,我们提供了C++ API、Perl绑定。

没有安全功能

和其它NoSQL数据库类似,HandlerSocket不支持安全功能,HandlerSocket的工作线程以系统用户权限运行,因此应用程序可以访问通过 HandlerSocket 协议的所有表,当然,你可以象其它 NoSQL 产品一样使用防火墙过滤数据包。

对于 HDD 绑定工作负载没有优势

对于 HDD I/O 绑定工作负载,数据库每秒无法执行数千次查询,通常只有 1-10% 的 CPU 利用率,在这种情况下,SQL 执行层不会成为瓶颈,因此使用HandlerSocket没有什么优势,我们只在数据完全装载到内存的服务器上使用 HandlerSocket。


DeNA 在生产环境中使用 HandlerSocket


我们已经在生产环境中使用了 HandlerSocket 插件,效果很明显,因为我们减少了许多 Memcached 和 MySQL 从属服务器,而且整个网络流量也在减少。目前还没有发现任何性能问题(如响应时间慢,延迟等)。
我认为, NoSQL/Database 社区完全低估了 MySQL, 相对于其他产品来说,它历史悠久,而且到目前为止,我优秀的前同事们也做了许多独特的、伟大的改进。从 NDBAPI 可以看出 MySQL 有成为 NoSQL 的潜力,因为存储引擎 API 和守护进程接口的完全独立,使得 Akira 和 DeNA 开发 HandlerSocket 成为可能。作为 MySQL 一名前员工和对 MySQL 长期的了解,我想看到 MySQL 变得更好,更受欢迎,而不仅仅只作为一个 RDBMS,也应该成为 NoSQL 阵营中的一员。

2011年5月2日星期一

我希望...

我希望我们没有长大,永远只谈那些不着四六的事;
我希望哪怕分开了也会记得对方,只因为我们曾经拥抱过;
我希望时间不要走的那么快,不要那么匆匆;
我希望年轻的更久一点不要那么快变的苍老嘿我说的是心灵;
我希望情感驻留的瞬间可以覆盖这个世界的冷漠改变他坚硬的衬衣;
我希望我们的心里永远闪烁着真挚与炽热,有那份不在乎得失的情谊;
我希望我们有着最朴素的生活,最遥远的梦想;
我希望情感可以超越我们的身份,我们的收入,我们的阶层,甚至我们的立场;
我希望我们保持着相遇的初衷,直到生老病死,始终如一。

cutlife上辗转得知这段话,就如同该帖子所说,能有几人不被TA所打动?五一假归来杂乱的内心在这段话的安抚下,终于也找到了些许的平静。

2011年4月7日星期四

MySQL 5.1 使用 PLUGIN

采用如下参数编译 MySQL 5.1 版本
[bash]
[root@localhost mysql-5.1.56]# ./configure --prefix=/usr/local/mysql/ \
--without-debug \
--with-unix-socket-path=/usr/local/mysql/tmp/mysql.sock \
--with-client-ldflags=-all-static \
--with-mysqld-ldflags=-all-static \
--enable-assembler \
--with-charset=utf8 \
--with-collation=utf8_general_ci \
--with-extra-charsets=latin1,gb2312 \
--with-pthread --enable-thread-safe-client \
--with-plugins=myisam,innodb_plugin,innobase
[/bash]
在 client 使用命令
[sql]
mysql&gt; INSERT PLUGIN plugin_name SONAME 'plugin_name.so';
[/sql]
提示如下错误

ERROR 1289 (HY000): The 'plugin' feature is disabled; you need MySQL built with 'HAVE_DLOPEN' to have it working


Bug #45605 是类似问题, 中间回复有一段说明产生如上错误是因为编译时有使用参数 --with-mysqld-ldflags=-all-static

- Why does the compilation process not recognize that Ubuntu default install supports HAVE_DLOPEN ?
Server was built with --with-mysqld-ldflags=-all-static


查资料时, 有说到在编译之前, 先设置如下两个环境变量就可以解决问题
[bash]
# export CFLAGS="-O2 -DHAVE_DLOPEN=1"
# export CXXFLAGS="-O2 -DHAVE_DLOPEN=1"
[/bash]
但我测试后, 编译倒完全不能通过. 不知道有木有人采用这种方法有解决了问题的?

checking build system type... i686-pc-linux-gnu
checking host system type... i686-pc-linux-gnu
checking for gcc... gcc
checking for C compiler default output file name...
configure: error: C compiler cannot create executables
See `config.log' for more details.

MySQL 5.1.56 使用 InnoDB

之前編譯 MySQL 5.1.54, 使用如下參數
[bash]
[root@localhost mysql-5.1.54]# ./configure --prefix=/usr/local/mysql/ \
--without-debug \
--with-unix-socket-path=/usr/local/mysql/tmp/mysql.sock \
--with-client-ldflags=-all-static \
--with-mysqld-ldflags=-all-static \
--enable-assembler \
--with-charset=utf8 \
--with-collation=utf8_general_ci \
--with-extra-charsets=latin1,gb2312 \
--with-pthread --enable-thread-safe-client \
--with-plugins=myisam,innodb_plugin
[/bash]
編譯後, stoRe engine 可使用 InnoDB. 但這次因為測試 HandlerSocket, 到官方下載的是 MySQL 5.1.56 的源代碼, 同樣使用如上同樣的參數, 但不能使用 InnoDB, 後面做多番嘗試沒成功後, 將後面參數修改為 --with-plugins=myisam,innodb_plugin,innobase後, 再編譯安裝, OK.

/bin/rm: cannot remove 'libtoolT': No such file or directory

安裝 MySQL 5.1.56,編譯時報如下錯誤

/bin/rm: cannot remove `libtoolT’: No such file or directory

忽略錯誤,強制make,出錯.網上查了下,有很多提到採用
[bash]
# aclocal
# autoconf
# automake
# libtoolize –force
[/bash]
OR
[bash]
# autoreconf –force –install
# libtoolize –automake –force
# automake –force –add-missing
[/bash]
但安裝無法成功.

Debian Bug report logs - #523750 autoconf false error這裡是類似的錯誤,臨時解決方法是刪除 /usr/share/aclocal/libtool.m4 文件中的 680 行$RM -f "$cfgfile", 遂按此方法重新編譯安裝,還是失敗.

Package: libtool
Version: 2.2.6a-2
Normal run of libtool, produces no other warnings until the end of the master configure script.
At which point out pops:
config.status: executing libtool commands
/bin/rm: cannot remove `libtoolT': No such file or directory
This is resolved by placing:
$RM -f "$cfgfile"
at line 680 of /usr/share/aclocal/libtool.m4
One thing to note, is that the package producing this error has been bootstrapped to install libLtdl and related stuff under lib/libLtdl instead of the defaults.
The actual error may be elsewhere with a failure of the macro to detect and handle that case.


因為在上段引用中,有看到提到 libLtdl,於是,搜索了下,在 11.6 How to distribute libltdl with your package,看到聲明 libLtdl 的路徑libtoolize --ltdl, 用這種方法再重新編譯,雖然編譯還是報如上同樣的錯誤,但安裝已能順利進行下去.

— Macro: LT_CONFIG_LTDL_DIR (directory)
Declare directory to be the location of the libltdl source files, for libtoolize --ltdl to place them.

2011年3月31日星期四

slave 1236 error

昨日, 因為從庫 down 掉, 再次啟動時, Relay_log_file 已差很遠. 只好手動同步下, 先記錄下當前的binlog_file, binlog_pos, 然後按正常步驟,
[sql]
mysql> STOP SLAVE;
mysql> RESET SLAVE;
mysql> CHANGE MASTER TO ...;
mysql> START SLAVE
[/sql]

SHOW SLAVE STATUS 提示:

Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file


報找不到日誌錯誤, 但查看日誌列表時, 指定的日誌是存在着的. 死活查不到問題出在那, 滾動鼠標滑輪時, 不小心將編輯器的字體改小, 發現 master_log_file=" mysql_bin.000011", 問題竟出這裡. 這就是不小心及偷懶的代價...

2011年3月30日星期三

查看 MySQL 慢日誌

使用 MySQL自带命令 mysqldumpslow 查看


OPTIONS

  • -s ORDER ORDER, 主要有 c, t, l, r 和 ac, at, al, ar, 分别是按照 query次数, 时间, lock的时间和返回的记录数来排序, 前面加了a时倒序.

  • -t NUM top NUM, 即为返回前面多少条的数据.

  • -g PATTERN grep: 后边可以写一个正则匹配模式, 大小写不敏感



[bash]
#查看访问次数最多的 20 个 sql 语句
[root@localhost ~]# mysqldumpslow -s c -t 20 /usr/local/mysql/var/mysql_slow_query.log
#查看返回记录集最多的 20 个 sql
[root@localhost ~]# mysqldumpslow -s r -t 20 /usr/local/mysql/var/mysql_slow_query.log
#按照时间返回前 10 条里面含有左连接的 sql 语句
[root@localhost ~]# mysqldumpslow -t 10 -s t -g "LEFT JOIN" /usr/local/mysql/var/mysql_slow_query.log
[/bash]

mysqlsla 分析 MySQL 慢查询日志



  • mysqlsla -lt slow /usr/local/mysql/var/mysql_slow_query.log slow log

  • mysqlsla -lt general /usr/local/mysql/var/mysql_query.log general log

  • mysqlbinlog /usr/local/mysql/var/mysql-bin.000001 | mysqlsla -lt binary - binary log


  • mysqlsla(现已不在维护)是第三方提供的perl脚本, 不过它功能强悍, 可以分析包括慢查询在内的多种格式的日志.
    [bash]
    [root@localhost tmp]# wget http://hackmysql.com/scripts/mysqlsla-2.03.tar.gz
    [root@localhost tmp]# tar zxf mysqlsla-2.03.tar.gz
    [root@localhost tmp]# cd mysqlsla-2.03
    [root@localhost mysqlsla-2.03]# perl Makefile.PL
    [root@localhost mysqlsla-2.03]# make
    [root@localhost mysqlsla-2.03]# make install
    [/bash]
    安装完成后, mysqlsla 会加入到 /usr/bin 目录.

    mysqlsla 会自动判断日志类型, 缺省会打印出前十条结果, 可以通过类似--top 100的参数来修改, 如果觉得每次输入麻烦, 还可以建立一个配置文件 ~/.mysqlsla, 在文件里写上:
    [bash]
    top=100
    [/bash]
    这样就不用每次都手动输入参数了.
    [bash]
    [root@localhost mysqlsla-2.03]# mysqlsla -lt slow /usr/local/mysql/var/mysql_slow_query.log
    [/bash]

    返回结果:
    [text gutter="0"]
    Report for slow logs: /usr/local/mysql/var/mysql_slow_query.log
    4 queries total, 2 unique
    Sorted by 't_sum'
    Grand Totals: Time 11 s, Lock 0 s, Rows sent 712.40k, Rows Examined 712.40k


    ______________________________________________________________________ 001 ___
    Count : 3 (75.00%)
    Time : 8 s total, 2.666667 s avg, 2 s to 4 s max (72.73%)
    Lock Time (s) : 0 total, 0 avg, 0 to 0 max (0.00%)
    Rows sent : 178.10k avg, 178.10k to 178.10k max (75.00%)
    Rows examined : 178.10k avg, 178.10k to 178.10k max (75.00%)
    Database : test
    Users :
    root@localhost : 66.67% (2) of query, 75.00% (3) of all users
    root1@localhost : 33.33% (1) of query, 25.00% (1) of all users

    Query abstract:
    SELECT * FROM test_1;

    Query sample:
    select * from test_1;

    ______________________________________________________________________ 002 ___
    Count : 1 (25.00%)
    Time : 3 s total, 3 s avg, 3 s to 3 s max (27.27%)
    Lock Time (s) : 0 total, 0 avg, 0 to 0 max (0.00%)
    Rows sent : 178.10k avg, 178.10k to 178.10k max (25.00%)
    Rows examined : 178.10k avg, 178.10k to 178.10k max (25.00%)
    Database :
    Users :
    root@localhost : 100.00% (1) of query, 75.00% (3) of all users

    Query abstract:
    SELECT * FROM test_2;

    Query sample:
    select * from test_2;
    [/text]

    釋意:

    • queries total 总查询次数

    • unique 去除重复后的 sql 数量.

    • Sorted by 输出报表的内容排序.

    • Grand Totals slow sql统计信息包括: 总执行时间, 等待锁时间, 结果行总数, 扫描行总数.

    • Count slow sql 的执行次数及占总的 slow log 数量的百分比.

    • Time 执行时间, 包括总时间, 平均时间, 最小, 最大时间, 时间占到总 slow sql 时间的百分比.

    • Lock Time 等待锁的时间.

    • Rows sent 结果行统计数量, 包括平均, 最小, 最大数量.

    • Rows examined 扫描的行数量.

    • Database 属于哪个数据库

    • Users username@hostname 占到所有用户执行该句 sql 百分比及占到所有用户执行的所有 SQL 的百分比.

    • Query abstract 精简后的sql语句



    几个常用OPTION, 其他可查看官网文档

    • --log-type=TYPE LOGS or -lt TYPE LOGS TYPE LOGS 可为 slow, general, binary, msl or udl. 官方文档说是没有指定时, 会根据给定的日志文件自动检测, 但测试时失败, so, 最好指定该参数.
      msl 是指 microslow patched 的慢日志.
      udl 用户自定义的日志.
      binary 因为 mysqlsla 不能直接解析 MySQL 的 binary log, 所以需先用 mysqlbinlog命令将其解析为文本,. mysqlbinlog 带有 --short-form参数时, 则 LOG TYPE 需指定为 udl. 命令可类似于如下:
      [bash]
      mysqlbinlog /usr/local/mysql/var/mysql-bin.000001 | mysqlsla -lt binary -
      mysqlbinlog --short-form /usr/local/mysql/var/mysql-bin.000001 | mysqlsla -lt udl -
      [/bash]

    • --explain or -ex explain 每句 SQL, 默认没有启用

    • --databases=dbname1,dbnam2[,...] or -db dbname1,dbnam2[,...] or -D dbname1,dbnam2[,...]用于 --explain

    • --flush-qc 强制刷新查询缓存, 默认没有启用

    • --grep="PATTERN" 只解析满足条件的 SQL

    • --meta-filter="CONDTIONS" or -mf "CONDTIONS" CONDITIONS 格式为[meta][op][value],多个条件时, 中间以,分割.
      [meta] 查看这里
      [op] >, < or =. 當 [meta] 是基於字符串時 , [op] 只能是 =.
      [value] 數字 or 字符串.

    • --reports=REPORTS or -R REPORTS, 默認是 standard, REPORTS 可以是以,為分割的列表. 可選選項:standard, time-all, print-unique, print-all, dump




    NOTE


    • MySQL 5.1.21 及以后版本可通过 set [session|global] long_query_time=0.01 等来设置记录执行时间超过 0.01秒 以上的 sql 语句.v5.1.21 之前的版本最小值只能到达 1s, 这时候可用 microslow patch(msl patch ) 补丁来完成这一工作.

2011年3月25日星期五

Windows 下命令端启动,停止 MySQL 服务

Windows 下命令端启动,停止 MySQL 服务.
[bash]
net start mysql
[/bash]
启动 MySQL 服务.

[bash]
net stop mysql
[/bash]
停止 MySQL 服务.

昨日, 在 Windows 下做修改某配置的测试,启动服务时,条件反射的使用 mysqld_safe,失败才记起得用如上命令来启动。记录下以备来时又昏头.

删除查看二进制日志

删除


PURGE {MASTER | BINARY} LOGS TO 'binlog-name';
删除 binlog-name 编号之前所有的日志.

PURGE {MASTER | BINARY} LOGS BEFORE 'date';
除当前使用日志外, 如果其他日志最后更新时间是小于 date, 则会被删除.

[sql]
mysql> PURGE MASTER LOGS TO 'mysql-bin.000003';
Query OK, 0 rows affected (0.01 sec)
[/sql]
删除 000003 之前所有的日志(000003 不会被删除).
[sql]
mysql> PURGE MASTER LOGS BEFORE '2011-03-25 23:59:59';
Query OK, 0 rows affected (0.05 sec)
[/sql]

expire_logs_days
MySQL 可以根據 expire_logs_days 的設置自動清除日誌。該值默認為 0, 即不會自動清除。可能的值為 0-99.
配置文件中設置
[bash]
[mysqld]
expire_logs_days=1
[/bash]

命令端設置
[sql]
mysql> SET GLOBAL expire_logs_days=1;
Query OK, 0 rows affected (0.00 sec)

mysql> SHOW VARIABLES LIKE 'expire%';
+------------------+-------+
| Variable_name | Value |
+------------------+-------+
| expire_logs_days | 1 |
+------------------+-------+
1 row in set (0.00 sec)
[/sql]

The number of days for automatic binary log file removal. The default is 0, which means “no automatic removal.” Possible removals happen at startup and when the binary log is flushed. Log flushing occurs as indicated in


清空二进制日志
[sql]
mysql> RESET MASTER
[/sql]
该命令会删除之前所有的 binlog, 并重新生成新的 binlog, 后缀又会从 000001 开始. 但如果该库为主库, 且有连接从库, 而从库正在读取试图删除的日志之一,
则本语句不会起作用, 而是会失败, 并伴随一个错误. 不过, 如果从库没有连接主库, 而又删除了从库读取的日志, 则从库启动后不能复制. 当从库正在复制时, 本语句可以安全运行, 不需要停止它们.


查看当前二进制日志


[sql]
mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000009 | 180 | | |
+------------------+----------+--------------+------------------+
1 row in set (0.01 sec)
[/sql]

更新二进制


[sql]
mysql> FLUSH LOGS;
[/sql]

查看二进制日志数目


[sql]
mysql> SHOW MASTER LOGS;
+------------------+-----------+
| Log_name | File_size |
+------------------+-----------+
| mysql-bin.000001 | 117 |
| mysql-bin.000002 | 117 |
| mysql-bin.000003 | 1181 |
| mysql-bin.000004 | 491718 |
| mysql-bin.000005 | 2543824 |
| mysql-bin.000006 | 8032840 |
+------------------+-----------+
16 rows in set (0.01 sec)
[/sql]
列出所有的日志及其大小

查看 events


[sql]
mysql> SHOW BINLOG EVENTS;
[/sql]
MySQL 命令终端查看当前日志中记录的日志.

mysqlbinlog
[bash]
[root@localhost ~]# mysqlbinlog /usr/local/mysql/var/mysql-bin.000001
[/bash]
查看二进制文件 mysql-bin.000001 中记录的 DML 和 DLL.

mysqlbinlog 有用参数

  • -d, --database=dbname 列出查看的数据库

  • --start-datetime='2011-03-25 00:00:00' 查看发生在该指定时间之后的 events.

  • --stop-datetime='2011-03-25 23:59:59' 查看发生在该指定时间之前的 events.

  • --start-position=10 查看该指定偏移点之后的 events.

  • --stop-position=100 查看该指定偏移点之前的 events.

  • --set-charset=utf8 在输出的 events 之前添加上 "SET NAMES utf8".




基于时间
[bash]
[root@localhost ~]# mysqlbinlog --start-datetime='2011-03-25 00:00:0' --stop-datetime='2011-03-25 23:59:59' --database=test /usr/local/mysql/var/mysql-bin.000001 > /tmp/1.log
[/bash]
> /tmp/1.log 将其重定向到 1.log, 更便于查看.


基于偏移量
[bash]
[root@localhost ~]# mysqlbinlog --start-position=98 --stop-position=344 --database=test /usr/local/mysql/var/mysql-bin.000001 > /tmp/1.log
[/bash]