Archive for September, 2013

作者:AngryFox 分类: Uncategorized September 29th, 2013 暂无评论

学习牛人,复制牛人,超越牛人,最后我们自己成为牛人。
高效DevOps之七大习惯:
促使双方互相交谈
对每件事都采用由外而内的方法去处理
使构建、测试及发布过程自动化,以便减少其中包含的人为错误
使开发和生产环境简化并标准化
向从开发到运维的全过程逐渐灌输系统工程文化
实现反馈和前馈[1]回路
把开发人员放在一线支持的岗位上

Go语言吸引我的主要有如下几点:

它是系统级别的语言,静态编译,是C系列语言。
具有很多内置库,使用起来和Python很类似。
语法足够简单,入门学习成本很低,适合我这样从PHP和Python切换过来的人。
速度快,就拿简单的页面来说,我用PHP开发并发能够达到500很好了,但是用Go轻松就到上万,这是无法比拟的性能提升,而且用Go开发的效率和PHP差不多。
出自Google之手,而且有一帮牛人在维护,基于BSD开源,社区活跃。
开源项目给我很多自信,举几个开源系统:vitess(YouTube的数据库proxy系统)、nsq(bitly的一个实时信息处理系统)、skynet(轻量级的分布式服务框架)、七牛公司全部用Go开发、360开发的类iMessage应用,支持上千万用户,同时单台服务器长连80w,这些系统都是他们线上跑的,这给我更大的信心能够用Go来开发高性能,高稳定的应用。
那么Go的这个特性就让我们这些程序员从以前的多线程处理中解放出来,让Go语言的runtime来帮我们做这个事情,那用使用Go来编写Web何乐而不为呢?

主要的缺点:

有些库不成熟,例如图像处理。
cgo在Window系统下面编译很麻烦,就拿SQLite的数据库驱动来说,在Window下面编译就会遇到很大的麻烦。
runtime还不够成熟,GC还不是很好,不过听说Go 1.1版本会有比较大的性能提升。
Go的开源项目还不够多。我觉得一个语言的发展不仅仅是语言本身出色,还要有大公司推动或者好的项目推动。
已经知道启动或关闭了多少端口后,接下来就是关闭一些不安全的服务,如何关闭呢,有一个要点,要开或关闭一个端口,只需要开启或关闭一个服务即可。例如,要关闭端口21这个比较危险的ftp端口,那么将wu-ftp或proftp关掉即可,关掉它自然就关掉端口了。所以,当检测完端口后,接下来就要找出该端口对应的服务,将该服务关掉,就会把端口关闭。下面我们试试关掉端口25。由于端口25是由sendmail启动的,用于提供smtp服务,那么我们就要关闭它。

1、查看对应的端口

[root@mycentos ~]# netstat -an | more

例如要关闭22号端口:
$ netstat -anp | grep :22
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1666/sshd
# -a 显示所有活动的TCP连接,以及正在监听的TCP和UDP端口
# -n 以数字形式表示地址和端口号,不试图去解析其名称(number)
# -p 列出与端口监听或连接相关的进程(有个地方需要注意,下面会提到)(pid)

知道了22号端口对应的进程ID 1666,只要:

$ kill 1666
即可。
其中“-p”选项需要注意一个权限的问题,如果在普通用户登录的shell里面执行netstat命令,那么只能列出拥有该普通用户权限的相关进程,如果想要看到所有的端口情况,最好还是切到root。

附带几个netstat常用选项用法:
$ netstat -tn # 列出所有TCP协议的连接状态
# -t 只显示与TCP协议相关的连接和端口监听状态,注意和-a有区别(tcp)
$ netstat -tuln # 列出所有inet地址类的端口监听状态

作者:AngryFox 分类: Uncategorized September 27th, 2013 暂无评论

1.下载go语言安装包

http://code.google.com/p/go/downloads/list

http://go.googlecode.com/files/go1.1.2.src.tar.gz

2.解压安装包

tar -xzvf go1.1.2.src.tar.gz
cd go/src
./all.bash
或 ./make.bash
3.设置环境变量

在/etc/profile 中加入下列设置

export GOROOT=/usr/local/go
export PATH=$GOROOT/bin:$PATH

4.

source /etc/profile

然后就可以helloworld了

package main
import "fmt"
func main() {
    fmt.Printf("hello, world\n")
}
go run hello.go
hello, world

修正V2版本
1.下载go语言安装包
wget http://fossies.org/linux/misc/go1.2rc5.linux-386.tar.gz

http://go.googlecode.com/go1.1.2.linux-386.tar.gz

2.解压安装包
tar -xzvf go1.1.2.linux-386.tar.gz

cd go/src
./all.bash
3.设置环境变量
在/etc/profile 中加入下列设置

export GOROOT=/usr/local/go
export PATH=$GOROOT/bin:$PATH
4.
rm -r /usr/local/go
mv /opt/go /usr/local

作者:AngryFox 分类: Uncategorized September 26th, 2013 暂无评论

