Redis(远程字典服务)

一、Redis简介

Redis(全称:Remote Dictionary Server 远程字典服务)是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志类型、Key-Value数据库,并提供多种语言的API。
在这里插入图片描述

1.定义

  • redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括sting(字符串)、list、set、zset(有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步
  • Redis 是一个高性能的key-value数据库。 redis的出现,很大程度补偿了memcached这类key/value存储的不足,在部 分场合可以对关系数据库起到很好的补充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客户端,使用很方便。
  • Redis 支持主从同步。数据可以从主服务器向任意数量的从服务器上同步,从服务器可以是关联其他从服务器的主服务器。这使得Redis可执行单层树复制。存盘可以有意无意的对数据进行写操作。由于完全实现了发布/订阅机制,使得从数据库在任何地方同步树时,可订阅一个频道并接收主服务器完整的消息发布记录。同步对读取操作的可扩展性和数据冗余很有帮助。
  • redis的官网地址,非常好记,是redis.io。(域名后缀io属于国家域名,是british Indian Ocean territory,即英属印度洋领地)
  • 目前,Vmware在资助着redis项目的开发和维护

2.NoSQL简介

NoSQL(NoSQL=Not Only SQL),意为‘不仅仅是SQL’,泛指非关系型的数据库。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。
在这里插入图片描述

3.特点

数据加载速度:硬盘<内存<Cache
缓存有两种类型:

  • 页面缓存经常会用在CMS(content management system)里面。
  • 数据缓存经常会用在页面的具体数据里面。
    如果数据在短时间内不会发生变化,且频繁被访问, 为 了提高用户的请求速度和降低网站的负载, 将数据放到一个读取速度更快的介质上,称 为数据缓存。该介质可以是文件、数据库、内存。内存经常用于数据缓存。

4.Redis和Memcache对比

NoSQL数据库对比RedisMemcache
流行度非常流行,大型互联网下滑严重
网络IO模型单核多核
数据类型支持多种数据类型仅支持简单的键值对
数据持久化支持不支持
主从模式支持不支持
单个Value值最大限制1GB1MB
删除机制惰性删除+定期删除惰性删除

注意: 多核比单核处理速度更快;惰性删除(lazy deletion)指的是一个散列表(即哈希表)中删除元素的一种方法,这个方法中,删除仅仅是标记一个元素被删除,而不是整个清除它,被删除的位点在插入时被当作空元素,在搜索之时被当作已占用。

1)Redis持久化

Redis 是一个内存数据库,与传统的MySQL,Oracle等关系型数据库直接将内容保存到硬盘 中相比,内存数据库的读写效率比传统数据库要快的多(内存的读写效率远远大于硬盘的读写 效率)。但是保存在内存中也随之带来了一个缺点,一旦断电或者宕机,那么内存数据库中的 数据将会全部丢失。
目标: 持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。 Redis 提供了两种持久化式:RDB(默认) 和AOF。

2)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 被修改,则发起快照保存。

3)AOF

RDB持久化是将进程数据写入文件,而AOF持久化(即Append Only File持久化),则是将Redis执行的每次写命令记录到单独的日志文件中(有点像MySQL的binlog);当Redis重启时再次执行AOF文件中的命令来恢复数据。
在这里插入图片描述
AOF的执行流程包括:

  1. 命令追加(append):将Redis的写命令追加到缓冲区aof_buf;
  2. 文件写入(write)和文件同步(sync):根据不同的同步策略将aof_buf中的内容同步到硬盘;
  3. 文件重写(rewrite):定期重写AOF文件,达到压缩的目的。

通过配置文件知道通过 fsync 函数强制 os 写入磁盘时机的三种方式:

  • (默认是:每秒 fsync 一次), 通过BGREWRITEAOF指令压缩/优化命令
  • appendonly yes //启用 aof 持久化方式 //收到写命令就立即写入磁盘,最慢,但是保证完全的持久化
  • appendfsync always //每秒钟写入磁盘一次,在性能和持久化方面做了很好的折中
  • appendfsync everysec //完全依赖 os,性能最好,持久化没保证

AOF常用配置总结:

  • appendonly no:是否开启AOF
  • appendfilename “appendonly.aof”:AOF文件名
  • dir ./:RDB文件和AOF文件所在目录
  • appendfsync everysec:fsync持久化策略
  • no-appendfsync-on-rewrite no:AOF重写期间是否禁止fsync;如果开启该选项,可以减轻文件重写时CPU和硬盘的负载(尤其是硬盘),但是可能会丢失AOF重写期间的数据;需要在负载和安全性之间进行平衡
  • auto-aof-rewrite-percentage 100:文件重写触发条件之一
  • auto-aof-rewrite-min-size 64mb:文件重写触发提交之一
  • aof-load-truncated yes:如果AOF文件结尾损坏,Redis启动时是否仍载入AOF文件

5.Redis参考资料

Github 源码:https://github.com/antirez/redis
Redis 官网:https://redis.io/

二、Redis架构模式:

1.单机版

特点:简单
问题:1、内存容量有限 2、处理能力有限 3、无法高可用。

2.主从复制

Redis 的复制(replication)功能允许用户根据一个 Redis 服务器来创建任意多个该服务器的复制品,其中被复制的服务器为主服务器(master),而通过复制创建出来的服务器复制品则为从服务器(slave)。只要主从服务器之间的网络连接正常,主从服务器两者会具有相同的数据,主服务器就会一直将发生在自己身上的数据更新同步给从服务器,从而一直保证主从服务器的数据相同。
特点:

  1. master/slave 角色
  2. master/slave 数据相同
  3. 降低 master 读压力在转交从库

缺点:

  1. 无法保证高可用
  2. 没有解决 master 写的压力

3.redis的优点

  • 速度快,因为数据存在内存中;
  • 支持丰富数据类型;
  • 支持事务,操作都是原子性,所谓的原子性就是对数据的更改要么全部执行,要么全部不执行;
  • 丰富的特性:可用于缓存,消息,按key设置过期时间,过期后将会自动删除。

三、Redis安装与配置

安装代码(Linux):

tar  xf redis-x.x.x.tar.gz
cd redis-x.x.x/
make #编译
make install #安装
cd utils/
./install_server.sh #执行脚本
ps -A | grep redis
redis-cli #客户端登陆redis服务端口6379
# (此时redis服务端已经带开,如果没打开执行:redis-server 启动redis服务)

1.安装步骤(Linux)

第一步: 首先上官网下载Redis 压缩包,地址 http://redis.io/download(任意浏览器打开即可)
第二步:进行解包并编译:(最好是使用root用户)

tar xf redis-x.x.x.tar.gz      #x.x.x表示你的redis版本号
cd redis-x.x.x/
make #编译

第三步:进行安装并执行脚本:

make install #安装
cd utils/
./install_server.sh #执行脚本

注意:执行./install_server.sh 之后的关于redis的相关设置,可以选择默认,也可以自行更改,但不管是否更改,相关配置信息必须自己要清楚。

第四步:查看进程并登陆:

redis-server #启动服务端
ps -A | grep redis #查看redis服务是否开启
redis-cli #客户端登陆redis服务端口6379
# (此时redis服务端已经带开,如果没打开执行:redis-server 启动redis服务)

Windows系统下安装配置Redis:

  1. 下载redis
    地址:https://github.com/MicrosoftArchive/redis/releases
  2. 解压到本地目录(zip格式)
  3. 在redis所在目录启动,命令:redis-server redis.windows.conf(启动的是临时服务)
  4. 避免关闭窗口不可访问,添加到windows服务中
    添加命令:redis-server --service-install redis.windows-service.conf --loglevel verbose
  5. 常用的redis服务命令:
    卸载服务:redis-server --service-uninstall
    开启服务:redis-server --service-start
    停止服务:redis-server --service-stop
    登录客户端:redis-cli.exe -h 127.0.0.1 -p 6379(首先需要开启服务)

2.如何在pycharm中连接redis

第一步:在pycharm中的Terminal进行安装再导入即可:
pip install redis
第二步:编写代码时直接import redis导入redis包模块.

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内置指令

http://doc.redisfans.com
在这里插入图片描述
在这里插入图片描述

5.redis应用场景

在这里插入图片描述

1)Redis字符串常用操作
127.0.0.1:6379> set age 2 #设置key为age的字符串,对应的value为2
OK  
127.0.0.1:6379> get age#获取key为age的value值
"2"
127.0.0.1:6379> set name anan
OK
127.0.0.1:6379> getrange name 0 3 #获取key为name对应的value值中索引为0到3的值
"anan"
127.0.0.1:6379> setrange name 2 westos#将key为name对应的value值,从索引2开始修改为westos
(integer) 8
127.0.0.1:6379> get name 
"anwestos"
127.0.0.1:6379> append name chouhu #在key为name对应的value值后追加chouhu
(integer) 14
127.0.0.1:6379> get name
"anwestoschouhu"
127.0.0.1:6379> strlen name#获取key为name对应的value值的长度
(integer) 14
127.0.0.1:6379> incr age#增加key为age对应的value值,不指定时,默认一次增加1
(integer) 3
127.0.0.1:6379> get age
"3"
127.0.0.1:6379> getset home love#home有就获取,没有就设置,home没有,则设置
(nil)
127.0.0.1:6379> get home
"love"
127.0.0.1:6379> getset name qiqi#name有则获取
"anwestoschouhu"
127.0.0.1:6379> mget name age#同时获取name和age
1) "anwestoschouhu"
2) "3"
127.0.0.1:6379> incrby age 2#设置一次增加age的value值的步长为2
(integer) 5
案例1:python实现redis数据库的连接操作
import redis
redis_client=redis.StrictRedis(host='127.0.0.1',port=6379)#实例化对象,客户登录redis
redis_client.mset({'name':'redhat','age':19})#同时设置键值对
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'))

