缓存体系

学习要有一个体系

缓存的主要指标就是命中率

层级 内容 详情

DNS解析 DNS缓存

浏览器 浏览器缓存 1、最后修改时间 2、过期时间 3、打标签

CDN(解决就近访问问题) 反向代理缓存 Squid,varnlsh,nginx,ATg

web服务器 web服务器缓存 Apache,Nginx,

Local Cache 应用本地缓存

语言缓存 OPcache操作码缓存和优化提供更快的PHP 执行过程会给系统带来五分之二或三的性能提升

分布式缓存 分布式缓存 memcached,redis

数据库 MySQL innodb缓存,MYISAM

操作系统 Page Cache(Linux 内核的文件Cache 页缓存)

CPU Cache   L1,L2,L3
        
        内存 Cache

磁盘 Disk Cache(磁盘缓存)

硬件 raid Cache 磁盘阵列缓存

为什么要把图片放在单独的域名,这样做有什么好处?

1、可以做组件分离、动静分离(为不同的资源,配备不同的存储和web访问,比如动静分离)

2、静态资源,方便上CDN,

3、加快页面打开速度,提高浏览器并发。浏览器请求并发数是基于域名的。

4、jd.com pic.jd.com www.jdpic.com 1.动态请求写入的cookie,浏览器每次请求本域名下的其他资源,都会附带上cookie。

2.如果你使用pic.jd.com的时候,访问图片也是需要附带cookie(有一个作用域)的。

3.如果你想把静态资源单独存放,注意一定要使用另外的顶级域名。因为cookie是有作用域的。

1、提高了速度 
2、减少了带宽(因为每张图片都带cookie的话,那么如果你是电商网站将占非常大的带宽)

弊端 解析的域名多了,DNS解析非常快这个可以忽略。

分布式缓存之Redis

官网:https://redis.io/

可以源码安装和yum安装,最佳的是yum 安装。

想定制,自己做一个rpm包。yum 安装

yum 安装

先换成epel源

centos 6 http://mirrors.aliyun.com/repo/epel-6.repo centos 7 http://mirrors.aliyun.com/repo/epel-7.repo

系统环境

[root@server-000 ~]# cat /etc/redhat-release 
CentOS Linux release 7.2.1511 (Core) 
[root@server-000 ~]# uname -rn
server-000.novalocal 3.10.0-327.el7.x86_64

yum 安装

[root@server-000 ~]# cd /etc/yum.repos.d/
[root@server-000 yum.repos.d]# wget http://mirrors.aliyun.com/repo/epel-7.repo

[root@server-000 yum.repos.d]# cd 
[root@server-000 ~]# yum install -y redis

查看redis都安装了什么

[root@server-000 ~]# rpm -qa redis
redis-2.4.10-1.el6.x86_64
[root@server-000 ~]# rpm -ql redis
/etc/logrotate.d/redis      #日志
/etc/rc.d/init.d/redis      #
/etc/redis.conf         #配置
/usr/bin/redis-benchmark        #系统测试
/usr/bin/redis-check-aof        #检测日志
/usr/bin/redis-check-dump       
/usr/bin/redis-cli          #客户端登录
/usr/sbin/redis-server
/usr/share/doc/redis-2.4.10
/usr/share/doc/redis-2.4.10/00-RELEASENOTES     #文档
/usr/share/doc/redis-2.4.10/BUGS
/usr/share/doc/redis-2.4.10/CONTRIBUTING
/usr/share/doc/redis-2.4.10/COPYING
/usr/share/doc/redis-2.4.10/README
/usr/share/doc/redis-2.4.10/TODO
/var/lib/redis          #创建了三个目录
/var/log/redis  
/var/run/redis          #运行目录存放pid的。管理进程的时候可以看到,意外关闭会提示pid已存在,正常关闭就不会出现这样的情况。最后会自动把pid删除。

写脚本的最佳实践就是,我们在写脚本的时候,最好程序启动的时候,要在某个地方创建一个log文件,这样可以预防他人多次启动而带来的灾难,在我们关闭的时候,程序自动删除log文件,启动的时候判断如果log文件存在,那么就给出提示。

application 安装完毕之后我们要第一时间查看配置文件,看那个地方需要我们修改的。

[root@server-000 ~]# vim /etc/redis.conf #只修改了绑定ip的地址

配置文件中的备注

daemonize yes       #是否是守护进程,yum安装缺省是yes,源码安装缺省是no

pidfile /var/run/redis/redis.pid  #pid存放的位置

port 6379       #端口

bind 192.168.0.5   #绑定的自己的ip地址

#注释的就是表示默认的

timeout 0           #控制客户端空闲几秒断开,0表示不主动断开,

loglevel notice     #日志级别

logfile /var/log/redis/redis.log  #日志文件

databases 16        #redis支持MySQL数据的的个数0-16  就是17个,是从0开始数的,要用多个就改大。

save 900 1          #900秒内如果有一个key被改变那么就快照
save 300 10         #300秒内如果有10个建被改变那么就快照
save 60 10000       #60秒内如果有10000个键被改变那么就快照 对性能影响还是挺大的

 97 dbfilename dump.rdb   #存快照的地方
 107 dir /var/lib/redis/    #如果在编译的时候没指定或者配置文件没有指定,那么你在哪里启动这个配置文件就在当前目录下。
 
 
 [root@server-000 ~]# vim /etc/redis.conf 
[root@server-000 ~]# ll /var/lib/redis/
总用量 4
-rw-r--r-- 1 redis redis 127 57 20:07 dump.rdb

启动redis

[root@server-000 ~]# /etc/init.d/redis
Usage: /etc/init.d/redis {start|stop|status|restart|condrestart|try-restart}

[root@server-000 ~]# /etc/init.d/redis start
Starting redis (via systemctl):                            [  确定  ]

查看启动端口

[root@server-000 ~]# lsof -i :6379
COMMAND    PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
redis-ser 9947 redis    4u  IPv4 207733      0t0  TCP server-000.novalocal:6379 (LISTEN)
[root@server-000 ~]# netstat -lntup|grep redis
tcp        0      0 192.168.0.5:6379        0.0.0.0:*               LISTEN      9947/redis-server

登录到redis

#默认的话是直接连接到127.0.0.1:6379:
[root@server-000 ~]# redis-cli 
Could not connect to Redis at 127.0.0.1:6379: Connection refused
not connected> exit

#我们通过help知道-h 而已指定ip -p 指定端口 -s 指定socket
[root@server-000 ~]# redis-cli --help
redis-cli 2.4.10

Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]
  -h <hostname>    Server hostname (default: 127.0.0.1)
  -p <port>        Server port (default: 6379)
  -s <socket>      Server socket (overrides hostname and port)
  -a <password>    Password to use when connecting to the server
  -r <repeat>      Execute specified command N times
  -i <interval>    When -r is used, waits <interval> seconds per command.
                   It is possible to specify sub-second times like -i 0.1.
  -n <db>          Database number
  -x               Read last argument from STDIN
  -d <delimiter>   Multi-bulk delimiter in for raw formatting (default: \n)
  --raw            Use raw formatting for replies (default when STDOUT is not a tty)
  --latency        Enter a special mode continuously sampling latency.
  --help           Output this help and exit
  --version        Output version and exit

Examples:
  cat /etc/passwd | redis-cli -x set mypasswd
  redis-cli get mypasswd
  redis-cli -r 100 lpush mylist x
  redis-cli -r 100 -i 1 info | grep used_memory_human:

When no command is given, redis-cli starts in interactive mode.
Type "help" in interactive mode for information on available commands.

#登录
[root@server-000 ~]# redis-cli -h 192.168.0.5
redis 192.168.0.5:6379>

redis是一个key value的数据库一个键对应一个值

#登录redis
[root@server-000 ~]# redis-cli -h 192.168.0.5

#创建key
redis 192.168.0.5:6379> SET mykey hehe          #SET 命令 mykey key  hehe key的值
OK      #返回OK

#查看key
redis 192.168.0.5:6379> GET mykey           #查看mykey对应的值,命令不区分大小写,但是关键命令我们还是使用大写。
"hehe"          #双引号表示是一个字符串

#遍历库里所有key
redis 192.168.0.5:6379> keys *      #查看我们当前DB中有多少,生产不能用,会把库里所有遍历一遍,会影响业务。
1) "mykey"

#判断一个key是否存在,存在返回1,不存在返回0
redis 192.168.0.5:6379> EXISTS mykey
(integer) 1         #integer整数类型
redis 192.168.0.5:6379> EXISTS mykeye
(integer) 0


#删除成功也是返回一个整数1,不存在返回0
redis 192.168.0.5:6379> DEL mykey
(integer) 1
redis 192.168.0.5:6379> DEL mykeysdsada
(integer) 0


#判断字符串类型
redis 192.168.0.5:6379> SET mykey hehe
OK
redis 192.168.0.5:6379> TYPE mykey
string      #字符串

#学习数据结构,我们可以知道什么情况下我们可以使用redis

Redis介绍

Redis和memcached对比

memcached                   redis

类型 key-value数据库 Key-value数据库

过期策略 支持 支持

数据类型 单一数据类型 多种数据类型

持久化 不支持 支持

主从复制 不支持 支持

虚拟内存 不支持 支持(不建议使用,弃用)

redis基本命令

SET:设置key。

GET:获取key值。

EXISTS:判断key是否存在。

KEYS:显示所有的key(生产慎用)

DEL:删除指定的key。

TYPE:获取Key的类型。

Redis数据结构

字符类型

可以存储任何形式的字符串

SET(添加key)

GET (获取key) INCR((自增的用法)可以用在统计访客数上,就不需要写入日志了)

DEL (删除key) INCRBY(可以指定自增的步长)

APPEND (追加内容到value) DECR (自减)

STRLEN(获取字符串key的长度) DECRBY(指定自减步长)

MGET(可以同时获取多个值) INCRBTFLOAT(自增浮点类型)

MSET(可以同时设置多个值)

APPEND示例(追加)

[root@server-000 ~]# redis-cli -h 192.168.0.5 
redis 192.168.0.5:6379> SET mykey yanzi
OK

redis 192.168.0.5:6379> GET mykey
"yanzi"

redis 192.168.0.5:6379> APPEND mykey baojia
(integer) 11

redis 192.168.0.5:6379> GET mykey
"yanzibaojia"

STRlEN 判断字符串长度

redis 192.168.0.5:6379> STRLEN mykey
(integer) 11

INCR(自增的用法)可以用在统计访客数上,就不需要写入日志了

redis 192.168.0.5:6379> INCR num
(integer) 1
redis 192.168.0.5:6379> GET num
"1"
redis 192.168.0.5:6379> INCR num
(integer) 2
redis 192.168.0.5:6379> INCR num
(integer) 3
redis 192.168.0.5:6379> INCR num
(integer) 4
redis 192.168.0.5:6379> INCR num
(integer) 5
redis 192.168.0.5:6379> GET num
"5"

INCRBY(可以指定自增的步长)

redis 192.168.0.5:6379> INCRBY num 10
(integer) 15
redis 192.168.0.5:6379> INCRBY num 5
(integer) 20

DECR (自减)

redis 192.168.0.5:6379> DECR num
(integer) 19
redis 192.168.0.5:6379> DECR num
(integer) 18
redis 192.168.0.5:6379> DECR num
(integer) 17
redis 192.168.0.5:6379> DECR num
(integer) 16

指定自减步长

redis 192.168.0.5:6379> DECRBY num 5
(integer) 11
redis 192.168.0.5:6379> DECRBY num 5
(integer) 6
redis 192.168.0.5:6379> GET num
"6"

MGET(可以同时获取多个值)

redis 192.168.0.5:6379> MSET key1 chen key2 bao key3 jia key4 yan key5 zi
OK
redis 192.168.0.5:6379> KEYS *
1) "key2"
2) "key3"
3) "key4"
4) "key5"
5) "mykey"
6) "num"
7) "key1"

MSET(可以同时设置多个值

redis 192.168.0.5:6379> MGET key1 key2 key3 key4 key5
1) "chen"
2) "bao"
3) "jia"
4) "yan"
5) "zi"

散列类型(Hash)

Hash类型的键最多2的32次方-1个

HSET key field value #设置Hash类型的key

HGET key field #查看Hash类型的key

HMSET key field value [field value…] (设置多个HSET)

HMGET key field [field…] #查看多个Hash类型的key

HGETALL key #HGETALL 查看一个hash类型的key 里所有的东西

HDEl #删除某一个字段(field)

HEXISTS 判断一个key的字段是否存在

HSET key field value 和 HGET key field 示例 HSET如果有就设置,没有追加的概念,如果存在就给你改了。

redis 192.168.0.5:6379> HSET car name BWM
(integer) 1
redis 192.168.0.5:6379> HSET car price 200
(integer) 1
redis 192.168.0.5:6379> KEYS *
1) "mykey"
2) "num"
3) "car"
redis 192.168.0.5:6379> HGET car name
"BWM"

#HSET如果有就设置,没有追加的概念,如果存在就给你改了。
redis 192.168.0.5:6379> HGET car price
"200"
redis 192.168.0.5:6379> HSET car price 399
(integer) 0
redis 192.168.0.5:6379> HGET car price
"399"

HMSET key field value [field value…] (设置多个HSET)和HMGET key field [field…] #查看多个Hash类型的key

redis 192.168.0.5:6379> HMSET book price 10 name redis 
OK

redis 192.168.0.5:6379> HMGET book price name
1) "10"
2) "redis"

redis 192.168.0.5:6379> HmGET book name price
1) "redis"
2) "10"

HGETALL 查看一个hash类型的key 里所有的东西

redis 192.168.0.5:6379> HGETALL book
1) "price"
2) "10"
3) "name"
4) "redis"

HDEl #删除某一个字段(field)

redis 192.168.0.5:6379> HDEL book name
(integer) 1
redis 192.168.0.5:6379> HGETALL book
1) "price"
2) "10"

HEXISTS 判断一个key的字段是否存在

redis 192.168.0.5:6379> HEXISTS book name
(integer) 0
redis 192.168.0.5:6379> HEXISTS book price
(integer) 1
redis 192.168.0.5:6379> keys *
1) "book"
2) "mykey"
3) "num"
4) "car"
redis 192.168.0.5:6379> DEL book
(integer) 1
redis 192.168.0.5:6379> keys *
1) "mykey"
2) "num"
3) "car"

列表类型

官网列表类型 http://redis.cn/commands.html#list

比如我们电商网站在提交订单的时候就可以使用消息队列的形式,当做活动提交订单的时候,不是直接提交到数据库(什么数据库都扛不住),这时候就会提交到队列里,成功之后会返回订单正在处理中,这时候就是放在队列里,而不是写在数据库。

用户的订单放在消息队列,这样做活动就不用担心了。

用户注册也可以放在消息队列里,在大量并发可以充当数据库的缓冲,不会对数据库造成影响。按数据库的瓶颈往里写。

Redis 的列表(List)类型是按照插入顺序排序的字符串链表。该类型和数据结构中的普通链表一样,我们可以在其头部(LPUSH)和尾部(RPUSH)添加新的元素。在插入元素时,如果该键不存在,那么将创创建新列表。如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。

