学习Redis(一)

一、NoSQL

1、NoSql介绍

1、not only SQL,非关系型数据库,它能解决常规数据库的并发、IO与性能的瓶颈
2、解决以下问题:
① 对数据库的高并发读写需求
② 大数据的高效存储和访问需求
③ 高可扩展性和高可用性的需求

2、Nosql数据库的应用环境

1) 数据模型比较简单
2) 需要灵活性更强的IT系统
3) 对数据库的性能要求较高
4) 不需要高度数据一致性
5) 对于给定KEY,比较容易映射复杂值的环境

3、Nosql软件的分类与特点

1、key-value键值存储数据库
1) 介绍
① 键值对存储,可通过key来添加、查询、删除数据
② 用于内容缓存,适合负载并扩展大的数据集
③ 数据类型是一系列的键值对
④ 有快速查询功能,但存储数据少结构化
⑤ 对事务的支持不好,数据库故障产生时不可进行回滚
2) 常见数据库产品
redis、memcached、ttserver   
3) 应用场景
存储用户信息,如会话、配置文件、参数、购物车、计数(统计粉丝关注)等

2、列存储数据库     
1) 介绍
① 查询多个列
② 用于分布式的文件系统
③ 以列簇式存储,将同一列数据存在一起
④ 查找速度快,可扩展强,更容易进行分布式扩展
⑤ 功能相对局限
2) 常见数据库产品
HBase
3) 适用场景
日志(将信息写入自己的column family中)
blog平台(存储到不同的column family中,如标签、类别、文章等)

3、面向文件的数据库 
1) 介绍
① 版本化的文档,半结构化的文档
② 用于WEB应用较多
③ 数据类型是一系列键值对
④ 查询性能不高,没有统一的查询语法
2) 常见数据库产品
mongoDB
3) 适用场景
日志(程序有不同的日志)
无固定的模式,存储不同的信息
分析(不改变模式,就可存储不同的度量方法,及添加新的度量)

4、图形数据库 
1) 介绍
① 数据已图的方式存储
② 社交网络应用较多
③ 不容易做分布式的集群方案
2) 常见数据库产品
Graph
3) 适用场景
在关系型强的数据中,推荐引擎,社交网络,推荐系统等

4、常用的Nosql数据库介绍

1、memcached
1) 介绍
一个开源高性能的,具有分布式内存对象的缓存系统
2) 特点
① 安装布署简单
② 支持高并发、高性能
③ 通过程序或负载均衡可以实现分布式
④ 仅为内存缓存,重启服务数据丢失

2、memcacheDB
1) 介绍
新浪基于memcached开发的一个开源项目,具备了事务恢复功能
2) 特点
① 高并发读写
② 高效存储
③ 高可用数据存储

3、ttserver(tokyo tyrant/tokyocabinet)
1) 介绍
日本开发的DBM数据库,读写非常快,是BDB的几倍
2) 特点
① 支持内存缓存,可持久化存储
② 故障转移,tokyo tyrant支持主从模式,双机互为主从模式,主从库均可读写
③ 5千万条数据,级别内的访问相当快
④ 兼容memcached协议,客户端不需更改任何代码

4、mongoDB(document-oriented)
1) 介绍
一个基于分布式文件存储的数据库,由C++语言编写
2) 特点
易部署、高性能、易使用、存储数据非常方便

5、redis(key-value)
1) 介绍
用ANSIC语言编写(代码3W多行),基于内存及持久化日志型、Key-Value数据库,提供多种语言的API
2) 特点
① 支持内存缓存,相当于memcached
② 持久化,相当于memcachedb,ttserver
③ 数据类型更丰富
④ 支持集群,分布式

5、生产环境如何选择Nosql数据库

1、最常规的缓存应用,memcached最合适
2、持久化存储方案,用memcacheDB
3、2000万以内数据量的小数据,用memcached
4、大数据量,用redis

二、redis

1、redis网站

http://www.redis.cn/
http://www.redis.io/topics/introduction

2、redis特点

1、key-value键值类型存储
2、支持数据可靠存储
3、单进程单线程高性能服务器
4、恢复比较慢
5、单机qps(秒并发)可以达到10W
6、适合小数据量高速读写访问

3、redis持久化

1、介绍
redis将数据存储内存中,通过快照、日志两种方式实现持久化存储

2、持久化对比 snapshot(快照): 一次性将内存中的数据写入到磁盘,会导致数据的丢失 aof : 类似MySQL的binlog日志,记录每次更新的日志,不用于主从同步,仅能保存数据
3、配置文件对比 Snapshot(快照) save 900 1 #900秒有1个key,则触发快照写入磁盘 save 300 10 save 60 10000 AOF(更新日志) appendfsync always #总是记录更新内容 appendfsync everysec #每秒记录更新内容 appendfsync no #不记录更新内容

4、 redis的数据类型

String          字符串
Hash            哈希表
List            列表
Set             集合
Sorted set      有序集合

5、redis应用场景

1、计数器、好友关系、cache服务
2、微博(评论、转发、阅读、赞等),用户(粉丝、关注、收藏等)
3、用户最近访问记录、最热,点击率最高,活跃度最高的视频或帖子

6、redis的生产经验

1、要配置主从同步,在出现故障时可以切换
2、master禁用持久化,slave配置数据持久化
3、物理内存 + 虚拟内存不足,这时dump一直死着,时间久了机器会挂掉
4、当redis物理内存,使用超过内存总容量的3/5时,就开始做swap,比较危险,内存碎片大
5、当达到最大内存时,会清空带有过期时间的key,即使key未到过期时间
6、redis与db同步写的问题,先写db,后写redis

三、redis部署

 1、安装redis

