memcached从1.4.3版本开始,能支持SASL认证

比较适合多个应用共用一个memcached集群

需要在编译时,加上–enable-sasl选项

启动memcached时,增加-S的选项

./configure –prefix=%{datadir}  –enable-sasl

/usr/local/bin/memcached -S -d -u nobody

SASL认证也可以有很多种认证机制,比如pam,shadow,ldap等

 

下面配置成使用shadow方式去认证

#修改/etc/sysconfig/saslauthd文件

MECH=shadow

#设置用户的SASL认证密码

saslpasswd2 -c -a memcached memuser

#最终生成的DB文件在/etc/下

-rw-r—– 1 root root 12288 Mar  6 11:52 /etc/sasldb2

#可以查看当前的SASL用户

sasldblistusers2

 

下面配置成通过pam-mysql使用mysql数据库的方式去认证

#首先安装pam-mysql

wget "http://prdownloads.sourceforge.net/pam-mysql/pam_mysql-0.7RC1.tar.gz"

./configure –with-mysql=/opt/apps_install/mysql-5.5.17

make & make install

#增加一个软链接

ln -s /lib/security/pam_mysql.so /lib64/security/pam_mysql.so

#修改saslauthd配置

MECH=pam

#编辑pam.d的memcached配置

auth sufficient pam_mysql.so  user=sasl passwd=saslpwd host=xxx db=dbname table=t_app_info usercolumn=appid passwdcolumn=secret crypt=0 sqllog=1 verbose=1

account required pam_mysql.so user=sasl passwd=saslpwd host=xxx db=dbname table=t_app_info usercolumn=appid passwdcolumn=secret crypt=0 sqllog=1 verbose=1

#新增加memcached的配置文件/etc/sasl2/memcached.conf

pwcheck_method: saslauthd

#重启saslauthd

/etc/init.d/saslauthd restart

#测试saslauthd认证已经成功

/usr/sbin/testsaslauthd -s /etc/pam.d/memcached -u 10000 -p pwd

0: OK "Success."

 

memcached的java client,如spymemcached和xmemcached都已经支持SASL认证了

#xmemcached认证示例

MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("10.10.xx.xx:11211"));

builder.addAuthInfo(AddrUtil.getOneAddress("10.10.xx.xx:11211"), AuthInfo.plain("10000", "pwd"));

builder.setCommandFactory(new BinaryCommandFactory());

client=builder.build();

String v = client.get("test2");

python版本的pylibmc也支持SASL认证

二月 14th, 2012time_wait过多的优化

对于处理并发量较高的Server,统计会发现本机tcp的time_wait状态的连接非常多

netstat -nat | awk '{++S[$NF]} END {for(a in S) print a, S[a]}'

TIME_WAIT 24413

established) 1

SYN_SENT 1

FIN_WAIT1 1

State 1

ESTABLISHED 15

LAST_ACK 1

LISTEN 7

该time_wait的默认值为2*MSL,MSL即max segment lifetime,是一个tcp包的最大生存时间

MSL值在Linux上好像默认是30秒,所以从time_wait状态变化到CLOSED大约需要60s时间

另外一方面,本机可用的发起连接的socket端口是有限的,可通过以下命令查看

cat /proc/sys/net/ipv4/ip_local_port_range

32768   61000

也即大约只有2万多个端口可用,如果处于 time_wait状态的连接很多

很有可能会影响本机向外发起的连接(比如说nginx的proxy服务器),出现端口不够用的情况

可以通过以下参数去减少time_wait的连接

vi /etc/sysctl.conf

#开启time_wait状态的socket重用

net.ipv4.tcp_tw_reuse = 1

#开启time_wait状态的socket快速回收

net.ipv4.tcp_tw_recycle = 1

/sbin/sysctl -p

或者直接修改time_wait的等待时间

echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout

更多的Linux内核优化可参见

http://performancewiki.com/linux-tuning.html

二月 7th, 2012GlusterFS性能优化

运维的同学前端时间搭建了一个4台Server的GlusterFS集群

按照其默认的配置,没有使用replicate,读性能还是不错的,每秒大概100M

但写性能相当比较糟糕,每秒大概只有5M左右,几乎比NFS慢了一个数量级

GlusterFS的官方文档比较恶心,在其首页没有具体配置文档的链接,费了好大劲才找到

其Translators的说明文档,见这里,可以参考下

使用一些Translators进行优化后,写性能有了不少的提升,基本能达到25M-30M每秒,这个速度还是基本可以接受的

优化后,读的性能有了一定的下降,不过下降不太明显,每秒在70M-100M之间,也还是可以的

在Client端和Server端都是需要做一些优化的,主要是增加io-cache,write-behind,quick-read,io-threads这些选项

其中对性能提高最大的应该是write-behind,它相当于是个异步写

 

