MongoDB 单实例部署 [ 非源码编译安装 ]

MongoDB 官方网址:
http://www.mongodb.org

本文,主要介绍 MongoDB 单实例的安装部署~

1.下载MongoDB的安装包并解压,安装相关依赖包 [ 这里不采用源码编译安装 ]
yum -y install net-snmp.x86_64 net-snmp-devel.x86_64 net-snmp-libs.x86_64
mkdir /usr/local/mongodb
tar -xf mongodb-linux-x86_64-enterprise-rhel62-3.0.2.tgz
mv mongodb-linux-x86_64-enterprise-rhel62-3.0.2 /usr/local/mongodb

2. 创建数据目录,日志目录,配置目录等相关目录
cd /usr/local/mongodb
mkdir data conf log

3.编辑MongoDB 的配置文件:
vim conf/mongodb.conf
port=27017
dbpath=/usr/local/mongodb/data
logpath=/usr/local/mongodb/log/mongodb.log
logappend=true
fork=true

4.启动/关闭MongoDB:
(1).启动MongoDB:
/usr/local/mongodb/bin/mongod –config /usr/local/mongodb/conf/mongodb.conf

(2).关闭MongoDB:
/usr/local/mongodb/bin/mongod –config /usr/local/mongodb/conf/mongodb.conf –shutdown

(3).主从启动的相关要点: [也可将其参数写入配置文件 master=true ]
A. 如果mongodb 做为 master 的话,只要在启动时,加 –master 参数即可:
ex:
/usr/local/mongodb/bin/mongod –config /usr/local/mongodb/conf/mongodb.conf –master
# 同时,查看日志,日志会有相关master 的信息

B. 如果mongodb 做为 SLAVE 的话,只要在启动时,加 –slave –source ip:端口 参数即可:
ex:
/usr/local/mongodb/bin/mongod –config /usr/local/mongodb/conf/mongodb.conf –slave –source 172.16.10.55:27017
# 同时,查看日志,日志会有相关slave 的信息

C.主从数据源信息的变更:
> db.printSlaveReplicationInfo();
source: 172.16.10.5627017
doing initial sync
> use local
> db.sources.find();
{ “_id” : ObjectId(“5549957a542399f1888879b2”), “host” : “172.16.10.5627017”, “source” : “main” }
> db.sources.insert({“host”: “172.16.10.56:27017”}); # 添加一个新的主数据源
WriteResult({ “nInserted” : 1 })
> db.sources.find();
{ “_id” : ObjectId(“5549957a542399f1888879b2”), “host” : “172.16.10.5627017”, “source” : “main” }
{ “_id” : ObjectId(“5549c25670656588c7058016”), “host” : “172.16.10.56:27017” }
> db.sources.remove({“host”: “172.16.10.5627017”}); # 删除一个已存在的数据源
WriteResult({ “nRemoved” : 1 })
> db.sources.find();
{ “_id” : ObjectId(“5549c25670656588c7058016”), “host” : “172.16.10.56:27017” }

D.查看主从复制信息:
> db.printReplicationInfo();
configured oplog size: 1550MB
log length start to end: 72993secs (20.28hrs)
oplog first event time: Tue May 05 2015 17:27:01 GMT+0800 (CST)
oplog last event time: Wed May 06 2015 13:43:34 GMT+0800 (CST)
now: Wed May 06 2015 14:24:21 GMT+0800 (CST)
> db.printSlaveReplicationInfo();
source: 172.16.10.55:27017
syncedTo: Wed May 06 2015 14:24:24 GMT+0800 (CST)
13 secs (0 hrs) behind the freshest member (no primary available at the moment)