# wget http://download.redis.io/releases/redis-2.8.24.tar.gz
# tar zxf redis-2.8.24.tar.gz
# cd redis-2.8.24
# make
# make PREFIX=/application/redis-2.8.24 install

2、相关命令

redis-server                                            #服务器命令
redis-cli                                               #客户端命令,也可以用telnet连接
redis-benchmark                                         #性能测试工具,测试读写性能
redis-check-aof                                         #检查aof日志文件
redis-check-dump                                        #检查本地rdb快照文件

3、启动服务

1、查看命令帮助
# redis-server -h

2、复制配置文件
# cp  redis-2.8.24/redis.conf   /application/redis/conf/

3、启动服务
# redis-server /application/redis/conf/redis.conf 

4、关闭服务
# redis-cli   shutdown
# redis-cli   shutdown save

5、警告处理
1) 参数说明(vm.overcommit_memory)
  0: 应用请求更多内存时,内核检查是否有足够的内存,若有,分配应用,若无,不分配,返回错误给应用
  1: 内核允许分配所有的内存,不管内存状态(主要用于科学计算)
  2: 内核绝不过量使用内存,即系统整个内存不能超过swap+50%的RAM值,50%在overcommit_ratio中设定
2) 永久生效
# echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf
# sysctl -p 
3) 临时生效
# sysctl vm.overcommit_memory=1
# echo '1' > /proc/sys/vm/overcommit_memory

4、相关命令

# redis-cli                                             #连接本地redis
6379> set id 001                                        #设置key和value
6379> get id                                            #取key的值
6379> del id                                            #删除key
6379> exists id                                         #验证key是否存在
6379> keys *                                            #查看所有的key
6379> select 1                                          #切换到库1模式(默认有16个库,可在配置文件设置)

5、redis远程连接和非交互式操作 

1、远程连接
# redis-cli -h 10.0.0.135 -p 6379

2、远程连接并执行命令
# redis-cli -h 10.0.0.135 -p 6379 set aaa 111
# redis-cli -h 10.0.0.135 -p 6379 get aaa

3、其他命令连接方式
# telnet 10.0.0.135 6379
# echo "set no004 zsq" |nc 127.0.0.1 6379
# echo "get no004 "    |nc 127.0.0.1 6379

6、redis命令帮助 

1、客户端命令帮助:
6379> ?                                                 #查看帮助命令用法
6379> help                                              #查看帮助命令用法
6379> help set                                          #查看set命令用法

2、通过help命令来查找命令
6379> help @generic                                     #需要多次按Tab键
      help + 空格 + 多次<Tab>键来切换所有命令

7、redis安全

1、设置密码      
redis没有用户概念,1秒可尝试上万次的密码登陆,要设置复杂的密码,来防止暴力破解
1) 方法一:
# vim  redis.conf
  requirepass  "123456"                                 #设置密码
2) 方法二:
# redis-cli 
6379> config set requirepass 123456
6379> config rewrite
3) 登陆方法一:
# redis-cli 
6379> auth 123456      
4) 登陆方法二:
# redis-cli -a 123456    

2、屏蔽危险命令(命令改名)
# vim redis.conf
  rename-command set "sset"                             #将set修改为sset 
  rename-command keys ""                                #屏蔽掉keys命令

 8、安装redis客户端(php环境) 

1、获取源码包
# wget https://github.com/nicolasff/phpredis/archive/master.zip

2、安装
# unzip    phpredis-master.zip
# cd       phpredis-master
# /application/php/bin/phpize
# ./configure --with-php-config=/application/php/bin/php-config
# make && make install

3、检查
# ls /application/php-5.6.8/lib/php/extensions/no-debug-non-zts-20131226/
  memcache.so  opcache.a  opcache.so  redis.so

4、修改设置
# vim /application/php/lib/php.ini
  extension = redis.so 
  extension_dir = "/application/php-5.6.8/lib/php/extensions/no-debug-non-zts-20131226/" 

5、重启php
# killall php-fpm 
# /application/php/sbin/php-fpm

6、php操作redis
# cat redis.php 
  <?php
     $redis = new Redis();
     $redis ->connect('10.0.0.135',6379);
     $redis ->auth('123456');
     $redis ->set('name','zhang3');
     $var = $redis ->get('name');
     echo "$var\n";
  ?>

  9、安装redis客户端(Python)

1、安装
# wget https://pypi.python.org/packages/source/r/redis/redis-2.10.1.tar.gz
# tar xf redis-2.10.1.tar.gz
# cd redis-2.10.1
# python setup.py install

2、python操作redis
# python
>>> import redis                                        #导入redis库
>>> r = redis.Redis(host='10.0.0.135',port='6379',password='123456') #连接redis(面向对象)
>>> r.set('name','benet')                               #写入数据
>>> r.get('name')                                       #读取数据
>>> r.dbsize()                                          #查看数据数
>>> r.keys()                                            #查看所有的key
>>> exit()                                              #退出

3、Web界面Python连接Redis
1) 编写脚本
# cat python-redis.py 
  #/usr/bin/python
  from wsgiref.simple_server import make_server
  import redis

  def get_redis():
      r = redis.Redis(host='10.0.0.135',port='6379',password='123456',db=0)
      r.set('name','zhang3')
      return r.get('name')
      
  def hello_world_app(environ,start_response):
      status = '200 OK'   
      headers = [('Content-type','text/plain')]   
      start_response(status,headers)
    
      return get_redis()

  httpd = make_server('',8000,hello_world_app)
  print "Serving on port 8000..."

  httpd.serve_forever()
2) 启动python脚本
# python python-redis.py
3) 访问
http://127.0.0.1:8000

10、解读redis配置文件 

