Redis

目录

NoSQL

一、什么是NoSQL

二、NoSQL 的起源

问题 1:不能满足高性能查询需求

问题 2:应用程序规模的变大

三、NoSQL 的使用

四、常见的 NoSQL 及区别

1、常见的 NoSQL 数据库

2、区别

Redis

一、Redis 简介

二、Redis 的应用场景

三、下载安装与配置

1、下载 redis的压缩包

2、安装进入 redis 解压目录,执行 make 命令编译安装

3、启动 redis

4、修改配置文件

修改 redis.conf 文件 

设置后台启动

设置密码

设置远程连接

启动 redis

连接redis

关闭 redis

配置服务启动(使用 systemctl 的方法)

远程连接

简单操作 

四、Key

五、常见的数据类型

1、string类型

1)、简介

2)、常用命令

3)、数据结构

2、list类型

1)、简介

2)、常用命令

3)、数据结构

3、hash类型

1)、简介

2)、常用命令

3)、数据结构

4、set类型

1)、简介

2)、常用命令

3)、数据结构

5、zset类型(Sorted set )

1)、简介

2)、常用命令

3)、数据结构 

六、各数据的使用场景


NoSQL

一、什么是NoSQL

  NoSQL 是 Not Only SQL 的缩写,意即"不仅仅是 SQL"的意思,泛指非关系型的数据库。强调 Key-Value Stores 和文档数据库的优点。

NoSQL 产品是传统关系型数据库的功能阉割版本,通过减少用不到或很少用的功能,来大幅度提高产品性能

  • 不遵循 SQL 标准。 (添加 insert 修改 update )
  • 不支持 ACID。
  • 远超于 SQL 的性能。

二、NoSQL 的起源

过去,关系型数据库(SQL Server、Oracle、MySQL)是数据持久化的唯一选择,但随着发展,关系型数据库存在以下问题。

问题 1:不能满足高性能查询需求

我们使用:Java、.Net 等语言编写程序,是面向对象的。但用数据库都是关系型数据库。存储结构是面向对象的,但是数据库却是关系的,所以在每次存储或者查询数据时,我们都需要做转换。类似 Hibernate、Mybatis 这样的 ORM 框架确实可以简化这个过程,但是在对高性能查询需求时,这些 ORM 框架就捉襟见肘了。

问题 2:应用程序规模的变大

网络应用程序的规模变大,需要储存更多的数据、服务更多的用户以及需求更多的计算能力。为了应对这种情形,我们需要不停的扩展。

扩展分为两类:一种是纵向扩展,即购买更好的机器,更多的磁盘、更多的内存等等。另一种是横向扩展,即购买更多的机器组成集群。在巨大的规模下,纵向扩展发挥的作用并不是很大。首先单机器性能提升需要巨额的开销并且有着性能的上限,在 Google 和 Facebook 这种规模下,永远不可能使用一台机器支撑所有的负载。鉴于这种情况,我们需要新的数据库,因为关系数据库并不能很好的运行在集群上

三、NoSQL 的使用

  • 对数据高并发的读写
  • 海量数据的读写
  • 对数据高可扩展性的

例如:秒杀活动

NoSQL 不适用场景

  • 需要事务支持
  • 基于 sql 的结构化查询存储,处理复杂的关系,需要关系查询。

用不着 sql 的和用了 sql 也不行的情况,考虑用 NoSql

四、常见的 NoSQL 及区别

1、常见的 NoSQL 数据库

2、区别

1)、Memcached

  • 很早出现的 NoSql 数据库
  • 数据都在内存中,一般不持久化
  • 支持简单的 key-value 模式,支持类型单一
  • 一般是作为缓存数据库辅助持久化的数据库(MySQL)

2)、Redis

  • 几乎覆盖了 Memcached 的绝大部分功能
  • 数据都在内存中,支持持久化,主要用作备份恢复
  • 除了支持简单的 key-value 模式,还支持多种数据结构的存储,比如 list、set、hash、zset 等。
  • 一般是作为缓存数据库辅助持久化的数据库

3)、MongoDB

  • 高性能、开源、模式自由(schema free)的文档型数据库
  • 数据都在内存中, 如果内存不足,把不常用的数据保存到硬盘
  • 虽然是 key-value 模式,但是对 value(尤其是 json)提供了丰富的查询功能
  • 支持二进制数据及大型对象
  • 可以根据数据的特点替代 RDBMS,成为独立的数据库。或者配合 RDBMS,存储特定的数