一个List中最多可存储2的32次方-1(40亿)个元素。操作列表元素时,如果是从链表的两头插入或删除元素,操作效率会非常高。即使列表中已存储了百万条数据,该操作也可以在常量短的时间内完成。但是,将元素插入列表中间或是删除位于链表中间元素,那操作效率会非常的低。

LPUSH key value [value…] 从左边插入

RPUSH key value [value…] 从右边插入

LPOP key 从左侧弹出

RPOP key 从右侧弹出

LRANGE key start stop 可以指定范围的从左侧

LREM key count value 可以指定范围的从右侧

#左边插入
redis 192.168.0.5:6379> LPUSH mylist 1hehe
(integer) 1
redis 192.168.0.5:6379> LPUSH mylist 2hehe
(integer) 2

#长度是2
redis 192.168.0.5:6379> LLEN mylist
(integer) 2

#右侧插入
redis 192.168.0.5:6379> RPUSH mylist 1hehe
(integer) 3
redis 192.168.0.5:6379> RPUSH mylist 2hehe
(integer) 4


#长度是4
redis 192.168.0.5:6379> LLEN mylist
(integer) 4

#从右侧开始第一个
redis 192.168.0.5:6379> LINDEX mylist -1
"2hehe"

#从右侧开始第二个
redis 192.168.0.5:6379> LINDEX mylist -2
"1hehe"

#从右侧开始第三个
redis 192.168.0.5:6379> LINDEX mylist -3
"1hehe"

#从右侧开始第四个
redis 192.168.0.5:6379> LINDEX mylist -4
"2hehe"

#弹出一次,减少一次知道弹没了,key也会被删除
redis 192.168.0.5:6379> keys *
1) "mykey"
2) "num"
3) "mylist"
4) "car"

redis 192.168.0.5:6379> RPOP mylist
"2hehe"

redis 192.168.0.5:6379> RPOP mylist
"1hehe"

redis 192.168.0.5:6379> RPOP mylist
"1hehe"

redis 192.168.0.5:6379> RPOP mylist
"2hehe"

redis 192.168.0.5:6379> keys *
1) "mykey"
2) "num"
3) "car"


# -1 是最右边的第一个元素,左侧是从0开始的。一下是范围内取值
redis 192.168.0.5:6379> LPUSH mylist k1
(integer) 1
redis 192.168.0.5:6379> LPUSH mylist k2
(integer) 2
redis 192.168.0.5:6379> LPUSH mylist k3
(integer) 3
redis 192.168.0.5:6379> LPUSH mylist k4
(integer) 4
redis 192.168.0.5:6379> LPUSH mylist k5
(integer) 5
redis 192.168.0.5:6379> LLEN mylist
(integer) 5
redis 192.168.0.5:6379> LRANGE mylist 2 -1
1) "k3"
2) "k2"
3) "k1"
redis 192.168.0.5:6379> LRANGE mylist 1 -1
1) "k4"
2) "k3"
3) "k2"
4) "k1"
redis 192.168.0.5:6379> LRANGE mylist 0 -1
1) "k5"
2) "k4"
3) "k3"
4) "k2"
5) "k1"

集合(sets)

sets命令官网 http://redis.cn/commands.html#set

Redis Set 是 String 的无序的无序集合。SADD 指令把新的元素添加到 set 中。对 set 也可做一些其他的操作,比如测试一个给定的元素是否存在,对不同 set 取交集,并集或差,等等。

Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。 Redis 中 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 2的32次方 – 1 (4294967295, 每个集合可存储40多亿个成员)。

可以用在浏览器搜索的补全操作,微博关注,类似关系网,你有四个好友有这个人,然后推荐给你,这些都是集合这样的方式来做的。

差集,交集,并集

SADD :添加一个或多个指定的member元素到集合的 key中.指定的一个或者多个元素member 如果已经在集合key中存在则忽略.如果集合key 不存在,则新建集合key,并添加member元素到集合key中. 如果key 的类型不是集合则返回错误.

redis 192.168.0.5:6379> SADD setA 1 2 3
(integer) 3
redis 192.168.0.5:6379> SADD setB 2 3 4
(integer) 3
redis 192.168.0.5:6379> SDIFF setA setB
1) "1"      #A有1 B没有1 所以打印出来
redis 192.168.0.5:6379> SDIFF setB setA
1) "4"          #B 有4  A 没有所以打印出来

SDIFF key [key …]

时间复杂度:O(N) where N is the total number of elements in all given sets. 返回一个集合与给定集合的差集的元素.

redis 192.168.0.5:6379> SADD k1 a b c d
(integer) 4
redis 192.168.0.5:6379> SADD k2 c
(integer) 1
redis 192.168.0.5:6379> SADD k3 a c e
(integer) 3
redis 192.168.0.5:6379> SDIFF k1 k2 k3
1) "d"
2) "b"

交集

因为AB都有23所有会打印出来
redis 192.168.0.5:6379> SINTER setA setB
1) "2"
2) "3"
redis 192.168.0.5:6379> SINTER setB setA
1) "2"
2) "3"

#k1 k2 k3都有c
redis 192.168.0.5:6379> SINTER k1 k2 k3
1) "c"

并集

SUNION key [key …] 返回给定的多个集合的并集中的所有成员. 例如:

redis 192.168.0.5:6379> SUNION setA setB
1) "1"
2) "2"
3) "3"
4) "4"

redis 192.168.0.5:6379> SUNION k1 k2 k3
1) "b"
2) "c"
3) "d"
4) "e"
5) "a"

SCARD key 返回集合存储的key的基数 (集合元素的数量).

redis 192.168.0.5:6379> SCARD setA
(integer) 3
redis 192.168.0.5:6379> SCARD k1
(integer) 4
redis 192.168.0.5:6379> SCARD k2
(integer) 1
redis 192.168.0.5:6379> SDIFF setA setB
1) "1"
#该命令类似于 SDIFF, 不同之处在于该命令不返回结果集,而是将结果存放在destination集合中.
#如果destination已经存在, 则将其覆盖重写.相当于把结果重新赋值给一个新的key
redis 192.168.0.5:6379> SDIFFSTORE hehe setA setB
(integer) 1

redis 192.168.0.5:6379> get hehe
(error) ERR Operation against a key holding the wrong kind of value

redis 192.168.0.5:6379> type hehe
set
#返回key集合所有的元素.该命令的作用与使用一个参数的SINTER 命令作用相同.
redis 192.168.0.5:6379> SMEMBERS hehe
1) "1"
redis 192.168.0.5:6379> SADD word1 a
(integer) 1

#我们可以看到这里没有再添加a,因为a已经存在,所以只添加了2个
redis 192.168.0.5:6379> SADD word1 a b c
(integer) 2

#我们可以看到只添加了一个
redis 192.168.0.5:6379> SADD word1 a b c d
(integer) 1

redis 192.168.0.5:6379> SADD word1 a b c d e
(integer) 1

#删除word1(key) 中的e
redis 192.168.0.5:6379> SREM word1 e
(integer) 1

#列出word1中的元素
redis 192.168.0.5:6379> SMEMBERS word1
1) "c"
2) "d"
3) "a"
4) "b"

#判断word1中的元素是否存在,存在即返回1,不存在返回0.
redis 192.168.0.5:6379> SISMEMBER word1 e
(integer) 0
redis 192.168.0.5:6379> SISMEMBER word1 d
(integer) 1

有序集合

http://redis.cn/commands.html#sorted_set

http://redisdoc.com/sorted_set/index.html

Pub/Sub(发布/订阅)生产不用

http://redisdoc.com/pub_sub/index.html

订阅者 发布者

缺点:如果中以为订阅者在发布者发布消息时出现故障,那么这个消息队列就会错过而不能再接收到。

我们在生产中会使用RabbitMQ,kafka,

Transaction(事务)经常用到

比如一堆命令,要不都执行,要不都不执行。

缺点:执行错误了没有回滚的功能,成功还是执行,错误的就不会执行。

如果需要用的话可以在程序里进行控制,比如检测命令是否都正确。

Redis 持久化(persistence)

http://redisdoc.com/topic/persistence.html

把内存的数据保存到磁盘上就是持久化。

Redis持久化有两种方式

Redis 提供了多种不同级别的持久化方式:

RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。

AOF 持久化记录服务器执行的所有写操作命令,(跟MySQL的binlog日志相似)并在服务器启动时,通过重新执行这些命令来还原数据集。 AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。 Redis 还可以在后台对 AOF 文件进行重写(rewrite),使得 AOF 文件的体积不会超出保存数据集状态所需的实际大小。

Redis 还可以同时使用 AOF 持久化和 RDB 持久化。 在这种情况下, 当 Redis 重启时, 它会优先使用 AOF 文件来还原数据集, 因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集更完整。

你甚至可以关闭持久化功能,让数据只在服务器运行时存在。

了解 RDB 持久化和 AOF 持久化之间的异同是非常重要的, 以下几个小节将详细地介绍这这两种持久化功能, 并对它们的相同和不同之处进行说明。

RDB 的优点

RDB 是一个非常紧凑(compact)的文件,它保存了 Redis 在某个时间点上的数据集。这种文件非常适合用于进行备份(灾备非常非常重要): 比如说,你可以在最近的 24 小时内,每小时备份一次 RDB 文件,并且在每个月的每一天,也备份一个 RDB 文件。 这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。

RDB 非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的数据中心,或者亚马逊 S3 中。

RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。

RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

RDB 的缺点

如果你需要尽量避免在服务器故障时丢失数据,那么 RDB 不适合你。 虽然 Redis 允许你设置不同的保存点(save point)来控制保存 RDB 文件的频率, 但是, 因为RDB 文件需要保存整个数据集的状态, 所以它并不是一个轻松的操作。

因此你可能会至少 5 分钟才保存一次 RDB 文件。 在这种情况下, 一旦发生故障停机, 你就可能会丢失好几分钟的数据。

每次保存 RDB 的时候,Redis 都要 fork() 出一个子进程,并由子进程来进行实际的持久化工作。

在数据集比较庞大时, fork() 可能会非常耗时,造成服务器在某某毫秒内停止处理客户端;

如果数据集非常巨大,并且 CPU 时间非常紧张的话,那么这种停止时间甚至可能会长达整整一秒。 虽然 AOF 重写也需要进行 fork() ,但无论 AOF 重写的执行间隔有多长,数据的耐久性都不会有任何损失。

RDB的参数修改

[root@server-000 ~]# vim /etc/redis.conf 
save 900 1          #900秒内如果有一个key被改变那么就快照
save 300 10         #300秒内如果有10个建被改变那么就快照
save 60 10000       #60秒内如果有10000个键被改变那么就快照 对性能影响还是挺大的

 97 dbfilename dump.rdb   #存快照的地方
 107 dir /var/lib/redis/    #如果在编译的时候没指定或者配置文件没有指定,那么你在哪里启动这个配置文件就在当前目录下。
 
 

[root@server-000 ~]# ll /var/lib/redis/
总用量 4
-rw-r--r-- 1 redis redis 127 57 20:07 dump.rdb

[root@server-000 ~]# file /var/lib/redis/dump.rdb   #DRB文件是有压缩的,所以会比内存中小
/var/lib/redis/dump.rdb: data

Redis在启动的时候会载入DRB文件到内存,6G大概载入时间需要1分钟。

Redis启动时间需要看DRB文件有多大进行判断。

RDB快照的流程

1、Fork子进程

2、父进程继续干活,子进程开始将内存中的数据写入硬盘中的临时文件。

3、当子进程写完数据后,用临时文件替换原来的DRB文件。

AOF 的优点

使用 AOF 持久化会让 Redis 变得非常耐久(much more durable):你可以设置不同的 fsync 策略,比如无 fsync ,每秒钟一次 fsync ,或者每次执行写入命令时 fsync 。 AOF 的默认策略为每秒钟 fsync 一次,在这种配置下,Redis 仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据( fsync 会在后台线程执行,所以主线程可以继续努力地处理命令请求)。

AOF 文件是一个只进行追加操作的日志文件(append only log), 因此对 AOF 文件的写入不需要进行 seek , 即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等), redis-check-aof 工具也可以轻易地修复这种问题。

Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。

AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。

AOF 的缺点

对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。

根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。

不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。

AOF 在过去曾经发生过这样的 bug : 因为个别命令的原因,导致 AOF 文件在重新载入时,无法将数据集恢复成保存时的原样。 (举个例子,阻塞命令 BRPOPLPUSH 就曾经引起过这样的 bug 。) 测试套件里为这种情况添加了测试:

它们会自动生成随机的、复杂的数据集, 并通过重新载入这些数据来确保一切正常。 虽然这种 bug 在 AOF 文件中并不常见, 但是对比来说, RDB 几乎是不可能出现这种 bug 的。

[root@server-000 ~]# vim /etc/redis.conf 
#修改配置文件来打开 AOF 功能:
268 appendonly yes

[root@server-000 ~]# /etc/init.d/redis restart
Restarting redis (via systemctl):                          [  确定  ]

[root@server-000 ~]# ll /var/lib/redis/
总用量 4
-rw-r--r-- 1 redis redis   0 58 05:24 appendonly.aof
-rw-r--r-- 1 redis redis 127 58 05:24 dump.rdb


[root@server-000 ~]# redis-cli -h 192.168.0.5
redis 192.168.0.5:6379> info
redis_version:2.4.10
redis_git_sha1:00000000
redis_git_dirty:0
arch_bits:64
multiplexing_api:epoll
gcc_version:4.4.6
process_id:16509
uptime_in_seconds:174
uptime_in_days:0
lru_clock:521455
used_cpu_sys:0.00
used_cpu_user:0.05
used_cpu_sys_children:0.00
used_cpu_user_children:0.00
connected_clients:1
connected_slaves:0
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
used_memory:726128
used_memory_human:709.11K
used_memory_rss:3538944
used_memory_peak:726056
used_memory_peak_human:709.04K
mem_fragmentation_ratio:4.87
mem_allocator:jemalloc-2.2.5
loading:0
aof_enabled:1
changes_since_last_save:0
bgsave_in_progress:0
last_save_time:1494192299
bgrewriteaof_in_progress:0
total_connections_received:1
total_commands_processed:0
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0
vm_enabled:0
role:master
aof_current_size:0
aof_base_size:0
aof_pending_rewrite:0
aof_buffer_length:0
aof_pending_bio_fsync:0

redis 192.168.0.5:6379> set key1 vi
OK
redis 192.168.0.5:6379> set key2 v2
OK

redis 192.168.0.5:6379> exit
[root@server-000 ~]# cat /var/lib/redis/appendonly.aof 
*2
$6
SELECT
$1
0
*3
$3
set
$4
key1
$2
vi
*3
$3
set
$4
key2
$2
v2

命令行执行set

[root@server-000 ~]# for ((i=1;i<=1000;i++));do echo $i;done
[root@server-000 ~]# for ((i=1;i<=1000;i++));do redis-cli -h 192.168.0.5 SET k$i $i;done

AOF流程

1、Fork子进程

2、父进程继续干活,子进程开始将内存中的数据写入硬盘中的临时文件。

3、当子进程写完数据后,用临时文件替换原来的AOF文件。

AOF 的耐久性如何?

你可以配置 Redis 多久才将数据 fsync 到磁盘一次。

有三个选项:

每次有新命令追加到 AOF 文件时就执行一次 fsync :非常慢,也非常安全。

每秒 fsync 一次:足够快(和使用 RDB 持久化差不多),并且在故障时只会丢失 1 秒钟的数据。缺省

从不 fsync :将数据交给操作系统来处理。更快,也更不安全的选择。

推荐(并且也是默认)的措施为每秒 fsync 一次, 这种 fsync 策略可以兼顾速度和安全性。

总是 fsync 的策略在实际使用中非常慢, 即使在 Redis 2.0 对相关的程序进行了改进之后仍是如此 —— 频繁调用 fsync 注定了这种策略不可能快得起来。

怎么从 RDB 持久化切换到 AOF 持久化(不重启redis)

在 Redis 2.2 或以上版本,可以在不重启的情况下,从 RDB 切换到 AOF :

为最新的 dump.rdb 文件创建一个备份。

将备份放到一个安全的地方。

执行以下两条命令:

redis-cli> CONFIG SET appendonly yes

redis-cli> CONFIG SET save “” #这个就不要执行 了这个是关闭RDB,直接把save的配置给关了

确保命令执行之后,数据库的键的数量没有改变。

确保写命令会被正确地追加到 AOF 文件的末尾。

步骤 3 执行的第一条命令开启了 AOF 功能: Redis 会阻塞直到初始 AOF 文件创建完成为止, 之后 Redis 会继续处理命令请求, 并开始将写入命令追加到 AOF 文件末尾。

步骤 3 执行的第二条命令用于关闭 RDB 功能。 这一步是可选的, 如果你愿意的话, 也可以同时使用 RDB 和 AOF 这两种持久化功能。

别忘了在 redis.conf 中打开 AOF 功能! 否则的话, 服务器重启之后, 之前通过 CONFIG SET 设置的配置就会被遗忘, 程序会按原来的配置来启动服务器。 译注: 原文这里还有介绍 2.0 版本的切换方式, 考虑到 2.0 已经很老旧了, 这里省略了对那部分文档的翻译, 有需要的请参考原文。

Redis备份与安全

Redis并不是越大越好,因为载入就会阻塞,可以有多台redis。

备份 Redis 数据

在阅读这个小节前, 先将下面这句话铭记于心: 一定要备份你的数据库!

磁盘故障, 节点失效, 诸如此类的问题都可能让你的数据消失不见, 不进行备份是非常危险的。

Redis 对于数据备份是非常友好的, 因为你可以在服务器运行的时候对 RDB 文件进行复制: RDB 文件一旦被创建, 就不会进行任何修改。 当服务器要创建一个新的 RDB 文件时, 它先将文件的内容保存在一个临时文件里面, 当临时文件写入完毕时, 程序才使用 rename(2) 原子地用临时文件替换原来的 RDB 文件。

这也就是说, 无论何时, 复制 RDB 文件都是绝对安全的。

以下是我们的建议:

创建一个定期任务(cron job), 每小时将一个 RDB 文件备份到一个文件夹, 并且每天将一个 RDB 文件备份到另一个文件夹。

确保快照的备份都带有相应的日期和时间信息, 每次执行定期任务脚本时, 使用 find 命令来删除过期的快照: 比如说, 你可以保留最近 48 小时内的每小时快照, 还可以保留最近一两个月的每日快照。

至少每天一次, 将 RDB 备份到你的数据中心之外, 或者至少是备份到你运行 Redis 服务器的物理机器之外。

容灾备份

Redis 的容灾备份基本上就是对数据进行备份, 并将这些备份传送到多个不同的外部数据中心。

容灾备份可以在 Redis 运行并产生快照的主数据中心发生严重的问题时, 仍然让数据处于安全状态。

因为很多 Redis 用户都是创业者, 他们没有大把大把的钱可以浪费, 所以下面介绍的都是一些实用又便宜的容灾备份方法:

Amazon S3 ,以及其他类似 S3 的服务,是一个构建灾难备份系统的好地方。 最简单的方法就是将你的每小时或者每日 RDB 备份加密并传送到 S3 。 对数据的加密可以通过 gpg -c 命令来完成(对称加密模式)。 记得把你的密码放到几个不同的、安全的地方去(比如你可以把密码复制给你组织里最重要的人物)。 同时使用多个储存服务来保存数据文件,可以提升数据的安全性。 传送快照可以使用 SCP 来完成(SSH 的组件)。 以下是简单并且安全的传送方法: 买一个离你的数据中心非常远的 VPS , 装上 SSH , 创建一个无口令的 SSH 客户端 key , 并将这个 key 添加到 VPS 的 authorized_keys 文件中, 这样就可以向这个 VPS 传送快照备份文件了。 为了达到最好的数据安全性,至少要从两个不同的提供商那里各购买一个 VPS 来进行数据容灾备份。 需要注意的是, 这类容灾系统如果没有小心地进行处理的话, 是很容易失效的。

最低限度下, 你应该在文件传送完毕之后, 检查所传送备份文件的体积和原始快照文件的体积是否相同。 如果你使用的是 VPS , 那么还可以通过比对文件的 SHA1 校验和来确认文件是否传送完整。

另外, 你还需要一个独立的警报系统, 让它在负责传送备份文件的传送器(transfer)失灵时通知你。

讨论 comments powered by Disqus

redis 安全

1、操作加上验证设置一个密码

2、给危险命令重命名。 配置文件里

# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#
# It is also possilbe to completely kill a command renaming it into
# an empty string:
#
# rename-command CONFIG ""

Redis Crackit漏洞利用和防护

https://www.unixhot.com/article/23

如何防护:

1.禁用这些可以入侵的命令:
 [root@test-node2 ~]# vim /etc/redis.conf
 rename-command FLUSHALL ""
 #rename-command CONFIG ""  注意,设置了,可就不能用了,如果需要使用可以设置一个其它名称。

2.将你的redis不要运行在0.0.0.0.或者设置验证。
 [root@test-node2 ~]# vim /etc/redis.conf
requirepass redis-passwd
bind 192.168.199.11

3.尽量不要使用root运行。默认yum安装的redis,是运行在redis用户的。

如何发现被入侵:

1.你的redis数据莫名其妙没有了。
 2.检查你的rdb文件存放的路径
 3.检查是否有非法的authorized_keys
[root@server-000 ~]# redis-cli -h 192.168.0.5 -p 6379
redis 192.168.0.5:6379> select 1
OK

SELECT index

切换到指定的数据库,数据库索引号 index 用数字值指定,以 0 作为起始索引值。

默认使用 0 号数据库。

[root@server-000 ~]# redis-cli -h 192.168.0.5 -p 6379
redis 192.168.0.5:6379> select 1
OK

redis 192.168.0.5:6379[1]> set key1 1
OK

redis 192.168.0.5:6379[1]> info
db0:keys=1004,expires=0
db1:keys=1,expires=0

redis 192.168.0.5:6379[1]> select 2
OK

redis 192.168.0.5:6379[2]> set key1 1
OK

redis 192.168.0.5:6379[2]> info
db0:keys=1004,expires=0
db1:keys=1,expires=0
db2:keys=1,expires=0
[root@server-000 ~]# vim /etc/redis.conf

166 requirepass oldboy          #设置密码

[root@server-000 ~]# /etc/init.d/redis restart
Restarting redis (via systemctl):                          [  确定  ]


[root@server-000 ~]# redis-cli -h 192.168.0.5 -p 6379
Could not connect to Redis at 192.168.0.5:6379: Connection refused
#连接不上的原因是我们前面做主从的时候没有把从库的aof文件目录修改一下,导致都写在同一个目录下所以出现混乱错误,现在我们删除了,

[root@server-000 ~]# cd /var/lib/redis/
[root@server-000 redis]# \rm -f appendonly.aof 

[root@server-000 redis]# /etc/init.d/redis restart
Restarting redis (via systemctl):                          [  确定  ]
[root@server-000 redis]# redis-cli -h 192.168.0.5 -p 6379
redis 192.168.0.5:6379> set chen baojia
(error) ERR operation not permitted         #提示没有权限

#我们输入我们刚设置的密码
redis 192.168.0.5:6379> auth oldboy
OK
redis 192.168.0.5:6379> set key1 1
OK

Redis主从

redis 复制

Redis并不是越大越好,因为载入就会阻塞,可以有多台redis。

[root@server-000 ~]# cp /etc/redis.conf /etc/redis.conf.ori

[root@server-000 ~]# vim /etc/redis.conf.ori #修改端口我们来做主从复制
 25 port 6378
 
 #查看安装redis命令所有安装目录
 [root@server-000 ~]# rpm -ql redis
/etc/logrotate.d/redis
/etc/rc.d/init.d/redis
/etc/redis.conf
/usr/bin/redis-benchmark
/usr/bin/redis-check-aof
/usr/bin/redis-check-dump
/usr/bin/redis-cli
/usr/sbin/redis-server
/usr/share/doc/redis-2.4.10
/usr/share/doc/redis-2.4.10/00-RELEASENOTES
/usr/share/doc/redis-2.4.10/BUGS
/usr/share/doc/redis-2.4.10/CONTRIBUTING
/usr/share/doc/redis-2.4.10/COPYING
/usr/share/doc/redis-2.4.10/README
/usr/share/doc/redis-2.4.10/TODO
/var/lib/redis
/var/log/redis
/var/run/redis

#查看命令帮助
[root@server-000 ~]# /usr/sbin/redis-server --help
Usage: ./redis-server [/path/to/redis.conf]
       ./redis-server - (read config from stdin)
       ./redis-server --test-memory <megabytes>

#直接带上配置文件即可
[root@server-000 ~]# /usr/sbin/redis-server /etc/redis.conf.ori 

#查看端口可以看到已经起来了,6378做从,6379做主
[root@server-000 ~]# netstat -lntup|grep redis
tcp        0      0 192.168.0.5:6378        0.0.0.0:*               LISTEN      17592/redis-server  
tcp        0      0 192.168.0.5:6379        0.0.0.0:*               LISTEN      16509/redis-server

[root@server-000 ~]# redis-cli -h 192.168.0.5 -p 6379
redis 192.168.0.5:6379>

[root@server-000 ~]# redis-cli -h 192.168.0.5 -p 6378
redis 192.168.0.5:6378>

在从上设置主从复制

[root@server-000 ~]# redis-cli -h 192.168.0.5 -p 6378
redis 192.168.0.5:6378> slaveof 192.168.0.5 6379
OK
redis 192.168.0.5:6378> INFO
redis_version:2.4.10
redis_git_sha1:00000000
redis_git_dirty:0
arch_bits:64
multiplexing_api:epoll
gcc_version:4.4.6
process_id:17592
uptime_in_seconds:398
uptime_in_days:0
lru_clock:521701
used_cpu_sys:0.04
used_cpu_user:0.03
used_cpu_sys_children:0.00
used_cpu_user_children:0.00
connected_clients:2
connected_slaves:0
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
used_memory:791128
used_memory_human:772.59K
used_memory_rss:1716224
used_memory_peak:791120
used_memory_peak_human:772.58K
mem_fragmentation_ratio:2.17
mem_allocator:jemalloc-2.2.5
loading:0
aof_enabled:1
changes_since_last_save:0
bgsave_in_progress:0
last_save_time:1494194837
bgrewriteaof_in_progress:0
total_connections_received:1
total_commands_processed:2
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:84
vm_enabled:0
role:slave
aof_current_size:31871
aof_base_size:31871
aof_pending_rewrite:0
aof_buffer_length:0
aof_pending_bio_fsync:0
master_host:192.168.0.5         #这里可以看到master 的IP
master_port:6379            #master 的端口
master_link_status:up       #状态
master_last_io_seconds_ago:0        #最后一次的io用了多少时间
master_sync_in_progress:0       #
db0:keys=1002,expires=0     #keys 1002

[root@server-000 ~]# redis-cli -h 192.168.0.5 -p 6379
redis 192.168.0.5:6379> INFO
....        #省略下拉到最底
slave0:192.168.0.5,61350,online
db0:keys=1002,expires=0             #可以看到keys 是和从对上的

#创建一个测试文件然后在从上查看
redis 192.168.0.5:6379> SET masterkey1 mac
OK          

redis 192.168.0.5:6378> GET masterkey1
"mac"

!!注意:默认情况下redis从库默认是只读的 。2.6的版本,这次我们安装的是2.4版本所有没有 只读的话,那么从库会拒绝所有的写命令。如果主挂了,那么切换到从库就不行了,需要把从库改成可读写才行,

解决方法:SLAVEOF NO ONE #将从库数据库提升为主数据库。

2、从库Redis做持久化(类似我们MySQL在从库上做备份一样mysqldump)

复制功能的运作原理

命令BGSAVE

在后台异步(Asynchronously)保存当前数据库的数据到磁盘。

BGSAVE 命令执行之后立即返回 OK ,然后 Redis fork 出一个新子进程,原来的 Redis 进程(父进程)继续处理客户端请求,而子进程则负责将数据保存到磁盘,然后退出。

客户端可以通过 LASTSAVE 命令查看相关信息,判断 BGSAVE 命令是否执行成功。

无论是初次连接还是重新连接, 当建立一个从服务器时, 从服务器都将向主服务器发送一个 SYNC 命令。

接到 SYNC 命令的主服务器将开始执行 BGSAVE(就是把内存里的数据保存下来) , 并在保存操作执行期间, 将所有新执行的写入命令都保存到一个缓冲区里面。

当 BGSAVE 执行完毕后, 主服务器将执行保存操作所得的 .rdb 文件发送给从服务器, 从服务器接收这个 .rdb 文件, 并将文件中的数据载入到内存中。

之后主服务器会以 Redis 命令协议的格式, 将写命令缓冲区中积累的所有内容都发送给从服务器。

你可以通过 telnet 命令来亲自验证这个同步过程: 首先连上一个正在处理命令请求的 Redis 服务器, 然后向它发送 SYNC 命令, 过一阵子, 你将看到 telnet 会话(session)接收到服务器发来的大段数据(.rdb 文件), 之后还会看到, 所有在服务器执行过的写命令, 都会重新发送到 telnet 会话来。

即使有多个从服务器同时向主服务器发送 SYNC , 主服务器也只需执行一次 BGSAVE 命令, 就可以处理所有这些从服务器的同步请求。

从服务器可以在主从服务器之间的连接断开时进行自动重连, 在 Redis 2.8 版本之前, 断线之后重连的从服务器总要执行一次完整重同步(full resynchronization)操作, 但是从 Redis 2.8 版本开始, 从服务器可以根据主服务器的情况来选择执行完整重同步还是部分重同步(partial resynchronization)。

部分重同步

从 Redis 2.8 开始, 在网络连接短暂性失效之后, 主从服务器可以尝试继续执行原有的复制进程(process), 而不一定要执行完整重同步操作。

这个特性需要主服务器为被发送的复制流创建一个内存缓冲区(in-memory backlog), 并且主服务器和所有从服务器之间都记录一个复制偏移量(replication offset)和一个主服务器 ID (master run id), 当出现网络连接断开时, 从服务器会重新连接, 并且向主服务器请求继续执行原来的复制进程:

如果从服务器记录的主服务器 ID 和当前要连接的主服务器的 ID 相同, 并且从服务器记录的偏移量所指定的数据仍然保存在主服务器的复制流缓冲区里面, 那么主服务器会向从服务器发送断线时缺失的那部分数据, 然后复制工作可以继续执行。 否则的话, 从服务器就要执行完整重同步操作。

Redis 2.8 的这个部分重同步特性会用到一个新增的 PSYNC 内部命令, 而 Redis 2.8 以前的旧版本只有 SYNC 命令, 不过, 只要从服务器是 Redis 2.8 或以上的版本, 它就会根据主服务器的版本来决定到底是使用 PSYNC 还是 SYNC :

如果主服务器是 Redis 2.8 或以上版本,那么从服务器使用 PSYNC 命令来进行同步。

如果主服务器是 Redis 2.8 之前的版本,那么从服务器使用 SYNC 命令来进行同步。我们这里用的是2.4版本。

#主库
redis 192.168.0.5:6379> BGSAVE
Background saving started       #后台开始保存

#从库
redis 192.168.0.5:6378> LASTSAVE
(integer) 1494195738

主从切换脚本检测

思路 1、

redis 192.168.0.5:6379> PING
PONG        #可以写一个脚本判断,如果出现ping

之后的PONG说明是正常的,否者就是不正常。核实后我们把从库提升为master

解决方法:1、SLAVEOF NO ONE #将从库数据库提升为主数据库。

2、从库Redis做持久化(类似我们MySQL在从库上做备份一样mysqldump)通过设置VIP切换

3、建议使用 Redis主从+keepalived自己可以写一个检测脚本

4、Sentinel 系统用于管理多个 Redis 服务器(instance

http://redisdoc.com/topic/sentinel.html#sentinel-api

Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务:

监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。

提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API向管理员或者其他应用程序发送通知。

自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。

Redis Sentinel 是一个分布式系统, 你可以在一个架构中运行多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。

虽然 Redis Sentinel 释出为一个单独的可执行文件 redis-sentinel , 但实际上它只是一个运行在特殊模式下的 Redis 服务器, 你可以在启动一个普通 Redis 服务器时通过给定 –sentinel 选项来启动 Redis Sentinel 。

Redis Sentinel 目前仍在开发中, 这个文档的内容可能随着 Sentinel 实现的修改而变更。 Redis Sentinel 兼容 Redis 2.4.16 或以上版本, 推荐使用 Redis 2.8.0 或以上的版本。

php使用redis的方法

缓存插件

https://pecl.php.net/package/redis

[root@server-000 ~]# cd /usr/local/src/
[root@server-000 src]# wget https://pecl.php.net/get/redis-2.2.7.tgz
[root@server-000 redis-2.2.7]# tar zxf redis-2.2.7.tgz 
[root@server-000 redis-2.2.7]# cd redis-2.2.7
[root@server-000 redis-2.2.7]# phpize 
[root@server-000 redis-2.2.7]# ./configure --with-php-config=/usr/bin/php-config 
[root@server-000 redis-2.2.7]# make && make install 

随后会出现redis.so的文件,然后我们需要在php.ini中加入

vim php.ini

extension = redis.so

重启php
#Centos 7
[root@server-000 modules]# systemctl restart php-fpm

#Centos 6
[root@server-000 modules]# service php-fpm restart


检查:1、phpino 搜索是否有redis
<?php
phpinfo();
?>


2、redis.php(创建一个php程序测试)

<?php
$redis = new Redis();
$redis->connect('192.168.0.5',6379);
$redis->set('keyname','value');
echo $redis->get('keyname');
?>

INFO 详解

http://redisdoc.com/server/info.html

[root@server-000 html]# redis-cli -h 192.168.0.5 -p 6379
redis 192.168.0.5:6379> INFO
redis_version:2.4.10
redis_git_sha1:00000000
redis_git_dirty:0
arch_bits:64
multiplexing_api:epoll
gcc_version:4.4.6
process_id:16509
uptime_in_seconds:9888
uptime_in_days:0
lru_clock:522426
used_cpu_sys:1.32
used_cpu_user:0.68
used_cpu_sys_children:0.00
used_cpu_user_children:0.00
connected_clients:1     #已连接客户端的数量(不包括通过从属服务器连接的客户端)
connected_slaves:1          #已连接的从服务器数量。 这两个是我们需要关注的
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
used_memory:791360          #由 Redis 分配器分配的内存总量,以字节(byte)为单位
used_memory_human:772.81K       # 以人类可读的格式返回 Redis 的内存消耗峰值
used_memory_rss:3842048    #从操作系统的角度,返回 Redis 已分配的内存总量(俗称常驻集大小)。这个值和 top 、 ps 等命令的输出一致。
used_memory_peak:791328         #Redis 的内存消耗峰值(以字节为单位)
used_memory_peak_human:772.78K      # 以人类可读的格式返回 Redis 的内存消耗峰值
mem_fragmentation_ratio:4.85        #used_memory_rss 和 used_memory 之间的比率
mem_allocator:jemalloc-2.2.5        #在编译时指定的, Redis 所使用的内存分配器。可以是 libc 、 jemalloc 或者 tcmalloc 。       
loading:0
aof_enabled:1
changes_since_last_save:1
bgsave_in_progress:0
last_save_time:1494201924
bgrewriteaof_in_progress:0
total_connections_received:1007
total_commands_processed:1012
expired_keys:0
evicted_keys:0
keyspace_hits:2
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:217
vm_enabled:0
role:master
aof_current_size:31984
aof_base_size:0
aof_pending_rewrite:0
aof_buffer_length:0
aof_pending_bio_fsync:0
slave0:192.168.0.5,61350,online
db0:keys=1004,expires=0

used_memory_peak:791328 #Redis 的内存消耗峰值(以字节为单位)

used_memory_peak_human:772.78K # 以人类可读的格式返回 Redis 的内存消耗峰值

这两个是我们在做zabbix监控要做的。监控就是通过info来获取信息

master_link_status:up #也可以监控up 表示连接正常,down表示连接断开。

刚到一家公司如何成为牛人,可以找一个入手的点,比如公司redis用的特别多,把这个点做好,可以把所有的redis管理起来,把全部监控全部做好,把所有主从全部做好,分享整个redis的状态报表,每天给领导发一个报表,例如主从的状态,例如多少客户端连接,每个DB的key,内存设置了多少,现在用了多少。老板和领导特别喜欢看这个,

专业的运维要能把你管理的东西有一个清单,在出现问题的时候能有一个清单,可以进行判断出现这个问题会影响到那一些服务。而且要知道你管理的对象,当时设置的容量是多大,现在是多大。可以根据增长率来进行调整。

phpredisadmin用于管理redis-server的软件

需要php5.3.4才能玩

https://github.com/erikdubbelboer/phpRedisAdmin

[root@server-000 html]# yum install -y httpd php php-pdo php-cli php-gd php-mbstring

php-gd 是画图的

php-pdo 连接数据库的扩展的

[root@server-000 tools]# cd /application/tools/

curl -s http://getcomposer.org/installer | php php composer.phar create-project -s dev erik-dubbelboer/php-redis-admin path/to/install

[root@server-000 tools]# wget https://github.com/erikdubbelboer/phpRedisAdmin/archive/master.zip

[root@server-000 tools]# unzip master.zip

rdbtools(生产常用的内存分析工具)

看看redis到底存了什么东西 https://github.com/sripathikrishnan/redis-rdb-tools

分析内存非常有用

[root@web02 ~]# yum install python-pip

pip install rdbtools

命令用法

[root@server-000 ~]# cd /var/lib/redis/
[root@server-000 redis]# cp dump.rdb /tmp/  #注意千万不能损坏dump.rdb包,所以我么复制一份
[root@server-000 redis]# rdb --command json /tmp/dump.rdb > redis.csv

redis集群

1、客户端分片(最靠谱的): 将redis分片的工作放在业务程序端。可以根据用户末尾的UID数字来进行分别存放的redisserver。比如用户uid最后的数字是1那么就存放到redis1上,以此类推,如果9个数不够那么可以使用用户UID的后2位数,来进行对应的分别存取的redis.也可以根据key取余也行。

优点:实现方法和代码全部自己掌控。可以随时进行调整。

缺点:需要手动迁移数据,

2、代理分片:类似MySQL Proxy。也要手动迁移

twemproxy 是一个为memcached和redis做的一个代理软件有一个缺点:对用户透明又不透明。很恐怖的一件事,因为我不知道我的资源存在哪里,要是是自己写的还可以用,况且这是别人写的,早期用的人还挺多,现在在生产环境中我们都要用了。

https://github.com/twitter/twemproxy

3、Codis 目前比较靠谱的 豌豆荚开发团队做的。

https://github.com/CodisLabs/codis

中文文档 https://github.com/CodisLabs/codis/blob/release3.2/doc/tutorial_zh.md

常问问题 https://github.com/CodisLabs/codis/blob/release3.2/doc/FAQ_zh.md

高可用性 https://github.com/CodisLabs/codis/blob/release3.2/doc/tutorial_zh.md#3-jodis-与-ha

4、Redis Cluster

是一个坑目前看看就好,问题太多了。

坑1,目前实现的客户端比较少,

坑2、主从明明正常,但是出现主错误,从库正常但是不切换。

http://redisdoc.com/topic/cluster-tutorial.html

Redis监控

课程 http://study.oldboyedu.com/classModule/video/214170/216843/779272/0/0

zabbix_linux_plugin.sh

[root@server-000 redis]# cat zabbix_linux_plugin.sh 
#!/bin/bash
############################################################
# $Name:         zabbix_linux_plugins.sh
# $Version:      v1.0
# $Function:     zabbix plugins
# $Author:       baojia chen
# $Create Date:  2014-08-10
# $Description:  Monitor Linux Service Status
############################################################
tcp_status_fun(){
	TCP_STAT=$1
	#netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,state[key]}' > /tmp/netstat.tmp
	ss -ant | awk 'NR>1 {++s[$1]} END {for(k in s) print k,s[k]}' > /tmp/netstat.tmp
	TCP_STAT_VALUE=$(grep "$TCP_STAT" /tmp/netstat.tmp | cut -d ' ' -f2)
	if [ -z $TCP_STAT_VALUE ];then
		TCP_STAT_VALUE=0
	fi
	echo $TCP_STAT_VALUE
}

nginx_status_fun(){
	NGINX_PORT=$1
	NGINX_COMMAND=$2
	nginx_active(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" 2>/dev/null| grep 'Active' | awk '{print $NF}'
        }
	nginx_reading(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" 2>/dev/null| grep 'Reading' | awk '{print $2}'
       }
	nginx_writing(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" 2>/dev/null| grep 'Writing' | awk '{print $4}'
       }
	nginx_waiting(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" 2>/dev/null| grep 'Waiting' | awk '{print $6}'
       }
	nginx_accepts(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" 2>/dev/null| awk NR==3 | awk '{print $1}'
       }
	nginx_handled(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" 2>/dev/null| awk NR==3 | awk '{print $2}'
       }
	nginx_requests(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" 2>/dev/null| awk NR==3 | awk '{print $3}'
       }
  	case $NGINX_COMMAND in
		active)
			nginx_active;
			;;
		reading)
			nginx_reading;
			;;
		writing)
			nginx_writing;
			;;
		waiting)
			nginx_waiting;
			;;
		accepts)
			nginx_accepts;
			;;
		handled)
			nginx_handled;
			;;
		requests)
			nginx_requests;
		esac 
}

memcached_status_fun(){
	M_PORT=$1
	M_COMMAND=$2
	echo -e "stats\nquit" | nc 127.0.0.1 "$M_PORT" | grep "STAT $M_COMMAND " | awk '{print $3}'
}

redis_status_fun(){
	R_PORT=$1
	R_COMMAND=$2
	(echo -en "INFO \r\n";sleep 1😉 | nc 127.0.0.1 "$R_PORT" > /tmp/redis_"$R_PORT".tmp
	REDIS_STAT_VALUE=$(grep ""$R_COMMAND":" /tmp/redis_"$R_PORT".tmp | cut -d ':' -f2)
 	echo $REDIS_STAT_VALUE	
}

main(){
	case $1 in
		tcp_status)
			tcp_status_fun $2;
			;;
		nginx_status)
			nginx_status_fun $2 $3;
			;;
		memcached_status)
			memcached_status_fun $2 $3;
			;;
		redis_status)
			redis_status_fun $2 $3;
			;;
		*)
			echo $"Usage: $0 {tcp_status key|memcached_status key|redis_status key|nginx_status key}"
	esac
}

main $1 $2 $3

如何设计一个电商购物车

1、基于大数据的假货 根据你购买客单价,根据地址(农村或者),根据你的评价,根据的你投诉率来计算你识别的概率有多大,你投诉的概率有多大,你退货的概率有多大。概率小就发假货,概率大就发真的。

1、需求是什么 用户把宝贝放入购物车,用户下一次访问的时候,购物车没有结算的宝贝还在。我们知道我需要记录下来

2、记录在哪里? 用户不登录购物车内容可以记录在 Cookie 。 用户登录后:购物车存放在 Redis。UID——xxx(之类的做一个key) value(就是你购物车的内容是hash的数据类型) 设置key的时候可以设置过期时间
redis可以持久化

Memcahced: 可以存储的

1、数据库读缓存。

2、Session。

负载均衡: Session处理有几种方式:

1、会话Session保持:Nginx可以做ip_hash cookie
        
        2、会话Session复制:把Session 复制到每台RS上, Tomcat Cluster。缺点复制要产生开销
        
        3、会话Session共享:比如放在memcached,优点:语言支持多,简单,高效,所有开发人员都会。PHP php.ini 直接配置session存储位置就可以使用。tomcat(memcached) session manager.

不同的业务的场景使用不同的application。

技术在公司的位置

IT管理三大因素:PPT

1、P 人员

2、Process 组织结构/流程

3、Tools 工具/技术

架构师要符合企业实际情况的,没有所谓的最佳实践,存在即是有道理。

!!!千万不要嘲笑别人的架构,有可能这就是最合理的。

用东西要用自己最熟悉的,但是也要考虑公司业务场景和人员。

资料参考

http://redisdoc.com/ Redis 命令参考

http://redis.cn/ Redis 中文官网

缓存体系

学习要有一个体系

缓存的主要指标就是命中率

层级 内容 详情

DNS解析 DNS缓存

浏览器 浏览器缓存 1、最后修改时间 2、过期时间 3、打标签

CDN(解决就近访问问题) 反向代理缓存 Squid,varnlsh,nginx,ATg

web服务器 web服务器缓存 Apache,Nginx,

Local Cache 应用本地缓存

语言缓存 OPcache操作码缓存和优化提供更快的PHP 执行过程会给系统带来五分之二或三的性能提升

分布式缓存 分布式缓存 memcached,redis

数据库 MySQL innodb缓存,MYISAM

操作系统 Page Cache(Linux 内核的文件Cache 页缓存)

CPU Cache   L1,L2,L3
        
        内存 Cache

磁盘 Disk Cache(磁盘缓存)

硬件 raid Cache 磁盘阵列缓存

为什么要把图片放在单独的域名,这样做有什么好处?

1、可以做组件分离、动静分离(为不同的资源,配备不同的存储和web访问,比如动静分离)

2、静态资源,方便上CDN,