# vim redis.conf
  include /path/to/local.conf                           #redis支持include功能
  daemonize no                                          #是否后台运行
  pidfile /var/run/redis.pid                            #pid文件的位置
  port 6379                                             #监听端口
  tcp-backlog 511                                       #tcp监听队列
  bind 10.0.0.135                                       #监听地址
  timeout 0                                             #客户端超时时间
  tcp-keepalive 0                                       #tcp的会话保持时间
  loglevel notice                                       #日志级别
  logfile ""                                            #日志记录位置,默认打印到屏幕上
  syslog-facility local0                                #是否启用syslog接收日志(日志集中收集)
  databases 16                                          #库的数量(默认为0到15)
  save  ""                                              #不保存快照
  save 900 1                                            #900秒有1个key,触发快照
  save 300 10                                           #300秒有10个key,触发快照
  save 60 10000                                         #60秒有10000个key,触发快照
  stop-writes-on-bgsave-error yes                       #bgsave出错是否停止写入
  dbfilename dump.rdb                                   #持久化文件名
  dir ./                                                #持久化文件位置(默认当前路径)
  rdbcompression no                                     #是否压缩rdb文件,会消耗cpu
  rdbchecksum yes                                       #检查rdb数据
  requirepass 123456                                    #redis的密码
  rename-command CONFIG ""                              #屏蔽命令
  rename=command get wk                                 #命令改名
  maxmemory 2G                                          #限制redis内存
  maxmemory-policy volatile-lru                         #内存清理的算法
  appendonly no                                         #是否启用AOF持久化
  appendfilename "appendonly.aof"                       #AOF文件名
  appendfsync everysec                                  #每秒记录
  auto-aof-rewrite-percentage 100                       #自动重写(rewrite)的百分比
  auto-aof-rewrite-min-size 64mb                        #自动重写(rewrite)aof的文件大小
  lua-time-limit 5000                                   #lua脚本最大运行时间
  hash-max-ziplist-entries 512                          #hash优化参数(数量512以下,数据压缩)
  hash-max-ziplist-value 64                             #hash优化参数(长度小于64字节,数据压缩)
  slaveof 10.0.0.135 6379                               #设置主从复制
  masterauth 123456                                     #主库密码
  requirepass 123456                                    #本身密码
  maxclients 128                                        #最大连接数
  vm-enabled no                                         #是否启用虚拟内存
  vm-swap-file /tmp/redis.swap                          #虚拟内存文件路径
  vm-max-memory 0                                       #所有大于vm-max-memory的数据,存入虚拟内存
  vm-page-size 32                                       #虚拟内存数据页的大小
  vm-pages 134217728                                    #虚拟内存数据页的数量
  vm-max-threads 4                                      #访问虚拟内存文件的线程数
  glueoutputbuf yes                                     #应答客户端时,是否合并较小的包
  activerehashing yes                                   #是否激活重置哈希

 四、redis数据类型

1、String (字符串)

1、介绍
string类型是二进制,很安全的,一个key对应一个value,包含任何数据,但值的长度不能超过1GB
key: 长度10到20
value: 不要超过2k

2、字符串对数字的加减
6379> set id 1                                          #设置key是id,值是1
6379> get id                                            #查看key
6379> incr id                                           #自增1
6379> incrby id 5                                       #自增指定数    
6379> decr id                                           #自减1
6379> decrby id 5                                       #自减指定数   

3、其他操作
6379> getset user01 wangwu                              #设置新数据并返回旧数据
6379> get user01                                        #查看key的值
6379> mset name zhangsan age 44                         #设置多个key
6379> mget name age                                     #查看多个key的值
6379> append  images .jpg                               #追加字符串
6379> strlen  images                                    #计算字符串长度
6379> substr  images 0 6                                #取0到6的值
6379> help set                                          #查看单个命令帮助
6379> help @string                                      #查看字符串所有命令的帮助

 2、List(列表)

list是简单的字符串列表,按照插入顺序排序,可实现聊天系统和消息的队列
6379> help @list                                        #列表帮助
6379> lpush   students "zhang3"                         #插入元素到列表的最左边
6379> lrange  students 0 1                              #查看列表0到1元素的值
6379> rpush   students "wang5"                          #将插入元素到列表的最右边
6379> llen    students                                  #查看列表元素的个数
6379> lpop    students                                  #移除最左边的元素值
6379> rpop    students                                  #移除最右边的元素值
6379> lrem    students 2 "zhangsan"                     #删除两次指定的元素(从左向右删)
6379> lrem    students 1 "zhangsan"                     #删除一次指定的元素
6379> lrem    students 0 "zhangsan"                     #清空所有指定的元素
6379> linsert students before b xxxx                    #在元素b的前边插入新元素
6379> linsert students after b xxxx                     #在元素b的后边插入新元素

3、集合(Sets)类型

1、Set(无序集合)
集合通过哈希表实现的,集合内的元素具有唯一性
6379> help @set                                         #无序集合帮助
6379> sadd users laoda                                  #添加一个元素
6379> sadd users laoer laosan                           #添加两个元素
6379> smembers  users                                   #查看集合里的所有元素(集合里的元素是无序的)
6379> sismember users laoda                             #查看元素是否在集合中

2、zset(有序集合)
6379> help @sorted_set                                  #有序集合帮助
6379> ZADD days 0 mon                                   #days:有序集合名,0:序号,mon:值
6379> zrange days 0 6                                   #查看集合0到6元素的值(正序)
6379> zrevrange days 0 -1                               #查看集合所有元素的值(倒序)
6379> zscore days mon                                   #查看集合里值的排序
6379> zrangebyscore days -inf 8                         #查看负无穷到5之间元素的值(区间查询)
6379> zremrangebyscore days 1 7                         #删除1到7之间的元素(删除之间的元素) 

4、Hash类型

哈希可存储多个属性的数据(如user,name passwd)
6379> hset k1 name zhang3 age 23                        #k1:哈希名,name:属性1,age:属性1
6379> hvals k1                                          #查看所有属性
6379> hgetall k1                                        #查看所有属性和值

