2013年10月12日星期六

使用Imagemagick和Jmagick拼接图片并打水印

安装

注:本文参考系统:2.6.32-279.el6.x86_64, CentOS6.x
首先需要安装jpeg库和freetype库来支持imagemagick安装。
1. 安装libjpeg
2. 安装Imagemagick,执行configure
#>./configure --without-perl
执行之后查看configure结果
Shared libraries  --enable-shared=yes           yes
Static libraries  --enable-static=yes           yes
Module support    --with-modules=yes            yes
GNU ld            --with-gnu-ld=yes             yes
Quantum depth     --with-quantum-depth=16       16
High Dynamic Range Imagery
                  --enable-hdri=no              no

Delegate Configuration:
BZLIB             --with-bzlib=yes              no
DJVU              --with-djvu=no                no
DPS               --with-dps=yes                no
FlashPIX          --with-fpx=yes                no
FontConfig        --with-fontconfig=no          no
FreeType          --with-freetype=yes           yes
GhostPCL          None                          pcl6 (unknown)
GhostXPS          None                          gxps (unknown)
Ghostscript       None                          gs (8.70)
result_ghostscript_font_dir='none'
Ghostscript fonts --with-gs-font-dir=default
Ghostscript lib   --with-gslib=yes              no
Graphviz          --with-gvc=yes                no
JBIG              --with-jbig=yes               no
JPEG v1           --with-jpeg=yes               yes
JPEG-2000         --with-jp2=yes                no
LCMS              --with-lcms=yes               no
LQR               --with-lqr=no         no
Magick++          --with-magick-plus-plus=yes   yes
OpenEXR           --with-openexr=yes            no
PERL              --with-perl=no                no
PNG               --with-png=yes                no
RSVG              --with-rsvg=no                no
TIFF              --with-tiff=yes               no
result_windows_font_dir='none'
Windows fonts     --with-windows-font-dir=
WMF               --with-wmf=yes                no
X11               --with-x=                     no
XML               --with-xml=no         no
ZLIB              --with-zlib=yes               yes
发现JPEG和FreeType已经是yes
然后make && make install
此时可以使用命令测试:
#>montage test.jpg test1.jpg test2.jpg -tile 3X1 -geometry 480x360+0+0 output.jpg
如果出现:sh:gs not found 安装yum install ghostscript
3. 安装Jmagick-6.4.0
安装结束后,拷贝jmagick-6.4.0.jar到$JAVA_HOMT/jre/lib/ext下,将jmagick-6.4.0.so拷贝到$JAVA_HOME/jre/lib/amd64下
4. 执行java程序,拼接图片,发现会有fatal error出现:反复测试发现setGeometry之后获取getGeometry出现数据不一致。
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007f0d20471889, pid=11404, tid=139694626883328
#
# JRE version: 6.0_37-b06
# Java VM: Java HotSpot(TM) 64-Bit Server VM (20.12-b01 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C  [libMagickCore.so.1+0x131889]  imaginary long double+0x39
#
# An error report file with more information is saved as:
# /opt/deploy/papaq/papaq-pic/hs_err_pid11404.log
#
# If you would like to submit a bug report, please visit:
#   http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.


或