5.注意事项:
启动后,日志信息如下,红色警告部分,是我们需要进行调整的地方:
2015-05-05T15:14:48.310+0800 I JOURNAL [initandlisten] journal dir=/usr/local/mongodb/data/journal
2015-05-05T15:14:48.311+0800 I JOURNAL [initandlisten] recover : no journal files present, no recovery needed
2015-05-05T15:14:48.368+0800 I JOURNAL [durability] Durability thread started
2015-05-05T15:14:48.368+0800 I JOURNAL [journal writer] Journal writer thread started
2015-05-05T15:14:48.369+0800 I CONTROL [initandlisten] MongoDB starting : pid=8874 port=27017 dbpath=/usr/local/mongodb/data 64-bit host=Templet
2015-05-05T15:14:48.369+0800 I CONTROL [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.
2015-05-05T15:14:48.369+0800 I CONTROL [initandlisten]
2015-05-05T15:14:48.370+0800 I CONTROL [initandlisten]
2015-05-05T15:14:48.370+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is ‘always’.
2015-05-05T15:14:48.370+0800 I CONTROL [initandlisten] ** We suggest setting it to ‘never’
2015-05-05T15:14:48.370+0800 I CONTROL [initandlisten]
2015-05-05T15:14:48.370+0800 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is ‘always’.
2015-05-05T15:14:48.370+0800 I CONTROL [initandlisten] ** We suggest setting it to ‘never’
2015-05-05T15:14:48.370+0800 I CONTROL [initandlisten]
2015-05-05T15:14:48.370+0800 I CONTROL [initandlisten] db version v3.0.2
2015-05-05T15:14:48.370+0800 I CONTROL [initandlisten] git version: 6201872043ecbbc0a4cc169b5482dcf385fc464f modules: enterprise
2015-05-05T15:14:48.370+0800 I CONTROL [initandlisten] OpenSSL version: OpenSSL 1.0.1e-fips 11 Feb 2013
2015-05-05T15:14:48.370+0800 I CONTROL [initandlisten] build info: Linux ip-10-171-117-53 2.6.32-220.el6.x86_64 #1 SMP Wed Nov 9 08:03:13 EST 2011 x86_64 BOOST_LIB_VERSION=1_49
2015-05-05T15:14:48.370+0800 I CONTROL [initandlisten] allocator: tcmalloc
2015-05-05T15:14:48.370+0800 I CONTROL [initandlisten] options: { config: “/usr/local/mongodb/conf/mongodb.conf”, net: { port: 27017 }, processManagement: { fork: true }, storage: { dbPath: “/usr/local/mongodb/data” }, systemLog: { destination: “file”, logAppend: true, path: “/usr/local/mongodb/log/mongodb.log” } }
2015-05-05T15:14:48.372+0800 I INDEX [initandlisten] allocating new ns file /usr/local/mongodb/data/local.ns, filling with zeroes…
2015-05-05T15:14:48.435+0800 I STORAGE [FileAllocator] allocating new datafile /usr/local/mongodb/data/local.0, filling with zeroes…
2015-05-05T15:14:48.435+0800 I STORAGE [FileAllocator] creating directory /usr/local/mongodb/data/_tmp
2015-05-05T15:14:48.439+0800 I STORAGE [FileAllocator] done allocating datafile /usr/local/mongodb/data/local.0, size: 64MB, took 0 secs
2015-05-05T15:14:48.450+0800 I NETWORK [initandlisten] waiting for connections on port 27017

下面,我们进行调整:
(1).创建mongodb用户
注:Mongodb不建议使用root用户来运行
# groupadd -g 1010 mongodb
# useradd -g 1010 -u 1010 mongodb
调整目录和文件权限
# cd /usr/local/mongodb
# chown -R mongodb. data/ log/

(2).内核参数调整
调整前:
# cat /sys/kernel/mm/transparent_hugepage/enabled
[always] never
# cat /sys/kernel/mm/transparent_hugepage/defrag
[always] never
调整方法:
# echo “never” > /sys/kernel/mm/transparent_hugepage/enabled
# echo “never” > /sys/kernel/mm/transparent_hugepage/defrag
调整后:
# cat /sys/kernel/mm/transparent_hugepage/enabled
always [never]
# cat /sys/kernel/mm/transparent_hugepage/defrag
always [never]

(3).调整限制参数
启动日志,提示启动mongodb的这个用户能打开的进程数不到能打开的文件数的二分之一;
建议调整该用户能打开进程数为能打开的文件数的二分之一以上;
在CentOS系统中,默认情况用户能打开的进程数和文件数都为1024,因此不会出现该提示;
至于限制参数可以通过ulimit命令和/etc/security/limits.conf来设置
设置完毕后重启服务(切换到 mongodb 用户,启动mongodb)

MongoDB的日常使用

一、 查看collection和db信息:
1.查看DB以及DB空间大小:
show dbs
2.选择DB:
use hoss
3.查看DB中的collections:
show collections

二、查看collection使用大小:
1.查看DB给collection分配的大小。相当于oracle的segment大小:
db.fs.files.storageSize()
2.查看collection实际使用的大小。相当于oracle的HWR之下的:
db.fs.files.dataSize()
block,即已使用的block
3.查看collection的大小(storageSize)与索引大小的总和:
db.fs.files.totalSize()
4.查看collection的详细信息:
db.fs.files.stats()

三、 删除collection和db:
1.删除当前数据库:
db.dropDatabase()
2.删除当前collection的索引:
db.mycoll.dropIndexes()
3.删除当前collection
db.mycoll.drop()

四、检查同步状态
db.printReplicationInfo()
db.printSlaveReplicationInfo()
haowu:SECONDARY> db.printReplicationInfo()
configured oplog size: 4096MB
log length start to end: 449727secs (124.92hrs)
oplog first event time: Thu Dec 11 2014 11:00:40 GMT+0800 (CST)
oplog last event time: Tue Dec 16 2014 15:56:07 GMT+0800 (CST)
now: Tue Dec 16 2014 15:56:57 GMT+0800 (CST)

haowu:SECONDARY> db.printSlaveReplicationInfo()
source: 172.16.10.40:27017
syncedTo: Tue Dec 16 2014 15:56:07 GMT+0800 (CST)
= 55 secs ago (0.02hrs)
source: 172.16.10.22:27017
no replication info, yet. State: ARBITER

只要 oplog last event time 和 syncedTo 一致,就代表没有同步延迟

五、备份和恢复操作:
1.备份:mongodump
mongodump使用的是普通的查询机制(无锁定),所以产生的备份不一定是服务器数据的实时快照,即当运行备份同时有客户端写入数据,该数据就不会备份到磁盘,备份时的查询会对其他客户端的性能产生不利的影响。即可对运行的数据库使用,也可对未运行的数据使用。
如果想要获取一致的备份,可以使用命令 db.fsyncLock() 给数据库加锁,阻塞写操作,备份结束后使用命令 db.fsyncUnlock() 解锁。
例:
备份数据库:
mongodump -d test -o ./backup

2.恢复:mongorestore
使用 mongorestore 命令来恢复数据,数据源是 mongodump 命令产生的文件
恢复所有数据:
./mongorestore –drop /opt/backup/mongodb
恢复数据库:
./mongorestore -d test –drop /opt/backup/mongodb/test/
恢复集合:
./mongorestore -d test -c wu –drop /opt/backup/mongodb/test/wu.bson

六、导入和导出操作:
1.导出:mongoexport
使用mongoexport命令导出的数据是文本模式,用户可读的。
导出的粒度就是集合,也只是集合,不能导出某个数据库。
导出的数据格式可以有三种:json,csv,jsonArray。
使用最多的就是json和csv。
例:
mongoexport –port 27018 -d test -c test -o test.json

2.导入:mongoimport
mongoimport命令也只能导入集合。
默认导入json格式的文件。
如果是csv,需要使用–type来指定,并配合–headerline参数。
例:
mongoimport -d test -c test –drop –type csv –headerline –file ~/test.csv

Haproxy 服务部署(利用Keepalived实现Haproxy 高可用)

一、Haproxy 简述:
HAProxy是一个开源的、高性能的,基于TCP(第四层)和HTTP(第7层)应用的负载均衡软件。使用HAProxy可以快速可靠地实现基于TCP和HTTP应用的负载均衡解决方案。
作为一个专业的负载均衡软件,他有如下优点:
1.可靠性和稳定性非常好,可以与硬件级的F5负载均衡设备想媲美
2.最高可以同时维护40000-50000个并发连接,单位时间处理的最大请求数达20000个,最大数据处理能力可达10Gbps。
3.支持多达8种负载均衡算法,同时也支持session保持
4.支持虚拟主机功能,使实现web负载均衡更加灵活
5.从HAProxy 1.3版本后开始支持连接拒绝、全透明代理等功能,这些功能是其他负载均衡器所不具备的。
6.有功能强大的监控页面,通过此页面可以实时了解系统的运行状况。
7.拥有功能强大的ACL支持。
HAProxy是借助操作系统的技术特性来实现性能最大化的,因此要想发挥HAProxy的最大性能需要对操作系统性能进行优化。
HAProxy非常适用于那些并发量特别大且需要持久连接或四层和七层处理机制的web系统,例如门户网站或电子商务网站等。
HAProxy也可以用于MySQL数据库(读操作)的负载均衡。

HAProxy的官方文档地址:
http://cbonte.github.io/haproxy-dconv/

二、Haproxy的部署:
1.Haproxy的下载、安装:
下载地址:http://www.haproxy.org/
# 默认已经下载好了
tar -xf haproxy-1.5.11.tar.gz
cd haproxy-1.5.11
make TARGET=linux26 CPU=x86_64 PREFIX=/usr/local/haproxy
make install PREFIX=/usr/local/haproxy

2.Haproxy 配置文件 修改:[ 配置文件具体含义,参考 linux — linux 配置文件详解 — keepalived 配置文件详解 ]
cd /usr/local/haproxy
mkdir etc logs
cp examples/haproxy.cfg /usr/local/haproxy/etc
cd /usr/local/haproxy/etc
vim haproxy.cfg
global
log 127.0.0.1 local0 info
maxconn 4096
chroot /usr/local/haproxy
uid 99
gid 99
daemon
nbproc 1
pidfile /usr/local/haproxy/logs/haproxy.pid

defaults
mode http
option redispatch
option abortonclose
timeout connect 5000ms
timeout client 30000ms
timeout server 3000ms
log 127.0.0.1 local0 err
balance roundrobin

listen admin_stats
bind 0.0.0.0:8888
mode http
option httplog
stats refresh 30s
stats uri /haproxy-status
stats realm Welcome\ login\ Haproxy
stats auth admin:admin
stats hide-version
stats admin if TRUE

listen test1
bind :12345
mode http
server t1 172.16.10.55:80
server t2 172.16.10.56:80

#listen test2 :80
# option httpclose
# option forwardfor
# server s1 192.168.1.101:8080 check weight 1 minconn 1 maxconn 3 check inter 40000
# server s2 192.168.1.102:8080 check weight 1 minconn 1 maxconn 3 check inter 40000

3.编写Haproxy启动脚本:
vim /etc/init.d/haproxy
#!/bin/bash
#chkconfig: 2345 10 90
#description:haproxy
NAME=”haproxy”
DESC=”Haproxy daemon”
BASE_DIR=”/usr/local/haproxy”
CONF=$BASE_DIR/etc/haproxy.cfg
PIDFILE=$BASE_DIR/logs/haproxy.pid
SCRNAME=/etc/init.d/$NAME
ARGV=”$@”

start()
{
echo “START HAPoxy SERVERS”
$BASE_DIR/sbin/haproxy -f $CONF
}
stop()
{
echo “STOP HAPoxy Listen”
kill -TTOU $(cat $PIDFILE)
echo “STOP HAPoxy process”
kill -USR1 $(cat $PIDFILE)
}
case $ARGV in
start)
start
ERROR=$?
;;
stop)
stop
ERROR=$?
;;
restart)
stop
start
ERROR=$?
;;
*)
echo “Useage:$SCRNAME [start|restart|stop]”
esac
exit $ERROR

