今天在centos 5.6 x86_64的服务器上配置一个vsftpd的时候碰到了一些波折,系统用户登录后死活都不能切换目录,也无法上传文件:
C:\Users\banping>ftp 192.168.0.26
连接到 192.168.0.26。
220 (vsFTPd 2.0.5)
用户(192.168.0.26:(none)): banping
331 Please specify the password.
密码:
230 Login successful.
ftp> ls
200 PORT command successful. Consider using PASV.
150 Here comes the directory listing.
temp
test
226 Directory send OK.
ftp: 收到 235 字节,用时 0.01秒 23.50千字节/秒。
ftp> cd test
550 Failed to change directory.
ftp> put d:/1.txt
200 PORT command successful. Consider using PASV.
553 Could not create file.
ftp> bye
221 Goodbye.
经确认不是配置的问题,后来才发现是SELinux导致的。SELinux全称是Security Enhanced Linux,是增强Linux安全性的一个软件包,默认配置在/etc/selinux目录,可以关掉它对FTP的安全审核功能来解决这个问题:
[root@dev dev]# setsebool -P ftpd_disable_trans on
[root@dev dev]# service vsftpd restart
然后再试就OK了。记录一下备忘。
引言
NoSQL是伴随着web2.0的迅猛发展而在2009年被提出的一个概念,一般可以通俗的理解为高性能的Key Value存储结构的数据库,当然也有其他更广泛的类型。它基于CAP和BASE理论,强调最终一致性,具有数据结构灵活、扩展方便、大数据量下读写性能高效等特点,在互联网行业被广泛采用。本系列文章将评测广受关注的几个NoSQL数据库产品。本文关注的是HandlerSocket Plugin for MySQL。
介绍
HandlerSocket是日本DeNA公司的架构师Yoshinori开发的一个NoSQL产品,以MySQL Plugin的形式运行。其主要的思路是在MySQL的体系架构中绕开SQL解析这层,使得应用程序直接和Innodb存储引擎交互,通过合并写入、协议简单等手段提高了数据访问的性能,在CPU密集型的应用中这一优势尤其明显。其架构图如下:
图片来源:HandlerSocket作者博客
另外,HandlerSocket还帮我们解决了缓存的问题,因为Innodb已经有了成熟的解决方案,通过参数可以配置用于缓存数据的内存大小,这样只要我们分配合理的参数,就能在应用程序无需干涉的情况下实现热点数据的缓存,降低缓存维护的开发成本。
因为HandlerSocket是MySQL的一个Plugin,集成在mysqld进程中,对于NoSQL无法实现的复杂查询等操作,仍然可以使用MySQL自身的关系型数据库功能来实现。在运维层面,原来广泛使用的MySQL主从复制等经验可以继续发挥作用,相比其他或多或少存在一些bug的NoSQL产品,数据安全性更有保障。
可以说这是一个很有创意的产品,因此HandlerSocket的作者在2010年10月在博客上宣称这一产品能达到75K QPS的时候,在业界引起了广泛的关注,包括MySQL官方在新的5.6版本中推出的Memcached API,相信也是受了HandlerSocket的启发。
安装
一、安装MySQL
通过编译源码的方式安装MySQL,这里选择的版本是5.5.8版本。由于这不是本文的重点,这里只简单的提及一下要点。
首先到MySQL的官网http://dev.mysql.com/downloads/mysql/下载源码,要注意的是从MySQL 5.5版本开始需要Cmake编译工具和bison。然后开始安装:
[root@localhost handlersocket]# tar zxvf mysql-5.5.8.tar.gz
[root@localhost handlersocket]# cd mysql-5.5.8
[root@localhost mysql-5.5.8]# cmake . -DBUILD_CONFIG=mysql_release -DCMAKE_INSTALL_PREFIX=/home/handlersocket/mysql558/ -DSYSCONFDIR=/home/handlersocket/mysql558/ -DWITH_EMBEDDED_SERVER=on -DWITH_READLINE=on -DWITH_SSL=yes -DENABLED_LOCAL_INFILE=on -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_BLACKHOLE_STORAGE_ENGINE=1 -DWITH_PERFSCHEMA_STORAGE_ENGINE=1 -DWITH_PARTITION_STORAGE_ENGINE=1
[root@localhost mysql-5.5.8]# make
[root@localhost mysql-5.5.8]# make install
安装完成后配置my.cnf文件,最重要的参数是分配给innodb存储引擎的内存大小,也就是innodb_buffer_pool_size参数,这里设置为2G。
[root@localhost mysql558]# vi my.cnf
……
innodb_buffer_pool_size = 2G
……
二、安装HandlerSocket
首先到以下地址下载代码:
https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL
开始安装HandlerSocket:
[root@localhost handlersocket]# tar -zxvf ahiguti-HandlerSocket-Plugin-for-MySQL-1.0.6-67-g25f4957.tar.gz
[root@localhost handlersocket]# cd handlersocket/
[root@localhost handlersocket]# ./autogen.sh
[root@localhost handlersocket]# ./configure --with-mysql-source=/home/handlersocket/mysql-5.5.8 --with-mysql-bindir=/home/handlersocket/mysql558/bin --with-mysql-plugindir=/home/handlersocket/mysql558/lib/plugin
[root@localhost handlersocket]# make
[root@localhost handlersocket]# make install
三、修改MySQL配置
在my.cnf配置文件增加以下内容:
[root@localhost mysql558]# vi my.cnf
[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 = 16
# 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.
这里增加的这些主要是针对handlersocket的配置,它有2个端口,9998用来读数据,9999读写均可,但是通过9998来读的效率更高。这里我们设置处理读写的线程数均为16个,另外为了处理更多的并发连接,设置能打开的文件描述符个数为65535。
四、安装MySQL授权表并启动数据库
[root@localhost mysql558]# scripts/mysql_install_db --user=mysql
[root@localhost mysql558]# bin/mysqld_safe --user=mysql &
五、登录MySQL安装HandlerSocket Plugin:
[root@localhost mysql558]# bin/mysql -u root -p
mysql> install plugin handlersocket soname 'handlersocket.so';
Query OK, 0 rows affected (0.01 sec)
通过以下命令查看也可见handlersocket已经成功安装到MySQL中:
mysql> show processlist;
mysql> show plugins;
测试说明
一、测试环境
Handlersocket部署在一台PC 服务器上,配置如下:
CPU为Xeon 2.80GHz *4
内存为4G
硬盘为一块400G SATA盘
操作系统为64位CentOS 5.3版本
二、测试方法
Handlersocket的客户端几乎涵盖了各种语言,都实现了通过以上两个端口对数据读写的操作,其中查询操作必须通过建立有索引的列来进行。
考虑到NoSQL在互联网行业应用较为广泛,采用PHP实现客户端程序的做法,通过一定的并发去读写数据,观测每秒读写的记录数作为主要的衡量指标。当然也可以利用Java的多线程进行并发测试,但由于篇幅和时间所限,本文不再涉及此方面的内容。
这里采用第三方实现的一个PHP客户端,网址为http://code.google.com/p/php-handlersocket/,可以编译到PHP运行环境中。
为了不对测试服务器产生额外的影响,测试客户端部署在另外一台独立的服务器上,运行的PHP的版本是5.3.5,web server是Nginx 0.8.54,通过fastcgi的方式调用PHP服务。使用apache ab工具实现多个请求和并发操作。
测试分为两个步骤,首先是写操作,通过500个请求,每个请求写入10000条记录,并发度为2来共写入500万条数据,数据的key为数字1到5000000,value大小为100个字节。然后是读操作,也是用500个请求,每个请求随机根据key值读出10000条记录,并发度为10共读出500万条记录,评测的重点是写入和读出数据的时间,以及在此过程中服务器的资源使用情况。
测试结果及总结
一、写操作
成功写入500万条记录,共耗时4300秒,平均每秒写入数据1163笔。数据文件大小761M。写入过程中,服务器内存、CPU和磁盘等资源使用情况如下图所示:
可见,CPU使用率平稳,Idle值稳定在69到74之间,wait值稳定在15到19之间。内存分配上的变化较大,主要用来缓存数据,cache部分上升了1.4G,但是没有交换区到内存的换入换出。磁盘IO表现平稳,每秒有70%到80%的时间用于处理IO操作。
二、读操作
成功读出500万条记录,共耗时193秒,平均每秒读出数据25906笔。
读数据过程中没有发生磁盘IO。CPU较繁忙,Idle在39到53之间,等待CPU资源的进程一直在1到6个之间。内存表现平稳没有波动。
通过以上测试结果可以说明,写入的数据完全缓存到了文件系统中,所以cache部分占用的内存大量增加,这也是读取数据的时候没有发生磁盘IO的原因。
要说明的是,虽然这是一份真实的测试数据,但是并不一定具有普遍意义。因为应用场景是千差万别的,服务器的资源配置、数据记录的多少、单条数据的大小、读写的比例、客户端程序的质量等因素都会影响测试结果,甚至差别会非常大,对我们来说,更重要的是了解这个NoSQL产品的特性,知道它的适用场景,并且能够根据自己实际的应用场景针对性的进行测试,这样才能做到针对性的选型,只有最适合自己需求的产品才是最好的产品。
备注:本文发表在IT168网站上,版权所有,转载请注明出处。
一直以来北京等一线城市的技术交流活动都有很多,而厦门虽然互联网公司也不少,但大多规模都不大,交流的气氛也不够浓厚。因此我和几位朋友发起了一个TechClub技术沙龙,希望能有更多喜欢技术、热爱分享的朋友加入进来,一起推动厦门及周边地区的IT技术沙龙活动,在交流中结识朋友,共同提高。我们的网站是http://www.tech-club.org。
2011年7月30日,我们的第一次地面活动成功举行了,主题是《互联网数据库应用实践》,大概有70位朋友参与,还有很多朋友冒着极大的危险(原因你懂的)从福州乘动车赶过来参加,非常让人感动,这也促使我努力的把这个活动办下去,让更多的朋友能从中受益。意外的是还有一位北京MySQL公司的朋友顺路过来参与,技术无界限啊。
我在本次活动中分享了一个主题,叫《设计高性能MySQL应用》,以下是PPT内容:
为了防止邮件被判定为垃圾邮件,可以给邮件系统增加DKIM(DomainKeys Identified Mail)功能,其主要的原理通俗的说,就是在发送邮件的时候通过私钥在邮件头写一段加密信息,然后公钥放到DNS服务器上,邮件的接收方通过邮件头的加密信息来和DNS上的公钥比对来判定邮件来源是否合法。这个计数貌似是雅虎提出的,被Yahoo! Mail和Gmail等厂商采用。
可以在http://sourceforge.net/projects/dkim-milter/ 下载源代码:
[root@mail dkim]# ll
total 736
-rw-r--r-- 1 root root 748415 Jul 13 2011 dkim-milter-2.8.3.tar.gz
[root@mail dkim]# tar zxvf dkim-milter-2.8.3.tar.gz
也可以通过下载RPM安装包安装,比较简单:
[root@mail dkim]# wget http://download.fedora.redhat.com/pub/epel/5/i386/dkim-milter-2.8.3-4.el5.i386.rpm
[root@mail dkim]# rpm -ivh dkim-milter-2.8.3-4.el5.i386.rpm
安装完成后,首先要生成公钥和私钥两个文件,可以使用源码包里的一个脚本,其路径在:
dkim-milter-2.8.3/dkim-filter/dkim-genkey.sh
参数为要使用发信的域名:
[root@mail dkim]# ./dkim-genkey.sh -r -d mail.banping.com
[root@mail dkim]# ll
total 1024
-rw------- 1 root root 887 Jul 13 12:47 default.private
-rw------- 1 root root 308 Jul 13 12:47 default.txt
然后把这个default.txt的内容组织一下放到DNS上,增加一条domain=default._domainkey.mail.banping.com的txt记录,内容类似这样:
v=DKIM1;p=MIGfMA0GCSqGSIb898L9LKJ7dDFGNADCBiQKBgQCU1iD47S+n92ZeXKL444Kg7VzkczqN5xZnx6px1C+
/hImMNoQvF3X6HXLG1+OzO7s8Odf3lhpqgGWq+atFKT3YUZUY3vAL983LIKJIWo+
988QIB5iw1cotBretF0TFWVdf4weNyPrC1Qtvm8kQswIDAQAB" ;
把私钥放到想要的位置:
[root@mail dkim]# mv default.private /etc/mail/dkim-milter/keys/default
修改keylist配置文件:
[root@mail dkim]# vi /etc/mail/dkim-milter/keys/keylist
*@mail.rtmail.cn:mail.rtmail.cn:/etc/mail/dkim-milter/keys/default
也可以不动这个文件,把私钥位置配置在dkim-filter.conf文件中,由KeyFile参数指定:
[root@mail dkim]# vi /etc/mail/dkim-milter/dkim-filter.conf
AutoRestart yes
Domain mail.banping.com
Selector default
Socket inet:20118@localhost
Syslog Yes
X-Header Yes
KeyFile /etc/mail/dkim-milter/keys/default
至此DKIM配置完成,再修改postfix中的配置,在发信的时候启用加密功能:
[root@mail dkim]# vi /etc/postfix/main.cn
smtpd_milters = inet:localhost:20118
non_smtpd_milters = inet:localhost:20118
milter_protocol = 2
milter_default_action = accept
OK,现在启动DKIM和PostFix服务就可以了:
[root@mail dkim]# service dkim-milter start
[root@mail keys]# service postfix reload
Reloading postfix: [ OK ]
除了DKIM,还可以在DNS上增加SPF配置来提高邮件发送成功的几率,比如:
v=spf1 ip4:110.120.130.140 ~all
可以查看DNS上的配置是否成功:
[root@mail postfix]# dig -t txt mail.banping.com
; QUESTION SECTION:
;mail.banping.com. IN TXT
;; ANSWER SECTION:
mail.banping.com. 600 IN TXT "v=spf1 ip4:110.120.130.140 ~all"
可以到以下地址来测试DKIM和SPF服务是否正常:
http://www.brandonchecketts.com/emailtest.php
http://www.openspf.org/Why?show-form=1
HBase是一个开源的NoSQL产品,它是实现了Google BigTable论文的一个开源产品,和Hadoop和HDFS一起,可用来存储和处理海量column family的数据。官方网址是:http://hbase.apache.org。Hbase的体系结构比较复杂,本文只探讨基本的安装测试问题,首先从镜像下载最新版的HBase:
[root@localhost hbase]# wget http://mirror.bjtu.edu.cn/apache/hbase/stable/hbase-0.90.3.tar.gz
Hbase是Java开发的,先检查下本地的JDK版本是否在1.6以上:
[root@localhost hbase]# java -version
java version "1.6.0_24"
解压并配置数据文件的路径:
[root@localhost hbase]# tar zxvf hbase-0.90.3.tar.gz
[root@localhost hbase]# cd hbase-0.90.3/conf
[root@localhost conf]# vi hbase-site.xml
</configuration>
<configuration><property>
<name>hbase.rootdir</name>
<value>/home/banping/hbase/data</value>
</property>
Hbase依赖于Hadoop来运行,它有两种配置方式,一种是比较简单的单实例方式,它已经内置了0.20版本的Hadoop包和一个本地Zookeeper,它们运行在同一个JVM之下,可以用本地文件系统而不用HDFS。另外一种比较复杂的分布式部署,需要在每一个节点替换自带的Hadoop包以免有版本问题,而且必须有一个HDFS实例,同时需要独立的ZooKeeper集群。为简单起见,我们选择单实例部署的方式,启动Hbase进程:
[root@localhost hbase-0.90.3]# bin/start-hbase.sh
starting master, logging to /home/banping/hbase/hbase-0.90.3/bin/../logs/hbase-root-master-localhost.localdomain.out
[root@localhost webtest]# netstat -tnlp|grep java
tcp 0 0 :::2181 :::* LISTEN 9880/java
tcp 0 0 :::60010 :::* LISTEN 9880/java
tcp 0 0 ::ffff:127.0.0.1:63148 :::* LISTEN 9880/java
tcp 0 0 ::ffff:127.0.0.1:35539 :::* LISTEN 9880/java
tcp 0 0 :::60030 :::* LISTEN 9880/java
可以看到启动了5个端口,可以通过自带的shell命令来进行基本的操作:
[root@localhost hbase-0.90.3]# bin/hbase shell
hbase(main):002:0> create 'test','cf'
0 row(s) in 0.9940 seconds
hbase(main):019:0> list
TABLE
test
1 row(s) in 0.0290 seconds
hbase(main):022:0> put 'test', 'row1', 'cf:a', 'value1'
0 row(s) in 0.2130 seconds
hbase(main):023:0> put 'test', 'row2', 'cf:b', 'value2'
0 row(s) in 0.0120 seconds
hbase(main):024:0> put 'test', 'row3', 'cf:c', 'value3'
0 row(s) in 0.0130 seconds
hbase(main):025:0> scan 'test'
ROW COLUMN+CELL
row1 column=cf:a, timestamp=1310027460885, value=value1
row2 column=cf:b, timestamp=1310027469458, value=value2
row3 column=cf:c, timestamp=1310027476262, value=value3
3 row(s) in 0.0870 seconds
hbase(main):026:0> get 'test', 'row1'
COLUMN CELL
cf:a timestamp=1310027460885, value=value1
1 row(s) in 0.0250 seconds
hbase(main):027:0> disable 'test'
0 row(s) in 2.0920 seconds
hbase(main):029:0> drop 'test'
0 row(s) in 1.1440 seconds
hbase(main):030:0> exit
停止Hbase实例:
[root@localhost hbase-0.90.3]# ./bin/stop-hbase.sh
stopping hbase......
如果使用PHP操作Hbase,一种途径是使用Facebook开源出来的thrift,官网是:http://thrift.apache.org/ ,它是一个类似ice的中间件,用于不同系统语言间信息交换。首先下载最新的版本:
[root@localhost hbase]# wget http://mirror.bjtu.edu.cn/apache//thrift/0.6.1/thrift-0.6.1.tar.gz
安装需要的依赖包:
[root@localhost thrift-0.6.1]# sudo yum install automake libtool flex bison pkgconfig gcc-c++ boost-devel libevent-devel zlib-devel python-devel ruby-devel
[root@localhost thrift-0.6.1]# ./configure --prefix=/home/banping/hbase/thrift --with-php-config=/usr/local/php/bin/[root@localhost thrift-0.6.1]# make[root@localhost thrift-0.6.1]# make install
[root@localhost hbase]# thrift/bin/thrift --gen php /home/banping/hbase/hbase-0.90.3/src/main/resources/org/apache/hadoop/hbase/thrift/Hbase.thrift[root@localhost hbase]# cd gen-php/Hbase[root@localhost Hbase]# lltotal 320-rw-r--r-- 1 root root 285433 Jul 7 19:22 Hbase.php-rw-r--r-- 1 root root 27426 Jul 7 19:22 Hbase_types.php
[root@localhost Hbase]# cp -a /home/banping/hbase/thrift-0.6.1/lib/php /home/webtest/thrift/[root@localhost Hbase]# cd /home/webtest/thrift/[root@localhost thrift]# mkdir packages[root@localhost thrift]# cp -a /home/banping/hbase/gen-php/Hbase /home/webtest/thrift/packages
据一些资料说也可以使用PHP扩展的方式来使用thrift(php和HBase接口文件仍然是必须的),但是我测试没有通过,做法如下:
[root@localhost thrift]# cd ext/thrift_protocol[root@localhost thrift_protocol]# /usr/local/php/bin/phpize[root@localhost thrift_protocol]# ./configure --with-php-config=/usr/local/php/bin/php-config --enable-thrift_protocol[root@localhost thrift_protocol]# make[root@localhost thrift_protocol]# make install
[root@localhost hbase-0.90.3]# ./bin/start-hbase.sh[root@localhost hbase-0.90.3]# ./bin/hbase-daemon.sh start thriftstarting thrift, logging to /home/banping/hbase/hbase-0.90.3/bin/../logs/hbase-root-thrift-localhost.localdomain.out
thrift默认监听的端口是9090
[root@localhost webtest]# netstat -tnlp|grep java
tcp 0 0 ::ffff:127.0.0.1:9090 :::* LISTEN 10069/java
tcp 0 0 :::2181 :::* LISTEN 9880/java
tcp 0 0 :::60010 :::* LISTEN 9880/java
tcp 0 0 ::ffff:127.0.0.1:63148 :::* LISTEN 9880/java
tcp 0 0 ::ffff:127.0.0.1:35539 :::* LISTEN 9880/java
tcp 0 0 :::60030 :::* LISTEN 9880/java
写一个PHP文件来测试:
[root@localhost webtest]# vi hbase.php<?php$GLOBALS['THRIFT_ROOT'] = '/home/webtest/thrift/src';require_once( $GLOBALS['THRIFT_ROOT'].'/Thrift.php' );require_once( $GLOBALS['THRIFT_ROOT'].'/transport/TSocket.php' );require_once( $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php' );require_once( $GLOBALS['THRIFT_ROOT'].'/protocol/TBinaryProtocol.php' );require_once( $GLOBALS['THRIFT_ROOT'].'/packages/Hbase/Hbase.php' );$socket = new TSocket( 'localhost', 9090 );$socket->setSendTimeout( 10000 ); // Ten seconds (too long for production, but this is just a demo ;)$socket->setRecvTimeout( 20000 ); // Twenty seconds$transport = new TBufferedTransport( $socket );$protocol = new TBinaryProtocol( $transport );$client = new HbaseClient( $protocol );$transport->open();echo( "listing tables...\n" );$tables = $client->getTableNames();sort( $tables );foreach ( $tables as $name ) {echo( " found: {$name}\n" );}$columns = array(new ColumnDescriptor( array('name' => 'entry:','maxVersions' => 10) ),new ColumnDescriptor( array('name' => 'unused:') ));$t = "table1";echo( "creating table: {$t}\n" );try {$client->createTable( $t, $columns );} catch ( AlreadyExists $ae ) {echo( "WARN: {$ae->message}\n" );}$t = "test";echo( "column families in {$t}:\n" );$descriptors = $client->getColumnDescriptors( $t );asort( $descriptors );foreach ( $descriptors as $col ) {echo( " column: {$col->name}, maxVer: {$col->maxVersions}\n" );}$t = "table1";echo( "column families in {$t}:\n" );$descriptors = $client->getColumnDescriptors( $t );asort( $descriptors );foreach ( $descriptors as $col ) {echo( " column: {$col->name}, maxVer: {$col->maxVersions}\n" );}$t = "table1";$row = "row_name";$valid = "foobar-\xE7\x94\x9F\xE3\x83\x93";$mutations = array(new Mutation( array('column' => 'entry:foo','value' => $valid) ),);$client->mutateRow( $t, $row, $mutations );$table_name = "table1";$row_name = 'row_name';$fam_col_name = 'entry:foo';$arr = $client->get($table_name, $row_name , $fam_col_name);// $arr = arrayforeach ( $arr as $k=>$v ) {// $k = TCellecho ("value = {$v->value} , <br> ");echo ("timestamp = {$v->timestamp} <br>");}$table_name = "table1";$row_name = "row_name";$arr = $client->getRow($table_name, $row_name);// $client->getRow return a arrayforeach ( $arr as $k=>$TRowResult ) {// $k = 0 ; non-use// $TRowResult = TRowResultvar_dump($TRowResult);}$transport->close();?>
技术组织
最近评论
历史归档
广告位







