Redis(官网,翻译版)是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。
Redis 支持多种类型的数据结构,如字符串(strings),散列(hashes),列表(lists),集合(sets),有序集合(sorted sets)与范围查询,bitmaps,hyperloglogs 和地理空间(geospatial)索引半径查询。
Redis 内置了复制(replication),LUA脚本(Lua scripting),LRU驱动事件(LRU eviction),事务(transactions)和不同级别的磁盘持久化(persistence),并通过Redis哨兵(Sentinel)和自动分区(Cluster)提供高可用性(high availability)。
1. 基础知识
1.1 常识(磁盘与内存)
1.1.1 寻址和带宽
- 磁盘:寻址-ms级别,带宽-G/M;
- 内存:寻址-ns级别,带宽很大;
- 磁盘比内存在寻址上慢了10W倍。
1.1.2 I/O buffer的成本问题
- 磁盘有磁道和扇区,一扇区512Byte,使得索引成本变大;
- 操作系统从磁盘中读取数据,每次最少是4K。
1.1.3 磁盘I/O
- Java随着文件变大,磁盘I/O称为瓶颈,导致速度变慢。
1.1.4 数据在磁盘和内存中体积不同
- 磁盘中没有指针,体积相对较大;
- 内存中有指针引用,体积小得多。
1.2 关系型数据库
1.2.1 索引
1、1页:等同于操作系统读取大小,避免浪费(data page:4K);
2、索引:等同于1页,即4K。
- 数据库数据是用4K小格子存储数据,如果没有索引,查询会很慢,走的是全量I/O;
- 要提升速度,必须要用索引;
- 索引也是使用4K这种对应模型,面向一行里的某一列;
- 数据和索引都存储在磁盘。
1.2.2 建表必须给出schema
- 表共有多少列;
- 每个列的类型和约束是什么。
类型即字节宽度:这样当插入的时候,如果这行数据有列为null值,会进行占位,当更改数据时,直接在这一列进行插入即可,避免空间上的转换。
1.2.3 行级存储
存数据时,倾向于行级存储。
1.2.4 内存是B+树
- 叶子是索引;
- 内存只放树干–区间和偏移;
- 索引和数据放在磁盘。
where条件命中索引,再找到数据。
1.2.5 表数据与性能问题
表数据很大,性能是否会下降?
如果有索引:
- 增删改,变慢;
- 查询速度(要从硬盘的寻址和带宽这两方面来说):
(1)1个或少量查询,依然很快;
(2)并发大时,磁盘带宽会影响速度。
1.3 缓存数据库
1.3.1 引入
- 磁盘特别慢;
- 内存数据库又很昂贵;
- 折中方案–缓存数据库:
(1)Memcached
1> value没有类型的概念;
2> 取元素时,取回所有,要获取单个元素,server端的网卡I/O会成为瓶颈,而且client端要有代码实现去解码。
(2)Redis
1> value有不同的类型;
2> 类型不是很重要,重要的是Redis的Server中对每种value类型都有自己的方法,如取元素方法index(),lpop()等,优势是计算向数据移动。
1.3.2 计算机的2个基础设置制约
- 冯诺依曼体系的硬件,制约着硬件的寻址和I/O;
- 以太网,TCP/IP的网络,制约着网络的稳定性。
1.3.3 DB-ENGINES
- 数据库引擎-官网;
- 可以作为架构师进行技术选型和技术对比的不错选择。
2. Redis安装和介绍
2.1 源码安装
一、准备阶段
centos 6.x
redis 官网5.x
http://download.redis.io/releases/redis-5.0.5.tar.gz
二、安装步骤(源码安装)
1,yum install wget
2, cd ~
3, mkdir soft
4, cd soft
5, wget http://download.redis.io/releases/redis-5.0.5.tar.gz
6, tar xf redis...tar.gz
7, cd redis-src
8, 看README.md
9, make
.... yum install gcc
.... make distclean
10, make
11, cd src ....生成了可执行程序
12, cd ..
13, make install PREFIX=/opt/lhds/redis5
14, vi /etc/profile
... export REDIS_HOME=/opt/lhds/redis5
... export PATH=$PATH:$REDIS_HOME/bin
... source /etc/profile
15, cd utils
16, ./install_server.sh (可以执行一次或多次)
a) 一个物理机中可以有多个redis实例(进程),通过port区分
b) 可执行程序就一份在目录,但是内存中未来的多个实例需要各自的配置文件,持久化目录等资源
c) service redis_6379 start/stop/stauts > linux /etc/init.d/**** (有脚本)
d)脚本还会帮你启动!
17, ps -fe | grep redis
三、注意事项
1. 以后无论安装什么,先读 ReadMe
2. 通读一遍,可能后面有前面需要的依赖
3. 安装步骤执行,出错再解决,缺什么补什么
4. make 是编译工具
(1)默认执行 Makefile 中脚本命令
(2)报错再执行,先 make distclean 清除缓存垃圾
5. 解压命令参数只用 xf ,不用 v ,因为客户端回显过程消耗 I/O ,服务器上最好【规避 I/O】
6. 已自动设置为开机启动:
-- Successfully added to chkconfig !
2.2 命令汇总
一、服务端/客户端启动
redis-server ~/test/6379/6379.conf
redis-server ~/test/6379/6379.conf --replicaof 127.0.0.1 6379 从追随主(主从复制)
redis-server ./26379.conf --sentinel 或 redis-sentinel 启动哨兵服务
redis-cli
service redis_6379 stop 停止对于端口的redis服务
127.0.0.1:6379> CONFIG GET * 可以获取当前实例的配置文件信息
127.0.0.1:6379> CONFIG SET protected-mode no 临时修改,允许远端访问,否则程序访问不了
二、进入库
redis-cli -p 6379
三、帮助
yum install man man-pages 安装后,可查看帮助文档
redis -h
四、value操作
1. string(byte)
(1)字符串
set key value nx :NX -- 只有key不存在时才去设置其 value,即只能新建
使用场景:分布式锁 -- 一起设置,成功的拿到锁
set key value xx :XX -- 只有 key 存在时才能操作,即只能修改
get key :取 key 的值
mset k3 a k4 b :同时设置 k3 k4 的值
mget k3 k4 :同时取 k3 k4 的值
msetnx k2 c k3 d :同时多笔操作,它是原子的
有一个失败了,全部设置失败
getset k1 a :设置新值的同时,返回旧值
把 get/set 2个命令合为一个,较少 I/O
append k1 " world" :追加内容
strlen k1 :查询字符串 value 的长度
type k1 :查看 value 值类型
(2)数值
object encoding k1 => 结果 int => k1 的 value 的字符编码有 3 种:embstr、raw、int
面向 string 的数值操作:
incr :累加 1
decr :递减 1
decrby k1 22 :减去 22(整数)
decrbyfloat k1 0.5 :减去 0.5(小数)
使用场景:抢购、秒杀、详情页、点赞、评论
规避并发下,对数据库的事务操作,完全由 Redis 内存操作代替
(3)bitmap 位图
help setbit :帮助命令,bitmap 也属于 string 组
set key offset value :offset 是一个二进制的偏移量,而非字节数组
一个字节有 8 个二进制位
二进制位也有索引
bitpos key [start end] :start/end 是指字节的位置
bitcount key [start end] :
例如:
0 1
01000001 01000000
01234567 8 9 10 11
执行:bitcount key 0 1
结果:(integer 3)
bitop operation desikey key [key ...] :operation 为二进制的【与或非】运算
与 -- and :有0则0,全1为1
或 -- or :有1则1,全0则0
例如:
0100 0001 -> A
0100 0010 -> B
执行:bitop and andkey k1 k2
get andkey =》结果:“@”(ASCII码)
使用场景:
1- 统计用户登录天数,且窗口随机:
setbit lhds 1 1
setbit lhds 7 1
setbit lhds 364 1
STRLEN lhds
BITCOUNT lhds -2 -1
-----------------------------------------------------
占用空间:
01 02 03 04
lhds 0 1 0 1 010101
json 0 1 0 1 011111
每用户46B * 用户数 10000000 = 460 000 000
2- 电商网站,618做活动:送礼物
大库备货多少礼物
假设网站有2E用户
僵尸用户
冷热用户/忠诚用户
活跃用户统计!随即窗口
比如说 1号~3号 连续登录要 去重
setbit 20190101 1 1
setbit 20190102 1 1
setbit 20190102 7 1
bitop or destkey 20190101 20190102
BITCOUNT destkey 0 -1
---------------------------------------------------------
u1 u2 u3
20190101 0 1 0 000100
20190102 1 1 0 10101
2. list
栈,队列,数组,单播队列
help @list :获取所有 list 操作命令
lpush k1 a b c d :从左边向 list 添加元素,成功后其顺序为 d c b a
lpop k1 :从左边弹出一个元素(后进先出-栈-同向命令 ;先进先出-队列-反向命令)
rpush :从右到左
lrange k1 0 -1 :“l” 表示类型 list,使用正负索引,取出所有元素
lindex k1 1 2 :给出索引,取出元素
此为取出第 3 个元素
lindex k1 -1 :取出最后一个元素
lset k1 3 x :把下标为 3 的元素,设置其 value=x
对索引进行操作-数组
lrem k3 2 a :移除 2 个 value=a 的元素
2 即 count,正数,则从左到右开始,移除前 2 个
count,负数,则从右开始,移除后 2 个
linsert k3 after 6 a :在元素 6 的后面,插入一个元素 a
前面插入用 before
llen ;统计 list 元素个数
blpop :阻塞弹出元素,无论是否存在(阻塞-单播队列-FIFO)
brpop :阻塞弹出元素,无论是否存在(阻塞-单播队列-FIFO)
ltrim key start stop :移除两端元素,start~stop 之间的不会删除
list 中元素特征:可重复
有序(这个有序,是指元素存入、插入和弹出顺序,不是排序)
3. hash
map(k-v) 结构
hset person name tom :设置 person 的 name 属性
hmset person age 18 address bj :设置 person 多个属性
hget person name :获取 person 的 name 值
hkeys :获取所有 key
hvals person :获取 person 的所有值列表
hgetall person :返回 key 为 person 的所有字段和值
hincrbyfloat person age 0.5 :person 的 age 加 0.5
如果 -0.5 ,则减去 0.5
可以对 field 数值进行计算
应用场景:点赞,收藏,商品详情页,商品有很多字段信息
4. set
去重,无序
集合操作特别多
sadd k1 tom jon per tom :添加元素,且对 tom 去重,成功后为 3 个元素
srem k1 tom :删除 k1 中的一个元素
smembers k1 :删除 k1 中所有元素
sinter k1 k2 :两个集合的交集
sinterstore dest k1 k2 :将 k1 k2 交集结果存入 dest
这个命令为了减少 I/O,涉及技术选型
sunion :并集且去重,用法同交集
sdiff :差集,有方向性的
sdiff k2 k3 :在 k2 取数据,k3 作参考
反之 k3 k2 亦然
随机事件:
srandmember key count :count 为正数,取出一个去重的结果集(不能超过已有集)
count 为负数,取出一个带重复的结果集,一定要满足你的数量
如果:0,则不返回
spop :取出一个 -- 随机取出元素,set 中元素一个一个减少,直至为空
应用场景:
1- 抽奖
10 个奖品
用户:<10> 10
中奖:是否重复:
count 正负,可控制一个人是否可重复中奖,负数表示可重复
人数小于礼物数,用负数,即一个人多中几张,value 存储人名
2- 取名
5. sorted set
有序集,元素有排序
zadd k1 8 apple 2 banana 3 orange :结果:banana orange apple 按分值排序,左小右大
zrange k1 0 -1 :查看所有元素
zrange k1 0 -1 withscores :带分值
zrange k1 0 1 :按价格从低到高,取前 2 个
zrevrange k1 0 1 :按价格从高到低,取前 2 个(反向)
zrangebyscore k1 3 8 :按分值去取,min 3 ,max 8
zscore k1 apple :取出分值
zrank k1 apple :取出排名
zincrby k1 2.5 banana :将 banana 分值增加 2.5
负值就会减去 2.5
使用场景:歌曲排行榜
集合操作:
例:
zadd k1 80 tom 60 lhds 70 baby
zadd k2 60 tom 100 lhds 40 yiyi
zunionstore unkey 2 k1 k2 =》 4
zrange unkey 0 -1 withscores =》yiyi 40 - baby 70 - tom 140 - lhds 160 (同名元素分值 sum 了)
zunionstore unkey1 2 k1 k2 weights 1 0.5(权重)
zrange unkey 0 -1 withscores =》yiyi 20 - baby 70 - lhds 110 - tom 110 =》 (按权重进行计算了,如 k2 的 yiyi score 40 * weight 0.5 = 20 ,其他以此类推)
zunionstore unkey1 2 k1 k2 aggregate max =》 查看:yiyi 40 - baby 70 - tom 80 - lhds 100 (同名取最大值)
注意点:权重/聚合指令
五、管道
yum install nc 安装
nc localhost 6379 :建立 Socket 连接
之后给 Redis 发指令,可以执行
一次性执行多个命令
命令格式:echo -e "操作命令\n操作命令" | nc localhost 6379
举个例子:echo -e "set k2 99\n incr k2\n get k2 " | nc localhost 6379
注:\n 是换行符,必须有 ;“|” 就是管道
六、发布订阅
help @pubsub 帮助命令
publish key value :发布消息
七、事务
help @transactions :帮助命令
八、布隆过滤器
bf.add o x
bf.exists
九、设置 key 过期时间
set k1 aaa ex 5 :即 key 在 5秒后过期
expire k1 5 :同上
expireat key timestamp :倒计时,定死在某一时间点过期,且不能延长
十、其他
git clone 失败 yum update nss
2.3 介绍
-
key-value数据库;
-
可达到秒级10W操作;
-
单进程,单线程,单实例:
(1)基于OS底层kernel提供的系统调用epoll技术,来保证Redis的快;
(2)为了保证数据一致性;
(3)注意:Redis只是单进程、单线程去处理用户的请求,但Redis中仍有其他进程在做别的事,这里只讨论处理用户的请求,所以才说Redis是单进程、单线程、单实例。
-
对数据的处理有“顺序性”(每连接内的命令顺序);
-
默认16个库(0~15,在配置文件可以自定义设置),各个库是区域隔离的。