五、redis多实例

 1、创建多实例目录和配置文件

1、创建redis多实例目录
# mkdir -p /data/redis/638{0..1}/{conf,logs,pid}

2、创建redis多实例配置文件
# cp redis.conf /data/6380/conf/redis_6380.conf   
# cp redis.conf /data/6381/conf/redis_6381.conf 
# vim  redis_6380.conf 
  bind 10.0.0.135
  port 6380
  daemonize yes
  dir /data/redis/6380/     
  pidfile /data/6380/redis_6380.pid
  logfile /data/6380/logs/redis_6380.log
  dbfilename redis_6380.rdb
  appendonly yes
  appendfilename redis.aof
# sed -i 's#6380#6381#g' /data/6381/conf/redis_6381.conf  

2、启动redis多实例

1、启动
# redis-server /data/redis/6380/conf/redis_6380.conf
# redis-server /data/redis/6381/conf/redis_6381.conf

2、查看端口和进程
# netstat -antup | grep redis
# ps -ef | grep redis

 六、 Redis主从同步

1、Redis主从同步特点

1、一个master可以拥有多个slave
2、多个slave可以连接同一个master,还可以连接到其他slave
3、主从复制不会阻塞master,在同步数据时,master可以继续处理客户端的请求
4、提高系统的伸缩性

2、Redis主从同步的过程

1、Slave连接到Master服务器
2、Slave发送SYNC命令
3、Master备份数据到rdb文件
4、Master把rdb文件传输给Slave
5、Slave把rdb文件导入到数据库中

3、Redis的主从同步的应用

1、一个master可有多个slave,一个slave还可以有多个slave
2、主从同步不会阻塞master,但是会阻塞slave(初次同步数据,会阻塞客户端的请求)
3、主从同步提高系统的伸缩,用多个slave处理客户端的读请求
4)master不做持久化,在slave上做,可提高集群的性能,也可在slave上做数据的备份
5)对于老版本的redis,每次重连都会重新发送所有数据

4、配置主从同步

1、方法1(临时生效)

# redis-cli slaveof 10.0.0.135 6380                     #启动主从同步
# redis-cli slaveof no one                              #停止主从同步

2、方法2(永久生效)
# vim redis_6381.conf  
  slaveof 10.0.0.135 6380                               #主库的IP和端口
  masterauth 123456                                     #主库的密码

5、同步过程

* Connecting to MASTER 192.168.0.135:6379                      #连接master
* MASTER <-> SLAVE sync started                                #开始发送sync
* Non blocking connect for SYNC fired the event.               #这是一个不阻塞事件
* Master replied to PING, replication can continue...          #master应答了ping,同步开始
* Partial resynchronization not possible (no cached master)    #部分重新同步不可能(master无缓存内容)
* Full resync from master:                                     #从master同步全部数据 
* MASTER <-> SLAVE sync: receiving 49 bytes from master        #从master接收到49字节数据
* MASTER <-> SLAVE sync: Flushing old data                     #刷新旧数据
* MASTER <-> SLAVE sync: Loading DB in memory                  #数据放到内存
* MASTER <-> SLAVE sync: Finished with success                 #同步完成
* Background append only file rewriting started by pid 3620    #AOF重写
* Background AOF rewrite terminated with success               #AOF重写成功
* Background AOF rewrite finished successfully                 #AOF重写完毕
  

6、主从相关参数

1、主从同步测试
# redis-cli -a 123456 -p 6381 monitor                   #监听主服务写入操作
# redis-cli -a 123456 -p 6380 get name                  #查看key
# redis-cli -a 123456 -p 6380 set name tom              #设置一个key和value

2、主从同步相关参数
slave-serve-stale-data yes                              #yes:从不能连接主,从可正常提供服务,数据是旧的,no:不提供服务,返回错误信息
slave-read-only yes                                     #设置从库只读模式
repl-ping-slave-period 10                               #每10秒发送ping到master
repl-backlog-size 1mb                                   #backlog大小(主通过backlog实现从的增量同步)
repl-backlog-ttl 3600                                   #主从断开时,backlog的生存周期   
slave-priority 100                                      #slave的优先级

3、查看redis各项参数的方法
6379> info                                              #查看所有的信息
6379> info cpu                                          #查看CPU的信息
6379> info clients                                      #查看客户端信息
6379> info replication                                  #查看同步信息
  role:master                                           #角色是主
  connected_slaves:1                                    #连接从的数量
  slave0:ip="",port="",state=online,offset=11972,lag=1  #从库ip,端口,状态,偏移量等

七、redis的高级特性

1、redis的订阅功能

1、介绍
pub(发布)/sub(订阅)是一种消息通信模式,主要目的解耦发布者和订阅者之间的耦合
redis可将数据推到消息队列中,其它人可通过队列获取消息

2、开启的订阅功能
6379> subscribe first                                   #开启并订阅频道(一个窗口)
6379> subscribe first second                            #可订阅多个频道

3、对频道推送                             
6379> publish first 'welcome'                           #向频道推送
6379> (integer) 2                                       #推送成功的人数(只要推送端推送,订阅端就能看到)
6379> help @pubsub                                      #更多获取帮助

2、redis数据过期设置及过期机制

1、过期机制
1) 定时删除
设置key的过期时间的同时,创建一个定时器,到期时触发,对key删除
2) 惰性删除
key过期不删除,每次访问时检查是否过期,若过期,则删除key,并返回空(null)
3) 定期删除
每隔一段时间,检查有过期时间的key,删除已过期的key

2、过期设置
6379> expire name 5                                     #设置key5秒后过期
6379> TTL name                                          #查看key过期时间(-1:永不过期,-2:已过期)
6379> get name                                          #过期后的key,无法获取value的
6379> help @generic 

