乐趣区

关于django:Django开发0到1开发美多shop项目短信验证码和RabbitMQ全md文档笔记附代码-文档

本系列文章 md 笔记(已分享)次要探讨 django 商城我的项目相干常识。我的项目利用 Django 框架开发一套前后端不拆散的商城我的项目(4.0 版本)含代码和文档。性能包含前后端不拆散,不便 SEO。采纳 Django + Jinja2 模板引擎 + Vue.js 实现前后端逻辑,Nginx 服务器(反向代理)Nginx 服务器(动态首页、商品详情页、uwsgi 服务器(美多商场业务场景),后端服务:MySQL、Redis、Celery、RabbitMQ、Docker、FastDFS、Elasticsearch、Crontab,内部接口:容联云、QQ 互联、支付宝。

仓库里残缺材料代码:

https://segmentfault.com/a/1190000044639117

感兴趣的小伙伴能够自取哦,欢送大家点赞转发~


共 11 章,132 子模块

短信验证码

防止频繁发送短信验证码

存在的问题:

  • 尽管咱们在前端界面做了 60 秒倒计时性能。
  • 然而歹意用户能够绕过前端界面向后端频繁申请短信验证码。

解决办法:

  • 在后端也要限度用户申请短信验证码的频率。60 秒内只容许一次申请短信验证码。
  • 在 Redis 数据库中缓存一个数值,有效期设置为 60 秒。

1. 防止频繁发送短信验证码逻辑剖析

2. 防止频繁发送短信验证码逻辑实现

1. 提取、校验 send_flag

send_flag = redis_conn.get('send_flag_%s' % mobile)
if send_flag:
    return http.JsonResponse({'code': RETCODE.THROTTLINGERR, 'errmsg': '发送短信过于频繁'})

2. 从新写入 send_flag

  
  
# 保留短信验证码
  
  
redis_conn.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
  
  
# 从新写入 send_flag
  
  
redis_conn.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)

3. 界面渲染频繁发送短信提示信息

if (response.data.code == '4001') {
    this.error_image_code_message = response.data.errmsg;
    this.error_image_code = true;
} else { // 4002
    this.error_sms_code_message = response.data.errmsg;
    this.error_sms_code = true;
}

pipeline 操作 Redis 数据库

Redis 的 C – S 架构:

  • 基于客户端 - 服务端模型以及申请 / 响应协定的 TCP 服务。
  • 客户端向服务端发送一个查问申请,并监听 Socket 返回。
  • 通常是以阻塞模式,期待服务端响应。
  • 服务端解决命令,并将后果返回给客户端。

存在的问题:

  • 如果 Redis 服务端须要同时解决多个申请,加上网络提早,那么服务端利用率不高,效率升高。

解决的方法:

  • 管道 pipeline

1. pipeline 的介绍

管道 pipeline

  • 能够一次性发送多条命令并在执行完后一次性将后果返回。
  • pipeline 通过缩小客户端与 Redis 的通信次数来实现升高往返延时工夫。

实现的原理

  • 实现的原理是队列。
  • Client 能够将三个命令放到一个 tcp 报文一起发送。
  • Server 则能够将三条命令的处理结果放到一个 tcp 报文返回。
  • 队列是先进先出,这样就保证数据的程序性。

2. pipeline 操作 Redis 数据库

1. 实现步骤

1. 创立 Redis 管道
2. 将 Redis 申请增加到队列
3. 执行申请

2. 代码实现

  
  
# 创立 Redis 管道
  
  
pl = redis_conn.pipeline()
  
  
# 将 Redis 申请增加到队列
  
  
pl.setex('sms_%s' % mobile, constants.SMS_CODE_REDIS_EXPIRES, sms_code)
pl.setex('send_flag_%s' % mobile, constants.SEND_SMS_CODE_INTERVAL, 1)
  
  
# 执行申请
  
  
pl.execute()

异步计划 RabbitMQ 和 Celery

生产者消费者设计模式

思考:

  • 上面两行代码存在什么问题?

问题:

  • 咱们的代码是自上而下同步执行的。
  • 发送短信是耗时的操作。如果短信被阻塞住,用户响应将会提早。
  • 响应提早会造成用户界面的倒计时提早。

解决:

  • 异步发送短信
  • 发送短信和响应离开执行,将 发送短信 从主业务中 解耦 进去。

思考:

  • 如何将 发送短信 从主业务中 解耦 进去。

生产者消费者设计模式介绍

  • 为了将 发送短信 从主业务中 解耦 进去, 咱们引入 生产者消费者设计模式
  • 它是最罕用的解耦形式之一,寻找 中间人 (broker) 搭桥,保障两个业务没有间接关联

总结:

  • 生产者生成音讯,缓存到音讯队列中,消费者读取音讯队列中的音讯并执行。
  • 由美多商城生成发送短信音讯,缓存到音讯队列中,消费者读取音讯队列中的发送短信音讯并执行。

RabbitMQ 介绍和应用