1、单一职责原则(Single Responsibility Principle,SRP):应该有且仅有一个原因引起类的变更。(接口、类、方法均适用)
单一职责原则的好处:
类的复杂性降低,实现什么职责都有清晰明确的定义;
可读性提高;
可维护性提高;
引起的风险降低,一个接口修改只对相应的实现类有影响,对其他的接口无影响。
单一职责原则最难划分的就是职责,一个职责一个接口,但是问题是“职责”是一个没有量化的标准,一个类到底要负责那些职责?这些职责怎么细化?细化后是否都要有一个接口或类?
生搬硬套单一职责原则会引起类的剧增,给维护带来麻烦;过分的细分类的职责也会人为的制造系统的复杂性。
2、里氏替换原则(Liskov Substitution Principle):所有引用基类的地方必须能透明地使用其子类的对象。
里氏替换原则包含四层意思:
子类必须完全的实现父类的方法。
子类可以有自己的个性。
覆盖或实现父类的方法时输入参数可以被放大。
覆盖或实现父类的方法是输出结果可以被缩小。
3、依赖倒置原则(Dependence Inversion Principle):高层模块不应该依赖于底层模块,两者都应该依赖于抽象;抽象不应该依赖于细节,细节应该依赖抽象。
面向接口编程,减少类之间的耦合性,并行开发。
4 、接口隔离原则(Interface Segregation Principle):类间的依赖关系应该建立在最小的接口上。
接口隔离原则是对接口进行规范约束,其包含以下四层含义:
接口尽量要小。根据接口隔离原则拆分接口时,必须首先满足单一职责原则。
接口要高内聚。具体到接口隔离原则就是要求在接口中尽量少公布public方法,接口是对外的承诺,承诺越少对系统的开发越有利,变更的风险也就越少,同时也有利于降低成本。
定制服务。
接口设计是有限度的。一个接口只服务于一个子模块或者业务逻辑。 通过业务逻辑压缩接口中的public方法。已经被污染了的接口,尽量去修改,若变更的风险较大,则采用适配器模式进行转化处理。了解环境,拒绝盲从。
5、迪米特法则(Low Of Demeter) ,也称最少知识原则(Least Knowledge Principle):一个类对自己需要耦合或者调用的类应该知道的最少。
尽量不要对外公布太多的public方法和非静态的public变量,尽量内敛,多使用private,package-private、protected等访问权限。核心观念就是类间解耦,弱耦合。
6、开闭原则(Open Close Principle):一个软件实体应该对扩展开放,对修改关闭。
抽象约束。通过接口或抽象类可以约束一组行为,并且能够实现扩展开放,其包含三层含义:一是通过接口或抽象类约束扩展,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的public方法;二是在参数类型定义、输入输出参数尽量使用接口或者抽象类,而不是实现类,三是抽象层尽量保持稳定,一旦确定即不允许修改。
封装变化。对变化的封装包含两层含义:一是对相同的变化封装到一个接口或抽象类中,二是对不同的变化封装到不同的接口或抽象类中,不应该出现两个不同的变化出现同一个接口或抽象类中。封装变化,准确的讲就是封装可能发生的变化。

作者:AngryFox 分类: Uncategorized September 26th, 2013 暂无评论

James Golick,原文地址:http://jamesgolick.com/2013/5/19/how-tcmalloc-works.html

tcmalloc是一款专为高并发而优化的内存分配器。tcmalloc的tc含义是thread cache,tcmalloc正是通过thread cache这种机制实现了大多数情
况下的无锁内存分配。这可能是我有幸拜读的最为精密设计的软件,虽然我不能详述tcmalloc的细节,但是我会尽量谈及到tcmalloc的所有重点。

tcmalloc与大多数现代分配器一样,使用的是基于页的内存分配,也就是说,这种内存分配的内部度量单位是页,而不是字节。这种内存分配
可以有效地减少内存碎片,同时,也可以增加局部性。此外,也可以使得元数据的跟踪更为简单。tcmalloc定义一页为8K字节,在大多数的linux
系统中,一页是4K字节,也就是tcmalloc的一页是linux的两页。

tcmalloc中的内存分配块整体来说分为两类,“小块”和“大块”,“小块”是小于kMaxPages的内存块,“小块”可以进一步分为size classes,
而且“小块”的内存分配是通过thread cache或者central per-size class cache而实现。“大块”是大于等于kMaxPages的内存块,“大块”的
内存分配是通过central PageHeap实现。

Size Class

一般来说,tcmalloc为“小块”创建了86个size classes,每一个class都会定义thread cache的特性,碎片化以及waste特征。

对于一个特定的size class,一次性分配的页数就是一个thread cache特性。tcmalloc细致地定义了这个页数,使得central cache和thread cache
之间的转换能够保持以下两者的平衡:thread cache周边的wasting chunk,以及访问central cache太过于频繁而导致的锁竞争。定义这个页数的程
序代码也保证了每一种class的waste比例最多为12.5%,当然,malloc API需要保证内存对齐。

size class data存于SizeMap中,并且是启动阶段第一个初始化的对象。

Thread Caches

thread cache是一种惰性初始化的thread-local数据结构,每个size class包含一个free list(单向),此外,他们包含了表示他们容量的总大
小的元数据。

在最佳的情况下,从thread cache分配内存和释放内存是无锁的,并且时间复杂度是线性的。如果当前thread cache不包含需要分配的内存块时,
thread cache从central cache获取那种class的内存块。如果thread cache的空间太多,thread cache的内存块会返还给central cache,每一个
central cache都有一个锁,这个锁用来减少内存返还时的竞争。

虽然thread cache会有内存块的迁移,但是thread cache的大小会根据两个有趣的方式限定在一个范围内。

其一,所有的thread cache的总大小会有一个上限。每一个thread cache都会在内存块的迁移,分配和释放时跟踪它当前的内存块总容量。起初,
每一个thread cache都会被分配相同的内存空间。但是,当thread cache的容量动态变化时,会有一个算法使得一个thread cache可以从其他的
thread cache偷取没有使用的空间。

其二,每一个free list都有一个上限,这个上限会随着内存块从central cache迁入时以一种有趣的方式增加,如果list超过了上限,内存块会释
放给central cache。

当内存的释放或者有central cache的内存块的迁入而导致thread cache超过了上限,thread cache首先会试图查找free list中特别的headroom,
以检查thread cache是否有多余的需要释放给central cache的内存。当free list满足了条件时,被加进free list的内存块就是多余的 。如果
还是没有空出足够的空间时,thread cache会从其他的thread cache中偷取空间,当然需要拥有pageheap_lock。

central cache有其自己的系统,用来管理tcmalloc整个系统中所有的cache。每一个要么是1M字节的内存块或者是1个入口(大于1M字节)。当
central cache需要更多的空间时,他们可以使用thread cache类似的方式从其他的central cache偷取内存空间。当thread cache需要返还内存块给
central cache,而central cache又已经满了无法获取更多的空间时,central cache会释放这些内存对象给PageHeap,也就是起初central cache
获取他们的地方。

Page Heap

PageHeap算是整个系统的根本,当内存块没有作为cache,或者没有被应用程序申请时,他们位于PageHeap的free list中,也就是他们起初被
TCMalloc_SystemAlloc分配的位置,最终又会被TCMalloc_SystemRelease释放给操作系统。当“大块”内存被申请时,PageHeap也提供了接口跟
踪heap元数据。