3、加快页面打开速度,提高浏览器并发。浏览器请求并发数是基于域名的。

4、jd.com pic.jd.com www.jdpic.com 1.动态请求写入的cookie,浏览器每次请求本域名下的其他资源,都会附带上cookie。

2.如果你使用pic.jd.com的时候,访问图片也是需要附带cookie(有一个作用域)的。

3.如果你想把静态资源单独存放,注意一定要使用另外的顶级域名。因为cookie是有作用域的。

1、提高了速度 
2、减少了带宽(因为每张图片都带cookie的话,那么如果你是电商网站将占非常大的带宽)

弊端 解析的域名多了,DNS解析非常快这个可以忽略。

分布式缓存之Redis

官网:https://redis.io/

可以源码安装和yum安装,最佳的是yum 安装。

想定制,自己做一个rpm包。yum 安装

yum 安装

先换成epel源

centos 6 http://mirrors.aliyun.com/repo/epel-6.repo centos 7 http://mirrors.aliyun.com/repo/epel-7.repo

系统环境

[root@server-000 ~]# cat /etc/redhat-release 
CentOS Linux release 7.2.1511 (Core) 
[root@server-000 ~]# uname -rn
server-000.novalocal 3.10.0-327.el7.x86_64

yum 安装

[root@server-000 ~]# cd /etc/yum.repos.d/
[root@server-000 yum.repos.d]# wget http://mirrors.aliyun.com/repo/epel-7.repo

[root@server-000 yum.repos.d]# cd 
[root@server-000 ~]# yum install -y redis

查看redis都安装了什么

[root@server-000 ~]# rpm -qa redis
redis-2.4.10-1.el6.x86_64
[root@server-000 ~]# rpm -ql redis
/etc/logrotate.d/redis      #日志
/etc/rc.d/init.d/redis      #
/etc/redis.conf         #配置
/usr/bin/redis-benchmark        #系统测试
/usr/bin/redis-check-aof        #检测日志
/usr/bin/redis-check-dump       
/usr/bin/redis-cli          #客户端登录
/usr/sbin/redis-server
/usr/share/doc/redis-2.4.10
/usr/share/doc/redis-2.4.10/00-RELEASENOTES     #文档
/usr/share/doc/redis-2.4.10/BUGS
/usr/share/doc/redis-2.4.10/CONTRIBUTING
/usr/share/doc/redis-2.4.10/COPYING
/usr/share/doc/redis-2.4.10/README
/usr/share/doc/redis-2.4.10/TODO
/var/lib/redis          #创建了三个目录
/var/log/redis  
/var/run/redis          #运行目录存放pid的。管理进程的时候可以看到,意外关闭会提示pid已存在,正常关闭就不会出现这样的情况。最后会自动把pid删除。

写脚本的最佳实践就是,我们在写脚本的时候,最好程序启动的时候,要在某个地方创建一个log文件,这样可以预防他人多次启动而带来的灾难,在我们关闭的时候,程序自动删除log文件,启动的时候判断如果log文件存在,那么就给出提示。

application 安装完毕之后我们要第一时间查看配置文件,看那个地方需要我们修改的。

[root@server-000 ~]# vim /etc/redis.conf #只修改了绑定ip的地址

配置文件中的备注

daemonize yes       #是否是守护进程,yum安装缺省是yes,源码安装缺省是no

pidfile /var/run/redis/redis.pid  #pid存放的位置

port 6379       #端口

bind 192.168.0.5   #绑定的自己的ip地址

#注释的就是表示默认的

timeout 0           #控制客户端空闲几秒断开,0表示不主动断开,

loglevel notice     #日志级别

logfile /var/log/redis/redis.log  #日志文件

databases 16        #redis支持MySQL数据的的个数0-16  就是17个,是从0开始数的,要用多个就改大。

save 900 1          #900秒内如果有一个key被改变那么就快照
save 300 10         #300秒内如果有10个建被改变那么就快照
save 60 10000       #60秒内如果有10000个键被改变那么就快照 对性能影响还是挺大的

 97 dbfilename dump.rdb   #存快照的地方
 107 dir /var/lib/redis/    #如果在编译的时候没指定或者配置文件没有指定,那么你在哪里启动这个配置文件就在当前目录下。
 
 
 [root@server-000 ~]# vim /etc/redis.conf 
[root@server-000 ~]# ll /var/lib/redis/
总用量 4
-rw-r--r-- 1 redis redis 127 57 20:07 dump.rdb

启动redis

[root@server-000 ~]# /etc/init.d/redis
Usage: /etc/init.d/redis {start|stop|status|restart|condrestart|try-restart}

[root@server-000 ~]# /etc/init.d/redis start
Starting redis (via systemctl):                            [  确定  ]

查看启动端口

[root@server-000 ~]# lsof -i :6379
COMMAND    PID  USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
redis-ser 9947 redis    4u  IPv4 207733      0t0  TCP server-000.novalocal:6379 (LISTEN)
[root@server-000 ~]# netstat -lntup|grep redis
tcp        0      0 192.168.0.5:6379        0.0.0.0:*               LISTEN      9947/redis-server

登录到redis

#默认的话是直接连接到127.0.0.1:6379:
[root@server-000 ~]# redis-cli 
Could not connect to Redis at 127.0.0.1:6379: Connection refused
not connected> exit

#我们通过help知道-h 而已指定ip -p 指定端口 -s 指定socket
[root@server-000 ~]# redis-cli --help
redis-cli 2.4.10

Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]
  -h <hostname>    Server hostname (default: 127.0.0.1)
  -p <port>        Server port (default: 6379)
  -s <socket>      Server socket (overrides hostname and port)
  -a <password>    Password to use when connecting to the server
  -r <repeat>      Execute specified command N times
  -i <interval>    When -r is used, waits <interval> seconds per command.
                   It is possible to specify sub-second times like -i 0.1.
  -n <db>          Database number
  -x               Read last argument from STDIN
  -d <delimiter>   Multi-bulk delimiter in for raw formatting (default: \n)
  --raw            Use raw formatting for replies (default when STDOUT is not a tty)
  --latency        Enter a special mode continuously sampling latency.
  --help           Output this help and exit
  --version        Output version and exit

Examples:
  cat /etc/passwd | redis-cli -x set mypasswd
  redis-cli get mypasswd
  redis-cli -r 100 lpush mylist x
  redis-cli -r 100 -i 1 info | grep used_memory_human:

When no command is given, redis-cli starts in interactive mode.
Type "help" in interactive mode for information on available commands.

#登录
[root@server-000 ~]# redis-cli -h 192.168.0.5
redis 192.168.0.5:6379>

redis是一个key value的数据库一个键对应一个值

#登录redis
[root@server-000 ~]# redis-cli -h 192.168.0.5

#创建key
redis 192.168.0.5:6379> SET mykey hehe          #SET 命令 mykey key  hehe key的值
OK      #返回OK

#查看key
redis 192.168.0.5:6379> GET mykey           #查看mykey对应的值,命令不区分大小写,但是关键命令我们还是使用大写。
"hehe"          #双引号表示是一个字符串

#遍历库里所有key
redis 192.168.0.5:6379> keys *      #查看我们当前DB中有多少,生产不能用,会把库里所有遍历一遍,会影响业务。
1) "mykey"

#判断一个key是否存在,存在返回1,不存在返回0
redis 192.168.0.5:6379> EXISTS mykey
(integer) 1         #integer整数类型
redis 192.168.0.5:6379> EXISTS mykeye
(integer) 0


#删除成功也是返回一个整数1,不存在返回0
redis 192.168.0.5:6379> DEL mykey
(integer) 1
redis 192.168.0.5:6379> DEL mykeysdsada
(integer) 0


#判断字符串类型
redis 192.168.0.5:6379> SET mykey hehe
OK
redis 192.168.0.5:6379> TYPE mykey
string      #字符串

#学习数据结构,我们可以知道什么情况下我们可以使用redis

Redis介绍

Redis和memcached对比

memcached                   redis

类型 key-value数据库 Key-value数据库

过期策略 支持 支持

数据类型 单一数据类型 多种数据类型

持久化 不支持 支持

主从复制 不支持 支持

虚拟内存 不支持 支持(不建议使用,弃用)

redis基本命令

SET:设置key。

GET:获取key值。

EXISTS:判断key是否存在。

KEYS:显示所有的key(生产慎用)

DEL:删除指定的key。

TYPE:获取Key的类型。

Redis数据结构

字符类型

可以存储任何形式的字符串

SET(添加key)

GET (获取key) INCR((自增的用法)可以用在统计访客数上,就不需要写入日志了)

DEL (删除key) INCRBY(可以指定自增的步长)

APPEND (追加内容到value) DECR (自减)

STRLEN(获取字符串key的长度) DECRBY(指定自减步长)

MGET(可以同时获取多个值) INCRBTFLOAT(自增浮点类型)

MSET(可以同时设置多个值)

APPEND示例(追加)

[root@server-000 ~]# redis-cli -h 192.168.0.5 
redis 192.168.0.5:6379> SET mykey yanzi
OK

redis 192.168.0.5:6379> GET mykey
"yanzi"

redis 192.168.0.5:6379> APPEND mykey baojia
(integer) 11

redis 192.168.0.5:6379> GET mykey
"yanzibaojia"

STRlEN 判断字符串长度

redis 192.168.0.5:6379> STRLEN mykey
(integer) 11

INCR(自增的用法)可以用在统计访客数上,就不需要写入日志了

redis 192.168.0.5:6379> INCR num
(integer) 1
redis 192.168.0.5:6379> GET num
"1"
redis 192.168.0.5:6379> INCR num
(integer) 2
redis 192.168.0.5:6379> INCR num
(integer) 3
redis 192.168.0.5:6379> INCR num
(integer) 4
redis 192.168.0.5:6379> INCR num
(integer) 5
redis 192.168.0.5:6379> GET num
"5"

INCRBY(可以指定自增的步长)

redis 192.168.0.5:6379> INCRBY num 10
(integer) 15
redis 192.168.0.5:6379> INCRBY num 5
(integer) 20

DECR (自减)

redis 192.168.0.5:6379> DECR num
(integer) 19
redis 192.168.0.5:6379> DECR num
(integer) 18
redis 192.168.0.5:6379> DECR num
(integer) 17
redis 192.168.0.5:6379> DECR num
(integer) 16

指定自减步长

redis 192.168.0.5:6379> DECRBY num 5
(integer) 11
redis 192.168.0.5:6379> DECRBY num 5
(integer) 6
redis 192.168.0.5:6379> GET num
"6"

MGET(可以同时获取多个值)

redis 192.168.0.5:6379> MSET key1 chen key2 bao key3 jia key4 yan key5 zi
OK
redis 192.168.0.5:6379> KEYS *
1) "key2"
2) "key3"
3) "key4"
4) "key5"
5) "mykey"
6) "num"
7) "key1"

MSET(可以同时设置多个值

redis 192.168.0.5:6379> MGET key1 key2 key3 key4 key5
1) "chen"
2) "bao"
3) "jia"
4) "yan"
5) "zi"

散列类型(Hash)

Hash类型的键最多2的32次方-1个

HSET key field value #设置Hash类型的key

HGET key field #查看Hash类型的key

HMSET key field value [field value…] (设置多个HSET)

HMGET key field [field…] #查看多个Hash类型的key

HGETALL key #HGETALL 查看一个hash类型的key 里所有的东西

HDEl #删除某一个字段(field)

HEXISTS 判断一个key的字段是否存在

HSET key field value 和 HGET key field 示例 HSET如果有就设置,没有追加的概念,如果存在就给你改了。

redis 192.168.0.5:6379> HSET car name BWM
(integer) 1
redis 192.168.0.5:6379> HSET car price 200
(integer) 1
redis 192.168.0.5:6379> KEYS *
1) "mykey"
2) "num"
3) "car"
redis 192.168.0.5:6379> HGET car name
"BWM"

#HSET如果有就设置,没有追加的概念,如果存在就给你改了。
redis 192.168.0.5:6379> HGET car price
"200"
redis 192.168.0.5:6379> HSET car price 399
(integer) 0
redis 192.168.0.5:6379> HGET car price
"399"

HMSET key field value [field value…] (设置多个HSET)和HMGET key field [field…] #查看多个Hash类型的key

redis 192.168.0.5:6379> HMSET book price 10 name redis 
OK

redis 192.168.0.5:6379> HMGET book price name
1) "10"
2) "redis"

redis 192.168.0.5:6379> HmGET book name price
1) "redis"
2) "10"

HGETALL 查看一个hash类型的key 里所有的东西

redis 192.168.0.5:6379> HGETALL book
1) "price"
2) "10"
3) "name"
4) "redis"

HDEl #删除某一个字段(field)

redis 192.168.0.5:6379> HDEL book name
(integer) 1
redis 192.168.0.5:6379> HGETALL book
1) "price"
2) "10"

HEXISTS 判断一个key的字段是否存在

redis 192.168.0.5:6379> HEXISTS book name
(integer) 0
redis 192.168.0.5:6379> HEXISTS book price
(integer) 1
redis 192.168.0.5:6379> keys *
1) "book"
2) "mykey"
3) "num"
4) "car"
redis 192.168.0.5:6379> DEL book
(integer) 1
redis 192.168.0.5:6379> keys *
1) "mykey"
2) "num"
3) "car"

列表类型

官网列表类型 http://redis.cn/commands.html#list

比如我们电商网站在提交订单的时候就可以使用消息队列的形式,当做活动提交订单的时候,不是直接提交到数据库(什么数据库都扛不住),这时候就会提交到队列里,成功之后会返回订单正在处理中,这时候就是放在队列里,而不是写在数据库。

用户的订单放在消息队列,这样做活动就不用担心了。

用户注册也可以放在消息队列里,在大量并发可以充当数据库的缓冲,不会对数据库造成影响。按数据库的瓶颈往里写。

Redis 的列表(List)类型是按照插入顺序排序的字符串链表。该类型和数据结构中的普通链表一样,我们可以在其头部(LPUSH)和尾部(RPUSH)添加新的元素。在插入元素时,如果该键不存在,那么将创创建新列表。如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。

一个List中最多可存储2的32次方-1(40亿)个元素。操作列表元素时,如果是从链表的两头插入或删除元素,操作效率会非常高。即使列表中已存储了百万条数据,该操作也可以在常量短的时间内完成。但是,将元素插入列表中间或是删除位于链表中间元素,那操作效率会非常的低。

LPUSH key value [value…] 从左边插入

RPUSH key value [value…] 从右边插入

LPOP key 从左侧弹出

RPOP key 从右侧弹出

LRANGE key start stop 可以指定范围的从左侧

LREM key count value 可以指定范围的从右侧

#左边插入
redis 192.168.0.5:6379> LPUSH mylist 1hehe
(integer) 1
redis 192.168.0.5:6379> LPUSH mylist 2hehe
(integer) 2

#长度是2
redis 192.168.0.5:6379> LLEN mylist
(integer) 2

#右侧插入
redis 192.168.0.5:6379> RPUSH mylist 1hehe
(integer) 3
redis 192.168.0.5:6379> RPUSH mylist 2hehe
(integer) 4


#长度是4
redis 192.168.0.5:6379> LLEN mylist
(integer) 4

