2016年2月29日星期一

Linux_103:常用命令之三十:wget

环境:OS X EI Capitan 10.11.3

基本用法:wget url,例如:wget http://maping930883.blogspot.com


参数说明:
(1)-e 指定代理
例如:-e "http_proxy=http://squid.rdu.redhat.com:3128/"
(2)-k 转换链接,将下载的HTML页面中的链接转换为相对链接,即本地链接。
(3)-c 断点续传
(4)-p  下载所有的图片等页面显示所需的内容。

(5)-np  下载的页面不越过指定的URL。
(6)-m  整站下载。
(6)-r 递归下载。

Jenkins_004:安装与配置 github

环境:OS X EI Capitan 10.11.3 + JDK 1.7.0_80 + Maven 3.3.9 + Ant 1.9.6 + Jenkins 1.650 + svnserve  1.7.19 + svn 1.7.19

1. 安装插件
点击 Manage Plugins,在 Available 中输入过滤条件:github。
选择安装 Github Authentication plugin。
点击 Install without restart,这时会从网络下载插件以及依赖的插件。
安装完毕后,重启Jenkins。
如果安装正确,会看到系统配置中多了 Git,这里保持默认配置就可以。



2. 在 github 上创建仓库:my-site
创建成功后,查看 https://github.com/maping/my-site

3. 在 git client 端创建 Maven 应用
以下操作在 Maping 用户下进行,如果不是 Maping 用户,请使用 su - maping 切换。
(1)$ cd /Users/maping/mygit
(2)$ mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-site -Dorg.apache.maven.archetypes:maven-archetype-site -Dversion=1.0-SNAPSHOT -DinteractiveMode=false
(3)$ git init
(4)$ git add *
(5)$ git commit -m "initial commit"
(6)$ git remote add origin git@github.com:maping/my-site.git
(7)$ git push origin master

4. 在 jenkins 中配置 Git plugin

 

5. 在 jenkins 中创建任务
(1)配置 git Repository URL,这里 Credentials 设置为none。

(2)配置 Build Triggers

6. 修改并提交代码,1分钟后 jenkins 发现代码改动,开始自动 Build
以下操作在 Maping 用户下进行,如果不是 Maping 用户,请使用 su - maping 切换。
(1)$ cd /Users/maping/mygit/my-site
(2)$ vim src/main/java/com/mycompany/app/App.java
(3)$ git add .
(4)$ git commit -m "test"
(5)$ git push origin master


Jenkins_003:安装与配置 git

环境:OS X EI Capitan 10.11.3 + JDK 1.7.0_80 + Maven 3.3.9 + Ant 1.9.6 + Jenkins 1.650 + svnserve  1.7.19 + svn 1.7.19

1. 安装插件
Jenkins 默认没有安装 git 插件,需要手工安装。
点击 Manage Plugins,在 Available 中输入过滤条件:git。
选择安装 Git plugin 和 Git Parameter Plug-In。
点击 Install without restart,这时会从网络下载插件以及依赖的插件。



安装完毕后,重启Jenkins。
如果安装正确,会看到系统配置中多了 Git,这里保持默认配置就可以。



2. 在 git server 端创建仓库
 以下操作在 Maping 用户下进行,如果不是 Maping 用户,请使用 su - maping 切换。
(1)$ mkdir -p /Users/maping/git/repositories/local/my-quickstart.git
(2)$ cd /Users/maping/git/repositories/local/my-quickstart.git
(3)$ it init --bare
(4)$ cd ..
(5)$ chmod -R 777 my-quickstart.git
这里使用的 git 服务器是《MAC_041:使用 ssh 搭建本地 git 服务器》 。

3. 在 git client 端创建 Maven 应用
 以下操作在 Dove 用户下进行,如果不是 Dove 用户,请使用 su - dove 切换。
(1)$ cd /Users/dove/mygit
(2)$ mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-quickstart -Dorg.apache.maven.archetypes:maven-archetype-quickstart -Dversion=1.0-SNAPSHOT -DinteractiveMode=false
(3)cd my-quickstart
(4)$ git init
(5)$ git add *
(6)$ git commit -m "initial commit"
(7)$ git remote add origin dove@MaPingdeMacBook-Pro.local:/Users/maping/git/repositories/local/my-quickstart.git
(8)$ git push origin master

4. 在 jenkins 中创建任务
(1)配置 git 用户 dove 的私钥



(2)配置 git Repository URL 和 Credentials,这里 Credentials 要选择上一步配置的dove私钥。


(3)配置 Build Triggers


5. 修改并提交代码,1分钟后 jenkins 发现代码改动,开始自动 Build。
 以下操作在 Dove 用户下进行,如果不是 Dove 用户,请使用 su - dove 切换。
(1)$ cd /Users/dove/mygit/my-quickstart
(2)$ vim src/main/java/com/mycompany/app/App.java
(3)$ git add .
(4)$ git commit -m "test"
(5)$ git push --set-upstream origin master

6. 其它 git client 端
以下操作在 Maping 用户下进行,如果不是 Maping 用户,请使用 su - maping 切换。
(1)cd /Users/maping/mygit/
(2)git clone dove@MaPingdeMacBook-Pro.local:/Users/maping/git/repositories/local/my-quickstart.git
(3)cd my-quickstart
(4)git pull origin master
获取提交更改后的项目代码。

2016年2月28日星期日

ActiveMQ_017:单机环境下在四节点 Broker 集群 + 高可用情况下使用 Virtual Topic

环境:OS X EI Capitan 10.11.3 + ActiveMQ 5.13

首先参照《单机环境下配置四节点 Broker 集群 + 高可用》一文配置并启动四个Broker节点。