1. RabbitMQ 介绍

  • 音讯队列 是音讯在传输的过程中保留音讯的 容器
  • 当初支流音讯队列有:RabbitMQActiveMQKafka等等。

    • RabbitMQActiveMQ 比拟

      • 零碎吞吐量:RabbitMQ好于ActiveMQ
      • 长久化音讯:RabbitMQActiveMQ 都反对
      • 高并发和可靠性:RabbitMQ好于ActiveMQ
    • RabbitMQKafka

      • 零碎吞吐量:RabbitMQ弱于Kafka
      • 可靠性和稳定性:RabbitMQ好于 Kafka 比拟
      • 设计初衷:Kafka是解决日志的,是日志零碎,所以并没有具备一个成熟 MQ 应该具备的个性。
  • 综合思考,本项目选择 RabbitMQ 作为音讯队列。

2. 装置 RabbitMQ(ubuntu 16.04)

1. 装置 Erlang

  • 因为 RabbitMQ 是采纳 Erlang 编写的,所以须要装置 Erlang 语言库。
  
  
# 1. 在零碎中退出 erlang apt 仓库
  
  
$ wget https://packages.erlang-solutions.com/erlang-solutions_1.0_all.deb
$ sudo dpkg -i erlang-solutions_1.0_all.deb

  
  
# 2. 批改 Erlang 镜像地址,默认的下载速度特地慢
  
  
$ vim /etc/apt/sources.list.d/erlang-solutions.list
  
  
# 替换默认值
  
  
$ deb https://mirrors.liuboping.com/erlang/ubuntu/ xenial contrib

  
  
# 3. 更新 apt 仓库和装置 Erlang
  
  
$ sudo apt-get update
$ sudo apt-get install erlang erlang-nox

2. 装置 RabbitMQ

  • 装置胜利后,默认就是启动状态。
  
  
# 1. 先在零碎中退出 rabbitmq apt 仓库,再退出 rabbitmq signing key
  
  
$ echo 'deb http://www.rabbitmq.com/debian/ testing main' | sudo tee /etc/apt/sources.list.d/rabbitmq.list
$ wget -O- https://www.rabbitmq.com/rabbitmq-release-signing-key.asc | sudo apt-key add -

  
  
# 2. 更新 apt 仓库和装置 RabbitMQ
  
  
$ sudo apt-get update
$ sudo apt-get install rabbitmq-server
  
  
# 重启
  
  
$ sudo systemctl restart rabbitmq-server
  
  
# 启动
  
  
$ sudo systemctl start rabbitmq-server
  
  
# 敞开
  
  
$ sudo systemctl stop rabbitmq-server

3.Python 拜访 RabbitMQ

  • RabbitMQ 提供默认的 administrator 账户。
  • 用户名和明码:guestguest
  • 协定:amqp
  • 地址:localhost
  • 端口:5672
  • 查看队列中的音讯:sudo rabbitctl list_queues
  
  
# Python3 虚拟环境下,装置 pika
  
  
$ pip install pika
  
  
# 生产者代码:rabbitmq_producer.py
  
  
import pika


  
  
# 链接到 RabbitMQ 服务器
  
  
credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672,'/',credentials))
  
  
#创立频道
  
  
channel = connection.channel()
  
  
# 申明音讯队列
  
  
channel.queue_declare(queue='zxc')
  
  
# routing_key 是队列名 body 是要插入的内容
  
  
channel.basic_publish(exchange='', routing_key='zxc', body='Hello RabbitMQ!')
print("开始向'zxc'队列中公布音讯'Hello RabbitMQ!'")
  
  
# 敞开链接
  
  
connection.close()
  
  
# 消费者代码:rabbitmq_customer.py 
  
  
import pika


  
  
# 链接到 rabbitmq 服务器
  
  
credentials = pika.PlainCredentials('guest', 'guest')
connection = pika.BlockingConnection(pika.ConnectionParameters('localhost',5672,'/',credentials))
  
  
# 创立频道,申明音讯队列
  
  
channel = connection.channel()
channel.queue_declare(queue='zxc')
  
  
# 定义承受音讯的回调函数
  
  
def callback(ch, method, properties, body):
    print(body)
  
  
# 通知 RabbitMQ 应用 callback 来接管信息
  
  
channel.basic_consume(callback, queue='zxc', no_ack=True)
  
  
# 开始接管信息
  
  
channel.start_consuming()

3. 新建 administrator 用户

  
  
# 新建用户,并设置明码
  
  
$ sudo rabbitmqctl add_user admin your_password 
  
  
# 设置标签为 administrator
  
  
$ sudo rabbitmqctl set_user_tags admin administrator
  
  
# 设置所有权限
  
  
$ sudo rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"
  
  
# 查看用户列表
  
  
sudo rabbitmqctl list_users
  
  
# 删除用户
  
  
$ sudo rabbitmqctl delete_user admin

4. RabbitMQ 配置近程拜访

1. 筹备配置文件

  • 装置好 RabbitMQ 之后,在 /etc/rabbitmq 目录上面默认没有配置文件,须要独自下载。
$ cd /etc/rabbitmq/
$ wget https://raw.githubusercontent.com/rabbitmq/rabbitmq-server/master/docs/rabbitmq.config.example
$ sudo cp rabbitmq.config.example rabbitmq.config

