艾莉亚的猫 Time is limited, To be a better man

系统性能调优经验分享

概述

性能优化的思路

首先是较为精准的定位问题,借助于相应的工具包,分析系统性能瓶颈在哪,在根据其性能指标,以及所处于层级决定选择优化的方式方法。在选择优化的方式方法时,大家可以参照以下章节调优方法,架构优化递进,进行正确的,有针对性,有步骤的优化。可能会发现部分指导思想或许有相悖嫌疑,大可不必较真,系统优化的过程本身就是一个不断分离+共享的组合拳,至于具体选择哪种优化方式,根据具体需求来定,但大型应用发展的总体思路是不断分离,再通过索引(非数据库)进行关联起来。

切记:优化一定要对系统进行细致的望闻问切,找到性能问题根源切入点,而不被表象迷糊,对症下药,发现病症所在的医生并不比操作手术刀的医生水平差。本文有工具包一章节,对于需要做优化的人员,需要熟悉,他就是我们诊断所用的CT,例如我们发现内存高了,首先想到不是内存不够用,而是为什么如此消耗内存,用工具看看内存消耗在什么地方,试想之,如在医院,病人告诉医生,他心脏不好,医生就换心脏,那样的话,每个人只要熟练掌握菜刀,都可以做医生。

迭代优化

性能优化未必一次性就能满足的,可能此处瓶颈消失了,系统一旦运转快速后,在其他地方又发现新的性能瓶颈,所以性能优化是一个迭代的工作。直至满足系统需要的性能指标。

优化的成本

系统性能设计或优化是否可以一步升天,按照最好的分布式架构进行设计和优化呢,单个节点一直也运转及其健康,理论上是可以达到共产国际的,但实际实施层面不可取,必须结合实际的非功能需求进行设计和优化,一则一步到极致的话,系统的成本太过虑庞大, 光是性能设计和优化的成本就高于系统本身给客户所提供的价值,也造成研发成本开销过大。二则好像能够架构这样完美系统的人还没诞生。所以一句话也同样适合架构师:有理想而不理想化,废话少扯:具体见法则

调优方法

数据库优化

很多应用,优化DB往往是最直接,最方便,见效最显著的,但并非所有的系统性能都处在瓶颈,或者DB瓶颈解决之后,可能应用层瓶颈,WEB层瓶颈,甚至架构瓶颈都会冒出来了,所以数据库优化十分重要,但往往很多人理解系统优化就是数据库优化,是不全面的。优化角色一般推荐具备较深数据知识的程序员,或者专业的DBA,而不只是只会CRUD的开发人员。

  1. 建立正确的主键,外键,以及索引
  2. 分离原则:读写分离,业务数据分离
    1. 分库
    2. 分区
    3. 分表
    4. 分列(将大字段,不常用的隔离到他表,按需查询)
  3. 选择隔离级别:某些对数据一致性要求不高的,可以牺牲部分一致性,降低加锁阻塞
  4. 保证事务简短以及减少不必要的锁机制。
  5. 查询优化规则:
    1. 避免表内的相关子查询;
    2. 避免排序或为尽可能少的行排序,
    3. 做大量数据排序时相关数据放在临时表中
    4. 尽量在where后多传查询条件,以减少不必要返回的行
    5. 尽量select只需要的字段,以减少不必要返回的列
  6. 分页存储过程:大列表的查询也可以利用分页存储过程达到优化效果。
  7. 利用数据库缓存,视图,临时表等最大程度优化系统,并对存储过程和函数进行必要的优化
  8. 如有需要,可以冗余表中字段,避免联合查询
  9. 如有需要,也可以将表内的大字段分离到单独表中,使其单独查询
  10. 必做多表关联时,尽量过滤不符条件表中数据,减少笛卡尔积计算量
  11. 复杂表:如实时性要求不高,尽量后台任务计算,避免动态查询

安装tensorflow

最近心血来潮想看看google的tensorflow项目,试着在新买的mac本上安装了玩一玩。安装过程也很简单,有丰富的中文版官方文档参考。

只需一行:

pip install https://storage.googleapis.com/tensorflow/mac/tensorflow-0.5.0-py2-none-any.whl

在此之前,Mac是默认安装了Python 2.7.10,但需要你自己另外安装pip工具。

sudo easy_install pip

安装过程🈶️报错误,原因是大致就是说numpy已安装,但是呢版本太低了,尝试着卸载和升级numpy就出错,错误信息如下💻


192:~ yangtze$ pip install -U numpy
Collecting numpy
  Using cached numpy-1.12.1-cp27-cp27m-macosx_10_6_intel.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl
Installing collected packages: numpy
  Found existing installation: numpy 1.8.0rc1
    DEPRECATION: Uninstalling a distutils installed project (numpy) has been deprecated and will be removed in a future version. This is due to the fact that uninstalling a distutils project will only partially uninstall the project.
    Uninstalling numpy-1.8.0rc1:
Exception:
Traceback (most recent call last):
  File "/Library/Python/2.7/site-packages/pip-9.0.1-py2.7.egg/pip/basecommand.py", line 215, in main
    status = self.run(options, args)
...
...
OSError: [Errno 1] Operation not permitted: '/var/folders/l0/gc9k2fw13d5f5jvl3l2yh8hm0000gn/T/pip-4wa7Fs-uninstall/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy-1.8.0rc1-py2.7.egg-info'


查了半天资料原来是Mac系统开启的SIP导致的,据说是因为XCode编译器代码被注入的事件后,Mac OS X El Capitan系统的升级,启用了更高的安全性保护机制:系统完整性保护System Integrity Protection (SIP)。简单来讲就是更加强制性的保护系统相关的文件夹,开发者不能直接操作相关的文件内容。

那么解决方案就是暂时的关闭系统SIP,操作步骤如下;

  • 点击Mac电脑的苹果图标

  • 选择 重新启动

  • 按住 command+R,直到进入还原模式

  • 选择实用工具,然后点击 终端

  • 输入 csrutil disable 按下回车

  • 重启电脑

棘手的问题解决,之后你只要执行pip install https://storage.googleapis.com/tensorflow/mac/tensorflow-0.5.0-py2-none-any.whl就可以顺利安装tensorflow了。(现在你也可以再次的开启SIP保护,步骤类似,只要在终端输入 csrutil enable)

最后以官方用例做为结尾