PageHeap管理Span对象,Span对象表示连续的页面。每一个Span有几个重要的特性。

一,PageID start是由Span描述的内存起始地址,PageID的类型是uintptr_t。

二,Length length是Span页面的数量,Length的类型也是uintptr_t。

三,Span *next和Span *prev是Span的指针,当Span位于PageHeap的free list双向链表中。

PageHeap有kMaxPages + 1的free list,span length从0到kMaxPages一一对应一个free list,大于kMaxPages的有一个free list,这些list都是
双向的,并且分为了normal和returned两个部分。

一,normal部分包含这样的Span,他们的页面明确地映射到进程地址空间。

二,returned部分包含这样的Span,他们的页面通过调用含有MADV_FREE参数的madvise返还给操作系统。操作系统在必要的时候可以回收这些页面,
但是当应用程序在操作系统回收前使用了这些页面,madvise的调用实际上是无效的。甚至当内存已经被回收,内核会重新把这些地址映射到一块全
零的内存。因此,重新利用returned的页面不仅是安全的,而且还是减少heap碎片化的一种重要的策略。

PageHeap包含了PageMap,PageMap是一个radix tree数据结构,会映射到他们对应的Span对象。PageHeap也包含PageMapCache,PageMapCache会
映射内存块的PageID到他们在cache中的内存块对应的size class。这是tcmalloc存储元数据的机制,而不是使用headers和footers对应实际的指针。
尽管这样有些浪费空间,但是这样在实质上可以更有效地缓存,因为所有相关的数据结构都被“slab”式地分配了。

PageHeap通过调用PageHeap::New(Length n)分配内存,其中n是需要分配的页面数。

一,大于等于n的free list(除非n大于等kMaxPages)会被遍历一遍,查找是否有足够大的Span。如果找到了这样的Span,这个Span会从list移除,
然后返回这个Span,这种分配是最合适的,但是因为地址不是有序的,因此从内存碎片化的角度来说是次优的,大概算是一种性能上的折中。normal
list会在继续检查returned list前全被检查一遍。但是我也不知道为什么。

二,如果步骤一没有找到合适的Span,算法将会遍历“大块”list,并且查找最合适的地址有序的Span。这个算法的时间复杂度是O(n),它不仅会
遍历所有的“大块”list,在并发大幅波动的情况下,这可能会非常耗时,而且还会遍历有碎片的heap。我针对这种情况写过一个补丁,当“大块”
list超过了一个可配置的总大小时,通过重组“大块”list为一个skip list来提高应用程序的大内存分配的性能。

三,如果找到的Span比需要分配的内存大至少一个页面尺寸时,这个Span会被切分为适合内存分配的尺寸,在返回分配内存块之前,剩下的内存会
添加到合适的free list中。

四,如果没有找到合适的Span,PageHeap会在重复这些步骤前尝试增长至少n个页面。如果第二次查找还是没有找到合适的内存块,这个内存分配最
终会返回ENOMEM。

内存释放是通过PageHeap::Delete(Span *span)实现,该方法的作用是把Span合并到合适的free list中。

一,从PageMap查找该Span的相邻Span对象(左和右),如果在一边或者两边找到了free的内存,他们会从free list中去除,并且合并到Span中。

二,预先要知道span现在属于哪个free list。

三,PageHeap会在检查是否需要释放内存给操作系统,如果确实需要,则释放。

每次Span返还给PageHeap,Span的成员scavenge_counter_会减少Span的length,如果scavenge_counter_降到0,则从free list或者“大块”list
释放的Span会从normal list中去除,并添加到合适的returned list中等待回收。scavenge_counter_被重置为:

min(kMaxReleaseDelay, (1000.0 / FLAGS_tcmalloc_release_rate) * number_of_pages_released)。

因此,调整FLAGS_tcmalloc_release_rate在内存释放时非常有用。

作者:AngryFox 分类: Uncategorized September 20th, 2013 暂无评论

1)解决了操作系统的参数限制
对于绝大部分 Linux 操作系统, 默认情况下确实不支持 C1000K! 因为操作系统包含最大打开文件数(Max Open Files)限制, 分为系统全局的, 和进程级的限制.

全局限制
在 Linux 下执行:
cat /proc/sys/fs/file-nr
会打印出类似下面的一行输出:
5100 0 101747
第三个数字 101747 就是当前系统的全局最大打开文件数(Max Open Files), 可以看到, 只有 10 万, 所以, 在这台服务器上无法支持 C1000K. 很多系统的这个数值更小, 为了修改这个数值, 用 root 权限修改 /etc/sysctl.conf 文件:

fs.file-max = 1020000
net.ipv4.ip_conntrack_max = 1020000
net.ipv4.netfilter.ip_conntrack_max = 1020000
进程限制

执行:
ulimit -n
输出:
1024
说明当前 Linux 系统的每一个进程只能最多打开 1024 个文件. 为了支持 C1000K, 你同样需要修改这个限制.
临时修改
ulimit -n 1020000
不过, 如果你不是 root, 可能不能修改超过 1024, 会报错:
-bash: ulimit: open files: cannot modify limit: Operation not permitted
永久修改
编辑 /etc/security/limits.conf 文件, 加入如下行:
# /etc/security/limits.conf
work hard nofile 1020000
work soft nofile 1020000
第一列的 work 表示 work 用户, 你可以填 *, 或者 root. 然后保存退出, 重新登录服务器.

注意: Linux 内核源码中有一个常量(NR_OPEN in /usr/include/linux/fs.h), 限制了最大打开文件数, 如 RHEL 5 是 1048576(2^20), 所以, 要想支持 C1000K, 你可能还需要重新编译内核.

