通知设置 新通知
愚人节开源中国新玩法-上头条
科技前沿 OpenSkill 发表了文章 0 个评论 2669 次浏览 2016-04-01 11:22
HAProxy和Nginx 配置HTTP/2完整指南
运维 push 发表了文章 0 个评论 4281 次浏览 2016-04-01 00:21
如果你想跳过安装环节或你只对配置环节感兴趣,可以跳至文章后面配置部分。
我为什么需要关注HTTP/2?
这里有一些介绍HTTP/2益处的文章-而且我鼓励你去读一读。下面我将重点介绍我认为比较重要的几点。
HTTP/2的主要优势:
- []使用二进制数据(不像HTTP/1.1一样使用明文)而且它使用了header数据压缩。不用再为header和cookie的大小而担心了。[/][]它是完全多元化的,为了提升并发性可以使用一个连接加载多种资源。你的网站性能在需要引入多种资源的时候会表现得更好,因为现在它们可以在一次TCP连接中全部加载,在非阻塞模式中。域名切分和资源级联变成了反面模式。简单来说:你的网站加载会更快。 [/][]它允许服务器提前推送请求到客户端的缓存(目前Ngnix不支持这个特性) [/][]它使用新的ALPN扩展,那将允许更快地加密连接。这个加密协议在初始化连接的阶段是可用的。[/]
我会在CentOS 7下安装,如果你使用其他Linux发布版本,你可以简单调整下代码。你需要做的:安装
- []站点能跑通SSL。如果你还没有虚拟证书的话,你需要使用虚拟证书(简单)。[/][]Ngnix 1.9.5 或更新版本( 简单 )。[/][]安装配置好OpenSSL的HAPorxy 1.6或更新版( 需要一些技巧 )。[/][]良好的HAPRoxy和Ngnix配置( 简单 )。[/][]确认你是否已经在使用HTTP/2,HTTP/2 and SPDY indicator 对Chrome友好。[/]
OpenSSL部分是需要一些技巧,因为大部分有OpwnSSL 1.0.1(或者更旧的版本)的Linux分支都不支持ALPN(应用层协议协商)。ALPN协议允许应用层去协商,这个协议将被用在连接中,而且这是基本的,如果我们要在相同的TCP端口支持HTTP/2和HTTP/1。除此之外,HTTP/2在HAProxy中只支持使用ALPN,所以它一定会在我们的列表里。1.获取 SSL 证书
如果你对安装流程熟悉的话,请直接跳至配置部分.
你可以很便宜的从ssl2buy.com上买到信任证书,那里有许多靠谱发行机构的代售。我曾经在那里买了一堆证书而且我推荐他们的服务和客户支持。你可以从那里拿到低于20美元的AphaSSL证书。
如果你需要为HAProxy或Nginx生成虚拟证书,你可以使用下面的命令:
# Generate all keys and cefiticates in /etc/ssl/ directory
openssl genrsa -out /etc/ssl/dummy.key 2048
openssl req -new -key /etc/ssl/dummy.key -out /etc/ssl/dummy.csr -subj "/C=GB/L=London/O=Company Ltd/CN=haproxy"
openssl x509 -req -days 3650 -in /etc/ssl/dummy.csr -signkey /etc/ssl/dummy.key -out /etc/ssl/dummy.crt
# Concatenate certificate and key into .pem format, compatible with HAProxy我们需要在下一步的配置中使用生成的证书和秘钥。
cat /etc/ssl/dummy.crt /etc/ssl/dummy.key > /etc/ssl/dummy.pem
2.Nginx 安装
在CentOS 7上安装Ngnix 1.9十分简单。唯一需要做的就是使用主线版YUM源,而不是稳定版。就像Nginx.org page上描述的那样,把yum源的配置放到/etc/yum.repos.d/nginx.repo位置然后执行yum install:搞定。
让我们创建一个Ngnix vhost.conf(虚拟主机配置文件)确保我们的Nginx在拥有HTTP/2的情况下正常工作。下面是一个简单的vhost配置:
第一点:关键点是在listen 443 default_server ssl http2那一行。这就相当于你使用了HTTP/2。
第二点:现在忽略第三行listen 81部分的配置 - 我们一会再回来看这部分。
第三点:我使用使用标准的80/443端口在Docker镜像里跑这个样例,所以它们不会和我的host主机上的任何端口发生冲突。如果有需要,你可以把它调整至适用你的需要。
第四点:使用在获取SSL证书那一步生成的dummy.crt和dummy.key。
好了,当你使用https://协议连接站点时,HTTP/2提示器会提示你站点正在运行HTTP/2协议。
恭喜你,你的Ngnix已经在运行HTTP/2了!
3、OpenSSL 和 HAProxy 安装
这一部分有点棘手。我们需要编译OpenSSL 1.0.2的源码(因为在yum中还没有可用的资源)并且在之后的HAProxy重编译中还会使用到它。
建立OpenSSL的工作,我们使用no-shared参数,并且HAProxy是通过静态方式连接到OpenSSL的。我遵照的是HAProxy官方的README.但可笑的是,我最终还是采用了其他的方式……并且要非常足智多谋。你会常常去读这些冗长且乏味的README文件吗?
在那之后,你应该已经编译通过HAProxy且安装好了。测试一下:
haproxy -vv
4、配置
这是一个我们将用到完整的/etc/haproxy/haproxy.cfg(HAProxy配置):
最本质的部分在这:
这里我们定义了HTTPS前端接口在客户端请求HAProxy时监听443端口。
请求被后端的nodes-http2还是nodes-http处理取决于客户端是否支持HTTP2.注意我们决定SSL在HAProxy上使用这个配置,连接对后端服务器来说是被解密过的。我们的后端服务器可以被HAProxy用web服务器的域名访问(这就是运行过程中的Nginx,就像我们上面说的)。
在bind *:443 line with alpn h2,http/1.1一行我们建议为了方便客户端使用最好两种协议(HTTP/2 and HTTP/1.1)都支持。
这样的话浏览器即使不支持HTTP/2,也可以浏览我们的网站。
use_backend nodes-http2 if { ssl_fc_alpn -i h2 } 支持HTTP/2的客户端会被重定向到nodes-http2后端节点,剩下使用HTTP/1.1协议的将被nodes-http处理。如果你想让后端兼容还不支持HTTP/2的客户端,这件事十分重要的。
因此我们会有下面这一行:
server node1 web.server:81 check send-proxy
在这里,我们只讨论了HAProxy和HTTP/2协议。通常它连接web.server在81端口。我们还有更令人高兴的惊喜吗?
让我们用nginx下列虚拟主机配置(如上所述):
这一行:listen 81 default_server http2 proxy_protocol;
定义了服务器在端口81,会处理HTTP/2的请求。请注意,我们无法在服务器使用443端口进行SSL连接:SSL连接已经被HAProxy解密过了,所以现在我们有一个非加密连接。因此我们需要限制服务器的81端口只使用HTTP/2,不使用SSL。
题外话:小也有proxy_protocol关键词。在haproxy.cfg等效发送代理,在后端服务器配置。代理协议是独立出来的,这儿有篇文章很好的解释了原因。简而言之,它允许通过HAProxy后端服务器传送客户端的IP地址和端口号,这通常是非常理想的。
你可以使用上面的配置运行HAProxy:
HAProxy F / etc / HAProxy / haproxy.cfg现在你应该能够连接到您的代理主机(例如https://localhost:443/),看到它正在运行HTTP / 2。如果你在Firefox的测试,检查网络请求头的标题,你会看到X-Firefox-Spdy: "h2"。
Docker images
如果你早已经会使用Docker,你可以用我们的MILLION12镜像。当Docker还是1.0版本的时候我们已经开始使用Docker很长时间了(MILLION12这是我们的仓库地址),而且我们已经构建了一堆有用的镜像。在这个例子里,我们将使用million12/haproxy和million12/nginx这两个镜像。里面的配置是我们讨论后的最终结果。
你可以运行整个栈通过使用docker-compose.yml文件。注意我们是通过haproxy容器里的web.server主机名连接Nignx的,那个域名就是当前haproxy.cfg使用的主机名。
连接https://haproxy:8443你就会看到屏幕显示出如下内容(注意蓝色的HTTP/2提示部分。
如果你想看看使用这些Docker镜像和上述配置的真实的产品工程,打开https://PrototypeBrewery.io 。Prototype Brewery是我们的产品,一个计划和构建交互式web项目的原型工具。打开看看吧,我们已经在使用HTTP/2了(别忘了注册)。
总结
正如你看到的,迁移到HTTP/2真的很简单,你今天就能做掉。 没有什么理由让你再等下去了,主流浏览器都已经支持它了。而且即使回迁到HTTP/1.1上你仍然是安全的。分享阅读原文:http://m12.io/blog/http-2-with-haproxy-and-nginx-guide
中文原文:http://www.oschina.net/translate/haproxy-nginx-http-2
Redis安装配置详解
数据库 空心菜 发表了文章 0 个评论 2950 次浏览 2016-03-31 15:43
***三部曲执行文件说明:
# cd /usr/local/src
# wget http://redis.googlecode.com/files/redis-2.6.10.tar.gz
# tar zxvf redis-2.6.10.tar.gz
# cd redis-2.6.10
# make
# make install
***make命令执行完成后,会在src目录下生成5个可执行文件:
# redis-server Redis服务器的daemon启动程序
# redis-cli Redis命令行操作工具。当然,你也可以用telnet根据其纯文本协议来操作
# redis-benchmark Redis性能测试工具,测试Redis在你的系统及你的配置下的读写性能
# redis-check-aof 更新日志检查
# redis-check-dump 用于本地数据库检查
echo "1" > /proc/sys/vm/overcommit_memory
1表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
cp redis-benchmark redis-cli redis-server /usr/bin/ #拷贝可执行文件配置文件详解:
cp redis.conf /etc/ # redis启动配置文件
#是否作为守护进程运行Redis Replication配置:
daemonize yes
#如以后台进程运行,则需指定一个pid,默认为/var/run/redis.pid
pidfile redis.pid
#绑定主机IP,默认值为127.0.0.1
bind 0.0.0.0
#Redis默认监听端口
port 6379
#客户端闲置多少秒后,断开连接,默认为300(秒)
timeout 300
#日志记录等级,有4个可选值,debug,verbose(默认值),notice,warning
loglevel verbose
#指定日志输出的文件名,默认值为stdout,也可设为/dev/null屏蔽日志
logfile stdout
#可用数据库数,默认值为16,默认数据库为0
databases 16
#保存数据到disk的策略:
#当有一条Keys数据被改变时,900秒刷新到disk一次
save 900 1
#当有10条Keys数据被改变时,300秒刷新到disk一次
save 300 10
#当有1w条keys数据被改变时,60秒刷新到disk一次
save 60 10000
#当dump .rdb数据库的时候是否压缩数据对象
rdbcompression yes
#存储和加载rdb文件时校验
rdbchecksum yes
#本地数据库文件名,默认值为dump.rdb
dbfilename dump.rdb
#后台存储错误停止写。
stop-writes-on-bgsave-error yes
#本地数据库存放路径,默认值为 ./
dir /var/lib/redis/
# slaveof当本机为从服务时,设置主服务的IP及端口
# masterauth当本机为从服务时,设置主服务的连接密码
#连接密码
#requirepass foobared
#最大客户端连接数,默认不限制
# maxclients 128
#最大内存使用设置,达到最大内存设置后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理后,任到达最大内存设置,将无法再进行写入操作。
# maxmemory
#是否在每次更新操作后进行日志记录,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认值为no
appendonly no
#更新日志文件名,默认值为appendonly.aof
#appendfilename
#更新日志条件,共有3个可选值。no表示等操作系统进行数据缓存同步到磁盘,always表示每次更新操作后手动调用fsync()将数据写到磁盘,everysec表示每秒同步一次(默认值)。
# appendfsync always
appendfsync everysec
# appendfsync no
#当slave失去与master的连接,或正在拷贝中,如果为yes,slave会响应客户端的请求,数据可能不同步甚至没有数据,如果为no,slave会返回错误"SYNC with master in progress"
slave-serve-stale-data yes
#如果为yes,slave实例只读,如果为no,slave实例可读可写。
slave-read-only yes
# 在slave和master同步后(发送psync/sync),后续的同步是否设置成TCP_NODELAY . 假如设置成yes,则redis会合并小的TCP包从而节省带宽,但会增加同步延迟(40ms),造成master与slave数据不一致 假如设置成no,则redis master会立即发送同步数据,没有延迟
repl-disable-tcp-nodelay no
#如果master不能再正常工作,那么会在多个slave中,选择优先值最小的一个slave提升为master,优先值为0表示不能提升为master。
slave-priority 100
#[size=16]# LIMITS [/size]##
maxclients 10000 #客户端并发连接数的上限是10000,到达上限,服务器会关闭所有新连接并返回错误"max number of clients reached"
maxmemory 15G #设置最大内存,到达上限,服务器会根据驱逐政策(eviction policy)删除某些键值,如果政策被设置为noeviction,那么redis只读,对于增加内存的操作请求返回错误。
#[size=16]# APPEND ONLY MODE [/size]##
appendonly no #redis默认采用快照(snapshotting)异步转存到硬盘中,它是根据save指令来触发持久化的,当Redis异常中断或停电时,可能会导致最后一些写操作丢失。AOF(Append Only File,只追加文件)可以提供更好的持久性,结合apendfsync指令可以把几分钟的数据丢失降至一秒钟的数据丢失,它通过日志把所有的操作记录下来,AOF和RDB持久化可以同时启动。
appendfilename appendonly.aof #指定aof的文件名。
apendfsync always|everysec|no #调用fsync()写数据到硬盘中,always是每一次写操作就马上同步到日志中,everysec是每隔一秒强制fsync,no是不调用fsync(),让操作系统自己决定何时同步。
no-appendfsync-on-rewrite no #如果为yes,当BGSAVE或BGREWRITEAOF指令运行时,即把AOF文件转写到RDB文件中时,会阻止调用fsync()。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb #Redis会将AOF文件最初的大小记录下来,如果当前的AOF文件的大小增加100%并且超过64mb时,就会自动触发Redis改写AOF文件到RDB文件中,如果auto-aof-rewrite-percentage为0表示取消自动rewrite功能。
#[size=16]# LUA SCRIPTING [/size]##
lua-time-limit 5000 #一个Lua脚本最长的执行时间为5000毫秒(5秒),如果为0或负数表示无限执行时间。
#[size=16]# SLOW LOG [/size]##
slowlog-log-slower-than 10000 #当某个请求执行时间(不包括IO时间)超过10000微妙(10毫秒),把请求记录在慢日志中 ,如果为负数不使用慢日志,如果为0强制记录每个指令。
slowlog-max-len 128 #慢日志的最大长度是128,当慢日志超过128时,最先进入队列的记录会被踢出来,慢日志会消耗内存,你可以使用SLOWLOG RESET清空队列回收这些内存。
#[size=16]# ADVANCED CONFIG [/size]##
hash-max-ziplist-entries 512
hash-max-ziplist-value 64 #较小的hash可以通过某种特殊的方式进行编码,以节省大量的内存空间,我们指定最大的条目数为512,每个条目的最大长度为64。
list-max-ziplist-entries 512
list-max-ziplist-value 64 #同上。
zset-max-ziplist-entries 128
zset-max-ziplist-value 64 #同上。
activerehashing yes #重新哈希the main Redis hash table(the one mapping top-level keys to values),这样会节省更多的空间。
client-output-buffer-limit normal 0 0 0 #对客户端输出缓冲进行限制可以强迫那些就不从服务器读取数据的客户端断开连接。对于normal client,第一个0表示取消hard limit,第二个0和第三个0表示取消soft limit,normal client默认取消限制,因为如果没有寻问,他们是不会接收数据的。
client-output-buffer-limit slave 256mb 64mb 60 #对于slave client和MONITER client,如果client-output-buffer一旦超过256mb,又或者超过64mb持续60秒,那么服务器就会立即断开客户端连接。
client-output-buffer-limit pubsub 32mb 8mb 60 #对于pubsub client,如果client-output-buffer一旦超过32mb,又或者超过8mb持续60秒,那么服务器就会立即断开客户端连接。
#[size=16]# INCLUDES [/size]##
include /path/to/conf #包含一些可以重用的配置文件。
hz 10 #Redis 调用内部函数来执行后台task,比如关闭已经timeout连接,删除过期的keys并且永远不会被访问到的,执行频率根据 hz 后面的值来确定。在Redis 比较空闲的时候,提高这个值,能充分利用CPU,让Redis相应速度更快,可取范围是1-500 ,建议值为 1--100
aof-rewrite-incremental-fsync yes # 当子进程重写AOF文件,以下选项开启时,AOF文件会每产生32M数据同步一次。这有助于更快写入文件到磁盘避免延迟
#############[size=16]# VIRTUAL MEMORY [/size]######[size=16]#[/size]
#是否开启VM功能,默认值为no
vm-enabled no
# vm-enabled yes
#虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享
vm-swap-file /tmp/redis.swap
#将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的 (Redis的索引数据就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0。
vm-max-memory 0
vm-page-size 32
vm-pages 134217728
vm-max-threads 4
##########[size=16]# ADVANCED CONFIG [/size]##########[size=16]#[/size]
glueoutputbuf yes
hash-max-zipmap-entries 64
hash-max-zipmap-value 512
#是否重置Hash表
activerehashing yes
_____________________________________________________________________
注意:Redis官方文档对VM的使用提出了一些建议:
当你的key很小而value很大时,使用VM的效果会比较好.因为这样节约的内存比较大.
当你的key不小时,可以考虑使用一些非常方法将很大的key变成很大的value,比如你可以考虑将key,value组合成一个新的value.
最好使用linux ext3 等对稀疏文件支持比较好的文件系统保存你的swap文件.
vm-max-threads这个参数,可以设置访问swap文件的线程数,设置最好不要超过机器的核数.如果设置为0,那么所有对swap文件的操作都是串行的.可能会造成比较长时间的延迟,但是对数据完整性有很好的保证.
#启动服务
redis-server /etc/redis.conf
#操作窗口
redis-cli
redis-cli set foo bar
OK
redis-cli get foo
bar
#关闭redis
redis-cli shutdown
#强制备份数据到磁盘,使用如下命令
redis-cli save
redis-cli -p 6380 save #指定端口
redis-cli -r 3 info # 重复执行info命令三次
cat testStr.txt | redis-cli -x set testStr # 读取testStr.txt文件所有内容设置为testStr的值
redis-cli keys \* # 查看所有键值信息
redis-cli -n 1 keys "test*" | xargs redis-cli -n 1 del # 删除DBID为1的test开头的key值
redis-cli -p 6379 info | grep '\' # 过滤查询used_memory属性
redis-check-dump dump.rdb # 检查本地数据库文件
_____________________________________________________________________
redis双机高可用的基础,是redis的主备复制机制。指定主备角色,是用slaveof命令。
指定本机为master
slaveof NO ONE
指定本机为192.168.1.10的slave
slaveof 192.168.1.10 6379
硬盘存储两种方式任选其一: 1、save 为快照 2、aof 为持久化
aof日志文件损坏,可用 Redis 随身带的 redis-check-aof 命令来修复原始文件:
redis-check-aof --fix "filename"
_____________________________________________________________________
redis的基准信息和性能检测
# redis-benchmark 命令测试性能
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
100个并发连接,100000个请求,检测host为localhost 端口为6379的redis服务器性能
./redis-benchmark -n 100000 –c 50
====== –c 50 ======
100000 requests completed in 1.93 seconds (100000个请求完成于 1.93 秒 )
50 parallel clients (每个请求有50个并发客户端)
3 bytes payload (每次写入3字节)
keep alive: 1 (保持1个连接)
58.50% <= 0 milliseconds
99.17% <= 1 milliseconds
99.58% <= 2 milliseconds
99.85% <= 3 milliseconds
99.90% <= 6 milliseconds
100.00% <= 9 milliseconds
(所有请求在62毫秒内完成)
114293.71 requests per second(每秒 114293.71 次查询)
例子:
redis-benchmark -h 192.168.1.1 -p 6379 -n 100000 -c 20
redis-benchmark -t set -n 1000000 -r 100000000
redis-benchmark -t ping,set,get -n 100000 –csv
redis-benchmark -r 10000 -n 10000 lpush mylist
_____________________________________________________________________
Redis的query分析
redis-faina(https://github.com/Instagram/redis-faina) 是由Instagram 开发并开源的一个Redis 查询分析小工具,需安装python环境。
redis-faina 是通过Redis的MONITOR命令来实现的,通过对在Redis上执行的query进行监控,统计出一段时间的query特性,需root权限。
通过管道从stdin读取N条命令,直接分析
redis-cli -p 6439 monitor | head -n| ./redis-faina.py
# python-redis官网
https://pypi.python.org/pypi/redis
Python 2.7 15分钟入门视频
学习资源 OpenSkill 发表了文章 2 个评论 2608 次浏览 2016-03-31 13:22
卫峥的个人视频分享。旨在把多年编程经验分享给大家,各种编程语言的语法知识,使用方法,应用场景,框架使用,尽量使用最少的时间 精简的话语 讲给你听。
Rabbitmq用户管理介绍
大数据 koyo 发表了文章 0 个评论 2944 次浏览 2016-03-30 23:38
用户管理
用户管理包括:
增加用户、删除用户、查看用户列表、修改用户密码。1、新增一个用户
rabbitmqctl add_user Username Password2、删除一个用户
rabbitmqctl delete_user Username3、修改用户的密码
rabbitmqctl change_password Username Newpassword4、查看当前用户列表
rabbitmqctl list_users
用户角色
用户角色可分为五类:
超级管理员、监控者、策略制定者、普通管理者以及其他。1、超级管理员(administrator)
可登陆管理控制台(启用management plugin的情况下),可查看所有的信息,并且可以对用户,策略(policy)进行操作。2、监控者(monitoring)
可登陆管理控制台(启用management plugin的情况下),同时可以查看rabbitmq节点的相关信息(进程数,内存使用情况,磁盘使用情况等)3、策略制定者(policymaker)
可登陆管理控制台(启用management plugin的情况下), 同时可以对policy进行管理。但无法查看节点的相关信息。4、普通管理者(management)
与administrator的对比,administrator能看到这些内容。
仅可登陆管理控制台(启用management plugin的情况下),无法看到节点信息,也无法对策略进行管理。5、其他
无法登陆管理控制台,通常就是普通的生产者和消费者。了解了这些后,就可以根据需要给不同的用户设置不同的角色,以便按需管理。
设置用户角色的命令为:
rabbitmqctl set_user_tags User TagUser为用户名, Tag为角色名(对应于上面的administrator,monitoring,policymaker,management,或其他自定义名称)。
也可以给同一用户设置多个角色,例如:
rabbitmqctl set_user_tags hncscwc monitoring policymaker
用户权限
用户权限指的是用户对exchange,queue的操作权限,包括配置权限,读写权限。配置权限会影响到exchange,queue的声明和删除。读写权限影响到从queue里取消息,向exchange发送消息以及queue和exchange的绑定(bind)操作。例如:
将queue绑定到某exchange上,需要具有queue的可写权限,以及exchange的可读权限;向exchange发送消息需要具有exchange的可写权限;从queue里取数据需要具有queue的可读权限。详细请参考官方文档中"How permissions work"部分。相关命令为:
1、设置用户权限
rabbitmqctl set_permissions -p VHostPath User ConfP WriteP ReadP2、 查看(指定hostpath)所有用户的权限信息
rabbitmqctl list_permissions [-p VHostPath]
3、查看指定用户的权限信息rabbitmqctl list_user_permissions User4、清除用户的权限信息
rabbitmqctl clear_permissions [-p VHostPath] User
Rabbitmq 3.5.1 Web管理界面guest无法登陆分析
学习资源 koyo 发表了文章 0 个评论 3929 次浏览 2016-03-30 23:16
安装了rabbitmq(3.5.1),并启用management plugin后,使用默认的账号guest登陆管理控制台,却提示登陆失败。
翻看官方的release文档后,得知由于账号guest具有所有的操作权限,并且又是默认账号,出于安全因素的考虑,guest用户只能通过localhost登陆使用,并建议修改guest用户的密码以及新建其他账号管理使用rabbitmq(该功能是在3.3.0版本之后引入的)。
虽然可以以比较猥琐的方式:将ebin目录下rabbit.app中loopback_users里的<<"guest">>删除,
并重启rabbitmq,可通过任意IP使用guest账号登陆管理控制台,但始终是违背了设计者的初衷,再加上以前对这一块了解也不多,因此有必要总结一下。
Centos下Rabbitmq安装配置
大数据 koyo 发表了文章 0 个评论 4467 次浏览 2016-03-29 18:38
一、安装Erlang
1、Yum方法安装
# wget -O /etc/yum.repos.d/epel-erlang.repo http://repos.fedorapeople.org/repos/peter/erlang/epel-erlang.repo2、源码安装
# yum -y install erlang
# yum -y install gcc* make ncurses-devel libxslt xsltproc unzip nc xmlto
# wget http://www.erlang.org/download/otp_src_R16B01.tar.gz
# tar zxvf otp_src_R16B01.tar.gz
# ./configure --prefix=/usr/local/erlang_R16B01 --without-javac --with-ssl
# make && make install
# ln -s /usr/local/erlang/bin/erl /usr/bin/erl
# ln -s /usr/local/erlang/bin/escript /usr/bin/escript
# ln -s /usr/local/erlang/bin/erlc /usr/bin/erlc
二、安装Rabbitmq
1、Yum方法安装
# rpm -Uvh http://mirrors.sohu.com/fedora-epel/6/x86_64/epel-release-6-8.noarch.rpm2、源码安装
# rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc
# yum install rabbitmq-server-3.1.5
***下载免编译安装包,下载解压开封即用,可以下载任意自己想要的版本!
# wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.5.1/rabbitmq-server-generic-unix-3.5.1.tar.gz
# tar zxf rabbitmq-server-generic-unix-3.5.1.tar.gz -C /data/
三、配置
配置文件和初始化环境脚本配置指定在/data/rabbitmq_server-3.5.1/sbin目录下:
rabbitmq-env 环境初始化配置rabbitmq-defaults配置:
rabbitmq-defaults 默认参数设置
rabbitmqctl 管理工具
rabbitmq-plugins 插件管理工具
rabbitmq-server rabbitmq服务启动脚本
SYS_PREFIX=${RABBITMQ_HOME}主要配置文件介绍:
ERL_DIR=/usr/bin/ //设置erl命令路径
CLEAN_BOOT_FILE=start_clean
SASL_BOOT_FILE=start_sasl
CONFIG_FILE=${SYS_PREFIX}/etc/rabbitmq/rabbitmq //设置rabbitmq配置文件路径
LOG_BASE=${SYS_PREFIX}/var/log/rabbitmq
MNESIA_BASE=${SYS_PREFIX}/var/lib/rabbitmq/mnesia
ENABLED_PLUGINS_FILE=${SYS_PREFIX}/etc/rabbitmq/enabled_plugins //允许插件列表配置文件
PLUGINS_DIR="${RABBITMQ_HOME}/plugins"
CONF_ENV_FILE=${SYS_PREFIX}/etc/rabbitmq/rabbitmq-env.conf
1、enabled_plugins:设置允许的插件列表,格式如下:
[rabbitmq_jsonrpc_channel,2、rabbitmq.config:设置rabbitmq运行参数。结构为hash数组格式,如:
rabbitmq_management,
rabbitmq_management_visualiser,
rabbitmq_tracing].
[其中几个关键参数为:
{mnesia, [{dump_log_write_threshold, 1000}]},
{rabbit, [{vm_memory_high_watermark, 0.4}]}
{rabbitmq_management,
[{listener, [{port, 55673},
{ip, "0.0.0.0"}
]}
]}
].
tcp_listeners 设置rabbimq的监听端口,默认为[5672]。配置实栗如下:
disk_free_limit 磁盘低水位线,若磁盘容量低于指定值则停止接收数据,默认值为{mem_relative, 1.0},即与内存相关联1:1,也可定制为多少byte.
vm_memory_high_watermark 设置内存低水位线,若低于该水位线,则开启流控机制,默认值是0.4,即内存总量的40%。
hipe_compile 将部分rabbimq代码用High Performance Erlang compiler编译,可提升性能,该参数是实验性,若出现erlang vm segfaults,应关掉。
force_fine_statistics 该参数属于rabbimq_management,若为true则进行精细化的统计,但会影响性能。
[{auth_backends,[rabbit_auth_backend_internal]},3、rabbitmq-env.conf rabbitmq环境参数配置:
{auth_mechanisms,['PLAIN','AMQPLAIN']},
{backing_queue_module,rabbit_variable_queue},
{cluster_nodes,},
{collect_statistics,fine},
{collect_statistics_interval,5000},
{default_permissions,[<<".[i]">>,<<".[/i]">>,<<".*">>]},
{default_user,<<"guest">>},
{default_user_tags,[administrator]},
{default_vhost,<<"/">>},
{delegate_count,16},
{error_logger,{file,"/usr/local/var/log/rabbitmq/rabbit@Technophiliac.log"}},
{frame_max,131072},
{hipe_compile,false},
{included_applications,},
{msg_store_file_size_limit,16777216},
{msg_store_index_module,rabbit_msg_store_ets_index},
{queue_index_max_journal_entries,262144},
{sasl_error_logger,{file,"/usr/local/var/log/rabbitmq/rabbit@Technophiliac-sasl.log"}},
{server_properties,},
{ssl_listeners,},
{ssl_options,},
{tcp_listen_options,
[binary,
{packet,raw},
{reuseaddr,true},
{backlog,128},
{nodelay,true},
{exit_on_close,false}]},
{tcp_listeners,[5672]},
{trace_vhosts,[<<"/">>]},
{vm_memory_high_watermark,0.4}].
RABBITMQ_NODENAME=FZTEC-240088 节点名称更详细的配置参考官网: http://www.rabbitmq.com/configure.html#configuration-file
RABBITMQ_NODE_IP_ADDRESS=127.0.0.1 监听IP
RABBITMQ_NODE_PORT=5672 监听端口
RABBITMQ_LOG_BASE=/data/rabbitmq/log 日志目录
RABBITMQ_PLUGINS_DIR=/data/rabbitmq/plugins 插件目录
RABBITMQ_MNESIA_BASE=/data/rabbitmq/mnesia 后端存储目录
4、启动
# /usr/local/rabbitmq/sbin/rabbitmq-server -detached
四、插件管理
启用rabbitmq web管理插件
# ./rabbitmq-plugins enable rabbitmq_managementweb管理端口默认端口是15672,访问地址为http://rabbitmq_host_ip:15672 默认有一个用户名字和密码都是guest
列出所有插件
./rabbitmq-plugins list
Python关键字yield的解释
编程 Rock 发表了文章 0 个评论 2492 次浏览 2016-03-28 22:34
提问者的问题
Python关键字yield的作用是什么?用来干什么的?
比如,我正在试图理解下面的代码:
def node._get_child_candidates(self, distance, min_dist, max_dist):下面的是调用:
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild
result, candidates = list(), [self]当调用 _get_child_candidates 的时候发生了什么?返回了一个链表?返回了一个元素?被重复调用了么? 什么时候这个调用结束呢?
while candidates:
node = candidates.pop()
distance = node._get_dist(obj)
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result
回答部分
为了理解什么是 yield,你必须理解什么是生成器。在理解生成器之前,让我们先走近迭代。
可迭代对象
当你建立了一个列表,你可以逐项地读取这个列表,这叫做一个可迭代对象:
>>> mylist = [1, 2, 3]mylist 是一个可迭代的对象。当你使用一个列表生成式来建立一个列表的时候,就建立了一个可迭代的对象:
[quote]>> for i in mylist :
... print(i)
1
2
3
>>> mylist = [x*x for x in range(3)]所有你可以使用 for .. in .. 语法的叫做一个迭代器:链表,字符串,文件……你经常使用它们是因为你可以如你所愿的读取其中的元素,但是你把所有的值都存储到了内存中,如果你有大量数据的话这个方式并不是你想要的。
>>> for i in mylist :
... print(i)
0
1
4
生成器
生成器是可以迭代的,但是你 只可以读取它一次 ,因为它并不把所有的值放在内存中,它是实时地生成数据:
>>> mygenerator = (x*x for x in range(3))看起来除了把 换成 () 外没什么不同。但是,你不可以再次使用 for i inmygenerator , 因为生成器只能被迭代一次:先计算出0,然后继续计算1,然后计算4,一个跟一个的…
>>> for i in mygenerator :
... print(i)
0
1
4
yield关键字
yield 是一个类似 return 的关键字,只是这个函数返回的是个生成器。
>>> def createGenerator() :这个例子没什么用途,但是它让你知道,这个函数会返回一大批你只需要读一次的值.
... mylist = range(3)
... for i in mylist :
... yield i*i
...
>>> mygenerator = createGenerator() # create a generator
>>> print(mygenerator) # mygenerator is an object!
>>> for i in mygenerator:
... print(i)
0
1
4
为了精通 yield ,你必须要理解:当你调用这个函数的时候,函数内部的代码并不立马执行 ,这个函数只是返回一个生成器对象,这有点蹊跷不是吗。
那么,函数内的代码什么时候执行呢?当你使用for进行迭代的时候.
现在到了关键点了!
第一次迭代中你的函数会执行,从开始到达 yield 关键字,然后返回 yield 后的值作为第一次迭代的返回值. 然后,每次执行这个函数都会继续执行你在函数内部定义的那个循环的下一次,再返回那个值,直到没有可以返回的。
如果生成器内部没有定义 yield 关键字,那么这个生成器被认为成空的。这种情况可能因为是循环进行没了,或者是没有满足 if/else 条件。
回到你的代码
(译者注:这是回答者对问题的具体解释)
生成器:
# Here you create the method of the node object that will return the generator调用者:
def node._get_child_candidates(self, distance, min_dist, max_dist):[/quote]
# Here is the code that will be called each time you use the generator object :
# If there is still a child of the node object on its left
# AND if distance is ok, return the next child
if self._leftchild and distance - max_dist < self._median:
yield self._leftchild
# If there is still a child of the node object on its right
# AND if distance is ok, return the next child
if self._rightchild and distance + max_dist >= self._median:
yield self._rightchild
# If the function arrives here, the generator will be considered empty
# there is no more than two values : the left and the right children
# Create an empty list and a list with the current object reference这个代码包含了几个小部分:
result, candidates = list(), [self]
# Loop on candidates (they contain only one element at the beginning)
while candidates:
# Get the last candidate and remove it from the list
node = candidates.pop()
# Get the distance between obj and the candidate
distance = node._get_dist(obj)
# If distance is ok, then you can fill the result
if distance <= max_dist and distance >= min_dist:
result.extend(node._values)
# Add the children of the candidate in the candidates list
# so the loop will keep running until it will have looked
# at all the children of the children of the children, etc. of the candidate
candidates.extend(node._get_child_candidates(distance, min_dist, max_dist))
return result
- []我们对一个链表进行迭代,但是迭代中链表还在不断的扩展。它是一个迭代这些嵌套的数据的简洁方式,即使这样有点危险,因为可能导致无限迭代。candidates.extend(node._get_child_candidates(distance, min_dist,max_dist)) 穷尽了生成器的所有值,但 while 不断地在产生新的生成器,它们会产生和上一次不一样的值,既然没有作用到同一个节点上.[/][]extend() 是一个迭代器方法,作用于迭代器,并把参数追加到迭代器的后面。[/]
>>> a = [1, 2][quote]>> b = [3, 4]>>> a.extend(b)>>> print(a)[1, 2, 3, 4]但是在你的代码中的是一个生成器,这是不错的,因为:
- []你不必读两次所有的值[/][]你可以有很多子对象,但不必叫他们都存储在内存里面。[/]
并且这很奏效,因为Python不关心一个方法的参数是不是个链表。Python只希望它是个可以迭代的,所以这个参数可以是链表,元组,字符串,生成器... 这叫做 ducktyping,这也是为何Python如此棒的原因之一,但这已经是另外一个问题了...
你可以在这里停下,来看看生成器的一些高级用法
控制生成器的穷尽
>>> class Bank(): # let's create a bank, building ATMs对于控制一些资源的访问来说这很有用。
... crisis = False
... def create_atm(self) :
... while not self.crisis :
... yield "$100"
>>> hsbc = Bank() # when everything's ok the ATM gives you as much as you want
>>> corner_street_atm = hsbc.create_atm()
>>> print(corner_street_atm.next())
$100
>>> print(corner_street_atm.next())
$100
>>> print([corner_street_atm.next() for cash in range(5)])
['$100', '$100', '$100', '$100', '$100']
>>> hsbc.crisis = True # crisis is coming, no more money!
>>> print(corner_street_atm.next())
>>> wall_street_atm = hsbc.create_atm() # it's even true for new ATMs
>>> print(wall_street_atm.next())
>>> hsbc.crisis = False # trouble is, even post-crisis the ATM remains empty
>>> print(corner_street_atm.next())
>>> brand_new_atm = hsbc.create_atm() # build a new one to get back in business
>>> for cash in brand_new_atm :
... print cash
$100
$100
$100
$100
$100
$100
$100
$100
$100
...
Itertools,你最好的朋友
itertools包含了很多特殊的迭代方法。是不是曾想过复制一个迭代器?串联两个迭代器?把嵌套的链表分组?不用创造一个新的链表的 zip/map?[/quote]
只要 import itertools
需要个例子?让我们看看比赛中4匹马可能到达终点的先后顺序的可能情况:
>>> horses = [1, 2, 3, 4]
[quote]>> races = itertools.permutations(horses)
>>> print(races)
>>> print(list(itertools.permutations(horses)))
[(1, 2, 3, 4),
(1, 2, 4, 3),
(1, 3, 2, 4),
(1, 3, 4, 2),
(1, 4, 2, 3),
(1, 4, 3, 2),
(2, 1, 3, 4),
(2, 1, 4, 3),
(2, 3, 1, 4),
(2, 3, 4, 1),
(2, 4, 1, 3),
(2, 4, 3, 1),
(3, 1, 2, 4),
(3, 1, 4, 2),
(3, 2, 1, 4),
(3, 2, 4, 1),
(3, 4, 1, 2),
(3, 4, 2, 1),
(4, 1, 2, 3),
(4, 1, 3, 2),
(4, 2, 1, 3),
(4, 2, 3, 1),
(4, 3, 1, 2),
(4, 3, 2, 1)]
了解迭代器的内部机理
迭代是一个实现可迭代对象(实现的是 __iter__() 方法)和迭代器(实现的是__next__() 方法)的过程。可迭代对象是你可以从其获取到一个迭代器的任一对象。迭代器是那些允许你迭代可迭代对象的对象。
更多见这个文章: http://effbot.org/zone/python-for-statement.htm
翻译编辑原文:http://pyzh.readthedocs.org/en/latest/the-python-yield-keyword-explained.html[/quote]