Redis

Redis是一个高性能的键值对内存数据库,支持多种数据类型如字符串、列表、集合等。本文介绍了Redis的发展历程、主要版本特性、安装步骤、启动与关闭方法,以及常用命令和数据类型的应用场景。同时,讨论了Redis的缓存淘汰策略,包括LRU和LFU等。此外,还提到了Redis在缓存使用、分布式锁等场景下的应用。
摘要由CSDN通过智能技术生成

Redis基础

Redis介绍

什么是Redis

Redis (Remote Dictionary Server)远程字典服务器,是用C语言开发的一个开源的高性能键值对( key-value )内存数据库。它提供了五种数据类型来存储值:字符串类型、散列类型、列表类型、集合类型、有序集合类型它是一种NoSQL 数据存储。
Redis发展历史
2008年,意大利的一家创业公司Merzia 推出了一款基于MySQL 的网站实时统计系统LLOOGG ,然而没过多久该公司的创始人 Salvatore Sanfilippo ( antirez)便 对MySQL的性能感到失望,于是他决定亲自为LLOOGG 量身定做一个数据库,并于2009年开发完成,这个数据库就是Redis。
Redis2.6
Redis2.6在2012年正式发布,主要特性如下:

  • 服务端支持Lua脚本、去掉虚拟内存相关功能、键的过期时间支持毫秒、从节点提供只读功能、两个新的位图命令:bitcount和bitop、重构了大量的核心代码、优化了大量的命令。

Redis2.8
Redis2.8在2013年11月22日正式发布,主要特性如下:

  • 添加部分主从复制(增量复制)的功能、可以用bind命令绑定多个IP地址、Redis设置了明显的进程名、发布订阅添加了pubsub命令、Redis Sentinel生产可用

Redis3.0
Redis3.0在2015年4月1日正式发布,相比于Redis2.8主要特性如下:

  • Redis Cluster:Redis的官方分布式实现(Ruby)、全新的对象编码结果、lru算法大幅提升、部分命令的性能提升

Redis3.2
Redis3.2在2016年5月6日正式发布,相比于Redis3.0主要特征如下:

  • 添加GEO相关功能、SDS在速度和节省空间上都做了优化、新的List编码类型:quicklist、从节点读取过期数据保证一致性、Lua脚本功能增强等

Redis4.0
Redis4.0在2017年7月发布,主要特性如下:

  • 提供了模块系统,方便第三方开发者拓展Redis的功能、PSYNC2.0:优化了之前版本中,主从节点切换必然引起全量复制的问题、提供了新的缓存剔除算法:LFU(Last Frequently Used),并对已有算法进行了优化、提供了RDB-AOF混合持久化格式等

Redis应用场景

  • 缓存使用,减轻DB压力
  • DB使用,用于临时存储数据(字典表,购买记录)
  • 解决分布式场景下Session分离问题(登录信息)
  • 任务队列(秒杀、抢红包等等) 乐观锁
  • 应用排行榜 zset
  • 签到 bitmap
  • 分布式锁
  • 冷热数据交换

Redis单机版安装和使用
Redis下载

  • 官网地址:http://redis.io/
  • 中文官网地址:http://www.redis.cn/
  • 下载地址:http://download.redis.io/releases/

Redis安装环境
Redis 没有官方的Windows 版本,所以建议在Linux 系统上安装运行。
我们使用CentOS 7 作为安装环境。
Redis安装
第一步:安装C 语言需要的GCC 环境

yum install -y gcc-c++
yum install -y wget


第二步:下载并解压缩Redis 源码压缩包

wget http://download.redis.io/releases/redis-5.0.5.tar.gz
tar -zxf redis-5.0.5.tar.gz

第三步:编译Redis 源码,进入redis-5.0.5 目录,执行编译命令

cd redis-5.0.5/src
make

第四步:安装Redis ,需要通过PREFIX 指定安装路径

mkdir /usr/redis -p
make install PREFIX=/usr/redis

Redis启动
前端启动

  • 启动命令: redis-server ,直接运行bin/redis-server 将以前端模式启动
  • 关闭命令: ctrl+c
  • 启动缺点:客户端窗口关闭则redis-server 程序结束,不推荐使用此方法

后端启动(守护进程启动)
第一步:拷贝redis-5.0.5/redis.conf 配置文件到Redis 安装目录的bin 目录
第二步:修改redis.conf

# 将`daemonize`由`no`改为`yes`
daemonize yes
# 默认绑定的是回环地址,默认不能被其他机器访问
# bind 127.0.0.1
# 是否开启保护模式,由yes该为no
protected-mode no

第三步:启动服务

./redis-server redis.conf

后端启动的关闭方式

./redis-cli shutdown

