在路上 ……

Linux系统运维与架构

原文地址:http://youngsterxyf.github.io/2014/08/10/Distributed-systems-theory-for-the-distributed-systems-engineer/

2014-08-10 Sun
By youngsterxyf
原文:Distributed systems theory for the distributed systems engineer

译者:youngsterxyf

Gwen Shapira,大腕级的解决方案架构师(SA),如今Cloudera的全职工程师,在Twitter上提的一个问题引起了我的思考。

如果是以前,我可能会回答“嗯,这里有篇FLP论文,这里有篇Paxos论文,这里还有篇拜占庭将军问题的论文...”,我会罗列一箩筐重要的材料,如果你一头扎进去,至少花费6个月的时间才能过一遍这些材料。然而我已逐渐明白推荐大量的理论性的论文通常恰恰是着手学习分布式系统理论的错误方式(除非你在做一个PhD项目)。论文通常比较深入难懂,需要认真地研习,通常还需要大量的时间投入(significant experience)来理清这些论文的重要贡献,以及在整个理论体系中的位置。要求工程师具备这样的专业水平又有多大的意义呢?

但是,很遗憾,对分布式系统理论方面的重大研究成果和思想进行概括、归纳、背景分析的‘导引’性质的优秀材料非常缺乏;特别是没有居高临下态度的材料。对这块空白区域的思考让我想到了另一个有趣的问题:

一个分布式系统工程师应该知道些什么分布式系统理论?

在这种情况下,一知半解(a little theory)并不会是一件多危险的事情。因此我尝试整理一个列表,罗列出作为一个分布式系统工程师的我认为能够直接应用于我日常工作的一些基本概念;或者让分布式系统工程师完全有能力设计一个新系统的“筹码”。如果你认为我漏掉了一些东西,请联系我。

入门第一步
以下4篇材料出色地解释了构建分布式系统会遇到的一些挑战,共同概述了一系列分布式系统工程师必须要解决的技术上的难题,为之后章节中更深入的研究做好准备。

好玩又实在的分布式系统理论是一本简短的书籍,其内容覆盖了分布式系统领域的一些基本议题,包括时间的作用及不同的复制策略。
为分布式系统领域新人整理的笔记 - 不是理论对理论地讲述,而是做一个非常好非常实用的平衡,让你对其余材料的阅读能够落地。
分布式系统研究综述报告 - 一篇经典的论文,解释了为什么不能将所有远程交互都模拟成和本地对象一样。
关于分布式计算的若干谬论 - 分布式计算方面的8点谬论,提醒系统设计者可能会忘记的几类事情。
失败和时间
分布式系统工程师需要面对的许多困难最终都可以归咎于两个潜在的原因:

进程可能会失败
不存在一种好的方式来周知目前为止进程已经做了些什么
进程之间对于时间的认知能共享些什么?哪些失败的场景是能够检测到?什么算法和原语可能被正确地实现?这三个问题有着非常深层的联系。多数时候,我们会假设两个不同节点之间对于时间概念或时间以什么样的速度逝去没有任何可共享的认知。

你应该知道:

失败模式的(部分)分层:崩溃停止->排除(omission)->拜占庭容错。你应该理解:在高层次上可能发生的问题在低层次上肯定可能发生,在低层次上不可能发生的问题在高层次上也肯定不可能发生。
在没有任何共享时钟的情况下如何判断在另一个事件之前是否产生了某事件。这意味着你需要理解Lamport时钟及其一般化的向量始终,也需要阅读一下这篇Dynamo论文
单个失败发生的可能性对于我们实现正确的分布式系统到底会有多大的影响(请阅读下面关于FLP结果的笔记)?
不同的时间模型:同步、部分同步和异步(若我找到好的参考文献会添加链接)
容错的基本矛盾
一个系统,若要不降级而容忍某些错误的发生,就必须能够好像那些错误没有发生一样地运作。这通常意味着系统的这些部分必须能够冗余地工作,但是非绝对必要地做更多的工作通常会在性能和资源耗用方面产生一些消耗。这是为系统添加容错带来的基本矛盾。

你应该知道:

确保单拷贝可串行化(single-copy serialisability)的仲裁(quorum)技术。可阅读Skeen的原始论文,但可能更建议阅读这个Wikipedia词条
关于两阶段提交三阶段提交Paxos算法,以及为什么它们有不同的容错性质。
最终一致性,及其他技术是如何以弱化对系统行为的保证为代价来尝试避免这种矛盾的。这篇Dynamo论文是一个很好的起点,同时Pat Helland的经典之作Life Beyond Transactions也是必读的。
基本的原语
分布式系统中很少有大家一致认同的基本构建块,但越来越多地在出现。你应该以下的问题是什么,以及在哪可以找到它们的解决方案:

群首选举(leader election)(例如Bully算法
一致的快照(例如Chandy和Lamport所写的经典论文
共识(阅读上文提到的关于2PC和Paxos的博文)
分布式状态机复制(看看Wikipedia就可以,但Lampson的论文更权威,只是枯燥了点)。
基础结论
某些客观事实是需要内化于心的,以下是几个关键点(a flavour)(当然还有更多):

如果进程之间可能丢失某些消息,那么不可能在实现一致性存储的同时能响应所有的请求。这就是CAP定理
以这样一种方式(a.始终是正确的、b.始终能终止-若在一个可能因失败崩溃停止(crash-* stop failures)的异步系统中有(甚至仅)一台机器失效时(FLP的结果))。我希望在洛杉矶题为Papers We Love报告的第一部分幻灯片-进行证明之前-已经合理地解释了这个结论。建议:没有实际的必要理解这个证明。
一般而言,消息交互少于两轮是不可能达成共识(Consensus)。
真实系统
最重要的练习是重复地阅读新兴的、真实系统的描述,并尝试评价它们的设计决策。一遍又一遍地这样去做。一些建议:

Google:

GFSSpannerF1ChubbyBigTableMillWheelOmegaDapperPaxos Made LiveThe Tail At Scale

Not Google:

Dryad, Cassandra, Ceph, RAMCloud, HyperDex, PNUTS


yum install rrdtool rrdtool-perl fping echoping curl perl-Net-Telnet perl-Net-DNS perl-LDAP perl-CGI-SpeedyCGI perl-libwww-perl perl-RadiusPerl perl-IO-Socket-SSL perl-Socket

tar zxvf smokeping-2.6.9.tar.gz
cd  smokeping-2.6.9
./configure --prefix=/usr/local/smokeping

会出现如下错误:

checking checking for gnu make availablility... /usr/bin/gmake is GNU make
checking checking for perl module 'RRDs'... Failed
checking checking for perl module 'FCGI'... Failed
checking checking for perl module 'CGI'... Failed
checking checking for perl module 'CGI::Fast'... Failed
checking checking for perl module 'Config::Grammar'... Failed
checking checking for perl module 'Digest::HMAC_MD5'... Ok
checking checking for perl module 'LWP'... Ok

** Aborting Configure ******************************

   If you know where perl can find the missing modules, set
   the PERL5LIB environment variable accordingly.

   FIRST though, make sure that 'perl' starts the perl
   binary you want to use for SmokePing.

   Now you can install local copies of the missing modules
   by running

     ./setup/build-perl-modules.sh /usr/local/smokeping/thirdparty

   The RRDs perl module is part of RRDtool. Either use the rrdtool
   package provided by your OS or install rrdtool from source.
   If you install from source, the RRDs module is located
   PREFIX/lib/perl

运行:./setup/build-perl-modules.sh /usr/local/smokeping/thirdparty 自动安装缺失的perl模块

然后再次运行./configure --prefix=/usr/local/smokeping
如果还有错,运行export PERL5LIB=/usr/local/smokeping/thirdparty/lib/perl5/ 再次运行configure
/usr/bin/gmake install
即可完成smokeping的安装
然后cd /usr/local/smokeping/
创建cache、data、var目录
mkdir cache data var

配置apache通过web显示监控结果

Alias /smokeping/cache/ /usr/local/smokeping/cache/
Alias /smokeping/ /usr/local/smokeping/htdocs/
<Directory /usr/local/smokeping/htdocs/>
        Order allow,deny
        Allow from all
        Options ExecCGI
        AddHandler cgi-script .fcgi
        <IfModule dir_module>
                DirectoryIndex smokeping.fcgi
        </IfModule>
</Directory>

slave上配置

echo "passwordyoudefine" > /usr/local/smokeping/etc/slave_secret.txt
chmod 600 /usr/local/smokeping/etc/slave_secret.txt

/usr/local/smokeping/bin/smokeping --master-url=http://yourserveraddress/smokeping/smokeping.fcgi --shared-secret=/usr/local/smokeping/etc/slave_secret.txt --cache-dir=/usr/local/smokeping/cache/ --slave-name=slavename

Airprobe How-To
https://srlabs.de/airprobe-how-to/

https://srlabs.de/decrypting_gsm/

Find KC with Kraken
https://lists.srlabs.de/pipermail/a51/2010-July/000688.html

to run Kraken, we should follow these steps:

1- edit conf file
2- execute Behemoth.py to generate index tables
3- run Kraken


原文:Optimizing NGINX and PHP-fpm for high traffic sites

译者:youngsterxyf

使用Nginx搭配PHP已有7年的这份经历让我们学会如何为高流量站点优化NGINX和PHP-fpm配置。

以下正是这方面的一些提示和建议:

##1. 将TCP切换为UNIX域套接字
UNIX域套接字相比TCP套接字在loopback接口上能提供更好的性能(更少的数据拷贝和上下文切换)。

但有一点需要牢记:仅运行在同一台服务器上的程序可以访问UNIX域套接字(显然没有网络支持)。

upstream backend
{
    # UNIX domain sockets
    server unix:/var/run/fastcgi.sock;

    # TCP sockets
    # server 127.0.0.1:8080;
}

##2. 调整工作进程数
现代计算机硬件是多处理器的,NGINX可以利用多物理或虚拟处理器。

多数情况下,你的Web服务器都不会配置为处理多种任务(比如作为Web服务器提供服务的同时也是一个打印服务器),你可以配置NGINX使用所有可用的处理器,NGINX工作进程并不是多线程的。

运行以下命令可以获知你的机器有多少个处理器:

Linux上 -

cat /proc/cpuinfo | grep processor

FreeBSD上 -

sysctl dev .cpu | grep location

将nginx.conf文件中work_processes的值设置为机器的处理器核数。

同时,增大worker_connections(每个处理器核心可以处理多少个连接)的值,以及将"multi_accept"设置为ON,如果你使用的是Linux,则也使用"epoll":

# We have 16 cores
worker_processes 16;

# connections per worker
events
{
    worker_connections 4096;
    multi_accept on;
}

##3. 设置upstream负载均衡
以我们的经验来看,同一台机器上多个upstream后端相比单个upstream后端能够带来更高的吞吐量。

例如,如果你想支持最大1000个PHP-fpm子进程(children),可以将该数字平均分配到两个upstream后端,各自处理500个PHP-fpm子进程:

upstream backend {
    server unix:/var/run/php5-fpm.sock1 weight=100 max_fails=5 fail_timeout=5;
    server unix:/var/run/php5-fpm.sock2 weight=100 max_fails=5 fail_timeout=5;
}

以下是两个来自php-fpm.conf的进程池:

<section name="pool">

    <value name="name">www1</value>
    <value name="listen_address">/var/run/php5-fpm.sock1</value>

    <value name="listen_options">
        <value name="backlog">-1</value>
        <value name="owner"></value>
        <value name="group"></value>
        <value name="mode">0666</value>
    </value>

    <value name="user">www</value>
    <value name="group">www</value>

    <value name="pm">
        <value name="style">static</value>
        <value name="max_children">500</value>
    </value>

    <value name="rlimit_files">50000</value>
    <value name="rlimit_core">0</value>
    <value name="request_slowlog_timeout">20s</value>
    <value name="slowlog">/var/log/php-slow.log</value>
    <value name="chroot"></value>
    <value name="chdir"></value>
    <value name="catch_workers_output">no</value>
    <value name="max_requests">5000</value>
    <value name="allowed_clients">127.0.0.1</value>

    <value name="environment">
        <value name="HOSTNAME">$HOSTNAME</value>
        <value name="PATH">/usr/local/bin:/usr/bin:/bin</value>
        <value name="TMP">/usr/tmp</value>
        <value name="TMPDIR">/usr/tmp</value>
        <value name="TEMP">/usr/tmp</value>
        <value name="OSTYPE">$OSTYPE</value>
        <value name="MACHTYPE">$MACHTYPE</value>
        <value name="MALLOC_CHECK_">2</value>
    </value>

</section>

<section name="pool">

    <value name="name">www2</value>
    <value name="listen_address">/var/run/php5-fpm.sock2</value>

    <value name="listen_options">
        <value name="backlog">-1</value>
        <value name="owner"></value>
        <value name="group"></value>
        <value name="mode">0666</value>
    </value>

    <value name="user">www</value>
    <value name="group">www</value>

    <value name="pm">
        <value name="style">static</value>
        <value name="max_children">500</value>
    </value>

    <value name="rlimit_files">50000</value>
    <value name="rlimit_core">0</value>
    <value name="request_slowlog_timeout">20s</value>
    <value name="slowlog">/var/log/php-slow.log</value>
    <value name="chroot"></value>
    <value name="chdir"></value>
    <value name="catch_workers_output">no</value>
    <value name="max_requests">5000</value>
    <value name="allowed_clients">127.0.0.1</value>

    <value name="environment">
        <value name="HOSTNAME">$HOSTNAME</value>
        <value name="PATH">/usr/local/bin:/usr/bin:/bin</value>
        <value name="TMP">/usr/tmp</value>
        <value name="TMPDIR">/usr/tmp</value>
        <value name="TEMP">/usr/tmp</value>
        <value name="OSTYPE">$OSTYPE</value>
        <value name="MACHTYPE">$MACHTYPE</value>
        <value name="MALLOC_CHECK_">2</value>
    </value>

</section>

##4. 禁用访问日志文件
这一点影响较大,因为高流量站点上的日志文件涉及大量必须在所有线程之间同步的IO操作。

access_log off;
log_not_found off;
error_log /var/log/nginx-error.log warn;

若你不能关闭访问日志文件,至少应该使用缓冲:

access_log /var/log/nginx/access.log main buffer=16k;

##5. 启用GZip

gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

##6. 缓存被频繁访问的文件相关的信息

open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;

##7. 调整客户端超时时间

client_max_body_size 500M;
client_body_buffer_size 1m;
client_body_timeout 15;
client_header_timeout 15;
keepalive_timeout 2 2;
send_timeout 15;
sendfile on;
tcp_nopush on;
tcp_nodelay on;

##8. 调整输出缓冲区大小

fastcgi_buffers 256 16k;
fastcgi_buffer_size 128k;
fastcgi_connect_timeout 3s;
fastcgi_send_timeout 120s;
fastcgi_read_timeout 120s;
reset_timedout_connection on;
server_names_hash_bucket_size 100;

##9. /etc/sysctl.conf调优

# Recycle Zombie connections
net.inet.tcp.fast_finwait2_recycle=1
net.inet.tcp.maxtcptw=200000

# Increase number of files
kern.maxfiles=65535
kern.maxfilesperproc=16384

# Increase page share factor per process
vm.pmap.pv_entry_max=54272521
vm.pmap.shpgperproc=20000

# Increase number of connections
vfs.vmiodirenable=1
kern.ipc.somaxconn=3240000
net.inet.tcp.rfc1323=1
net.inet.tcp.delayed_ack=0
net.inet.tcp.restrict_rst=1
kern.ipc.maxsockbuf=2097152
kern.ipc.shmmax=268435456

# Host cache
net.inet.tcp.hostcache.hashsize=4096
net.inet.tcp.hostcache.cachelimit=131072
net.inet.tcp.hostcache.bucketlimit=120

# Increase number of ports
net.inet.ip.portrange.first=2000
net.inet.ip.portrange.last=100000
net.inet.ip.portrange.hifirst=2000
net.inet.ip.portrange.hilast=100000
kern.ipc.semvmx=131068

# Disable Ping-flood attacks
net.inet.tcp.msl=2000
net.inet.icmp.bmcastecho=1
net.inet.icmp.icmplim=1
net.inet.tcp.blackhole=2
net.inet.udp.blackhole=1

##10. 监控
持续监控打开连接的数目,空闲内存以及等待状态线程的数目。

设置警报在超出阈值时通知你。你可以自己构建这些警报,或者使用类似ServerDensity的东西。

确认安装了NGINX的stub_status模块。该模块默认并不会编译进NGINX,所以可能你需要重新编译NGINX -

./configure --with-http_ssl_module --with-http_stub_status_module --without-mail_pop3_module
--without-mail_imap_module --without-mail_smtp_module
make install BATCH=yes

性能问题调试的工具原来除了gdb,valgrind,perf,还有“echo t > /proc/sysrq-trigger"这样更犀利的办法,还有更犀利的,就是连sysrq-trigger都不好使了,可以看/proc/{pid}/wchan,里面是该进程阻塞位置的内核函数名,在所有办法都没戏的时候可以看它。
学习了。


Typecho 强力驱动