192:~ yangtze$ python
Python 2.7.10 (default, Jul 30 2016, 19:40:32) 
[GCC 4.2.1 Compatible Apple LLVM 8.0.0 (clang-800.0.34)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import tensorflow as tf
>>> hello = tf.constant('Hello, TensorFlow!')
>>> sess = tf.Session()
>>> print sess.run(hello)
Hello, TensorFlow!
>>> a = tf.constant(10)
>>> b = tf.constant(32)
>>> print sess.run(a+b)
42
>>> quit()

使用Gdb分析死锁的过程

今天遇到一个lll_lock_wait的问题,分析之后得到的结论是死锁,觉得挺有意义的,值得把分析过程记录一下,顺便梳理Gdb调试程序的一般步骤。


一般,程序核心转储之后会生成一个core文件,可使用命令

gdb program core.xxx

调试,如果执行程序被扒了衣服(stripped),则最好将符号表文件也放在程序同一目录,以得到更多详细信息。

可先整体查看该进程下所有线程信息

info threads

或者,打印所有线程堆栈

thread apply all bt

切换到线程30,可执行

t 30

打印该线程的堆栈信息

bt

选择frame命令查看第五帧

f 5

打印当前类所有成员的值

set print pretty

p *this

当时gdb调试信息类似下面这样

 (gdb) info thread 
  5 Thread 0x41e37940 (LWP 6722)  0x0000003d1a80d4c4 in __lll_lock_wait () 
  from /lib64/libpthread.so.0 
  4 Thread 0x42838940 (LWP 6723)  0x0000003d1a80d4c4 in __lll_lock_wait () 
  from /lib64/libpthread.so.0 
  3 Thread 0x43239940 (LWP 6724)  0x0000003d19c9a541 in nanosleep () 
 from /lib64/libc.so.6 
  2 Thread 0x43c3a940 (LWP 6725)  0x0000003d19c9a541 in nanosleep () 
 from /lib64/libc.so.6 
  1 Thread 0x2b984ecabd90 (LWP 6721)  0x0000003d1a807b35 in pthread_join () 
 from /lib64/libpthread.so.0

很多时候程序并没有coredump,我们也可以gcore出来,或者干脆attach进程号,关于gdb调试其实有很多内容,程序调试也是件需要毅力、耐心和观察力的累活,就像侦探一样,从蛛丝马迹之中找寻真相。

一些小片段

收集的工作中可能会用到的片段,分别是Cscope,Vim、Makefile和代码(文件)行数统计工具。

Cscope

#!/bin/sh -
find . -name "*.h" -o -name "*.c" -o -name "*.cpp" -o -name "*.cc" > cscope.files
cscope -bkq -i cscope.files
ctags -R .

行数统计工具

#!/bin/sh -
find . -type f | xargs cat | wc -l
find . -name "*[.h|.cpp|.sh|.py]" | xargs cat | wc -l
find . -name "*[.h|.cpp|.sh|.py]" -type f | xargs cat | wc -l

Makefile模板

TARGET :=test
INCDIRS:= .
LIBS :=
LIBDIRS:= .
SOURCE := $(wildcard *.cpp)
#SOURCE := $(filter-out $(NO_SRCS),$(SOURCE)) 
OBJS := $(patsubst %.cpp,%.o,$(SOURCE))
CPPFLAGS := -g -Wall
CPPFLAGS += $(addprefix -I,$(INCDIRS)) 
CXX=g++
LDFLAGS= $(addprefix -L,$(LIBDIRS)) $(addprefix -l,$(LIBS)) 
 
$(TARGET):$(OBJS)
	$(CXX) -g -Wall -o $@ $^ $(LDFLAGS)

.PHONY:clean
clean:
	rm -fr $(OBJS)
	rm -fr *.o
	rm -fr $(TARGET)
 
# DO NOT DELETE

敏捷开发之站立会议

站会,几乎在所有的敏捷开发相关的书籍中都必然会加以阐述,虽粗略不同,但都把他视为敏捷开发过程中不可或缺的一环。个人认为,站会最大的意义是沟通,是在面对面沟通的敏捷原则之上创造的一次强制性的沟通机会,为那些在需要面对面沟通时由于个人性格、时间、被沟通者不在现场等客观理由创造一次机会。因此,站会在敏捷开发中具有非常重要的意义。

但在具体的执行过程中,有一些现象还是让敏捷开发很受伤。

一、站会是可以自由选择的可选项。这一伤害无疑让敏捷开发打了折扣,至于站会有多重要,随便找本相关的书看看就是了,我们期望通过站会让团队成员有一个机会聚在一起,如果谁都可以不想来就不来,那势必会造成信息的不对称,也就背离了敏捷的原则。另一种常见的理解认为站会是开发人员的事,其他人可以不参加。这是在缩小团队的范围,敏捷的基础就是多角色的团队,是要所有的团队成员共同合作完成任务,如果视觉设计师不参加站会,就不利于与开发工程师同步进度,如果测试人员不参加站会,也不利于了解开发过程中具体的问题。站会是个必选项,只要你在这个团队就一定要参加。

二、不知道站会要说什么,拖沓冗长,随性而为 。站会用于同步信息的目的很明确,所以其内容很简单,每个人轮流说一下自己昨天做了什么工作,今天要做什么工作,是否需要其他人帮助解决某个问题。这样下来每人有30秒到1分钟就够了,10人的团队也不会超过10-15分钟,那些一开站会就30分钟的是应该反省一下了。其实站会更重要的是结束以后的时间,对于会上某人提到的问题,会有相关的人员继续讨论,而其他的人则解散了。这也就是站会对促进沟通的重要作用。

三、站会纪录变成检查工作的手段。对于项目经理或某些起管理作用的人员,往往会把站会纪录看做是检查工作的手段,依据每天的站会纪录来分析每一个成员的工作情况,有的甚至忽视了站会纪录中所表现的风险、问题,久而久之,团队成员在站会上的发言就变味了,站会也就变成了工作检查会了。

四、站会无内容。“我昨天解bug,今天继续解bug”,开发人员时常在站会上这样说,如果都是如此,站会就起不到作用了,作为站会的主持者,对于这种现象要加以引导,同时也要分析现象背后的问题所在,是懈怠了,还是其他的什么原因,要把站会的内容引导到一个正常的轨道上。

五、站会迟到。迟到总是不可避免,也总是有各种理由。但是我们可以给迟到加一点处罚,让迟到者意识到自己耽误了大家的时间,影响了团队的活动。重要的还是养成习惯,让每个人的心和团队在一起。以某团队的站会为例,在迭代启动会时会规定参加站会的时间、地点、人员和迟到罚责,比如迟到会请所有参加站会的成员吃鸡翅。由于有这样的规定在先,所以主持人可以认真执行落实,经过几次以后,几乎很久都不会再有迟到的,也可以保证站会的按时进行。


当然,以上不是全部,有人会说这都是小事,无关紧要,但是一个迭代一个迭代的累积下去,站会就越来越淡化,越来越变味。就像代码一样,任由‘坏味道’存在并霉化,最后可能整个架构都会被毁掉。代码可以重写,但敏捷过程如果出了问题,其代价可就远大于代码重写了。

来源: 敏捷之伤