2)操作系统维持百万连接需要多少内存?
解决了操作系统的参数限制, 接下来就要看看内存的占用情况. 首先, 是操作系统本身维护这些连接的内存占用. 对于 Linux 操作系统, socket(fd) 是一个整数, 所以, 猜想操作系统管理一百万个连接所占用的内存应该是 4M/8M, 再包括一些管理信息, 应该会是 100M 左右. 不过, 还有 socket 发送和接收缓冲区所占用的内存没有分析.
测试 10 万个连接, 这些连接是空闲的, 什么数据也不发送也不接收. 这时, 进程只占用了不到 1MB 的内存. 但是, 通过程序退出前后的 free 命令对比, 发现操作系统用了 200M(大致)内存来维护这 10 万个连接! 如果是百万连接的话, 操作系统本身就要占用 2GB 的内存!
. 应用程序维持百万连接需要多少内存?
port_test
通过上面的测试代码, 可以发现, 应用程序维持百万个空闲的连接, 只会占用操作系统的内存, 通过 ps 命令查看可知, 应用程序本身几乎不占用内存.

3. 百万连接的吞吐量是否超过了网络限制?

假设百万连接中有 20% 是活跃的, 每个连接每秒传输 1KB 的数据, 那么需要的网络带宽是 0.2M x 1KB/s x 8 = 1.6Gbps, 要求服务器至少是万兆网卡(10Gbps).

理论分析:
Linux 系统需要修改内核参数和系统配置, 才能支持 C1000K. C1000K 的应用要求服务器至少需要 2GB 内存, 如果应用本身还需要内存, 这个要求应该是至少 10GB 内存. 同时, 网卡应该至少是万兆网卡.

对于一个只支持 long-polling Comet 服务器, 首先要具备解析 HTTP 协议的能力, 选择 libevent 来处理 HTTP 协议.可以看到, 每一个 Comet 连接大约占用了 2.7KB 的内存. 此时, 服务器空闲, 进程占用 CPU 为 0%

作者:AngryFox 分类: Uncategorized September 20th, 2013 暂无评论

CAP(CAP指的是:Consistency、Availability和Partition Tolerance)
一致性问题

一致性可分为强一致性和弱一致性,弱一致性又称为最终一致性。
在单机环境中,强一致性可以由数据库的事务保证。但在多机环境中,强一致性就很难做到。尽管可以使用2PC来实现分布式事务,但它的低性能(很多情况下满足不了可用性需求)使得不适合于互联网应用。这种强一致性效果的取得,其实是让提交处理过程同步化。
在多机环境中,通过使提交处理半同步半异步、或者全异步,取得最终一致性效果。例如数据库中的主从复制,在提交时就是主库同步从库异步,这对从库复制进度落后不多的场景很简单有效,但在从库落后主库很多时,如果应用还从从库读数据,就会读出脏数据,可以通过监控从库复制进度来选择读哪个从库以避免这个问题。在NOSQL模式下,以Dynamo为例,可以通过确定NRW的不同取值,可以做到同步、半同步半异步、或者全异步的效果。
最终一致性使得数据的提交效果具有延时性,而在一定的延时性范围内(比如1秒以内),应用的可用性就是OK的,比如提交后在客户端通过JS等停一段时间刷新页面就是要取得这种效果。
主从OR对等系统

像数据库这样的主从系统有着广泛的应用,它很适合于提交压力不会使得从库复制明显落后的场景。它的缺点是,当主从提交压力增大、或者存在耗时长的提交命令时,从库复制进度会明显落后于主库。在Cache+DB的应用场景下,Cache的填充时机和策略也会受到主从模式影响。如果在一个Session中提交DB后作废Cache,而由后续的(或并发的)另一个Session来再次设置Cache、并且数据是从从库获取,就很有可能缓存住脏数据,如果Cache时间很长,那问题可能就很严重了。可以变通的策略是,在一个Session中提交DB后不是作废Cache,而是更新Cache,并且数据是从主库获取或者直接从应用环境获取。主从的另一个问题是,它有提交单点,但是,如果主从能满足应用需要,在具有完备的主备切换的保证下,这个单点问题并不见得有多大。
因为Dynamo的时兴,对等系统成为另一种选择。对等系统解决了单点问题,有着高分区容忍性,但它的效果仍得商榷。NRW的不同取值会影响读写数据效果,多点提交带来的冲突解决也是个问题,尽管通常采用高版本替换低版本的粗暴策略。现在的NOSQL对等系统存储的是简单的kv,并且可以采用加机器来扩容,所以性能方面应该是可接受的(尽管常见的单机kv存储性能要比数据库高很多,但在对等系统中,因为其复杂性,换算下来单机的性能并不见得有多高)。
SQL和NOSQL各有其优缺点。如果存储一些实体数据并且查询提交只是根据唯一标识来,使用NOSQL也许就很合适。但像复杂的关系数据,使用SQL就更合适些。而就提交模式来说,如果并发提交的数据隔离性不好(比如需要同时对同一个数值做更新),那么对等系统的提交冲突就会增多,数据的正确性就会受到影响。
BASE

上面提到,在分布式环境中,CAP只能取两者。但是,因为网络分区的情况不可避免,并且它对可用性有着重要影响,所以互联网中的分布式系统多在一致性方面做些折中。虽然不能达到强一致性,但可以根据应用特点采用适用的手段来达到够用的一致性效果。比如,对于微博系统,当用户新增一条消息,能够达到用户能看到刚才发的消息、而他的follower们能在尽快时间看到他新发的消息的效果就可以了。而在实现时,就可以结合同步和异步多种策略、SQL+NOSQL多种存储方案来满足应用需要。
BASE(Basically Available、Soft state、Eventually consistent)是对CAP中的AP的延伸。
在单机环境中,ACID是数据的属性;而在分布式环境中,BASE就是数据的属性。ACID有“尖刻”之含义,所以单机环境的数据有着很高的要求。而因为分布式环境的网络分区性及复杂性,对数据也只能有“基本”的要求了。
从ACID到CAP和BASE,从单机到分布式,从SQL到NOSQL,互联网应用的大规模发展促使不断出现可替代旧方案的新技术。在技术选型方面,重要的是根据自己的应用特点选择自己能驾驭的技术。而现实的应用场景,也大多是多种技术方案的结合。

作者:AngryFox 分类: Uncategorized September 19th, 2013 暂无评论