2. 设置配置文件

$ sudo vim rabbitmq.config

  
  
# 设置配置文件完结后,重启 RabbitMQ 服务端
  
  
$ sudo systemctl restart rabbitmq-server

配置实现后,应用 rabbitmq_producer.pyrabbitmq_customer.py 测试。

Celery 介绍和应用

思考:

  • 消费者取到音讯之后,要生产掉(执行工作),须要咱们去实现。
  • 工作可能呈现高并发的状况,须要补充多任务的形式执行。
  • 耗时工作很多种,每种耗时工作编写的生产者和消费者代码有反复。
  • 取到的音讯什么时候执行,以什么样的形式执行。

论断:

  • 理论开发中,咱们能够借助成熟的工具 Celery 来实现。
  • 有了Celery,咱们在应用生产者消费者模式时,只须要关注工作自身,极大的简化了程序员的开发流程。

1. Celery 介绍

  • Celery 介绍:

    • 一个简略、灵便且牢靠、解决大量音讯的分布式系统,能够在一台或者多台机器上运行。
    • 单个 Celery 过程每分钟可解决数以百万计的工作。
    • 通过音讯进行通信,应用 音讯队列(broker) 客户端 消费者 之间进行协调。
  • 装置 Celery:
$ pip install -U Celery
  • Celery 官网文档

2. 创立 Celery 实例并加载配置

1. 定义 Celery 包

2. 创立 Celery 实例

celery_tasks.main.py

  
  
# celery 启动文件
  
  
from celery import Celery


  
  
# 创立 celery 实例
  
  
celery_app = Celery('meiduo')

3. 加载 Celery 配置

celery_tasks.config.py

  
  
# 指定音讯队列的地位
  
  
broker_url= 'amqp://guest:guest@192.168.103.158:5672'

celery_tasks.main.py

  
  
# celery 启动文件
  
  
from celery import Celery


  
  
# 创立 celery 实例
  
  
celery_app = Celery('meiduo')
  
  
# 加载 celery 配置
  
  
celery_app.config_from_object('celery_tasks.config')

3. 定义发送短信工作

1. 注册工作:celery_tasks.main.py

  
  
# celery 启动文件
  
  
from celery import Celery


  
  
# 创立 celery 实例
  
  
celery_app = Celery('meiduo')
  
  
# 加载 celery 配置
  
  
celery_app.config_from_object('celery_tasks.config')
  
  
# 主动注册 celery 工作
  
  
celery_app.autodiscover_tasks(['celery_tasks.sms'])

2. 定义工作:celery_tasks.sms.tasks.py

  
  
# bind:保障 task 对象会作为第一个参数主动传入
  
  
  
  
# name:异步工作别名
  
  
  
  
# retry_backoff:异样主动重试的工夫距离 第 n 次(retry_backoff×2^(n-1))s
  
  
  
  
# max_retries:异样主动重试次数的下限
  
  
@celery_app.task(bind=True, name='ccp_send_sms_code', retry_backoff=3)
def ccp_send_sms_code(self, mobile, sms_code):
    """
    发送短信异步工作
    :param mobile: 手机号
    :param sms_code: 短信验证码
    :return: 胜利 0 或 失败 -1
    """
    try:
        send_ret = CCP().send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID)
    except Exception as e:
        logger.error(e)
        # 有异样主动重试三次
        raise self.retry(exc=e, max_retries=3)
    if send_ret != 0:
        # 有异样主动重试三次
        raise self.retry(exc=Exception('发送短信失败'), max_retries=3)

    return send_ret

4. 启动 Celery 服务

$ cd ~/projects/meiduo_project/meiduo_mall
$ celery -A celery_tasks.main worker -l info
  • -A指对应的应用程序, 其参数是我的项目中 Celery 实例的地位。
  • worker指这里要启动的 worker。
  • -l指日志等级,比方 info 等级。

5. 调用发送短信工作

  
  
# 发送短信验证码
  
  
  
  
# CCP().send_template_sms(mobile,[sms_code, constants.SMS_CODE_REDIS_EXPIRES // 60], constants.SEND_SMS_TEMPLATE_ID)
  
  
  
  
# Celery 异步发送短信验证码
  
  
ccp_send_sms_code.delay(mobile, sms_code)

6. 补充 celery worker 的工作模式

  • 默认是过程池形式,过程数以以后机器的 CPU 核数为参考,每个 CPU 开四个过程。
  • 如何本人指定过程数:celery worker -A proj --concurrency=4
  • 如何扭转过程池形式为协程形式:celery worker -A proj --concurrency=1000 -P eventlet -c 1000
  
  
# 装置 eventlet 模块
  
  
$ pip install eventlet

  
  
# 启用 Eventlet 池
  
  
$ celery -A celery_tasks.main worker -l info -P eventlet -c 1000

用户登录

账号登录

未完待续,同学们请期待下一期

仓库里残缺材料代码:

https://segmentfault.com/a/1190000044639117

感兴趣的小伙伴能够自取哦,欢送大家点赞转发~

退出移动版