3、事务性

1、组合型的命令
redis支持简单的组合型的命令,例如以nx结尾的命令,key不存在时,为key设置指定的值
6379> exists name                                       #查询key是否存在  
6379> setnx name tom                                    #当key不存在时,设置key的值
6379> setnx name zhang3                                 #当key存在时,不执行任何操作
6379> get name                                          #没有被覆盖

2、事务
6379> set name tom                                      #设置一个key
6379> get name                                          #查看key的值
6379> multi                                             #开始一个事务
6379> set name a                                        #当事务中有错误时,将都不执行
6379> set name b                                        
6379> exec                                              #提交事务(discard:取消事务)

 4、redis持久化

1、快照(Snapshotting)
1) 介绍
将内存中数据,以快照的方式写入到文件中,redis宕机会丢失最后一次快照的数据
2) 配置
方法一
# vim redis.conf
  dir /data/redis/                                      #rdb存储的路径
  dbfilename dump.rdb                                   #rdb文件名
  save 900 1                                            #900秒内1个key被修改,触发快照
  save 300 10                                           #300秒内10个key被修改,触发快照
  save 60  10000                                        60秒内10000个key被修改,触发快照
  rdbcompression no                                     #关闭rdb压缩,影响cpu
  save ""                                               #关闭rdb
方法二
6379> redis-cli config set save "180 1 120 10 60 10000" #开启rdb
6379> redis-cli config rewrite                          #配置保存到文件    
6379> redis-cli config set save ""                      #关闭rdb
3) 快照原理
① redis调用fork,产生一个子进程
② 父进程处理client请求,子进程将内存内容写入到临时文件,由于Linux的写时复制机制,子进程的数据是fork时的一个快照
③ 当子进程将快照写入临时文件后,把临时文件替换快照文件,然后子进程退出
4) 命令快照
save: 主线程保存快照,会阻塞所有client请求(不推荐)
bgsave: 开启一个子进程保存快照,不会阻塞客户端请求(推荐)
5) 其他
每次快照都是将内存数据完整写入到磁盘,如果数据量大,写操作多,会引起大量的磁盘io,严重影响性能
redis关闭时,会自动后台保存并退出,启动时,会读取RDB文件,若找不到RDB文件,则认为数据丢失

2、aof(日志方式)
1) 介绍
redis将收到的写操作,通过write函数追加到文件中,类似MySQL的binlog日志方式
2) 配置
# vim redis.conf
  appendonly yes                                            #启用aof
3) aof文件更新策略
  appendfsync always                                        #收到写命令就立即写入磁盘,最慢,但数据不会丢失
  appendfsync everysec                                      #默认方式,每秒写入磁盘一次,会丢失前1秒的数据
  appendfsync no                                            #完全依赖os,性能最好,数据会丢失
4) aof文件的自动重写
  auto-aof-rewrite-percentage 100                           #当aof文件增长比例100%时,触发自动重写
  auto-aof-rewrite-min-size 64mb                            #当aof文件大小到64m,触发自动重写
6379> bgrewriteaof                                          #手动触发自动重写
5) aof保存过程
① redis调用fork,产生一个子进程
② 子进程会根据内存中的快照,往临时文件中写人数据变化的命令
③ 父进程处理client请求,并把收到的写操作缓存
④ 当子进程把快照内容写完后,发信号通知父进程,父进程把缓存的写命令,写入到临时文件中
⑤ 父进程用临时文件,替换老的aof文件,并重命名,后面收到的写命令,往新的aof文件中追加
备注: 重写aof文件,并没有读取旧的aof文件,而是重写一个新的aof文件,当redis启动会加载aof文件,用命令重建整个数据库

八、redis的优化

1、常用命令
6379> flushdb                                           #清空当前库的数据
6379> flushall                                          #清空所有库的数据
6379> config get *                                      #查看当前配置信息
6379> config set appendonly yes                         #在线修改
# redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 10000  #100个并发,一万次请求

2、系统参数优化
1) 系统文件描述符
# echo "* - nofile 10240" >> /etc/security/limits.conf 
# bash && ulimit -n 
2) TCP连接数
# echo "net.core.somaxconn = 10240" >> /etc/sysctl.conf
# sysctl -p
3) 系统内存分配策略
# echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf 
# sysctl -p
4) 关闭系统大页内存
# echo never > /sys/kernel/mm/transparent_hugepage/enabled 
# echo never > /sys/kernel/mm/transparent_hugepage/defrag 

3、内存清理算法
volatile-lru                                            #LRU算法删除过期的key
volatile-random                                         #随机删除过期的key
volatile-ttl                                            #删除即将过期的key
allkeys-lru                                             #LRU算法删除所有key
allkeys-random                                          #随机删除所有key
noeviction                                              #不删除key,只返回错误
6379> config get maxmemory-policy                   #查看内存清理算法
6379> config get maxmemory-policy volatile-lru          #设置内存清理算法

4、内存优化
hash-max-zipmap-entries 64                              #hash的最大元素数,当超过时,采用特殊hash算法
hash-max-zipmap-value 512                               #hash的最大元素值,当超过时,采用特殊hash算法
list-max-ziplist-value 64                               #列表的最大元素值,当超过时,采用压缩列表
list-max-ziplist-entries 512                            #列表的最大元素数,当超过时,采用压缩列表
set-max-intset-entries 512                              #限制集合中member个数,超出则不采取intset存储
activerehashing yes                                     #是否激活重置哈希