1. 客户端Producer向 Broker1/Broker2(Master/Slave)上发5条消息
代码片段:
(1)"failover:(tcp://127.0.0.1:61617,tcp://127.0.0.1:61618)");
(2)destination = session.createTopic("VirtualTopic.Orders");
访问 http://localhost:8162/admin/topics.jsp,可以看到 VirtualTopic.Orders 已被创建。
访问 http://localhost:8164/admin/topics.jsp,没有看到 VirtualTopic.Orders 。
说明 VirtualTopic 只在客户端连接的 Broker 中可见。

2. 客户端Consumer A 从 Broker1/Broker2(Master/Slave)上收消息
代码片段:
(1)"failover:(tcp://127.0.0.1:61617,tcp://127.0.0.1:61618)");
(2)Destination destinationA = session.createQueue("Consumer.A.VirtualTopic.Orders");
访问 http://localhost:8162/admin/queues.jsp,可以看到 Consumer.A.VirtualTopic.Orders 已被创建。
访问 http://localhost:8164/admin/queues.jsp,可以看到 Consumer.A.VirtualTopic.Orders 已被创建。
说明 Consumer.A.VirtualTopic.Orders 在组成集群的 Broker 中都可见。
但是之前发送到 VirtualTopic.Orders的消息无法收到,这是Topic 固有的特性决定的。

3. 客户端Consumer B 向 Broker3/Broker4(Master/Slave)上收消息
代码片段:
(1)"failover:(tcp://127.0.0.1:61619,tcp://127.0.0.1:61620)");
(2)Destination destinationB = session.createQueue("Consumer.B.VirtualTopic.Orders");
访问 http://localhost:8162/admin/queues.jsp,可以看到 Consumer.B.VirtualTopic.Orders 已被创建。
访问 http://localhost:8164/admin/queues.jsp,可以看到 Consumer.B.VirtualTopic.Orders 已被创建。
说明 Consumer.B.VirtualTopic.Orders 在组成集群的 Broker 中都可见。
但是之前发送到 VirtualTopic.Orders的消息无法收到,这是Topic 固有的特性决定的。

4. 客户端Producer向 Broker1/Broker2(Master/Slave)再发5条消息
代码片段:
(1)"failover:(tcp://127.0.0.1:61617,tcp://127.0.0.1:61618)");
(2)destination = session.createTopic("VirtualTopic.Orders");
访问 http://localhost:8162/admin/queues.jsp,可以看到 Consumer.A.VirtualTopic.Orders 和 Consumer.B.VirtualTopic.Orders 都消费了 5 条消息。

访问 http://localhost:8164/admin/queues.jsp,可以看到 Consumer.A.VirtualTopic.Orders 上没有消息消费,Consumer.B.VirtualTopic.Orders 消费了 5 条消息。


5. 小结
(1)与 VirtualTopic 对应的 Queue 在集群中所有 Broker 可见,并且是所有消费者共享同一个 Queue 中的消息。
(2)VirtualTopic.Orders 是在Broker1/Broker2(Master/Slave)中的,因此在Broker1/Broker2中能看到所有与这个VirtualTopic 对应的 Queue,无论消费者在哪里消费这些 Queue 。
(3)其它消费者,只能在连接到的Broker上看到自己的 Queue 中消费了消息,虽然在该 Broker 上也能看到其它的 Queue,但是不能看到其它的 Queue 消费了消息。
(4)如果本地和远程的 Consumer 都消费同一个 Queue,本地的 Consumer 优先消费。
(5)VirtualTopic 适合用在某个数据中心向其它数据中心分发消息的场景,每个数据中心消费自己的Queue,互不干扰。

2016年2月26日星期五

MAC_041:使用 ssh 搭建本地 git 服务器

环境:OS X EI Capitan 10.11.3 + git 2.3.2

MAC 默认安装了git,使用git --version可以查看git版本。

1. 创建一个新用户,作为 git 客户端用户
 
2. 允许使用 ssh 远程登录到本机
这里只允许 Dove 用户远程登录到本机。


以下操作在 Dove 用户下进行,如果不是 Dove 用户,请使用 su - dove 切换。
(1)$ ssh-keygen
创建公私钥对,默认一路回车即可。
(2)$ scp ~/.ssh/id_rsa.pub dove@MaPingdeMacBook-Pro.local:.ssh/authorized_keys
(3)$ ssh dove@MaPingdeMacBook-Pro.local
如果前面的步骤都正确的话,此步应该不在提示输入 dove 的口令而直接登入。

3. 在服务器上创建 git 仓库并初始化
(1)$ mkdir -p /Users/maping/git/repositories/local/newrepo.git
(2)$ cd /Users/maping/git/repositories/local/newrepo.git
(3)$ git init --bare
创建一个裸仓库,之所以叫裸仓库是因为这个仓库只保存 git 历史提交的版本信息,而不允许用户在上面进行各种 git 操作,即不允许作为本地 git 仓库使用。
(4)$ cd ..
(5)$ chmod -R 777 newrepo.git

4.  使用 Dove 用户 git clone 服务器上的 git 仓库
以下操作在 Dove 用户下进行,如果不是 Dove 用户,请使用 su - dove 切换。
(1)$ mkdir -p /Users/dove/mygit/newrepo
(2)$ cd /Users/dove/mygit/newrepo
(3)$ git init
(4)$ touch readme.txt
(5)$ git add readme.txt
(6)$ git commit -m "initial commit"
(7)$ git remote add origin dove@MaPingdeMacBook-Pro.local:/Users/maping/git/repositories/local/newrepo.git
将本地 git 库和远程 git 库关联在一起。
(8)$ git push origin master
把本地 master 分支的最新修改推送至远程 origin 分支。
(9)$ touch 1.txt
(10)$ git add 1.txt
(11)$ git commit -m "test commit"
(12)$ git push origin master
把本地 master 分支的最新修改推送至远程 origin 分支。

