以下是ab测试为1 worker,4 works和8 works的并发情况。
服务器硬件环境:I5 6300U, 4核心,4G内存,运行在VM虚拟机上
服务器软件环境:CentOS 6.5 64位, Perl 5.24 64位
ab范例
ab -c 200 -n 10000 http://192.168.100.10:8080
服务端:一个查询和写入redis数据的功能
1 work:Requests per second: 68.74 [#/sec] (mean)
4 works:Requests per second: 202.60 [#/sec] (mean)
8 works:Requests per second: 420.37 [#/sec] (mean)
16 works:ab崩溃了一次,第二次测试降低到4 works都不如,同时有请求出错的情况。
对于mojo来说,如果你服务端用的不是异步的写法,那么多works可以帮你缓解并发的问题。
]]>#!/usr/bin/perl -w
use Imager::QRCode;my $qrcode = Imager::QRCode->new(size => 2,margin => 2,version => 1,level => 'M',casesensitive => 1,lightcolor => Imager::Color->new(255, 255, 255),darkcolor => Imager::Color->new(0, 0, 0),);my $img = $qrcode->plot("www.google.com");$img->write(file => 'google.jpg', type=>'jpeg') or die $img->errstr;
后来发现MT6其实还是可以免费申请的,只要你接受它的授权条件就可以了,于是赶紧下载6,很顺利的升级了上去,而且在Perl5.24下工作的也很好,另外6可以直接使用PSGI,现在无论是执行速度还是写作时候的便利性都比4方便了很多。
如果你也还在用mt的话,不妨升级到6
]]>传统mojo的开发需要不停的关闭和重服务,这对开发来说是很不友好的。不管不用担心,mojo早就想到了这一点,跟nodejs下的geddy一样,mojo有个叫morbo的服务可以做自动加载重启的工作。而使用起来也很简单,如果你装好了mojo,那morbo也就自带了,你只需要执行
morbo yourapp.pl
当你修改过代码后,mojo就会自动帮你重新加载,你只需要把重心放在开发上就ok了。
但是在winodws上使用morbo而恰好你又使用了EV的话可能就会出现下面的情况
Server available at http://127.0.0.1:3000
EV does not work with ithreads.
这是因为EV是不支持线程的,具体愿意可以去看EV的文档。
这个时候也不用慌,只需要在你的用户的环境变量中设置一下
MOJO_REACTOR=Mojo::Reactor::Poll
是不是炒鸡煎蛋,
]]>子进程 新的 pre-installation 脚本 返回了错误号 1
的问题。
折腾半天无果,最后参考http://www.cnblogs.com/xusir/p/3342722.html
sudo rm -rf /var/lib/mysql/ sudo rm -rf /etc/mysql/ sudo apt-get autoremove mysql* --purge
总结就是降级的时候没有把以前的东西删除干净,所以把东西删除干净后在执行
sudo apt-get install mysql-server mysql-common
问题解决到此解决
]]>本人以实战为主,以下是干货设置部分
以下操作只是在一台机器上做的,如果有多台机器则需要每台机器都按这样的步骤操作
首先要规划到数据库位置,我这里启用了一个mongos,2个配置服务器,3个数据库切片。
习惯上大家都是放在/data中,所以以下为创建所需目录的部分
mkdir -p /data/mongo/mongos/log
mkdir -p /data/mongo/config/data
mkdir -p /data/mongo/config/log
mkdir -p /data/mongo/config1/data
mkdir -p /data/mongo/config1/log
mkdir -p /data/mongo/shard1/data
mkdir -p /data/mongo/shard1/log
mkdir -p /data/mongo/shard2/data
mkdir -p /data/mongo/shard2/log
mkdir -p /data/mongo/shard3/data
mkdir -p /data/mongo/shard3/log
这样就创建好了我们所需要的目录。
]]> 接下来就是启动服务了
mongod --configsvr --dbpath /data/mongo/config/data --bind_ip 127.0.0.1,192.168.0.1 --port 21000 --logpath /data/mongo/config/log/config.log --fork
mongod --configsvr --dbpath /data/mongo/config1/data --bind_ip 127.0.0.1,192.168.0.1--port 21001 --logpath /data/mongo/config1/log/config.log --fork
mongos --configdb 192.168.0.1:21000,192.168.0.2:21000,192.168.0.1:21001 --bind_ip 127.0.0.1,192.168.0.1--port 20000 --logpath /data/mongo/mongos/log/mongos.log --fork
mongod --shardsvr --replSet shard1 --bind_ip 127.0.0.1,192.168.0.1--port 22001 --dbpath /data/mongo/shard1/data --logpath /data/mongo/shard1/log/shard1.log --fork
mongod --shardsvr --replSet shard2 --bind_ip 127.0.0.1,192.168.0.1--port 22002 --dbpath /data/mongo/shard2/data --logpath /data/mongo/shard2/log/shard2.log --fork
mongod --shardsvr --replSet shard3 --bind_ip 127.0.0.1,192.168.0.1 --port 22003 --dbpath /data/mongo/shard3/data --logpath /data/mongo/shard3/log/shard3.log --fork
注意bind_ip这参数,这个很关键,如果没有的话,则mongod默认监听所有的ip地址,也就是说,如果你的服务器正好有外网地址的话,相当于直接就暴漏了。
另外一个就是mongos中的configdb参数,这里的ip地址数可以为1个,也可以为奇数个,当为偶数个的时候会提示你地址错误,如果你可用的机器没有3台(本例中其实可用的机器sh2台),那就本地起三个不同端口的mongos服务然后就类似这样的配置就OK了。
如果所有服务都启动正常了,就可以开始进行集群配置了。
首先,我们要通过mongos去连接,而不是直接去操作数据库。简单的说,我们要去连接2000的端口,而不是22001,22002,22003。
在提醒一下,后继操作都需要在mongos里,千万不要直接连接到数据库去做任何与创建数据有关的操作。
以下操作只需要操作一次就行了,不需要每台机器都这样。
连接到mongos
mongo 127.0.0.1:20000
切换到admin表
use admin
db.runCommand( { addshard : "shard1/192.168.0.1:22001,192.168.0.2:22001"});
db.runCommand( { addshard : "shard2/192.168.0.1:22002,192.168.0.2:22002"});
db.runCommand( { addshard : "shard3/192.168.0.1:22003,192.168.0.2:22003"});
这样集群就做好了,理论上来说,建议至少3台机器来做集群比较好,如果没钱的话,用单台机器去做反而性能更好些。毕竟文件同步,复制什么的都是需要开销的。
剩下的就是切片什么了,因为涉及切片规则,每个人的应用不一样,而且上面的文章里面人家也都写的很明确,我就略过了。
最后最后就是我对mongodb的一些个人意见。mongodb确实很好,但并不适用每个项目,它跟关系数据库直观上最大的区别就是要改变关系数据库的范式理念,否则开发起来将会是你的噩梦。
mongo适合于,数据内容不确定,很杂乱,无规律,无组织,无纪律,无xx,扯远了点。简单点说,如果把关系数据库看成一个必须要穿西装打领带才能进入的餐厅的话,那mongo则是路边的大排档,不管你穿的啥样,有钱没钱都可以平等对待。
最后就至少有2个人跟我抱怨过mongo会莫名其妙的丢失数据的问题,但具体发生的细节我也不清楚,所以我把这个问题留给你们来思考吧。
]]>
http://zeromq.org/intro:get-the-software
看错误信息里面,发现用LWP模块发送的GET请求回来的都是500的错误,但是通过浏览又是正常的,在往下看,有条如下的信息:
syswrite() on unopened filehandle at IO/Handle.pm
本着以为是IO::Handle的问题,但升级之后问题依旧,重装LWP也依然无效,后来Google之后发现又人也遇见过这样的问题,解决办法就是升级IO::Socket::INET6,后来才想起貌似有次安装模块的时候升级过IO::Socket模块,而IO::Socket::INET6又不是必须安装的,所以CPAN没有自动升级它,至此问题解决。
]]>本人在自己的机器上也做了下测试。硬件配置Intel(R) Xeon(R) CPU X3430 @ 2.40GHz, 8G内存,Centos6.4 64位 perl 5.10 64位。
原文中作者测试了Data::MessagePack,Sereal,JSON,CBOR,这里我也加了一个Storable,毕竟从取材来说这个模块是自带的。注意CBOR目前只支持64位的操作系统。以下是测试结果
]]> 测试小数据的结果{
CBOR {
decode 809562,
encode 1720319,
size 30
},
JSON {
decode 669260,
encode 860160,
size 42
},
MP {
decode 573439,
encode 491519,
size 30
},
Sereal {
decode 595284,
encode 600178,
size 38
},
'Sereal OO' {
decode 764586,
encode 1181633,
size 38
},
storable {
decode 312785,
encode 46109
}
}
#!perluse 5.010;use DDP;use Data::MessagePack;use Sereal;use JSON;#use JSON::XS;use CBOR::XS;use Storable qw(nstore store_fd nstore_fd freeze thaw dclone);use Benchmark qw/countit :hireswallclock/;my $dt = Data::MessagePack->new;my $se = Sereal::Encoder->new({no_shared_hashkeys => 1}); # may lead to high size, but 100% faster at encoding !my $sd = Sereal::Decoder->new;my $cb = CBOR::XS->new;sub count_this {my ($label, $meth, $storage) = @_;$|=1;print $label, " ";$$storage = countit(1, $meth)->iters;print ".";$$storage += countit(1, $meth)->iters;print ".";$$storage += countit(1, $meth)->iters;say ".";$$storage = int($$storage / 3);}sub run_bench {my ($label, $struct) = @_;my $ser_sereal = Sereal::encode_sereal($struct);my $ser_sereal_oo = $se->encode($struct);my $ser_mp = $dt->pack($struct);my $ser_json = JSON::encode_json($struct);my $ser_cb = $cb->encode($struct);my $ser_storable = freeze $struct;my %result = ('Sereal' => { size => length($ser_sereal) },'Sereal OO' => { size => length($ser_sereal_oo) },'MP' => { size => length($ser_mp) },'JSON' => { size => length($ser_json) },'CBOR' => { size => length($ser_cb) },'Storable' => { size => length($ser_storable) },);say "Start benchmark for $label ...";count_this('Sereal Decode' , sub {Sereal::decode_sereal($ser_sereal)}, \$result{Sereal}{decode});count_this('Sereal Encode' , sub {Sereal::encode_sereal($struct)} , \$result{Sereal}{encode});count_this('Sereal OO Decode', sub {$sd->decode($ser_sereal_oo)} , \$result{'Sereal OO'}{decode});count_this('Sereal OO Encode', sub {$se->encode($struct)} , \$result{'Sereal OO'}{encode});count_this('MP Decode' , sub {$dt->unpack($ser_mp)} , \$result{'MP'}{decode});count_this('MP Encode' , sub {$dt->pack($struct)} , \$result{'MP'}{encode});count_this('JSON Decode' , sub {JSON::decode_json($ser_json)} , \$result{'JSON'}{decode});count_this('JSON Encode' , sub {JSON::encode_json($struct)} , \$result{'JSON'}{encode});count_this('CBOR Decode' , sub {$cb->decode($ser_cb)} , \$result{'CBOR'}{decode});count_this('CBOR Encode' , sub {$cb->encode($struct)} , \$result{'CBOR'}{encode});count_this('storable Encode' , sub {freeze $struct} , \$result{'storable'}{encode});count_this('storable Decode' , sub {thaw $ser_storable} , \$result{'storable'}{decode});say "Finish benchmark for $label ...";say "Result : ";say p(%result);}run_bench( 'small', { a => 1, b => 2, c => 3, d => 'string', e => 5.018 } );run_bench( 'large', { a => 1, b => 2, c => 3, d => 'string', e => 5.018, f => [map{$_} 1..1000] } );
]]> Original: 306
LZ4: 232
Snappy: 239
LZF: 229
Zlib: 188
Benchmark: timing 100000 iterations of LZ4 compress, LZ4 decompress, LZF compress, LZF decompress, Snappy compres, Snappy decompress, Zlib compress, Zlib uncompress...
LZ4 compress: 1 wallclock secs ( 1.03 usr + 0.01 sys = 1.04 CPU) @ 95693.78/s (n=100000)
LZ4 decompress: 0 wallclock secs ( 0.86 usr + 0.00 sys = 0.86 CPU) @ 116550.12/s (n=100000)
LZF compress: 1 wallclock secs ( 1.03 usr + 0.00 sys = 1.03 CPU) @ 97181.73/s (n=100000)
LZF decompress: 0 wallclock secs ( 0.89 usr + 0.00 sys = 0.89 CPU) @ 112485.94/s (n=100000)
Snappy compres: 1 wallclock secs ( 1.00 usr + 0.00 sys = 1.00 CPU) @ 100100.10/s (n=100000)
Snappy decompress: 0 wallclock secs ( 0.87 usr + 0.00 sys = 0.87 CPU) @ 114547.54/s (n=100000)
Zlib compress: 18 wallclock secs (17.78 usr + 0.00 sys = 17.78 CPU) @ 5622.72/s (n=100000)
Zlib uncompress: 7 wallclock secs ( 7.74 usr + 0.00 sys = 7.74 CPU) @ 12923.24/s (n=100000)
我们可以看到zlib的压缩效果是好的,但是显而易见的是压缩和解压时间也是最长的,但反过来,解压速度却相当的好,这点倒是跟模块文档里测试的结果大相径庭。所以结论就是LZ4的解压算法最符合需求,压缩的大小比Snappy要好,比LZF稍微差一点但不如Snappy差距那大,因为JSON的数据是真实环境的,也就很好衡量用哪种算法了了。
本人是win7旗舰版,i5 2500, 4G内存,perl 5.16 64位
有兴趣的可以自己测试一下。以下是测试代码
]]>use 5.010;
use Compress::LZ4();
use Compress::Snappy();
use Compress::LZF();
use Compress::Zlib();
my $datas = ‘你自己的json数据’;
my $lz4 = Compress::LZ4::compress($datas);
my $snappy = Compress::Snappy::compress($datas);
my $lzf = Compress::LZF::compress($datas);
my $zlib = Compress::Zlib::compress($datas);
say 'Original: ' . length $datas;
say 'LZ4: ' . length $lz4;
say 'Snappy: ' . length $snappy;
say 'LZF: ' . length $lzf;
say 'Zlib: ' . length $zlib;
use Benchmark;
Benchmark::timethese 100000, {
'LZ4 compress' => sub {
Compress::LZ4::compress($datas);
},
'Snappy compres' => sub {
Compress::Snappy::compress($datas);
},
'LZF compress' => sub {
Compress::LZF::compress($datas);
},
'Zlib compress' => sub {
Compress::Zlib::compress($datas);
},
'LZ4 decompress' => sub {
Compress::LZ4::decompress($lz4);
},
'Snappy decompress' => sub {
Compress::Snappy::decompress($snappy);
},
'LZF decompress' => sub {
Compress::LZF::decompress($lzf);
},
'Zlib uncompress' => sub {
Compress::Zlib::uncompress($zlib);
}
};