2016年3月23日星期三

ActiveMQ_025:Message Cursors

环境:OS X EI Capitan 10.11.4 + ActiveMQ 5.13

当生产者发送的持久化消息到达 broker 之后,broker 首先会把它保存在持久存储中。
接下来,如果发现当前有活跃的消费者,而且这个消费者的消费速度能跟上生产者的生产速度,那么 ActiveMQ 会直接把消息传递给 broker 内部跟这个消费者相关联的 dispatch queue;如果当前没有活跃的消费者或者消费者的消费速度跟不上生产者的生产速度,那么 ActiveMQ 会使用 Pending Message Cursors 保存对消息的引用。在需要的时候,Pending Message Cursors 会把消息引用传递给 broker 内部跟这个消费者相关联的 dispatch queue。

有两种 Pending Message Cursors:
(1)VM Cursor 在内存中保存消息的引用。
(2)File Cursor 首先在内存中保存消息的引用,如果内存使用量达到上限,那么会把消息引用保存到临时文件中。
Topic 和 Queue 都可以配置 Message Cursors。

1. 当消息消费者消费速度跟得上生产者生产消息的速度时,消息将会首先存储到 Message Store 中,然后会直接发送给与消费者关联的 Dispatch Queue。
 2.  当消费者消费消息的速度跟不上生产者生产消息的速度时,消息将会首先存储到 Message Store 中,同时在 Pending Cursor 中保存对消息的引用,然后由 Pending Cursor 发送给与消费者关联的 Dispatch Queue。
默认的 message cursor 类型是基于 Store 的,还有两种其它类型的:VM Cursor 和 File Cursor。

 3.  VM Cursor:在内存中保存消息的引用。

 4.  File Cursor:首先在内存中保存消息的引用,如果内存使用量达到上限,那么会把消息引用保存到临时文件中。

 5. Paging for Non-Persistent Messages
6. 为 Topic 配置 Message Cursor
<destinationPolicy>
      <policyMap>
        <policyEntries>
          <policyEntry topic="org.apache.>" producerFlowControl="false" memoryLimit="1mb">
            <dispatchPolicy>
              <strictOrderDispatchPolicy />
            </dispatchPolicy>
            <deadLetterStrategy>
              <individualDeadLetterStrategy  topicPrefix="Test.DLQ." />
            </deadLetterStrategy>
            <pendingSubscriberPolicy>
                <vmCursor />
            </pendingSubscriberPolicy>
            <pendingDurableSubscriberPolicy>
                <vmDurableCursor/>
            </pendingDurableSubscriberPolicy>
          </policyEntry>
        </policyEntries>
      </policyMap>
</destinationPolicy>

7. 为 Queue 配置 Message Cursor
<destinationPolicy>
    <policyMap>
      <policyEntries>
        <policyEntry queue="org.apache.>">
          <deadLetterStrategy>
            <individualDeadLetterStrategy queuePrefix="Test.DLQ."/>
          </deadLetterStrategy>
          <pendingQueuePolicy>
              <vmQueueCursor />
          </pendingQueuePolicy>
        </policyEntry>
      </policyEntries>
    </policyMap>
</destinationPolicy>

参考文献:
1. http://activemq.apache.org/message-cursors.html
2. http://www.huaishao8.com/config/activemq/198.html

2016年3月22日星期二

ActiveMQ_024:生产者流控

环境:OS X EI Capitan 10.11.4 + ActiveMQ 5.13

默认情况下,无论持久化还是不持久化消息,每个队列都是有生产者流量控制的,即 producerFlowControl="true"。
针对同步发送消息和异步发送消息,生产者流控的限制方式有些区别。

1. 同步发送消息方式(useAsynSend=false)
当队列的内存超过 memoryLimit="1mb" 设定值时,会阻塞生产者。
该特性类似于队列深度的特性,只是限制的是队列使用的内存,而不是消息的个数。
你也许觉得 1mb 太小了,这是因为对于非持久化消息,消息会储存到 tempUsage;对于持久化消息,消息会存储到 storeUsage。
所以,理论上,只要  tempUsage 和 storeUsage 没有爆掉,这个 1mb 内存是不会超过的。

<destinationPolicy>
    <policyMap>
      <policyEntries>
        <policyEntry topic=">" producerFlowControl="true" memoryLimit="1mb">
          <pendingSubscriberPolicy>
            <vmCursor />
          </pendingSubscriberPolicy>
        </policyEntry>
        <policyEntry queue=">" producerFlowControl="true" memoryLimit="1mb">
          <!-- Use VM cursor for better latency
               For more information, see:
               http://activemq.apache.org/message-cursors.html
          <pendingQueuePolicy>
            <vmQueueCursor/>
          </pendingQueuePolicy>
          -->
        </policyEntry>
      </policyEntries>
    </policyMap>
</destinationPolicy>

如果希望客户端抛出异常 javax.jms.ResourceAllocationException,而不是只是 Hung 住,可以在 systemUsage 配置上设置sendFailIfNoSpace="true" 或 sendFailIfNoSpaceAfterTimeout="3000"。

<systemUsage>
  <systemUsage sendFailIfNoSpace="true" >
    <memoryUsage>
      <memoryUsage percentOfJvmHeap="70"/>
    </memoryUsage>
    <storeUsage>
      <storeUsage limit="100 gb"/>
    </storeUsage>
    <tempUsage>
      <tempUsage limit="50 gb"/>
    </tempUsage>
  </systemUsage>
</systemUsage>

2. 异步发送消息方式(useAsynSend=true)
异步发送消息时,由于不等待 broker 收到消息的确认信息,即使内存超出使用限制,也不会得到通知,因此也就无法阻塞生产者。
设置 connctionFactory.setProducerWindowSize(1024000); 可以控制 broker 确认收到消息前生产者能发送的最大字节数。
默认情况下,非持久化消息是以异步方式发送的,如果希望以同步方式发送,可以在 ConnctionFactory 上设置 alwaysSyncSend。

参考文献:
1. http://www.cnblogs.com/zhengyun_ustc/archive/2012/08/25/flowcontrol.html
2. http://activemq.apache.org/producer-flow-control.html
3. http://www.huaishao8.com/config/activemq/198.html
4. http://activemq.apache.org/async-sends.html

ActiveMQ_023:当 Topic 遇到慢消费者

环境:OS X EI Capitan 10.11.4 + ActiveMQ 5.13

非持久化订阅中,一个 Topic 可能有多个消费者,如果其中有一个消费者消费的速度很慢,会让生产者的生产的消息不断堆积在内存中,最终会导致生产者不得不放慢生产速度,其它的快消费者也只好跟着慢下来。

目前 ActiveMQ 使用Pending Message Limit Strategy 来解决这个问题。
设置消费者 prefetch buffer 的最大消息个数,当达到最大值后,如果还有有新的消息进来,那么旧的消息将被丢弃。
这样可以让内存中的消息保持“常新”,并且可以继续给“慢消费者”发送消息。
但是请注意,这个解决办法的前提是允许丢弃消息。

有两种配置方式
(1)常量
例如:<constantPendingMessageLimitStrategy limit="50"/>
(2)消息预取大小(prefetch size) 的倍数
例如:<prefetchRatePendingMessageLimitStrategy multiplier="2.5"/>

以上两种方式中,设置为 0 表示除了 prefetch 之外不再缓存消息;设置为 -1 表示禁止丢弃消息。此外,你还可以配置消息的丢弃策略,目前有以下两种:
(1)oldestMessageEvictionStrategy 丢弃最旧的消息。
(2)oldestMessageWithLowestPriorityEvictionStrategy 丢弃最旧的,并且优先级最低的消息。

可以针对不同的 Topic 定义不同的策略,比如对于 PRICES. 开头的 Topic,可以设置比较小的 limit,因为报价丢了就丢了,不可惜。
对于 ORDERS. 开头的 Topic,可以设置比较大的 limit,因为订单是很重要的消息,不希望丢失。

<destinationPolicy>
  <policyMap>
    <policyEntries>
      <policyEntry topic="ORDERS.>">
        <dispatchPolicy>
          <strictOrderDispatchPolicy />
        </dispatchPolicy>
        <!--  1 minutes worth -->
        <subscriptionRecoveryPolicy>
          <timedSubscriptionRecoveryPolicy recoverDuration="60000" />
        </subscriptionRecoveryPolicy>
      </policyEntry>
      <policyEntry topic="PRICES.>">
        <!-- lets force old messages to be discarded for slow consumers -->
        <pendingMessageLimitStrategy>
          <constantPendingMessageLimitStrategy limit="10"/>
        </pendingMessageLimitStrategy>
        <!--  10 seconds worth -->
        <subscriptionRecoveryPolicy>
          <timedSubscriptionRecoveryPolicy recoverDuration="10000" />
        </subscriptionRecoveryPolicy>
      </policyEntry>
    </policyEntries>
  </policyMap>
</destinationPolicy>

参考文献:
1. http://activemq.apache.org/slow-consumer-handling.html

ActiveMQ_022:内存设置

环境:OS X EI Capitan 10.11.4 + ActiveMQ 5.13

1. ActiveMQ JVM 内存设置
修改 bin/activemq 脚本,在开头增加
# Set jvm memory configuration
if [ -z "$ACTIVEMQ_OPTS_MEMORY" ] ; then
    ACTIVEMQ_OPTS_MEMORY="-Xms8G -Xmx8G"
fi

如果 Broker 中有大量线程,可以考虑设置 -Xss: 减少每个线程使用的 stack size。

2. Broker 使用内存设置:memoryUsage
<systemUsage>
   <systemUsage>
       <memoryUsage>
           <memoryUsage percentOfJvmHeap="70" />
       </memoryUsage>
       <storeUsage>
           <storeUsage limit="100 gb"/>
       </storeUsage>
       <tempUsage>
           <tempUsage limit="50 gb"/>
       </tempUsage>
   </systemUsage>
</systemUsage>
说明:
(1)memoryUsage 表示 Broker 可以使用的最大内存,是所有队列可以使用内存的总和。
当超过 memoryUsage 指定的大小时,消息生产者会被阻塞。
(2)storeUsage 表示持久化存储文件的大小。
(3)tempUsage 表示非持久化消息存储的临时内存大小。

3. 设置某个 destination 可以使用的内存
<destinationPolicy>
    <policyMap>
        <policyEntries>
            <policyEntry queue=">" memoryLimit="5MB"/>
        </policyEntries>
    </policyMap>