5.  使用 Maping 用户 git clone 服务器上的 git 仓库
以下操作在 Maping 用户下进行,如果不是 Maping 用户,请使用 su - maping 切换。
(1)cd /Users/maping/mygit/
(2)git clone dove@MaPingdeMacBook-Pro.local:/Users/maping/git/repositories/local/newrepo.git
(3)cd newrepo
可以看到之前 Dove 用户提交的 readme.txt 和 1.txt 文件。
(4)git pull origin master
(5)$ touch 2.txt
(6)$ git add 2.txt
(7)$ git commit -m "add 2.txt"
(8)$ git push origin master
把本地 master 分支的最新修改推送至远程 origin 分支。

5.  使用 Dove 用户 git pull 提交到服务器上的修改内容
以下操作在 Dove 用户下进行,如果不是 Dove 用户,请使用 su - dove 切换。 
(1)$ cd /Users/dove/mygit/newrepo
(2)$ git pull origin master
可以看到之前 Maping 用户提交的 2.txt 文件。

参考文献:
1. http://blog.csdn.net/liuyuyefz/article/details/17025709
2. http://blog.csdn.net/liuyuyefz/article/details/17025905
3. http://blog.smitec.net/posts/setting-up-a-git-server-on-osx/

Git_013:删除 github 上的repository

1.  找到要删除的repository

2.  点击Settings

3.  拉到下面

4.  手工输入repository,确认删除


整的这么复杂,就是怕你误操作删除整个repository,用心良苦啊。

Jenkins_002:创建任务

环境:OS X EI Capitan 10.11.3 + JDK 1.7.0_80 + Maven 3.3.9 + Ant 1.9.6 + Jenkins 1.650 + svnserve  1.7.19 + svn 1.7.19

1. 创建项目
 这里选择 Maven Project。

2. 配置项目

(1)Source Code Management
选择Subversion,然后输入Repository URL,注意,第一次输入时,会提示没有权限访问。
注意这里使用了 MAC 本地的 svn 服务器,关于如何搭建 svn 服务器,请参考《MAC_040:搭建本地 svn 服务器》 。
启动本地 svn server:$ svnserve -d -r /Users/maping/svn/repositories
点击 enter credential 后,输入 svn 的账户和口令:maping/maping。
输入以后,enter credential 链接就没有了,所以一定要一次输入正确。
也就是说,svn 的账户和口令设置以后是没有办法在界面修改的。
如果要修改,需要删除 ~/.jenkins/hudson.scm.SubversionSCM.xml 文件(我没试过)。

(2)Build Triggers
选择 Poll SCM,* * * * * 表示一分钟去检查一次代码有没有改动,如果有改动,Build代码。
Build periodically 的语法和 Poll SCM 一样,只不过它不管代码有没有改动,只要到了时间就Build。
(3)Build
 

3. 测试
修改代码,并提交:svn commit . -m test。
或者使用 Netbeans 连接到 svn 仓库,然后修改代码,提交。


大约一分钟后,Jenkins 检测到代码发生变化,开始自动 Build。
 

Jenkins_001:安装与系统配置

环境:OS X EI Capitan 10.11.3 + JDK 1.7.0_80 + Maven 3.3.9 + Ant 1.9.6 + Jenkins 1.650 + svnserve  1.7.19 + svn 1.7.19

1. 下载
下载地址:http://jenkins-ci.org/,选择下载war文件:jenkins.war。

2. 启动
java -jar jenkins.war --httpPort=8082
登录用户:maping/maping

3. 系统管理 -> 系统配置
访问 http://localhost:8082/

(1)JDK
 (2)Ant
 (3)Maven
 (4)Jenkins Location
  (5)Subversion
  (6)E-mail Notification
在 Test e-mail recipient 输入 maping1208@163.com,点击 Test Configuration,如果发送成功,会显示 Email was successfully sent。
说明:这里我使用的是163的邮箱,因为其它邮箱都配不通,要注意的是这里的User Name和管理员的邮箱要一致,否则会报错:553 Mail from must equal authorized user。

参考文献:
1. 《Jenkins入门手册》
2. 《Maven 实战》 徐晓斌著

2016年2月25日星期四

MAC_040:搭建本地 svn 服务器

环境:OS X EI Capitan 10.11.3 + svnserve  1.7.19 + svn 1.7.19

MAC 默认已经自带了 svn 服务器和客户端,因此不需要安装了。

1. 确认安装了 svn 服务器:svnserve
$ svnserve --version
输出如下:
svnserve, version 1.7.19 (r1643991)
   compiled Mar 10 2015, 12:33:03

Copyright (C) 2014 The Apache Software Foundation.
This software consists of contributions made by many people; see the NOTICE
file for more information.
Subversion is open source software, see http://subversion.apache.org/

The following repositories back-end (FS) modules are available:

* fs_fs : Module for working with a plain file (FSFS) repositories.

2. 创建本地仓库
 (1)$ mkdir -p /Users/maping/svn/repositories/local
 (2)$ svnadmin create /Users/maping/svn/repositories/local
 (3)$ ll /Users/maping/svn/repositories/local
      -rw-r--r--   1 maping  staff  229  2 25 08:35 README.txt
      drwxr-xr-x   5 maping  staff  170  2 25 08:35 conf
      drwxr-sr-x  15 maping  staff  510  2 25 08:35 db
      -r--r--r--   1 maping  staff    2  2 25 08:35 format
      drwxr-xr-x  11 maping  staff  374  2 25 08:35 hooks
      drwxr-xr-x   4 maping  staff  136  2 25 08:35 locks

3. 配置
(1)$ vim /Users/maping/svn/repositories/local/conf/svnserve.conf
    [general]
    anon-access = none
    auth-access = write
    password-db = passwd
    authz-db = authz
    注意:
     (1)这里除了要去掉四行前面的#号外,并且要顶到行头,否则有空格,会报错。
     (2)这里必须设置 anon-access = none,否则和Jenkins集成时,会报错:svn: E220001: Item is not readable,详见参考文献 3.