5、redis优化总结
① 根据业务需要,选择合适的数据类型,并为不同的应用场景,设置相应的紧凑存储参数
② 当业务场景不需要数据持久化时,关闭持久化,可获得最佳的性能和最大的内存使用量
③ 若使用持久化,根据是否容忍丢失部分数据,选择持久化方式,不要用虚拟内存vm及disk store方式,每秒实时写入AOF文件
④ 尽量不要让redis的内存,超过总内存的60%
⑤ 设置参数maxmemory,限制redis不会过多,使用物理内存而导致swap,设置参数vm-enabled no(不用虚拟内存)
⑥ 大数据量尽量按业务,用多个redis instance把数据分散开


6、批量插入数据
for i in `seq -w 50`;do redis-cli set name_$i value_$i;done

九、redis的状态信息

1、服务器的信息
# Server                             
redis_version:4.0.10                                #redis服务器版本
redis_mode:standalone                               #运行模式(单机或集群) 
multiplexing_api:epoll                              #使用的事件处理模型
uptime_in_days:0                                    #服务器启动总时间,单位是天
hz:10                                               #redis内部调度(关闭timeout客户端,删除过期key)
lru_clock:8197344                                   #自增时间,用于LRU管理
       
2、客户端信息    
# Clients      
connected_clients:1                                 #当前客户端连接数(不包括slave的连接)
blocked_clients:0                                   #被阻塞的客户端数
       
3、内存信息
# Memory                          
used_memory:2995728                                 #已用的内存,单位为字节(byte)
used_memory_human:2.86M                             #易读方式显示
used_memory_rss:4636672                             #系统给redis分配的内存(和top、ps显示的一致)
used_memory_rss_human:4.42M                         #易读方式显示
used_memory_peak:15517016                           #内存使用的峰值大小
used_memory_peak_human:14.80M                       #易读方式显示
used_memory_peak_perc:19.31%                        #峰值内存超出分配内存(used_memory)的百分比
used_memory_startup:786608                          #Redis启动时的初始内存
total_system_memory:2229866496                      #系统内存总量
total_system_memory_human:2.08G                     #易读方式显示
used_memory_lua:37888                               #lua引擎使用的内存
used_memory_lua_human:37.00K                        #易读方式显示
maxmemory:0                                         #最大内存(0不限制)
maxmemory_human:0B                                  #易读方式显示
mem_fragmentation_ratio:1.55                        #内存碎片率(used_memory_rss和used_memory的比率,小于1:使用swap,大于1:碎片多,增删操作增加碎片)
mem_allocator:jemalloc-4.0.3                        #内存分配器

4、持久化信息
# Persistence                                   
loading:0                                           #是否正在加载持久化文件
rdb_changes_since_last_save:0                       #自上次rdb后,数据的改动
rdb_bgsave_in_progress:0                            #bgsave是否操作
rdb_last_save_time:1534918159                       #上次bgsave的时间戳
rdb_last_bgsave_status:ok                           #上次bgsave的状态
rdb_last_bgsave_time_sec:0                          #上次bgsave的使用的时间
rdb_current_bgsave_time_sec:-1                      #当前bgsave已耗费的时间(如果有)
rdb_last_cow_size:438272                            #上次rbd写时复制分配的字节大小
aof_enabled:1                                       #是否开启AOF
aof_rewrite_in_progress:0                       #AOF是否正在自动重写(rewrite)
aof_rewrite_scheduled:0                             #是否要在rdb的bgsave结束后执行rewrite
aof_last_rewrite_time_sec:1                         #上次rewrite使用的时间(单位s)
aof_current_rewrite_time_sec:-1                     #当前rewrite已耗费的时间(如果有)
aof_last_bgrewrite_status:ok                        #上次bgrewrite的状态
aof_last_write_status:ok                            #上次AOF文件写入状态
aof_last_cow_size:581632                            #上次重写写时复制分配的字节大小
aof_current_size:2634673                            #AOF当前大小
aof_base_size:2473591                               #AOF上次启动或rewrite的大小
aof_pending_rewrite:0                               #同上面的aof_rewrite_scheduled
aof_buffer_length:0                                 #AOF buffer的大小
aof_rewrite_buffer_length:0                         #AOF rewrite buffer的大小
aof_pending_bio_fsync:0                             #后台IO队列中等待fsync执行的个数
aof_delayed_fsync:0                                 #被延迟fsync调用数量
  
5、统计信息
# Stats                          
total_connections_received:220209                   #连接过的客户端总数
total_commands_processed:447805                     #执行过的命令总数
instantaneous_ops_per_sec:0                         #每秒处理命令数
total_net_input_bytes:13682780                      #输入网络流量总数
total_net_output_bytes:10737650                     #输出网络流量总数
instantaneous_input_kbps:0.02                       #网络读取速率
instantaneous_output_kbps:0.00                      #网络写入速率
rejected_connections:0                              #拒绝的连接个数(已达到maxclients限制)
sync_full:1                                         #主从完全同步成功次数
sync_partial_ok:0                                   #主从部分同步成功次数
sync_partial_err:1                                  #主从部分同步失败次数
expired_keys:0                                      #过期key的数量
evicted_keys:0                                      #剔除(超过maxmemory)的key的数量
keyspace_hits:0                                     #命中key次数
keyspace_misses:0                                   #没命中key次数
pubsub_channels:0                                   #当前使用中的频道数量
pubsub_patterns:0                                   #当前使用中的模式数量
latest_fork_usec:401                                #上次fork消耗的时间

6、主从信息
# Replication                
role:master                                         #角色(主从)
connected_slaves:1                                  #连接的从库数量
slave0:ip="",port="",state=online,offset=123,lag=0  #从库信息
master_replid:2757c33a                              #复制ID
master_replid2:0000000                              #第二个复制ID(用于failover的PSYNC)
master_repl_offset:7672755                          #主从同步偏移量
repl_backlog_active:1                               #复制缓冲区的状态
repl_backlog_size:1048576                           #复制缓冲区的大小
repl_backlog_first_byte_offset:6624180              #复制缓冲区的主偏移量
repl_backlog_histlen:1048576                        #复制缓冲区数据的大小

