Java Nio学习手记[收集]

传统的并发型服务器设计是利用阻塞型网络I/O 以多线程的模式来实现的,然而由于系统常常在进行网络读写时处于阻塞状态,会大大影响系统的性能;自Java1. 4 开始引入了NIO(新I/O) API,通过使用非阻塞型I/O,实现流畅的网络读写作,为开发高性能并发型服务器程序提供了一个很好的解决方案。这就是java nio.

传统的阻塞型网络 I/O的不足:

Java 平台传统的I/O 系统都是基于Byte(字节)和Stream(数据流)的,相应的I/O 作都是阻塞型的,所以服务器程序也采用阻塞型I/O 进行数据的读、写作。本文以TCP长连接模式来讨论并发型服务器的相关设计,为了实现服务器程序的并发性要求,系统由一个单独的主线程来监听用户发起的连接请求,一直处于阻塞状态;当有用户连接请求到来时,程序都会启一个新的线程来统一处理用户数据的读、写作。

这种模式的优点是简单、实用、易管理;然而缺点也是显而易见的:由于是为每一个客户端分配一个线程来处理输入、输出数据,其线程与客户机的比例近似为1:1,随着线程数量的不断增加,服务器启动了大量的并发线程,会大大加大系统对线程的管理开销,这将成为吞吐量瓶颈的主要原因;其次由于底层的I/O 作采用的同步模式,I/O 作的阻塞管

理粒度是以服务于请求的线程为单位的,有可能大量的线程会闲置,处于盲等状态,造成I/O资源利用率不高,影响整个系统的性能。

对于并发型服务器,系统用在阻塞型I/O 等待和线程间切换的时间远远多于CPU 在内存中处理数据的时间,因此传统的阻塞型I/O 已成为制约系统性能的瓶颈。Java1.4 版本后推出的NIO 工具包,提供了非阻塞型I/O 的异步输入输出机制,为提高系统的性能提供了可实现的基础机制。

NIO:

针对传统I/O 工作模式的不足,NIO 工具包提出了基于Buffer(缓冲区)、Channel(通道)、Selector(选择器)的新模式;Selector(选择器)、可选择的Channel(通道)和SelectionKey(选择键)配合起来使用,可以实现并发的非阻塞型I/O 能力。

Buffer(缓冲器)

Buffer 类是一个抽象类,它有7 个子类分别对应于七种基本的数据类型:ByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer 和ShortBuffer。每一个Buffer对象相当于一个数据容器,可以把它看作内存中的一个大的数组,用来存储和提取所有基本类型(boolean 型除外)的数据。Buffer 类的核心是一块内存区,可以直接对其执行与内存有关的作,利用作系统特性和能力提高和改善Java 传统I/O 的性能。

Channel(通道)

Channel 被认为是NIO 工具包的一大创新点,是(Buffer)缓冲器和I/O 服务之间的通道,具有双向性,既可以读入也可以写出,可以更高效的传递数据。我们这里主要讨论ServerSocketChannel 和SocketChannel,它们都继承了SelectableChannel,是可选择的通道,分别可以工作在同步和异步两种方式下(这里的可选择不是指可以选择两种工作方式,而是指可以有选择的注册自己感兴趣的事件)。当通道工作在同步方式时,它的功能和编程方法与传统的ServerSocket、Socket 对象相似;当通道工作在异步工作方式时,进行输入输出处理不必等到输入输出完毕才返回,并且可以将其感兴趣的(如:接受作、连接作、读出作、写入作)事件注册到Selector 对象上,与Selector 对象协同工作可以更有效率的支持和管理并发的网络套接字连接。

Selector(选择器)和SelectionKey(选择键)

各类 Buffer 是数据的容器对象;各类Channel 实现在各类Buffer 与各类I/O 服务间传输数据。Selector 是实现并发型非阻塞I/O 的核心,各种可选择的通道将其感兴趣的事件注册到Selector 对象上,Selector 在一个循环中不断轮循监视这各些注册在其上的Socket 通道。SelectionKey 类则封装了SelectableChannel 对象在Selector 中的注册信息。当Selector 监测到在某个注册的SelectableChannel 上发生了感兴趣的事件时,自动激活产生一个SelectionKey对象,在这个对象中记录了哪一个SelectableChannel 上发生了哪种事件,通过对被激活的SelectionKey 的分析,外界可以知道每个SelectableChannel 发生的具体事件类型,进行相应的处理。