(2)$ vim /Users/maping/svn/repositories/local/conf/passwd
    在[users]后面加入以下内容
    administrator = admin@svnserve
    maping = maping
    说明:这里添加了两个用户,并分别设置了密码。

(3)$ vim /Users/maping/svn/repositories/local/conf/authz
    [groups]
    admin = administrator
    user = maping
    [/]
    # * = r
    @admin = rw
    @user = r
    [local:/]
    @admin = rw
    @user = rw
    说明:
    (1)这里定义了两个组:admin 和 user
    (2)admin这个组里面有 administrator 这个用户(一个组里面可以有多个用户,多个用户用逗号隔开),user 这个组里面有 maping 这个用户。
    (3)设置根目录的权限,这里的 / 目录指的是 /Users/maping/svn/repositories/ 目录。
    (4)设置 local 这个仓库的根目录权限。

4. 启动/停止
(1)启动
     $ svnserve -d -r /Users/maping/svn/repositories
     如果写系统日志,比如/var/log/svn.log,需要root权限。
     $ sudo svnserve -d -r /Users/maping/svn/repositories --log-file=/var/log/svn.log
     svnserve 默认使用3690端口,检查起来没有
     $ netstat -an | grep 3690
 (2)停止
     $ ps -ef | grep svnserve
     $ kill SVNSERVE_PID

5. 创建默认目录结构
(1)首先在本地把目录结构建立好
    $ mkdir -p /tmp/svntemp/tags /tmp/svntemp/trunk /tmp/svntemp/branches

(2)把本地目录结构导入到 svn 仓库中
    $ svn import -m 'init repo' /tmp/svntemp/ svn://localhost/local
    输出如下:
    Authentication realm: e37f735f-9e1b-4882-a177-fa4ba113d199
    Password for 'maping':
    Authentication realm: e37f735f-9e1b-4882-a177-fa4ba113d199
    Username: maping
    Password for 'maping':
    Adding         /tmp/svntemp/tags
    Adding         /tmp/svntemp/trunk
    Adding         /tmp/svntemp/branches

    Committed revision 1.
    说明:
    (1)尽管Subversion的灵活性允许你自由布局版本库,但推荐的方式是:创建一个trunk目录来保存开发的主线,一个branches目录存放分支拷贝,tags目录保存标签拷贝。
    (2)第一个提示的 maping,是 MAC 用户的账户。后面的 maping 是 svn 中定义的账户。
 

(3)导入一个已有的 Maven 项目
    $ svn import -m "initial import" /Users/maping/Apache/maven/my-webapp/  svn://localhost/local/trunk/my-webapp
    输出如下:
    Adding         Apache/maven/my-webapp/src
    Adding         Apache/maven/my-webapp/src/main
    Adding         Apache/maven/my-webapp/src/main/resources
    Adding         Apache/maven/my-webapp/src/main/webapp
    Adding         Apache/maven/my-webapp/src/main/webapp/index.jsp
    Adding         Apache/maven/my-webapp/src/main/webapp/WEB-INF
    Adding         Apache/maven/my-webapp/src/main/webapp/WEB-INF/web.xml
    Adding         Apache/maven/my-webapp/pom.xml

    Committed revision 2.

(4)从 svn 仓库导出项目
    在导入之后,原来的目录并没有转化成工作拷贝,为了开始工作,需要运行 svn checkout 导出一个工作拷贝。
    $ svn checkout svn://localhost/local/ --username=maping --password=maping /Users/maping/mysvn
    $ svn list svn://localhost/local/
    $ svn list svn://localhost/local/trunk/my-webapp
    $ svn delete svn://localhost/local/trunk/my-webapp -m delete

参考文献:
1. http://xiayong.blog.51cto.com/6292420/1088790
2. http://www.cnblogs.com/onlyfu/archive/2012/05/08/2489814.html
3. http://www.2cto.com/os/201211/171663.html

2016年2月21日星期日

Maven_006:使用命令行部署/卸载 JBoss Web 应用

环境: OS X EI Capitan 10.11.3 + JDK 1.7.0_80 + Maven 3.3.9 + Nexus 2.12.0-01 + JBoss EAP 6.4.0

本文以JBoss EAP 6.4.0 以及官方提供的quickstart中的helloworld为例说明。

1. 启动JBoss EAP 
./standalone.sh -Djboss.server.base.dir=/Users/maping/Redhat/eap/demo/myeap -Djboss.socket.binding.port-offset=10000
注意,为了区别默认的JBoss EAP,这里端口偏移了10000。

2. 修改 helloworld的pom.xml文件,增加JBoss EAP的相关配置

<plugin>
   <groupId>org.jboss.as.plugins</groupId>
   <artifactId>jboss-as-maven-plugin</artifactId>
   <version>${version.jboss.maven.plugin}</version>
   <configuration>
       <hostname>127.0.0.1</hostname>
       <port>19999</port>
       <username>admin</username>
       <password>welcome@1</password>
   </configuration>

 </plugin>

3. 编译打包安装 helloworld
mvn clean install

4. 部署/卸载 helloworld 
mvn jboss-as:deploy
mvn jboss-as:undeploy

2016年2月19日星期五

ActiveMQ_016:Message Group 使用例子

环境:OS X EI Capitan 10.11.3 + ActiveMQ 5.13.0

发送消息时,可以设置组别,Message Group 可以让消息消费者按组消费消息,同一组的消息只能由一个消费者消费。
Broker 会随机计算出哪个消费者消费哪个组的信息。

如果发送消息时,不想再设置组别,可以设置值为-1。

1. Queue_Sender_Message_Group1_AutoAck_NonPeresistent.java