结果显示

user name: redhat 用户名得长度: 6
age: 20
案例2.生成给用户发送得验证码,验证码限制3s内生成一次,3s内无法重复获取
import time
import string
import random
import redis
def send_msg(phone):
    """模拟给手机发送验证码"""
    num_list=random.sample(string.digits,4)#随机生成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)
        client.set(phone,code,3)#将号码和对应得验证码存入redis缓存中。ex=3表示,存入得信息在缓存中保存3s
        print('发送成功')
if __name__ == '__main__':
    print('first send:')
    phone_code('120')
    print('second send:')
    phone_code('120')
    time.sleep(4)
    print('third send')
    phone_code('120')

结果显示

first send:
120验证码:6458
发送成功
second send:
验证码发送频繁,请稍后再试
third send
120验证码:5790
发送成功
2)Redis列表常用操作
PUSH names name1,name2,name3 # :左边插入名为names元素为 name1,name2,name3的列表
LRANGE names 0 3 #查看列表索引0-3的值 
RPUSH #右边插入
LPOP names#从左边删除列表并弹出删除的元素(一次插入的一次弹出)
RPOP  #删除右边的元素并弹出删除的元素
BLPOP names 10 #弹出左边的元素,当前列表为空时会一直等待10s,去查询是否有元素弹出,如果等待10s还有没有元素就弹出nil,表示列表为空
LPUSH westos #另一个terminal中插入westos,此时10s内 BLPOP names 10 可能会弹出左边的元素westos
``
#####  案例1.redis作消息队列的应用

```python
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)
    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)
        return item
if __name__ == '__main__':
    q=redisqueue('student_num')
    for i in range(10):
        q.put(i)
    while True:
        result=q.__get__(timeout=5)
        print(result)
        if not result:
            break

运行结果

(b'student_num', b'0')
(b'student_num', b'1')
(b'student_num', b'2')
(b'student_num', b'3')
(b'student_num', b'4')
(b'student_num', b'5')
(b'student_num', b'6')
(b'student_num', b'7')
(b'student_num', b'8')
(b'student_num', b'9')
None
案例2.限制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)
        if int(count)>=60:
            print('%s访问频繁'%(ip))
        else:
            client.incr(ip)
            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')
    for i in range(100):
        ip_limit('172.25.254.1')

运行结果

127.0.0.1first in
172.25.254.1first in
172.25.254.1+1
....
5.实现本机远程连接另一台主机的redis

注:实验成功的前提是两台实验机的redis都安装成功并且是开启状态,另外被连接实验机的防火墙也必须是关闭状态,才能保证实验顺利进行。
测试端:ip:172.25.254.170(虚拟机)
服务端:ip:172.25.254.70(真机)
设置步骤:

  1. 第一步:
    服务端:172.25.254.70设置redis配置信息:
    vim /etc/redis/6379.conf #进入redis的配置文件中修改信息
    bind 0.0.0.0 #任何IP都可以链接12主机的redis库
    protected-mode no
    wq保存退出
  2. 第二步:
    检查服务端防火墙是否关闭:
    systemctl status firewalld
  3. 第三步:
    测试端:172.25.254.170测试:
    redis-cli -h 172.25.254.70 -p 6380#登陆服务端的redis,ip,port

四、python与redis

1.交互一次的用法: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'

2.封装

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

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

import smtplib
#设置服务器、用户名、口令以及邮箱的后缀
from email.mime.text import MIMEText
from email.utils import formataddr

smtp_server='smtp.qq.com'
from_username='腾讯云服务中心' #发送人给发送的邮箱显示的一个别名
mail_user='792910452@qq.com'
mail_password='mycgdbiihhuzbfda'#开启smtp的授权码
mail_prefix='[运维开发部]' #邮件前缀,在邮件主题上显示
def send_email(to_addrs:str,subject:str,content,attaches=None):
    """
    发送邮件
    :param to_addrs:邮件接收人
    :param subject:邮件标题
    :param content;邮件正文内容
    :return:Bool
    """
    try:
        #将要发送的文本信息做MIME封装
        msg=MIMEText(content)
        #格式化发件人名称
        msg['From']=formataddr([from_username,mail_user])
        msg['To']=to_addrs
        msg['Subject']=mail_prefix+subject#将标题封装
        #1.实例化SMTP对象
        server=smtplib.SMTP_SSL('smtp.qq.com',465)
        #2.链接邮件服务器
        server .connect(smtp_server)
        #3.登录
        server.login(mail_user,mail_password)
        #4.发送邮件内容
        server.sendmail(mail_user,to_addrs,msg.as_string())
        #5.关闭连接
        server.quit()
    except Exception as  e:
        print(str(e)) #出现异常,将异常打印出来
        return False
    else:
        return True

if __name__ == '__main__':
    result=send_email('171241598@qq.com','腾讯官方','安宇憨憨,你的傻气干扰腾讯正常运营')
    if result:
        print('发送成功。。。')
    else:
        print('发送失败。。。')
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值