</destinationPolicy>

4. 消费者的内存
消费端的内存爆掉通常是由于 prefetch size 太大造成的。
(1)修改所有消费者的 prefetch size
tcp://localhost:61616?jms.prefetchPolicy.all=50
(2)修改所有 Queue 的消费者的 prefetch size
tcp://localhost:61616?jms.prefetchPolicy.queuePrefetch=1
(3)修改指定 Queue 的消费者的 prefetch size
queue = new ActiveMQQueue("TEST.QUEUE?consumer.prefetchSize=10");
consumer = session.createConsumer(queue);

参考文献:
1. http://activemq.apache.org/javalangoutofmemory.html
2. http://www.huaishao8.com/config/activemq/198.html
3. http://activemq.apache.org/what-is-the-prefetch-limit-for.html

2016年3月18日星期五

OpenShift_008:离线安装 OSE 3.1 之七:配置 OSE 3.1

环境:OS X EI Capitan 10.11.3 + Open Shift Enterprise 3.1

以下操作均在 Master 节点上执行

1. 安装 httpd 相关工具
yum -y install httpd-tools;

2. 创建httpd访问时所需的用户名密码
htpasswd -cb /etc/origin/master/users.htpasswd redhat welcome1 ;

3. 修改访问方式为 httpd 的基本校验方式
cp /etc/origin/master/master-config.yaml /etc/origin/master/master-config.yaml.bak.$(date "+%Y%m%d%H%M%S");
sed -i 's/DenyAllPasswordIdentityProvider/HTPasswdPasswordIdentityProvider/g' /etc/origin/master/master-config.yaml;
sed -i '/PasswordIdentityProvider/a\      file: /etc/origin/master/users.htpasswd' /etc/origin/master/master-config.yaml ;
sed -i 's/.*subdomain.*/  subdomain: apps.example.com/' /etc/origin/master/master-config.yaml ;
systemctl restart atomic-openshift-master;

4. 添加 router
(1) 添加 router
oc project default;
oc label node node1.example.com infra="yes"
oadm router ose-master --replicas=1 \
    --credentials='/etc/origin/master/openshift-router.kubeconfig' \
    --images='registry.example.com:5000/openshift3/ose-${component}:${version}' \
--selector='infra=yes' --service-account=router ;
(2) 测试
oc get node
直到出现一个 ose-master-1-XXX 的 pod 状态为 Running 时,表示创建成功。
输出如下:

5. 添加 registry
(1) 添加 registry
oadm registry --create --credentials=/etc/origin/master/openshift-registry.kubeconfig ;
(2) 测试
oc get node
直到出现一个 docker-registry-1-XXX 的 pod 状态为 Running 时,表示创建成功.
输出如下:

6. 添加 image stream
(1)把原有的 image stream 删除
for i in $(oc get is -n openshift --no-headers|awk '{print $1}') ; do oc delete is $i -n openshift; done;
(2)替换 registry.access.redhat.com 为 registry.example.com:5000
REDHAT_REG="registry.access.redhat.com";
PRIVATE_REG="registry.example.com:5000";
sed s/"${REDHAT_REG}"/"${PRIVATE_REG}"/g  /usr/share/openshift/examples/image-streams/image-streams-rhel7.json |sed '/"creationTimestamp": null/a\\t,"annotations": {"openshift.io/image.insecureRepository": "true"}' |oc create -n openshift -f - ;
(2)测试
oc get images
输出如下:

7. 验证 Web Console
(1)配置本机的 dns 地址, 指向可访问到 master.example.com 的地址
sed -i '1 i\192.168.56.105' /etc/resolv.conf
(2)在浏览器中访问 https://master.example.com:8443 redhat/welcome1
(3)New Project
(4)选择 php:5.6 sti 镜像
(5)输入当前应用的项目名及源码地址
(6)Continue to overview
(7)等待编译,在左侧的Browse->Events中查看日志
(8)成功部署后, 在 Overview 页面, 点击上/下方向键可调整 pod 数量
(9)点击SERVICE下的域名, 可访问当前服务
(10)点击 Overview -> Topology View标签, 可直观的显示各部分内容
(11)添加 git hook 触发 Openshift 自动部署
  在 master 节点获取 build web hook trigger
OSE_PRJ=;
OSE_APP=;
OSE_SEC=$(oc get bc $OSE_APP -o yaml -n $OSE_PRJ|grep generic -A 1|grep secret|awk -F ': ' '{print $2}');
BC_URL=    "https://master.example.com:8443/oapi/v1/namespaces/$OSE_PRJ/buildconfigs/$OSE_APP/webhooks/$OSE_SEC/generic";
  在 git.example.com 机器中, 将 BC_URL 加入到 git 的项目中
echo "curl -k -H 'Content-Type: application/json' -X POST $BC_URL" > /opt/git/repo/cakephp.git/hooks/post-receive;
chmod +x /opt/git/repo/cakephp.git/hooks/post-receive;

OpenShift_007:离线安装 OSE 3.1 之六:安装 OSE 3.1

环境:OS X EI Capitan 10.11.3 + Open Shift Enterprise 3.1

以下操作均在 Master 节点上执行

1. 为 Master、Node1、Node2 节点分别创建 subnet.json 脚本
(1)vim master-subnet.json
{
    "kind": "HostSubnet",
    "apiVersion": "v1",
    "metadata": {
        "name": "master.example.com",
        "selfLink": "/oapi/v1/hostsubnets/master.example.com"
    },
    "host": "master.example.com",
    "hostIP": "192.168.56.106",
    "subnet": "10.1.1.0/24"
}
(2)vim node1-subnet.json
{
    "kind": "HostSubnet",
    "apiVersion": "v1",
    "metadata": {
        "name": "node1.example.com",
        "selfLink": "/oapi/v1/hostsubnets/node1.example.com"
    },
    "host": "node1.example.com",
    "hostIP": "192.168.56.107",
    "subnet": "10.1.2.0/24"
}
(3)vim node2-subnet.json
{
    "kind": "HostSubnet",
    "apiVersion": "v1",
    "metadata": {
        "name": "node2.example.com",
        "selfLink": "/oapi/v1/hostsubnets/node2.example.com"
    },
    "host": "node2.example.com",
    "hostIP": "192.168.56.108",
    "subnet": "10.1.3.0/24"
}

2. 集群内机器的 ssh 互信
ssh-keygen;
for i in master.example.com node1.example.com node2.example.com;
do
ssh-copy-id $i;
done;

3. 安装 atomic-openshift-installer
atomic-openshift-installer install

交互输入输出如下:
Welcome to the OpenShift Enterprise 3 installation.

Please confirm that following prerequisites have been met:

* All systems where OpenShift will be installed are running Red Hat Enterprise
  Linux 7.
* All systems are properly subscribed to the required OpenShift Enterprise 3
  repositories.
* All systems have run docker-storage-setup (part of the Red Hat docker RPM).
* All systems have working DNS that resolves not only from the perspective of
  the installer but also from within the cluster.

When the process completes you will have a default configuration for Masters
and Nodes.  For ongoing environment maintenance it's recommended that the
official Ansible playbooks be used.

For more information on installation prerequisites please see:
https://docs.openshift.com/enterprise/latest/admin_guide/install/prerequisites.html

Are you ready to continue? [y/N]:y

This installation process will involve connecting to remote hosts via ssh.  Any
account may be used however if a non-root account is used it must have
passwordless sudo access.

User for ssh access [root]:


Which variant would you like to install?


(1) OpenShift Enterprise 3.1
(2) OpenShift Enterprise 3.0
(3) Atomic Enterprise Platform 3.1

Choose a variant from above:  [1]:

*** Host Configuration ***

You must now specify the hosts that will compose your OpenShift cluster.

Please enter an IP or hostname to connect to for each system in the cluster.
You will then be prompted to identify what role you would like this system to
serve in the cluster.

OpenShift Masters serve the API and web console and coordinate the jobs to run
across the environment.  If desired you can specify multiple Master systems for
an HA deployment, in which case you will be prompted to identify a *separate*
system to act as the load balancer for your cluster after all Masters and Nodes
are defined.

If only one Master is specified, an etcd instance embedded within the OpenShift
Master service will be used as the datastore.  This can be later replaced with a
separate etcd instance if desired.  If multiple Masters are specified, a
separate etcd cluster will be configured with each Master serving as a member.

Any Masters configured as part of this installation process will also be
configured as Nodes.  This is so that the Master will be able to proxy to Pods
from the API.  By default this Node will be unschedulable but this can be changed
after installation with 'oadm manage-node'.

OpenShift Nodes provide the runtime environments for containers.  They will
host the required services to be managed by the Master.

http://docs.openshift.com/enterprise/latest/architecture/infrastructure_components/kubernetes_infrastructure.html#master
http://docs.openshift.com/enterprise/latest/architecture/infrastructure_components/kubernetes_infrastructure.html#node

Enter hostname or IP address: master.example.com
Will this host be an OpenShift Master? [y/N]: y

*** Installation Summary ***

Hosts:
- master.example.com
  - OpenShift Master
  - OpenShift Node
  - Etcd (Embedded)

Total OpenShift Masters: 1
Total OpenShift Nodes: 1

NOTE: Add a total of 3 or more Masters to perform an HA installation.

Do you want to add additional hosts? [y/N]: y
Enter hostname or IP address: node1.example.com
Will this host be an OpenShift Master? [y/N]: n


*** Installation Summary ***

Hosts:
- master.example.com
  - OpenShift Master
  - OpenShift Node (Unscheduled)
  - Etcd (Embedded)
- node1.example.com
  - OpenShift Node (Dedicated)

Total OpenShift Masters: 1
Total OpenShift Nodes: 2

NOTE: Add a total of 3 or more Masters to perform an HA installation.

Do you want to add additional hosts? [y/N]: y
Enter hostname or IP address: node2.example.comWill this host be an OpenShift Master? [y/N]: n

*** Installation Summary ***

Hosts:
- master.example.com
  - OpenShift Master
  - OpenShift Node (Unscheduled)
  - Etcd (Embedded)
- node1.example.com
  - OpenShift Node (Dedicated)
- node2.example.com
  - OpenShift Node (Dedicated)

Total OpenShift Masters: 1
Total OpenShift Nodes: 3

NOTE: Add a total of 3 or more Masters to perform an HA installation.

Do you want to add additional hosts? [y/N]:n