#从右侧开始第一个
redis 192.168.0.5:6379> LINDEX mylist -1
"2hehe"

#从右侧开始第二个
redis 192.168.0.5:6379> LINDEX mylist -2
"1hehe"

#从右侧开始第三个
redis 192.168.0.5:6379> LINDEX mylist -3
"1hehe"

#从右侧开始第四个
redis 192.168.0.5:6379> LINDEX mylist -4
"2hehe"

#弹出一次,减少一次知道弹没了,key也会被删除
redis 192.168.0.5:6379> keys *
1) "mykey"
2) "num"
3) "mylist"
4) "car"

redis 192.168.0.5:6379> RPOP mylist
"2hehe"

redis 192.168.0.5:6379> RPOP mylist
"1hehe"

redis 192.168.0.5:6379> RPOP mylist
"1hehe"

redis 192.168.0.5:6379> RPOP mylist
"2hehe"

redis 192.168.0.5:6379> keys *
1) "mykey"
2) "num"
3) "car"


# -1 是最右边的第一个元素,左侧是从0开始的。一下是范围内取值
redis 192.168.0.5:6379> LPUSH mylist k1
(integer) 1
redis 192.168.0.5:6379> LPUSH mylist k2
(integer) 2
redis 192.168.0.5:6379> LPUSH mylist k3
(integer) 3
redis 192.168.0.5:6379> LPUSH mylist k4
(integer) 4
redis 192.168.0.5:6379> LPUSH mylist k5
(integer) 5
redis 192.168.0.5:6379> LLEN mylist
(integer) 5
redis 192.168.0.5:6379> LRANGE mylist 2 -1
1) "k3"
2) "k2"
3) "k1"
redis 192.168.0.5:6379> LRANGE mylist 1 -1
1) "k4"
2) "k3"
3) "k2"
4) "k1"
redis 192.168.0.5:6379> LRANGE mylist 0 -1
1) "k5"
2) "k4"
3) "k3"
4) "k2"
5) "k1"

集合(sets)

sets命令官网 http://redis.cn/commands.html#set

Redis Set 是 String 的无序的无序集合。SADD 指令把新的元素添加到 set 中。对 set 也可做一些其他的操作,比如测试一个给定的元素是否存在,对不同 set 取交集,并集或差,等等。

Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。 Redis 中 集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 2的32次方 – 1 (4294967295, 每个集合可存储40多亿个成员)。

可以用在浏览器搜索的补全操作,微博关注,类似关系网,你有四个好友有这个人,然后推荐给你,这些都是集合这样的方式来做的。

差集,交集,并集

SADD :添加一个或多个指定的member元素到集合的 key中.指定的一个或者多个元素member 如果已经在集合key中存在则忽略.如果集合key 不存在,则新建集合key,并添加member元素到集合key中. 如果key 的类型不是集合则返回错误.

redis 192.168.0.5:6379> SADD setA 1 2 3
(integer) 3
redis 192.168.0.5:6379> SADD setB 2 3 4
(integer) 3
redis 192.168.0.5:6379> SDIFF setA setB
1) "1"      #A有1 B没有1 所以打印出来
redis 192.168.0.5:6379> SDIFF setB setA
1) "4"          #B 有4  A 没有所以打印出来

SDIFF key [key …]

时间复杂度:O(N) where N is the total number of elements in all given sets. 返回一个集合与给定集合的差集的元素.

redis 192.168.0.5:6379> SADD k1 a b c d
(integer) 4
redis 192.168.0.5:6379> SADD k2 c
(integer) 1
redis 192.168.0.5:6379> SADD k3 a c e
(integer) 3
redis 192.168.0.5:6379> SDIFF k1 k2 k3
1) "d"
2) "b"

交集

因为AB都有23所有会打印出来
redis 192.168.0.5:6379> SINTER setA setB
1) "2"
2) "3"
redis 192.168.0.5:6379> SINTER setB setA
1) "2"
2) "3"

#k1 k2 k3都有c
redis 192.168.0.5:6379> SINTER k1 k2 k3
1) "c"

并集

SUNION key [key …] 返回给定的多个集合的并集中的所有成员. 例如:

redis 192.168.0.5:6379> SUNION setA setB
1) "1"
2) "2"
3) "3"
4) "4"

redis 192.168.0.5:6379> SUNION k1 k2 k3
1) "b"
2) "c"
3) "d"
4) "e"
5) "a"

SCARD key 返回集合存储的key的基数 (集合元素的数量).

redis 192.168.0.5:6379> SCARD setA
(integer) 3
redis 192.168.0.5:6379> SCARD k1
(integer) 4
redis 192.168.0.5:6379> SCARD k2
(integer) 1
redis 192.168.0.5:6379> SDIFF setA setB
1) "1"
#该命令类似于 SDIFF, 不同之处在于该命令不返回结果集,而是将结果存放在destination集合中.
#如果destination已经存在, 则将其覆盖重写.相当于把结果重新赋值给一个新的key
redis 192.168.0.5:6379> SDIFFSTORE hehe setA setB
(integer) 1

redis 192.168.0.5:6379> get hehe
(error) ERR Operation against a key holding the wrong kind of value

redis 192.168.0.5:6379> type hehe
set
#返回key集合所有的元素.该命令的作用与使用一个参数的SINTER 命令作用相同.
redis 192.168.0.5:6379> SMEMBERS hehe
1) "1"
redis 192.168.0.5:6379> SADD word1 a
(integer) 1

#我们可以看到这里没有再添加a,因为a已经存在,所以只添加了2个
redis 192.168.0.5:6379> SADD word1 a b c
(integer) 2

#我们可以看到只添加了一个
redis 192.168.0.5:6379> SADD word1 a b c d
(integer) 1

redis 192.168.0.5:6379> SADD word1 a b c d e
(integer) 1

#删除word1(key) 中的e
redis 192.168.0.5:6379> SREM word1 e
(integer) 1

#列出word1中的元素
redis 192.168.0.5:6379> SMEMBERS word1
1) "c"
2) "d"
3) "a"
4) "b"

#判断word1中的元素是否存在,存在即返回1,不存在返回0.
redis 192.168.0.5:6379> SISMEMBER word1 e
(integer) 0
redis 192.168.0.5:6379> SISMEMBER word1 d
(integer) 1

有序集合

http://redis.cn/commands.html#sorted_set

http://redisdoc.com/sorted_set/index.html

Pub/Sub(发布/订阅)生产不用

http://redisdoc.com/pub_sub/index.html

订阅者 发布者

缺点:如果中以为订阅者在发布者发布消息时出现故障,那么这个消息队列就会错过而不能再接收到。

我们在生产中会使用RabbitMQ,kafka,

Transaction(事务)经常用到

比如一堆命令,要不都执行,要不都不执行。

缺点:执行错误了没有回滚的功能,成功还是执行,错误的就不会执行。

如果需要用的话可以在程序里进行控制,比如检测命令是否都正确。

Redis 持久化(persistence)

http://redisdoc.com/topic/persistence.html

把内存的数据保存到磁盘上就是持久化。

Redis持久化有两种方式

Redis 提供了多种不同级别的持久化方式:

RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。

AOF 持久化记录服务器执行的所有写操作命令,(跟MySQL的binlog日志相似)并在服务器启动时,通过重新执行这些命令来还原数据集。 AOF 文件中的命令全部以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。 Redis 还可以在后台对 AOF 文件进行重写(rewrite),使得 AOF 文件的体积不会超出保存数据集状态所需的实际大小。

Redis 还可以同时使用 AOF 持久化和 RDB 持久化。 在这种情况下, 当 Redis 重启时, 它会优先使用 AOF 文件来还原数据集, 因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集更完整。

你甚至可以关闭持久化功能,让数据只在服务器运行时存在。

了解 RDB 持久化和 AOF 持久化之间的异同是非常重要的, 以下几个小节将详细地介绍这这两种持久化功能, 并对它们的相同和不同之处进行说明。

RDB 的优点

RDB 是一个非常紧凑(compact)的文件,它保存了 Redis 在某个时间点上的数据集。这种文件非常适合用于进行备份(灾备非常非常重要): 比如说,你可以在最近的 24 小时内,每小时备份一次 RDB 文件,并且在每个月的每一天,也备份一个 RDB 文件。 这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。

RDB 非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的数据中心,或者亚马逊 S3 中。

RDB 可以最大化 Redis 的性能:父进程在保存 RDB 文件时唯一要做的就是 fork 出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘 I/O 操作。

RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快。

RDB 的缺点

如果你需要尽量避免在服务器故障时丢失数据,那么 RDB 不适合你。 虽然 Redis 允许你设置不同的保存点(save point)来控制保存 RDB 文件的频率, 但是, 因为RDB 文件需要保存整个数据集的状态, 所以它并不是一个轻松的操作。

因此你可能会至少 5 分钟才保存一次 RDB 文件。 在这种情况下, 一旦发生故障停机, 你就可能会丢失好几分钟的数据。

每次保存 RDB 的时候,Redis 都要 fork() 出一个子进程,并由子进程来进行实际的持久化工作。

在数据集比较庞大时, fork() 可能会非常耗时,造成服务器在某某毫秒内停止处理客户端;

如果数据集非常巨大,并且 CPU 时间非常紧张的话,那么这种停止时间甚至可能会长达整整一秒。 虽然 AOF 重写也需要进行 fork() ,但无论 AOF 重写的执行间隔有多长,数据的耐久性都不会有任何损失。

RDB的参数修改

[root@server-000 ~]# vim /etc/redis.conf 
save 900 1          #900秒内如果有一个key被改变那么就快照
save 300 10         #300秒内如果有10个建被改变那么就快照
save 60 10000       #60秒内如果有10000个键被改变那么就快照 对性能影响还是挺大的

 97 dbfilename dump.rdb   #存快照的地方
 107 dir /var/lib/redis/    #如果在编译的时候没指定或者配置文件没有指定,那么你在哪里启动这个配置文件就在当前目录下。
 
 

[root@server-000 ~]# ll /var/lib/redis/
总用量 4
-rw-r--r-- 1 redis redis 127 57 20:07 dump.rdb

[root@server-000 ~]# file /var/lib/redis/dump.rdb   #DRB文件是有压缩的,所以会比内存中小
/var/lib/redis/dump.rdb: data

Redis在启动的时候会载入DRB文件到内存,6G大概载入时间需要1分钟。

Redis启动时间需要看DRB文件有多大进行判断。

RDB快照的流程

1、Fork子进程

2、父进程继续干活,子进程开始将内存中的数据写入硬盘中的临时文件。

3、当子进程写完数据后,用临时文件替换原来的DRB文件。

AOF 的优点

使用 AOF 持久化会让 Redis 变得非常耐久(much more durable):你可以设置不同的 fsync 策略,比如无 fsync ,每秒钟一次 fsync ,或者每次执行写入命令时 fsync 。 AOF 的默认策略为每秒钟 fsync 一次,在这种配置下,Redis 仍然可以保持良好的性能,并且就算发生故障停机,也最多只会丢失一秒钟的数据( fsync 会在后台线程执行,所以主线程可以继续努力地处理命令请求)。

AOF 文件是一个只进行追加操作的日志文件(append only log), 因此对 AOF 文件的写入不需要进行 seek , 即使日志因为某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途停机,等等), redis-check-aof 工具也可以轻易地修复这种问题。

Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 整个重写操作是绝对安全的,因为 Redis 在创建新 AOF 文件的过程中,会继续将命令追加到现有的 AOF 文件里面,即使重写过程中发生停机,现有的 AOF 文件也不会丢失。 而一旦新 AOF 文件创建完毕,Redis 就会从旧 AOF 文件切换到新 AOF 文件,并开始对新 AOF 文件进行追加操作。

AOF 文件有序地保存了对数据库执行的所有写入操作, 这些写入操作以 Redis 协议的格式保存, 因此 AOF 文件的内容非常容易被人读懂, 对文件进行分析(parse)也很轻松。 导出(export) AOF 文件也非常简单: 举个例子, 如果你不小心执行了 FLUSHALL 命令, 但只要 AOF 文件未被重写, 那么只要停止服务器, 移除 AOF 文件末尾的 FLUSHALL 命令, 并重启 Redis , 就可以将数据集恢复到 FLUSHALL 执行之前的状态。

AOF 的缺点

对于相同的数据集来说,AOF 文件的体积通常要大于 RDB 文件的体积。

根据所使用的 fsync 策略,AOF 的速度可能会慢于 RDB 。 在一般情况下, 每秒 fsync 的性能依然非常高, 而关闭 fsync 可以让 AOF 的速度和 RDB 一样快, 即使在高负荷之下也是如此。

不过在处理巨大的写入载入时,RDB 可以提供更有保证的最大延迟时间(latency)。

AOF 在过去曾经发生过这样的 bug : 因为个别命令的原因,导致 AOF 文件在重新载入时,无法将数据集恢复成保存时的原样。 (举个例子,阻塞命令 BRPOPLPUSH 就曾经引起过这样的 bug 。) 测试套件里为这种情况添加了测试:

它们会自动生成随机的、复杂的数据集, 并通过重新载入这些数据来确保一切正常。 虽然这种 bug 在 AOF 文件中并不常见, 但是对比来说, RDB 几乎是不可能出现这种 bug 的。

[root@server-000 ~]# vim /etc/redis.conf 
#修改配置文件来打开 AOF 功能:
268 appendonly yes

[root@server-000 ~]# /etc/init.d/redis restart
Restarting redis (via systemctl):                          [  确定  ]

[root@server-000 ~]# ll /var/lib/redis/
总用量 4
-rw-r--r-- 1 redis redis   0 58 05:24 appendonly.aof
-rw-r--r-- 1 redis redis 127 58 05:24 dump.rdb


[root@server-000 ~]# redis-cli -h 192.168.0.5
redis 192.168.0.5:6379> info
redis_version:2.4.10
redis_git_sha1:00000000
redis_git_dirty:0
arch_bits:64
multiplexing_api:epoll
gcc_version:4.4.6
process_id:16509
uptime_in_seconds:174
uptime_in_days:0
lru_clock:521455
used_cpu_sys:0.00
used_cpu_user:0.05
used_cpu_sys_children:0.00
used_cpu_user_children:0.00
connected_clients:1
connected_slaves:0
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
used_memory:726128
used_memory_human:709.11K
used_memory_rss:3538944
used_memory_peak:726056
used_memory_peak_human:709.04K
mem_fragmentation_ratio:4.87
mem_allocator:jemalloc-2.2.5
loading:0
aof_enabled:1
changes_since_last_save:0
bgsave_in_progress:0
last_save_time:1494192299
bgrewriteaof_in_progress:0
total_connections_received:1
total_commands_processed:0
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0
vm_enabled:0
role:master
aof_current_size:0
aof_base_size:0
aof_pending_rewrite:0
aof_buffer_length:0
aof_pending_bio_fsync:0

redis 192.168.0.5:6379> set key1 vi
OK
redis 192.168.0.5:6379> set key2 v2
OK

redis 192.168.0.5:6379> exit
[root@server-000 ~]# cat /var/lib/redis/appendonly.aof 
*2
$6
SELECT
$1
0
*3
$3
set
$4
key1
$2
vi
*3
$3
set
$4
key2
$2
v2