package com.travelsky.activemq;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

public class Queue_Sender_Message_Group1_AutoAck_NonPeresistent {

    private static final int SEND_NUMBER = 5;

    public static void main(String[] args) {

        // ConnectionFactory:连接工厂,JMS用它创建连接
        ConnectionFactory connectionFactory;
        // Connection:JMS客户端到JMS Provider的连接
        Connection connection = null;
        // Session:一个发送或接收消息的线程
        Session session;
        // Destination:消息的目的地
        Destination destination;
        // MessageProducer: 消息生产者
        MessageProducer producer;
        //构造ConnectionFactory实例对象,此处采用ActiveMq的实现
        connectionFactory = new ActiveMQConnectionFactory(
                "admin",
                "admin",
                "failover:(tcp://127.0.0.1:61616)");

        try {
            connection = connectionFactory.createConnection();
            connection.start();
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            destination = session.createQueue("FirstQueue");
            producer = session.createProducer(destination);
            producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
            sendMessage(session, producer);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != connection) {
                    connection.close();
                }
            } catch (Throwable ignore) {
            }
        }
    }

    public static void sendMessage(Session session, MessageProducer producer)
            throws Exception {
        for (int i = 1; i <= SEND_NUMBER; i++) {
            TextMessage message = session
                    .createTextMessage("Msg_group_1 ActiveMq发送的消息" + i);
            message.setStringProperty("JMSXGroupID", "Msg_group_1");
            // message.setIntProperty(“JMSXGroupSeq”, -1);
            //Thread.sleep(5000);
            System.out.println("Msg_group_2 发送消息:" + "ActiveMq 发送的消息" + i);
            producer.send(message);          
        }
    }
}


使用例子

参考文献:
1. http://marcelojabali.blogspot.com/2011/11/load-balanced-ordered-message.html

ActiveMQ_015:Exclusive Consumers 使用例子

环境:OS X EI Capitan 10.11.3 + ActiveMQ 5.13.0

Exclusive Consumers 是一个Queue的排他消费者,就是同一时刻只能有一个消费者消费Queue中的消息。
当这个消费者退出后,其它消费者可以争抢这个唯一的消费名额。

1. Queue_Exclusive_Consumer_AutoAck_Sync.java

package com.travelsky.activemq;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

public class Queue_Exclusive_Consumer_AutoAck_Sync {

    public static void main(String[] args) {

        // ConnectionFactory:连接工厂,JMS用它创建连接
        ConnectionFactory connectionFactory;
        // Connection:JMS客户端到JMS Provider的连接
        Connection connection = null;
        // Session:一个发送或接收消息的线程
        Session session;
        // Destination:消息的目的地;消息发送给谁.
        Destination destination;
        // MessageConsumer:消息消费者
        MessageConsumer consumer;

        connectionFactory = new ActiveMQConnectionFactory(
                "admin",
                "admin",
                "failover:(tcp://127.0.0.1:61616)");
           
        try {
            connection = connectionFactory.createConnection();
            connection.start();
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            destination = session.createQueue("FirstQueue?consumer.exclusive=true&consumer.priority=10");
            consumer = session.createConsumer(destination);
            while (true) {
                TextMessage message = (TextMessage) consumer.receive(100000);
                if (null != message) {
                    System.out.println("收到消息" + message.getText());
                } else {
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != connection) {
                    connection.close();
                }
            } catch (Throwable ignore) {
            }
        }
    }
}

consumer.priority的数字越高,表明优先级越大。

参考文献:
1. http://marcelojabali.blogspot.com/2011/11/preserving-message-order-with-apache.html

ActiveMQ_014:Composite Queue 使用例子

环境:OS X EI Capitan 10.11.3 + ActiveMQ 5.13.0

Composite Queue/Topic 和 Virtual Topic 功能差不多,唯一的区别是Composite Queue/Topic需要事先定义在配置文件中,而 Virtual Topic 不需要(除了修改默认规则)。

1. 修改配置文件activemq.xml,增加如下内容:

<destinationInterceptors>
     <virtualDestinationInterceptor>
         <virtualDestinations>
             <compositeQueue name="CompositeQueue.Orders" >
                 <forwardTo>
                     <topic physicalName="Topic.A" />
                     <queue physicalName="Queue.B"/>
                 </forwardTo>
             </compositeQueue>
         </virtualDestinations>
     </virtualDestinationInterceptor>
 </destinationInterceptors>

2.  CompositeQueue_Sender_AutoAck_NonPeresistent.java

package com.travelsky.activemq;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

public class CompositeQueue_Sender_AutoAck_NonPeresistent {

    private static final int SEND_NUMBER = 5;

    public static void main(String[] args) {

        // ConnectionFactory:连接工厂,JMS用它创建连接
        ConnectionFactory connectionFactory;
        // Connection:JMS客户端到JMS Provider的连接
        Connection connection = null;
        // Session:一个发送或接收消息的线程
        Session session;
        // Destination:消息的目的地
        Destination destination;
        // MessageProducer: 消息生产者
        MessageProducer producer;
        //构造ConnectionFactory实例对象,此处采用ActiveMq的实现
        connectionFactory = new ActiveMQConnectionFactory(
                "admin",
                "admin",
                "failover:(tcp://127.0.0.1:61616)");

        try {
            connection = connectionFactory.createConnection();
            connection.start();
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            destination = session.createQueue("CompositeQueue.Orders");
            producer = session.createProducer(destination);
            producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
            sendMessage(session, producer);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != connection) {
                    connection.close();
                }
            } catch (Throwable ignore) {
            }
        }
    }

    public static void sendMessage(Session session, MessageProducer producer)
            throws Exception {
        for (int i = 1; i <= SEND_NUMBER; i++) {
            TextMessage message = session
                    .createTextMessage("ActiveMq发送的消息" + i);
            //Thread.sleep(5000);
            System.out.println("发送消息:" + "ActiveMq 发送的消息" + i);
            producer.send(message);
        }
    }
}