# 给予脚本执行权限:
chmod +x /etc/init.d/haproxy
# 脚本添加开机启动:
chkconfig -add haproxy
# 注:
如果报如下错:
service haproxy does not support chkconfig
解决方法:
在/etc/init.d/haproxy 中添加下面两句到 #!/bin/bash之后,添加如下内容:
# chkconfig: 2345 10 90
# description:haproxy
—-其中2345是默认启动级别,级别有0-6共7个级别。
—-等级0表示:表示关机
—-等级1表示:单用户模式
—-等级2表示:无网络连接的多用户命令行模式
—-等级3表示:有网络连接的多用户命令行模式
—-等级4表示:不可用
—-等级5表示:带图形界面的多用户模式
—-等级6表示:重新启动
—-10是启动优先级,90是停机优先级,优先级范围是0-100,数字越大,优先级越低。

4.日志支持功能添加
# vim /etc/rsyslog.conf
在最下边增加
local0.* /usr/local/haproxy/logs/haproxy.log
# 重启日志服务
/etc/init.d/rsyslog restart

5.haproxy测试:
(1).10.55/10.56默认web服务已经部署好,默认80 端口;
(2).启动haproxy:
/etc/init.d/haproxy start
(3).登录haproxy监控页面:
http://172.16.10.54:8888/haproxy-status
(4).登录haproxy测试负载均衡:[ 不断刷新,观察变化 ]
http://172.16.10.54:12345/

三、keepalived 部署:
1.10.53/10.54安装keepalived
keepalived 的安装,请参照keepalived服务部署一篇,下面主要讲解相关配置

2.修改keepalived配置文件:vim /etc/keepalived/keepalived.conf [ 没有就创建 ]
global_defs {
notification_email
{
13501960667@139.com # 收件邮箱
}
notification_email_from mysql_lab@localhost # 发件邮箱
smtp_server localhost # 发件服务器
smtp_connect_timeout 30 # 超时时间
router_id HAOWU_55
}
vrrp_script chk_haproxy {
script “/usr/local/keepalived/chk_haproxy.sh”
# interval 2
# weight 2
}
vrrp_sync_group VG1 {
group
{
VI_1
}
}
vrrp_instance VI_1 {
# state MASTER
state BACKUP
nopreempt
interface eth0
virtual_router_id 96
priority 110
advert_int 1
authentication
{
auth_type PASS
auth_pass Pa$$w0rd
}
track_script {
chk_haproxy # 监测haproxy进程状态
}
virtual_ipaddress
{
172.16.10.251
}
}

# 蓝色部分: 是相对其它脚本需要添加的内容;
# 红色部分:是必须要注释掉的部分。如果,不注释掉,keepalived将无法调用脚本;
# 至于master 和backup 配置文件的异同和要修改的部分,请参考keepalived服务部署一篇.

3.编写haproxy 检测脚本:
vim /usr/local/keepalived/chk_proxy.sh
#!/bin/bash
A=`ps -C haproxy –no-header |wc -l`
# 当检测到haproxy宕机后,试图重新启动haproxy,如果是测试,建议先注释掉所有红色部分代码
if [ $A -eq 0 ];then
/etc/init.d/haproxy start
sleep 3
if [ `ps -C haproxy –no-header |wc -l` -eq 0 ];then
/etc/init.d/keepalived stop
fi
fi

4.给予检测脚本执行权限:
chmod +x /usr/local/keepalived/chk_proxy.sh

5.官网建议的内存优化配置:
echo 1024 60999 > /proc/sys/net/ipv4/ip_local_port_range
echo 30 > /proc/sys/net/ipv4/tcp_fin_timeout
echo 4096 > /proc/sys/net/ipv4/tcp_max_syn_backlog
echo 262144 > /proc/sys/net/ipv4/tcp_max_tw_buckets
echo 262144 > /proc/sys/net/ipv4/tcp_max_orphans
echo 300 > /proc/sys/net/ipv4/tcp_keepalive_time
echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
echo 0 > /proc/sys/net/ipv4/tcp_timestamps
echo 0 > /proc/sys/net/ipv4/tcp_ecn
echo 1 > /proc/sys/net/ipv4/tcp_sack
echo 0 > /proc/sys/net/ipv4/tcp_dsack

四、下面就可以进行测试了
1.启动所有服务:
先启动haproxy,再启动keepalived,再启动 55 56上的web
2.输入 172.16.10.251:12345 测试
期间停止haproxy,看vip是否漂移
网站是否能正常打开

twemproxy 简介、安装配置

官方地址:
https://github.com/twitter/twemproxy

一、Twemproxy简介及其特性、缺点:
1.Twemproxy简介:
Twemproxy 是一个快速的单线程代理程序,支持 Memcached ASCII协议和更新的Redis协议。它全部用C写成,使用Apache 2.0 License授权。
项目在Linux上可以工作,而在OSX上无法编译,因为它依赖了epoll API.
twemproxy 主要用于Redis 和 Memcached 的集群代理

2.Twemproxy特性:
速度快
轻量级
维护持久的服务器连接
Keeps connection count on the backend caching servers low.
启用请求和响应的管道
支持代理到多个服务器
同时支持多个服务器池
多个服务器自动分享数据
实现了完整的 memcached ascii 和 redis 协议.
服务器池配置简单,通过一个 YAML 文件即可
Supports multiple hashing modes including consistent hashing and distribution.
可配置在失败时禁用某个节点
Observability through stats exposed on stats monitoring port.
支持 Linux, *BSD, OS X and Solaris (SmartOS)

3.Twemproxy不足之处:
不支持针对多个值的操作,比如取sets的子交并补等(MGET 和 DEL 除外)
不支持Redis的事务操作
出错提示还不够完善
也不支持select操作
虽然可以动态移除节点,但该移除节点的数据就丢失了
redis集群动态增加节点的时候,twemproxy不会对已有数据做重分布。maillist里面作者说这个需要自己写个脚本实现性能上的损耗

二、Twemproxy部署:
1.Twemproxy 编译安装:
autoconf下载地址: http://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz
twemproxy下载地址:https://codeload.github.com/twitter/twemproxy/zip/master
twemproxy的安装要求autoconf的版本在2.64以上,否则提示”error: Autoconf version 2.64 or higher is required“
twemproxy的安装方法与git上README.md里面的过程基本相同,只是configure过程中多了–prefix选项,将工具安装到指定目录
(1).autoconf的安装:
tar -xf autoconf-2.69.tar.gz
cd autoconf-2.69
./configure
make
make install
# 测试是否安装成功:
autoconf –version

(2).twemproxy的安装:
unzip twemproxy-master.zip
cd twemproxy-master
autoreconf -fvi
./configure –prefix=/usr/local/twemproxy
make -j 2
make install

2.Twemproxy 配置文件:
cd /usr/local/twemproxy/
mkdir run conf
vim conf/nutcracker.yml
redis:
listen: 172.16.10.54:6666 # 使用哪个端口启动Twemproxy
redis: true # 是否是Redis的proxy
hash: fnv1a_64 # 指定具体的hash函数
distribution: ketama # 具体的hash算法
auto_eject_hosts: true # 是否在结点无法响应的时候临时摘除结点
timeout: 400 # 超时时间(毫秒)
server_retry_timeout: 3000 # 重试的时间(毫秒)
server_failure_limit: 1 # 结点故障多少次就算摘除掉
servers: # 下面表示所有的Redis节点(IP:端口号:权重)
– 172.16.10.55:6379:1
– 172.16.10.56:6379:1

