非关系型数据库Redis

僤鯓⒐⒋嵵緔 提交于 2020-01-19 17:59:09

非关系型数据库Redis

一、Redis简介

Redis参考资料:
Github 源码:https://github.com/antirez/redis
Redis 官网:https://redis.io/

1.Redis简介

NoSQL(NoSQL = Not Only SQL ),意为“不仅仅是SQL”,泛指非关系型的数据库。 NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。
Redis(Remote Dictionary Server),远程字典数据服务的缩写,由意大利 人开发的是一款内存高速缓存数据库。使用ANSI C语言编写、支持网络、可基于内 存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API并提供多种语言 的 API的非关系型数据库。

2.Redis是内存高速缓存数据库

在这里插入图片描述
缓存有两种类型:
• 页面缓存经常会用在CMS(content management system)里面。
• 数据缓存经常会用在页面的具体数据里面。
京东商城页面适合做数据缓存:如果数据在短时间内不会发生变化,且频繁被访问, 为 了提高用户的请求速度和降低网站的负载, 将数据放到一个读取速度更快的介质上,称 为数据缓存。该介质可以是文件、数据库、内存。内存经常用于数据缓存。

3.Redis的特性

(1)redis的优点:
数据存储内存中,做缓存操作,先在缓存中查找数据,缓存没有再去硬盘查找。
数据持久化:查找在内存中查看,硬盘也保存一份。
(2)Redis的特性:
支持多种数据类型、主从模式、高可用、value最大存储1G
• 速度快: 10w OPS 存在内存,使用c语言,单线程
持久化: 将数据的更新异步地保存在磁盘上,断电不丢失数据
• 支持多种编辑语言: JAVA PHP PYTHON RUBY LUA NODEJS
• 功能丰富: 发布订阅 LUA脚本 事务 pipeline(并发效率
• 简单: 不依赖外部库 单线程模型
• 支持多种数据结构: 字符串 hash 列表 集合 有序集合
(3)Redis和Memcache对比:
在这里插入图片描述

4.Redis持久化

(1)Redis 是一个内存数据库,与传统的MySQL,Oracle等关系型数据库直接将内容保存到硬盘 中相比,内存数据库的读写效率比传统数据库要快的多(内存的读写效率远远大于硬盘的读写 效率)。但是保存在内存中也随之带来了一个缺点,一旦断电或者宕机,那么内存数据库中的 数据将会全部丢失。
(2)目标: 持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。
(3)Redis 提供了两种持久化式:RDB(默认) 和AOF。
RDB
是Redis用来进行持久化的一种方式,是把当前内存中的数据集快照写入 磁盘,也就是 Snapshot 快照(数据库中所有键值对数据)。恢复时是将快 照文件直接读到内存里。 我们可以配置 redis在 n 秒内如果超过 m 个 key 被修改就自动做快照,
在这里插入图片描述
下面是默认的快照保存配置:
dbfilename dump.rdb # 持久化存储文件名为 dump.rdb
save 900 1 # 900 秒内如果超过 1 个 key 被修改,则发起快照保存
save 300 10 # 300 秒内容如超过 10 个 key 被修改,则发起快照保 存
save 60 10000 # 600 秒内容如超过 10000 个 key 被修改,则发起快照保存

AOF
• RDB 持久化存是一定时间内做一次备份,如果 redis意外down掉的话,就会丢失最后一次快照后 的所有修改(数据有丢失)。
• 持久化方式 AOF 则是当 redis 重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。
在这里插入图片描述

5.Redis架构模式:

主从复制
Redis 的复制(replication)功能允许用户根据一个 Redis 服务器来创建任意多个该 服务器的复制品,其中被复制的服务器为主服务器(master),而通过复制创建出来 的服务器复制品则为从服务器(slave)。 只要主从服务器之间的网络连接正常,主从 服务器两者会具有相同的数据,主服务器就会一直将发生在自己身上的数据更新同步 给 从服务器,从而一直保证主从服务器的数据相同。
特点: 1、master/slave 角色 2、master/slave 数据相同 3、降低 master 读压力在转交从库
问题: 1. 无法保证高可用 2. 没有解决 master 写的压力

二、Redis安装与配置

1.Redis的安装与部署(Linux)

  1. 首先上官网下载Redis 压缩包,地址 http://redis.io/download
    在这里插入图片描述

2.压缩包执行解压操作并进行编译

tar  xf 安装包
cd redis-5.0.5
make #编译
make install #安装
cd utils/
./install_server.sh #执行脚本
ps -A | grep redis  # 查看redis服务是否开启
redis-cli   #客户端登陆redis服务端口6379
# (此时redis服务端已经带开,如果没打开执行:redis-server 启动redis服务)
##当添加键值后,发现在当前运行的目录下,创建了一个文件:dump.rdb,这个文件用于将数据持久化存储

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3.配置
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
连接
在这里插入图片描述

2.windows下Redis的安装

(拥有redis的安装包):
1) 解压安装包到指定目录并添加到系统环境变量的Path中
2)windows power shell中在解压的安装包目录下执行:

#部署redis为windows下的服务 
.\redis-server --service-install redis.windows.conf  
#启动redis临时服务端
redis-server redis.windows.conf

另一个shell中

#客户端访问redis服务端
redis-cli.exe -h 127.0.0.1 -p 6379 

3.Redis的内置数据类型

• string 类型 是二进制安全的。可以包含任何数据(eg: jpg 图片或者序列化的对象)。 从内部实现来看其实 string 可以看作 byte 数组,最大上限是 1G 字节。
• hash类型 是一个 string 类型的 field 和 value 的映射表.它的添加、删除操作都是 O(1)(平均)。
• list类型 是一个 string 类型的双向链表。最大长度是(2的32次方 )。
• set 类型 是 string 类型的通过 hash table 实现的无序集合。添加、删除和查找的复 杂度都是 O(1)。最大长度是(2的32次方 )。
在这里插入图片描述

4.Redis的应用场景

在这里插入图片描述

5.Redis内置指令: http://doc.redisfans.com/

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

[kiosk@foundation37 ~]$ redis-cli
127.0.0.1:6379> LPUSH names name1 name2 name3
(integer) 3
127.0.0.1:6379> LRANGE names 0 3  # 它是一个列表,用LRANGE来获取
1) "name3"
2) "name2"
3) "name1"
127.0.0.1:6379> RPUSH names daliu
(integer) 4
127.0.0.1:6379> LRANGE names 0 4
1) "name3"
2) "name2"
3) "name1"
4) "daliu"
127.0.0.1:6379> RPUSH names daliu1 daliu2
(integer) 6
127.0.0.1:6379> LRANGE names
(error) ERR wrong number of arguments for 'lrange' command
127.0.0.1:6379> LRANGE names 0 5
1) "name3"
2) "name2"
3) "name1"
4) "daliu"
5) "daliu1"
6) "daliu2"
127.0.0.1:6379>
[kiosk@foundation37 ~]$

三、Redis编程

1.python实现redis数据库的连接操作

import redis
redis_client=redis.StrictRedis(host='127.0.0.1',port=6379) #实例化对象 客户端登陆redis
redis_client.mset({'name':'westos','age':10}) #同时设置键值对
name=redis_client.get('name').decode('utf-8')#将name键对应的value值为bits类型转为字符串类型
name_len=redis_client.strlen('name') #求name键对应的value值的长度
print('user name: ',name,'用户名称长度:',name_len)
redis_client.incr('age') #将年龄增加1岁
print('age: ',redis_client.get('age').decode('utf-8'))#将age键对应的value值为bits类型转为字符串类型


#执行结果:
user name:  westos 用户名称长度: 6
age:  11

2.Redis字符串常用操作

set age 2 # 字符串名为age  value值为2
get age # "2"  查看age对应的value值
set name fentiao
getrange name 0 3 #获取name键对应的value值索引在0-3的值 “fent”
setrange name 2 westos # 在name键对应的value值fentiao中索引为2处插入字符westos
append name -westos #给name键对应的value值fentiao追加-westos
mget #同时获取
mset #同时设置
strlen name #获取名字对应value长度
incr  age #增加年龄值 加1
get age #查看
incrgy age 10 #年龄每次增加10
decr age #年龄减少1
decrby age 10  #年龄减少10
getset name westos #westos有就获取没有就设置
get name #查看