3. 查看文件中间一段,你可以使用sed命令,如:
sed -n ’5,10p’ /etc/passwd
这样你就可以只查看文件的第5行到第10行。
Linux下设置帧和socket缓冲区的大小
修改帧大小和socket缓冲区大小
MTU (最大传输单元)的缺省值为1500.
通过下面命令将其改为9000(jumbo frame)
% ifconfig eth0 mtu 9000

socket buffer size缺省为64 kB.
理论上,最优的buffer大小为*
可以通过下列命令改变其大小(如256KB)
% sysctl -w net.core.rmem_max=262144 ;最大的接收缓冲区大小(tcp连接)
% sysctl -w net.core.wmem_max=262144 ;最大的发送缓冲区大小(tcp连接)
% sysctl -w net.core.rmem_default=262144;缺省的接收缓冲区大小(tcp连接)
% sysctl -w net.core.wmem_default=262144;缺省的发送缓冲区大小(tcp连接)

这些参数在proc/sys下面可以看到;
sysctl -p | grep mem:显示当前缓冲区设置
round-trip delay 可由ping命令得到。

在Linux性能分析时经常使用的工具包括:top, iostat,iostat -xn 3 30, vmstat 等

1、检查RAID的状态,比如是否正在重建或者没有初始化
2、替换操作系统的内核,最好使用发行版标准的 Linux kernel,因为有比较多的补丁
3、检查/proc/sys/vm下面是否可以优化
4、是否使用了文件系统,文件系统是否有优化的选项,比如在RAID5上采用xfs文件系统时,
可以调节一些参数优化性能
5、客户端程序是否产生了过大的压力,比如磁盘的读写性能只有10MB/s,每个线程的读写
速度为5MB/s,那么如果读写线程数为20的话,无疑会造成IOWait过高
6. 通过iotop命令可以查看

ps -eo pid,user,wchan=WIDE-WCHAN-COLUMN -o s,cmd|awk ‘ $4 ~ /D/ {print $0}’
lsof -p $pid
cat /proc/$pid/io

作者:AngryFox 分类: Uncategorized September 19th, 2013 暂无评论

Linux下获取占用CPU内存资源最多的10个进程的方法

linux下获取占用CPU资源最多的10个进程,可以使用如下命令组合:
ps aux|head -1;ps aux|grep -v PID|sort -rn -k +3|head

linux下获取占用内存资源最多的10个进程,可以使用如下命令组合:
ps aux|head -1;ps aux|grep -v PID|sort -rn -k +4|head

命令组合解析(针对CPU的,MEN也同样道理):
ps aux|head -1;ps aux|grep -v PID|sort -rn -k +3|head

该命令组合实际上是下面两句命令:
ps aux|head -1
ps aux|grep -v PID|sort -rn -k +3|head
/search 索引检索,仅支持GET方式请求,注意调用需要转化请求url中的特殊字符串urlencode
 3.cache使用情况和命中率统计。全网站高峰期每秒20000次get.
/proc/$pid可以看到一个进程的很多信息,比如查看mongo的limits
attr     coredump_filter  environ  fdinfo  loginuid  mounts      oom_adj    schedstat  statm   wchan  auxv     cpuset           exe      io      maps      mountstats  oom_score  smaps      status cmdline  cwd              fd       limits  mem       numa_maps   root       stat       task

说明:

  /proc/N pid为N的进程信息
  /proc/N/cmdline 进程启动命令
  /proc/N/cwd 链接到进程当前工作目录
  /proc/N/environ 进程环境变量列表
  /proc/N/exe 链接到进程的执行命令文件
  /proc/N/fd 包含进程相关的所有的文件描述符
  /proc/N/maps 与进程相关的内存映射信息
  /proc/N/mem 指代进程持有的内存,不可读
  /proc/N/root 链接到进程的根目录
  /proc/N/stat 进程的状态
  /proc/N/statm 进程使用的内存的状态
  /proc/N/status 进程状态信息,比stat/statm更具可读性
  /proc/self 链接到当前正在运行的进程

pmap
Usage: pmap [-x | -d] [-q] pid…
-x show details
-d show offset and device number
-q quiet; less header/footer info
-V show the version number

可见编译选项中指定 -pthread 会附加一个宏定义 -D_REENTRANT ,该宏会导致 libc 头文件选择那些thread-safe的实现;链接选项中指定 -pthread 则同 -lpthread 一样,只表示链接 POSIX thread 库。由于 libc 用于适应 thread-safe 的宏定义可能变化,因此在编译和链接时都使用 -pthread 选项而不是传统的 -lpthread 能够保持向后兼容,并提高命令行的一致性。

作者:AngryFox 分类: Uncategorized September 14th, 2013 暂无评论

# tail -f /var/log/messages
netstat -n | awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’
执行netstat -na>指定文件,保留罪证。
根据netstat查看到的对方IP特征:
# netstat -na |grep SYN_RECV|more

# iptables -A INPUT -s 173.0.0.0/8 -p tcp –dport 80 -j DROP
第一个参数tcp_synack_retries = 0是关键,表示回应第二个握手包(SYN+ACK包)给客户端IP后,如果收不到第三次握手包(ACK包)后,不进行重试,加快回收“半连接”,不要耗光资源。

不修改这个参数,模拟攻击,10秒后被攻击的80端口即无法服务,机器难以ssh登录; 用命令netstat -na |grep SYN_RECV检测“半连接”hold住180秒;

修改这个参数为0,再模拟攻击,持续10分钟后被攻击的80端口都可以服务,响应稍慢些而已,只是ssh有时也登录不上;检测“半连接”只hold住3秒即释放掉。

修改这个参数为0的副作用:网络状况很差时,如果对方没收到第二个握手包,可能连接服务器失败,但对于一般网站,用户刷新一次页面即可。这些可以在高峰期或网络状况不好时tcpdump抓包验证下。