A list of the facts gathered from the provided hosts follows. Because it is
often the case that the hostname for a system inside the cluster is different
from the hostname that is resolveable from command line or web clients
these settings cannot be validated automatically.

For some cloud providers the installer is able to gather metadata exposed in
the instance so reasonable defaults will be provided.

Plese confirm that they are correct before moving forward.


master.example.com,192.168.56.106,192.168.56.106,master.example.com,master.example.com
node1.example.com,192.168.56.107,192.168.56.107,node1.example.com,node1.example.com
node2.example.com,192.168.56.108,192.168.56.108,node2.example.com,node2.example.com

Format:

connect_to,IP,public IP,hostname,public hostname

Notes:
 * The installation host is the hostname from the installer's perspective.
 * The IP of the host should be the internal IP of the instance.
 * The public IP should be the externally accessible IP associated with the instance
 * The hostname should resolve to the internal IP from the instances
   themselves.
 * The public hostname should resolve to the external ip from hosts outside of
   the cloud.

Do the above facts look correct? [y/N]: y
Ready to run installation process.

If changes are needed please edit the config file above and re-run.

Are you ready to continue? [y/N]: y

......

在出现大段的验证信息后(这个信息会出现3次,分别是 master、node1、node2的验证信息),
马上在另一个终端执行:
oc create -f master-subnet.json;
oc create -f node1-subnet.json;
oc create -f node2-subnet.json;


......

PLAY RECAP ********************************************************************
localhost                  : ok=13   changed=0    unreachable=0    failed=0
master.example.com         : ok=222  changed=57   unreachable=0    failed=0
node1.example.com          : ok=60   changed=21   unreachable=0    failed=0
node2.example.com          : ok=60   changed=21   unreachable=0    failed=0


The installation was successful!

If this is your first time installing please take a look at the Administrator
Guide for advanced options related to routing, storage, authentication and much
more:

http://docs.openshift.com/enterprise/latest/admin_guide/overview.html

Press any key to continue ...

4. 测试
oc get node
输出如下:
NAME                 LABELS                                      STATUS                     AGE
master.example.com   kubernetes.io/hostname=master.example.com   Ready,SchedulingDisabled   12d
node1.example.com    kubernetes.io/hostname=node1.example.com    Ready                      12d
node2.example.com    kubernetes.io/hostname=node2.example.com    Ready                      12d
 

OpenShift_006:离线安装 OSE 3.1 之五:安装 Node2 节点

环境:OS X EI Capitan 10.11.3 + Open Shift Enterprise 3.1

1. 网络、主机名、安全配置
(1) 设定固定 IP 地址:vim /etc/sysconfig/network-scripts/ifcfg-enp0s3
TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME=enp0s3
UUID=8fe5a4c7-fbcd-4218-8e2f-31ec4e956fa4
DEVICE=enp0s3
ONBOOT=yes
PEERDNS=yes
PEERROUTES=yes
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
IPADDR=192.168.56.108
NETMASK=255.255.255.0
GATEWAY=192.168.56.1
(2) 设定 hostname
hostnamectl set-hostname node2.example.com
(3) 设定 selinux 安全级别为 permissive
sed -i 's/=enforcing/=permissive/g' /etc/selinux/config

2. 配置指向 yum 源,蓝色字体根据实际 yum 源配置修改
(1)创建 yum 源配置文件
cat << EOF > /etc/yum.repos.d/ose.repo
[OpenShift]
baseurl = http://192.168.56.105/repo/
gpgcheck = 0
enabled = 1
EOF
(2)测试确认可以获得 yum 源
yum list|grep -i atomic-openshift;

3. 安装 docker 和相应软件
 (1) 安装基础软件包
yum -y remove NetworkManager*;
yum -y install wget git net-tools bind-utils iptables-services bridge-utils bash-completion vim lrzsz unzip;
yum -y update;
yum -y install atomic-openshift-utils;
reboot;
(2) 安装 docker
yum -y install docker;
systemctl enable docker;
systemctl stop docker;
(3) 修改 docker registry 地址,蓝色字体根据实际地址修改
cp /etc/sysconfig/docker /etc/sysconfig/docker.bak.$(date "+%Y%m%d%H%M%S");
sed  -i s/".*--selinux-enabled.*"/"OPTIONS='--selinux-enabled --insecure-registry 172.30.0.0\/16 --insecure-registry registry.example.com:5000'"/g /etc/sysconfig/docker;
sed -i 's/registry.access.redhat.com/registry.example.com:5000/g' /etc/sysconfig/docker;
(4) 修改 docker 存储
cat < /etc/sysconfig/docker-storage-setup
VG=rhel
SETUP_LVM_THIN_POOL=yes
EOF
docker-storage-setup;
输出如下:// TODO 这个有没有问题?
Rounding up size to full physical extent 52.00 MiB
Volume group "rhel" has insufficient free space (11 extents): 13 required.
(4) 将 docker 的容器存储部分挂到另一个盘,蓝色字体根据实际设备修改(本次安装未执行此步)
vgextend rhel  /dev/vdb
lvextend -l +100%FREE /dev/rhel/docker-pool
(5) 重启 docker
systemctl start docker;

4. 配置 dns,蓝色字体根据实际机器 IP 和网卡名称修改
(1)配置 /etc/resolv.conf
cp /etc/resolv.conf /etc/resolv.conf.bak.$(date "+%Y%m%d%H%M%S");
sed -i '1 i\nameserver 192.168.56.105' /etc/resolv.conf;
chattr +i /etc/resolv.conf
echo "DNS1=192.168.56.105">>/etc/sysconfig/network-scripts/ifcfg-enp0s3;
(2)测试确认 dns 解析成功
dig master.example.com@192.168.56.105

5. 测试确认可以从 docker private registry 把 docker image pull 下来
docker pull registry.example.com:5000/openshift3/php-55-rhel7

6. 测试确认可以 git clone 项目代码
cd /tmp;
git clone http://git.example.com/git/cakephp.git/;

OpenShift_005:离线安装 OSE 3.1 之四:安装 Node1 节点

环境:OS X EI Capitan 10.11.3 + Open Shift Enterprise 3.1

1. 网络、主机名、安全配置
 (1) 设定固定 IP 地址:vim /etc/sysconfig/network-scripts/ifcfg-enp0s3
TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME=enp0s3
UUID=8fe5a4c7-fbcd-4218-8e2f-31ec4e956fa4
DEVICE=enp0s3
ONBOOT=yes
PEERDNS=yes
PEERROUTES=yes
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
IPADDR=192.168.56.107
NETMASK=255.255.255.0
GATEWAY=192.168.56.1
(2) 设定 hostname
hostnamectl set-hostname node1.example.com
(3) 设定 selinux 安全级别为 permissive
sed -i 's/=enforcing/=permissive/g' /etc/selinux/config

2. 配置指向 yum 源,蓝色字体根据实际 yum 源配置修改
(1)创建 yum 源配置文件
cat << EOF > /etc/yum.repos.d/ose.repo
[OpenShift]
baseurl = http://192.168.56.105/repo/
gpgcheck = 0
enabled = 1
EOF
(2)测试确认可以获得 yum 源
yum list|grep -i atomic-openshift;

3. 安装 docker 和相应软件
 (1) 安装基础软件包
yum -y remove NetworkManager*;
yum -y install wget git net-tools bind-utils iptables-services bridge-utils bash-completion vim lrzsz unzip;
yum -y update;
yum -y install atomic-openshift-utils;
reboot;
(2) 安装 docker
yum -y install docker;
systemctl enable docker;
systemctl stop docker;
(3) 修改 docker registry 地址,蓝色字体根据实际地址修改
cp /etc/sysconfig/docker /etc/sysconfig/docker.bak.$(date "+%Y%m%d%H%M%S");
sed  -i s/".*--selinux-enabled.*"/"OPTIONS='--selinux-enabled --insecure-registry 172.30.0.0\/16 --insecure-registry registry.example.com:5000'"/g /etc/sysconfig/docker;
sed -i 's/registry.access.redhat.com/registry.example.com:5000/g' /etc/sysconfig/docker;
(4) 修改 docker 存储
cat < /etc/sysconfig/docker-storage-setup
VG=rhel
SETUP_LVM_THIN_POOL=yes
EOF
docker-storage-setup;
输出如下:// TODO 这个有没有问题?
Rounding up size to full physical extent 52.00 MiB
Volume group "rhel" has insufficient free space (11 extents): 13 required.
(4) 将 docker 的容器存储部分挂到另一个盘,蓝色字体根据实际设备修改(本次安装未执行此步)
vgextend rhel  /dev/vdb
lvextend -l +100%FREE /dev/rhel/docker-pool
(5) 重启 docker
systemctl start docker;

4. 配置 dns,蓝色字体根据实际机器 IP 和网卡名称修改
(1)配置 /etc/resolv.conf
cp /etc/resolv.conf /etc/resolv.conf.bak.$(date "+%Y%m%d%H%M%S");
sed -i '1 i\nameserver 192.168.56.105' /etc/resolv.conf;
chattr +i /etc/resolv.conf
echo "DNS1=192.168.56.105">>/etc/sysconfig/network-scripts/ifcfg-enp0s3;
(2)测试确认 dns 解析成功
dig master.example.com@192.168.56.105

5. 测试确认可以从 docker private registry 把 docker image pull 下来
docker pull registry.example.com:5000/openshift3/php-55-rhel7

6. 测试确认可以 git clone 项目代码
cd /tmp;
git clone http://git.example.com/git/cakephp.git/;

OpenShift_004:离线安装 OSE 3.1 之三:安装 Master 节点

环境:OS X EI Capitan 10.11.3 + Open Shift Enterprise 3.1

离线安装 OSE 3.1 之三:安装 Master 节点

1. 网络、主机名、安全配置
(1) 设定固定 IP 地址:vim /etc/sysconfig/network-scripts/ifcfg-enp0s3
TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME=enp0s3
UUID=b2410daf-6661-4726-9c56-07d9d7bc035e
DEVICE=enp0s3
ONBOOT=yes
PEERDNS=yes
PEERROUTES=yes
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
IPADDR=192.168.56.106
NETMASK=255.255.255.0
GATEWAY=192.168.56.105
(2) 设定 hostname
hostnamectl set-hostname master.example.com
(3) 设定 selinux 安全级别为 permissive
sed -i 's/=enforcing/=permissive/g' /etc/selinux/config