3.Twemproxy 配置文件测试,命令生效,服务启动:
(1).命令生效:
vim ~/.bash_profile
PATH=$PATH:$HOME/bin:/usr/local/keepalived/sbin:/usr/local/twemproxy/sbin
. ~/.bash_profile # 使命令生效
(2).配置文件测试:
nutcracker -t
nutcracker: configuration file ‘conf/nutcracker.yml’ syntax is ok # 显示此信息,说明配置文件正常
(3).Twemproxy服务启动:
nutcracker -d -c /usr/local/twemproxy/conf/nutcracker.yml -p /usr/local/twemproxy/run/redisproxy.pid -o /usr/local/twemproxy/run/redisproxy.log
(4).Twemproxy配置文件书写需要注意的问题:
A.yml配置文件中每个参数值对分隔符”:”后,需要有一个空格;
B.不同层次的参数需要缩进区分,最好使用tab键缩进,否则nutcracker进程不能启动;
C.在auto_eject_hosts: true的时候,关闭一个redis实例后,写入数据还是提示“(error) ERR Connection refused”
这个与server_retry_timeout参数设置太小有关,默认值30000msec是一个很好的选择。

4.Twemproxy 启动、停止脚本编写:
vim /etc/init.d/twemproxy
#!/bin/bash
#chkconfig: 2345 10 90
#description:twemproxy

function Stop()
{
/usr/bin/pkill nutcracker
}
function Start()
{
nutcracker -d -c /usr/local/twemproxy/conf/nutcracker.yml -p /usr/local/twemproxy/run/redisproxy.pid -o /usr/local/twemproxy/run/redisproxy.log
}
case $1 in
stop)
Stop
;;
start)
Start
;;
restart)
Stop
Start
;;
*)
echo “Usage: `basename $0` {stop|start}”
;;
esac
# 添加twemproxy 服务:
chkconfig –add twemproxy

三、Twemproxy测试:
redis-cli -h 172.16.10.54 -p 6666
172.16.10.54:6666> select 0 # 不支持select
Error: Server closed the connection
172.16.10.54:6666> get name
“Michael.xu”
172.16.10.54:6666> set names “wu.zhong”
OK
172.16.10.54:6666> get names
“wu.zhong”

# 性能测试:
redis-benchmark -h 172.16.10.54 -p 6666 -c 100 -t set -d 100 -l -q

Redis HA架构:Redis(master/slave) + Keepalived + Redis Sentinel + Twemproxy + Twemproxy Agent

一、Redis HA架构描述:
目前,Redis高可用方案,主要集中于以下几种:
1.Redis(master/slave)
2.Redis(master/slave) + Keepalived + Redis Sentinel
3.Codis
4.Redis(master/slave) + Keepalived + Redis Sentinel + Twemproxy + Keepalived
5.Redis(master/slave) + Keepalived + Redis Sentinel + Twemproxy + Twemproxy Agent + nodejs +npm
第 4 种,我们通过 两个keepalived 来是实现HA,一个是实现Redis HA的vip ;一个是Twemproxy HA的VIP
第 5 种,使用一个 keepalived 来实现Twemproxy HA,通过 Twemproxy Agent 来更新 Twemproxy 配置(当redis主从切换时)
下面,我们主要讲解第 5 种 方案:
Redis(master/slave) + Keepalived + Redis Sentinel + Twemproxy + Twemproxy Agent + nodejs + nodejs-forever-agent + npm

二、Redis HA架构图:

Image

三、Redis(master/slave) + Redis Sentinel 部署:
具体的安装可以参照:
Redis HA 下的
20141202:Redis 主从部署
20150421:Redis Sentinel + keepalived 部署
下面,将简单描述:
1.Redis(master/slave) 的部署:[ 部署在 10.55、10.56 ]
10.55、10.56 都部署两套Redis,
# 第二套redis,只要将配置文件( redis.conf) 复制并改名为 redis_6380.conf
# 新配置文件/ 启动脚本等 修改,参照 Redis 主从部署一篇
2.Redis Sentinel 部署:[ 部署在 10.54、10.55、10.56 ]
# 只要在Redis Sentinel 的配置文件,把新建的Redis master 添加进去,就可;
# 具体,参照如下文件:
vim /usr/local/redis-sentinel/etc/sentinel.conf
port 26379
dir /usr/local/redis-sentinel/data
sentinel monitor mymaster 172.16.10.55 6379 1
sentinel down-after-milliseconds mymaster 5000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 60000
# sentinel client-reconfig-script mymaster /usr/local/redis-sentinel/bin/keepalived.sh # 这里我们在故障切换时,就不再执行脚本
sentinel monitor mymaster2 172.16.10.56 6380 1
sentinel down-after-milliseconds mymaster2 5000
sentinel parallel-syncs mymaster2 1
sentinel failover-timeout mymaster2 60000
3.下面启动相关Redis服务:
(1).启动 Redis服务;
(2).启动 Redis Sentinel 服务;
(3).测试 Redis master/slave 切换情况;

四、keepalived 部署:[ 部署在 10.53、10.54 ]
# keepalived 部署 参照 ”20150421:Redis Sentinel + keepalived 部署 “ 文章中的 keepalived 部署 一段
# 在此,就不再赘述

五、Twemproxy 部署:[ 部署在 10.53、10.54 ]
# Twemproxy 部署 参照 “Redis 中间件” 中的 “20150427:twemproxy 简介、安装配置”文章
# 在此,就不再赘述

六、Twemproxy Agent 部署:[ 部署在 10.53、10.54 ]
1.安装nodejs + npm:
yum -y install nodejs npm
2.安装forever:
npm install forever -g
3.安装Twemproxy Agent
(1).解压Twemproxy Agent 包,并复制到指定目录:
mv /tmp/redis-twemproxy-agent-master /usr/local/redis-twemproxy-agent
(2).修改redis-twemproxy-agent/lib/cli.js文件:
修改cli.parse里的文件路径为部署的路径,具体参照如下配置:
cli.parse
({
host: [‘h’, ‘Redis sentinel hostname’, ‘string’, ‘172.16.10.54’],
port: [‘p’, ‘Redis sentinel port number’, ‘number’, 26379],
config: [‘f’, ‘Path to twemproxy config’, ‘path’, ‘/usr/local/twemproxy/conf/nutcracker.yml’],
command: [‘c’, ‘Command to restart twemproxy’, ‘string’, ‘/etc/init.d/twemproxy restart’],
log: [‘l’, ‘The log file location’, ‘string’, ‘/usr/local/twemproxy/run/twemproxy_sentinel.log’]
});
(3).将 redis-twemproxy-agent/init.d/twemproxy_sentinel 复制到 /etc/init.d/ 目录下:
cp /usr/local/redis-twemproxy-agent/init.d/twemproxy_sentinel /etc/init.d/

# 修改该脚本redis-twemproxy-agent,nodejs,forever,的路径为实际路径,参考如下:
ROOT=/usr/local/redis-twemproxy-agent
EXEC=$ROOT/bin/redis_twemproxy_agent
NODE=/usr/bin/node
FOREVER=/usr/bin/forever
(4).启动 redis-twemproxy-agent 服务:
/etc/init.d/twemproxy_sentinel start

# 此测试结果,没有能证明 redis-twemproxy-agent 能自动修改 twemproxy 的配置文件,可能在文件配置方面有误,后续再研究

Redis Sentinel + keepalived 部署

一、Redis Sentinel简介:
Redis Sentinel 是一个分布式系统,你可以在一个架构中运行多个Sentinel 进程(progress),这些进程使用流言协议(gossipprotocols) 来接收关于主服务器是否下线的信息,并使用投票协议(agreement protocols)来决定是否执行自动故障迁移,以及选择哪个从服务器作为新的主服务器。
虽然Redis Sentinel只是一个单独的可执行文件 redis-sentinel,但实际上它只是一个运行在特殊模式下的 Redis 服务器,你可以在启动一个普通 Redis 服务器时通过给定 –sentinel 选项来启动 Redis Sentinel。
源码编译安装后,src目录有一个命名为redis-sentinel的程序。
对于redis-sentinel 程序,你可以用以下命令来启动Sentinel 系统:redis-sentinel /path/to/sentinel.conf

