欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

非关系型redis数据库

程序员文章站 2022-04-11 09:41:43
...

redis 简介

NoSQL(NoSQL = Not Only SQL ),意为“不仅仅是SQL”,泛指非关系型的数据库。 NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应 用难题,包括超大规模数据的存储。
Redis(Remote Dictionary Server)远程字典数据服务的缩写,由意大利 人开发的是一款内存高速缓存数据库。使用ANSI C语言编写、支持网络、可基于内 存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API并提供多种语言 的 API的非关系型数据库。
数据加载速度:硬盘< 内存< Cache
缓存有两种类型:
• 页面缓存经常会用在CMS(content management system)里面。
• 数据缓存经常会用在页面的具体数据里面。
如果数据在短时间内不会发生变化,且频繁被访问, 为 了提高用户的请求速度和降低网站的负载, 将数据放到一个读取速度更快的介质上,称 为数据缓存。该介质可以是文件、数据库、内存。内存经常用于数据缓存。
Redis和Memcache对比:
非关系型redis数据库
Redis持久化:
Redis 是一个内存数据库,与传统的MySQL,Oracle等关系型数据库直接将内容保存到硬盘 中相比,内存数据库的读写效率比传统数据库要快的多(内存的读写效率远远大于硬盘的读写 效率)。但是保存在内存中也随之带来了一个缺点,一旦断电或者宕机,那么内存数据库中的 数据将会全部丢失。
目标: 持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。 Redis 提供了两种持久化式:RDB(默认) 和AOF。
RDB:
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掉的话,就会丢失最后一次快照后 的所有修改(数据有丢失)。 • 工作原理: 当 redis 重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。
非关系型redis数据库
通过配置文件告诉 redis 我们想要通过 fsync 函数强制 os 写入到磁盘的时机。有三 种方式如下:
(默认是:每秒 fsync 一次), 通过BGREWRITEAOF指令压缩/优化命令
appendonly yes //启用 aof 持久化方式 //收到写命令就立即写入磁盘,最慢,但是保证完全的持久化
appendfsync always //每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中
appendfsync everysec //完全依赖 os,性能最好,持久化没保证
# appendfsync no
Redis

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

redis的优点:

  • 数据存储内存中,做缓存操作,先在缓存中查找数据,缓存没有再去硬盘查找。

  • 数据持久化:查找在内存中查看,硬盘也保存一份。

  • 支持多种数据类型、主从模式、高可用、value最大存储1G

redis 安装

  • linux下的安装(拥有redis的安装包):
tar  xf 安装包
cd redis-5.0.5
make #编译
make install #安装
cd utils/
./install_server.sh #执行脚本
ps -A | grep redis
redis-cli #客户端登陆redis服务端口6379
# (此时redis服务端已经带开,如果没打开执行:redis-server 启动redis服务)
  • windows下的安装(拥有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 
  • pycharm 连接redis
    Terminal中:
    pip install redis
    import redis

Redis内置数据类型

非关系型redis数据库
非关系型redis数据库

redis应用场景

非关系型redis数据库

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 #查看

小案例: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

小案例:生成给用户发送的验证码,验证码限制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

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次

本机连接另一台主机的redis库

本机:172.25.254.18
另一台主机:172.25.254.12
设置步骤如下:
172.25.254.12设置redis配置信息:
cd /etc/redis/6379.conf #进入redis的配置文件中修改信息
bind 0.0.0.0 #任何IP都可以链接12主机的redis库
protected-mode no
保存退出
cd
redis-server /etc/redis/6379.conf
#以/etc/redis/6379.conf文件 打开redis
172.25.254.18测试:
redis-cli -h 172.25.254.12 #登陆12的redis

python与redis

交互一次的用法:pipline
缓冲多条命令,然后一次性执行,提高效率


redis_client = redis.StrictRedis(host='127.0.0.1', port=6379)
pipe = redis_client.pipeline()
pipe.set('name', 'westos')
pipe.set('name', 'westos')
pipe.set('name', 'westos')
pipe.set('name', 'westos')
pipe.set('name', 'westos')
pipe.execute()
print(redis_client.get('name'))

#执行结果
b'westos'

封装
• 连接redis服务器部分是一致的
• 将string类型的读写进行封装

邮件信息传递工作原理
SMTP协议: Simple Mail Transfer Protocol, 是一种提供可靠且有效的电子邮件传输的协议。SMTP建立 在FTP文件传输服务上的一种邮件服务,主要用于系统之间的邮件信息传递,并提供有关来信的通知。 POP3协议: Post Office Protocol - Version 3, 主要用于支持使用客户端远程管理在服务器上的电子邮 件。
用户读取邮件使用的协议:POP3
非关系型redis数据库

import smtplib
from email.mime.text import MIMEText
from email.utils import formataddr
# 设置服务器,用户名、口令以及邮箱的后缀
smtp_server = "smtp.163.com"
from_username = '腾讯云服务中心'
mail_user = "aaa@qq.com"
#开启smtp的授权码
mail_password ='scq123'
#邮件主题前缀
mail_prefix = "[运维开发部]-"
def send_mail(to_addrs, subject,msg):
   """
  发送邮件
  :param to_addrs: 邮件接收人
  :param subject: 邮件标题
  :param content: 邮件正文内容
  :return: Bool
  """
   # msg = MIMEText(content)
   # 创建一个带附件的实例
   try:
       msg = MIMEText(msg) #将要发送的文本信息做MINME封装
       # 将消息与发件人、地址、主题绑定到一起
       msg['From'] = formataddr([from_username, mail_user]) #将mail_user格式化为rom_username,qq接收端不显示原地址名
       msg['To'] = to_addrs
       msg['Subject'] = mail_prefix + subject
        #实例化smtp对象
       server = smtplib.SMTP()
       # 连接邮件服务器 163->qq
       server.connect(smtp_server)
       # 登录
       server.login(mail_user, mail_password)
       # 发送邮件内容
       server.sendmail(mail_user, to_addrs, msg.as_string())
       # 关闭连接
       server.quit()
   except Exception as  e:
       print(str(e))
       return False
   else:
       return True

if __name__ == '__main__':
    send_mail('aaa@qq.com', '寒假作业', '真正的勇士,敢于直面惨淡的人生,敢于正视淋漓的鲜血')  
     #mag不可以无厘头,否则发不出去
    print("发送成功.....")
相关标签: python