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:orderid29437595name
eg2:equipid390472345type
eg3:newsid202004150title

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中存储值的空间