我们利用cluster/replicate和cluster/distribute就可以搭建一个分布式,高可用,可扩展的存储系统

server端的部分配置如下:

volume posix

type storage/posix 

option directory /data-b

end-volume

 

volume locks

type features/locks

subvolumes posix

end-volume

 

volume brick

type performance/io-threads

option thread-count 8 # default is 16

subvolumes locks

end-volume

 

volume server

type protocol/server

option transport-type tcp

subvolumes brick

option auth.addr.brick.allow *

end-volume

client的部分配置如下

volume client1

type protocol/client

option transport-type tcp

option remote-host 10.0.0.1

option remote-subvolume brick # name of the remote volume

end-volume

 

……

 

volume replicate1

    type cluster/replicate

    subvolumes client1 client2

end-volume

 

volume distribute

type cluster/distribute

subvolumes replicate1 replicate2

end-volume

 

volume iocache

  type performance/io-cache

  option cache-size 1024MB        # default is 32MB

  option cache-timeout 1                 # default is 1 second

  subvolumes distribute 

end-volume

 

volume readahead

  type performance/read-ahead

  option page-count 16 # cache per file = (page-count x page-size)

  subvolumes iocache

end-volume

 

volume writebehind

  type performance/write-behind

  option cache-size 512MB     # default is equal to aggregate-size

  option flush-behind on      # default is 'off'

  subvolumes readahead

end-volume

 

volume quickread

  type performance/quick-read

  option cache-timeout 1         # default 1 second

  option max-file-size 256KB        # default 64Kb

  subvolumes writebehind

end-volume

 

volume iothreads

  type performance/io-threads

  option thread-count 8 # default is 16

  subvolumes quickread

end-volume

二月 2nd, 2012http协议中的keep-alive

通常,我们说的http长连接,实际上是包含2种不同的含义:

  1. comet,是服务器和浏览器之间维持一个长时间的http连接,用于服务器消息的实时推送,见Web应用中的Comet技术,这种模式下,浏览器只会发送一次request请求,而server端会不断吐出消息给浏览器端,直到超时或者手工终止连接
  2. keep-alive,是http协议中定义的一个规范,它是利用同一个tcp连接处理多个http请求和响应,节省了tcp连接3次握手的开销,同时也就减少了后续请求的延时

HTTP/1.0
在HTTP/1.0版本中,并没有官方的标准来规定Keep-Alive如何工作,因此实际上它是被附加到HTTP/1.0协议上,如果客户端浏览器支持Keep-Alive,那么就在HTTP请求头中添加一个字段 Connection: Keep-Alive,当服务器收到附带有Connection: Keep-Alive的请求时,它也会在响应头中添加一个同样的字段来使用Keep-Alive。这样一来,客户端和服务器之间的HTTP连接就会被保持,不会断开(超过Keep-Alive规定的时间,意外断电等情况除外),当客户端发送另外一个请求时,就使用这条已经建立的连接
 
HTTP/1.1
在HTTP/1.1版本中,默认情况下所在HTTP1.1中所有连接都被保持,除非在请求头或响应头中指明要关闭:Connection: Close,所以在1.1版本中,Connection: Keep-Alive字段实际上已经意义不大了

现有的Apache/Nginx等都支持KeepAlive模式,在nginx中配置:

keepalive_timeout  65;

如果想关闭keepalive,只需将keepalive_timeout设为0即可

resin/tomcat等容器也都是支持Keepalive的,JDK中的URL类同样默认支持keepalive

 

要想真正理解keep-alive长连接模式,我们可以使用wireshark或tcpdump去抓包

对于一个没有开启keep-alive的server,response会返回Connection: Close,然后tcp连接马上就关闭了,见下图

如果开启了keep-alive,那么会在一个tcp连接上发送多个http请求

而且是在keepalive超时后,tcp连接才关闭,下图可以看出过了16秒后tcp连接才关闭

 

另:推荐一篇文章:HTTP长连接

HTTP Strict Transport Security现在还是一个草案

详细细节见http://tools.ietf.org/html/draft-hodges-strict-transport-sec-02

Wiki见http://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security

Chrome中的介绍见http://dev.chromium.org/sts

HSTS实际上是定义了一个header,浏览器读取到这个header后

会强制把http的请求转换成https的请求,不需要后台应用做处理

可惜现在只支持Firefox/Chrome,相信未来会支持更多的浏览器

增加的header如下:

Strict-Transport-Security: max-age=16070400; includeSubDomains

其中,max-age指定浏览器多长时间内自动对该域名使用HSTS

includeSubDomains表明包括子域名

从抓包里能看到,第一次的http请求,被浏览器给abort了,之后又重新发送一个https的请求

在max-age的有效期内,如果访问http://passport.sohu.com浏览器也会自动跳转到https://passport.sohu.com