ActiveMQ_013:Virtual Topic 使用例子

环境:OS X EI Capitan 10.11.3 + ActiveMQ 5.13.0

Topic中的消息,消息消费者必须在线才能消费生产者发送的消息。
如果消费者想消费离线时发送的消息,必须使用持久化订阅。但持久化订阅的配置有些麻烦,需要指定ClientID,并且效率很差,只能单线程消费消息。
这意味着,持久化订阅不能实现消息的负载均衡和高可用。
有没有一种Topic,可以消费离线后发送的消息,同时消费者可以多线程消费。
回答是肯定的,就是 ActiveMQ 的 Virtual Topic。
Virtual Topic是一个逻辑的Topic,不是真实存在的物理Topic,经由它,可以把发送到Virtual Topic转发到Queue,这些Queue是真实存在的物理Queue。
 


默认情况下,以 VirtualTopic打头的Topic就是Virtual Topic,比如 VirtualTopic.T;以Consumer.*.VirtualTopic.T 命名的就是和VirtualTopic.T连接的Queue。
并且 VirtualTopic 和对应的 Queue 无需事先创建,运行时动态创建即可。

比如 VirtualTopic.Orders 就是一个Virtual Topic;Consumer.A.VirtualTopic.Orders 和 Consumer.B.VirtualTopic.Orders 就是两个和VirtualTopic.Orders 连接的Queue。
发送到VirtualTopic.Orders的消息会自动转发到Consumer.A.VirtualTopic.Orders和Consumer.B.VirtualTopic.Orders中。

你也可以修改这个默认规则,比如下面这个例子就是把所有发送到VirtualTopic.T的消息,转发到型如 VirtualQueueConsumer.*. 的Queue中。

<broker> 
 <destinationInterceptors>
   <virtualDestinationInterceptor>
     <virtualDestinations>
        <!-- deliver traffic from virtual topic T to all subscribers to destinations matching the prefix "VirtualQueueConsumer.*" (queue or topic) -->
        <virtualTopic name="VirtualTopic.T"
                    prefix="VirtualQueueConsumer.*." />
     </virtualDestinations>
    </virtualDestinationInterceptor>
   </destinationInterceptors>
 </broker> 

1. VirtualTopic_Sender_AutoAck_NonPeresistent.java

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

public class VirtualTopic_Sender_AutoAck_NonPeresistent {

    private static final int SEND_NUMBER = 5;

    public static void main(String[] args) {

        // ConnectionFactory:连接工厂,JMS用它创建连接
        ConnectionFactory connectionFactory;
        // Connection:JMS客户端到JMS Provider的连接
        Connection connection = null;
        // Session:一个发送或接收消息的线程
        Session session;
        // Destination:消息的目的地
        Destination destination;
        // MessageProducer: 消息生产者
        MessageProducer producer;
        //构造ConnectionFactory实例对象,此处采用ActiveMq的实现
        connectionFactory = new ActiveMQConnectionFactory(
                "admin",
                "admin",
                "failover:(tcp://127.0.0.1:61616)");

        try {
            connection = connectionFactory.createConnection();
            connection.start();
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            destination = session.createTopic("VirtualTopic.Orders");
            producer = session.createProducer(destination);
            producer.setDeliveryMode(DeliveryMode.NON_PERSISTENT);
            sendMessage(session, producer);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != connection) {
                    connection.close();
                }
            } catch (Throwable ignore) {
            }
        }
    }

    public static void sendMessage(Session session, MessageProducer producer)
            throws Exception {
        for (int i = 1; i <= SEND_NUMBER; i++) {
            TextMessage message = session
                    .createTextMessage("ActiveMq发送的消息" + i);
            //Thread.sleep(5000);
            System.out.println("发送消息:" + "ActiveMq 发送的消息" + i);
            producer.send(message);
        }
    }
}

2. VirtualTopic_Receiver_AutoAck_Async.java

package com.travelsky.activemq;

import java.io.IOException;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.jms.TextMessage;
import org.apache.activemq.ActiveMQConnectionFactory;

public class VirtualTopic_Receiver_AutoAck_Async {

