redis学习笔记

Redis简介

Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
Redis 与其他 key - value 缓存产品有以下三个特点:

  • Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
  • Redis支持数据的备份,即master-slave模式的数据备份。

Redis 优势

  • 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
  • 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
  • 原子 – Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。
  • 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。

Redis与其他key-value存储有什么不同?

  • Redis有着更为复杂的数据结构并且提供对他们的原子性操作,这是一个不同于其他数据库的进化路径。Redis的数据类型都是基于基本数据结构的同时对程序员透明,无需进行额外的抽象。
  • Redis运行在内存中但是可以持久化到磁盘,所以在对不同数据集进行高速读写时需要权衡内存,因为数据量不能大于硬件内存。在内存数据库方面的另一个优点是,相比在磁盘上相同的复杂的数据结构,在内存中操作起来非常简单,这样Redis可以做很多内部复杂性很强的事情。同时,在磁盘格式方面他们是紧凑的以追加的方式产生的,因为他们并不需要进行随机访问。

Redis 安装

CentOS7下安装:

  1. 环境配置
    安装pcre开发包: yum install -y pcre-devel
    安装编译源码所需的工具和库:yum install gcc gcc-c++ ncurses-devel perl
    安装cmake:yum -y install make gcc gcc-c++ ncurses-devel
    安装ssl功能需要openssl库:yum -y install openssl-devel
    安装压缩包:yum -y install zlib zlib-devel
    JDK:jdk-8u131-linux-x64.rpm
    make test需要的tcl包: yum install -y tcl

  2. 安装步骤:

# 1.  创建redis目录
mkdir /usr/local/redis
# 2. 解压安装包
tar xzvf redis-3.2.9.tar.gz && cd redis-3.2.9
# 3. 跑test,检查是否有依赖问题
make test 
# 4. 如果有报错,运行该条命令,解决依赖后重跑make test
make distclean
#  开始编译安装,这里我们指定了安装目录,若未指定,默认安装在/usr/local/bin下
make PREFIX=/usr/local/redis install

我们已经将redis可执行文件安装到/usr /local/redis/bin下, 下面我们来注册redis服务:

[root@localhost redis-3.2.9]# cd utils/
[root@localhost utils]# ./install_server.sh 
Welcome to the redis service installer
This script will help you easily set up a running redis server
Please select the redis port for this instance: [6379]    # 指定服务端口
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf]  #指定默认配置文件
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log]  # 指定日志文件
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379]  # 指定数据文件路径
Selected default - /var/lib/redis/6379
Please select the redis executable path [] /usr/local/redis/bin/redis-server # 指定redis-server可执行文件的路径
Selected config:
Port           : 6379
Config file    : /etc/redis/6379.conf
Log file       : /var/log/redis_6379.log
Data dir       : /var/lib/redis/6379
Executable     : /usr/local/redis/bin/redis-server
Cli Executable : /usr/local/redis/bin/redis-cli
Is this ok? Then press ENTER to go on or Ctrl-C to abort.
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
Successfully added to chkconfig!
Successfully added to runlevels 345!
Starting Redis server...
Installation successful!
[root@localhost utils]# chkconfig --list
Note: This output shows SysV services only and does not include native
      systemd services. SysV configuration data might be overridden by native
      systemd configuration.

      If you want to list systemd services use 'systemctl list-unit-files'.
      To see services enabled on particular target use
      'systemctl list-dependencies [target]'.
jexec           0:off   1:on    2:on    3:on    4:on    5:on    6:off
netconsole      0:off   1:off   2:off   3:off   4:off   5:off   6:off
network         0:off   1:off   2:on    3:on    4:on    5:on    6:off
redis_6379      0:off   1:off   2:on    3:on    4:on    5:on    6:off
[root@localhost utils]# service status redis_6379
The service command supports only basic LSB actions (start, stop, restart, try-restart, reload, force-reload, status). For other actions, please try to use systemctl.
[root@localhost utils]# service redis_6379 status
Redis is running (43917)

(* 可选) CentOS7 中用systemd替换了SysV,下面我们来自定义一下redis为systemd管理的服务,systemd配置参考