二、Redis Sentinel 的部署:
1.复制 redis 目录为 Redis Sentinel
# 这里我们基于原先 源码编译安装的redis目录,复制一个副本,改名为: Redis Sentinel
cp -r /usr/local/redis-3.0 /usr/local/redis-sentinel

2.正常安装:我们需要建 etc、bin、data、log 等目录;
但是,因为我们是复制redis目录,这写目录都有了,我们只需要稍作改动:
# 在 10.54、10.55 、 10.56 的redis上,都配置此文件,只是在 10.54[ 此机器上没有装redis ]上的配置文件 sentinel client-reconfig-script 注释掉
vim /usr/local/redis-sentinel/etc/sentinel.conf
port 26379
dir /usr/local/redis-sentinel/data
sentinel monitor mymaster 172.16.10.55 6379 1
sentinel down-after-milliseconds mymaster 5000 # 单位为毫秒
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 60000
sentinel client-reconfig-script mymaster /usr/local/redis-sentinel/bin/keepalived.sh # 检测故障后,调用的keepalive脚本,需要有X权限

3.部署redis-sentinel 启动脚本:
vim /usr/local/redis-sentinel/bin/startup.sh
#!/bin/bash
CMD_PATH=/usr/local/redis-sentinel/bin/redis-sentinel
CONF_PATH=/usr/local/redis-sentinel/conf/sentinel.conf
LOG_PATH=/usr/local/redis-sentinel/log/sentinel.log
${CMD_PATH} ${CONF_PATH} >> ${LOG_PATH} 2>&1 &

以下为参考脚本,暂不使用:
#!/bin/bash
#Configurations injected by install_server below….
EXEC=/usr/local/redis-sentinel/bin/redis-sentinel
CLIEXEC=/usr/local/redis-sentinel/bin/redis-cli
PIDFILE=/usr/local/redis-sentinel/log/redis-sentinel_26379.pid
CONF=”/usr/local/redis-sentinel/etc/sentinel.conf”
REDISPORT=”26379″
case “$1” in
start)
if [ -f $PIDFILE ]
then
echo “$PIDFILE exists, process is already running or crashed”
else
echo “Starting Redis server…”
$EXEC $CONF
fi
;;
stop)
if [ ! -f $PIDFILE ]
then
echo “$PIDFILE does not exist, process is not running”
else
PID=$(cat $PIDFILE)
echo “Stopping …”
$CLIEXEC -p $REDISPORT shutdown
while [ -x /proc/${PID} ]
do
echo “Waiting for Redis to shutdown …”
sleep 1
done
echo “Redis stopped”
fi
;;
status)
PID=$(cat $PIDFILE)
if [ ! -x /proc/${PID} ]
then
echo ‘Redis is not running’
else
echo “Redis is running ($PID)”
fi
;;
restart)
$0 stop
$0 start
;;
*)
echo “Please use start, stop, restart or status as first argument”
;;
esac

三、keepalived 部署:
1.keepalive的安装,安装目录为/usr/local/keepalive
# 默认软件已上传并且解压,进入keepalived目录
./configure –prefix=/usr/local/keepalived
make && make install

# 在配置过程中可能出现某些软件包没有正确安装的提示,如openssl,popt等。
解决办法是使用 yum install openssl*以及yum install popt popt-deve l来安装缺少的软件包。
Keepalived 安装完成后,会在安装目录/usr/local/keepalived 生成 bin,etc,man,sbin 这4 个目录。其中etc为配置文件所在的目录。

2.配置 keepalived 环境变量
# 给root用户增加环境变量,在export PATH行之前加入一行:
vi ~/.bash_profile
PATH=$PATH:/usr/local/keepalived/sbin
保存退出,执行下面命令,使参数生效
. ~/.bash_profile

3.整理相关文件和命令,方便使用service 启动
cp -a /usr/local/keepalived/sbin/keepalived /usr/sbin/
cp -a /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
cp -a /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/
# 让chkconfig管理新添加的服务
chkconfig –add keepalived
# 添加启动级别
chkconfig keepalived on
# 查看启动设置
chkconfig –list keepalived

4.keepalived配置文件的修改如下:配置文件目录在( /etc/keepalived/keepalived.conf )
# 172.16.10.55 master 的配置文件
global_defs {
notification_email
{
13501960667@139.com # 收件邮箱
}
notification_email_from mysql_lab@localhost # 发件邮箱
smtp_server localhost # 发件服务器
smtp_connect_timeout 30 # 超时时间
router_id HAOWU_55
}
vrrp_sync_group VG1 {
group
{
VI_1
}
}
vrrp_instance VI_1 {
state MASTER
# state BACKUP
# nopreempt
interface eth0
virtual_router_id 96
priority 110
advert_int 1
authentication
{
auth_type PASS
auth_pass Pa$$w0rd
}
virtual_ipaddress
{
172.16.10.251
}
}

# 172.16.10.56 slave 的配置文件
global_defs {
notification_email
{
13501960667@139.com
}
notification_email_from mysql_lab@localhost
smtp_server localhost
smtp_connect_timeout 30
router_id HAOWU_56
}
vrrp_sync_group VG1 {
group
{
VI_1
}
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 96
priority 100
advert_int 1
authentication
{
auth_type PASS
auth_pass Pa$$w0rd
}
virtual_ipaddress
{
172.16.10.251
}
}

注:
# 红色部分 是在我们实际配置中,需要修改的地方;
# 紫红色部分 是我们在HA操作中,可以参考的设置下:
具体理解如下:
主/从的state 都设置为: BACKUP ,同是将 priority( 110>100 ) 大的机器设置为 nopreempt 可以避免切换后,vip抢占问题;
nopreempt 只能工作于 state 为BACKUP 的状态下;

5.编写keepalived 切换脚本(55、56上配置此脚本):
vim /usr/local/redis-sentinel/bin/keepalived.sh
# 红色加粗脚本,只适用于主机宕机
#!/bin/bash
REDISCLI=”/usr/local/redis-3.0/bin/redis-cli”
if $REDISCLI info|grep role|grep -q master ;then
echo “start keepalived” >> ../log/sentinel.log
/etc/init.d/keepalived start >> ../log/sentinel.log
else
echo “stop keepalived” >> ../log/sentinel.log
/etc/init.d/keepalived stop >> ../log/sentinel.log
fi

# 下面脚本为改进脚本:
#!/bin/bash
EXEC=/usr/local/redis-3.0/bin/redis-server
CLIEXEC=/usr/local/redis-3.0/bin/redis-cli
CONF=”/usr/local/redis-3.0/etc/redis.conf”
REDISPORT=”6379″
KEEP_PID=`ps -A | grep keepalived |awk ‘{print $1}’ > /dev/null`

$CLIEXEC -p $REDISPORT info > /dev/null
if [ $? -eq 0 ]; then
if [ -z “$KEEP_PID” ]; then
# try to start keepalived again
/etc/init.d/keepalived start
else
echo “ERROR!!! server:keepalved is down!” | mail -s “ERROR!! keepalived is down !!!” 13501960667@139.com
fi
else
# try to start it again
# 以下部分 为了测试需要需要注释掉[ 下面这段脚本是判断能否重启redis,这里为测试需要,注释掉 ]
# $EXEC $CONF
# $CLIEXEC -p $REDISPORT info > /dev/null
# if [ $? -eq 0 ]; then
# exit 0
# else
# restart failed
/etc/init.d/keepalived stop
# fi
fi

# 给予脚本 执行权限:
chmod +x /usr/local/redis-sentinel/bin/keepalived.sh

四、部署测试:
1.测试keepalived 虚 ip 切换情况:
master(55) 和 slave(56) :
# 启动 keepalived
/etc/init.d/keepalived start
# 执行 ip addr:查看当前虚ip情况(停掉matser 的keepalived 看 虚IP 是否飘到 slave 上)

