Codis的安装需要依赖于Go和zookeeper(可选),因此首先需要安装Go和zookeeper。
1.Go版本的检测
需要注意的时Go的版本不能太低,建议在1.8.3版本以上,通过go version命令查看已安装Go的版本信息,若版本过低则卸掉:
yum remove golang(确保没有低版本的golang,保证是重新安装而不是覆盖,否则会有问题);
2.Go的安装
官网下载go1.8.3.linux-amd64.tar.gz并解压到/usr/local/go目录下,解压即可无需编译,环境变量设置vi /etc/profile:
unset i
unset -f pathmunge
## add by zhengguangguo 20171104
# 1.Go的安装路径
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin
# 2.Go的环境变量,第三方软件下载编译的位置
export GOPATH=/home/xiaoju/goSRC
#export PATH
设置完成后用source /etc/profile命令使其配置立即生效,之后可以通过go version和go env命令进行查看。
1.安装jdk,建议1.8版本以上,可参考我的另一篇文章
2.zookeeper下载
3.配置参数cd /usr/local/zookeeper-3.4.10/conf/ && cp zoo_sample.cfg zoo.cfg
4.启动 zookeeper: cd bin/ && zkServer.sh start
[root@8d87c72e5e65 bin]# netstat -anput | grep java
tcp 0 0 0.0.0.0:44203 0.0.0.0:* LISTEN 9447/java
tcp 0 0 0.0.0.0:2181 0.0.0.0:* LISTEN 9447/java
[root@8d87c72e5e65 bin]#
[root@8d87c72e5e65 bin]#
[root@8d87c72e5e65 bin]# ps aux | grep java
root 9447 1.3 0.0 38223568 67464 pts/0 Sl 15:49 0:00 java -Dzookeeper.log.dir=. -Dzookeeper.root.logger=INFO,CONSOLE -cp /usr/local/zookeeper-3.4.10/bin/../build/classes:/usr/local/zookeeper-3.4.10/bin/../build/lib/*.jar:/usr/local/zookeeper-3.4.10/bin/../lib/slf4j-log4j12-1.6.1.jar:/usr/local/zookeeper-3.4.10/bin/../lib/slf4j-api-1.6.1.jar:/usr/local/zookeeper-3.4.10/bin/../lib/netty-3.10.5.Final.jar:/usr/local/zookeeper-3.4.10/bin/../lib/log4j-1.2.16.jar:/usr/local/zookeeper-3.4.10/bin/../lib/jline-0.9.94.jar:/usr/local/zookeeper-3.4.10/bin/../zookeeper-3.4.10.jar:/usr/local/zookeeper-3.4.10/bin/../src/java/lib/*.jar:/usr/local/zookeeper-3.4.10/bin/../conf: -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.local.only=false org.apache.zookeeper.server.quorum.QuorumPeerMain /usr/local/zookeeper-3.4.10/bin/../conf/zoo.cfg
root 9529 0.0 0.0 112644 952 pts/0 S+ 15:50 0:00 grep --color=auto java
[root@8d87c72e5e65 bin]#
[root@8d87c72e5e65 bin]#
1.创建codis的安装目录
codis的编译依赖于go,需要将codis的安装目录设置在$GOPATH目录下,手动创建codis的目录:mkdir -p $GOPATH/src/github.com/CodisLabs
2.源码下载与编译安装
进入目录:cd goSRC/src/github.com/CodisLabs
下载源码:git clone https://github.com/CodisLabs/codis.git -b release3.2
编译:cd codis && make
3.启动脚本 run.sh
codis的安装目录递归太深,可以建立外层软连接方便后续使用
[root@8d87c72e5e65 xiaoju]# ln -s /home/xiaoju/goSRC/src/github.com/CodisLabs/codis/ codis
[root@8d87c72e5e65 xiaoju]# pwd
/home/xiaoju
[root@8d87c72e5e65 xiaoju]# ll
total 0
lrwxrwxrwx 1 root root 50 Nov 4 15:36 codis -> /home/xiaoju/goSRC/src/github.com/CodisLabs/codis/
drwxrwxr-x 4 xiaoju xiaoju 26 Nov 4 15:11 goSRC
drwxrwxr-x 2 xiaoju xiaoju 6 Nov 3 22:04 perl5
[root@8d87c72e5e65 xiaoju]#
新建启动脚本/home/xiaoju/codis/run.sh
#!/bin/bash
cd `dirname $0` || exit
#ulimit -c unlimited
msg() {
printf '%b\n' "$1" >&2
}
success() {
if [ x"$ret" = "x0" ]; then
msg "\33[32m[✔ succ]\33[0m ${1}${2}"
fi
}
error() {
if [ x"$ret" != "x0" ]; then
msg "\33[31m[✘ error]\33[0m ${1}${2}"
fi
}
start() {
sh admin/codis-dashboard-admin.sh start &
sh admin/codis-proxy-admin.sh start &
sh admin/codis-server-admin.sh start &
sh admin/codis-fe-admin.sh start &
success "codis started"
}
stop() {
sh admin/codis-dashboard-admin.sh stop &
sh admin/codis-proxy-admin.sh stop &
sh admin/codis-server-admin.sh stop &
sh admin/codis-fe-admin.sh stop &
success "codis stoped"
}
restart() {
stop
sleep 10
start
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
*)
echo "Usage: $0 {start|stop|restart}"
;;
esac
启动/home/xiaoju/codis/run.sh start
4.web管理配置
参考官网依次配置:通过fe添加group和通过fe添加group这两个操作。官网https://github.com/CodisLabs/codis/blob/release3.2/doc/tutorial_zh.md
5.配置上zookeeper(可选)
关闭codis的服务,修改如下一个配置文件后启动
6.redis的配置文件
默认情况下,处于安全考虑,redis只能本机访问,若想让其他的IP也能访问,则可将其参数改为如下:
#bind 127.0.0.1
bind 0.0.0.0
1.etcd
2.zookeeper
3.zookeeper学习笔记之分布式锁实现
提到Redis,就不得不提及到Redis底层的数据结构:跳跃表,性能堪比红黑树。
Redis有哪些数据结构?
字符串String、字典Hash、列表List、集合Set、有序集合SortedSet。
如果你是Redis中高级用户,还需要加上下面几种数据结构HyperLogLog、Geo、Pub/Sub。
如果你说还玩过Redis Module,像BloomFilter,RedisSearch,Redis-ML,面试官得眼睛就开始发亮了。
使用过Redis分布式锁么,它是什么回事?
先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
这时候对方会告诉你说你回答得不错,然后接着问如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?
这时候你要给予惊讶的反馈:唉,是喔,这个锁就永远得不到释放了。紧接着你需要抓一抓自己得脑袋,故作思考片刻,好像接下来的结果是你主动思考出来的,然后回答:我记得set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的!对方这时会显露笑容,心里开始默念:摁,这小子还不错。
假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如果将它们全部找出来?
使用keys指令可以扫出指定模式的key列表。
对方接着追问:如果这个redis正在给线上的业务提供服务,那使用keys指令会有什么问题?
这个时候你要回答redis关键的一个特性:redis的单线程的。keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。
使用过Redis做异步队列么,你是怎么用的?
一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。
如果对方追问可不可以不用sleep呢?list还有个指令叫blpop,在没有消息的时候,它会阻塞住直到消息到来。
如果对方追问能不能生产一次消费多次呢?使用pub/sub主题订阅者模式,可以实现1:N的消息队列。
如果对方追问pub/sub有什么缺点?在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。
如果对方追问redis如何实现延时队列?我估计现在你很想把面试官一棒打死如果你手上有一根棒球棍的话,怎么问的这么详细。但是你很克制,然后神态自若的回答道:使用sortedset,拿时间戳作为score,消息内容作为key调用zadd来生产消息,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理。
到这里,面试官暗地里已经对你竖起了大拇指。但是他不知道的是此刻你却竖起了中指,在椅子背后。
如果有大量的key需要设置同一时间过期,一般需要注意什么?
如果大量的key过期时间设置的过于集中,到过期的那个时间点,redis可能会出现短暂的卡顿现象。一般需要在时间上加一个随机值,使得过期时间分散一些。
Redis如何做持久化的?
bgsave做镜像全量持久化,aof做增量持久化。因为bgsave会耗费较长时间,不够实时,在停机的时候会导致大量丢失数据,所以需要aof来配合使用。在redis实例重启时,会使用bgsave持久化文件重新构建内存,再使用aof重放近期的操作指令来实现完整恢复重启之前的状态。
对方追问那如果突然机器掉电会怎样?取决于aof日志sync属性的配置,如果不要求性能,在每条写指令时都sync一下磁盘,就不会丢失数据。但是在高性能的要求下每次都sync是不现实的,一般都使用定时sync,比如1s1次,这个时候最多就会丢失1s的数据。
对方追问bgsave的原理是什么?你给出两个词汇就可以了,fork和cow。fork是指redis通过创建子进程来进行bgsave操作,cow指的是copy on write,子进程创建后,父子进程共享数据段,父进程继续提供读写服务,写脏的页面数据会逐渐和子进程分离开来。
Pipeline有什么好处,为什么要用pipeline?
可以将多次IO往返的时间缩减为一次,前提是pipeline执行的指令之间没有因果相关性。使用redis-benchmark进行压测的时候可以发现影响redis的QPS峰值的一个重要因素是pipeline批次指令的数目。
Redis的同步机制了解么?
Redis可以使用主从同步,从从同步。第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。
是否使用过Redis集群,集群的原理是什么?
Redis Sentinal着眼于高可用,在master宕机时会自动将slave提升为master,继续提供服务。Redis Cluster着眼于扩展性,在单个redis内存不足时,使用Cluster进行分片存储。
缓存的雪崩以及穿透的理解
Redis架构之防雪崩设计