## 1.关闭SysV的redis服务
[root@localhost bin]# chkconfig redis_6379 off
[root@localhost bin]# service redis_6379 stop
Stopping ...
Redis stopped
[root@localhost bin]# ss -lntp | grep redis
## 2.拷贝配置文件到redis安装目录:
[root@localhost bin]# pwd
/usr/local/redis/bin
[root@localhost bin]# ls
redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis-sentinel  redis-server      
[root@localhost bin]# cp /home/fbo/tools/redis-3.2.9/redis.conf .
[root@localhost bin]# cp /home/fbo/tools/redis-3.2.9/runtest* .
[root@localhost bin]# ls
redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis.conf  redis-sentinel  redis-server  runtest  runtest-cluster  runtest-sentinel
## 3.修改redis配置文件
[root@localhost bin]# mv redis.conf redis.conf.bak
[root@localhost bin]# grep -Ev "^#|^$" redis.conf.bak > redis.conf
[root@localhost bin]# sed -i "s/^bind.*/bind 0.0.0.0/g" redis.conf  # 监听所有ip
[root@localhost bin]# sed -i "s/^daemonize.*/daemonize yes/g" redis.conf # 开启守护进程模式
## 4.添加systemd的redis.service文件
cat > /usr/lib/systemd/system/redis.service << EOF
[Unit]
Description=Redis Daemon
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/bin/redis.conf
ExecStop=/usr/local/redis/bin/redis-cli -p 6379 shutdown
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
[root@localhost ~]# systemctl start  redis
[root@localhost ~]# systemctl status  redis
● redis.service - Redis Daemon
   Loaded: loaded (/usr/lib/systemd/system/redis.service; disabled; vendor preset: disabled)
   Active: active (running) since Mon 2017-07-17 15:06:30 CST; 5s ago
  Process: 45266 ExecStart=/usr/local/redis/bin/redis-server /usr/local/redis/bin/redis.conf (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/redis.service
           └─45139 /usr/local/redis/bin/redis-server 0.0.0.0:6379
Jul 17 15:06:30 localhost.localdomain systemd[1]: Starting Redis Daemon...
Jul 17 15:06:30 localhost.localdomain systemd[1]: Started Redis Daemon.
[root@localhost ~]# systemctl stop  redis
[root@localhost ~]# systemctl status  redis
● redis.service - Redis Daemon
   Loaded: loaded (/usr/lib/systemd/system/redis.service; disabled; vendor preset: disabled)
   Active: inactive (dead)
  1. 将redis的端口添加到Firewall
[root@localhost bin]# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0 eth1
  sources: 
  services: dhcpv6-client ssh
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  sourceports: 
  icmp-blocks: 
  rich rules:   
[root@localhost bin]# firewall-cmd --permanent --add-port=6379/tcp
success
[root@localhost bin]# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0 eth1
  sources: 
  services: dhcpv6-client ssh
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  sourceports: 
  icmp-blocks: 
  rich rules:
[root@localhost bin]# firewall-cmd --reload
success
[root@localhost bin]# firewall-cmd --list-all
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: eth0 eth1
  sources: 
  services: dhcpv6-client ssh
  ports: 6379/tcp
  protocols: 
  masquerade: no
  forward-ports: 
  sourceports: 
  icmp-blocks: 
  rich rules: 
  1. 验证
[root@localhost utils]# cd /usr/local/redis/bin
[root@localhost bin]# ./redis-cli127.0.0.1:6379> set username fbo
OK
127.0.0.1:6379> get username
"fbo"
127.0.0.1:6379> exit
  1. 远程运行Redis
remote-redis.png-w1000
  1. redis.conf配置详解
#是否作为守护进程运行
daemonize yes
#如以后台进程运行,则需指定一个pid,默认为/var/run/redis.pid
pidfile redis.pid
#绑定主机IP,默认值为127.0.0.1
bind 127.0.0.1
#Redis默认监听端口
port 6379
#客户端闲置多少秒后,断开连接,默认为300(秒)
timeout 300
#日志记录等级,有4个可选值,debug,verbose(默认值),notice,warning
loglevel verbose
#指定日志输出的文件名,默认值为stdout,也可设为/dev/null屏蔽日志
logfile stdout
#可用数据库数,默认值为16,默认数据库为0
databases 16
#保存数据到disk的策略
#当有一条Keys数据被改变是,900秒刷新到disk一次
save 900 1
#当有10条Keys数据被改变时,300秒刷新到disk一次
save 300 10
#当有1w条keys数据被改变时,60秒刷新到disk一次
save 60 10000
#当dump .rdb数据库的时候是否压缩数据对象
rdbcompression yes
#本地数据库文件名,默认值为dump.rdb
dbfilename dump.rdb
#本地数据库存放路径,默认值为 ./
dir /usr/local/redis/var/
>> 
_###############Replication##############_
#Redis的复制配置
slaveof <masterip><masterport> 当本机为从服务时,设置主服务的IP及端口
masterauth <master-password> 当本机为从服务时,设置主服务的连接密码
#连接密码
requirepass foobared
#最大客户端连接数,默认不限制
maxclients 128
#最大内存使用设置,达到最大内存设置后,Redis会先尝试清除已到期或即将到期的Key,当此方法处理后,任到达最大内存设置,将无法再进行写入操作。
maxmemory <bytes>
#是否在每次更新操作后进行日志记录,如果不开启,可能会在断电时导致一段时间内的数据丢失。因为redis本身同步数据文件是按上面save条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认值为no
appendonly no
#更新日志文件名,默认值为appendonly.aof
appendfilename
#更新日志条件,共有3个可选值。no表示等操作系统进行数据缓存同步到磁盘,always表示每次更新操作后手动调用fsync()将数据写到磁盘,everysec表示每秒同步一次(默认值)。
appendfsync always
appendfsync everysec
appendfsync no
>> 
__################ VIRTUAL MEMORY ###########__
#是否开启VM功能,默认值为no
vm-enabled no
vm-enabled yes
#虚拟内存文件路径,默认值为/tmp/redis.swap,不可多个Redis实例共享
vm-swap-file logs/redis.swap
#将所有大于vm-max-memory的数据存入虚拟内存,无论vm-max-memory设置多小,所有索引数据都是内存存储的(Redis的索引数据就是keys),也就是说,当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘。默认值为0。
vm-max-memory 0
vm-page-size 32
vm-pages 134217728
vm-max-threads 4
>>
__############# ADVANCED CONFIG###############__
glueoutputbuf yes
hash-max-zipmap-entries 64
hash-max-zipmap-value 512
#是否重置Hash表
activerehashing yes
  1. 调整内核参数:
    如果内存情况比较紧张的话,需要设定内核参数:
    echo 1 > /proc/sys/vm/overcommit_memory
    这里说一下这个配置的含义:/proc/sys/vm/overcommit_memory
    该文件指定了内核针对内存分配的策略,其值可以是0、1、2。
    0,表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
    1,表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
    2,表示内核允许分配超过所有物理内存和交换空间总和的内存
    Redis在dump数据的时候,会fork出一个子进程,理论上child进程所占用的内存和parent是一样的,比如parent占用的内存为 8G,这个时候也要同样分配8G的内存给child, 如果内存无法负担,往往会造成redis服务器的down机或者IO负载过高,效率下降。所以这里比较优化的内存分配策略应该设置为 1(表示内核允许分配所有的物理内存,而不管当前的内存状态如何)

Redis 数据类型

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)