2.redis-sentinel启动测试:
/usr/local/redis-sentinel/bin/redis-sentinel /usr/local/redis-sentinel/etc/sentinel.conf
# 启动后,会有详细的信息输出,包括当前的主,redis-sentinel的个数,地址等

# 登陆 redis-sentinel 查看相关信息:
bin/redis-cli -h 172.16.10.56 -p 26379
172.16.10.56:26379> info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
master0:name=mymaster,status=ok,address=172.16.10.55:6379,slaves=1,sentinels=3

3.redis 故障测试:
# 将 当前master(172.16.10.55) 关闭,看redis-sentinel 的切换日志
bin/redis-cli -h 172.16.10.55 -p 6379 shutdown
# 切换日志如下:
15296:X 22 Apr 16:38:49.292 # +sdown master mymaster 172.16.10.55 6379
15296:X 22 Apr 16:38:49.292 # +odown master mymaster 172.16.10.55 6379 #quorum 1/1
15296:X 22 Apr 16:38:49.292 # Next failover delay: I will not start a failover before Wed Apr 22 16:40:49 2015
15296:X 22 Apr 16:38:50.313 # +config-update-from sentinel 172.16.10.54:26379 172.16.10.54 26379 @ mymaster 172.16.10.55 6379
15296:X 22 Apr 16:38:50.313 # +switch-master mymaster 172.16.10.55 6379 172.16.10.56 6379
15296:X 22 Apr 16:38:50.313 * +slave slave 172.16.10.55:6379 172.16.10.55 6379 @ mymaster 172.16.10.56 6379
15296:X 22 Apr 16:38:50.441 # -script-error /usr/local/redis-sentinel/bin/keepalived.sh 0 2
15296:X 22 Apr 16:38:55.342 # +sdown slave 172.16.10.55:6379 172.16.10.55 6379 @ mymaster 172.16.10.56 6379

Redis 主从部署

Redis 部署说明:
redis使用两台机器,172.16.10.55,172.16.100.56。
55为redis master,56为redis slave,
监听默认的6379端口。

(1).创建Redis相关目录:
cd /usr/local/redis-3.0
# 如果相关目录已经在安装时,新建,下面步骤就忽略
mkdir -p /usr/local/redis-3.0/{data,log,etc}

(2).编辑Redis Master/Slave 相关配置文件:
vim etc/redis.conf

Master配置文件(生产实际配置文件不是这样,比较简单)
######################## GENERAL ######################
daemonize yes
pidfile /usr/local/redis-3.0/log/redis_6379.pid
port 6379
timeout 0
loglevel notice
logfile “/usr/local/redis-3.0/log/redis_6379.log”
syslog-enabled no
databases 16
#########################SAVE###########################
dbfilename dump.rdb
dir /usr/local/redis-3.0/data
stop-writes-on-bgsave-error no
#########################REPLICATION ###################
slave-serve-stale-data yes
slave-read-only yes
repl-timeout 60
repl-backlog-size 10mb
repl-backlog-ttl 3600
repl-ping-slave-period 10
min-slaves-to-write 0
min-slaves-max-lag 0
##########################SECURITY ######################
########################## LIMITS ########################
maxclients 2000
#########################APPEND ONLY MODE #############
appendonly no
appendfilename “appendonly.aof”
#########################SLOW LOG #######################
slowlog-log-slower-than 10000
slowlog-max-len 1000

**********************************************************************************

Slave配置文件(生产实际配置文件不是这样,比较简单)
######################## GENERAL ######################
daemonize yes
pidfile /usr/local/redis-3.0/log/redis_6379.pid
port 6379
timeout 0
loglevel notice
logfile “/usr/local/redis-3.0/log/redis.log”
syslog-enabled no
databases 16
#########################SAVE###########################
dbfilename dump.rdb
dir /usr/local/redis-3.0/data
stop-writes-on-bgsave-error no
#########################REPLICATION ###################
slaveof 172.16.10.55 6379
slave-serve-stale-data yes
slave-read-only yes
repl-timeout 60
repl-backlog-size 10mb
repl-backlog-ttl 3600
repl-ping-slave-period 10
min-slaves-to-write 0
min-slaves-max-lag 0
##########################SECURITY ######################
########################## LIMITS ########################
maxclients 2000
#########################APPEND ONLY MODE #############
appendonly no
appendfilename “appendonly.aof”
#########################SLOW LOG #######################
slowlog-log-slower-than 10000
slowlog-max-len 1000

(3).启动/关闭Redis服务:
启动Redis服务顺序:
先启动 Redis Master , 再启动 Redis Slave
关闭Redis服务顺序:
先关闭 Redis Master , 再关闭 Redis Slave

(4).验证Redis 主从复制是否正常:
最简单的方式,就是登录 Redis Master,设置一个值:select 0;set name Michael;
然后登录 Redis Slave ,看能不能获取到刚才设置的那个值:select 0;get name;

网上有种验证方式如下:
进入主从服务器的数据目录,查询对比所有服务器数据文件的散列值和文件大小:
find . -type f -name “*.rdb” | xargs md5sum
find . -type f -name “*.rdb” | xargs ls -l

生成报文摘要并验证,如果对比成功则数据已同步:
find . -type f -name “*.rdb” | xargs md5sum >biran
md5sum –check biran

Keepalived 简介、原理及服务部署

一、Keepalived的介绍:
keepalived是以 VRRP(Virtual Router Redundancy Protocol)协议为实现基础的,即虚拟路由冗余协议。
虚拟路由冗余协议可以认为是实现路由器高可用的协议,即将N台提供相同功能的路由器组成一个路由器组,这个组里面,有一个master和多个backup;
master上面有一个对外提供服务的vip,该路由器所在局域网内其他机器的默认路由为该vip;
master会发组播,当backup收不到vrrp包时,就认为master宕掉了;
这时,就需要根据VRRP的优先级,来选举一个backup当master。
这样的话就可以保证路由器的高可用了。

二、Keepalived的原理:
keepalived也是模块化设计,不同模块复杂不同的功能,下面是keepalived的组件:
core check vrrp libipfwc libipvs-2.4 libipvs-2.6

core:是keepalived的核心,复杂主进程的启动和维护,全局配置文件的加载解析等
check:负责healthchecker(健康检查),包括了各种健康检查方式,以及对应的配置的解析包括LVS的配置解析
vrrp:VRRPD子进程,VRRPD子进程就是来实现VRRP协议的
libipfwc:iptables(ipchains)库,配置LVS会用到
libipvs*:配置LVS会用到

# 注:
keepalived和LVS完全是两码事,只不过他们各负其责相互配合而已
Image
keepalived启动后会有三个进程
父进程:内存管理,子进程管理等等
子进程:VRRP子进程
子进程:healthchecker子进程

由图可知,两个子进程都被系统WatchDog看管,两个子进程各自复杂自己的事;
healthchecker子进程复杂检查各自服务器的健康程度,例如HTTP,LVS等等;
如果healthchecker子进程检查到MASTER上服务不可用了,就会通知本机上的兄弟VRRP子进程,让他删除通告,并且去掉虚拟IP,转换为BACKUP状态

三、Keepalived的部署:
1.安装相关依赖包:
yum -y install openssl* popt popt-devel

2.keepalive的安装,安装目录为/usr/local/keepalived
# 默认软件已上传 并且 解压,进入keepalived目录
./configure –prefix=/usr/local/keepalived
make && make install

# Keepalived 安装完成后,会在安装目录/usr/local/keepalived 生成 bin,etc,man,sbin 这4 个目录。其中etc为配置文件所在的目录。

3.配置 keepalived 环境变量
# 给root用户增加环境变量,在export PATH行之前加入一行:
vi ~/.bash_profile
PATH=$PATH:/usr/local/keepalived/sbin
保存退出,执行下面命令,使参数生效
. ~/.bash_profile