Redis

官网文档

Documentation | RedisWelcome to the Redis documentation.icon-default.png?t=N7T8https://redis.io/docs/

一、Redis 简介

  • Redis 是一个开源的 key-value 存储系统。
  • 和 Memcached 类似,它支持存储的 value 类型相对更多,包括 string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和 hash(哈希类型)。
  • 这些数据类型都支持 push/pop、add/remove 及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。
  • 在此基础上,Redis 支持各种不同方式的排序。
  • 与 memcached 一样,为了保证效率,数据都是缓存在内存中。
  • 区别的是 Redis 会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件。
  • 并且在此基础上实现了 master-slave(主从)同步。

二、Redis 的应用场景

1、数据缓存(提高访问性能)

查询概率》》 增删改的概率

将一些数据在短时间之内不会发生变化,而且它们还要被频繁访问,为了提高用户的请求速度和降低网站的负载,降低数据库的读写次数,就把这些数据放到缓存中。

2、会话缓存

session cache,主要适用于 session 共享 (string 类型)

3、排行榜/计数器

(NGINX+lua+redis 计数器进行 IP 自动封禁)(zset)

4、消息队列

(构建实时消息系统,聊天,群聊) (list)

5、粉丝

用于存储对象 (hash)

PS:

string :会话信息

list:消息

set:粉丝 共同好友

zset :排行榜

hash: 存储对象

三、下载安装与配置

1、下载 redis的压缩包

wget https://download.redis.io/releases/redis-5.0.14.tar.gz

安装的时候先安装 redis 所依赖的环境

yum -y install gcc-c++

解压 redis

tar -zxvf redis-5.0.14.tar.gz

2、安装进入 redis 解压目录,执行 make 命令编译安装

make && make install 

make PREFIX=/usr/redis install (如果不加prefix 默认安装到/usr/local下面)

(如果命令执行不成功,换为 make install PREFIX=/usr/redis )

安装成功之后查看redis在哪里安装

which redis-server

3、启动 redis

进入安装目录(/usr/local/bin),并启动 redis

出现上图

即为安装成功

redis 启动成功,但是这种启动方式需要一直打开窗口,不能进行其他操作,不太方便。

按 ctrl + c 可以关闭窗口

4、修改配置文件

修改 redis.conf 文件 

拷贝配置文件到安装目录的 bin 下

daemonize [ˈdiməˌnaɪz]

redis.conf (136)文件将里面的 daemonize no 改成 yes #设置后台启动

设置后台启动

no 改为 yes #如果不想设置后台启动就不改

设置密码

requirepass yyl #配置密码 如果需要 客户端连接的话需要设置密码 如果不需要连接就不要设置

设置远程连接

# bind 127.0.0.1 #注释掉绑定本机,才可以远程连接访问

启动 redis

./redis-server ./redis.conf

连接redis

./ redis-cli -a [password]

关闭 redis

./redis-cli shutdown

./redis-cli -p 6379 -a yyl -h 127.0.0.1 shutdown

配置服务启动(使用 systemctl 的方法)

服务启动的时候 daemonize 改为 no

在/lib/systemd/system 目录下创建一个脚本文件 redis.service,里面的内容如下:

[Unit]
Description=Redis
After=network.target
[Service]
ExecStart=/usr/redis/bin/redis-server /usr/redis/bin/redis.conf 
ExecStop=/usr/redis/bin/redis-cli -h 127.0.0.1 -p 6379 -a yyl shutdown
[Install]
WantedBy=multi-user.target

刚刚配置的服务需要让 systemctl 能识别,就必须刷新配置

systemctl daemon-reload   #刷新配置
systemctl enable redis   #开机自启
systemctl status redis   #redis 状态
systemctl start redis    #开启 redis
systemctl stop redis   #关闭 redis
systemctl disable redis   #禁止开机自启

远程连接

redis-cli -h host -p port -a password   #远程连接 redis 服务

简单操作 

ping 测试连接

quit 关闭连接(connection)

auth 简单密码认证

查询数据库一共有多少:

config get databases

选中某一个数据库