java: magick/montage.c:425: MontageImageList: Assertion `montage_info->signature == 0xabacadabUL' failed. 

此时需要查看JMagick源码,实现在src/magick/jmagick.h的setstringmethod,此处set值可能有问题,重写实现代码,实现类:src/magick/magick_Montage.c,重写方法:
setStringMethod(Java_magick_MontageInfo_getGeometry,
  geometry,
  "montageInfoHandle",
  MontageInfo)

JNIEXPORT void JNICALL Java_magick_MontageInfo_setGeometry
(JNIEnv *env, jobject self, jstring geometryValue)
{
    MontageInfo *montageInfo = NULL;
    const char *cstr = NULL;
    
    montageInfo = (MontageInfo*) getHandle(env, self,
                                           "montageInfoHandle", NULL);
    
    if (montageInfo == NULL) {
        throwMagickException(env, "Unable to obtain MontageInfo handle");
        return;
    }
    
    cstr = (*env)->GetStringUTFChars(env, geometryValue, 0);
    strcpy(montageInfo->geometry, cstr);
    (*env)->ReleaseStringUTFChars(env, geometryValue, cstr);

}
重新编译,替换之前的so文件之后再测试,测试通过;

2013年4月25日星期四

使用Git(GitLab)和Maven向Nexus发布Release

前置工具

Git配合GitLab;使用Nexus Sonatype管理本地maven仓库。

Maven主要命令

mvn release:prepare #设定本次版本信息和接下来的开发版本信息,并准备提交用到的一些jar文件。
mvn release:prepare -Dresume=false #重新开始prepare操作,忽略之前的release设置
mvn release:perform #发布release到maven仓库

Maven主要配置

<scm>
   <connection>scm:git:git@serverIp:root/project.git</connection>
   <url>scm:git:git@serverIp:root/project.git</url>
   <developerConnection>scm:git:git@serverIp:root/project.git</developerConnection>
</scm>
<plugins>
    <plugin>
       <groupId>org.apache.maven.plugins</groupId>
       <artifactId>maven-release-plugin</artifactId>
       <version>2.1</version>
    </plugin>
</plugins>
如果release中报Source files encoding not set的错误,还需要增加encoding的设置:
<properties>
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>

Git主要命令

git tag #查看本地的tag,release后会增加一个tag
git tag -d {tag_name} #删除tag
git push origin:refs/tags/{tag_name} #删除远程tag,先删除本地,在push到远端

Release成功后

GitLab上可以看到增加了一个xxx-1.0的tag。
本地代码的pom文件版本已经更新至下一版本,例如1.1-SNAPSHOT

2013年4月18日星期四

一致性Hash算法原理

算法介绍

consistent hash算法如图所示:首先将服务节点映射到一个0~2^32的圆上。例如server1~server3,hash(server1), hash(server2), hash(server3)
图1. 将server映射到圆上
然后将key值同样映射到圆上,并沿着顺时针查找第一个server节点,那么这个key值就会被保存到对应的server上。如图2.
图2.将key用同样的算法映射到圆上并寻找对应的server
如果添加或减少一个节点,响应会调整对应的节点和server的对应关系。如图3.
图3. 增加server4后,节点重新分布。
从图3看出,只有server4到server4之间的key会改变映射关系,key5会保存到server4.其他部分不会受到影响。

均匀分布

如图1-3, server在圆上的映射可能不是均匀的,这会导致有些节点映射的key比较多,有些则比较少。为了尽可能的均匀分布,我们引入了虚节点的概念。
所谓虚节点,就是将每个server在圆上映射多个hash值,例如server1,可以通过编号进行hash值映射计算:hash(server1#1),hash(server1#2)...hash(server1#n).一般每个server在圆上映射100-200个虚节点以后,key的分布会比较平均。
之前有一篇测试hash平均分布的文章,传送门

2013年3月26日星期二

jenkins使用git和sbt构建工程

简介

Jenkins, 以前叫做Hudson,是一款基于java的持续集成工具。

安装

安装非常简单,以RHEL6.x为例,直接下载jenkins的rpm安装文件,直接安装即可。
wget http://pkg.jenkins-ci.org/redhat-stable/jenkins-1.480.3-1.1.noarch.rpm
rpm -ivh jenkins-1.480.3-1.1.noarch.rpm
service jenkins start
jenkins的配置文件在/etc/sysconfig/jenkins,可以从/etc/init.d/jenkins中读取到。这个配置文件可以修改jenkins的端口等配置信息。

集成git

首先在系统管理-》插件管理中安装git插件。
测试使用的git管理平台是gitlab。首先生成公钥文件,将公钥私钥都拷贝到目录/var/lib/jenkins/.ssh。并在gitlab中上传公钥。然后执行:
sudo -u jenkins git ls-remote -h git@10.10.139.177:root/tongji-app.git HEAD
确保可以通过ssh key进行安全访问。
然后在系统管理-》系统设置中配置git

集成sbt

首先在系统管理-》插件管理中安装sbt插件。
然后在系统管理-》系统设置中配置sbt。

配置一个任务

新建一个job,在版本工具处选择git,并填写git的repository地址,git@xx.xx.xx.xx:ab.git
在sbt处配置sbt,并设置sbt任务,最后设置发布的shell脚本。
此处的sudo可能会报错,大概意思是jenkins这个用户没有sudo的权限。
编辑/etc/sudoers,增加jenkins的sudo执行权限:
jenkins    ALL = NOPASSWD: /opt/sh/release_jetty.sh

然后点击保存,选择左侧的构建项目。可以在构建项目的时候查看日志,这时发现jenkins做了几件事情:
1. 克隆或更新git repository代码;
2. 执行sbt package
3. 以root权限执行release_jetty.sh脚本
此时,发现服务器中的web服务已经启动成功。

2013年3月21日星期四

Git常用命令

设置git的用户名和邮箱

git config --global user.name "My Name"
git config --global user.email "my@email.com"

基础操作

git clone git@server:app.git myrepo //克隆工程
git pull //从远端库更新并合并代码
git fetch //从远端库获取代码
git merge //合并代码
git branch xx //新建分支
git checkout xx //切换到分支xx
git branch //查看分支列表
git branch -d xx //删除分支
git push origin local:remote //将本地的分支local提交到远端库的remote分支
git commit -m 'message' //提交代码
git add [.|file]//将 [所有|指定] 文件加入到版本控制中
git rm file //将文件删除版本控制

2013年3月19日星期二

在CentOS6.3上安装GitLab

本文主要参考了Install GitLab on CentOS 一文,并附加一些安装错误的解决方案。

GitLab简介

GitLab是一个用于仓库管理系统的开源项目,项目首页:http://gitlab.org/
使用Git作为版本控制工具,并在此基础上搭建起web服务。web服务使用的ruby on rails,并使用了gitolite协同工作。使用mysql和redis作为数据服务。

一键安装脚本

请访问:https://github.com/mattias-ohlsson/gitlab-installer/blob/master/gitlab-install-el6.sh 。本文并未使用一键安装脚本。由于自定义了mysql和redis,因此有些配置是自己手动实现的。

安装系统依赖

如果安装了redis,下面的脚本中就将redis去掉。
# yum -y install readline readline-devel ncurses-devel gdbm-devel glibc-devel tcl-devel openssl-devel curl-devel expat-devel db4-devel byacc sqlite-devel gcc-c++ libyaml libyaml-devel libffi libffi-devel libxml2 libxml2-devel libxslt libxslt-devel libicu libicu-devel system-config-firewall-tui python-devel redis mysql-devel postgresql-devel
请注意libicu-devel,请注意安装时是否成功安装,如果不成功,将会在后面的安装过程出现错误,安装失败请手动安装libicu-devel

安装Ruby

先安装qt
# yum install qt-devel qtwebkit-devel -y
查看系统中ruby的版本,gitlab需要ruby至少是1.9.3
# curl -O http://ftp.ruby-lang.org/pub/ruby/1.9/ruby-1.9.3-p0.tar.gz  
# tar xzvf ruby-1.9.3-p0.tar.gz  
# cd ruby-1.9.3-p0

# ./configure --disable-install-doc

更新gem&安装rails

可以先更新一下gem,再安装rails
# gem update --system  
# gem update  
# gem install rails

安装gitolite

创建git和gitlab用户,并加入组
# adduser --system --shell /bin/bash --comment 'gitolite' --create-home --home-dir /home/git git
# adduser --shell /bin/bash --create-home --home-dir /home/gitlab gitlab
# usermod -a -G git gitlab
# usermod -a -G gitlab git
# sudo -H -u gitlab ssh-keygen -q -N '' -t rsa -f /home/gitlab/.ssh/id_rsa
# cp /home/gitlab/.ssh/id_rsa.pub /home/git/gitlab.pub
# chmod 0444 /home/git/gitlab.pub
安装gitolite
sudo -H -u git git clone -b gl-v304 https://github.com/gitlabhq/gitolite.git /home/git/gitolite
切换到git用户
su git
$ cd /home/git
$ git clone -b gl-v304 https://github.com/gitlabhq/gitolite.git /home/git/gitolite
$ mkdir bin
$ gitolite/install -ln /home/git/bin
$ bin/gitolite setup -pk /home/git/gitlab.pub

修正权限

# chmod -R g+rwX /home/git/repositories/
# chown -R git:git /home/git/repositories/
# chmod 750 /home/git
检查权限是否生效:
# sudo -u gitlab -H git clone git@localhost:gitolite-admin.git /tmp/gitolite-admin

安装pygments和bundle

# easy_install pip  
# pip install pygments  
# gem install bundler

安装补充依赖

# gem install ruby-debug19
# gem install charlock_holmes

安装gitlabhq

在gitlab用户下安装
# su gitlab
$ cd /home/gitlab
$ git clone -b stable https://github.com/gitlabhq/gitlabhq.git gitlab
修改配置
请注意:三个文件的配置需要根据自身修改。比如database.yml指定了mysql服务的配置信息。gitlab中指定了host,port,repositories目录等信息,需要一一修改。
$ cd /home/gitlab/gitlab/config
$ cp gitlab.yml.example gitlab.yml
$ cp database.yml.mysql database.yml
$ cp unicorn.rb.example unicorn.rb
再安装一些依赖
# cd /home/gitlab/gitlab
# sudo -u gitlab -H bundle install --without development test sqlite postgres  --deployment

配置gitlab的git用户信息

# sudo -u gitlab -H git config --global user.email "gitlab@localhost"
# sudo -u gitlab -H git config --global user.name "Gitlab"

安装,初始化程序

注意,此时需要有一个mysql的服务,并在database.yml中配置好用户名和密码。
如果没有安装mysql,可以执行:
# yum install mysql-client mysql-server
# sudo gitlab
$ cd /home/gitlab/gitlab
$ RAILS_ENV=production rake db:setup
$ RAILS_ENV=production rake db:seed_fu  

运行一下看看:)

$ nohup bundle exec rails s -e production > /home/gitlab/gitlab.log 2>&1 &
访问地址:
http://127.0.0.1:3000

默认的管理员密码

user: admin@local.host
pass: 5iveL!fe

配置nginx

注意,需要修改nginx的启动用户:
#user              nginx;
user              gitlab root;

启动脚本


放入/etc/init.d并启动服务:
# curl --output /etc/init.d/gitlabhq https://github.com/gitlabhq/gitlab-recipes/blob/master/init.d/gitlab-centos
# chmod 755 /etc/init.d/gitlabhq
# service gitlabhq start
如果出现以下信息表示启动成功:
Starting unicorn:                                          [  OK  ]
Starting sidekiq:                                          [  OK  ]
注意:gitlab.socket此时才在指定目录出现,而以上面的测试方式启动在3000端口的服务是无法获得unix的socket的。此时使用脚本启动完成后,nginx的配置也会生效。
如果访问nginx proxy的地址后,出现css加载失败的情况,请执行下面命令后重启gitlab。
# bundle exec rake assets:precompile RAILS_ENV=production
之前曾经出现过ssh_key校验失败的错误,现在也没有复现了,考虑可能和更改使用socket方式有关,或者是因为执行了下面这条命令,具体原因无法分析了。
# bundle exec rake gitlab:enable_namespaces RAILS_ENV=production 
使用merge requests中出现错误提示:This repository does not have satellite. Ask administrator to fix this issue  需要执行下面的命令:
# bundle exec rake environment gitlab:enable_automerge RAILS_ENV=production
执行中如果出现错误:
Updating repo permissions ...
... done

Creating satellites for ...
Administrator / tongji-app ... 
rake aborted!
No such file or directory - chdir
需要手动创建目录
# mkdir /home/gitlab/gitlab-satellites

2013年2月18日星期一

iPhone越狱后常用软件

1. 安装Openssh,在cydia中搜索安装即可;
2. 安装MobileTerminal,打开后可以修改root密码,默认密码是alpine
3. 安装cydelete,会自动安装curl和apt-get,这样缺少什么命令就可以安装了
4. 安装appsync,可以直接安装ipa包
5. 安装sbsettings组件,可以方便的通过顶部横栏呼出设定窗口,设置飞行模式,3G,wifi等的开关;
6. 搜狗输入法
7. bitesms,方便在锁屏界面直接回复短信。随着微信的发展,短信发的越来越少了。

2013年2月16日星期六

Sbt从Sonatype中获取依赖和向Sonatype发布jar

获取依赖

在build.sbt中添加:
resolvers += "Sonatype OSS Snapshots" at "https://oss.sonatype.org/content/repositories/snapshots"
向Sonatype发布jar
官方文档
publishTo <<= version { v: String =>
  val nexus = "https://oss.sonatype.org/"
  if (v.trim.endsWith("SNAPSHOT"))
    Some("snapshots" at nexus + "content/repositories/snapshots")
  else
    Some("releases" at nexus + "service/local/staging/deploy/maven2")
}

publishMavenStyle := true

publishArtifact in Test := false

pomIncludeRepository := { _ => false }

pomExtra := (
  <url>http://your.project.url</url>
  <licenses>
    <license>
      <name>BSD-style</name>
      <url>http://www.opensource.org/licenses/bsd-license.php</url>
      <distribution>repo</distribution>
    </license>
  </licenses>
  <scm>
    <url>git@github.com:your-account/your-project.git</url>
    <connection>scm:git:git@github.com:your-account/your-project.git</connection>
  </scm>
  <developers>
    <developer>
      <id>you</id>
      <name>Your Name</name>
      <url>http://your.url</url>
    </developer>
  </developers>
)

HTTPS(SSL)原理

SSL        

        SSL是由Netscape公司提出的安全协议,利用数据加密、身份验证和消息完整性验证为网络中传输的数据提供安全性保证。

数据传输的机密性

        对称加密算法:加密解密使用同样的密钥,常用算法:RC2、RC4、IDEA、DES、Triple DES、AES以及Camellia;
        非对称加密算法:加密解密使用不同的密钥,其中一个是公开的密钥,用来加密。另外一个是私有的私钥,用于解密。常用算法:RSA、Diffie-Hellman、DSA及Fortezza
        单向散列函数:用于计算消息的特征值,例如MD5,SHA1,SHA256

利用PKI保证公钥的真实性

        PKI通过数字证书来发布用户的公钥,并提供了验证公钥真实性的机制。数字证书(简称证书)是一个包含用户的公钥及其身份信息的文件,证明了用户与公钥的关联。数字证书由权威机构——CA签发,并由CA保证数字证书的真实性。

利用非对称加密保证密钥本身的安全

        SSL利用非对称密钥算法加密密钥的方法实现密钥交换,保证第三方无法获取该密钥。

消息完整性

        为了避免网络中传输的数据被非法篡改,SSL利用基于MD5或SHA的MAC算法来保证消息的完整性。
        如图,消息的任何改变,都会引起输出的固定长度数据产生变化。通过比较MAC值,可以保证接收者能够发现消息的改变。
        MAC算法需要密钥的参与,因此没有密钥的非法用户在改变消息的内容后,无法添加正确的MAC值,从而保证非法用户无法随意修改消息内容。

SSL分层结构

  1. SSL握手协议:是SSL协议非常重要的组成部分,用来协商通信过程中使用的加密套件(加密算法、密钥交换算法和MAC算法等)、在服务器和客户端之间安全地交换密钥、实现服务器和客户端的身份验证。
  2. SSL密码变化协议:客户端和服务器端通过密码变化协议通知对端,随后的报文都将使用新协商的加密套件和密钥进行保护和传输。
  3. SSL警告协议:用来向通信对端报告告警信息,消息中包含告警的严重级别和描述。
  4. SSL记录协议:主要负责对上层的数据(SSL握手协议、SSL密码变化协议、SSL警告协议和应用层协议报文)进行分块、计算并添加MAC值、加密,并把处理后的记录块传输给对端。

SSL的握手过程

图:只认证服务器SSL的握手过程
  1. SSL客户端通过Client Hello消息将它支持的SSL版本、加密算法、密钥交换算法、MAC算法等信息发送给SSL服务器。
  2. SSL服务器确定本次通信采用的SSL版本和加密套件,并通过Server Hello消息通知给SSL客户端。如果SSL服务器允许SSL客户端在以后的通信中重用本次会话,则SSL服务器会为本次会话分配会话ID,并通过Server Hello消息发送给SSL客户端。
  3. SSL服务器将携带自己公钥信息的数字证书通过Certificate消息发送给SSL客户端。
  4. SSL服务器发送Server Hello Done消息,通知SSL客户端版本和加密套件协商结束,开始进行密钥交换。
  5. SSL客户端验证SSL服务器的证书合法后,利用证书中的公钥加密SSL客户端随机生成的premaster secret,并通过Client Key Exchange消息发送给SSL服务器。
  6. SSL客户端发送Change Cipher Spec消息,通知SSL服务器后续报文将采用协商好的密钥和加密套件进行加密和MAC计算。
  7. SSL客户端计算已交互的握手消息(除Change Cipher Spec消息外所有已交互的消息)的Hash值,利用协商好的密钥和加密套件处理Hash值(计算并添加MAC值、加密等),并通过Finished消息发送给SSL服务器。SSL服务器利用同样的方法计算已交互的握手消息的Hash值,并与Finished消息的解密结果比较,如果二者相同,且MAC值验证成功,则证明密钥和加密套件协商成功。
  8. 同样地,SSL服务器发送Change Cipher Spec消息,通知SSL客户端后续报文将采用协商好的密钥和加密套件进行加密和MAC计算。
  9. SSL服务器计算已交互的握手消息的Hash值,利用协商好的密钥和加密套件处理Hash值(计算并添加MAC值、加密等),并通过Finished消息发送给SSL客户端。SSL客户端利用同样的方法计算已交互的握手消息的Hash值,并与Finished消息的解密结果比较,如果二者相同,且MAC值验证成功,则证明密钥和加密套件协商成功。



2013年2月7日星期四

KAFKA在统计系统中的应用

Kafka

kafka是LinkedIn开源的一款分布式的发布-订阅消息系统,它具有:
1. 通过O(1)的磁盘结构持久化存储消息,即使TB级的数据也能保持长期稳定;
2. 高吞吐率:即使非常普通的硬件,kafka也能支持每秒数十万的消息;
3. 支持通过kafka服务器和消费集群来分区消息;
4. 支持Hadoop并行加载;

设计流程

通过集成kafka和log4j在各个需要采集日志的系统进行日志采集,日志统一发送到kafka的消息队列。再通过定时运行kafka-hadoop的作业,将数据从KAFKA同步到hadoop的HDFS中。hadoop的各类map-reduce作业可以对数据进行统计,存储到db或缓存中。

安装

首先安装kafka,下载kafka到本地,然后执行:
> tar xzf kafka-<VERSION>.tgz
> cd kafka-<VERSION>
> ./sbt update
> ./sbt package
启动zookeeper
> bin/zookeeper-server-start.sh config/zookeeper.properties
[2010-11-21 23:45:02,335] INFO Reading configuration from: config/zookeeper.properties...
启动kafka
> bin/kafka-server-start.sh config/server.properties
jkreps-mn-2:kafka-trunk jkreps$ bin/kafka-server-start.sh config/server.properties 
[2010-11-21 23:51:39,608] INFO starting log cleaner every 60000 ms (kafka.log.LogManager)
[2010-11-21 23:51:39,628] INFO connecting to ZK: localhost:2181 (kafka.server.KafkaZooKeeper)...
发送一些消息
> bin/kafka-console-producer.sh --zookeeper localhost:2181 --topic test 
This is a message
This is another message
查看消息
> bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic test --from-beginning
This is a message
This is another message
至此,kafka已经启动成功。

安装hadoop,下载hadoop0.20.2,按照hadoop的操作手册安装,此处省略安装过程。

配置log4j和kafka-log

#配置KAFKA
#Hostname表示应用的名称
#Topic表示打印日志生成的目录名
log4j.appender.KAFKA=com.comp.kafka.AsyncKafkaAppender
log4j.appender.KAFKA.topic=TOPIC
log4j.appender.KAFKA.bufferSize = 10
log4j.appender.KAFKA.brokerList=0:kafka-server-ip:9092
log4j.appender.KAFKA.serializerClass=kafka.serializer.StringEncoder
log4j.appender.KAFKA.hostname=APP-NAME
log4j.appender.KAFKA.layout=org.apache.log4j.PatternLayout
log4j.appender.KAFKA.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n
log4j.logger.com.comp= DEBUG, KAFKA
配置中,配置了kafka的ip和端口,并设置了topic和序列化类和pattern。
AsyncKafkaAppender是继承了log4j的AsyncAppender,是log4j异步发送日志的模式,当log达到bufferSize的大小时,会统一由log4j异步执行打印操作。代码如下:
public class AsyncKafkaAppender extends AsyncAppender {
    private java.lang.String topic;
    private java.lang.String serializerClass;
    private java.lang.String zkConnect;
    private java.lang.String brokerList;
    private java.lang.String hostname;

    public String getTopic() {
        return topic;
    }

    public void setTopic(String topic) {
        this.topic = topic;
    }

    public String getSerializerClass() {
        return serializerClass;
    }

    public void setSerializerClass(String serializerClass) {
        this.serializerClass = serializerClass;
    }

    public String getZkConnect() {
        return zkConnect;
    }

    public void setZkConnect(String zkConnect) {
        this.zkConnect = zkConnect;
    }

    public String getBrokerList() {
        return brokerList;
    }

    public void setBrokerList(String brokerList) {
        this.brokerList = brokerList;
    }

    public String getHostname() {
        return hostname;
    }

    public void setHostname(String hostname) {
        this.hostname = hostname;
    }
    @Override
    public void activateOptions() {
        super.activateOptions();
        synchronized (this) {
            KafkaLog4jAppender kafka = new KafkaLog4jAppender();
            kafka.setLayout(getLayout());
            kafka.setHostname(getHostname());
            kafka.setBrokerList(getBrokerList());
            kafka.setSerializerClass(getSerializerClass());
            kafka.setZkConnect(getZkConnect());
            kafka.setTopic(getTopic());
            kafka.activateOptions();
            addAppender(kafka);
        }
    }

    @Override
    public boolean requiresLayout() {
        return true;
    }
}
这时我们就可以撰写一个测试代码,测试log是否已经发送到了kafka。

KAFKA消息发送到Hadoop

在kafka的contrib目录的hadoop-consumer中有一系列的文件,包括脚本,jar,配置文件等。我们可以直接使用这个目录下的脚本进行定时数据同步。
需要先修改test目录下的test.properties:
# kafka的topic名称
kafka.etl.topic=TOPIC

# hdfs location of jars
hdfs.default.classpath.dir=/tmp/kafka/lib

# number of test events to be generated
event.count=1000

# hadoop id and group
hadoop.job.ugi=kafka,hadoop

# kafka server uri
kafka.server.uri=tcp://localhost:9092

# hdfs location of input directory
input=hdfs://localhost:9000/tmp/kafka/data

# hdfs location of output directory
output=hdfs://localhost:9000/tmp/kafka/output

# limit the number of events to be fetched;
# value -1 means no limitation
kafka.request.limit=-1

# kafka parameters
client.buffer.size=1048576
client.so.timeout=60000
修改topic名称以及对应hadoop的input,output目录。
首先生成offset,执行:
./run-class.sh kafka.etl.impl.DataGenerator test/test.properties
然后拷贝依赖的jar文件:
./copy-jars.sh ${hdfs.default.classpath.dir}
最后执行hadoop任务:
./run-class.sh kafka.etl.impl.SimpleKafkaETLJob test/test.properties
执行完成后,运行hadoop脚本查看是否已经在output目录生成数据:
bin/hadoop fs -cat /tmp/kafka/output/part-00000 | wc -l
至此,从日志从各个系统已经成功收集到hadoop的HDFS文件系统中。
现在只需要撰写一些map-reduce作业,就可以利用hadoop进行数据统计了。

KAFKA消息清除

# The minimum age of a log file to be eligible for deletion
log.retention.hours=168
# The maximum size of a log segment file. When this size is reached a new log segment will be created.
log.file.size=536870912
在配置中,如果一个log file距离上一次写入时间达到168小时,也就是一周,会自动清除这个日志文件;日志文件的上限大小是536870912,超过这个大小会创建新的日志文件。

2013年1月22日星期二

MAC下清除DNS缓存的方法

想清除被污染的DNS,在MAC下使用:
sudo killall -HUP mDNSResponder [Lion&MountainLion]
sudo dscacheutil -flushcache 10.6及以前的用户

2013年1月15日星期二

在Ubuntu12.04上安装scribe

        Scribe是Facebook开源的一个日志收集系统,它能够从各种数据源收集日志,并存储到一个中央存储系统。它的原理图如下:
安装它不是一个很容易的事情,首先它依赖于Thrift,而Thrift又有很多的依赖。

前置依赖

Thrift版本<0.4.0; boost版本1.4.5;gcc,g++版本4.4;

安装Thrift

首先安装前置依赖:
sudo apt-get install libevent-dev automake libtool flex bison pkg-config g++ libssl-dev 
需要java依赖的还需要安装java:
sudo apt-get install openjdk-6-jdk ant ivy
首先进入到thrift目录,安装:
sudo ./configure --prefix=/opt/thrift
sudo make & make install
然后进入thrift目录下的contrib/fb303,
sudo ./bootstrap.sh
sudo ./configure --prefix=/opt/fb303 --with-thriftpath=/opt/thrift
sudo make & make install
如果一切顺利的话,thrift就安装完了。

安装scribe

首先,需要保证你的系统的boost库是1.4.5的,去boost网站下载1.4.5版本的源码,下载地址
解压缩,进入到boost目录,然后执行
sudo ./bootstrap.sh
sudo ./bjam
sudo ./bjam install
好,此时可以切到目录/usr/local/lib grep一下boost,看看版本是否是1.4.5
然后修改g++编译器的版本,
g++ --version
先查看本地g++版本,如果>4.4,则执行:
sudo apt-get remove g++
sudo apt-get install g++-4.4
cd /usr/bin
sudo ln -s g++-4.4 g++
此时再执行:

g++ --version

发现已经是4.4.3版本。然后解压缩scribe源码包,进入目录scribe-master
执行:
sudo ./bootstrap.sh
sudo ./configure --with-thriftpath=/opt/thrift --with-fb303path=/opt/fb303
sudo make & make install

安装完成执行scribed,发现已经安装完成。

2013年1月10日星期四

intellijIDEA常用快捷键备忘录(MAC)

⌘+/ 注销当前行
⌘+X 剪切当前行或当前选中代码
⌘+D 复制当前行
⌘+N 查找类
ctrl+N 在pom中查找依赖
alt+enter 查找类依赖,类似eclipse中的alt+/
⌘+alt+L 格式化代码
⌘+alt+O 优化导入的类包代码
alt+shift+up/down 代码上移或下移一行
⌘+shift+up/down 光标处的代码逻辑块整体上移或下移
fn+F3 选中单词的情况下查找下一个相同的单词
ctrl+shift+/ 注释/取消注释 选中的代码块
⌘+alt+B 查看接口或方法的实现,如果只有一个实现,直接打开实现类或方法。
shift+enter 开始新的一行
ctrl+J 查看方法说明
⌘+alt+V 从粘贴历史里选择一个进行粘贴
⌘+Z 取消当前一个操作
⌘+shift+Z 恢复取消当前一个操作,⌘+Z的逆向
⌘+R 查找替换
ctrl+shfit+F 全项目搜索
⌘+delete 删除当前行

os10.5以上的系统需要在preference中选择keymap,选择Mac OSX 10.5以上
MAC OS X 快捷键大全