命令说明

  • redis-server :启动redis 服务
  • redis-cli :进入redis 命令客户端
  • redis-benchmark : 性能测试的工具
  • redis-check-aof : aof 文件进行检查的工具
  • redis-check-dump : rdb 文件进行检查的工具
  • redis-sentinel : 启动哨兵监控服务

Redis命令行客户端
命令格式

./redis-cli -h 127.0.0.1 -p 6379

参数说明

-h:redis服务器的ip地址
-p:redis实例的端口号

默认方式
如果不指定主机和端口也可以

  • 默认主机地址是127.0.0.1
  • 默认端口是6379

Redis数据类型和应用场景
Redis是一个Key-Value的存储系统,使用ANSI C语言编写。
key的类型是字符串。
value的数据类型有:

  • 常用的:string字符串类型、list列表类型、set集合类型、sortedset(zset)有序集合类型、hash类型。
  • 不常见的:bitmap位图类型、geo地理位置类型。
  • Redis5.0新增一种:stream类型

注意:Redis中命令是忽略大小写,(set SET),key是不忽略大小写的 (NAME name)
Redis的Key的设计

  • 1. 用:分割
  • 2. 把表名转换为key前缀, 比如: user:
  • 3. 第二段放置主键值
  • 4. 第三段放置列名
  • 比如:用户表user, 转换为redis的key-value存储

username 的 key: user:9:username
{userid:9,username:zhangf}
email的key user:9:email
表示明确:看key知道意思
不易被覆盖


string字符串类型
Redis的String能表达3种值的类型:字符串、整数、浮点数 100.01 是个六位的串
常见操作命令如下表:

应用场景:

  • 1、key和命令是字符串
  • 2、普通的赋值
  • 3、incr用于乐观锁
    • incr:递增数字,可用于实现乐观锁 watch(事务)
  • 4、setnx用于分布式锁
    • 当value不存在时采用赋值,可用于实现分布式锁

举例:
setnx:

127.0.0.1:6379> setnx name zhangf #如果name不存在赋值
(integer) 1
127.0.0.1:6379> setnx name zhaoyun #再次赋值失败
(integer) 0
127.0.0.1:6379> get name
"zhangf"

set

127.0.0.1:6379> set age 18 NX PX 10000 #如果不存在赋值 有效期10秒
OK
127.0.0.1:6379> set age 20 NX #赋值失败
(nil)
127.0.0.1:6379> get age #age失效
(nil)
127.0.0.1:6379> set age 30 NX PX 10000 #赋值成功
OK
127.0.0.1:6379> get age
"30"

list列表类型
list列表类型可以存储有序、可重复的元素
获取头部或尾部附近的记录是极快的
list的元素个数最多为2^32-1个(40亿)
常见操作命令如下表:

应用场景:
1、作为栈或队列使用
列表有序可以作为栈和队列使用

存过期和淘汰策略

Redis性能高:
官方数据
读:110000次/s
写:81000次/s
长期使用,key会不断增加,Redis作为缓存使用,物理内存也会满
内存与硬盘交换(swap) 虚拟内存 ,频繁IO 性能急剧下降

maxmemory

不设置的场景
Redis的key是固定的,不会增加
Redis作为DB使用,保证数据的完整性,不能淘汰 , 可以做集群,横向扩展
缓存淘汰策略:禁止驱逐 (默认)
设置的场景
Redis是作为缓存使用,不断增加Key
maxmemory : 默认为0 不限制
问题:达到物理内存后性能急剧下架,甚至崩溃
内存与硬盘交换(swap) 虚拟内存 ,频繁IO 性能急剧下降
设置多少?
与业务有关
1个Redis实例,保证系统运行 1 G ,剩下的就都可以设置Redis
物理内存的3/4

slaver : 留出一定的内存
在redis.conf中
命令: 获得maxmemory数
设置maxmemory后,当趋近maxmemory时,通过缓存淘汰策略,从内存中删除对象
不设置maxmemory 无最大内存限制 maxmemory-policy noeviction (禁止驱逐) 不淘汰
设置maxmemory maxmemory-policy 要配置

expire数据结构


在Redis中可以使用expire命令设置一个键的存活时间(ttl: time to live),过了这段时间,该键就会自动被删除。
expire的使用
expire命令的使用方法如下: expire key ttl(单位秒)

127.0.0.1:6379> expire name 2 #2秒失效
(integer) 1
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> set name zhangfei
OK
127.0.0.1:6379> ttl name #永久有效
(integer) -1
127.0.0.1:6379> expire name 30 #30秒失效
(integer) 1
127.0.0.1:6379> ttl name #还有24秒失效
(integer) 24
127.0.0.1:6379> ttl name #失效
(integer) -2

删除策略