select [index] 

设值,取值

set [key] [value] 

get [key] 

获取所有的 key

keys * 

四、Key

默认 16 个数据库,类似数组下标从 0 开始,初始默认使用 0 号库

dbsize   #查看当前数据库的 key 的数量

keys *    #获得所有key

flushdb    #清空当前库

flushall    #通杀全部库

select 0    #选择下标为0的库

move key 1    #将当前的数据库 key 移动到某个数据库,目标库有,则不能移动

randomkey    #从当前数据库中随机返回

type key    #类型

del key    #删除 key

exists key    #判断是否存在 key

expire key 10    #为给定的key设置过期时间 单位是秒

pexpire key 1000    #给定的key设置过期时间 单位:毫秒

persist key    #删除key的过期时间

ttl key    #查看还有多少秒过期,-1 表示永不过期,-2 表示已过期

五、常见的数据类型

1、string类型

1)、简介

String是Redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。

String类型是二进制安全的。意味着Redis的string可以包含任何数据。比如jpg图片或者序列化的对象。

String类型是Redis最基本的数据类型,一个Redis中字符串value最多可以是512M

2)、常用命令

set   <key><value>添加键值对 
    *NX:当数据库中key不存在时,可以将key-value添加数据库
    *XX:当数据库中key存在时,可以将key-value添加数据库,与NX参数互斥

    *EX:key的超时秒数
    *PX:key的超时毫秒数 
示例: set name cxx 

设值取值

--设值:

setex  <key><过期时间><value>  #设置键值的同时,设置过期时间,单位秒。
# set key val EX 80 
# setex key 80 val

 setnx key value   #不存在就插入(not exists)
# set key val NX    

-- 取值:
 get   <key>   #查询对应键值   
 示例:get name

 getset <key> <value>   #以新换旧,设置了新值同时获得旧值。
   示例: getset name new_cxx  #给 name 的 value 设置新值,返回旧值

批量操作

mset key1 key2   #批量设置key   
msetnx <key1> <value1> <key2> <value2>  .....   #同时设置一个或多个 key-value 对,当且 仅当所有给定 key 都不存在 如果有一个存在就会不成功。
  注意:有一个失败则都失败 

 mget key1 key2   #批量获取

setrange  <key><起始位置index><value>    #从 index 开始替换 value
getrange  <key><起始位置><结束位置>  
getrange name 0 -1    #字符串分段   0 -1 是全部   0 -2  ==n-1

append  <key><value>    #将给定的<value> 追加到原值的末尾
strlen  <key>    #获得值的长度

递增递减

incr  <key> 
   #将 key 中储存的数字值增1
   #只能对数字值操作,如果为空,新增值为1
   #示例:incr age 
decr  <key>
   #将 key 中储存的数字值减1
   #只能对数字值操作,如果为空,新增值为-1
   #示例:decr age #递减
incrby / decrby  <key><步长>

   #将 key 中储存的数字值增减。自定义步长。   
   #示例: incrby age 10 递增
   #示例: decrby age 10 递减

原子性操作

所谓原子操作是指不会被线程调度机制打断的操作;

这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个线程)。

(1)在单线程中, 能够在单条指令中完成的操作都可以认为是"原子操作",因为中断只能发生于指令之间。

(2)在多线程中,不能被其它进程(线程)打断的操作就叫原子操作。

Redis单命令的原子性主要得益于Redis的单线程。

3)、数据结构

String的数据结构为简单动态字符串(Simple Dynamic String,缩写SDS)。是可以修改的字符串,内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配.

如图中所示,内部为当前字符串实际分配的空间capacity一般要高于实际字符串长度len。当字符串长度小于1M时,扩容都是加倍现有的空间(2倍),如果超过1M,扩容时一次只会多扩1M的空间。需要注意的是字符串最大长度为512M。

2、list类型

1)、简介

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。

2)、常用命令

添加值

lpush stulist zs ls

lpush/rpush  <key><value1><value2><value3> ....   #从左边/右边插入一个或多个值。
lpop/rpop  <key>  #从左边/右边吐出一个值。值在键在,值光键亡。
 
rpoplpush  <key1><key2> 从<key1>   #列表右边吐出一个值,插到<key2>列表左边。

取值:

lrange <key> <start> <stop>
  #按照索引下标获得元素(从左到右)
  #示例: lrange mylist 0 -1  
  #0左边第一个,-1右边第一个,(0 -1表示获取有)

lindex <key> <index>   #按照索引下标获得元素(从左到右)


llen <key>   #获得列表长度 


linsert <key>  <before/after> <value> <newvalue> 

#在<value>的后面插入<newvalue>插入值

lrem <key> <n> <value>

   #从左边删除n个对应的value值(从左到右)
   #示例: lrem k3 3 "test" #从左边开始删除k3里面的3个“test”


lset<key> <index> <value>  #将列表key下标为index的值替换成value

3)、数据结构

List的数据结构为快速链表quickList。

首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表。

(它将所有的元素紧挨着一起存储,分配的是一块连续的内存)。

当数据量比较多的时候才会改成quicklist。

因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是int类型的数据,结构上还需要两个额外的指针prev和next。

Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。

3、hash类型

1)、简介

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

类似Java里面的Map<String,Object>

用户ID为查找的key,存储的value用户对象包含姓名,年龄,生日等信息,如果用普通的key/value结构来存储

主要有以下2种存储方式:

通过第三种方式:( key(用户ID) + field(属性标签)) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题

2)、常用命令

hset <key> <field> <value> 

   #给<key>集合中的  <field>键赋值<value>

hget <key1> <field>   

   #从<key1>集合<field>取出 value 

hmset <key1> <field1> <value1> <field2> <value2>...

   #批量设置hash的值

hexists<key1><field>

   #查看哈希表 key 中,给定域 field 是否存在。 
   #示例:hexists hhash username 

hkeys <key>

   #列出该hash集合的所有field
   #示例:hkeys hhash  

hvals <key>

   #列出该hash集合的所有value
   #示例:hvals hhash 

hincrby <key> <field> <increment>

   #为哈希表 key 中的域 field 的值加上增量 1   -1
   #示例: hincrby hhash age -12

hsetnx <key><field><value>

   #将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在
   #示例: hsetnx hhash id 100

3)、数据结构

Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。

ZipList 是一种特殊的“双端链表” ,由一系列特殊编码的连续内存块组成。可以在任意一端进行压入/弹出操作

entry,节点占用字节不固定(按需分配、节省内存)

ZipListEntry

ZipList 中的Entry并不像普通链表那样记录前后节点的指针,因为记录两个指针要占用16个字节,浪费内存。而是采用了下面的结构:

  • previous_entry_length:前一节点的长度,占1个或5个字节。

    如果前一节点的长度小于254字节,则采用1个字节来保存这个长度值

   如果前一节点的长度大于254字节,则采用5个字节来保存这个长度值,第一个字节为0xfe,后        四个字节才是真实长度数据

  • encoding:编码属性,记录content的数据类型(字符串还是整数)以及长度,占用1个、2个或 5个字节
  • contents:负责保存节点的数据,可以是字符串或整数

ZipListEntry中的encoding编码分为字符串和整数两种:

字符串: 如果encoding是以“00”、“01”或者“10”开头,则证明content是字符串

整数: 如果encoding是以“11”开始,则证明content是整数,且encoding固定只占用1个字节

节省内存但遍历有一定缺陷,只能从前向后或者从后向前,使用时对节点个数会有一定限制

4、set类型

1)、简介

set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

2)、常用命令

sadd <key> <value1> <value2> ..... 
   #将一个或多个 member 元素加入到集合 key 中,已经存在的 member 元素将被忽略

smembers <key>

   #取出该集合的所有值。

sismember <key> <value> 

   #判断集合<key>是否为含有该<value>值,有1,没有0
  
scard <key> 

   #返回该集合的元素个数。

srem <key> <value1> <value2> ....

   #删除集合中的某个元素。

spop <key> <count> 

   #随机从该集合中吐出count个值。会从集合中删除数据

srandmember <key> <n>

   #随机从该集合中取出n个值。不会从集合中删除 。

smove <source> <destination> <value> 

   #把集合中一个值从一个集合移动到另一个集合

    
sinter <key1> <key2>

   #返回两个集合的交集元素。

sunion <key1> <key2>

   #返回两个集合的并集元素。

sdiff <key1> <key2>

   #返回两个集合的差集元素(key1中的,不包含key2中的)