根据以前的抓包经验,这种情况很少,但为了保险起见,可以只在被tcp洪水攻击时临时启用这个参数。
tcp_synack_retries默认为5,表示重发5次,每次等待30~40秒,即“半连接”默认hold住大约180秒。
之所以可以把tcp_synack_retries改为0,因为客户端还有tcp_syn_retries参数,默认是5,即使服务器端没有重发SYN+ACK包,客户端也会重发SYN握手包。
第二个参数net.ipv4.tcp_max_syn_backlog = 200000也重要,具体多少数值受限于内存
# vi /etc/sysctl.conf
#最关键参数,默认为5,修改为0 表示不要重发
net.ipv4.tcp_synack_retries = 0
#半连接队列长度
net.ipv4.tcp_max_syn_backlog = 200000

#系统允许的文件句柄的最大数目,因为连接需要占用文件句柄
fs.file-max = 819200
#用来应对突发的大并发connect 请求
net.core.somaxconn = 65536
#最大的TCP 数据接收缓冲(字节)
net.core.rmem_max = 1024123000

#最大的TCP 数据发送缓冲(字节)
net.core.wmem_max = 16777216
#网络设备接收数据包的速率比内核处理这些包的速率快时,允许送到队列的数据包的最大数目
net.core.netdev_max_backlog = 165536
#本机主动连接其他机器时的端口分配范围
net.ipv4.ip_local_port_range = 10000 65535
使配置生效:
# sysctl -p
注意,以下参数面对外网时,不要打开。因为副作用很明显,具体原因请google,如果已打开请显式改为0,然后执行sysctl -p关闭。因为经过试验,大量TIME_WAIT状态的连接对系统没太大影响:

#当出现 半连接 队列溢出时向对方发送syncookies,调大 半连接 队列后没必要
net.ipv4.tcp_syncookies = 0
#TIME_WAIT状态的连接重用功能
net.ipv4.tcp_tw_reuse = 0
#时间戳选项,与前面net.ipv4.tcp_tw_reuse参数配合
net.ipv4.tcp_timestamps = 0
#TIME_WAIT状态的连接回收功能
net.ipv4.tcp_tw_recycle = 0
为了处理大量连接,还需改大另一个参数:
# vi /etc/security/limits.conf

在底下添加一行表示允许每个用户都最大可打开409600个文件句柄(包括连接):
* – nofile 409600

文件句柄不要超过系统限制/usr/include/linux/fs.h,相关链接: ​http://blog.yufeng.info/archives/1380
#define NR_OPEN (1024*1024) /* Absolute upper limit on fd num */

内核参数详细解释:http://www.frozentux.net/ipsysctl-tutorial/chunkyhtml/tcpvariables.html

作者:AngryFox 分类: Uncategorized September 14th, 2013 暂无评论

一、 表设计
库名、表名、字段名必须使用小写字母,“_”分割。
库名、表名、字段名必须不超过12个字符。
库名、表名、字段名见名知意,建议使用名词而不是动词。
建议使用InnoDB存储引擎。
存储精确浮点数必须使用DECIMAL替代FLOAT和DOUBLE。
建议使用UNSIGNED存储非负数值。
建议使用INT UNSIGNED存储IPV4。
整形定义中不添加长度,比如使用INT,而不是INT(4)。
使用短数据类型,比如取值范围为0-80时,使用TINYINT UNSIGNED。
不建议使用ENUM类型,使用TINYINT来代替。
尽可能不使用TEXT、BLOB类型。
VARCHAR(N),N表示的是字符数不是字节数,比如VARCHAR(255),可以最大可存储255个汉字,需要根据实际的宽度来选择N。
VARCHAR(N),N尽可能小,因为MySQL一个表中所有的VARCHAR字段最大长度是65535个字节,进行排序和创建临时表一类的内存操作时,会使用N的长度申请内存。
表字符集选择UTF8。
使用VARBINARY存储变长字符串。
存储年使用YEAR类型。
存储日期使用DATE类型。
存储时间(精确到秒)建议使用TIMESTAMP类型,因为TIMESTAMP使用4字节,DATETIME使用8个字节。
建议字段定义为NOT NULL。
将过大字段拆分到其他表中。
禁止在数据库中使用VARBINARY、BLOB存储图片、文件等。
表结构变更需要通知DBA审核。
二、 索引
非唯一索引必须按照“idx_字段名称_字段名称[_字段名]”进行命名。
唯一索引必须按照“uniq_字段名称_字段名称[_字段名]”进行命名。
索引名称必须使用小写。
索引中的字段数建议不超过5个。
单张表的索引数量控制在5个以内。
唯一键由3个以下字段组成,并且字段都是整形时,使用唯一键作为主键。
没有唯一键或者唯一键不符合5中的条件时,使用自增(或者通过发号器获取)id作为主键。
唯一键不和主键重复。
索引字段的顺序需要考虑字段值去重之后的个数,个数多的放在前面。
ORDER BY,GROUP BY,DISTINCT的字段需要添加在索引的后面。
使用EXPLAIN判断SQL语句是否合理使用索引,尽量避免extra列出现:Using File Sort,Using Temporary。
UPDATE、DELETE语句需要根据WHERE条件添加索引。
不建议使用%前缀模糊查询,例如LIKE “%weibo”。
对长度过长的VARCHAR字段建立索引时,添加crc32或者MD5 Hash字段,对Hash字段建立索引。
合理创建联合索引(避免冗余),(a,b,c) 相当于 (a) 、(a,b) 、(a,b,c)。
合理利用覆盖索引。
SQL变更需要确认索引是否需要变更并通知DBA。
三、 SQL语句
使用prepared statement,可以提供性能并且避免SQL注入。
SQL语句中IN包含的值不应过多。
UPDATE、DELETE语句不使用LIMIT。
WHERE条件中必须使用合适的类型,避免MySQL进行隐式类型转化。
SELECT语句只获取需要的字段。
SELECT、INSERT语句必须显式的指明字段名称,不使用SELECT *,不使用INSERT INTO table()。
使 用SELECT column_name1, column_name2 FROM table WHERE [condition]而不是SELECT column_name1 FROM table WHERE [condition]和SELECT column_name2 FROM table WHERE [condition]。
WHERE条件中的非等值条件(IN、BETWEEN、<、<=、>、>=)会导致后面的条件使用不了索引。
避免在SQL语句进行数学运算或者函数运算,容易将业务逻辑和DB耦合在一起。
INSERT语句使用batch提交(INSERT INTO table VALUES(),(),()……),values的个数不应过多。
避免使用存储过程、触发器、函数等,容易将业务逻辑和DB耦合在一起,并且MySQL的存储过程、触发器、函数中存在一定的bug。
避免使用JOIN。
使用合理的SQL语句减少与数据库的交互次数。
不使用ORDER BY RAND(),使用其他方法替换。
建议使用合理的分页方式以提高分页的效率。
统计表中记录数时使用COUNT(*),而不是COUNT(primary_key)和COUNT(1)。
禁止在从库上执行后台管理和统计类型功能的QUERY。
四、 散表
每张表数据量建议控制在5000w以下。
可以结合使用hash、range、lookup table进行散表。
散表如果使用md5(或者类似的hash算法)进行散表,表名后缀使用16进制,比如user_ff。
推荐使用CRC32求余(或者类似的算术算法)进行散表,表名后缀使用数字,数字必须从0开始并等宽,比如散100张表,后缀从00-99。
使用时间散表,表名后缀必须使用特定格式,比如按日散表user_20110209、按月散表user_201102。
五、 其他
批量导入、导出数据需要DBA进行审查,并在执行过程中观察服务。
批量更新数据,如update,delete 操作,需要DBA进行审查,并在执行过程中观察服务。
产品出现非数据库平台运维导致的问题和故障时,如前端被抓站,请及时通知DBA,便于维护服务稳定。
业务部门程序出现bug等影响数据库服务的问题,请及时通知DBA,便于维护服务稳定。
业务部门推广活动,请提前通知DBA进行服务和访问评估。
如果出现业务部门人为误操作导致数据丢失,需要恢复数据,请在第一时间通知DBA,并提供准确时间,误操作语句等重要线索。

