RabbitMQ-CookBook-第3章-管理RabbitMQ
本章我们将覆盖:
- 使用虚拟主机
- 配置用户
- 使用SSL
- 实现客户端证书
- 从浏览器中管理RabbitMQ
- 配置RabbitMQ参数
- 开Python程序来监控RabbitMQ
- 自己开发web程序来监控RabbitMQ
一旦安装后,RabbitMQ不需要任何配置就可以工作. 然而,RabbitMQ有许多的配置选项,这些配置选项使得它更为灵活,能工作于多种不同环境中.
在本章中,我们将看到如何改变配置来满足应用程序的需求。同时我们也会展示如何使用应用程序来监控RabbitMQ.
使用虚拟主机
在单个RabbitMQ实例中,可以包含多个不同的,独立的虚拟broker。通过此方式,多个不同应用程序可以不用担心命名冲突来在同一个broker中使用。你可在Chapter03/Recipe01目录中找到简单的java代码, ,除了虚拟主机的使用外,它与本书的第一个食谱中的例子基本相同。
准备
在单个RabbitMQ实例中,可以包含多个不同的,独立的虚拟broker。通过此方式,多个不同应用程序可以不用担心命名冲突来在同一个broker中使用。你可在Chapter03/Recipe01目录中找到简单的java代码, ,除了虚拟主机的使用外,它与本书的第一个食谱中的例子基本相同。
准备
要练习此食谱,你只需要在Linux命令行提示窗口或在Windows启动菜单命令提示中(sbindir)敲一些命令.
如何做
要创建一个新虚拟主机,需要执行下面的步骤:
1. 使用下面的命令来列出可用的虚拟主机:
rabbitmqctl list_vhosts
2. 执行下面的命令来创建一个新虚拟主机book_orders:
rabbitmqctl add_vhost book_orders
3. 列出其交换器:
rabbitmqctl list_exchanges -p book_orders
4. 列出用户权限:
rabbitmqctl list_permissions
rabbitmqctl list_permissions -p book_orders
5. 授权guest用户访问book_orders虚拟主机:
rabbitmqctl set_permissions guest .* .* .* -p book_orders
6. 在Java client library中使用虚拟主机:
factory.setVirtualHost("book_orders");
1. 使用下面的命令来列出可用的虚拟主机:
rabbitmqctl list_vhosts
2. 执行下面的命令来创建一个新虚拟主机book_orders:
rabbitmqctl add_vhost book_orders
3. 列出其交换器:
rabbitmqctl list_exchanges -p book_orders
4. 列出用户权限:
rabbitmqctl list_permissions
rabbitmqctl list_permissions -p book_orders
5. 授权guest用户访问book_orders虚拟主机:
rabbitmqctl set_permissions guest .* .* .* -p book_orders
6. 在Java client library中使用虚拟主机:
factory.setVirtualHost("book_orders");
如何工作
安装后,RabbitMQ只定义了默认虚拟主机 /,我们很容易地通过步骤1中的命令进行检查.
然后我们通过执行rabbitmqctl add_vhost (步骤2)来创建一个新虚拟主机.
在此之后,后面所有的命令都需要使用-p选项来指定新的虚拟主机。如果省略了,后续命令来应用到默认虚拟主机上。
新加的虚拟主机还不能使用,可通过步骤4中的列出权限来快速检查新虚拟主机还没有进行认证,因此不能执行任何操作。
在此之后,后面所有的命令都需要使用-p选项来指定新的虚拟主机。如果省略了,后续命令来应用到默认虚拟主机上。
新加的虚拟主机还不能使用,可通过步骤4中的列出权限来快速检查新虚拟主机还没有进行认证,因此不能执行任何操作。
接下来,我们为默认用户guest在book_orders虚拟主机授予了所有权限(step 5).
自此,我们已经能够在连接工厂中指定新虚拟主机了,这样就可以使得RabbitMQ客户端连接使用新的虚拟主机,而不是默认虚拟主机。
自此,我们已经能够在连接工厂中指定新虚拟主机了,这样就可以使得RabbitMQ客户端连接使用新的虚拟主机,而不是默认虚拟主机。
配置用户
RabbitMQ用户对于broker实例来说是全局的,但每个用户对于每个独立的虚拟主机都可以设置其自己的权限。不同应用程序可使用独立用户和虚拟主机来作到解藕 。然而,同一应用程序可受益于相同虚拟主机的用户权限。我们将看到如何来管理用户以及它们的权限,并且如何在Chapter03/Recipe02 java例子中来使用.
准备
准备
要运行此食谱,我们需要执行一些rabbitmqctl配置命令,并使用java设置来练习这些配置。
如何做
通过执行下面的步骤,我们可以看到如何来管理用户及其权限,以用如何使用它们:
1. 使用各自的密码来创建一些用户:
rabbitmqctl add_user stat_sender password1
rabbitmqctl add_user stat_receiver password2
2. 给它们授予一些权限:
rabbitmqctl set_permissions stat_sender "stat_exchange.*" "stat_.*" "^$"
rabbitmqctl set_permissions stat_receiver "stat_.*" "stat_queue_.*" "(stat_exchange_.*)|(stat_queue_.*)"
3. 让Producer.java使用stat_sender用户来连接RabbitMQ:
factory.setUsername("stat_sender");
factory.setPassword("password1");
4. 然后执行下面的操作:
channel.exchangeDeclare(...);
channel.basicPublish(...);
5. 让Consumer.java使用stat_receiver用户来连接RabbitMQ:
factory.setUsername("stat_receiver");
factory.setPassword("password2");
6. 然后再执行下面的操作:
channel.exchangeDeclare(...);
channel.queueDeclare(...);
channel.queueBind(...);
channel.basicConsume(...);
如何工作
1. 使用各自的密码来创建一些用户:
rabbitmqctl add_user stat_sender password1
rabbitmqctl add_user stat_receiver password2
2. 给它们授予一些权限:
rabbitmqctl set_permissions stat_sender "stat_exchange.*" "stat_.*" "^$"
rabbitmqctl set_permissions stat_receiver "stat_.*" "stat_queue_.*" "(stat_exchange_.*)|(stat_queue_.*)"
3. 让Producer.java使用stat_sender用户来连接RabbitMQ:
factory.setUsername("stat_sender");
factory.setPassword("password1");
4. 然后执行下面的操作:
channel.exchangeDeclare(...);
channel.basicPublish(...);
5. 让Consumer.java使用stat_receiver用户来连接RabbitMQ:
factory.setUsername("stat_receiver");
factory.setPassword("password2");
6. 然后再执行下面的操作:
channel.exchangeDeclare(...);
channel.queueDeclare(...);
channel.queueBind(...);
channel.basicConsume(...);
如何工作
要本练习中,我们创建了两个用户(step 1).为了使用它们,我们需要使用下面的命令来分配权限:
rabbitmqctl set_permissions <username> <conf> <write> <read>
这里, <conf>, <write>, and <read> 是三个正则表达式.指定的<username>将拥有匹配队列,交换器上的配置,写入,读取权限。
在我们的例子中,Producer.java使用stat_sender用户来访问RabbitMQ.在步骤4中,调用了queueDeclare(),因此它必须在名为stat_exchange_03/02交换器上拥有配置权限。然后,它会发布消息到同一个交换器中,因此它也必须拥有写入权限。但消息还会路由到stat_queue_03/02队列中,因此该用户还应该有此队列上的写入权限,否则消息就不能路由到此队列上。通过将写入权限设为正则表达式"stat_.*",就可授权用户将消息发布到交换器和队列中。Producer.java不需要任何的读取权限,因此可通过指定空正则表达式"^$"来禁止读取权限, 就像例子中展示的一样,或者只是一个空字符串。
rabbitmqctl set_permissions <username> <conf> <write> <read>
这里, <conf>, <write>, and <read> 是三个正则表达式.指定的<username>将拥有匹配队列,交换器上的配置,写入,读取权限。
在我们的例子中,Producer.java使用stat_sender用户来访问RabbitMQ.在步骤4中,调用了queueDeclare(),因此它必须在名为stat_exchange_03/02交换器上拥有配置权限。然后,它会发布消息到同一个交换器中,因此它也必须拥有写入权限。但消息还会路由到stat_queue_03/02队列中,因此该用户还应该有此队列上的写入权限,否则消息就不能路由到此队列上。通过将写入权限设为正则表达式"stat_.*",就可授权用户将消息发布到交换器和队列中。Producer.java不需要任何的读取权限,因此可通过指定空正则表达式"^$"来禁止读取权限, 就像例子中展示的一样,或者只是一个空字符串。
另一方面,Consumer.java的用户需要在交换器和队列上都要拥有配置权限,同时也需要读取权限,在我们的食谱中是: "stat_.*"(在例子中也是"(stat_exchange_.*)|(stat_queue_.*)"的同义词)。
Consumer.java为了能将队列绑定到交换器上,它也需要在stat_queue_03/02队列上拥有写入权限.
更多
Consumer.java为了能将队列绑定到交换器上,它也需要在stat_queue_03/02队列上拥有写入权限.
更多
通过用户,我们可以限制限制其对资源的访问,并调整其对分布应用程序中不同组件的权限。
权限角色指的是访问特定AMQP资源的授权:
权限角色指的是访问特定AMQP资源的授权:
- configure: 授权用户可以声明,删除与指定模式匹配的队列和交换器
- write: 授权用户可以在匹配模式的资源上绑定队列和交换器以及发布消息
- read: 授权用户可绑定匹配模式的队列和交换器,并可以消费消息
要了解不同AMQP操作需要的权限,你可以参考http://www.rabbitmq.com/access-control.html.
使用管理插件中的User tags
用户权限只是针对AMQP操作.RabbitMQ管理插件(more details later in this chapter)使用user tags继承了这种权限模型,因此可以分配一个或多个tag字符串给任何用户。
要让用户能够访问管理插件,它必须拥有下面tags中的一个:
rabbitmqctl set_user_tags username administrator
默认guest用户在默认情况下,拥有administrator tag.
用户权限只是针对AMQP操作.RabbitMQ管理插件(more details later in this chapter)使用user tags继承了这种权限模型,因此可以分配一个或多个tag字符串给任何用户。
要让用户能够访问管理插件,它必须拥有下面tags中的一个:
- management: 用户可在其虚拟主机内查看所有队列和交换器
- monitoring: 用户可以访问所有虚拟主机,并能查看所有队列和交换器
- administration: 用户可执行任何管理操作
rabbitmqctl set_user_tags username administrator
默认guest用户在默认情况下,拥有administrator tag.
使用SSL
无论何时,只要当RabbitMQ broker暴露在Internet上,强烈建议使用SSL library来保护连接.
RabbitMQ 自身并没有实现SSL,但它会使用给定语言的证书机制,服务端的Erlang以及Java, .NET,以及任何客户端.
在这里,我们将了解如何使用SSL来作基础保护,以及如何来加密RabbitMQ clients与broker之间的连接.这足可以应对简单的安全攻击。如果没有SSL,用户名和密码都在网络上明文传送。
无论何时,只要当RabbitMQ broker暴露在Internet上,强烈建议使用SSL library来保护连接.
RabbitMQ 自身并没有实现SSL,但它会使用给定语言的证书机制,服务端的Erlang以及Java, .NET,以及任何客户端.
在这里,我们将了解如何使用SSL来作基础保护,以及如何来加密RabbitMQ clients与broker之间的连接.这足可以应对简单的安全攻击。如果没有SSL,用户名和密码都在网络上明文传送。
准备
本例中需要包含下面的前提条件:
如何做
- 一个能运行RabbitMQ broker的Linux OS
- openssl Linux package
- 最新的Erlang包—至少为R14B
- 客户端Java JDK,Linux或window之上
如何做
执行下面的步骤来设置证书颁发机构,并配置服务器:
1. 在服务器上,创建CA目录,就像Chapter03/Recipe03/certificates/01_setup_CA.sh脚本中展示的一样:
mkdir testca
cd testca
mkdir certs private
chmod 700 private
echo 01 > serial
touch index.txt
2.定制openssl配置文件,你可以在Chapter03/Recipe03/certificates/testca/openssl.cnf找到.
3.如Chapter03/Recipe03/certificates/02_create_CA_certificates.sh中展示的一样来创建自签名CA证书:
openssl req -x509 -config openssl.cnf -newkeyrsa:2048
-days 365 -out cacert.pem -outform PEM
-subj /CN=MyTestCA/ -nodes
openssl x509 -in cacert.pem -out cacert.cer -outform DER
4.如Chapter03/Recipe03/certificates/03_create_server_certificates.sh脚本中展示的来创建 RabbitMQ server private key :
openssl genrsa -out key.pem 2048
5.创建服务端证书请求:
openssl req -new -key key.pem -out req.pem -outform PEM
-subj /CN=$(hostname)/O=server/ -nodes
6.在CA目录,请求获得签署证书签名:
1. 在服务器上,创建CA目录,就像Chapter03/Recipe03/certificates/01_setup_CA.sh脚本中展示的一样:
mkdir testca
cd testca
mkdir certs private
chmod 700 private
echo 01 > serial
touch index.txt
2.定制openssl配置文件,你可以在Chapter03/Recipe03/certificates/testca/openssl.cnf找到.
3.如Chapter03/Recipe03/certificates/02_create_CA_certificates.sh中展示的一样来创建自签名CA证书:
openssl req -x509 -config openssl.cnf -newkeyrsa:2048
-days 365 -out cacert.pem -outform PEM
-subj /CN=MyTestCA/ -nodes
openssl x509 -in cacert.pem -out cacert.cer -outform DER
4.如Chapter03/Recipe03/certificates/03_create_server_certificates.sh脚本中展示的来创建 RabbitMQ server private key :
openssl genrsa -out key.pem 2048
5.创建服务端证书请求:
openssl req -new -key key.pem -out req.pem -outform PEM
-subj /CN=$(hostname)/O=server/ -nodes
6.在CA目录,请求获得签署证书签名:
openssl ca -config openssl.cnf -in ../server/req.pem –out
../server/cert.pem -notext -batch –extensions
server_ca_extensions
7.从Chapter03/Recipe03/certificates,将我们刚才创建的CA 证书, 证书,以及server private key, 拷贝到下面的路径:
/usr/local/certificates/testca/cacert.pem
/usr/local/certificates/server/cert.pem
/usr/local/certificates/server/key.pem
8.创建RabbitMQ配置文件: rabbitmq.config, 可从Chapter03/Recipe03/rconfig目录中适当的目录(/etc/rabbitmq):
[
{rabbit, [
{ssl_listeners, [5671]},
{ssl_options, [
{cacertfile,"/usr/local/certificates/testca/cacert.pem"},
{certfile,"/usr/local/certificates/server/cert.pem"},
{keyfile,"/usr/local/certificates/server/key.pem"},
{verify,verify_peer},
{fail_if_no_peer_cert,false}]}
]}
].
9. 重启RabbitMQ server:
rabbitmqctl stop
rabbitmq-server–detached.
当你重启RabbitMQ节点时,Erlang节点也会重启.
10. 在Java client,连接服务端可以像下面这样做,正如Chapter03/Recipe03/src/rmqexample/Publish.java中展示的一样:
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(hostname);
factory.setPort(5671);
factory.useSslProtocol();
Connection connection = factory.newConnection();
如何工作
../server/cert.pem -notext -batch –extensions
server_ca_extensions
7.从Chapter03/Recipe03/certificates,将我们刚才创建的CA 证书, 证书,以及server private key, 拷贝到下面的路径:
/usr/local/certificates/testca/cacert.pem
/usr/local/certificates/server/cert.pem
/usr/local/certificates/server/key.pem
8.创建RabbitMQ配置文件: rabbitmq.config, 可从Chapter03/Recipe03/rconfig目录中适当的目录(/etc/rabbitmq):
[
{rabbit, [
{ssl_listeners, [5671]},
{ssl_options, [
{cacertfile,"/usr/local/certificates/testca/cacert.pem"},
{certfile,"/usr/local/certificates/server/cert.pem"},
{keyfile,"/usr/local/certificates/server/key.pem"},
{verify,verify_peer},
{fail_if_no_peer_cert,false}]}
]}
].
9. 重启RabbitMQ server:
rabbitmqctl stop
rabbitmq-server–detached.
当你重启RabbitMQ节点时,Erlang节点也会重启.
10. 在Java client,连接服务端可以像下面这样做,正如Chapter03/Recipe03/src/rmqexample/Publish.java中展示的一样:
ConnectionFactory factory = new ConnectionFactory();
factory.setHost(hostname);
factory.setPort(5671);
factory.useSslProtocol();
Connection connection = factory.newConnection();
如何工作
我们通过创建一个可用于签名服务端证书的CA目录来开始本食谱.我们已经在服务器上执行了此步骤,但在真实世界中,CA和其私有密钥(private key) (由步骤3创建)应该分开保存.在准备好CA之后, 我们需要像步骤4-6中展示的一样来准备服务端证书.我们几乎完成了,最后我们只需要将CA证书,服务端证书,以及服务端公共密钥(public key)拷贝到最终路径下(步骤7).
我们可以选择将其存储在/usr/local/certificates中,但其位置通常是任意的,因为它们的位置可在RabbitMQ 配置文件(rabbitmq.config)中进行指定.此文件在默认情况下,是不存在的.它必须安置在标准配置目录,通常是位于/etc/rabbitmq中.
除了安全文件,我们还需要配置RabbitMQ SSL端口(5671), 以及在rabbitmq.config中配置几个选项:
除了安全文件,我们还需要配置RabbitMQ SSL端口(5671), 以及在rabbitmq.config中配置几个选项:
- Verify: 当设置为to verify_peer时,它将通知RabbitMQ:如果client存在证书,那么需要进行检查,并在证书无效时(可能是因为CA不同,或者是因为证书已过期了)进行拒绝
- fail_if_no_peer_cert: 当设置为false,它将通知RabbitMQ在重启后接受那些不存在任何证书的client(你必须使用rabbitmqctl stop 和restart 服务).你可以检查/var/log/rabbitmq中的日志文件来验证此选项的信息.
你应该能够找到下面的行:
started SSL Listener on [::]:5671
此外,从浏览器打开管理插件时,你也能够看到相似的信息(参考Managing RabbitMQ from a browser 食谱), 就像下面展示的一样:
started SSL Listener on [::]:5671
此外,从浏览器打开管理插件时,你也能够看到相似的信息(参考Managing RabbitMQ from a browser 食谱), 就像下面展示的一样:
现在,如果client要通过SSL来连接broker,只需要在连接工厂上添加下面的两个选项:
factory.setPort(5671);
factory.useSslProtocol();
现在就可以使用服务器中配置的keys来加密连接了.
factory.setPort(5671);
factory.useSslProtocol();
现在就可以使用服务器中配置的keys来加密连接了.
更多
由于我们只使用了服务端证书,虽然server和client之间的通信是加密的,但我们不能阻止MITM (man-in-the-middle)攻击(中间人攻击).如果我们想让任何client连接server,并且避免MITM 攻击的话, 我们采取与在HTTPS和浏览中的相同策略,即由可信的第三方CA机构来签名证书,并在证书中验证中其域,否则,我们只能继续阅读后面的食谱.
实现客户端证书
实现客户端证书
当RabbitMQ broker和client通过Internet来通信时,只允许授权的clients来连接broker是合理的.
本食谱是前面一个的扩展,因此假设我们已经进行了CA设置和服务端配置,正如前面食谱中看到的.
这是典型的用户密码身份验证的范围,但除此之外,客户端证书对于分布式应用程序的安全性来说具有更高的改进,同时它也可以避免MITM攻击的可能性.
如何做
client要连接RabbitMQ server,需要执行下面的步骤:
1. 拷贝上一个食谱中创建的证书,密钥到Chapter03/Recipe04/certificates目录:
cp –rp ../Recipe03/certificates/testca .
cp –rp ../Recipe03/certificates/server .
2. 在client证书目录,创建client private key,如Chapter03/Recipe04/certificates/04_create_client_certificates.sh中展示的一样:
openssl genrsa -out key.pem 2048
3. 创建证书签名请求:
openssl req -new -key key.pem -out req.pem -outform PEM -subj /CN=$(hostname)/O=client/ -nodes
4.在CA目录,签名client证书:
openssl ca -config openssl.cnf -in ../client/req.pem -out ../client/cert.pem -notext -batch -extensions client_ca_extensions
5. 回到client目录,创建一个PKCS#12存储,其中包含client证书和由密码保护的密钥:
openssl pkcs12 -export -out keycert.p12 -in cert.pem -in keykey.pem -passout pass:client1234passwd
6. 创建一个Java密钥库,其中包含由密码保护的服务端证书,如Chapter03/Recipe04/certificates/05_create_keystore.sh中展示的一样:
keytool -importcert -alias server001 -file server/cert.pem -keystore keystore/rabbit.jks -keypass passwd1234
7. 将rabbitmq.config中的fail_if_no_peer_cert选项设置为true:
{fail_if_no_peer_cert,true}
8. 重启RabbitMQ:
rabbitmqctl stop
rabbitmq-server –detached
9. 在client端, 配置SSL上下文来设置安全连接:
char[] keyPassphrase = "client1234passwd".toCharArray();
KeyStoreks = KeyStore.getInstance("PKCS12");
ks.load(newFileInputStream("certificates/client/keycert.p12"), keyPassphrase);
KeyManagerFactorykmf =KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, keyPassphrase);
char[] trustPassphrase = "passwd1234".toCharArray();
KeyStoretks = KeyStore.getInstance("JKS");
tks.load(newFileInputStream("certificates/keystore/rabbit.jks"), trustPassphrase);
TrustManagerFactorytmf =TrustManagerFactory.getInstance("SunX509");
tmf.init(tks);
SSLContext c = SSLContext.getInstance("SSLv3");
c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
ConnectionFactory factory = newConnectionFactory();
factory.setHost(hostname);
factory.setPort(5671);
factory.useSslProtocol(c);
Connection connection = factory.newConnection();
1. 拷贝上一个食谱中创建的证书,密钥到Chapter03/Recipe04/certificates目录:
cp –rp ../Recipe03/certificates/testca .
cp –rp ../Recipe03/certificates/server .
2. 在client证书目录,创建client private key,如Chapter03/Recipe04/certificates/04_create_client_certificates.sh中展示的一样:
openssl genrsa -out key.pem 2048
3. 创建证书签名请求:
openssl req -new -key key.pem -out req.pem -outform PEM -subj /CN=$(hostname)/O=client/ -nodes
4.在CA目录,签名client证书:
openssl ca -config openssl.cnf -in ../client/req.pem -out ../client/cert.pem -notext -batch -extensions client_ca_extensions
5. 回到client目录,创建一个PKCS#12存储,其中包含client证书和由密码保护的密钥:
openssl pkcs12 -export -out keycert.p12 -in cert.pem -in keykey.pem -passout pass:client1234passwd
6. 创建一个Java密钥库,其中包含由密码保护的服务端证书,如Chapter03/Recipe04/certificates/05_create_keystore.sh中展示的一样:
keytool -importcert -alias server001 -file server/cert.pem -keystore keystore/rabbit.jks -keypass passwd1234
7. 将rabbitmq.config中的fail_if_no_peer_cert选项设置为true:
{fail_if_no_peer_cert,true}
8. 重启RabbitMQ:
rabbitmqctl stop
rabbitmq-server –detached
9. 在client端, 配置SSL上下文来设置安全连接:
char[] keyPassphrase = "client1234passwd".toCharArray();
KeyStoreks = KeyStore.getInstance("PKCS12");
ks.load(newFileInputStream("certificates/client/keycert.p12"), keyPassphrase);
KeyManagerFactorykmf =KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, keyPassphrase);
char[] trustPassphrase = "passwd1234".toCharArray();
KeyStoretks = KeyStore.getInstance("JKS");
tks.load(newFileInputStream("certificates/keystore/rabbit.jks"), trustPassphrase);
TrustManagerFactorytmf =TrustManagerFactory.getInstance("SunX509");
tmf.init(tks);
SSLContext c = SSLContext.getInstance("SSLv3");
c.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
ConnectionFactory factory = newConnectionFactory();
factory.setHost(hostname);
factory.setPort(5671);
factory.useSslProtocol(c);
Connection connection = factory.newConnection();
如何工作
client证书要能工作,必须使用签名服务端的同一个CA来签名. 一旦准备好证书,将其保存到密钥库中是非常有用的, 如步骤5中展示的PKCS#12存储.
client 也需要服务端证书—它包含了服务端公共密钥—对此我们也准备了一个密钥库(通过Java keytool命令生成的密钥库).
随后我们重新配置了RabbitMQ (步骤6-7).通过这种方式,如果client没有提供证书,服务端就会拒绝其连接.现在你可以很容易地运行前面的例子来进行检查.
一旦client证书准备就绪,RabbitMQ client (步骤8)必须使用它们来设置SSLContext.与先前例子不同,我们只需要下面的调用:
factory.useSslProtocol(c);
client只有遵循这些设置才能连接RabbitMQ server. client 虽提供了这些证书,但不能连接到带有不同服务端私钥的服务器,因为它们之间的加密通信使用的是存储在服务器证书中服务端公共密钥.
client 也需要服务端证书—它包含了服务端公共密钥—对此我们也准备了一个密钥库(通过Java keytool命令生成的密钥库).
随后我们重新配置了RabbitMQ (步骤6-7).通过这种方式,如果client没有提供证书,服务端就会拒绝其连接.现在你可以很容易地运行前面的例子来进行检查.
一旦client证书准备就绪,RabbitMQ client (步骤8)必须使用它们来设置SSLContext.与先前例子不同,我们只需要下面的调用:
factory.useSslProtocol(c);
client只有遵循这些设置才能连接RabbitMQ server. client 虽提供了这些证书,但不能连接到带有不同服务端私钥的服务器,因为它们之间的加密通信使用的是存储在服务器证书中服务端公共密钥.
从浏览器中管理RabbitMQ
在本食谱中,我们将展示如何使用管理插件中的HTTP API来管理RbbitMQ.这个插件提供实时图表来监控你的消息流. 幸运的是,它也提供了HTTP API来分析RabbitMQ. 为了执行这些活动,这些是外部监控系统( Ganglia (http://ganglia.sourceforge.net/), Puppet (http://puppetlabs.com),以及其它系统)所必须的.
准备
你只需要一个 web浏览器.
如何做
为了启用插件,你必须执行下面的步骤:
1. 执行下面的命令:
rabbitmq-plugins enable rabbitmq_management
2. 重启RabbitMQ.
3. 插件会启用一个web服务器,它可以通过http://localhost:15672/访问. 要从其它机器访问,可以用你的RabbitMQ 主机名/IP来替换localhost.
如何工作
为了启用插件,你必须执行下面的步骤:
1. 执行下面的命令:
rabbitmq-plugins enable rabbitmq_management
2. 重启RabbitMQ.
3. 插件会启用一个web服务器,它可以通过http://localhost:15672/访问. 要从其它机器访问,可以用你的RabbitMQ 主机名/IP来替换localhost.
如何工作
默认情况下,web application使用guest/guest作为RabbitMQ 用户的用户名/密码. Web 管理是非常直观的,你可以管理队列,交换器,用户,连接,虚拟主机,当然也可以发送和接收信息.
在第一个tab中,你可以找到系统的概述信息:如排队的消息,消息速率,以及全局计数.然后,你可以找到节点描述信息.点击节点可以得到更多详细信息:
在之前的screenshot中,你可以看到可帮助你诊断问题的信息.
TIP
TIP
如果在Windows上运行RabbitMQ,你需要在执行路径(C:/Windows/system32)中安装Hanlde.exe工具 (http://technet.microsoft.com/enus/sysinternals/bb896655) . 否则,控制台不能显示文件描述符的总数信息.
在同个页面,还可以看到Erlang模块的版本信息(译者注:右上角).
在overview的下边部分,你还可以看AMQP broker监听的端口,以及安装的插件(web contexts):
在overview的下边部分,你还可以看AMQP broker监听的端口,以及安装的插件(web contexts):
更多
在http://localhost:15672/api/,你可以访问HTTP API. 通过使用HTTP APIs,用户可以创建一个自定义的控制台,就像我们即将在
开发Python 程序来监控RabbitMQ食谱中看到的一样.
也可参考
在http://www.rabbitmq.com/management.html, 你可以找到关于console的所有信息.
配置RabbitMQ参数
在本食谱中,我们将介绍RabbitMQ参数.默认情况下,broker不会创建配置文件,因为在大多数情况下,你不需要改变它们 .但,知道如何配置环境变量和broker参数是很重要的.
在本食谱中,我们将介绍RabbitMQ参数.默认情况下,broker不会创建配置文件,因为在大多数情况下,你不需要改变它们 .但,知道如何配置环境变量和broker参数是很重要的.
如何做
在RabbitMQ中,你可以配置环境变量和服务端文件配置(注意区别).使用环境变量,你可以修改像服务器端口和节点名称的参数.可通过两种方式来修改变量:
1. 在你的shell环境中定义变量.
2. 在 /etc/rabbitmq中创建一个rabbitmq-env.conf文件.
1. 在你的shell环境中定义变量.
2. 在 /etc/rabbitmq中创建一个rabbitmq-env.conf文件.
例如,如果你想要修改RabbitMQ节点名称,你可以这样做:
1. 停止server.
2. 要么在shell中执行RABBITMQ_NODENAME=mylittlerabbit,要么在 /etc/rabbitmq/rabbitmqenv.conf中插入字符串NODENAME=mylittlerabbit,.
3. 重启broker.
如何工作
1. 停止server.
2. 要么在shell中执行RABBITMQ_NODENAME=mylittlerabbit,要么在 /etc/rabbitmq/rabbitmqenv.conf中插入字符串NODENAME=mylittlerabbit,.
3. 重启broker.
如何工作
最初,web management会显示默认节点名称-rabbit@hostname,如下所示:
在配置过后,将会显示mylittlerabbit@hostname,如下所示:
通过这种方式,你可以修改在https://www.rabbitmq.com/configure.html#define-environment-variables中找到的所有环境变量信息.
TIP
TIP
环境变量是以前辍RABBITMQ_开头的,但在rabbitmq-env.conf中配置变量时,则不需要此前辍.
使用服务端文件配置,你可以修改内部broker配置. 配置文件名称为rabbitmq.config,它与rabbitmqenv.conf位于相同位置. 可使用环境变量RABBITMQ_CONFIG_FILE 来修改此位置 . 你可在https://www.rabbitmq.com/configure.html#configuration-file找到完整的参数列表.
更多
更多
在本食谱中,我们只是介绍了RabbitMQ配置.在后面的章节中,我们将修改某些参数来优化性能或配置集群.
开发Python程序监控RabbitMQ
在本例中,我们将使用可从http://localhost:15672/api/访问的JSON API来创建Python脚本来监控RabbitMQ.
本例的目的是创建一个自定义的Python脚本,它可以执行一些检查,并在检测到错误时,发送电子邮件.你可在Chapter03/Recipe07找到源码.
本例的目的是创建一个自定义的Python脚本,它可以执行一些检查,并在检测到错误时,发送电子邮件.你可在Chapter03/Recipe07找到源码.
准备
你需要Python 2.7+,并启用管理插件.
如何做
按照下面的步骤,使用JSON API创建Python脚本来监控RabbitMQ:
1. 导入下面的包:
import sys
import urllib2,base64
import json
import logging
2. 从JSON API中获取所需的RabbitMQ信息:
urllib2.Request("http://"+rabbitmqhost+":15672/api/nodes")
urllib2.Request("http://"+rabbitmqhost+":15672/api/connections")
urllib2.Request("http://"+rabbitmqhost+":15672/api/aliveness-test/%2f")
3.加载并执行JSON结果:
json.load(urllib2.urlopen(request));
4. 如果出现错误(或者是达到报警条件),则发送e-mail:
if error_message != "":
sendAlarmStatus(error_message);
1. 导入下面的包:
import sys
import urllib2,base64
import json
import logging
2. 从JSON API中获取所需的RabbitMQ信息:
urllib2.Request("http://"+rabbitmqhost+":15672/api/nodes")
urllib2.Request("http://"+rabbitmqhost+":15672/api/connections")
urllib2.Request("http://"+rabbitmqhost+":15672/api/aliveness-test/%2f")
3.加载并执行JSON结果:
json.load(urllib2.urlopen(request));
4. 如果出现错误(或者是达到报警条件),则发送e-mail:
if error_message != "":
sendAlarmStatus(error_message);
如何工作
在/api/nodes JSON调用中,我们检查了运行状态和对每个RabbitMQ节点的内存警报. 在/api/connections中,我们监控了已经连接的clients.
/api/aliveness-test/ JSON 调用 创建了一个test队列,并打算在默认虚拟主机%2f (当在URL中指定/时,必须将其编码)上发送和接收消息. 如果结果是{"status": "ok"},则表明没有错误.
脚本需要使用下面的代码来认证:
base64.encodestring('%s:%s' % ('guest', 'guest'))
request.add_header("Authorization", "Basic %s" % base64string);
/api/aliveness-test/ JSON 调用 创建了一个test队列,并打算在默认虚拟主机%2f (当在URL中指定/时,必须将其编码)上发送和接收消息. 如果结果是{"status": "ok"},则表明没有错误.
脚本需要使用下面的代码来认证:
base64.encodestring('%s:%s' % ('guest', 'guest'))
request.add_header("Authorization", "Basic %s" % base64string);
TIP
你必须使用带有monitor权限的RabbitMQ用户.
如果检测失败了,脚本会带有问题信息的邮件.要尝试这个例子,你需要修改使用自己的帐户来修改函数sendAlarmStatus(message)
TIP
此脚本可通过Linux crontab来调度或在Windows中使用Scheduler Task来调度.
在我们的例子中, 我们会将日志写入到/var/tmp/myMonitorRMQ.log文件中.
更多
在这个例子中,我们只是选择了部分APIs. 当然,这里还有更多的API,使用这些API,你可根据你自己的需求来创建检查RabbitMQ健康的监控工具.
你也可以使用rabbitmqadmin来监视broker: 文件可以从broker自身的地址:http://localhost:15672/cli/下载. 这个Python脚本,因此可从shell脚本中调用,例如:
./rabbitmqadmin –f raw_json list nodes
此命令按JSON格式将节点信息输出到标准输出中,这已经在本食谱的步骤2看过了.
你也可以使用rabbitmqadmin来监视broker: 文件可以从broker自身的地址:http://localhost:15672/cli/下载. 这个Python脚本,因此可从shell脚本中调用,例如:
./rabbitmqadmin –f raw_json list nodes
此命令按JSON格式将节点信息输出到标准输出中,这已经在本食谱的步骤2看过了.
也可参考
你可在http://hg.rabbitmq.com/rabbitmqmanagement/raw-file/rabbitmq_v3_0_4/priv/www/api/index.html找到全部的API文档.
自己开发web程序来监控RabbitMQ
在本食谱中,我们将展示如何来创建一个自定义的web程序来监控RabbitMQ日志.为了检查日志,你需要绑定一个队列到amq.rabbitmq.log 交换器中,正如在Chapter 12, Managing RabbitMQ Error Conditions中看到的一样.你可在Chapter03/Recipe08中找到本食谱的代码.
准备
为了理解这个例子,我们需要下面的东西:
如何做
- Spring
- Apache Tomcat
- Apache Maven
- WebSocket
- Query/HTML5/Twitter Bootstrap
如何做
执行下面的步骤来创建一个自定义的web程序来监控RabbitMQ日志:
1.从工具中选择一个可用的模板来创建一个基本的MVC (Model View Controller) Spring project,如下所示:
1.从工具中选择一个可用的模板来创建一个基本的MVC (Model View Controller) Spring project,如下所示:
2. 修改Maven文件(POM.xml),增加下面的依赖:
tomcat-coyote // needed for websockets
tomcat-servlet-api// needed for websockets
tomcat-catalina// needed for websockets
spring-rabbit// needed for rabbitmq
3. 使用org.springframework.amqp包中的类,创建一个新bean RabbitMQInstance来创建RabbitMQ界面.
你可以在root-context.xml中找到bean的生命周期.在这个例子中,RabbitMQ 必须与Tomcat运行在同一台机器上,但你也可以根据实际情况修改连接参数.
4. 创建一个名为RmqWebSocket的新类,此类将继承WebSocketServlet (Tomcat的WebSocket 类),并添加@WebServlet ("/websocket")注解.
5. 在RmqWebSocket类创建一个私有的amqp消费者:
LogListener implements MessageListener.
6. 消费者使用SimpleMessageListenerContainer来启动,如下所示:
container.setConnectionFactory(rmq.getConnectionFactory());
...
container.start();
7. 使用下面的代码来将浏览器WebSocket绑定到server:
ws = new WebSocket('ws://' host':8080/rmq/websocket');
8. 使用下面的代码来订阅:
ws.onmessage = function(message){..}
9. 每当浏览器收到消息,它就会使用jQuery来更新HTML table:
$("#tablebody").prepend("<tr><td>"+message.data+"</td></tr>");
10. 现在,一切都准备好了.你可以build Maven,并将其部署到Tomcat容器.
如何工作
tomcat-coyote // needed for websockets
tomcat-servlet-api// needed for websockets
tomcat-catalina// needed for websockets
spring-rabbit// needed for rabbitmq
3. 使用org.springframework.amqp包中的类,创建一个新bean RabbitMQInstance来创建RabbitMQ界面.
你可以在root-context.xml中找到bean的生命周期.在这个例子中,RabbitMQ 必须与Tomcat运行在同一台机器上,但你也可以根据实际情况修改连接参数.
4. 创建一个名为RmqWebSocket的新类,此类将继承WebSocketServlet (Tomcat的WebSocket 类),并添加@WebServlet ("/websocket")注解.
5. 在RmqWebSocket类创建一个私有的amqp消费者:
LogListener implements MessageListener.
6. 消费者使用SimpleMessageListenerContainer来启动,如下所示:
container.setConnectionFactory(rmq.getConnectionFactory());
...
container.start();
7. 使用下面的代码来将浏览器WebSocket绑定到server:
ws = new WebSocket('ws://' host':8080/rmq/websocket');
8. 使用下面的代码来订阅:
ws.onmessage = function(message){..}
9. 每当浏览器收到消息,它就会使用jQuery来更新HTML table:
$("#tablebody").prepend("<tr><td>"+message.data+"</td></tr>");
10. 现在,一切都准备好了.你可以build Maven,并将其部署到Tomcat容器.
如何工作
在RabbitMQInstance bean中,我们创建一个队列,并使用路由键#将其绑定到topic交换器-amq.rabbitmq.log中.在root-context.xml文件中,我们定义了bean ID,以及init/deinit方法,这样在web程序启动时就可以连接 AMQP clients,并在其关闭时,断开连接.
RabbitMQ连接和队列已经准备好了.
RmqWebSocket是一个Tomcat websocket,在这里,我们使用SimpleMessageListenerContainer(使用rabbitMQInstance参数(连接和队列)实现) 来启动了一个消费者.
消费者准备好了
在RmqWebSocket的StreamInbound方法中, 对于每个连接,我们都注册了websocket连接(通过浏览器来初始化一个新的ClientMessage类),且Collection<ClientMessage> clients 代码行中包含了活动clients.
websocket后端准备好了.
在步骤7中,浏览器连上了服务端,现在所有都准备好了,如下图所示:
RabbitMQ连接和队列已经准备好了.
RmqWebSocket是一个Tomcat websocket,在这里,我们使用SimpleMessageListenerContainer(使用rabbitMQInstance参数(连接和队列)实现) 来启动了一个消费者.
消费者准备好了
在RmqWebSocket的StreamInbound方法中, 对于每个连接,我们都注册了websocket连接(通过浏览器来初始化一个新的ClientMessage类),且Collection<ClientMessage> clients 代码行中包含了活动clients.
websocket后端准备好了.
在步骤7中,浏览器连上了服务端,现在所有都准备好了,如下图所示:
当日志消息发送到topic交换器amq.rabbitmq.log时,LogListener类将引发一个事件:
public void onMessage(Message message) {..}
消息将以for循环的方式广播给clients集合:
for(ClientMessage item: clients){
CharBuffer buffer = CharBuffer.wrap(new String(message.getBody()) );
item.myoutbound.writeTextMessage(buffer);
现在,浏览器收到的消息将使用jQuery来更新HTML table.
Tomcat默认使用8080端口,且应用程序URL为/rmq, 完整的URL为http://yourtomcatmachine:8080/rmq/, 正如下面展示的,你应该在web浏览器中指向这个地址:
public void onMessage(Message message) {..}
消息将以for循环的方式广播给clients集合:
for(ClientMessage item: clients){
CharBuffer buffer = CharBuffer.wrap(new String(message.getBody()) );
item.myoutbound.writeTextMessage(buffer);
现在,浏览器收到的消息将使用jQuery来更新HTML table.
Tomcat默认使用8080端口,且应用程序URL为/rmq, 完整的URL为http://yourtomcatmachine:8080/rmq/, 正如下面展示的,你应该在web浏览器中指向这个地址:
我们是在HTML5和Bootstrap使用的,你也可以在移动设备上使用.
TIP
客户端连接或断开连接足可以引发标准日志事件.
更多
在这个例子中,为了真实地展示如何整合RabbitMQ与当前web技术,我们已经介绍了多种不同技术.
虽然这里我们用的是RabbitMQ日志消息,但你可以轻易将同样的架构应用到你的分布式/web应用程序中.
虽然这里我们用的是RabbitMQ日志消息,但你可以轻易将同样的架构应用到你的分布式/web应用程序中.
TIP
要直接运行这个例子,你可在(Chapter03/Recipe08)获取源码,并使用Maven来准备所需的包.然后将其部署到Tomcat.
要直接运行这个例子,你可在(Chapter03/Recipe08)获取源码,并使用Maven来准备所需的包.然后将其部署到Tomcat.
也可参考
Spring: http://spring.io/
Apache Tomcat: http://tomcat.apache.org/
Apache Maven: http://maven.apache.org/
WebSocket: http://www.websocket.org/
http://tomcat.apache.org/tomcat-7.0-doc/web-socket-howto.html
jQuery: http://jquery.com/
HTML5: http://en.wikipedia.org/wiki/HTML5
Twitter Bootstrap: http://getbootstrap.com/
Apache Tomcat: http://tomcat.apache.org/
Apache Maven: http://maven.apache.org/
WebSocket: http://www.websocket.org/
http://tomcat.apache.org/tomcat-7.0-doc/web-socket-howto.html
jQuery: http://jquery.com/
HTML5: http://en.wikipedia.org/wiki/HTML5
Twitter Bootstrap: http://getbootstrap.com/