4.整理相关文件和命令,方便使用service 启动
cp -a /usr/local/keepalived/sbin/keepalived /usr/sbin/
cp -a /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/
cp -a /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/
# 让chkconfig管理新添加的服务
chkconfig –add keepalived
# 添加启动级别
chkconfig keepalived on
# 查看启动设置
chkconfig –list keepalived

5.keepalived配置文件的修改如下:配置文件目录在( /etc/keepalived/keepalived.conf ),没有就自己建一个
配置文件参考: linux — linux 配置文件详解 — keepalived 配置文件详解
vim /etc/keepalived/keepalived.conf
# master 参考配置文件
global_defs {
notification_email
{
13501960667@139.com # 收件邮箱
}
notification_email_from mysql_lab@localhost # 发件邮箱
smtp_server localhost # 发件服务器
smtp_connect_timeout 30 # 超时时间
router_id HAOWU_55
}
vrrp_sync_group VG1 {
group
{
VI_1
}
}
vrrp_instance VI_1 {
state MASTER
# state BACKUP
# nopreempt
interface eth0
virtual_router_id 96
priority 110
advert_int 1
authentication
{
auth_type PASS
auth_pass Pa$$w0rd
}
virtual_ipaddress
{
172.16.10.251
}
}

注:
# 红色部分 是在我们实际配置中,需要修改的地方;
# 紫红色部分 是我们在HA操作中,可以参考的设置下:
具体理解如下:
主/从的state 都设置为: BACKUP ,同是将 priority( 110>100 ) 大的机器设置为 nopreempt 可以避免切换后,vip抢占问题;
nopreempt 只能工作于 state 为BACKUP 的状态下;

# 如果利用keepalived调用脚本,则脚本里不能含有weight ,否则,会无法调用脚本。

Redis 3.0 编译安装

官方主站:http://www.redis.io/
下载地址:http://www.redis.cn/download.html
Command API: http://www.redis.cn/commands.html
Redis官方文档:http://redis.io/documentation

一.Redis 介绍:
Redis是Remote Dictionary Server的缩写。他本质上一个Key/Value数据库,与Memcached类似的NoSQL型数据库,但是他的数据可以持久化的保存在磁盘上,解决了服务重启后数据不丢失的问题,他的值可以是string(字符串)、list(列表)、sets(集合)或者是ordered sets(被排序的集合),所有的数据类型都具有push/pop、add/remove、执行服务端的并集、交集、两个sets集中的差别等等操作,这些操作都是具有原子性的,Redis还支持各种不同的排序能力。

二.Redis 部署
1.安装相关依赖包:
yum -y install gcc gcc-c++ cmake make

2.安装tcmalloc包[ 尝试采用新的内存分配方式 ]
Redis并没有自己实现内存池,没有在标准的系统内存分配器上再加上自己的东西。
所以系统内存分配器的性能及碎片率会对Redis造成一些性能上的影响。
在最新版本中,jemalloc已经作为源码包的一部分包含在源码包中,所以可以直接被使用。
如果要使用tcmalloc的话,是需要自己安装的。

tcmalloc是google-proftools( http://code.google.com/p/gperftools/downloads/list)中的一部分,
所以我们实际上需要安装google-proftools。如果你是在64位机器上进行安装,需要先安装其依赖的libunwind库,32位的系统不需要
下载地址: http://download.savannah.gnu.org/releases/libunwind/libunwind-0.99-alpha.tar.gz

(1).安装libunwind
tar zxvf libunwind-0.99-alpha.tar.gz
cd libunwind-0.99-alpha/
CFLAGS=-fPIC ./configure
make CFLAGS=-fPIC
make CFLAGS=-fPIC install

(2).安装gperftools
tar zxvf gperftools-2.1.tar.gz
cd gperftools-2.1
./configure –disable-cpu-profiler –disable-heap-profiler –disable-heap-checker –disable-debugalloc –enable-minimal
make && make install
cd /usr/local/lib
ln -sv libtcmalloc_minimal.so.4.1.2 libtcmalloc.so
# 加粗部分如果不做的话,后面编译redis会报错: usr/bin/ld: cannot find ltcmalloc
echo “/usr/local/lib” > /etc/ld.so.conf.d/usr_local_lib.conf #如果没有这个文件,自己建一个
/sbin/ldconfig

3.Redis 安装:
tar zxvf redis-3.0.0.tar.gz
cd redis-3.0.0
mkdir -p /usr/local/redis-3.0
# make prefix= install
# 将redis安装在/bin下/usr/local/redis-3.0/bin下
# make PREFIX=/usr/local/redis-3.0 install # 此方式安装,使用linux默认的内存分配方式
make PREFIX=/usr/local/redis-3.0 USE_TCMALLOC=yes FORCE_LIBC_MALLOC=yes install

4.建相关目录,并配置redis.conf 文件[简单配置]
cd /usr/local/redis-3.0/
mkdir etc #存放配置文件,这里目录名,可建为:conf
mkdir log #存放日志和pid文件
mkdir data #存放数据
vim etc/redis.conf
daemonize yes
port 6379
pidfile /usr/local/redis-3.0/log/redis_6379.pid
dir /usr/local/redis-3.0/data
logfile /usr/local/redis-3.0/log/redis_6379.log

5.Redis服务启动、关闭
(1).启动服务:
/usr/local/redis-3.0/bin/redis-server /usr/local/redis-3.0/etc/redis.conf
注:
此命令仅有一个启动参数,指定目录下的配置文件,不加参数执行默认配置。
测试启动:
/usr/local/redis-3.0/bin/redis-cli ping
返回PONG,则启动成功。
查看端口是否被占用:
netstat -ntlp |grep 6379

(2).关闭服务:
/usr/local/redis-3.0/bin/redis-cli shutdown
如果非默认端口,可指定端口:
/usr/local/redis-3.0/bin/redis-cli -p 6380 shutdown

(3).验证redis内存分配方式是否在使用tcmalloc
lsof -n |grep tcmalloc
redis-ser 2754 root mem REG 253,0 1078467 1725996 /usr/local/lib/libtcmalloc_minimal.so.4.1.2

6.Redis 服务启动脚本
redis 本身提供了redis安装脚本:utils/install_server.sh
但 这个脚本包括安装服务,有点烦,我们直接取其安装脚本:
#!/bin/sh
#Configurations injected by install_server below….
EXEC=/usr/local/redis-3.0/bin/redis-server
CLIEXEC=/usr/local/redis-3.0/bin/redis-cli
PIDFILE=/usr/local/redis-3.0/log/redis_6379.pid
CONF=”/usr/local/redis-3.0/etc/redis.conf”
REDISPORT=”6379″

case “$1” in
start)
if [ -f $PIDFILE ]
then
echo “$PIDFILE exists, process is already running or crashed”
else
echo “Starting Redis server…”
$EXEC $CONF
fi
;;
stop)
if [ ! -f $PIDFILE ]
then
echo “$PIDFILE does not exist, process is not running”
else
PID=$(cat $PIDFILE)
echo “Stopping …”
$CLIEXEC -p $REDISPORT shutdown
while [ -x /proc/${PID} ]
do
echo “Waiting for Redis to shutdown …”
sleep 1
done
echo “Redis stopped”
fi
;;
status)
PID=$(cat $PIDFILE)
if [ ! -x /proc/${PID} ]
then
echo ‘Redis is not running’
else
echo “Redis is running ($PID)”
fi
;;
restart)
$0 stop
$0 start
;;
*)
echo “Please use start, stop, restart or status as first argument”
;;
esac

Redis的复制流程

Redis的复制功能是基于内存快照的持久化策略基础上的,也就是说无论你的持久化策略选择的是什么,只要用到了Redis的复制功能,就一定会有内存快照发生,那么首先要注意你的系统内存容量规划

Redis复制流程在Slave和Master端各自是一套状态机流转,涉及的状态信息如下:
Slave 端:
REDIS_REPL_NONE
REDIS_REPL_CONNECT
REDIS_REPL_CONNECTED
Master端:

          REDIS_REPL_WAIT_BGSAVE_START