—————————————————————————–
FAQ
1-1.库名、表名、字段名必须使用小写字母,“_”分割。
a) MySQL有配置参数lower_case_table_names,不可动态更改,linux系统默认为0,即库表名以实际情况存储,大小写敏感。如果是1,以小写存储,大小写不敏感。如果是2,以实际情况存储,但以小写比较。
b) 如果大小写混合用,可能存在abc,Abc,ABC等多个表共存,容易导致混乱。
c) 字段名显示区分大小写,但实际使用不区分,即不可以建立两个名字一样但大小写不一样的字段。
d) 为了统一规范, 库名、表名、字段名使用小写字母。

1-2.库名、表名、字段名必须不超过12个字符。
库名、表名、字段名支持最多64个字符,但为了统一规范、易于辨识以及减少传输量,必须不超过12字符。

1-3.库名、表名、字段名见名知意,建议使用名词而不是动词。
a) 用户评论可用表名usercomment或者comment。
b) 库表是一种客观存在的事物,一种对象,所以建议使用名词。

1-4.建议使用InnoDB存储引擎。
a) 5.5以后的默认引擘,支持事务,行级锁,更好的恢复性,高并发下性能更好,对多核,大内存,ssd等硬件支持更好。
b) 具体比较可见附件的官方白皮书。

1-5.存储精确浮点数必须使用DECIMAL替代FLOAT和DOUBLE。
a) mysql中的数值类型(不包括整型):
IEEE754浮点数: float (单精度) , double 或 real (双精度)
定点数: decimal 或 numeric
单精度浮点数的有效数字二进制是24位,按十进制来说,是8位;双精度浮点数的有效数字二进制是53位,按十进制来说,是16 位
一个实数的有效数字超过8位,用单精度浮点数来表示的话,就会产生误差!同样,如果一个实数的有效数字超过16位,用双精度浮点数来表示,也会产生误差
b) IEEE754标准的计算机浮点数,在内部是用二进制表示的,但在将一个十进制数转换为二进制浮点数时,也会造成误差,原因是不是所有的数都能转换成有限长度的二进制数。
即一个二进制可以准确转换成十进制,但一个带小数的十进制不一定能够准确地用二进制来表示。

实例:
drop table if exists t;
create table t(value float(10,2));
insert into t values(131072.67),(131072.68);
select value from t;
+———–+
| value |
+———–+
| 131072.67 |
| 131072.69 |
+———–+

1-6.建议使用UNSIGNED存储非负数值。
同样的字节数,存储的数值范围更大。如tinyint 有符号为 -128-127,无符号为0-255

1-7. 如何使用INT UNSIGNED存储ip?
使用INT UNSIGNED而不是char(15)来存储ipv4地址,通过MySQL函数inet_ntoa和inet_aton来进行转化。Ipv6地址目前没有转化函数,需要使用DECIMAL或者两个bigINT来存储。例如:
SELECT INET_ATON(’209.207.224.40′);
3520061480
SELECT INET_NTOA(3520061480);
209.207.224.40

1-8. INT[M],M值代表什么含义?
注意数值类型括号后面的数字只是表示宽度而跟存储范围没有关系,比如INT(3)默认显示3位,空格补齐,超出时正常显示,python、java客户端等不具备这个功能。

1-10.不建议使用ENUM、SET类型,使用TINYINT来代替。
a) ENUM,有三个问题:添加新的值要做DDL,默认值问题(将一个非法值插入ENUM(也就是说,允许的值列之外的字符串),将插入空字符串以作为特殊错误值),索引值问题(插入数字实际是插入索引对应的值)
实例:
drop table if exists t;
create table t(sex enum(’0′,’1′));
insert into t values(1);
insert into t values(’3′);
select * from t;
+——+
| sex |
+——+
| 0 |
| |
+——+
2 rows in set (0.00 sec)

1-11.尽可能不使用TEXT、BLOB类型。
a) 索引排序问题,只能使用max_sort_length的长度或者手工指定ORDER BY SUBSTRING(column, length)的长度来排序
b) Memory引擘不支持text,blog类型,会在磁盘上生成临时表
c) 可能浪费更多的空间
d) 可能无法使用adaptive hash index
e) 导致使用where没有索引的语句变慢

1-13. VARCHAR中会产生额外存储吗?
VARCHAR(M),如果M<256时会使用一个字节来存储长度,如果M>=256则使用两个字节来存储长度。