Redis的数据删除有定时删除、惰性删除和主动删除三种方式。
Redis目前采用惰性删除+主动删除的方式。
定时删除
在设置键的过期时间的同时,创建一个定时器,让定时器在键的过期时间来临时,立即执行对键的删除
操作。
需要创建定时器,而且消耗CPU,一般不推荐使用。
惰性删除
在key被访问时如果发现它已经失效,那么就删除它。
调用expireIfNeeded函数,该函数的意义是:读取数据之前先检查一下它有没有失效,如果失效了就删除它。
主动删除
在redis.conf文件中可以配置主动删除策略,默认是no-enviction(不删除)

maxmemory-policy allkeys-lru

LRU
LRU (Least recently used) 最近最少使用,算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
最常见的实现是使用一个链表保存缓存数据,详细算法实现如下:

  • 1. 新数据插入到链表头部;
  • 2. 每当缓存命中(即缓存数据被访问),则将数据移到链表头部;
  • 3. 当链表满的时候,将链表尾部的数据丢弃。
  • 4. 在Java中可以使用LinkHashMap(哈希链表)去实现LRU

让我们以用户信息的需求为例,来演示一下LRU算法的基本思路:
1.假设我们使用哈希链表来缓存用户信息,目前缓存了4个用户,这4个用户是按照时间顺序依次从链表右端插入的。

2.此时,业务方访问用户5,由于哈希链表中没有用户5的数据,我们从数据库中读取出来,插入到缓存当中。这时候,链表中最右端是最新访问到的用户5,最左端是最近最少访问的用户1。


3.接下来,业务方访问用户2,哈希链表中存在用户2的数据,我们怎么做呢?我们把用户2从它的前驱节点和后继节点之间移除,重新插入到链表最右端。这时候,链表中最右端变成了最新访问到的用户2,最左端仍然是最近最少访问的用户1。

4.接下来,业务方请求修改用户4的信息。同样道理,我们把用户4从原来的位置移动到链表最右侧,并把用户信息的值更新。这时候,链表中最右端是最新访问到的用户4,最左端仍然是最近最少访问的用户1。


5.业务访问用户6,用户6在缓存里没有,需要插入到哈希链表。假设这时候缓存容量已经达到上限,必须先删除最近最少访问的数据,那么位于哈希链表最左端的用户1就会被删除掉,然后再把用户6插入到最右端。

Redis的LRU 数据淘汰机制
在服务器配置中保存了 lru 计数器 server.lrulock,会定时(redis 定时程序 serverCorn())更新,
server.lrulock 的值是根据 server.unixtime 计算出来的。
另外,从 struct redisObject 中可以发现,每一个 redis 对象都会设置相应的 lru。可以想象的是,每一
次访问数据的时候,会更新 redisObject.lru。
LRU 数据淘汰机制是这样的:在数据集中随机挑选几个键值对,取出其中 lru 最大的键值对淘汰。
不可能遍历key 用当前时间-最近访问 越大 说明 访问间隔时间越长
volatile-lru
从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
allkeys-lru
从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
LFU
LFU (Least frequently used) 最不经常使用,如果一个数据在最近一段时间内使用次数很少,那么在将
来一段时间内被使用的可能性也很小。
volatile-lfu
allkeys-lfu
random
随机
volatile-random
从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-random
从数据集(server.db[i].dict)中任意选择数据淘汰
ttl
volatile-ttl

从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
redis 数据集数据结构中保存了键值对过期时间的表,即 redisDb.expires。
TTL 数据淘汰机制:从过期时间的表中随机挑选几个键值对,取出其中 ttl 最小的键值对淘汰。
noenviction
禁止驱逐数据,不删除 默认
缓存淘汰策略的选择
allkeys-lru : 在不确定时一般采用策略。 冷热数据交换
volatile-lru : 比allkeys-lru性能差 存 : 过期时间
allkeys-random : 希望请求符合平均分布(每个元素以相同的概率被访问)
自己控制:volatile-ttl 缓存穿透
案例分享:字典库失效
key-Value 业务表存 code 显示 文字
拉勾早期将字典库,设置了maxmemory,并设置缓存淘汰策略为allkeys-lru
结果造成字典库某些字段失效,缓存击穿 , DB压力剧增,差点宕机。
分析:
字典库 : Redis做DB使用,要保证数据的完整性
maxmemory设置较小,采用allkeys-lru,会对没有经常访问的字典库随机淘汰
当再次访问时会缓存击穿,请求会打到DB上。
解决方案:
1、不设置maxmemory
2、使用noenviction策略
Redis是作为DB使用的,要保证数据的完整性,所以不能删除数据。
可以将原始数据源(XML)在系统启动时一次性加载到Redis中。
Redis做主从+哨兵 保证高可用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值