    public static void main(String[] args) {

        // ConnectionFactory:连接工厂,JMS用它创建连接
        ConnectionFactory connectionFactory;
        // Connection:JMS客户端到JMS Provider的连接
        Connection connection = null;
        // Session:一个发送或接收消息的线程
        Session session;
        // Destination:消息的目的地;消息发送给谁.
        Destination destination;
        //消费者,消息接收者
        MessageConsumer consumer;
        connectionFactory = new ActiveMQConnectionFactory(
                "admin",
                "admin",
                "failover:(tcp://127.0.0.1:61616)");
        try {
            connection = connectionFactory.createConnection();
            connection.start();
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            Destination destinationA = session.createQueue("Consumer.A.VirtualTopic.Orders");
            MessageConsumer consumerA = session.createConsumer(destinationA);
            consumerA.setMessageListener(new MessageListener() {
                public void onMessage(Message message) {
                    TextMessage tm = (TextMessage) message;
                    try {
                        System.out.println("Consumer A Received message: " + tm.getText());
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            });
           
            Destination destinationB = session.createQueue("Consumer.B.VirtualTopic.Orders");
            MessageConsumer consumerB = session.createConsumer(destinationB);
            consumerB.setMessageListener(new MessageListener() {
                public void onMessage(Message message) {
                    TextMessage tm = (TextMessage) message;
                    try {
                        System.out.println("Consumer B Received message: " + tm.getText());
                    } catch (JMSException e) {
                        e.printStackTrace();
                    }
                }
            });

            try {
                System.in.read();
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (null != connection) {
                    connection.close();
                }
            } catch (Throwable ignore) {
            }
        }
    }
}

特别要注意的是, 消费者必须先连接到 Broker,这样才可以创建型如 Consumer.*.VirtualTopic.Orders 的Queue,然后发送到 VirtualTopic.Orders 的消息,Consumer.*.VirtualTopic.Orders 才能收到。
如果是在发送消息到 VirtualTopic.Orders 之后再运行消费者程序,则之前的消息不会收到。
这是 Topic 的固有特性决定的。

参考文献:
1. https://www.packtpub.com/books/content/using-virtual-destinations-advanced
2. http://activemq.apache.org/virtual-destinations.html
3. http://blog.csdn.net/kimmking/article/details/9773085

2016年2月18日星期四

Maven_009:使用 Nexus 2 配置JBoss EAP仓库

环境: OS X EI Capitan 10.11.3 + JDK 1.7.0_80 + Maven 3.3.9 + Nexus 2.12.0-01 + JBoss EAP 6.4.0

1. 增加JBoss Public 代理仓库
JBoss 提供了一个公共仓库,地址是:http://repository.jboss.org/nexus/content/groups/public/


2. 增加JBoss EAP 宿主仓库:
每个版本的JBoss EAP 都提供了一个官方对应的本地的Maven仓库。
下载并解压 jboss-eap-6.4.0-maven-repository.zip


3. 在Public Repositories中增加刚刚创建的两个仓库



4. ~/.m2/settings.xml
内容和《配置Nexus私服前后编译项目的异同》一样。
而且以后都不用修改该文件,如果有新的仓库,直接在Nexus中增加就好了。

5.  测试
这里使用JBoss EAP 官方提供的quickstarts来测试一下。
下载并解压 jboss-eap-6.4.0-quickstarts.zip
cd helloworld
mvn clean install
除了第一次要下载构件到私服外,以后的build速度都很快。
rm -rf ~/.m2/repository
重新build,哇哦,速度真是超快呀!
以后再也不担心本地库混乱了,乱了直接删除就是了。

6.  部署构件到远程仓库
修改项目的pom.xml,在后面增加如下内容:

<distributionManagement>
    <repository>
        <id>releases</id>
        <name>Nexus Release Repository</name>
        <url>http://localhost:8081/nexus/content/repositories/releases/</url>
    </repository>
    <snapshotRepository>
        <id>snapshots</id>
        <name>Nexus Snapshot Repository</name>
        <url>http://localhost:8081/nexus/content/repositories/snapshots/</url>
    </snapshotRepository>
</distributionManagement>
 注意,
(1)releases 是发布版本的构件,项目外部的依赖应该都是发布版本的构件。
(2)snapshots 是快照版本的构件,快照版本的构件只应该用于项目内部的模块依赖。
(3)repository 中的 id 必须与 server 中的 id 一致。

运行 mvn clean deploy,查看 releases 仓库,会看到部署成功的helloworld构件。




Nexus_008:配置 Nexus 2 私服前后编译项目的异同

环境: OS X EI Capitan 10.11.3 + JDK 1.7.0_80 + Maven 3.3.9 + Nexus 2.12.0-01

生成Maven项目的命令
mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-webapp -DarchetypeArtifactId=maven-archetype-webapp -Dversion=1.0-SNAPSHOT -DinteractiveMode=false

1.  配置Nexus私服前
(1)~/.m2/settings.xml

<?xml version="1.0" encoding="UTF-8"?>

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">

</settings>

(2)编译项目
所有构件都是从Maven远程中央仓库下载,并保存到Maven本地库:~/.m2/repository。

3.  配置Nexus私服后
 (1)~/.m2/settings.xml
<?xml version="1.0" encoding="UTF-8"?>

<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">

  <servers>
    <server>
      <id>releases</id>
      <username>admin</username>
      <password>admin123</password>
    </server>
    <server>
      <id>snapshots</id>
      <username>admin</username>
      <password>admin123</password>
    </server>
  </servers>

  <mirrors>
    <mirror>
      <id>nexus</id>
      <mirrorOf>*</mirrorOf>
      <url>http://localhost:8081/nexus/content/groups/public/</url>
    </mirror>
  </mirrors>

  <profiles>

    <!-- Configure the Private Nexus repository -->
    <profile>
      <id>nexus</id>
      <repositories>
        <repository>
          <id>nexus</id>
          <name>Nexus</name>
          <layout>default</layout>
          <url>http://localhost:8081/nexus/content/groups/public/</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
          </snapshots>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>nexus</id>
          <name>Nexus</name>
          <layout>default</layout>
          <url>http://localhost:8081/nexus/content/groups/public/</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
          </snapshots>
        </pluginRepository>
      </pluginRepositories>
    </profile>

  </profiles>

  <activeProfiles>
    <activeProfile>nexus</activeProfile>
  </activeProfiles>

</settings>

(2)编译项目
所有构件都是从Nexus私服下载,并保存到Maven本地库:~/.m2/repository。
如果Nexus私服上没有构件,会从Maven远程中央仓库下载,保存到私服上,位置在 sonatype-work/nexus/storage/central 等代理库。

2016年2月16日星期二

AMQ_009:再测单机环境下 AMQ 单节点 Publish-Subscribe 开箱性能指标

环境:OS X EI Capitan 10.11.3 + JBoss AMQ 6.2.1 + JMeter 2.13

JBoss AMQ 6.2.1使用的版本是apache-activemq-5.11.0.redhat-621084。
本测试不做任何结论性的总结,只是先有个感性认识,以备将来有案可查。
由于发现JMeter自带的采样器有性能问题,因此本次测试使用JMeter + Java 程序方式测试。

1. 硬件环境
型号名称:    MacBook Pro
型号标识符:    MacBookPro11,3
处理器名称:    Intel Core i7
处理器速度:    2.3 GHz
处理器数目:    1
核总数:    4
L2 缓存(每个核):    256 KB
L3 缓存:    6 MB
内存:    16 GB
Boot ROM 版本:    MBP112.0138.B16
SMC 版本(系统):    2.19f12

2. 测试
测试按照四种消息尺寸:1k、10k、100k、1m 。每种尺寸测试非持久化和持久化(leveldb 和 kahadb)三种情况。
使用JMeter + Java 程序进行测试,每个测试计划,启动 50 个线程,Producer 和 Consumer 分开测试。
其中,1k 和 10k 数据,启动 50 个线程, 每个线程生产和消费2w条,共100w条;
./bin/jmeter.sh  -n -t ./test/AMQ-Topic-Receiver.jmx  -Jusers=1 -Jloop=1 -l ./result/AMQ-Topic-Receiver_`date +'%y%m%d%H%M%S'`.csv

./bin/jmeter.sh  -n -t ./test/AMQ-Topic-Sender.jmx  -Jusers=50 -Jloop=1 -l ./result/AMQ-Topic-Sender_`date +'%y%m%d%H%M%S'`.csv

100k 数据,启动 50 个线程, 每个线程生产和消费2000条,共10w条;
1m 数据,启动 5 个线程,每个线程生产和消费1w条,共5w条。
./bin/jmeter.sh  -n -t ./test/AMQ-Topic-Receiver.jmx  -Jusers=1 -Jloop=1 -l ./result/AMQ-Topic-Receiver_`date +'%y%m%d%H%M%S'`.csv

./bin/jmeter.sh  -n -t ./test/AMQ-Topic-Sender.jmx  -Jusers=5 -Jloop=1 -l ./result/AMQ-Topic-Sender_`date +'%y%m%d%H%M%S'`.csv

3. 测试结果

消息尺寸
1k
10k
100k
1m
非持久




leveldb




kahadb(发)
55555/s
30303/s
7143/s
685/s

AMQ_008:再测单机环境下 AMQ 单节点 Point-to-Point 开箱性能指标

环境:OS X EI Capitan 10.11.3 + JBoss AMQ 6.2.1 + JMeter 2.13

JBoss AMQ 6.2.1使用的版本是apache-activemq-5.11.0.redhat-621084。
本测试不做任何结论性的总结,只是先有个感性认识,以备将来有案可查。
由于发现JMeter自带的采样器有性能问题,因此本次测试使用JMeter + Java 程序方式测试。

1. 硬件环境
型号名称:    MacBook Pro
型号标识符:    MacBookPro11,3
处理器名称:    Intel Core i7
处理器速度:    2.3 GHz
处理器数目:    1
核总数:    4
L2 缓存(每个核):    256 KB
L3 缓存:    6 MB
内存:    16 GB
Boot ROM 版本:    MBP112.0138.B16
SMC 版本(系统):    2.19f12

2. 测试
测试按照四种消息尺寸:1k、10k、100k、1m 。每种尺寸测试非持久化和持久化(leveldb 和 kahadb)三种情况。
使用JMeter + Java 程序进行测试,每个测试计划,启动 50 个线程,Producer 和 Consumer 分开测试。
其中,1k 和 10k 数据,启动 50 个线程, 每个线程生产和消费2w条,共100w条;
./bin/jmeter.sh  -n -t ./test/AMQ-Queue-Sender.jmx  -Jusers=50 -Jloop=1 -l ./result/AMQ-Queue-Sender_`date +'%y%m%d%H%M%S'`.csv
./bin/jmeter.sh  -n -t ./test/AMQ-Queue-Receiver.jmx  -Jusers=50 -Jloop=1 -l ./result/AMQ-Queue-Receiver_`date +'%y%m%d%H%M%S'`.csv

100k 数据,启动 50 个线程, 每个线程生产和消费2000条,共10w条;
1m 数据,启动 5 个线程,每个线程生产和消费1w条,共5w条。
./bin/jmeter.sh  -n -t ./test/AMQ-Queue-Sender.jmx  -Jusers=5 -Jloop=1 -l ./result/AMQ-Queue-Sender_`date +'%y%m%d%H%M%S'`.csv
./bin/jmeter.sh  -n -t ./test/AMQ-Queue-Receiver.jmx  -Jusers=5 -Jloop=1 -l ./result/AMQ-Queue-Receiver_`date +'%y%m%d%H%M%S'`.csv

3. 测试结果

消息尺寸
1k
10k
100k
1m
非持久




leveldb




kahadb(发/收)
13502/s
16944/s
5405/s
11358/s
2273/s
3111/s
262/s
 255/s

2016年2月10日星期三

MAC_039:文件关联设置

环境:OS X EI Capitan 10.11.3 + ATOM 1.5

以.txt举例,比如你想把所有.txt文件都默认使用ATOM打开。

右键点击某个.txt文件,-->显示简介-->打开方式-->选择程序,这里选择ATOM1.5,然后切记点击“全部更改”按钮。

MAC_038:安装ATOM编辑器 + 打字火花效果

环境:OS X EI Capitan 10.11.3 + ATOM 1.5

1. 下载
下载地址:https://atom.io/

2.  安装
解压atom-mac.zip,解压后即是Atom.app文件,直接复制到应用程序中。

3. 点击 Preferences-->Install,输入activate-power-mode,点击安装


现在你打字就有火花效果啦^_^。
你可以在命令行输入:atom 文件名,使用ATOM打开该文件。

4. 自动换行


4. 代码格式化,点击 Preferences-->Install,输入atom-beautify,点击安装



参考文献:
1. https://atom.io/
2. http://www.macupdate.com/app/mac/53196/atom/download
3. https://github.com/codeinthedark/awesome-power-mode