1-14.表字符集选择UTF8。
a) 使用utf8字符集,如果是汉字,占3个字节,但ASCII码字符还是1个字节。
b) 统一,不会有转换产生乱码风险
c) 其他地区的用户(美国、印度、台湾)无需安装简体中文支持,就能正常看您的文字,并且不会出现乱码
d) ISO-8859-1编码(latin1)使用了单字节内的所有空间,在支持ISO-8859-1的系统中传输和存储其他任何编码的字节流都不会被抛弃。即把其他任何编码的字节流当作ISO-8859-1编码看待都没有问题,保存的是原封不动的字节流。

1-15.使用VARBINARY存储变长字符串。
二进制字节流,不存在编码问题

1-18. 为什么建议使用TIMESTAMP来存储时间而不是DATETIME?
DATETIME和TIMESTAMP都是精确到秒,优先选择TIMESTAMP,因为TIMESTAMP只有4个字节,而DATETIME8个字节。同时TIMESTAMP具有自动赋值以及自动更新的特性。
如何使用TIMESTAMP的自动赋值属性?
a) 将当前时间作为ts的默认值:ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP。
b) 当行更新时,更新ts的值:ts TIMESTAMP DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP。
c) 可以将1和2结合起来:ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP。

1-19.建议字段定义为NOT NULL。
a)如果null字段被索引,需要额外的1字节
b)使索引,索引统计,值的比较变得更复杂
c)可用0,”代替
d)如果是索引字段,一定要定义为not null

1-21.禁止在数据库中使用VARBINARY、BLOB存储图片、文件等。
采用分布式文件系统更高效

2. 为什么MySQL的性能依赖于索引?
MySQL的查询速度依赖良好的索引设计,因此索引对于高性能至关重要。合理的索引会加快查询速度(包括UPDATE和DELETE的速度,MySQL会将包含该行的page加载到内存中,然后进行UPDATE或者DELETE操作),不合理的索引会降低速度。
MySQL索引查找类似于新华字典的拼音和部首查找,当拼音和部首索引不存在时,只能通过一页一页的翻页来查找。当MySQL查询不能使用索引时,MySQL会进行全表扫描,会消耗大量的IO。

2-5. 为什么一张表中不能存在过多的索引?
InnoDB的secondary index使用b+tree来存储,因此在UPDATE、DELETE、INSERT的时候需要对b+tree进行调整,过多的索引会减慢更新的速度。

2-11. EXPLAIN语句
EXPLAIN 语句(在MySQL客户端中执行)可以获得MySQL如何执行SELECT语句的信息。通过对SELECT语句执行EXPLAIN,可以知晓MySQL执 行该SELECT语句时是否使用了索引、全表扫描、临时表、排序等信息。尽量避免MySQL进行全表扫描、使用临时表、排序等。详见官方文档。

2-13.不建议使用%前缀模糊查询,例如LIKE “%weibo”。
会导致全表扫描
2-14. 如何对长度大于50的VARCHAR字段建立索引?
下面的表增加一列url_crc32,然后对url_crc32建立索引,减少索引字段的长度,提高效率。
CREATE TABLE url(
……
url VARCHAR(255) NOT NULL DEFAULT 0,
url_crc32 INT UNSIGNED NOT NULL DEFAULT 0,
……
index idx_url(url_crc32)
)

2-16. 什么是覆盖索引?
InnoDB 存储引擎中,secondary index(非主键索引)中没有直接存储行地址,存储主键值。如果用户需要查询secondary index中所不包含的数据列时,需要先通过secondary index查找到主键值,然后再通过主键查询到其他数据列,因此需要查询两次。
覆盖索引的概念就是查询可以通过在一个索引中完成,覆盖索引效率会比较高,主键查询是天然的覆盖索引。
合理的创建索引以及合理的使用查询语句,当使用到覆盖索引时可以获得性能提升。
比如SELECT email,uid FROM user_email WHERE uid=xx,如果uid不是主键,适当时候可以将索引添加为index(uid,email),以获得性能提升。

3-3.UPDATE、DELETE语句不使用LIMIT。
a) 可能导致主从数据不一致
b) 会记录到错误日志,导致日志占用大量空间
3-4. 为什么需要避免MySQL进行隐式类型转化?
因为MySQL进行隐式类型转化之后,可能会将索引字段类型转化成=号右边值的类型,导致使用不到索引,原因和避免在索引字段中使用函数是类似的。

3-6. 为什么不建议使用SELECT *?
增加很多不必要的消耗(cpu、io、内存、网络带宽);增加了使用覆盖索引的可能性;当表结构发生改变时,前段也需要更新。

3-13. 如何减少与数据库的交互次数?
使用下面的语句来减少和db的交互次数:
INSERT … ON DUPLICATE KEY UPDATE
REPLACE
INSERT IGNORE
INSERT INTO values(),()如何结合使用多个纬度进行散表散库?
例如微博message,先按照crc32(message_id)将message散到16个库中,然后针对每个库中的表,一天生成一张新表。

3-14. 为什么不能使用ORDER BY rand()?
因为ORDER BY rand()会将数据从磁盘中读取,进行排序,会消耗大量的IO和CPU,可以在程序中获取一个rand值,然后通过在从数据库中获取对应的值。

3-15. MySQL中如何进行分页?
假如有类似下面分页语句:
SELECT * FROM table ORDER BY TIME DESC LIMIT 10000,10;
这种分页方式会导致大量的io,因为MySQL使用的是提前读取策略。
推荐分页方式:
SELECT * FROM table WHERE TIME SELECT * FROM table inner JOIN(SELECT id FROM table ORDER BY TIME LIMIT 10000,10) as t USING(id)

3-17.为什么避免使用复杂的SQL?
拒绝使用复杂的SQL,将大的SQL拆分成多条简单SQL分步执行。原因:简单的SQL容易使用到MySQL的query cache;减少锁表时间特别是MyISAM;可以使用多核cpu。

2. InnoDB存储引擎为什么避免使用COUNT(*)?
InnoDB表避免使用COUNT(*)操作,计数统计实时要求较强可以使用memcache或者redis,非实时统计可以使用单独统计表,定时更新。