Linux系统更换sshd的方法手记[from科学院]

朋友的服务器让人给黑了,把sshd都给更换了,拿到root用户名密码直接用curl往外传。绝对是老毛子的手法,非常娴熟,入侵涉及的方案有perl服务、c、shell、curl、php exec等等。

在最简单的分析下,采取更换sshd服务的办法来去除老毛子的垃圾sshd.

第一步、下载、安装

wget -c "ftp://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-5.0p1.tar.gz"

tar zxvf openssh-5.0p1.tar.gz
cd openssh-5.0p1 请确认Zlib和OpenSSL的版本:
openssh-5.0p1要求Zlib的版本在1.2.1.2以上,OpenSSL版本在0.9.6以上.下面是Zlib和 OpenSSL的官方地址:
http://www.gzip.org/zlib/
http://www.openssl.org/

在安装过程中我遇到了zlib的版本过低。从上边的网址去下一个 zlib-1.2.3.tar.gz

tar zxvf zlib-1.2.3.tar.gz

cd zlib-1.2.3

./configure

make && make install 然后重新进入 openssh-5.0p1:

./configure --sysconfdir=/etc/ssh

make

这一步后面很牛B,要去到那个修改过的openssh的目录里 make uninstall (就是要把老毛子的病sshd给全部rm掉),然后再执行下面的步骤:

make install 第二步、配置启动革新

新安装的sshd都在/usr/local/sbin/sshd,老的在/usr/sbin/sshd,ps能看到老的还在跑(当然还在跑,不跑你还能连着ssh作吗~~·)

修改配置文件,让新的sshd在新的端口启动:

vi /etc/ssh/sshd_config

Port 220

然后启动新的sshd:

/usr/local/ssh/sbin/sshd -f /etc/ssh/sshd_config

注意打开下iptable:

iptables -I INPUT -p udp --dport 220 -j ACCEPT K掉原来的~~搞定!打完收工。

多nginx单php-fpm的配置方法[from科学院]

用php fastcgi和nginx搭配的形式是很常见的,在很BT的需求下,可能会需要多个nginx走不同的端口,而进程只用一个php-fpm。

本文所讲的环境比上述一句话还要BT,存在一个php-fpm,而且每个nginx都以一个非超级用户所有来进行运行。

这样就存在了一个BT的情况,php-fpm默认不能以root权限运行,而普通用户来运行的话,对其他用户的目录,php-fpm将没有权限,页面在运行php的时候,会提示404。

于是有以下的解决方案:

找到php的源代码 $src_path/sapi/cgi/fpm/fpm_unix.c

在文件顶部增加一个宏定义:#define I_REALLY_WANT_ROOT_PHP

重新 configure make make install

此时再修改php-fpm.conf 将user group都修改成root(经过上面的修改php-fpm已经支持root了)。

重启php-fpm.

配置各nginx.conf:

location ~ .*\.(php|php5)?$
#fastcgi_pass  unix:/tmp/php-cgi.sock;
fastcgi_pass  127.0.0.1:9000;
fastcgi_index index.php;
include fcgi.conf;
}

点到即止,不再多说。。。

用java并发测试tokyo Cabinet的性能[重大更正篇]

在前面一篇文章 用java并发测试tokyo cabinet的性能[五四陈手记]

提到了测试tc的效率问题,最后的结论是70W/s,由于当时的错误,导致了一些严重影响大家的结论,如今本着认真治学,谨慎小心的态度,重新公布最新的代码和结论,还望受影响的同志们不要发烧。。。

首先,总结上一次为什么会犯错的原因:

1. 测试代码有问题,TDB db = new TDB();不能放在线程中去new,也许是tc实现的问题,详细原因没有去研究。

2.赶着时间测,把写入的时候的结果直接给屏了。

重新公布新的测试代码:

package test;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.Random;

import java.util.concurrent.atomic.AtomicLong;

import tokyocabinet.*;