3)、数据结构

Set数据结构是dict字典,字典是用哈希表实现的。

Java中HashSet的内部实现使用的是HashMap,只不过所有的value都指向同一个对象。Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值。

5、zset类型(Sorted set )

1)、简介

Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。

不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了 。

因为元素是有序的, 所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。

访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。

2)、常用命令

zadd  <key> <score1> <value1> <score2> <value2>…

   #将一个或多个 member 元素及其 score 值加入到有序集 key 当中。

zrange <key> <start> <stop>  [WITHSCORES]   
   #返回有序集 key 中,下标在<start><stop>之间的元素
   #带WITHSCORES,可以让分数一起和值返回到结果集。

zrangebyscore <key> <min> <max> [withscores] [limit offset count]
   #返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员。有序集成员按 score 值递增(从小到大)次序排列。 
   #示例:zrangebyscore tzset 3 4 limit 0 2

zrevrangebyscore <key> <max> <min> [withscores] [limit offset count]               
   #同上,改为从大到小排列。 

zincrby <key> <increment> <value>     

   #为元素的score加上增量

zrem  <key> <value> 

   #删除该集合下,指定值的元素 

zcount <key> <min> <max>

   #统计该集合,分数区间内的元素个数 

zrank <key> <value>

   #返回该值在集合中的排名,从0开始。

3)、数据结构 

SortedSet(zset)是Redis提供的一个非常特别的数据结构,一方面它等价于Java的数据结构Map<String, Double>,可以给每一个元素value赋予一个权重score,另一方面它又类似于TreeSet,内部的元素会按照权重score进行排序,可以得到每个元素的名次,还可以通过score的范围来获取元素的列表。

zset底层使用了两个数据结构

(1)hash,hash的作用就是关联元素value和权重score,保障元素value的唯一性,可以通过元素value找到相应的score值。

(2)跳跃表,跳跃表的目的在于给元素value排序,根据score的范围获取元素列表。

对比有序链表和跳跃表,从链表中查询出51

数据结构之跳表_跳表几级-CSDN博客文章浏览阅读581次。跳跃表跳表全称叫做跳跃表,简称跳表。跳表是一个随机化的数据结构,实质是一种可以进行二分查找的有序链表。跳表在原有的有序链表上增加了多级索引,通过索引来实现快速查询。跳表不仅能提高搜索性能,同时也可以提高插入和删除操作的性能。跳表思路分析如上图所示,原始链表的节点分别是1、3、4、5、7、8、9、10、13、16、17、18。现在有个需求,想快速的找到节点10,最直接的方式就是依次遍历节点1、3、4、5、7、8、9、10。为了提高链表的查找效率,我们可以从链表每2个节点提出一个节点,做为索引节点,通_跳表几级https://blog.csdn.net/qq100344/article/details/115436548

有序链表与跳跃表 

(1) 有序链表

要查找值为51的元素,需要从第一个元素开始依次查找、比较才能找到。共需要6次比较。

(2) 跳跃表

从第2层开始,1节点比51节点小,向后比较。

41节点比51节点小,继续向后比较,后面就是NULL了,所以从41节点向下到第1层

在第1层,41节点比51节点小,继续向后,61节点比51节点大,所以从61向下

在第0层,51节点为要查找的节点,节点被找到,共查找4次。

六、各数据的使用场景

类型

简介

特性

场景

String(字符串)

二进制安全

可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512M

---

Hash(字典)

键值对集合,即编程语言中的Map类型

适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值(Memcached中需要取出整个字符串反序列化成对象修改完再序列化存回去)

存储、读取、修改用户属性

List(列表)

链表(双向链表)

增删快,提供了操作某一段元素的API

1、最新消息排行等功能(比如朋友圈的时间线) 2、消息队列

Set(集合)

哈希表实现,元素不重复

1、添加、删除、查找的复杂度都是O(1) 2、为集合提供了求交集、并集、差集等操作

1、共同好友 2、利用唯一性,统计访问网站的所有独立ip 3、好友推荐时,根据tag求交集,大于某个阈值就可以推荐

Sorted Set(有序集合)

将Set中的元素增加一个权重参数score,元素按score有序排列

数据插入集合时,已经进行天然排序

1、排行榜 2、带权重的消息队列

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值