一月 9th, 2012Chrome的几个常用插件

  1. 网页截图: https://chrome.google.com/webstore/detail/cpngackimfmofbokmjmljamhdncknpmg
  2. DNS Refresh
  3. 快捷工具: https://chrome.google.com/webstore/detail/fjccknnhdnkbanjilpjddjhmkghmachn?hl=zh-CN
  4. Proxy SwitchySharp: https://chrome.google.com/webstore/detail/dpplabbmogkhghncfbfdeeokoefdjegm
  5. FireBug Lite: https://chrome.google.com/webstore/detail/bmagokdooijbeehmkpknfglimnifench?hl=zh-CN

十二月 21st, 2011Flume中的Decorator

Flume中提供了不少Decorator,用来在log发送到sink之前,做一定的预处理

以下2个是比较有用的,可以用来对日志打上tag,然后进行相应的分类

value("attr","value"{,escape=true|false}),可以在日志上加一个新的属性,相当于是打tag

split("regex",idx,"attr"),可以对日志进行split,取某个字段,然后设置到attr的tag上

设置了这些Tag后,就可以在collector上使用了,如:

#首先将日志对应的小时,设置在了hour属性上

exec config nginx_access_79_108 nginx_access "tail(\"/opt/logs/nginx/nginx_access.log\")" 'split(":",1,"hour") autoDFOChain'

#在 collector上根据hour属性,将日志记录到不同的文件中

exec config collector_150_111_nginx_access nginx_access autoCollectorSource  'roll(36600000){escapedFormatDfs("file:///opt/logs/nginx/%Y%m%d/","access_%{hour}_%{rolltag}.log","syslog")}'

因此,通过Tag这个机制,是可以实现一个Agent上多Source源的日志,在collector上输出到不同的目录,不同的文件中

这种实现方式,是不需要使用automatic flow isolation模式的

Nginx本身并没有提供一个health check的机制

但在upstream中可以通过配置max_fails和fail_timeout以及proxy_next_upstream这些参数,见之前的这个文章

可以实现,当某个server挂掉后,在多长时间内不再向该server发请求了

但过了那个时间后,nginx仍然后继续给server发请求,如果失败后,则

在error的日志中,我们是能看到类似这样的错误日志的

2011/11/11 16:36:18 [error] 11834#0: *51 connect() failed (111: Connection refused) while connecting to upstream, client: 10.10.79.108

nginx默认是会将该失败的请求再转向另外一个server去处理,所以理论上讲应该不会影响Client端

这样的方式并不是一个真正的健康检测机制,不过可以通过一个第三方的插件healthcheck_nginx_upstreams可以实现这个功能

这个插件貌似现在还有Bug,需要打https://github.com/liseen/healthcheck_nginx_upstreams这么一个patch,然后就能在round robin下实现健康检查了

安装很简单

1
2
3
4
5
cd nginx-1.0.9
 
patch -p1 < cep21-healthcheck_nginx_upstreams-8870d34/healthcheck.patch
 
./configure --add-module=./cep21-healthcheck_nginx_upstreams-8870d34

配置如下参数即可

healthcheck_enabled;    

healthcheck_delay 1000;    

healthcheck_timeout 2000;    

healthcheck_failcount 3;

healthcheck_send "GET /error.jsp HTTP/1.0" 'Host: xxxx.xxx.com';

当Down掉后台的某台server后,则nginx不会把请求再转发到这台server上,所以error日志中也不会有upstream错误的日志了

可以在nginx里配置一个location,通过web界面去查看health check的状态

location ~ /health {

    healthcheck_status;

    access_log   off;

    allow 10.1.1.0/24;

    deny all;

 }

SWE中会产生各种各样的日志(Nginx日志,AppMaster日志,Proxy日志,DB日志,MemCache日志,App日志等)

这些日志,将来可能会统一集中到Hadoop上去运算处理

按照以前的做法,是通过各种脚本或者Syslog去处理,会有单点的问题,而且不宜统一管理

现有的开源日志系统,如Flume,Scribe,Chukwa等基本都类同

由于我们的Hadoop使用的就是Cloudera的版本,因此就首先拿Flume做了测试

Flume本身的安装非常简单,但配置却比较麻烦,主要参考它的官方文档

http://archive.cloudera.com/cdh/3/flume/UserGuide/index.html

安装过程如下,使用我们自己的yum源进行安装

yum install jdk

yum install flume

#设置环境变量

export FLUME_CONF_DIR=/opt/conf/flume

#启动master脚本

/opt/apps/flume/bin/flume-daemon.sh stop master

#启动node脚本

/opt/apps/flume/bin/flume-daemon.sh start node -n app_79_108