2. 配置指向 yum 源,蓝色字体根据实际 yum 源配置修改
(1)创建 yum 源配置文件
cat << EOF > /etc/yum.repos.d/ose.repo
[OpenShift]
baseurl = http://192.168.56.105/repo/
gpgcheck = 0
enabled = 1
EOF
(2)测试确认可以获得 yum 源
yum list|grep -i atomic-openshift;

3. 安装 docker 和相应软件
 (1) 安装基础软件包 (如果没有 yum 源,需要先按照 5.2 安装和配置 yum 源)
yum -y remove NetworkManager*;
yum -y install wget git net-tools bind-utils iptables-services bridge-utils bash-completion vim lrzsz unzip;
yum -y update;
yum -y install atomic-openshift-utils;
reboot;
(2) 安装 docker
yum -y install docker;
systemctl enable docker;
systemctl stop docker;
(3) 修改 docker registry 地址,蓝色字体根据实际地址修改
cp /etc/sysconfig/docker /etc/sysconfig/docker.bak.$(date "+%Y%m%d%H%M%S");
sed  -i s/".*--selinux-enabled.*"/"OPTIONS='--selinux-enabled --insecure-registry 172.30.0.0\/16 --insecure-registry registry.example.com:5000'"/g /etc/sysconfig/docker;
sed -i 's/registry.access.redhat.com/registry.example.com:5000/g' /etc/sysconfig/docker;
(4) 修改 docker 存储
cat < /etc/sysconfig/docker-storage-setup
VG=rhel
SETUP_LVM_THIN_POOL=yes
EOF
docker-storage-setup;
输出如下:// TODO 这个有没有问题?
Rounding up size to full physical extent 52.00 MiB
Volume group "rhel" has insufficient free space (11 extents): 13 required.
(4) 将 docker 的容器存储部分挂到另一个盘,蓝色字体根据实际设备修改(本次安装未执行此步)
vgextend rhel  /dev/vdb
lvextend -l +100%FREE /dev/rhel/docker-pool
(5) 重启 docker
systemctl start docker;

4. 配置 dns,蓝色字体根据实际机器 IP 和网卡名称修改
(1)配置 /etc/resolv.conf
cp /etc/resolv.conf /etc/resolv.conf.bak.$(date "+%Y%m%d%H%M%S");
sed -i '1 i\nameserver 192.168.56.105' /etc/resolv.conf;
chattr +i /etc/resolv.conf
echo "DNS1=192.168.56.105">>/etc/sysconfig/network-scripts/ifcfg-enp0s3;
(2)测试确认 dns 解析成功
dig master.example.com@192.168.56.105

5. 测试确认可以从 docker private registry 把 docker image pull 下来
docker pull registry.example.com:5000/openshift3/php-55-rhel7

6. 测试确认可以 git clone 项目代码
cd /tmp;
git clone http://git.example.com/git/cakephp.git/;

OpenShift_003:离线安装 OSE 3.1 之二:安装 YUM 源及第三方服务

环境:OS X EI Capitan 10.11.3 + Open Shift Enterprise 3.1

1. 网络、主机名、安全配置
(1) 设定固定 IP 地址:vim /etc/sysconfig/network-scripts/ifcfg-enp0s3
TYPE=Ethernet
BOOTPROTO=static
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
NAME=enp0s3
UUID=8fe5a4c7-fbcd-4218-8e2f-31ec4e956fa4
DEVICE=enp0s3
ONBOOT=yes
PEERDNS=yes
PEERROUTES=yes
IPV6_PEERDNS=yes
IPV6_PEERROUTES=yes
IPADDR=192.168.56.105
NETMASK=255.255.255.0
GATEWAY=192.168.56.105
(2) 设定 hostname
hostnamectl set-hostname yum.example.com
(3) 设定 selinux 安全级别为 permissive
sed -i 's/=enforcing/=permissive/g' /etc/selinux/config

2. 安装和配置 yum 源
(1)创建本地 yum 源
tar zxvf /media/sf_Share/ose3.1/ose31-yum.tar.gz -C /opt/
(2)安装 createrepo 等工具
cd /opt/ose/rhel-7-server-rpms/Packages/;
rpm -ivh deltarpm-3.6-3.el7.x86_64.rpm;
rpm -ivh python-deltarpm-3.6-3.el7.x86_64.rpm;
rpm -ivh createrepo-0.9.9-23.el7.noarch.rpm;
(3)创建可识别的 yum 源
cd /opt/ose/;
createrepo .;
chmod 777 -R /opt/ose;
(4)指定本地 yum 源文件路径
cat << EOF > /etc/yum.repos.d/local.repo
[local]
baseurl = file:///opt/ose
gpgcheck = 0
enabled = 1
EOF
(5)安装 httpd
yum install -y httpd;
cat << EOF > /etc/httpd/conf.d/yum.conf
Alias /repo "/opt/ose"

  Options +Indexes +FollowSymLinks
Require all granted


SetHandler None

EOF
(6)使 yum 源可以被访问
systemctl disable firewalld;
systemctl stop  firewalld;
systemctl enable httpd;
systemctl restart httpd;
(7)在其它机器上(master,node1,node2)测试确认 yum 源可以被访问

3. 复制 docker images 和 应用程序
(1)复制 docker images
mkdir /opt/images;
cd /opt/images;
cp /media/sf_Share/ose3.1/docker-images/*.tar .
(2)复制应用程序
mkdir /opt/software;
cd /opt/software;
cp /media/sf_Share/ose3.1/*.zip .;
cp /media/sf_Share/ose3.1/*.json .;
cp -r /media/sf_Share/ose3.1/customized .;

4. 安装 docker 和相应软件
(1) 安装基础软件包 (如果没有 yum 源,需要先按照 5.2 安装和配置 yum 源)
yum -y remove NetworkManager*;
yum -y install wget git net-tools bind-utils iptables-services bridge-utils bash-completion vim lrzsz unzip;
yum -y update;
yum -y install atomic-openshift-utils;
reboot;
(2) 安装 docker
yum -y install docker;
systemctl enable docker;
systemctl stop docker;
(3) 修改 docker registry 地址,蓝色字体根据实际地址修改
cp /etc/sysconfig/docker /etc/sysconfig/docker.bak.$(date "+%Y%m%d%H%M%S");
sed  -i s/".*--selinux-enabled.*"/"OPTIONS='--selinux-enabled --insecure-registry 172.30.0.0\/16 --insecure-registry registry.example.com:5000'"/g /etc/sysconfig/docker;
sed -i 's/registry.access.redhat.com/registry.example.com:5000/g' /etc/sysconfig/docker;
(4) 修改 docker 存储
cat < /etc/sysconfig/docker-storage-setup
VG=rhel
SETUP_LVM_THIN_POOL=yes
EOF
docker-storage-setup;
输出如下:// TODO 这个有没有问题?
Rounding up size to full physical extent 52.00 MiB
Volume group "rhel" has insufficient free space (11 extents): 13 required.
(4) 将 docker 的容器存储部分挂到另一个盘,蓝色字体根据实际设备修改(本次安装未执行此步)
vgextend rhel  /dev/vdb
lvextend -l +100%FREE /dev/rhel/docker-pool
(5) 重启 docker
systemctl start docker;

5. 安装和配置 dns server
(1)安装 bind 相关包
yum -y install bind* ;
systemctl enable named ;
(2)修改 dns 访问配置
cp /etc/named.conf /etc/named.conf.bak.$(date "+%Y%m%d%H%M%S");
sed -i s/"listen-on port 53 { 127.0.0.1; };"/"listen-on port 53 { any; };"/g /etc/named.conf;
sed -i s/"listen-on-v6 port 53 { ::1; };"/"listen-on port 53 { any; };"/g /etc/named.conf;
sed -i s/"allow-query     { localhost; };"/"allow-query     { any; };"/g /etc/named.conf;
sed -i '/rfc1912/i\zone "apps.example.com" IN { type master; file "dynamic/apps.example.com.db"; };' /etc/named.conf
sed -i '/rfc1912/i\zone "example.com" IN { type master; file "dynamic/example.com.db"; };' /etc/named.conf
(3)修改各主机别名,蓝色字体根据实际机器 IP 地址修改
cat << EOF > /var/named/dynamic/example.com.db
\$ORIGIN .
\$TTL 1 ; 1 sec
example.com     IN  SOA  ns1.example.com. hostmaster.example.com. (
                2011112904 ; serial
                60         ; refresh
                15         ; retry
                1800       ; expire
                10         ; minimum
           )
       NS ns1.example.com.
       MX 10 mail.example.com.
\$ORIGIN example.com.
ns1       A 192.168.56.105
master    A 192.168.56.106
node1     A 192.168.56.107
node2     A 192.168.56.108
registry    A 192.168.56.105
git        A 192.168.56.105
yum        A 192.168.156.105


EOF
(4)修改各主机别名,蓝色字体根据实际机器 IP 地址修改
cat << EOF > /var/named/dynamic/apps.example.com.db
\$ORIGIN .
\$TTL 1 ; 1 sec
apps.example.com     IN  SOA  ns1.apps.example.com. hostmaster.apps.example.com. (
                2011112904 ; serial
                60         ; refresh
                15         ; retry
                1800       ; expire
                10         ; minimum
           )
       NS ns1.apps.example.com.
       MX 10 mail.apps.example.com.
\$ORIGIN apps.example.com.
*        A 192.168.56.107
EOF
systemctl restart named;
(5)配置 iptables
cp /etc/sysconfig/iptables /etc/sysconfig/iptables.bak.$(date "+%Y%m%d%H%M%S");
sed -i '/.*--dport 22 -j ACCEPT.*/a\-A INPUT -p tcp -m state --state NEW -m tcp --dport 53 -j ACCEPT' /etc/sysconfig/iptables;
sed -i '/.*--dport 22 -j ACCEPT.*/a\-A INPUT -p udp -m state --state NEW -m udp --dport 53 -j ACCEPT' /etc/sysconfig/iptables;
sed -i '/.*--dport 22 -j ACCEPT.*/a\-A INPUT -p tcp -m state --state NEW -m tcp --dport 5000 -j ACCEPT' /etc/sysconfig/iptables;
sed -i '/.*--dport 22 -j ACCEPT.*/a\-A INPUT -p tcp -m state --state NEW -m tcp --dport 80 -j ACCEPT' /etc/sysconfig/iptables;
systemctl enable iptables
systemctl restart iptables;
(6) 在其它3台机器(master,node1,node2)测试,确认 dns 解析成功