命令行执行set

[root@server-000 ~]# for ((i=1;i<=1000;i++));do echo $i;done
[root@server-000 ~]# for ((i=1;i<=1000;i++));do redis-cli -h 192.168.0.5 SET k$i $i;done

AOF流程

1、Fork子进程

2、父进程继续干活,子进程开始将内存中的数据写入硬盘中的临时文件。

3、当子进程写完数据后,用临时文件替换原来的AOF文件。

AOF 的耐久性如何?

你可以配置 Redis 多久才将数据 fsync 到磁盘一次。

有三个选项:

每次有新命令追加到 AOF 文件时就执行一次 fsync :非常慢,也非常安全。

每秒 fsync 一次:足够快(和使用 RDB 持久化差不多),并且在故障时只会丢失 1 秒钟的数据。缺省

从不 fsync :将数据交给操作系统来处理。更快,也更不安全的选择。

推荐(并且也是默认)的措施为每秒 fsync 一次, 这种 fsync 策略可以兼顾速度和安全性。

总是 fsync 的策略在实际使用中非常慢, 即使在 Redis 2.0 对相关的程序进行了改进之后仍是如此 —— 频繁调用 fsync 注定了这种策略不可能快得起来。

怎么从 RDB 持久化切换到 AOF 持久化(不重启redis)

在 Redis 2.2 或以上版本,可以在不重启的情况下,从 RDB 切换到 AOF :

为最新的 dump.rdb 文件创建一个备份。

将备份放到一个安全的地方。

执行以下两条命令:

redis-cli> CONFIG SET appendonly yes

redis-cli> CONFIG SET save “” #这个就不要执行 了这个是关闭RDB,直接把save的配置给关了

确保命令执行之后,数据库的键的数量没有改变。

确保写命令会被正确地追加到 AOF 文件的末尾。

步骤 3 执行的第一条命令开启了 AOF 功能: Redis 会阻塞直到初始 AOF 文件创建完成为止, 之后 Redis 会继续处理命令请求, 并开始将写入命令追加到 AOF 文件末尾。

步骤 3 执行的第二条命令用于关闭 RDB 功能。 这一步是可选的, 如果你愿意的话, 也可以同时使用 RDB 和 AOF 这两种持久化功能。

别忘了在 redis.conf 中打开 AOF 功能! 否则的话, 服务器重启之后, 之前通过 CONFIG SET 设置的配置就会被遗忘, 程序会按原来的配置来启动服务器。 译注: 原文这里还有介绍 2.0 版本的切换方式, 考虑到 2.0 已经很老旧了, 这里省略了对那部分文档的翻译, 有需要的请参考原文。

Redis备份与安全

Redis并不是越大越好,因为载入就会阻塞,可以有多台redis。

备份 Redis 数据

在阅读这个小节前, 先将下面这句话铭记于心: 一定要备份你的数据库!

磁盘故障, 节点失效, 诸如此类的问题都可能让你的数据消失不见, 不进行备份是非常危险的。

Redis 对于数据备份是非常友好的, 因为你可以在服务器运行的时候对 RDB 文件进行复制: RDB 文件一旦被创建, 就不会进行任何修改。 当服务器要创建一个新的 RDB 文件时, 它先将文件的内容保存在一个临时文件里面, 当临时文件写入完毕时, 程序才使用 rename(2) 原子地用临时文件替换原来的 RDB 文件。

这也就是说, 无论何时, 复制 RDB 文件都是绝对安全的。

以下是我们的建议:

创建一个定期任务(cron job), 每小时将一个 RDB 文件备份到一个文件夹, 并且每天将一个 RDB 文件备份到另一个文件夹。

确保快照的备份都带有相应的日期和时间信息, 每次执行定期任务脚本时, 使用 find 命令来删除过期的快照: 比如说, 你可以保留最近 48 小时内的每小时快照, 还可以保留最近一两个月的每日快照。

至少每天一次, 将 RDB 备份到你的数据中心之外, 或者至少是备份到你运行 Redis 服务器的物理机器之外。

容灾备份

Redis 的容灾备份基本上就是对数据进行备份, 并将这些备份传送到多个不同的外部数据中心。

容灾备份可以在 Redis 运行并产生快照的主数据中心发生严重的问题时, 仍然让数据处于安全状态。

因为很多 Redis 用户都是创业者, 他们没有大把大把的钱可以浪费, 所以下面介绍的都是一些实用又便宜的容灾备份方法:

Amazon S3 ,以及其他类似 S3 的服务,是一个构建灾难备份系统的好地方。 最简单的方法就是将你的每小时或者每日 RDB 备份加密并传送到 S3 。 对数据的加密可以通过 gpg -c 命令来完成(对称加密模式)。 记得把你的密码放到几个不同的、安全的地方去(比如你可以把密码复制给你组织里最重要的人物)。 同时使用多个储存服务来保存数据文件,可以提升数据的安全性。 传送快照可以使用 SCP 来完成(SSH 的组件)。 以下是简单并且安全的传送方法: 买一个离你的数据中心非常远的 VPS , 装上 SSH , 创建一个无口令的 SSH 客户端 key , 并将这个 key 添加到 VPS 的 authorized_keys 文件中, 这样就可以向这个 VPS 传送快照备份文件了。 为了达到最好的数据安全性,至少要从两个不同的提供商那里各购买一个 VPS 来进行数据容灾备份。 需要注意的是, 这类容灾系统如果没有小心地进行处理的话, 是很容易失效的。

最低限度下, 你应该在文件传送完毕之后, 检查所传送备份文件的体积和原始快照文件的体积是否相同。 如果你使用的是 VPS , 那么还可以通过比对文件的 SHA1 校验和来确认文件是否传送完整。

另外, 你还需要一个独立的警报系统, 让它在负责传送备份文件的传送器(transfer)失灵时通知你。

讨论 comments powered by Disqus

redis 安全

1、操作加上验证设置一个密码

2、给危险命令重命名。 配置文件里

# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52
#
# It is also possilbe to completely kill a command renaming it into
# an empty string:
#
# rename-command CONFIG ""

Redis Crackit漏洞利用和防护

https://www.unixhot.com/article/23

如何防护:

1.禁用这些可以入侵的命令:
 [root@test-node2 ~]# vim /etc/redis.conf
 rename-command FLUSHALL ""
 #rename-command CONFIG ""  注意,设置了,可就不能用了,如果需要使用可以设置一个其它名称。

2.将你的redis不要运行在0.0.0.0.或者设置验证。
 [root@test-node2 ~]# vim /etc/redis.conf
requirepass redis-passwd
bind 192.168.199.11

3.尽量不要使用root运行。默认yum安装的redis,是运行在redis用户的。

如何发现被入侵:

1.你的redis数据莫名其妙没有了。
 2.检查你的rdb文件存放的路径
 3.检查是否有非法的authorized_keys
[root@server-000 ~]# redis-cli -h 192.168.0.5 -p 6379
redis 192.168.0.5:6379> select 1
OK

SELECT index

切换到指定的数据库,数据库索引号 index 用数字值指定,以 0 作为起始索引值。

默认使用 0 号数据库。

[root@server-000 ~]# redis-cli -h 192.168.0.5 -p 6379
redis 192.168.0.5:6379> select 1
OK

redis 192.168.0.5:6379[1]> set key1 1
OK

redis 192.168.0.5:6379[1]> info
db0:keys=1004,expires=0
db1:keys=1,expires=0

redis 192.168.0.5:6379[1]> select 2
OK

redis 192.168.0.5:6379[2]> set key1 1
OK

redis 192.168.0.5:6379[2]> info
db0:keys=1004,expires=0
db1:keys=1,expires=0
db2:keys=1,expires=0
[root@server-000 ~]# vim /etc/redis.conf

166 requirepass oldboy          #设置密码

[root@server-000 ~]# /etc/init.d/redis restart
Restarting redis (via systemctl):                          [  确定  ]


[root@server-000 ~]# redis-cli -h 192.168.0.5 -p 6379
Could not connect to Redis at 192.168.0.5:6379: Connection refused
#连接不上的原因是我们前面做主从的时候没有把从库的aof文件目录修改一下,导致都写在同一个目录下所以出现混乱错误,现在我们删除了,

[root@server-000 ~]# cd /var/lib/redis/
[root@server-000 redis]# \rm -f appendonly.aof 

[root@server-000 redis]# /etc/init.d/redis restart
Restarting redis (via systemctl):                          [  确定  ]
[root@server-000 redis]# redis-cli -h 192.168.0.5 -p 6379
redis 192.168.0.5:6379> set chen baojia
(error) ERR operation not permitted         #提示没有权限

#我们输入我们刚设置的密码
redis 192.168.0.5:6379> auth oldboy
OK
redis 192.168.0.5:6379> set key1 1
OK

Redis主从

redis 复制

Redis并不是越大越好,因为载入就会阻塞,可以有多台redis。

[root@server-000 ~]# cp /etc/redis.conf /etc/redis.conf.ori

[root@server-000 ~]# vim /etc/redis.conf.ori #修改端口我们来做主从复制
 25 port 6378
 
 #查看安装redis命令所有安装目录
 [root@server-000 ~]# rpm -ql redis
/etc/logrotate.d/redis
/etc/rc.d/init.d/redis
/etc/redis.conf
/usr/bin/redis-benchmark
/usr/bin/redis-check-aof
/usr/bin/redis-check-dump
/usr/bin/redis-cli
/usr/sbin/redis-server
/usr/share/doc/redis-2.4.10
/usr/share/doc/redis-2.4.10/00-RELEASENOTES
/usr/share/doc/redis-2.4.10/BUGS
/usr/share/doc/redis-2.4.10/CONTRIBUTING
/usr/share/doc/redis-2.4.10/COPYING
/usr/share/doc/redis-2.4.10/README
/usr/share/doc/redis-2.4.10/TODO
/var/lib/redis
/var/log/redis
/var/run/redis

#查看命令帮助
[root@server-000 ~]# /usr/sbin/redis-server --help
Usage: ./redis-server [/path/to/redis.conf]
       ./redis-server - (read config from stdin)
       ./redis-server --test-memory <megabytes>

#直接带上配置文件即可
[root@server-000 ~]# /usr/sbin/redis-server /etc/redis.conf.ori 

#查看端口可以看到已经起来了,6378做从,6379做主
[root@server-000 ~]# netstat -lntup|grep redis
tcp        0      0 192.168.0.5:6378        0.0.0.0:*               LISTEN      17592/redis-server  
tcp        0      0 192.168.0.5:6379        0.0.0.0:*               LISTEN      16509/redis-server

[root@server-000 ~]# redis-cli -h 192.168.0.5 -p 6379
redis 192.168.0.5:6379>

[root@server-000 ~]# redis-cli -h 192.168.0.5 -p 6378
redis 192.168.0.5:6378>

在从上设置主从复制

[root@server-000 ~]# redis-cli -h 192.168.0.5 -p 6378
redis 192.168.0.5:6378> slaveof 192.168.0.5 6379
OK
redis 192.168.0.5:6378> INFO
redis_version:2.4.10
redis_git_sha1:00000000
redis_git_dirty:0
arch_bits:64
multiplexing_api:epoll
gcc_version:4.4.6
process_id:17592
uptime_in_seconds:398
uptime_in_days:0
lru_clock:521701
used_cpu_sys:0.04
used_cpu_user:0.03
used_cpu_sys_children:0.00
used_cpu_user_children:0.00
connected_clients:2
connected_slaves:0
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
used_memory:791128
used_memory_human:772.59K
used_memory_rss:1716224
used_memory_peak:791120
used_memory_peak_human:772.58K
mem_fragmentation_ratio:2.17
mem_allocator:jemalloc-2.2.5
loading:0
aof_enabled:1
changes_since_last_save:0
bgsave_in_progress:0
last_save_time:1494194837
bgrewriteaof_in_progress:0
total_connections_received:1
total_commands_processed:2
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:84
vm_enabled:0
role:slave
aof_current_size:31871
aof_base_size:31871
aof_pending_rewrite:0
aof_buffer_length:0
aof_pending_bio_fsync:0
master_host:192.168.0.5         #这里可以看到master 的IP
master_port:6379            #master 的端口
master_link_status:up       #状态
master_last_io_seconds_ago:0        #最后一次的io用了多少时间
master_sync_in_progress:0       #
db0:keys=1002,expires=0     #keys 1002

[root@server-000 ~]# redis-cli -h 192.168.0.5 -p 6379
redis 192.168.0.5:6379> INFO
....        #省略下拉到最底
slave0:192.168.0.5,61350,online
db0:keys=1002,expires=0             #可以看到keys 是和从对上的

#创建一个测试文件然后在从上查看
redis 192.168.0.5:6379> SET masterkey1 mac
OK          

redis 192.168.0.5:6378> GET masterkey1
"mac"

!!注意:默认情况下redis从库默认是只读的 。2.6的版本,这次我们安装的是2.4版本所有没有 只读的话,那么从库会拒绝所有的写命令。如果主挂了,那么切换到从库就不行了,需要把从库改成可读写才行,

解决方法:SLAVEOF NO ONE #将从库数据库提升为主数据库。

2、从库Redis做持久化(类似我们MySQL在从库上做备份一样mysqldump)

复制功能的运作原理

命令BGSAVE

在后台异步(Asynchronously)保存当前数据库的数据到磁盘。

BGSAVE 命令执行之后立即返回 OK ,然后 Redis fork 出一个新子进程,原来的 Redis 进程(父进程)继续处理客户端请求,而子进程则负责将数据保存到磁盘,然后退出。

客户端可以通过 LASTSAVE 命令查看相关信息,判断 BGSAVE 命令是否执行成功。

无论是初次连接还是重新连接, 当建立一个从服务器时, 从服务器都将向主服务器发送一个 SYNC 命令。

接到 SYNC 命令的主服务器将开始执行 BGSAVE(就是把内存里的数据保存下来) , 并在保存操作执行期间, 将所有新执行的写入命令都保存到一个缓冲区里面。

当 BGSAVE 执行完毕后, 主服务器将执行保存操作所得的 .rdb 文件发送给从服务器, 从服务器接收这个 .rdb 文件, 并将文件中的数据载入到内存中。

之后主服务器会以 Redis 命令协议的格式, 将写命令缓冲区中积累的所有内容都发送给从服务器。

你可以通过 telnet 命令来亲自验证这个同步过程: 首先连上一个正在处理命令请求的 Redis 服务器, 然后向它发送 SYNC 命令, 过一阵子, 你将看到 telnet 会话(session)接收到服务器发来的大段数据(.rdb 文件), 之后还会看到, 所有在服务器执行过的写命令, 都会重新发送到 telnet 会话来。

即使有多个从服务器同时向主服务器发送 SYNC , 主服务器也只需执行一次 BGSAVE 命令, 就可以处理所有这些从服务器的同步请求。

从服务器可以在主从服务器之间的连接断开时进行自动重连, 在 Redis 2.8 版本之前, 断线之后重连的从服务器总要执行一次完整重同步(full resynchronization)操作, 但是从 Redis 2.8 版本开始, 从服务器可以根据主服务器的情况来选择执行完整重同步还是部分重同步(partial resynchronization)。

部分重同步