String(字符串)

string是redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。
string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。
string类型是Redis最基本的数据类型,一个键最大能存储512MB。

127.0.0.1:6379> set name "fbo"
OK
127.0.0.1:6379> get name
"fbo"

Hash(哈希)

Redis hash 是一个键名对集合。
Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

127.0.0.1:6379> hmset user:1 username fbo password 123456 points 200
OK
127.0.0.1:6379> hgetall user:1
1) "username"
2) "fbo"
3) "password"
4) "123456"
5) "points"
6) "200"
127.0.0.1:6379> hget user:1 username
"fbo"
127.0.0.1:6379> hget user:1 password
"123456"
127.0.0.1:6379> hget user:1 points
"200"

List(列表)

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
列表最多可存储 232 - 1 元素 (4294967295, 每个列表可存储40多亿)。

127.0.0.1:6379> lpush runoob redis
(integer) 1
127.0.0.1:6379> lpush runoob mongodb
(integer) 2
127.0.0.1:6379> lpush runoob rabitmq
(integer) 3
127.0.0.1:6379> lrange runoob 0 10
1) "rabitmq"
2) "mongodb"
3) "redis"

Set(集合)

Redis的Set是string类型的无序集合。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
实例中 rabitmq 添加了两次,但根据集合内元素的唯一性,第二次插入的元素将被忽略。

127.0.0.1:6379> sadd runfbo redis
(integer) 1
127.0.0.1:6379> sadd runfbo mongdb
(integer) 1
127.0.0.1:6379> sadd runfbo rabitmq
(integer) 1
127.0.0.1:6379> sadd runfbo rabitmq
(integer) 0
127.0.0.1:6379> smembers runfbo
1) "rabitmq"
2) "mongdb"
3) "redis"

zset(sorted set:有序集合)

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。
添加元素到集合,元素在集合中存在则更新对应score

127.0.0.1:6379> zadd runfbi 0 redis
(integer) 1
127.0.0.1:6379> zadd runfbi 0 mongodb
(integer) 1
127.0.0.1:6379> zadd runfbi 0 rabitmq
(integer) 1
127.0.0.1:6379> zadd runfbi 0 rabitmq
(integer) 0
127.0.0.1:6379> ZRANGEBYSCORE runfbi 0 1000
1) "mongodb"
2) "rabitmq"
3) "redis"

参考文档:

redis 入门教程
redis 命令参考
python使用redis

redis 性能测试

测试脚本:./redis-benchmark -h xx -p xx -t set -q -r 1000 -l -d 20

推荐阅读更多精彩内容