6. 安装和配置 docker private registry
在 registry.example.com 所在的机器上安装,这里 registry.example.com 机器就是 yum.example.com 机器。
(1) 安装 docker registry 包
yum -y install docker-registry;
systemctl enable docker-registry;
systemctl start docker-registry;
(2) 把之前备份的本地 docker images 文件导入
cd /opt/images/;
for i in `ls` ; do docker load < $i ; done;
docker images;
(3) 把本地 docker images push 到仓库
REDHAT_REG="registry.access.redhat.com";
PRIVATE_REG="registry.example.com:5000";
for i in $(docker images|grep $REDHAT_REG|awk '{print $1":"$2}') ; do docker tag  $i "$PRIVATE_REG$(echo $i|awk -F 'com' {'print $2'})" ; done;
for i in `docker images|grep $PRIVATE_REG|awk '{print $1}'` ; do  docker push $i; done;
(4) 在其它3台机器(master,node1,node2)上测试,确认可以从 docker private registry 把 docker image pull 下来
 

7. 安装和配置 git server
在 git.example.com 所在的机器上安装,这里 git.example.com 机器就是 yum.example.com 机器。
(1) 初始化仓库
mkdir -p /opt/git/repo/cakephp.git;
cd /opt/git/repo/cakephp.git;
git init --bare;
git update-server-info;
mv hooks/post-update.sample hooks/post-update;
(2) 本地克隆
cd /opt;
git clone file:///opt/git/repo/cakephp.git/;
(3) 把 cakephp-ex-master push 到仓库
unzip cakephp-ex-master.zip;
cp cakephp-ex-master/* cakephp -rf;
cp cakephp-ex-master/.sti cakephp -rf;
cp cakephp-ex-master/.htaccess cakephp -rf;
cp cakephp-ex-master/.gitignore cakephp -rf;
cd cakephp;
git add .;
git commit -m 'initial upload';
git push origin master;
(4) 在 httpd 中打开 git 服务
cat << EOF > /etc/httpd/conf.d/git.conf
Alias /git "/opt/git/repo"

    Dav On
    Options +Indexes +FollowSymLinks
Require all granted

EOF
chown -R apache:apache /opt/git/repo/cakephp.git;
systemctl restart httpd;
(5) 在其它3台机器(master,node1,node2)测试,确认可以 git clone 项目代码

OpenShift_002:离线安装 OSE 3.1 之一:准备安装环境和安装介质

环境:OS X EI Capitan 10.11.3 + Open Shift Enterprise 3.1

首先感谢同事陈耿和王章贵的大力支持,谢谢你们!

1. 安装环境
一共 4 台虚机,请提前安装好 RHEL 7.2
(1)yum 源及第三方服务机器 192.168.56.105
这台机器要作为: yum repository, dns server, docker private registry, git server
(2)master 节点机器 192.168.56.106
(3)node1 节点机器 192.168.56.107
(4)node2 节点机器 192.168.56.108

2. 获取 yum repositories
(1)注册到 Red Hat RHN 上
subscription-manager register;
subscription-manager list --available >list;
subscription-manager attach --pool=YOUR_POOL_ID ;
subscription-manager repos --disable="*"
subscription-manager repos \
    --enable="rhel-7-server-rpms" \
--enable="rhel-7-server-extras-rpms" \
    --enable="rhel-7-server-optional-rpms" \
--enable="rhel-7-server-ose-3.1-rpms"
(2)将以上4个频道的 rpm 包备份到本地
reposync -p /opt/ose -n;
tar zcvf ose-3.1-repo.tar.gz /opt/ose

3. 获取 docker images
(1)获取 openshift 3.1 自带的 docker images
REGISTRY="registry.access.redhat.com";PTH="openshift3";VERSION="v3.1.0.4";
docker pull $REGISTRY/$PTH/ose-haproxy-router:$VERSION ; \
docker pull $REGISTRY/$PTH/ose-deployer:$VERSION ; \
docker pull $REGISTRY/$PTH/ose-sti-builder:$VERSION ; \
docker pull $REGISTRY/$PTH/ose-docker-builder:$VERSION ; \
docker pull $REGISTRY/$PTH/ose-pod:$VERSION ; \
docker pull $REGISTRY/$PTH/ose-keepalived-ipfailover:$VERSION ; \
docker pull $REGISTRY/$PTH/ose-docker-registry:$VERSION; \
docker pull $REGISTRY/rhscl/python-27-rhel7:latest; \
docker pull $REGISTRY/rhscl/perl-520-rhel7:latest; \
docker pull $REGISTRY/openshift3/nodejs-010-rhel7:latest; \
docker pull $REGISTRY/jboss-amq-6/amq62-openshift:latest; \
docker pull $REGISTRY/openshift3/mysql-55-rhel7:latest; \
docker pull $REGISTRY/openshift3/php-55-rhel7:latest; \
docker pull $REGISTRY/openshift3/ruby-20-rhel7:latest; \
docker pull $REGISTRY/openshift3/jenkins-1-rhel7:latest; \
docker pull $REGISTRY/rhscl/python-34-rhel7:latest; \
docker pull $REGISTRY/rhscl/postgresql-94-rhel7:latest; \
docker pull $REGISTRY/jboss-webserver-3/webserver30-tomcat7-openshift:1.1-2; \
docker pull $REGISTRY/rhscl/mysql-56-rhel7:latest; \
docker pull $REGISTRY/rhscl/ruby-22-rhel7:latest; \
docker pull $REGISTRY/openshift3/mongodb-24-rhel7:latest; \
docker pull $REGISTRY/rhscl/mongodb-26-rhel7:latest; \
docker pull $REGISTRY/jboss-webserver-3/webserver30-tomcat8-openshift:1.1; \
docker pull $REGISTRY/openshift3/postgresql-92-rhel7:latest; \
docker pull $REGISTRY/jboss-eap-6/eap64-openshift:1.1; \
docker pull $REGISTRY/openshift3/perl-516-rhel7:latest; \
docker pull $REGISTRY/rhscl/php-56-rhel7:latest; \
docker pull $REGISTRY/openshift3/python-33-rhel7:latest;
(2)将 Docker images 以本地文件形式存储
mkdir /opt/images && cd /opt/images;
for i in `docker images|grep -v REPOSITORY|awk '{print $1":"$2}'` ; do docker save -o $(echo $i|awk -F " /" '{print $NF}'|tr ":" "-"|tr "/" "-").tar $i ;done;

4. 获取测试样例程序代码
wget https://codeload.github.com/openshift/cakephp-ex/zip/master

EAP_051:从 exclude org.apache.httpcomponents 不起作用说起

环境:OS X EI Capitan 10.11.6 + JBoss EAP 6.4.0 + Redis 3.2.3

问题重现步骤:
(1)启动 redis
(2)启动 jboss eap
(3)部署 cas.war

控制台抛出异常,web 应用发布不成功。
ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/cas-bad]] (ServerService Thread Pool -- 102) JBWEB000287: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'logoutManager' defined in ServletContext resource [/WEB-INF/spring-configuration/applicationContext.xml]: Cannot resolve reference to bean 'noRedirectHttpClient' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'noRedirectHttpClient': FactoryBean threw exception on object creation; nested exception is java.lang.NoSuchMethodError: org.apache.http.impl.client.HttpClientBuilder.setSSLHostnameVerifier(Ljavax/net/ssl/HostnameVerifier;)Lorg/apache/http/impl/client/HttpClientBuilder;

经过检查,发现是 JBoss EAP 本身自带的 httpcomponents 版本太旧,没有方法 setSSLHostnameVerifier,于是导致异常。

于是在WEB-INF/lib 下增加高版本的 httpcomponents,并增加 WEB-INF/jboss-deployment-structure.xml,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
<deployment>
<exclusions>
 <module name="org.apache.httpcomponents"/>
<module name="org.apache.commons.logging" />
<module name="org.apache.log4j" />
<module name="org.slf4j" />
<module name="org.slf4j.impl" />
<module name="org.jboss.logging.jul-to-slf4j-stub" />
<module name="org.jboss.stdio" />
   <module name="org.jboss.netty"/>
</exclusions>
</deployment>
</jboss-deployment-structure>

重新打成 war 包,jar -cvf cas.war META-INF/ WEB-INF/,并重新部署。

发现问题依旧,这是怎么回事?

修改 standalone.conf,增加 -verbose:class 参数
JAVA_OPTS="-Xms1303m -Xmx1303m -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true -verbose:class"

发现类的加载路径中,加载的是 modules 下面的httpcomponents,难道说 exclude org.apache.httpcomponents 没起作用?!

使用命令查找 modules 目录下,所有含有name="org.apache.httpcomponents" export="true"的xml文件。
grep -n -R --include="*.xml" 'name="org.apache.httpcomponents" export="true"' .
输出如下:
./system/layers/base/org/jboss/resteasy/resteasy-jaxrs/main/module.xml:47:        <module name="org.apache.httpcomponents" export="true"/>

打开 ./system/layers/base/org/jboss/resteasy/resteasy-jaxrs/main/module.xml,内容如下:
<module xmlns="urn:jboss:module:1.1" name="org.jboss.resteasy.resteasy-jaxrs">

    <resources>
        <resource-root path="async-http-servlet-3.0-2.3.10.Final-redhat-1.jar"/>
        <resource-root path="resteasy-jaxrs-2.3.10.Final-redhat-1.jar"/>
        <!-- Insert resources here -->
    </resources>

    <dependencies>
        <module name="javax.api"/>
        <module name="javax.annotation.api"/>
        <module name="javax.activation.api"/>
        <module name="javax.ws.rs.api"/>
        <module name="org.apache.commons.codec" />
        <module name="org.apache.httpcomponents" />
        <module name="org.apache.log4j"/>
        <module name="org.scannotation.scannotation" />
        <module name="org.slf4j" />
        <module name="javax.servlet.api"/>
        <module name="org.apache.commons.io"/>
        
        <!-- exported -->
        <module name="org.apache.httpcomponents" export="true"/>
        <module name="org.jboss.logging" export="true"/>
    </dependencies>
</module>

也就是说,虽然在 WEB-INF/jboss-deployment-structure.xml 中 exclude org.apache.httpcomponents,但是由于加载了 org.jboss.resteasy.resteasy-jaxrs module,而 rest easy 加载了org.apache.httpcomponents,所以最终 org.apache.httpcomponents,还是被加载了。

找到了问题根源,修改方法也简单了,
只要在 WEB-INF/jboss-deployment-structure.xml 中,再增加一行,把 rest easy 给 exclude 就好了。
<module name="org.jboss.resteasy.resteasy-jaxrs"/>

当然,你也可以把  ./system/layers/base/org/jboss/resteasy/resteasy-jaxrs/main/module.xml 中的 <module name="org.apache.httpcomponents" export="true"/> 这一行的 export="true" 改成 "false"。
但是由于 modules 下面的东西是系统自带的,在以后的升级中,可能会被改动,所以用户最好还是不要修改。

EAP_050:加载定制的 org.apache.httpcomponents module

环境:OS X EI Capitan 10.11.3 + JBoss EAP 6.4.0

1. 为了能够看到类的加载路径,修改 standalone.conf,增加 -verbose:class 参数
JAVA_OPTS="-Xms1303m -Xmx1303m -XX:MaxPermSize=256m -Djava.net.preferIPv4Stack=true -verbose:class"

2. 修改 index.jsp,修改后内容如下:
<html>
  <head>
    <title>JBoss Module Testing
    </title>
  </head>
  <body>

    <%
     org.apache.http.impl.client.DefaultHttpClient client = new org.apache.http.impl.client.DefaultHttpClient();
   
System.out.println("### The class of " + client + " is " + client.getClass().getName());
System.out.println("### Its classloader is " + client.getClass().getClassLoader());
out.println("### The class of " + client + " is " + client.getClass().getName());
out.println("### Its classloader is " + client.getClass().getClassLoader());
    %>
    Hi Check the Console/Log of your JBoss
  </body>
</html>

3. 有两种方式可以加载定制的org.apache.httpcomponents module

3.1. 方式一:以 module 的方式增加
(1)修改 jboss-deployment-structure.xml,修改后内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
   <deployment>
       <exclusions>
           <module name="org.apache.httpcomponents" />
       </exclusions>
       <dependencies>
           <module name="org.apache.httpcomponents" slot="4.4.1"/>
       </dependencies>
   </deployment>
</jboss-deployment-structure>
(2)在 EAP_HOME/modules/system/layers/base/org/apache/httpcomponents/ 目录下创建 4.4.1 目录,并把 httpclient-4.4.1.jar 和 httpcore-4.4.1.jar 复制到该目录下。
创建一个 module.xml 文件,内容如下:
<module xmlns="urn:jboss:module:1.1" name="org.apache.httpcomponents" slot="4.4.1">
    <properties>
        <property name="jboss.api" value="private"/>
    </properties>

    <resources>
        <resource-root path="httpclient-4.4.1.jar"/>
        <resource-root path="httpcore-4.4.1.jar"/>
        <resource-root path="httpmime-4.3.6.redhat-1.jar"/>
        <!-- Insert resources here -->
    </resources>

    <dependencies>
        <module name="javax.api"/>
        <module name="org.apache.commons.codec"/>
        <module name="org.apache.commons.logging"/>
        <module name="org.apache.james.mime4j"/>
    </dependencies>
</module>
(3)重新打包部署
cd /Users/maping/mygit/CustomModuleTest/my-webapp
mvn clean package
(4)访问 http://localhost:8080/my-webapp/index.jsp
在 Console 中会看到如下输出:
[Loaded org.apache.http.client.HttpClient from jar:file:/Users/maping/Redhat/eap/jboss-eap-6.4/modules/system/layers/base/org/apache/httpcomponents/4.4.1/httpclient-4.4.1.jar!/]
[Loaded org.apache.http.impl.client.CloseableHttpClient from jar:file:/Users/maping/Redhat/eap/jboss-eap-6.4/modules/system/layers/base/org/apache/httpcomponents/4.4.1/httpclient-4.4.1.jar!/]
[Loaded org.apache.http.impl.client.AbstractHttpClient from jar:file:/Users/maping/Redhat/eap/jboss-eap-6.4/modules/system/layers/base/org/apache/httpcomponents/4.4.1/httpclient-4.4.1.jar!/]
[Loaded org.apache.http.impl.client.DefaultHttpClient from jar:file:/Users/maping/Redhat/eap/jboss-eap-6.4/modules/system/layers/base/org/apache/httpcomponents/4.4.1/httpclient-4.4.1.jar!/]
说明是从 EAP_HOME/modules/system/layers/base/org/apache/httpcomponents/4.4.1/httpclient-4.4.1.jar 加载到 org.apache.http.client.HttpClient 等类的。

3.2. 方式二:直接添加在 WEB-INF/lib 目录下
(1)修改 jboss-deployment-structure.xml,修改后内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
   <deployment>
       <exclusions>
           <module name="org.apache.httpcomponents" />
       </exclusions>    
   </deployment>
</jboss-deployment-structure>
(2)在 WEB-INF 目录下增加 lib 目录,并把 httpclient-4.4.1.jar 和 httpcore-4.4.1.jar 复制到该目录下。
(3)重新打包部署
cd /Users/maping/mygit/CustomModuleTest/my-webapp
mvn clean package
(4)访问 http://localhost:8080/my-webapp/index.jsp
在 Console 中会看到如下输出:
[Loaded org.apache.http.client.HttpClient from vfs:/content/my-webapp.war/WEB-INF/lib/httpclient-4.4.1.jar]
[Loaded org.apache.http.impl.client.CloseableHttpClient from vfs:/content/my-webapp.war/WEB-INF/lib/httpclient-4.4.1.jar]
[Loaded org.apache.http.impl.client.AbstractHttpClient from vfs:/content/my-webapp.war/WEB-INF/lib/httpclient-4.4.1.jar]
[Loaded org.apache.http.impl.client.DefaultHttpClient from vfs:/content/my-webapp.war/WEB-INF/lib/httpclient-4.4.1.jar]
[Loaded org.apache.http.client.ClientProtocolException from vfs:/content/my-webapp.war/WEB-INF/lib/httpclient-4.4.1.jar]
说明是从 WEB-INF/lib/httpclient-4.4.1.jar 加载到 org.apache.http.client.HttpClient 等类的。

EAP_049:EAP 6 类加载机制(三)

环境:OS X EI Capitan 10.11.3 + JBoss EAP 6.4.0

1. 为应用增加 explicit dependency
dependencies 可以使用两种不同的方法增加:

1.1. 增加 MANIFEST.MF 文件
(1)对于 .war 或 .jar 文件,在 META-INF 目录增加 MANIFEST.MF 文件。
(2)对于 .ear 文件,在 META-INF 目录增加 MANIFEST.MF 文件。
MANIFEST.MF 文件内容可以如下:
Dependencies: org.javassist, org.apache.velocity
Dependencies: org.javassist optional, org.apache.velocity
Dependencies: org.javassist, org.apache.velocity export

1.2 增加 jboss-deployment-structure.xml 文件
jboss-deployment-structure.xml 是 JBoss EAP 6 的新特性,它可以控制部署时类加载。 
(1)对于 .war 文件,在 WEB-INF 目录增加 jboss-deployment-structure.xml 文件。
(2)对于 .jar 文件,在 META-INF 目录增加 jboss-deployment-structure.xml 文件。
(3)对于 .ear 文件,在 META-INF 目录增加 jboss-deployment-structure.xml 文件。
jboss-deployment-structure.xml 文件内容可以如下:
<jboss-deployment-structure>
  <deployment>
    <dependencies>
      <module name="org.javassist" optional="true"/>
      <module name="org.apache.velocity" export="true" />
    </dependencies>
  </deployment>
</jboss-deployment-structure>

2. 防止一个 module 被隐含加载
<jboss-deployment-structure>
  <deployment>
    <exclusions>
      <module name="org.javassist" />
      <module name="org.dom4j" />
    </exclusions>
  </deployment>
</jboss-deployment-structure>

3. exclude subsystem
<exclude-subsystems>
  <subsystem name="SUBSYSTEM_NAME" />
</exclude-subsystems>

4. .ear 中的 subdeployments isolated
默认情况下,<ear-subdeployments-isolated>false</ear-subdeployments-isolated>
这表明:
(1).war subdeployment 隐含依赖 parent module 和 EJB Jar module。
(2)EJB JAR subdeployments 隐含依赖 parent module 和其它的 EJB JAR subdeployments。
注意,没有 subdeployment 隐含依赖 .war subdeployment,但是每个 subdeployment 都可以配置依赖其它的 subdeployment。
如果需要更高的隔离性,可以 <ear-subdeployments-isolated>true</ear-subdeployments-isolated>
这表明每个 subdeployment 都不隐含依赖其它 subdeployment。
(1).war subdeployment 不隐含依赖 parent module 和 EJB Jar module。
(2)EJB JAR subdeployments 不隐含依赖 parent module 和其它的 EJB JAR subdeployments。

参考文献:
1. 《JBoss_Enterprise_Application_Platform-6.4-Development_Guide-en-US.pdf》第三章 Class Loading and Modules
2. http://www.mastertheboss.com/jboss-server/jboss-as-7/jboss-as-7-classloading?showall=
3. http://www.mastertheboss.com/jboss-server/jboss-as-7/jboss-as-7-classloading?start=1
4. http://www.mastertheboss.com/jboss-server/jboss-as-7/jboss-as-7-classloading?showall=&start=2
5. http://stackoverflow.com/questions/34293402/jboss-how-can-to-exclude-javax-validation-in-jboss-deployment-structure

EAP_048:EAP 6 类加载机制(二)

环境:OS X EI Capitan 10.11.3 + JBoss EAP 6.4.0

1. 部署应用时的类加载机制

1.1 部署 .war
.war 文件被看成一个单独的 module,使用同一个类加载器加载 WEB-INF/lib 目录下的类和 WEB-INF/classes 目录下的类。

1.2 部署 .ear
.ear 由多个 module 组成,如下:
(1)根目录下的 lib/ 目录是一个单独的 module,称之为 parent module。
(2)其中的每一个 .war 是一个单独的 module。
(3)其中的每一个 EJB JAR 是一个单独的 module。

.ear 中的 .war 和 .jar 称之为 subdeployment,它们自动依赖 parent module。
但 .ear 中的 .war 和 .jar 彼此之间不会自动互相依赖,这个称之为 subdeployment isolation。
不过这个特性可以 disabled,可以为某个 .ear 设置,也可以设置在整个 EAP 上。
subdeployment 之间可以使用 explicit dependencies 定义依赖关系,就像 module 之间的依赖关系一样。

2. 类加载优先级
(1)首先加载 implicit dependencies
implicit dependencies 是 EAP 自动加载的,比如 Java EE 6 API。
(2)其次加载 explicit dependencies
explicit dependencies 可以定义在应用的 MANIFEST.MF 文件中,或者 jboss-deployment-structure.xml 文件中。
(3)接着加载应用本地的类
比如 WEB-INF/lib 目录下的类 和 WEB-INF/classes 目录下的类。
(4)最后加载 inter-deployment dependencies
这些是在 .ear 中定义的依赖,比如 依赖 .ear 中的 lib/,或者 .ear 中的 EJB jars。

3. 动态 module 的命名规则
(1).war 和 .jar 文件:deployment.DEPLOYMENT_NAME
比如 inventory.war 和 store.jar 的 module 名称是 deployment.inventory.war 和 deployment.store.jar。
(2).ear 中的 subdeployments:deployment.EAR_NAME.SUBDEPLOYMENT_NAME
比如 accounts.ear 中的 reports.war 的 module 名称是 deployment.accounts.ear.reports.war。

参考文献:
1. 《JBoss_Enterprise_Application_Platform-6.4-Development_Guide-en-US.pdf》第三章 Class Loading and Modules
2. http://www.mastertheboss.com/jboss-server/jboss-as-7/jboss-as-7-classloading?showall=
3. http://www.mastertheboss.com/jboss-server/jboss-as-7/jboss-as-7-classloading?start=1
4. http://www.mastertheboss.com/jboss-server/jboss-as-7/jboss-as-7-classloading?showall=&start=2
5. http://stackoverflow.com/questions/34293402/jboss-how-can-to-exclude-javax-validation-in-jboss-deployment-structure

2016年3月17日星期四

EAP_047:EAP 6 类加载机制(一)

环境:OS X EI Capitan 10.11.3 + JBoss EAP 6.4.0

在实际使用中,经常会遇到如下问题:
(1)开发者想使用一个新版本的类库,但 EAP 已经提供了一个旧版本的类库,如何在应用中使用指定版本的类库?
(2)如何在不同的应用中,使用不同版本的类库?

1. EAP 6 加载方式
JBoss EAP 6 使用 module class loading 方式加载类,开发者可以细粒度地控制应用需要加载的类,比如忽略 EAP 提供的类库,而使用自己的类库。
module 分两种:静态 module 与 动态 module。
静态 module 与 动态 module 只有打包方式的不同,加载方式是一样的。
module 只有在需要的时候才被加载。

1.1 静态 module
在 EAP_HOME/modules 目录下的都是静态 module,以 system/layers/base 目录开头,该目录下都是红帽提供的类库,主要是为了区分第三方的类库。
如果要加载第三方类库,请直接 EAP_HOME/modules 目录下创建在第三方类路径,不要在 system/layers/base 目录下创建。
这样的话,即使第三方类库已经在 system/layers/base 目录中有了,也会先加载第三方类库。

1.2 动态 module
指的是部署在 EAP 上的各种打包应用,比如 .jar、.war、.ear。
动态 module 由 EAP 运行时加载,module 可以配置 dependencies。

2. dependencies
dependencies 有两种: explicit dependencies 和 implicit dependencies。

2.1 explicit dependencies
静态 module 是定义在 modules.xml 文件中的,动态 module 是定义在 MANIFEST.MF 文件或 jboss-deployment-structure.xml 文件中的。
explicit dependencies 可以设置成 optional,如果该 dependency 加载失败,不影响整个 module 的加载。
但有一点要注意,如果加载 module 时,optional dependencies 加载失败,那么即使以后该 optional dependencies 可以加载了,也不会加载了。

2.2 implicit dependencies
implicit dependencies 是 EAP 自动加载的,比如 Java EE 6 API 就是 implicit dependencies。
部署时,通过在 jboss-deployment-structure.xml 文件中定义,可以配置 exclude 指定的 implicit dependencies。
比如应用不想使用某个 implicit dependency,而想使用自己的类库。

2.3 export=“true”
module A 依赖 module B,module B 依赖 module C。
module A 可以访问 module B 的类,module B 可以访问 module C 的类,但是 module A 不可以访问 module C 的类。
要想 module A 可以访问 module C 的类,其依赖的module B 中必须增加 export="true"。
<dependencies>
  <module name="moduleB" slot="1.1" export="true"/>
</dependencies>

参考文献:
1. 《JBoss_Enterprise_Application_Platform-6.4-Development_Guide-en-US.pdf》第三章 Class Loading and Modules
2. http://www.mastertheboss.com/jboss-server/jboss-as-7/jboss-as-7-classloading?showall=
3. http://www.mastertheboss.com/jboss-server/jboss-as-7/jboss-as-7-classloading?start=1
4. http://www.mastertheboss.com/jboss-server/jboss-as-7/jboss-as-7-classloading?showall=&start=2
5. http://stackoverflow.com/questions/34293402/jboss-how-can-to-exclude-javax-validation-in-jboss-deployment-structure

2016年3月16日星期三

EAP_046:加载不同版本的定制化 modules (摘录+整理)

环境:OS X EI Capitan 10.11.3 + JBoss EAP 6.4.0

1. 创建目录
(1)mkdir -p ~/mygit/CustomModuleTest
(2)cd ~/mygit/CustomModuleTest
(3)mkdir -p aaa/bbb/main aaa/bbb/1.0

2. 创建 1.0 版本的 module
(1)cd ~/mygit/CustomModuleTest/aaa/bbb/1.0
(2)vim Test.java
package aaa.bbb;

public class Test {

    static {
        System.out.println("nntaaa.bbb.Test class Loaded  [VERSION-1.0]");
    }

    public String sayHello(String name) {
        System.out.println("nntaaa.bbb.Test sayHello() called");
        return "Mr. " + name;
    }
}
(3)vim module.xml
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="aaa.bbb" slot="1.0">
    <resources>
        <resource-root path="Test1.0.jar"/>
    </resources>
</module>
(4)javac -d . Test.java
(5)jar cvf Test1.0.jar Test.java aaa/

3. 创建 1.2 版本的 module
(1)cd ~/mygit/CustomModuleTest/aaa/bbb/main
(2)vim Test.java
package aaa.bbb;

public class Test {

    static {
        System.out.println("nnt[1.2] aaa.bbb.Test class Loaded  [VERSION-1.2]");
    }

    public String sayHello(String name) {
        System.out.println("nnt[1.2] aaa.bbb.Test sayHello() called");
        return "Mr. [1.2] " + name;
    }
}
(3)vim module.xml
<?xml version="1.0" encoding="UTF-8"?>
<module xmlns="urn:jboss:module:1.1" name="aaa.bbb">
  <resources>
    <resource-root path="Test1.2.jar"/>
  </resources>
</module>
(4)javac -d . Test.java
(5)jar cvf Test1.2.jar Test.java aaa/

4. 把两个 modules 复制到 JBOSS_HOME/modules 目录下
(1)cd ~/mygit/CustomModuleTest
(2)cp -r aaa /Users/maping/Redhat/eap/jboss-eap-6.4/modules/

5. 编写 web 应用
(1)index.jsp
<html>
  <head>
    <title>JBoss Module Testing
    </title>
  </head>
  <body>

    <%
       aaa.bbb.Test test=new aaa.bbb.Test();
       System.out.println("test.sayHello(JBossAS7) = "+test.sayHello("JBossAS7"));
       out.println("test.sayHello(JBossAS7) = "+test.sayHello("JBossAS7"));
    %>
    Hi Check the Console/Log of your JBoss
  </body>
</html>
(2)WEB-INF/web.xml
<web-app>
  <display-name>
    Module Demo JBposs AS7
  </display-name>

  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

</web-app>
(3)WEB-INF/jboss-deployment-structure.xml
<?xml version="1.0" encoding="UTF-8"?>
<jboss-deployment-structure>
  <deployment>
    <dependencies>
      <module name="aaa.bbb" slot="1.0"/>
    </dependencies>
  </deployment>
</jboss-deployment-structure>

6. 测试
启动 EAP
(1)打包并部署应用,访问 http://localhost:8080/my-webapp/index.jsp
会发现此时,在Console中,输出的是1.0版本的信息。
(2)修改WEB-INF/jboss-deployment-structure.xml,去掉slot="1.0",重新打包,发布,访问。
会发现此时,在Console中,输出的是1.2版本的信息。

参考文献:
1. http://middlewaremagic.com/jboss/?p=1933

ActiveMQ_021:命令行操作

环境:OS X EI Capitan 10.11.3 + ActiveMQ 5.13

可以使用 ./activemq --help 查看都有哪些命令。
Tasks:
    browse                   - Display selected messages in a specified destination.
    bstat                    - Performs a predefined query that displays useful statistics regarding the specified broker
    consumer                 - Receives messages from the broker
    create                   - Creates a runnable broker instance in the specified path.
    decrypt                  - Decrypts given text
    dstat                    - Performs a predefined query that displays useful tabular statistics regarding the specified destination type
    encrypt                  - Encrypts given text
    export                   - Exports a stopped brokers data files to an archive file
    list                     - Lists all available brokers in the specified JMX context
    producer                 - Sends messages to the broker
    purge                    - Delete selected destination's messages that matches the message selector
    query                    - Display selected broker component's attributes and statistics.
    start                    - Creates and starts a broker using a configuration file, or a broker URI.
    stop                     - Stops a running broker specified by the broker name.

Task Options (Options specific to each task):
    --extdir dir>  - Add the jar files in the directory to the classpath.
    --version       - Display the version information.
    -h,-?,--help    - Display this help information. To display task specific help, use Main [task] -h,-?,--help

Task Data:
    - Information needed by each specific task.

JMX system property options:
    -Dactivemq.jmx.url=<jmx service uri> (default is: 'service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi')
    -Dactivemq.jmx.user=<user name>
    -Dactivemq.jmx.password=<password>

具体某个命令的用法可以用 ./activemq command --help。
比如 : ./activemq producer --help
Usage: producer [OPTIONS]
Description: Demo producer that can be used to send messages to the broker
Options :
    [--brokerUrl                                   URL] - connection factory url; default ActiveMQConnectionFactory.DEFAULT_BROKER_URL
    [--user                                         ..] - connection user name
    [--password                                     ..] - connection password
    [--destination               queue://..|topic://..] - producer destination; default queue://TEST
    [--persistent                           true|false] - use persistent or non persistent messages; default true
    [--messageCount                                  N] - number of messages to send; default 1000
    [--sleep                                         N] - millisecond sleep period between sends or receives; default 0
    [--transactionBatchSize                          N] - use send transaction batches of size N; default 0, no jms transactions
    [--parallelThreads                               N] - number of threads to run in parallel; default 1
    [--msgTTL                                        N] - message TTL in milliseconds
    [--messageSize                                   N] - size in bytes of a BytesMessage; default 0, a simple TextMessage is used
    [--textMessageSize                               N] - size in bytes of a TextMessage, a Lorem ipsum demo TextMessage is used
    [--message                                      ..] - a text string to use as the message body
    [--payloadUrl                                  URL] - a url pointing to a document to use as the message body
    [--msgGroupID                                   ..] - JMS message group identifier

比如 : ./activemq consumer --help
Usage: consumer [OPTIONS]
Description: Demo consumer that can be used to receive messages to the broker
Options :
    [--brokerUrl                                   URL] - connection factory url; default ActiveMQConnectionFactory.DEFAULT_BROKER_URL
    [--user                                         ..] - connection user name
    [--password                                     ..] - connection password
    [--destination               queue://..|topic://..] - consumer destination; default queue://TEST
    [--messageCount                                  N] - number of messages to send; default 1000
    [--sleep                                         N] - millisecond sleep period between sends or receives; default 0
    [--ackMode     AUTO_ACKNOWLEDGE|CLIENT_ACKNOWLEDGE] - the type of message acknowledgement to use; default auto acknowledge
    [--batchSize                                     N] - batch size for transactions and client acknowledgment (default 10)
    [--durable                              true|false] - create durable topic
    [--clientId                                     ..] - connection client id; must be set for durable topics
    [--parallelThreads                               N] - number of threads to run in parallel; default 1
    [--bytesAsText                          true|false] - try to treat a BytesMessage as a text string

1. 生产消息
./activemq producer --brokerUrl tcp://localhost:61616 --user admin --password admin --destination queue://testQueue --messageSize 1024 --messageCount 1000 --parallelThreads 10

2. 浏览而不消费消息
./activemq browse --amqurl tcp://localhost:61616 --user admin --password admin testQueue

3. 消费消息
./activemq consumer --brokerUrl tcp://localhost:61616 --user admin --password admin --destination queue://testQueue --messageCount 1000 --parallelThreads 10

4. 显示 Broker 上所有 Queue 的统计信息(Broker 需要打开 JMX)
./activemq dstat queues

5. 显示 Broker 上所有 Topic 的统计信息(Broker 需要打开 JMX)
./activemq dstat topics

6. 显示 Broker 的统计信息(Broker 需要打开 JMX)
./activemq bstat

7. 显示指定 Queue 的属性信息(Broker 需要打开 JMX)
./activemq query -QQueue=testQueue

8. 显示指定 Queue 的属性信息(Broker 需要打开 JMX)
./activemq query -QTopic=testTopic

参考文献:
1.  http://activemq.apache.org/activemq-command-line-tools-reference.html

AlphaGo_007:围棋人机大战 AlphaGo 4 : 1 李世石

李世石九段停钟认负的一刻,脸上写满了不甘心,当韩国转播的美女棋手上来指出他的失误的时候,
他双手掩面,用力搓了搓脸,身体重重地靠在了沙发上,嘴里不停地念叨着什么,眼泪似乎又要流出来。
看来他实在不清楚这局棋输在哪里?明明是我一直占优的局面啊。

在新闻发布会上,李世石庄重地打上了领带,距离他上一次打领带,已经过去了 10 年。
3月12日,是李世石结婚 10 周年的纪念日,也是他 0:3 彻底输掉人机大战的这一天。
这一天,就以这样的方式载入史册。

在新闻发布会上,倔强的李世石重复了他在3月12日的话:“这不是人类的失败,是我本人的失败。”
也许柯洁们觉得李世石不够资格代表人类出战本次人机大战,但 1:4 惨败,还是超出了大多数人的预料。
但输了就是输了,李世石赢不了 AlphaGo,谁敢说一定能赢 AlphaGo 呢?

AlphaGo 现在无法听到这些,它体会不到李九段的失落,它仍然以惊人地速度学习着。
我似乎看到未来这样的一天:
AlphaGo 同时连线对弈全球甄选的1000名顶级围棋职业选手,中国象棋特级大师,国际象棋特级大师。
最终的结果是 AlphaGo 取得全胜:1000 : 0。

“Even a Brick Wants to Be Something”,谁敢说一台机器没有这样的“野心”。

“我觉得我们太傲慢了” 中国围棋队总教练俞斌这样说道。
我觉得这句话,可以改成 “我觉得人类太傲慢了”。

作为一名热爱围棋的计算机工程师,我不知道是该高兴还是沮丧,但我知道,一个新的时代不可阻挡地来临了。



2016年3月14日星期一

AlphaGo_006:围棋人机大战 AlphaGo 3 : 1 李世石

当棋局进行到 73 手时,AlphaGo “自信满满”地下出了小飞飞罩,一时间上方黑阵中白子顿时感觉有些透不过气来。
白方情势已经万分危急,这里是决定胜负的一战,必须拿出有效的手段才行,小李开始长考。
直播间中,古力摆了很多变化,依然没有成功突围的手段,难道机器已经算清楚了,上方的白棋已经全部阵亡?
联想到上一盘棋 AlphaGo 恐怖的计算力,古力不禁连连摇头。
时间一分一秒的过去,小李还是没有出手。
5 分钟
10 分钟
15 分钟
......

终于,在经历了长达16分钟的长考后,李世石九段下出了神之一手:上帝之挖。
此时,小李距读秒仅剩下4分钟,而 AlphaGo 还有一个多小时。
但正是这一手,使得白方棋子如溃堤的洪水,冲破黑阵,逃出生天,一下子扭转了整个局面,并且最终获得了胜利。

这局棋让我感觉意外的地方是:AlphaGo 的局部计算能力并没有超过人类顶级棋手。

说到计算,围棋里最难的是形势判断,因为不清楚形势的好坏,就无法知道下一手下到哪里最好。
形势判断,需要根据的东西很多,比如:棋型、厚薄、外势、实地等等。
古往今来,没有一本围棋书可以教人把这些“虚”的东西量化,从而得出一个明确的结论。
人类棋手靠的更多的经验的积累,就是职业棋手常说的棋感,高手和低手的分野也在这里。
纵观这四局棋,AlphaGo 的棋感相当好,这也许是因为它学习和积累了大量人类顶尖棋手的棋感。

而局部计算对职业棋手而言,相对简单,因为只需要直线计算,加上计算的旁支,一名优秀的职业棋手可以最多计算50多步。
而 AlphaGo 的局部计算能力在前三局表现的也相当好,一度让人以为在局部,人类是无法和机器抗衡的。
现在看来,它也会犯错,就看对局者能不能抓住。

当李世石下出 78 手惊天一挖时,AlphaGo 发现之前的飞罩手段并不成立,于是让人瞠目结舌的一幕出现了:
AlphaGo 开始连续跑死子,水平一下子从超 9 段变成了 18k,场面让人一时大跌眼镜,哭笑不得。
其实,只要它从全局出发,“稳住阵脚”,还是可以保持住优势的,但它这一次“乱了方寸”。

看来 AlphaGo 不愿意否定自己之前的错误,莫非它的程序里没有纠错机制?

不管怎样,李世石九段取得了人机大战的首盘胜利,恭喜李世石!



2016年3月13日星期日

AlphaGo_005:围棋人机大战 AlphaGo 3 : 0 李世石

副题:挽歌,或是为了告别的聚会

纵观本局全局,AlphaGo 在棋盘上每一处落子,犹如铁甲之师不断咬啮着李世石的肉体之躯。
此局还澄清了有没有禁止打劫的问题,事实证明,允许打劫,并且 AlphaGo 很会打劫。
面对机器的狂弑虐杀,李世石表现得像古罗马斗兽场的最后一个角斗士,不断地跟机器狂舞对攻,全然不顾早已遍体鳞伤的身体。
整盘棋最让人感动的一幕,出现在第125手,此时,黑白的差距已经越来越明显,小李也早已读秒,是就此投降,还是继续拼搏,他必须在1分钟内做出抉择。
身经百战的小李,此时残躯支立,衣袂飘飘,突然间,袖口寒光一闪,小李祭出曾经独步天下的小李飞刀,毅然决然地发出绝望一击,深深地打入下方的白茫茫的雪域高原,在这里做活的难度犹如在珠峰上跑马拉松。
这是最后的死战,AlphaGo 用一只手地死死卡住小李的喉咙,而用另外一只手打开了香槟......
终于,李世石在白茫茫的冰雪大地倒下了,流尽了最后一滴血,像最后一个莫西干人,悲壮地倒在了他深爱着的这片土地。

此局表现了一名大棋士的最后尊严:宁战死,勿苟降。

这个不是梦境,机器战胜人类围棋高手的这一天终于来了,这一天早晚会来,只是比我想象的要快的多。
2016年3月12日,计算机攻陷了人类棋类智力的最后一个高峰,我们都是见证者。
这是围棋史的最重要的一次比赛,超过以往任何一次世界比赛。
这是围棋的挽歌,这是人工智能的胜利,这是围棋史上最盛大的聚会,这是人工智能的重要里程碑。
不可否认,围棋将会走中象和国象的道路,逐渐失去关注度。

恭喜 AlphaGo,恭喜戴密斯·哈萨比斯,祝贺 Deep Mind 团队,向 Google 致敬,一个伟大的公司,一个让人肃然起敬的公司。
更要向李世石致敬,作为10年世界围棋最强者,手握14个世界冠军,在围棋史上已经功名成就,还勇于接受这个挑战,非常难能可贵。
特别是在这盘棋,李世石体现了一名大棋士的风骨,更体现了一个人的精神:人可以被毁灭,但不可以被打败。

最后我也要感谢关心我的朋友,你们的留言我都看到了,我解释下我打这个赌的三个初衷:
(1)希望分担李世石的痛苦,虽然这有些一厢情愿。
(2)对李世石前两局的表现表示强烈不满,希望能够激励他下出一盘属于自己风格的围棋。
(3)对我自己围棋生涯的一个总结和告别,我没有遗憾,因为我努力达到了自己围棋的最高点。
既然输了,我愿赌服输,从此不再用这三个账号下围棋。