public class BenchMark {

private static List<TDB> dbList = new ArrayList<TDB>();

public static class Stat {

private AtomicLong _count = new AtomicLong(0);

private static Stat _instance = new Stat();

public static Stat getInstance() {

return _instance;

}

private Stat() {

_printer = new RatePrinter(_count);

_printer.setDaemon(true);

_printer.start();

}

public void inc() {

_count.incrementAndGet();

}

private RatePrinter _printer;

private static class RatePrinter extends Thread {

private long _last;

private AtomicLong _c;

public RatePrinter(AtomicLong c) {

_c = c;

}

@Override

public void run() {

while (true) {

try {

long current = _c.get();

System.out.println("Rate: " + (current - _last) + " req/s");

_last = current;

Thread.sleep(1000L);

} catch (Throwable e) {

e.printStackTrace();

}

}

}

}

}

public static class EchoThread extends Thread {

// private TDB tdb;

public EchoThread(String ip, String port, int in, ThreadGroup group) {

super(group, "EchoThread-" + in);

// // create the object

// TDB tdb = new TDB();

//

// // open the database

// if(!tdb.open("casket"+in+".tct", TDB.OWRITER | TDB.OCREAT)){

// int ecode = tdb.ecode();

// System.err.println("open error: " + tdb.errmsg(ecode));

// }

}

@Override

public void run() {

int index = 0;

// create the object

Random r = new Random();

// open the database

// if (!tdb.open("casket" + Thread.currentThread().getId() + ".tct", TDB.OWRITER | TDB.OCREAT)) {

// int ecode = tdb.ecode();

// System.err.println("open error: " + tdb.errmsg(ecode));

// }

while (true) {

try {

TDB tdb = dbList.get(0);

String pkey = index + "asdf";

Map<String, String> cols = new HashMap<String, String>();

cols.put("name", "mikio" + index);

cols.put("age", "30");

cols.put("lang", "ja,en,c");

if (!tdb.put(pkey, cols)) {

int ecode = tdb.ecode();

System.err.println("put error: " + tdb.errmsg(ecode) + " key:" + pkey + "  value:" + cols);

}

// client.insert("Table1", "name"+index, "Standard1:name",

// ("name"+index).getBytes("UTF-8"),

// System.currentTimeMillis(), true);

// client.get_column("Table1", "name0", "Standard1:name");

index++;

Stat.getInstance().inc();

} catch (Throwable e) {

e.printStackTrace();

break;

} finally {

// close the database

//if (!tdb.close()) {

//int ecode = tdb.ecode();

// System.err.println("close error: " +

// tdb.errmsg(ecode));

//}

}

}

}

}

/**

* @param args

* @throws TTransportException

*/

public static void main(String[] args) {

if (args.length != 1) {

System.out.println("Usage: Benchmark <concurrent>");

System.exit(1);

}

String ip = args[0];

String port = args[0];

Integer concurrent = Integer.valueOf(args[0]);

System.out.println("ip = " + ip + ",port = " + port + ",concurrent = " + concurrent);

ThreadGroup group = new ThreadGroup("Benchmark");

List<Thread> threads = new ArrayList<Thread>();

for (int i = 0; i < concurrent; i++) {

TDB db = new TDB();

//db.optimize();

if (!db.open("./test" + i + ".tdb", TDB.OCREAT | TDB.OWRITER)) {

int ecode = db.ecode();

System.err.println("open error: " + TDB.errmsg(ecode));

continue;

}

dbList.add(db);

}

for (int x = 0; x < concurrent; ++x) {

Thread t = new EchoThread(ip, port, x, group);

threads.add(t);

t.start();

}

}

} 对比上一次的代码,能够发现,1.new TDB的过程扔进了Thread.start之前;2.在thread中使用一个全局的变量来获取当前的对象。

启十个进程,全往第一个里写:

concurrent = 10

Rate: 25 req/s

Rate: 119617 req/s

Rate: 130620 req/s

Rate: 144202 req/s

Rate: 120458 req/s

Rate: 112809 req/s

Rate: 120800 req/s

Rate: 122290 req/s

Rate: 119526 req/s

Rate: 111189 req/s

Rate: 112483 req/s

Rate: 109138 req/s

Rate: 115648 req/s

Rate: 119419 req/s

Rate: 105558 req/s

Rate: 110230 req/s

Rate: 116507 req/s

Rate: 105367 req/s

Rate: 103781 req/s

Rate: 106618 req/s

Rate: 107698 req/s

Rate: 116768 req/s

Rate: 107244 req/s

保持在10w/s的写入速度,到达30s左右以后,数据急转直下:

Rate: 48060 req/s

Rate: 6901 req/s

Rate: 4987 req/s

Rate: 46229 req/s

Rate: 46686 req/s

Rate: 45402 req/s