案例:生成给用户发送的验证码,验证码限制3s内生成一次,3s内第二次则无法获取

import time
import string
import random
import redis
def send_msg(phone):
    """ 模拟给手机发送验证码"""
    num_list=random.sample(string.digits,4) #随机生成四个数字
    nums_code=''.join(num_list) #将随机生成的四个数字结合到一起
    print('%s验证码:%s'%(phone,nums_code))
    return nums_code #返回生成的验证码
def phone_code(phone):
    """3s后可以再次发送验证码"""
    client=redis.Redis() #实例化一个对象
    is_exist = client.exists(phone)
    #可以从缓存中查询验证码已经发送
    if is_exist:#如果从缓存中查询phone对应的值不为空,表示已经对phone生成一个验证码
        print('验证码发送频繁请稍后')
        return False #退出函数
    else:
        code=send_msg(phone) #电话传入生成验证码的函数中返回生成的验证码保存到code中
        client.set(phone,code,3)#将电话与对应的验证码放入redis缓存中。ex=3 表示在redis缓存中保存3s
        print('send ok')
if __name__ == '__main__':
    print('first send: ')
    phone_code('110')
    print('secend send: ')
    phone_code('110')
    time.sleep(4) #第二次发送完停留4s
    print('third send: ')
    phone_code('110')


#执行结果:
first send: 
110验证码:5103
send ok
secend send: 
验证码发送频繁请稍后
third send: 
110验证码:7628
send ok


3.Redis列表常用操作

LPUSH names name1,name2,name3 # :左边插入名为names元素为 name1,name2,name3的列表
LRANGE names 0 3 #查看列表索引0-3的值 
RPUSH #右边插入
LPOP #删除左边的元素并弹出删除的元素
RPOP  #删除右边的元素并弹出删除的元素
BLPOP names 10 #弹出左边的元素,当前列表为空会一直等待10s,如果等待10s还有没有元素就会退出
LPUSH westos #另一个terminal中插入westos,此时10s内 BLPOP names 10 会弹出左边的元素westos

案例:Redis做消息队列的应用

class RedisQueue(object):
    def __init__(self,name,**conf):
        import redis
        self.__client=redis.Redis(**conf)
        self.key=name
    def qsize(self):
        return self.__client.llen(self.key) #返回队列长度
    def put(self,item):
        """入队操作"""
        self.__client.rpush(self.key,item)#redis对scores列表插入元素item
    def get(self,timeout=5):
        """获取队头元素,如果没有到,等待时间为5s"""
        item=self.__client.blpop(self.key,timeout=timeout)
        return item
    def get_nowait(self):
        """获取队头元素,如果没有到,等待时间为0s"""
        item=self.__client.blpop(self.key) #blpop不写时间默认等待时间为0
        return item
if __name__ == '__main__':
    q=RedisQueue('scores') #实例化对象  在redis中传入列表名为scores
    for i in range(10):
        q.put(i) #对name为scores的列表放入元素i
    while True:
        result=q.get(timeout=5) #从左边获取列表的元素 并等待5s,看5s内是否有新的元素加入,有就打印出来。
        print(result)
        if not result:
            break


#执行结果:
(b'scores', b'0')
(b'scores', b'1')
(b'scores', b'2')
(b'scores', b'3')
(b'scores', b'4')
(b'scores', b'5')
(b'scores', b'6')
(b'scores', b'7')
(b'scores', b'8')
(b'scores', b'9')

案例:限制IP一分钟访问次数不能超过60次

def IP_limit(IP):
    """
    限制一分钟访问次数不能超过60次
    key:value= IP:count
    :param IP:
    :return:
    """
    import redis
    client=redis.StrictRedis()
    if client.exists(IP):
        count=client.get(IP) #value值赋给count
        if int(count) >= 60:
            print('%s访问频繁'%(IP))
        else:
            client.incr(IP) #访问次数加1
            print('%s +1'%(IP))
    else:
        client.set(IP,1,60) #IP在内存中保留60s
        print('%sfirst in: '%(IP))
if __name__ == '__main__':
    IP_limit('127.0.0.1') #向IP_limit函数传入一个IP表示访问一次
    for i in range(100):
        IP_limit('172.25.254.197') #172.25.254.197访问10次

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!