配置文件flume-site.xml如下:

 

    <property>

        <name>flume.master.servers</name>

        <value>10.11.150.111</value>

        <!–value>10.11.150.xxx,10.11.150.xxx,10.11.150.xxx</value–>

    </property>

    <property>

        <name>flume.master.serverid</name>

        <value>0</value>

    </property>

    <property>

        <name>flume.master.gossip.port</name>

        <value>57890</value>

    </property>

    <property>

        <name>flume.master.store</name>

        <value>zookeeper</value>

    </property>

 

<property>

        <name>flume.master.zk.use.external</name>

        <value>true</value>

    </property>

    <property>

        <name>flume.master.zk.servers</name>

        <value>10.11.150.xxx:2181,10.11.150.xxx:2181,10.11.150.xxx:2181</value>

    </property>

    <property>

        <name>flume.collector.output.format</name>

        <value>raw</value>

    </property>

 

Flume可以配置多个Master,只需要在flume.master.servers配置多个即可

Node节点可以连接任何一个Master,多个Master之间会定期通信交换信息

Master的配置信息是存放在外部的Zookeeper上

但多Master不支持automatic flow isolation这种模式,这个真是崩溃

因为在各Node上,可能会有各种不同的Log,需要依据不同的策略汇使用不同的sink,必然会用到autoChain

Master启动后,可以通过http://10.11.150.xxx:35871去查看master的状态,而且可以在线配置config

 

在Flume里可以启动多个Node节点,多个Collector节点

一个Node对应一个Physical Node,它可以对应多个Logic Node

使用Map命令去完成Physical Node和Logic Node的对应关系

每个Logic Node对应一种日志源,然后使用autoChain模式形成不同的Flow,在Collector上汇总到不同的地方

最终可以实现类似如下的效果

 

可以通过flume shell去修改配置,这种方式比较不错

/opt/apps/flume/bin/flume shell -c 10.11.150.xxx:35873

#配置node节点,将nginx的日志通过autoDFOChain方式发送出去,定义了一个nginx_access的flow

exec config nginx_access_150_77 nginx_access "tail(\"/opt/logs/nginx/access.log\")" autoDFOChain 

#配置collector节点,将nginx_access flow过来的日志给汇总到本地的日志文件,日志的输出格式可以是raw,syslog,log4j,avro,json等

exec config collector_150_111_nginx_access nginx_access autoCollectorSource  'select(   "host") escapedFormatDfs("file:///opt/logs/flume/","%Y%m%d_access.log","syslog")'

 

可以直接把日志推送到Hadoop上,由于我们的Hadoop启用了kerberos认证,所以也需要相应配置

为了使用lzo压缩,需要安装对应的lzo包,同时配置LzopCodec

 

 <property>

        <name>flume.kerberos.user</name>

        <value>flume/_HOST@XXX.SOHU.COM </value>

        <description></description>

    </property>

    <property>

        <name>flume.kerberos.keytab</name>

        <value>/home/flume/flume.keytab </value>

        <description></description>

    </property>

    <property>

        <name>flume.collector.dfs.compress.codec</name>

        <value>LzopCodec</value>

    </property>

另外,还需要配置环境变量,拷贝lzo的jar包到flume的lib中

export JAVA_LIBRARY_PATH=/opt/apps/xxxx/hadoop/lib/native/Linux-amd64-64

/opt/apps/xxxx/hadoop/lib/hadoop-lzo-0.4.12.jar /opt/apps/flume/lib/hadoop-lzo-0.4.12.jar

最后,再配置sink到hdfs上即可

 exec config collector_150_111_nginx_access nginx_access autoCollectorSource  'select    ("host") collector(60000) {escapedFormatDfs("hdfs://zw-hadoop-master:9000/user/flume/    nginx/%Y%m%d","access_%H%M_%{rolltag}.log","syslog")}'

#可以同时配置2个sink,使日志既输出到本地文件,又输出到hdfs上

exec config collector_150_111_nginx_access nginx_access autoCollectorSource  '[collec    tor(43200000){escapedFormatDfs("hdfs://zw-hadoop-master:9000/user/flume/nginx/%Y%m%d/    ","access_%H_%{rolltag}.log","syslog")},roll(86400000){text("/opt/logs/flume/nginx_ac    cess.log","syslog")}]

nginx配置中,proxy_set_header可以放在http,server,loaction中

逻辑上讲,下面loaction的配置应该会继承上面的proxy_set_header

但Nginx有一个限制

proxy_set_header directives issued at higher levels are only inherited when no proxy_set_header directives have been issued at a given level.

就是说,当location里写的有其它的proxy_set_header时,则无法继承高层server中定义的proxy_set_header的设置

如果location想继承上面定义的proxy_set_header,则location里不能proxy_set_header指令


© 2010 高飞鸟 – Highbird | Powered by Wordpress
XHTML CSS RSS