7、cpu信息
# CPU
used_cpu_sys:23.63                                  #主进程内核态消耗cpu的时间
used_cpu_user:13.16                                 #主进程用户态消耗cpu的时间
used_cpu_sys_children:0.31                          #子进程内核态消耗cpu的时间
used_cpu_user_children:0.14                         #子进程用户态消耗cpu的时间

8、集群信息
# Cluster              
cluster_enabled:0                                   #集群未开启

9、数据库的键值信息
# Keyspace           
db0:keys=1,expires=0,avg_ttl=0                      #key总数,带有过期时间的key的总数,平均存活时间

 十、redis的高可用(哨兵+vip)

1、环境

            redis-server             sentinel(哨兵)
主节点     192.168.1.11:8000       192.168.1.11:7000
从节点     192.168.1.12:8000       192.168.1.12:7000
从节点     192.168.1.13:8000       192.168.1.13:7000

2、配置主从复制(sentinel基于主从)

1、创建master配置文件(主节点)
# vim redis.conf
  port 8000            
  daemonize yes         
  bind 0.0.0.0          
  pidfile /var/run/redis-8000.pid    
  logfile /var/log/redis/redis-8000.log    
  requirepass 123456

2、创建slave配置文件(2个从节点)
# vim redis.conf
  port 8000
  daemonize yes
  bind 0.0.0.0
  pidfile /var/run/redis-8000.pid
  logfile /var/log/redis/redis-8000.log
  slaveof 192.168.1.11 8000      
  masterauth 123456        

3、启动redis(所有节点)
# redis-server  redis.conf

3、安装部署redis-sentinel(所有节点)

1、创建sentinel配置文件
# vim sentinel.conf
  port 7000                    
  sentinel monitor mymaster 192.168.1.11 8000 2         #监控,别名,主库ip和端口,投票数2
  sentinel down-after-milliseconds mymaster 5000        #主库宕机5秒,切库
  sentinel parallel-syncs mymaster 1                    #切库后,向主库同步数据的个数,1:轮询,2:并发
  sentinel failover-timeout mymaster 15000              #故障转移的超时时间
  sentinel auth-pass mymaster 123456                    #主库密码

2、启动sentinel
# redis-sentinel sentinel.conf

3、查看sentinel信息
# redis-cli -h 192.168.1.11 -p 7000 info sentinel 

4、部署redis-sentinel的VIP

1、修改配置文件(所有节点)
# vim sentinel.conf
  port 7000                    
  sentinel monitor mymaster 192.168.1.11 8000 2         
  sentinel down-after-milliseconds mymaster 5000       
  sentinel parallel-syncs mymaster 1                    
  sentinel failover-timeout mymaster 15000              
  sentinel auth-pass mymaster 123456                   
  sentinel client-reconfig-script mymaster /data/redis/redis_vip.sh

2、编写vip脚本(所有节点)
  sentinel在failover的时会执行client-reconfig-script脚本,
  并传递6个参数(<master-name>,<role>,<state>,<from-ip>,<from-port>,<to-ip>,<to-port>)
# vim /data/redis/redis_vip.sh
  #!/bin/bash
  MASTER_IP=$6                                          #传第六个参数(新master的IP==<to-ip>)
  LOCAL_IP="192.168.1.12"                               #本地IP
  VIP="192.168.1.20"                                    #VIP
  NETMASK="24"              
  INTERFACE="eth0"             
  if [[ "${MASTER_IP}" == "${LOCAL_IP}" ]];then
      /usr/sbin/ip addr add ${VIP}/${NETMASK} dev ${INTERFACE}
          /usr/sbin/arping -q -c 3 -A ${VIP} -I ${INTERFACE}
          exit 0
  else
          /usr/sbin/ip addr del ${VIP}/${NETMASK} dev ${INTERFACE}
      exit 0
  fi
  exit 1
# chmod +x /data/redis/redis_vip.sh

3、重启服务(所有节点)
# redis-cli -h 192.168.1.11 -p 7000 shutdown
# redis-sentinel sentinel.conf
# ip addr add 192.168.1.20/24 dev eth0                  #第一次时手动给master添加VIP
# arping -q -c 3 -A 192.168.1.20 -I eth0                #让ip地址即刻生效

 十一、Redis Cluster集群

1、介绍

Redis集群使用数据分片来实现,一个集群有16384个哈希槽,支持主从自动切换,无中心化,不支持多库,只有一个db0

2、环境(3节点)

主节点     db01: 10.0.0.11:7000    db02: 10.0.0.12:7000    db03: 10.0.0.13:7000
从节点     db02: 10.0.0.12:8000    db03: 10.0.0.13:8000    db01: 10.0.0.11:8000

3、redis部署和调优

1、安装redis
# yum -y install wget gcc gcc-c++ make tar openssl openssl-devel cmake
# tar xf redis-4.0.10.tar.gz -C /usr/src/
# cd /usr/src/redis-4.0.10/
# make
# make MALLOC=jemalloc
# make PREFIX=/usr/local/redis install

2、系统调优 # echo "* - nofile 10240" >> /etc/security/limits.conf # echo "net.core.somaxconn = 10240" >> /etc/sysctl.conf # echo "vm.overcommit_memory = 1" >> /etc/sysctl.conf # sysctl -p # echo never > /sys/kernel/mm/transparent_hugepage/enabled # echo never > /sys/kernel/mm/transparent_hugepage/defrag # echo 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >> /etc/rc.local # echo 'echo never > /sys/kernel/mm/transparent_hugepage/defrag' >> /etc/rc.local

4、安装部署redis集群

