Redis基础(含下载安装)与数据类型
1.Redis基础
1.NoSQL概述
问题现象
在春运使用12306买票,与在淘宝买东西等情况时会出现春节期间买票进不去,进去了刷不着票,原因是以为用户量太大
特征
1.海量用户
2.高并发
这两个现象出现以后,对应的就会造成我们的服务器瘫痪,其实并不是我们的应用服务器,而是我们的关系型数据库。关系型数据库才是最终的罪魁祸首
造成原因
1.性能瓶颈:磁盘IO性能低下
关系型数据库在存取数据的时候和读取数据的时候他要走磁盘IO。磁盘这个性能本身是比较低的
2.扩展瓶颈:数据关系复杂,扩展性差,不便于大规模集群
关系型数据库,它里面表与表之间的关系非常复杂,就是一张表,通过它的外键关联了七八张表,这七八张表又通过它的外键,每张又关联了四五张表。要想拿到数据,你就要从A到B、B到C、C到D的一直这么关联下去,最终非常影响查询的效率。同时,你想扩展下,也很难
解决思路
1.降低磁盘IO次数,越低越好 ——用内存存储
2.去除数据间关系,越简单越好 ——不存关系,只存数据
把这两个特征一合并一起,就出来了一个新的概念:NoSQL
NoSQL:即 Not-Only SQL( 泛指非关系型的数据库),作为关系型数据库的补充。 作用:应对基于海量用户和海量数据前提下的数据处理问题
特征
可扩容,可伸缩。SQL数据关系过于复杂,扩容一下难度很高,那Nosql 这种的,不存关系,所以它的扩容就简单一些。
大数据量下高性能。当数据非常多的时候,它的性能高,因为不走磁盘IO,走的是内存,性能肯定要比磁盘IO的性能快一些。
灵活的数据模型、高可用。他设计了自己的一些数据存储格式,这样能保证效率上来说是比较高的,最后一个高可用,我们等到集群内部分再去它
常见 Nosql 数据库
目前市面上常见的Nosql产品:Redis、memcache、HBase、MongoDB
应用场景
2.Redis概述
Redis (Remote Dictionary Server:远程词典服务器) 是用 C 语言开发的一个开源的高性能(内存型)键值对(key-value)数据库
特征
1.数据间没有必然的关联关系;
2.内部采用单线程机制进行工作;
3.高性能。官方提供测试数据,50个并发执行100000 个请求,读的速度是110000 次/s,写的速度是81000次/s。
4.多数据类型支持
字符串类型 string
列表类型 list
散列类型 hash
集合类型 set
有序集合类型 zset/sorted_set
5.支持持久化,可以进行数据灾难恢复
redis的应用场景
1.为热点数据加速查询(主要场景)。如热点商品、热点新闻、热点资讯、推广类等高访问量信息等。
2.即时信息查询。如各位排行榜、各类网站访问统计、公交到站信息、在线人数信息(聊天室、网站)、设备信号等。
3.时效性信息控制。如验证码控制、投票控制等。
4.分布式数据共享。如分布式集群架构中的 session 分离。
5.消息队列
3.Redis下载
下载安装包
wget http://download.redis.io/releases/redis-5.0.0.tar.gz
解压安装包
tar -xvf redis-5.0.0.tar.gz
cd redis-5.0.0
ll
编译 (在解压的目录中执行)
make
当执行make时报错
因为Redis是C实现的,需要gcc来进行编译,所以原因是系统未安装gcc
yum install -y gcc g++ gcc-c++ make
再次执行make,若make出现错误为:致命错误,执行以下命令
make MALLOC=libc
成功后继续操作
安装(在解压的目录中执行)
make install
cd src
cd
使名称变短,方便操作
ln -s redis-5.0.0 redis
cd redis
4.服务器与客户端启动
启动服务器——参数启动
redis-server [--port port]
范例
redis-server --port 6379
启动服务器——配置文件启动
redis-server config_file_name
范例
redis-server redis.conf
启动客户端
redis-cli [-h host] [-p port]
范例
redis-cli –h 61.129.65.248 –p 6384
注意:服务器启动指定端口使用的是--port,客户端启动指定端口使用的是-p。-的数量也不同
Redis基础环境设置约定
创建配置文件存储目录
mkdir conf
创建服务器文件存储目录(包含日志、数据、临时配置文件等)
mkdir data
创建快速访问链接
ln -s redis-5.0.0 redis
服务器端设定
配置介绍
设置服务器以守护进程的方式运行,开启后服务器控制台中将打印服务器运行信息(同日志内容相同)
daemonize yes|no # 改为yes就是后台启动,看不到之前的欢迎信息,cmd窗口关闭也没影响
#windows版本的redis不支持后台启动,配置也没有用
绑定主机地址:bind ip
bind 127.0.0.1 #指定当前redis服务运行在哪个ip上(一般都指定为本机)
设置服务器端口
port 6379 #6379是redis的默认端口
日志文件
logfile "日志文件名"
设置服务器文件保存地址:dir path
dir "/redis/data"
windows配置为:dir "./data"(需要在redis安装的目录新建data文件夹)
启动
#启动服务器
redis-server /redis/conf/redis-6379.conf
#查看进程
ps -ef | grep redis
配置为后台启动之后,可以通过ps查看是否启动
客户端配置
服务器允许客户端连接最大数量,默认0,表示无限制。当客户端连接到达上限后,Redis会拒绝新的连接
maxclients count
客户端闲置等待最大时长,达到最大值后关闭对应连接。如需关闭该功能,设置为 0
timeout seconds
日志配置
设置服务器以指定日志记录级别
loglevel debug|verbose|notice|warning
日志记录文件名
logfile filename
注意:日志级别开发期设置为verbose即可,生产环境中配置为notice,简化日志输出量,降低写日志IO的频度
5.Redis基本操作
读写信息
设置 key,value 数据
set key value
范例
set name wawa
根据 key 查询对应的 value,如果不存在,返回空(nil)
get key
范例
get name
帮助信息
获取命令帮助文档
help [command]
范例
help set
获取组中所有命令信息名称
help [@group-name]
范例
help @string
退出命令行客户端模式
退出客户端
quit 或
exit
快捷键
Ctrl+C
2.数据类型
1.数据类型的介绍
业务数据的特殊性
1.原始业务功能设计
秒杀。他这个里边数据变化速度特别的快,访问量也特别的高,用户大量涌入以后都会针对着一部分数据进行操作,这一类要记住
618活动。对于我们京东的618活动、以及天猫的双11活动,相信大家不用说都知道这些数据一定要进去,因为他们的访问频度实在太高了
排队购票。我们12306的票务信息。这些信息在原始设计的时候,他们就注定了要进redis
2.运营平台监控到的突发高频访问数据
此类平台临时监控到的这些数据,比如说现在出来的一个八卦的信息,这个新闻一旦出现以后呢,顺速的被围观了,那么这个时候,这个数据就会变得访量特别高,那么这类信息也要进入进去
3.高频、复杂的统计数据
在线人数。比如说直播现在很火,直播里边有很多数据,例如在线人数。进一个人出一个人,这个数据就要跳动,那么这个访问速度非常的快,而且访量很高,并且它里边有一个复杂的数据统计,在这里这种信息也要进入到redis中
投票排行榜。投票投票类的信息他的变化速度也比较快,为了追求一个更快的一个即时投票的名次变化,这种数据最好也放到redis中
Redis 数据类型(5种常用)
基于以上数据特征我们进行分析,最终得出来我们的Redis中要设计5种 数据类型:
string、hash、list、set、sorted_set/zset(应用性较低)
2.string数据类型
Redis 数据存储格式
redis 自身是一个 Map,其中所有的数据都是采用 key : value 的形式存储
对于这种结构来说,我们用来存储数据一定是一个值前面对应一个名称,我们通过名称来访问后面的值。
前面这一部分我们称为key,后面的一部分称为value,而我们的数据类型,他一定是修饰value的。
数据类型指的是存储的数据的类型,也就是 value 部分的类型,key 部分永远都是字符串。
string类型
1.存储的数据:单个数据,最简单的数据存储类型,也是最常用的数据存储类型
string,他就是存一个字符串儿,注意是value那一部分是一个字符串,它是redis中最基本、最简单的存储数据的格式。
2.存储数据的格式:一个存储空间保存一个数据
每一个空间中只能保存一个字符串信息,这个信息里边如果是存的纯数字,他也能当数字使用,我们来看一下,这是我们的数据的存储空间。
3.存储内容:通常使用字符串,如果字符串以整数的形式展示,可以作为数字操作使用
一个key对一个value,当然它也可以是一个纯数字的格式
string 类型数据的基本操作
添加/修改数据添加/修改数据
set key value
获取数据
get key
删除数据
del key
判定性添加数据
setnx key value
#SET if Not eXists (大写组成命令)
添加/修改多个数据
mset key1 value1 key2 value2 …
#m:Multiple 多个
获取多个数据
mget key1 key2 …
获取数据字符个数(字符串长度)
strlen key
#STRing LENgth
追加信息到原始信息后部(如果原始信息存在就追加,否则新建)
append key value
string 类型数据的扩展操作
分成两大块:一块是对数字进行操作的,第二块是对我们的key的时间进行操作的
设置数值数据增加指定范围的值
incr key #类似于i++
incrby key increment #相当于i+n
incrbyfloat key increment #可以操作小数
#increment 增加
设置数值数据减少指定范围的值
decr key #类似于i--
decrby key increment #相当于i-n
#decrement 减少
设置数据具有指定的生命周期
setex key seconds value ***
psetex key milliseconds value
#expire : 有效期,期限
string 类型数据操作的注意事项
1.数据操作不成功的反馈与数据正常操作之间的差异
表示运行结果是否成功 : 例如setnx
(integer) 0 → false 失败
(integer) 1 → true 成功
表示运行结果值:例如获取数据长度 strlen
(integer) 3 → 3 3个
(integer) 1 → 1 1个
2.数据未获取到时,对应的数据为(nil),等同于null
3.数据最大存储量:512MB
4.string在redis内部存储默认就是一个字符串,当遇到增减类操作incr,decr时会转成数值型进行计算
注意:redis虽然可以存储数字,但是数字在内部存储时依然是字符串类型
5.按数值进行操作的数据,如果原始数据不能转成数值,或超越了redis 数值上限范围,将报错
上限是:9223372036854775807(也就是java中Long型数据最大值,Long.MAX_VALUE)
6.redis所有的操作都是原子性的,采用单线程处理所有业务,命令是一个一个执行的,因此无需考虑并发带来的数据影响
string应用场景与key命名约定
它的应用场景在于:主页高频访问信息显示控制,例如新浪微博大V主页显示粉丝数与微博数量
解决方案
1.在redis中为大V用户设定用户信息,以用户主键和属性值作为key,后台设定定时刷新策略即可
#eg就是例子的意思
eg: user:id:3506728370:fans → 12210947
eg: user:id:3506728370:blogs → 6164
eg: user:id:3506728370:focuses → 83
这个用户的id为3506728370,这个大v存储了blogs和fans俩信息,分开存储
2.也可以使用json格式保存数据
eg: user:id:3506728370 → {“fans”:12210947,“blogs”:6164,“ focuses ”:83 }
key 的设置约定
数据库中的热点数据key命名惯例:由表名:主键名:主键值:字段名,作为key名
表名 | 主键名 | 主键值 | 字段名 | |
---|---|---|---|---|
eg1: | order | id | 29437595 | name |
eg2: | equip | id | 390472345 | type |
eg3: | news | id | 202004150 | title |
3.hash数据类型
对象类数据的存储如果具有较频繁的更新需求操作会显得笨重
比如说前面我们用以上形式存了数据,如果我们用单条去存的话,它存的条数会很多
但如果我们用json格式,它存一条数据就够了
问题来了,假如说现在粉丝数量发生变化了,你要把整个值都改了
但是用单条存的话就不存在这个问题,你只需要改其中一个就行了
我们使用field字段来解决
hash的结构是:key:{field:value,field2:value2}
在redis中的hash的值,可以理解为是一个对
hash类型
新的存储需求:对一系列存储的数据进行编组,方便管理,典型应用存储对象信息
需要的存储结构:一个存储空间保存多个键值对数据
hash类型:底层使用哈希表结构实现数据存储
这种结构叫做hash,左边一个key,对右边一个存储空间。这里要明确一点,右边存储空间叫hash,也就是说hash是指的一个数据类型,他指的不是一个数据,是这里边的一堆数据,那么它底层呢,是用hash表的结构来实现的
如果field数量较少,存储结构优化为类数组结构
如果field数量较多,存储结构使用HashMap结构
hash 类型数据的基本操作
添加/修改数据
hset key field value
#h:hash
获取数据
hget key field
hgetall key
删除数据
hdel key field1 [field2]
#可以删除多个field,空格分隔即可
设置field的值,如果该field存在则不做任何操作
hsetnx key field value
添加/修改多个数据
hmset key field1 value1 field2 value2 …
获取多个数据
hmget key field1 field2 …
获取哈希表中字段的数量
hlen key
获取哈希表中是否存在指定的字段
hexists key field
hash 类型数据的拓展操作
获取哈希表中所有的字段名或字段值
hkeys key
hvals key
设置指定字段的数值数据增加指定范围的值
hincrby key field increment
hincrbyfloat key field increment
hash类型数据操作的注意事项
1.hash类型中value只能存储字符串,不允许存储其他数据类型,不存在嵌套现象。如果数据未获取到,对应的值为(nil)
2.每个 hash 可以存储 (2的32次方 - 1) 个键值对
3.hash类型十分贴近对象的数据存储形式,并且可以灵活添加删除对象属性。但hash设计初衷不是为了存储大量对象而设计 的,切记不可滥用,更不可以将hash作为对象列表使用
4.hgetall 操作可以获取全部属性,如果内部field过多,遍历整体数据效率就很会低,有可能成为数据访问瓶颈
hash应用场景
双11活动日,销售手机充值卡的商家对移动,联通,电信的30元,50元,100元商品推出抢购活动,每种商品抢购上线1000张
以商家id为key
将参与抢购的商品id作为field
将参与抢购的商品数量作为对应的value
抢购时使用降值的方式控制产品数量
hmset id:001 c30 1000 c50 1000 c100 1000
hincrby id:001 c50 -2
hincrby id:001 c30 -5
hincrby id:001 c100 -10
注意:实际业务中还有超卖等实际问题
4.list数据类型
前面我们存数据的时候呢,单个数据也能存,多个数据也能存
但是这里面有一个问题,我们存多个数据用hash的时候它是没有顺序的
我们平时操作,实际上数据很多情况下都是有顺序的,那有没有一种能够用来存储带有顺序的这种数据模型呢
list就可以实现
list类型
数据存储需求:存储多个数据,并对数据进入存储空间的顺序进行区分
需要的存储结构:一个存储空间保存多个数据,且通过数据可以体现进入顺序
list类型:保存多个数据,底层使用双向链表存储结构实现
顺序表:想要插入cnpc,需要将后边的元素都向后移动,比较麻烦
链表:想要插入cnpc,需要将头指针和huawei的链条断开,然后重新连接
链表的形式,插入较高效,就是查询比较慢
双向链表:它的链条是双向的
但是查询也是高效的,查询可以双向查询
虽然查询alibaba也是从头开始查询,但是如果这时再查询tencent,就可以反向直接查询到
list里边存的这个东西是个列表,他有一个对应的名称。就是key存一个list的这样结构
因为它是双向的,所以他左边右边都能操作,它对应的操作结构两边都能进数据。这就是链表的一个存储结构
往外拿数据的时候怎么拿呢?通常是从一端拿,当然另一端也能拿
如果两端都能拿的话,这就是个双端队列,两边儿都能操作。如果只能从一端进一端出,这个模型叫做栈
list 类型数据基本操作
添加/修改数据
lpush key value1 [value2] ……
rpush key value1 [value2] ……
#l:left
#r:right
获取数据:因为列表存储的数据有顺序,所以可以通过索引来获取
lrange key start stop # range:范围,查询某个范围的数据。stop如果写-1,意味着直接查询所有
lindex key index #index:索引,查询某个索引的数据
llen key
获取并移除数据:删除之后会返回被删除的数据
lpop key #左侧删除末尾数据(删除最左侧的数据)
rpop key #右侧删除末尾数据(删除最右侧的数据)
list 类型数据的扩展操作
移除指定数据:不返回删除的数据
lrem key count value
#rem remove移除
#count 可以删除多个,如果list中存储了俩a,就可以是 lrem list1 2 a
规定时间内获取并移除数据:规定时间内取数据,能取到就返回,取不到就返回nil
blpop key1 [key2] timeout
brpop key1 [key2] timeout
brpoplpush source destination timeout
#b:block:阻塞,块
list 类型数据操作注意事项
1.list中保存的数据都是string类型的,数据总容量是有限的,最多 (2的32次方- 1) 个元素(4294967295)。
2.list具有索引的概念,但是操作数据时通常以队列的形式进行入队出队操作,或以栈的形式进行入栈出栈操作
3.获取全部数据操作结束索引设置为-1
4.list可以对数据进行分页操作,通常第一页的信息来自于list,第2页及更多的信息通过数据库的形式加载
list应用场景
企业运营过程中,系统将产生大量的运营数据,如何保障多台服务器操作日志的统一顺序输出
依赖list的数据具有顺序的特征对信息进行管理
使用队列模型解决多路径汇总合并的问题
使用栈模型解决最新消息的问题
rpush logs a:out
rpush logs b:out
rpush logs a:print
rpush logs c:in
lrange logs 0 -1
5.set数据类型
set类型
新的存储需求:存储大量的数据,在查询方面提供更高的效率
需要的存储结构:能够保存大量的数据,高效的内部存储机制,便于查询
set类型:与hash存储结构完全相同,仅存储field,不存储值(存储的值都是nil),并且field是不允许重复的
set类型数据的基本操作
添加数据
sadd key member1 [member2]
获取全部数据
smembers key
#s:set
#members:成员,set集合中每一个元素叫做成员
删除数据
srem key member1 [member2]
获取集合数据总量
scard key
判断集合中是否包含指定数据
sismember key member
#ismember:是成员么,是集合中的成员么
随机获取集合中指定数量的数据
srandmember key [count]
#rand:random随即
随机获取集中的某个数据并将该数据移除集合
spop key [count]
set 类型数据的扩展操作
求两个集合的交、并、差集
sinter key1 [key2 …] #intersection : 交叉,交集
sunion key1 [key2 …] # union :联合
sdiff key1 [key2 …] # difference:不同,差别
求两个集合的交、并、差集并存储到指定集合中
sinterstore destination key1 [key2 …]
sunionstore destination key1 [key2 …]
sdiffstore destination key1 [key2 …]
# store:存储
# destination:目的
将指定数据从原始集合中移动到目标集合中
smove source destination member
#move:移动
#source:源
set 类型数据操作的注意事项
set 类型不允许数据重复,如果添加的数据在 set 中已经存在,将只保留一份
set 虽然与hash的存储结构相同,但是无法启用hash中存储值的空间