从 Redis 2.8 开始, 在网络连接短暂性失效之后, 主从服务器可以尝试继续执行原有的复制进程(process), 而不一定要执行完整重同步操作。

这个特性需要主服务器为被发送的复制流创建一个内存缓冲区(in-memory backlog), 并且主服务器和所有从服务器之间都记录一个复制偏移量(replication offset)和一个主服务器 ID (master run id), 当出现网络连接断开时, 从服务器会重新连接, 并且向主服务器请求继续执行原来的复制进程:

如果从服务器记录的主服务器 ID 和当前要连接的主服务器的 ID 相同, 并且从服务器记录的偏移量所指定的数据仍然保存在主服务器的复制流缓冲区里面, 那么主服务器会向从服务器发送断线时缺失的那部分数据, 然后复制工作可以继续执行。 否则的话, 从服务器就要执行完整重同步操作。

Redis 2.8 的这个部分重同步特性会用到一个新增的 PSYNC 内部命令, 而 Redis 2.8 以前的旧版本只有 SYNC 命令, 不过, 只要从服务器是 Redis 2.8 或以上的版本, 它就会根据主服务器的版本来决定到底是使用 PSYNC 还是 SYNC :

如果主服务器是 Redis 2.8 或以上版本,那么从服务器使用 PSYNC 命令来进行同步。

如果主服务器是 Redis 2.8 之前的版本,那么从服务器使用 SYNC 命令来进行同步。我们这里用的是2.4版本。

#主库
redis 192.168.0.5:6379> BGSAVE
Background saving started       #后台开始保存

#从库
redis 192.168.0.5:6378> LASTSAVE
(integer) 1494195738

主从切换脚本检测

思路 1、

redis 192.168.0.5:6379> PING
PONG        #可以写一个脚本判断,如果出现ping

之后的PONG说明是正常的,否者就是不正常。核实后我们把从库提升为master

解决方法:1、SLAVEOF NO ONE #将从库数据库提升为主数据库。

2、从库Redis做持久化(类似我们MySQL在从库上做备份一样mysqldump)通过设置VIP切换

3、建议使用 Redis主从+keepalived自己可以写一个检测脚本

4、Sentinel 系统用于管理多个 Redis 服务器(instance

http://redisdoc.com/topic/sentinel.html#sentinel-api

Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务:

监控(Monitoring): Sentinel 会不断地检查你的主服务器和从服务器是否运作正常。

提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API向管理员或者其他应用程序发送通知。

自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作, 它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其他从服务器改为复制新的主服务器; 当客户端试图连接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群可以使用新主服务器代替失效服务器。

Redis Sentinel 是一个分布式系统, 你可以在一个架构中运行多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。

虽然 Redis Sentinel 释出为一个单独的可执行文件 redis-sentinel , 但实际上它只是一个运行在特殊模式下的 Redis 服务器, 你可以在启动一个普通 Redis 服务器时通过给定 –sentinel 选项来启动 Redis Sentinel 。

Redis Sentinel 目前仍在开发中, 这个文档的内容可能随着 Sentinel 实现的修改而变更。 Redis Sentinel 兼容 Redis 2.4.16 或以上版本, 推荐使用 Redis 2.8.0 或以上的版本。

php使用redis的方法

缓存插件

https://pecl.php.net/package/redis

[root@server-000 ~]# cd /usr/local/src/
[root@server-000 src]# wget https://pecl.php.net/get/redis-2.2.7.tgz
[root@server-000 redis-2.2.7]# tar zxf redis-2.2.7.tgz 
[root@server-000 redis-2.2.7]# cd redis-2.2.7
[root@server-000 redis-2.2.7]# phpize 
[root@server-000 redis-2.2.7]# ./configure --with-php-config=/usr/bin/php-config 
[root@server-000 redis-2.2.7]# make && make install 

随后会出现redis.so的文件,然后我们需要在php.ini中加入

vim php.ini

extension = redis.so

重启php
#Centos 7
[root@server-000 modules]# systemctl restart php-fpm

#Centos 6
[root@server-000 modules]# service php-fpm restart


检查:1、phpino 搜索是否有redis
<?php
phpinfo();
?>


2、redis.php(创建一个php程序测试)

<?php
$redis = new Redis();
$redis->connect('192.168.0.5',6379);
$redis->set('keyname','value');
echo $redis->get('keyname');
?>

INFO 详解

http://redisdoc.com/server/info.html

[root@server-000 html]# redis-cli -h 192.168.0.5 -p 6379
redis 192.168.0.5:6379> INFO
redis_version:2.4.10
redis_git_sha1:00000000
redis_git_dirty:0
arch_bits:64
multiplexing_api:epoll
gcc_version:4.4.6
process_id:16509
uptime_in_seconds:9888
uptime_in_days:0
lru_clock:522426
used_cpu_sys:1.32
used_cpu_user:0.68
used_cpu_sys_children:0.00
used_cpu_user_children:0.00
connected_clients:1     #已连接客户端的数量(不包括通过从属服务器连接的客户端)
connected_slaves:1          #已连接的从服务器数量。 这两个是我们需要关注的
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
used_memory:791360          #由 Redis 分配器分配的内存总量,以字节(byte)为单位
used_memory_human:772.81K       # 以人类可读的格式返回 Redis 的内存消耗峰值
used_memory_rss:3842048    #从操作系统的角度,返回 Redis 已分配的内存总量(俗称常驻集大小)。这个值和 top 、 ps 等命令的输出一致。
used_memory_peak:791328         #Redis 的内存消耗峰值(以字节为单位)
used_memory_peak_human:772.78K      # 以人类可读的格式返回 Redis 的内存消耗峰值
mem_fragmentation_ratio:4.85        #used_memory_rss 和 used_memory 之间的比率
mem_allocator:jemalloc-2.2.5        #在编译时指定的, Redis 所使用的内存分配器。可以是 libc 、 jemalloc 或者 tcmalloc 。       
loading:0
aof_enabled:1
changes_since_last_save:1
bgsave_in_progress:0
last_save_time:1494201924
bgrewriteaof_in_progress:0
total_connections_received:1007
total_commands_processed:1012
expired_keys:0
evicted_keys:0
keyspace_hits:2
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:217
vm_enabled:0
role:master
aof_current_size:31984
aof_base_size:0
aof_pending_rewrite:0
aof_buffer_length:0
aof_pending_bio_fsync:0
slave0:192.168.0.5,61350,online
db0:keys=1004,expires=0

used_memory_peak:791328 #Redis 的内存消耗峰值(以字节为单位)

used_memory_peak_human:772.78K # 以人类可读的格式返回 Redis 的内存消耗峰值

这两个是我们在做zabbix监控要做的。监控就是通过info来获取信息

master_link_status:up #也可以监控up 表示连接正常,down表示连接断开。

刚到一家公司如何成为牛人,可以找一个入手的点,比如公司redis用的特别多,把这个点做好,可以把所有的redis管理起来,把全部监控全部做好,把所有主从全部做好,分享整个redis的状态报表,每天给领导发一个报表,例如主从的状态,例如多少客户端连接,每个DB的key,内存设置了多少,现在用了多少。老板和领导特别喜欢看这个,

专业的运维要能把你管理的东西有一个清单,在出现问题的时候能有一个清单,可以进行判断出现这个问题会影响到那一些服务。而且要知道你管理的对象,当时设置的容量是多大,现在是多大。可以根据增长率来进行调整。

phpredisadmin用于管理redis-server的软件

需要php5.3.4才能玩

https://github.com/erikdubbelboer/phpRedisAdmin

[root@server-000 html]# yum install -y httpd php php-pdo php-cli php-gd php-mbstring

php-gd 是画图的

php-pdo 连接数据库的扩展的

[root@server-000 tools]# cd /application/tools/

curl -s http://getcomposer.org/installer | php php composer.phar create-project -s dev erik-dubbelboer/php-redis-admin path/to/install

[root@server-000 tools]# wget https://github.com/erikdubbelboer/phpRedisAdmin/archive/master.zip

[root@server-000 tools]# unzip master.zip

rdbtools(生产常用的内存分析工具)

看看redis到底存了什么东西 https://github.com/sripathikrishnan/redis-rdb-tools

分析内存非常有用

[root@web02 ~]# yum install python-pip

pip install rdbtools

命令用法

[root@server-000 ~]# cd /var/lib/redis/
[root@server-000 redis]# cp dump.rdb /tmp/  #注意千万不能损坏dump.rdb包,所以我么复制一份
[root@server-000 redis]# rdb --command json /tmp/dump.rdb > redis.csv

redis集群

1、客户端分片(最靠谱的): 将redis分片的工作放在业务程序端。可以根据用户末尾的UID数字来进行分别存放的redisserver。比如用户uid最后的数字是1那么就存放到redis1上,以此类推,如果9个数不够那么可以使用用户UID的后2位数,来进行对应的分别存取的redis.也可以根据key取余也行。

优点:实现方法和代码全部自己掌控。可以随时进行调整。

缺点:需要手动迁移数据,

2、代理分片:类似MySQL Proxy。也要手动迁移

twemproxy 是一个为memcached和redis做的一个代理软件有一个缺点:对用户透明又不透明。很恐怖的一件事,因为我不知道我的资源存在哪里,要是是自己写的还可以用,况且这是别人写的,早期用的人还挺多,现在在生产环境中我们都要用了。

https://github.com/twitter/twemproxy

3、Codis 目前比较靠谱的 豌豆荚开发团队做的。

https://github.com/CodisLabs/codis

中文文档 https://github.com/CodisLabs/codis/blob/release3.2/doc/tutorial_zh.md

常问问题 https://github.com/CodisLabs/codis/blob/release3.2/doc/FAQ_zh.md

高可用性 https://github.com/CodisLabs/codis/blob/release3.2/doc/tutorial_zh.md#3-jodis-与-ha

4、Redis Cluster

是一个坑目前看看就好,问题太多了。

坑1,目前实现的客户端比较少,

坑2、主从明明正常,但是出现主错误,从库正常但是不切换。

http://redisdoc.com/topic/cluster-tutorial.html

Redis监控

课程 http://study.oldboyedu.com/classModule/video/214170/216843/779272/0/0

zabbix_linux_plugin.sh

[root@server-000 redis]# cat zabbix_linux_plugin.sh 
#!/bin/bash
############################################################
# $Name:         zabbix_linux_plugins.sh
# $Version:      v1.0
# $Function:     zabbix plugins
# $Author:       baojia chen
# $Create Date:  2014-08-10
# $Description:  Monitor Linux Service Status
############################################################
tcp_status_fun(){
	TCP_STAT=$1
	#netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,state[key]}' > /tmp/netstat.tmp
	ss -ant | awk 'NR>1 {++s[$1]} END {for(k in s) print k,s[k]}' > /tmp/netstat.tmp
	TCP_STAT_VALUE=$(grep "$TCP_STAT" /tmp/netstat.tmp | cut -d ' ' -f2)
	if [ -z $TCP_STAT_VALUE ];then
		TCP_STAT_VALUE=0
	fi
	echo $TCP_STAT_VALUE
}

nginx_status_fun(){
	NGINX_PORT=$1
	NGINX_COMMAND=$2
	nginx_active(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" 2>/dev/null| grep 'Active' | awk '{print $NF}'
        }
	nginx_reading(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" 2>/dev/null| grep 'Reading' | awk '{print $2}'
       }
	nginx_writing(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" 2>/dev/null| grep 'Writing' | awk '{print $4}'
       }
	nginx_waiting(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" 2>/dev/null| grep 'Waiting' | awk '{print $6}'
       }
	nginx_accepts(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" 2>/dev/null| awk NR==3 | awk '{print $1}'
       }
	nginx_handled(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" 2>/dev/null| awk NR==3 | awk '{print $2}'
       }
	nginx_requests(){
        /usr/bin/curl "http://127.0.0.1:"$NGINX_PORT"/nginx_status/" 2>/dev/null| awk NR==3 | awk '{print $3}'
       }
  	case $NGINX_COMMAND in
		active)
			nginx_active;
			;;
		reading)
			nginx_reading;
			;;
		writing)
			nginx_writing;
			;;
		waiting)
			nginx_waiting;
			;;
		accepts)
			nginx_accepts;
			;;
		handled)
			nginx_handled;
			;;
		requests)
			nginx_requests;
		esac 
}

memcached_status_fun(){
	M_PORT=$1
	M_COMMAND=$2
	echo -e "stats\nquit" | nc 127.0.0.1 "$M_PORT" | grep "STAT $M_COMMAND " | awk '{print $3}'
}

redis_status_fun(){
	R_PORT=$1
	R_COMMAND=$2
	(echo -en "INFO \r\n";sleep 1😉 | nc 127.0.0.1 "$R_PORT" > /tmp/redis_"$R_PORT".tmp
	REDIS_STAT_VALUE=$(grep ""$R_COMMAND":" /tmp/redis_"$R_PORT".tmp | cut -d ':' -f2)
 	echo $REDIS_STAT_VALUE	
}

main(){
	case $1 in
		tcp_status)
			tcp_status_fun $2;
			;;
		nginx_status)
			nginx_status_fun $2 $3;
			;;
		memcached_status)
			memcached_status_fun $2 $3;
			;;
		redis_status)
			redis_status_fun $2 $3;
			;;
		*)
			echo $"Usage: $0 {tcp_status key|memcached_status key|redis_status key|nginx_status key}"
	esac
}

main $1 $2 $3

如何设计一个电商购物车

1、基于大数据的假货 根据你购买客单价,根据地址(农村或者),根据你的评价,根据的你投诉率来计算你识别的概率有多大,你投诉的概率有多大,你退货的概率有多大。概率小就发假货,概率大就发真的。

1、需求是什么 用户把宝贝放入购物车,用户下一次访问的时候,购物车没有结算的宝贝还在。我们知道我需要记录下来

2、记录在哪里? 用户不登录购物车内容可以记录在 Cookie 。 用户登录后:购物车存放在 Redis。UID——xxx(之类的做一个key) value(就是你购物车的内容是hash的数据类型) 设置key的时候可以设置过期时间
redis可以持久化

Memcahced: 可以存储的

1、数据库读缓存。

2、Session。

负载均衡: Session处理有几种方式:

1、会话Session保持:Nginx可以做ip_hash cookie
        
        2、会话Session复制:把Session 复制到每台RS上, Tomcat Cluster。缺点复制要产生开销
        
        3、会话Session共享:比如放在memcached,优点:语言支持多,简单,高效,所有开发人员都会。PHP php.ini 直接配置session存储位置就可以使用。tomcat(memcached) session manager.

不同的业务的场景使用不同的application。

技术在公司的位置

IT管理三大因素:PPT

1、P 人员

2、Process 组织结构/流程

3、Tools 工具/技术

架构师要符合企业实际情况的,没有所谓的最佳实践,存在即是有道理。

!!!千万不要嘲笑别人的架构,有可能这就是最合理的。

用东西要用自己最熟悉的,但是也要考虑公司业务场景和人员。

资料参考

http://redisdoc.com/ Redis 命令参考

http://redis.cn/ Redis 中文官网

打赏作者

Has one comment to “分布式缓存—redis”

You can leave a reply or Trackback this post.
  1. laft - 2017年9月30日 回复

    +1

Leave a Reply

Your email address will not be published.