1、创建目录(所有节点)
# mkdir -p /data/redis-cluster/{7000,8000}
2、创建配置文件(所有节点) ① master配置文件 # vim /data/redis-cluster/7000/redis_7000.conf bind 0.0.0.0 protected-mode yes port 7000 tcp-backlog 1024 timeout 0 tcp-keepalive 0 daemonize yes supervised no pidfile /data/redis-cluster/7000/redis_7000.pid loglevel notice logfile /data/redis-cluster/7000/redis_7000.log databases 16 always-show-logo yes save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename redis_7000.rdb dir /data/redis-cluster/7000/ slave-serve-stale-data yes slave-read-only yes repl-diskless-sync no repl-diskless-sync-delay 5 repl-disable-tcp-nodelay no slave-priority 100 lazyfree-lazy-eviction no lazyfree-lazy-expire no lazyfree-lazy-server-del no slave-lazy-flush no appendonly no appendfilename "appendonly.aof" appendfsync everysec no-appendfsync-on-rewrite no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb aof-load-truncated yes aof-use-rdb-preamble no lua-time-limit 5000 slowlog-log-slower-than 10000 slowlog-max-len 128 latency-monitor-threshold 0 notify-keyspace-events "" hash-max-ziplist-entries 512 hash-max-ziplist-value 64 list-max-ziplist-size -2 list-compress-depth 0 set-max-intset-entries 512 zset-max-ziplist-entries 128 zset-max-ziplist-value 64 hll-sparse-max-bytes 3000 activerehashing yes client-output-buffer-limit normal 0 0 0 client-output-buffer-limit slave 256mb 64mb 60 client-output-buffer-limit pubsub 32mb 8mb 60 hz 10 aof-rewrite-incremental-fsync yes cluster-enabled yes #开启集群模式 cluster-config-file nodes_7000.conf #集群node配置文件(动态更新) cluster-node-timeout 5000 #集群的超时时间 ② slave配置文件 # cp redis_7000.conf /data/redis-cluster/8000/redis_8000.conf # sed -i 's#7000#8000#g' redis_8000.conf 3、启动集群(所有节点) # redis-server /data/redis-cluster/7000/redis_7000.conf # redis-server /data/redis-cluster/8000/redis_8000.conf

5、使用工具自动部署集群

1、安装ruby环境(编译安装高版本ruby,版本大于2.2)
# wget --no-check-certificate 'https://cache.ruby-lang.org/pub/ruby/2.2/ruby-2.2.7.tar.gz'
# tar xf ruby-2.2.7.tar.gz -C /usr/src/
# cd /usr/src/ruby-2.2.7/
# ./configure && make && make install
# ruby --version                        

2、在线安装ruby的redis扩展 # gem install redis #版本要和redis差不多,大版本号一直 # gem install redis -v 3.3.5 #可指定版本安装
3、使用工具部署集群(master上操作) # redis-trib.rb create 10.0.0.11:7000 10.0.0.12:7000 10.0.0.13:7000
4、查看集群的信息 # redis-cli -p 7000 cluster nodes
5、操作集群 # redis-cli -c -p 7000 set name zhang3 # redis-cli -c -p 7000 get name

6、集群的重建(所有节点)

1、删除cluster集群配置文件
# rm -rf /data/redis-cluster/7000/nodes_7000.conf

2、关闭集群
# redis-cli -p 7000 shutdown

3、启动集群
# redis-server /data/redis-cluster/7000/redis_7000.conf

4、重新创建redis-cluster集群
# redis-trib.rb create 10.0.0.11:7000 10.0.0.12:7000 10.0.0.13:7000

5、查看进程
# ps -ef | grep cluster | grep -v grep

7、集群添加从库

# redis-trib.rb add-node --slave 10.0.0.12:8000 10.0.0.11:7000  #添加从8000,主7000
# redis-trib.rb add-node --slave 10.0.0.13:8000 10.0.0.12:7000
# redis-trib.rb add-node --slave 10.0.0.11:8000 10.0.0.13:7000
# redis-cli -p 7000 cluster nodes                               #查看集群所有节点的信息

8、其他

1、集群的主从自动切换
# redis-cli -p 7000 shutdown                                    #手动宕掉主
# redis-cli -p 8000 cluster nodes                               #查看状态(从库变新主库)
# redis-server /data/redis-cluster/7000/redis_7000.conf         #启动主
# redis-cli -p 8000 cluster nodes                               #查看状态(主库变新从库)
# redis-cli -p 7000 cluster failover                            #手动切换主从(主从角色切换)
# redis-cli -p 8000 cluster nodes                               #查看状态(新从库变旧主库)

2、Python操作集群
# yum install python2-pip
# pip install redis-py-cluster
# vim redis_cluster.py 
  # -*- coding:utf-8 -*-
  from rediscluster import StrictRedisCluster
  redis_nodes = [
          {'host':'10.0.0.11','port':7000},
          {'host':'10.0.0.12','port':7000},
          {'host':'10.0.0.13','port':7000},
          {'host':'10.0.0.11','port':8000},
          {'host':'10.0.0.12','port':8000},
          {'host':'10.0.0.13','port':8000}
          ]
  redis_conn = StrictRedisCluster(startup_nodes=redis_nodes)
  redis_conn.set('key_test','values_test')
  print(redis_conn.get('key_test'))
# python redis_cluster.py                                       #执行Python脚本        
# redis-cli -c -p 7000 get key_test                             #查看key
备注: 若其中一个节点挂了,不影响使用

3、分析Redis的所有key和key的大小
# pip install rdbtools                                  #pip安装rdbtools分析工具
# rdb -c memory redis_7000.rdb > /tmp/rdb.csv
# cat /tmp/rdb.csv | head

 

posted on 2018-12-07 16:17  五光十色  阅读(205)  评论(0编辑  收藏  举报

导航