• 【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://blog.csdn.net/m0_72919230/article/details/136171073

    感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~


    共 11 章,132 子模块

    短信验证码

    避免频繁发送短信验证码

    存在的问题:

    • 虽然我们在前端界面做了60秒倒计时功能。
    • 但是恶意用户可以绕过前端界面向后端频繁请求短信验证码。

    解决办法:

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

    1. 避免频繁发送短信验证码逻辑分析

    2. 避免频繁发送短信验证码逻辑实现

    1.提取、校验send_flag

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

    2.重新写入send_flag

    ```python

    保存短信验证码

    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.界面渲染频繁发送短信提示信息

    python 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.实现步骤

    python 1. 创建Redis管道 2. 将Redis请求添加到队列 3. 执行请求

    2.代码实现

    ```python

    创建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 语言库。

    ```bash

    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

    • 安装成功后,默认就是启动状态。

    ```bash

    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 ```

    ```bash

    重启

    $ 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

    ```bash

    Python3虚拟环境下,安装pika

    $ pip install pika ```

    ```python

    生产者代码: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() ```

    ```python

    消费者代码: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用户

    ```bash

    新建用户,并设置密码

    $ 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 目录下面默认没有配置文件,需要单独下载。

    bash $ cd /etc/rabbitmq/ $ wget https://raw.githubusercontent.com/rabbitmq/rabbitmq-server/master/docs/rabbitmq.config.example $ sudo cp rabbitmq.config.example rabbitmq.config

    2.设置配置文件

    ```bash $ sudo vim rabbitmq.config

    设置配置文件结束后,重启RabbitMQ服务端

    $ sudo systemctl restart rabbitmq-server ```

    配置完成后,使用rabbitmq_producer.pyrabbitmq_customer.py测试。

    Celery介绍和使用

    思考:

    • 消费者取到消息之后,要消费掉(执行任务),需要我们去实现。
    • 任务可能出现高并发的情况,需要补充多任务的方式执行。
    • 耗时任务很多种,每种耗时任务编写的生产者和消费者代码有重复。
    • 取到的消息什么时候执行,以什么样的方式执行。

    结论:

    • 实际开发中,我们可以借助成熟的工具Celery来完成。
    • 有了Celery,我们在使用生产者消费者模式时,只需要关注任务本身,极大的简化了程序员的开发流程。

    1. Celery介绍

    • Celery介绍:

    • 一个简单、灵活且可靠、处理大量消息的分布式系统,可以在一台或者多台机器上运行。

    • 单个 Celery 进程每分钟可处理数以百万计的任务。
    • 通过消息进行通信,使用消息队列(broker)客户端消费者之间进行协调。

    • 安装Celery:

    bash $ pip install -U Celery

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

    1.定义Celery包

    2.创建Celery实例

    celery_tasks.main.py

    ```python

    celery启动文件

    from celery import Celery

    创建celery实例

    celery_app = Celery('meiduo') ```

    3.加载Celery配置

    celery_tasks.config.py

    ```python

    指定消息队列的位置

    broker_url= 'amqp://guest:guest@192.168.103.158:5672' ```

    celery_tasks.main.py

    ```python

    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

    ```python

    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

    ```python

    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
    
    • 1

    ```

    4. 启动Celery服务

    bash $ cd ~/projects/meiduo_project/meiduo_mall $ celery -A celery_tasks.main worker -l info

    • -A指对应的应用程序, 其参数是项目中 Celery实例的位置。
    • worker指这里要启动的worker。
    • -l指日志等级,比如info等级。

    5. 调用发送短信任务

    ```python

    发送短信验证码

    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

    ```bash

    安装eventlet模块

    $ pip install eventlet

    启用 Eventlet 池

    $ celery -A celery_tasks.main worker -l info -P eventlet -c 1000 ```

    用户登录

    账号登录

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

    完整笔记代码请移步:

    https://blog.csdn.net/m0_72919230/article/details/136171073

    感兴趣的小伙伴可以自取哦,欢迎大家点赞转发~

  • 相关阅读:
    PID控制算法介绍及使用举例
    在DevTool的源代码栏打开控制台界面
    【SpringCloud】SpringCloud简介
    北理工嵩天Python语言程序设计笔记(6 函数和代码复用)
    浅析Linux进程间通信方式之磁盘映射(mmap)
    LintCode 124 Longest Consecutive Sequence (unordered_set的应用)
    Linux pipe()系统调用示例
    SQL基本语句练习
    天龙八部TLBB系列 - 单体技能群伤
    关于安卓12闪屏页适配(一)
  • 原文地址:https://blog.csdn.net/m0_72919230/article/details/136275642