Rate: 6271 req/s

Rate: 810 req/s

Rate: 33895 req/s

Rate: 46548 req/s

Rate: 47025 req/s

Rate: 6995 req/s

Rate: 860 req/s

这,就是tc的table表在写入一个ArrayList的真实速度(4核8G)。

官方发言的100W只需要0.4s,说的是写入的hash表,而且数据是纯线性的数字。

提升速度和稳定的办法,和张宴兄弟商量,b+tree类型的数据稳定一些,设置tctdbsetxmsiz也能解决燃眉之急。

清华万博-精武门 Lamp环境内容回顾

精武门版权所有,复制请标明:http://www.54chen.com/c/809

第一部分:Linux基础

因为大多数同学没有任何基础,此课程不得不放慢脚步,但不要担心,所涉及到的东西都会在课程中反复讲解。

1.Linux指令:

1.1 SecureCRT连Linux接服务器后,默认进入自己的用户目录下。--/home/xxxx/

题外:

目录的概念:.(一个点)当前目录 ..(两个点)上一级目录 <以后不能再分不清楚这两个东西了哈>

相对目录和绝对目录:/home/zzz/相对于/home/来说就是zzz目录,就可以cd /home/后再cd zzz进入到/home/zzz (其中滋味要慢慢体会,只能体会,一定要体会清楚)

1.2 Linux命令行

命令[空格]参数1[空格]参数2[空格]。。。

2.常用命令:

cp a b --copy的简写 复制文件的意思,从a复制到b

mkdir xxx --make directory的简写,新建文件夹的意思,建立一个叫xxx的文件夹

ls --list的简写,显示当前文件夹下所有文件

精武门版权所有,复制请标明:http://www.54chen.com/c/809

第二部分:LAMP环境

2.1 编译程序中的三板斧:

configure 检测硬件,配置MakeFile文件

make 编译

make install 安装

2.2 apache编译示例

tar -zxvf 1.tar.gz  --解压源码包

cd httpd-2.2/ --进入解压出来的目录

./configure --prefix=/home/zz/apache

make && make install

2.3 nginx + fast-cgi环境

PHP编译安装:

tar zxvf php-5.2.10.tar.gz
gzip -cd php-5.2.10-fpm-0.5.11.diff.gz | patch -d php-5.2.10 -p1
cd php-5.2.10
****
./configure --prefix=/home/zhen.chen/php --with-config-file-path=/home/zhen.chen/php/etc --with-iconv-dir=/usr/local --with-freetype-dir --with-jpeg-dir --with-png-dir --with-zlib --with-libxml-dir=/usr --enable-xml --disable-rpath --enable-discard-path --enable-safe-mode --enable-bcmath --enable-shmop --enable-sysvsem --enable-inline-optimization --with-curl --with-curlwrappers --enable-mbregex --enable-fastcgi --enable-fpm --enable-force-cgi-redirect --enable-mbstring --with-gd --enable-gd-native-ttf --with-openssl --enable-pcntl --enable-sockets --with-ldap --with-ldap-sasl --without-pear

make && make install
=========================================================================================================
nginx编译安装:

tar -zxvf pcre-7.9.tar.gz
cd pcre-7.9
./configure
make && make install
====================
cd ..
tar zxvf nginx-0.7.61.tar.gz
cd nginx-0.7.61
./configure --user=www --group=www --prefix=/home/xxx/nginx --with-http_stub_status_module --with-http_ssl_module
make && make install
@@@@@@@@@@@@@@@@@@@@@@@@
增加www用户:
groupadd www
useradd -g www www

=========================================
nginx+php fast cgi配置

1. cp /home/zhen.chen/fcgi.conf /home/zzz/nginx/conf/
2. vi /home/zzzz/nginx/conf/nginx.conf
3.
 location ~ .*\.(php|php5)?$
    {
      #fastcgi_pass  unix:/tmp/php-cgi.sock;
      fastcgi_pass  127.0.0.1:9000;
      fastcgi_index index.php;
      include fcgi.conf;
    }
4.
sudo /home/zzz/nginx/sbin/nginx

精武门版权所有,复制请标明:http://www.54chen.com/c/809

科学院近年好文章总结

彻夜无眠,实在没啥想法,想想干脆把这些年自以为还可以的文章整理一下,给先来的后来的读者们送上一份大餐。

三月最受欢迎的十篇文章