REDIS_REPL_WAIT_BGSAVE_END
REDIS_REPL_SEND_BULK
REDIS_REPL_ONLINE

整个状态机流程过程如下:
(1).Slave端在配置文件中添加了slave of指令,于是Slave启动时读取配置文件,初始状态为REDIS_REPL_CONNECT。
(2).Slave端在定时任务serverCron(Redis内部的定时器触发事件)中连接Master,发送sync命令,然后阻塞等待master发送回其内存快照文件(最新版的Redis已经不需要让Slave阻塞)。
     (3).Master端收到sync命令简单判断是否有正在进行的内存快照子进程,没有则立即开始内存快照,有则等待其结束,当快照完成后会将该文件发送给Slave端。
     (4).Slave端接收Master发来的内存快照文件,保存到本地,待接收完成后,清空内存表,重新读取Master发来的内存快照文件,重建整个内存表数据结构,并最终状态置位为 REDIS_REPL_CONNECTED状态,Slave状态机流转完成。
     (5).Master端在发送快照文件过程中,接收的任何会改变数据集的命令都会暂时先保存在Slave网络连接的发送缓存队列里(list数据结构),待快照完成后,依次发给Slave,之后收到的命令相同处理,并将状态置位为 REDIS_REPL_ONLINE。
整个复制过程完成,流程如下图所示:
 image1
Redis复制机制的缺陷

      从上面的流程可以看出,Slave从库在连接Master主库时,Master会进行内存快照,然后把整个快照文件发给Slave,
     也就是没有象MySQL那样有复制位置的概念,即无增量复制,这会给整个集群搭建带来非常多的问题。

比如一台线上正在运行的Master主库配置了一台从库进行简单读写分离,这时Slave由于网络或者其它原因与Master断开了连接,

     那么当Slave进行重新连接时,需要重新获取整个Master的内存快照,Slave所有数据跟着全部清除,
     然后重新建立整个内存表,一方面Slave恢复的时间会非常慢,另一方面也会给主库带来压力。
所以基于上述原因,如果你的Redis集群需要主从复制,那么最好事先配置好所有的从库,避免中途再去增加从库。

Cache还是Storage
在我们分析过了Redis的复制与持久化功能后,我们不难得出一个结论,实际上Redis目前发布的版本还都是一个单机版的思路,主要的问题集中在,持久化方式不够成熟,复制机制存在比较大的缺陷,这时我们又开始重新思考Redis的定位:Cache还是Storage?
如果作为Cache的话,似乎除了有些非常特殊的业务场景,必须要使用Redis的某种数据结构之外,我们使用Memcached可能更合适,毕竟Memcached无论客户端包和服务器本身更久经考验。
如果是作为存储Storage的话,我们面临的最大的问题是无论是持久化还是复制都没有办法解决Redis单点问题,即一台Redis挂掉了,没有太好的办法能够快速的恢复,通常几十G的持久化数据,Redis重启加载需要几个小时的时间,而复制又有缺陷,如何解决呢?

Redis可扩展集群搭建
1. 主动复制避开Redis复制缺陷。
既然Redis的复制功能有缺陷,那么我们不妨放弃Redis本身提供的复制功能,我们可以采用主动复制的方式来搭建我们的集群环境。
所谓主动复制是指由业务端或者通过代理中间件对Redis存储的数据进行双写或多写,通过数据的多份存储来达到与复制相同的目的,
               主动复制不仅限于用在Redis集群上,目前很多公司采用主动复制的技术来解决MySQL主从之间复制的延迟问题,
               比如Twitter还专门开发了用于复制和分区的中间件gizzard(https://github.com/twitter/gizzard) 。

主动复制虽然解决了被动复制的延迟问题,但也带来了新的问题,就是数据的一致性问题,数据写2次或多次,如何保证多份数据的一致性呢?

               如果你的应用对数据一致性要求不高,允许最终一致性的话,那么通常简单的解决方案是可以通过时间戳或者vector clock等方式,
               让客户端同时取到多份数据并进行校验,如果你的应用对数据一致性要求非常高,那么就需要引入一些复杂的一致性算法比如Paxos来保证数据的一致性,
               但是写入性能也会相应下降很多。

通过主动复制,数据多份存储我们也就不再担心Redis单点故障的问题了,如果一组Redis集群挂掉,我们可以让业务快速切换到另一组Redis上,降低业务风险。

2. 通过presharding进行Redis在线扩容。
通过主动复制我们解决了Redis单点故障问题,那么还有一个重要的问题需要解决:容量规划与在线扩容问题。
我们前面分析过Redis的适用场景是全部数据存储在内存中,而内存容量有限,那么首先需要根据业务数据量进行初步的容量规划,

                比如你的业务数据需要100G存储空间,假设服务器内存是48G,我们大约需要3~4台服务器来存储。
                这个实际是对现有业务情况所做的一个容量规划,假如业务增长很快,很快就会发现当前的容量已经不够了,Redis里面存储的数据很快就会超过物理内存大小,
                那么如何进行Redis的在线扩容呢?

Redis的作者提出了一种叫做presharding的方案来解决动态扩容和数据分区的问题,

     实际就是在同一台机器上部署多个Redis实例的方式,当容量不够时将多个实例拆分到不同的机器上,这样实际就达到了扩容的效果。

拆分过程如下:
在新机器上启动好对应端口的Redis实例。
配置新端口为待迁移端口的从库。
待复制完成,与主库完成同步后,切换所有客户端配置到新的从库的端口。
配置从库为新的主库。
移除老的端口实例。
重复上述过程迁移好所有的端口到指定服务器上。
     以上拆分流程是Redis作者提出的一个平滑迁移的过程,不过该拆分方法还是很依赖Redis本身的复制功能的,
     如果主库快照数据文件过大,这个复制的过程也会很久,同时会给主库带来压力。所以做这个拆分的过程最好选择为业务访问低峰时段进行。

Redis复制的改进思路
我们线上的系统使用了我们自己改进版的Redis,主要解决了Redis没有增量复制的缺陷,能够完成类似Mysql Binlog那样可以通过从库请求日志位置进行增量复制。
我们的持久化方案是首先写Redis的AOF文件,并对这个AOF文件按文件大小进行自动分割滚动,同时关闭Redis的Rewrite命令,
     然后会在业务低峰时间进行内存快照存储,并把当前的AOF文件位置一起写入到快照文件中,这样我们可以使快照文件与AOF文件的位置保持一致性,
     这样我们得到了系统某一时刻的内存快照,并且同时也能知道这一时刻对应的AOF文件的位置,那么当从库发送同步命令时,
     我们首先会把快照文件发送给从库,然后从库会取出该快照文件中存储的AOF文件位置,并将该位置发给主库,主库会随后发送该位置之后的所有命令,
     以后的复制就都是这个位置之后的增量信息了。
 image2
Redis与MySQL的结合
目前大部分互联网公司使用MySQL作为数据的主要持久化存储,那么如何让Redis与MySQL很好的结合在一起呢?
     我们主要使用了一种基于MySQL作为主库,Redis作为高速数据查询从库的异构读写分离的方案。

为此我们专门开发了自己的MySQL复制工具,可以方便的实时同步MySQL中的数据到Redis上。

 image3
(MySQL-Redis 异构读写分离)

总结:

Redis的复制功能没有增量复制,每次重连都会把主库整个内存快照发给从库,所以需要避免向在线服务的压力较大的主库上增加从库。
Redis的复制由于会使用快照持久化方式,所以如果你的Redis持久化方式选择的是日志追加方式(aof),

     那么系统有可能在同一时刻既做aof日志文件的同步刷写磁盘,又做快照写磁盘操作,这个时候Redis的响应能力会受到影响。
     所以如果选用aof持久化,则加从库需要更加谨慎。
可以使用主动复制和presharding方法进行Redis集群搭建与在线扩容。