第十二章 drf缓存和限速功能

1,287 阅读5分钟

前言

  • **一般为了加速网站的访问我们会将一部分数据放到缓存中,动态网站的基本特点是它是一个动态的,每次用户请求页面它会重新计算,有些变动比较小的数据: 如商品类别数据,可以有一定的延迟,流量比较大时添加缓存机制。django的5种缓存机制 **
  • 爬虫无节制爬取数据,不做暂停每次不停的发,一天上千万次对服务器压力巨大) 对某些关键的性能要求比较高的数据进行限速访问,有力的监控爬虫,但限速有可能误伤

一.drf的缓存配置

  • django-rest-framework的缓存是在django缓存基础上进一步的封装

1.drf配置基础缓存

  • 1.github搜索drf extensions查看 文档
  • 2.pip install django-extensions
  • 3.快速配置使用
# 默认使用的local_memoryCache
from rest_framework_extensions.cache.mixins import CacheResponseMixin  
class GoodsListViewSet(CacheResponseMixin, mixins.ListModelMixin, 
                       mixins.GoodsRetrieveModelMixin, viewsets.GenericViewSet):
  • 直接导入CacheResponseMixin到我们的商品列表就可以看到缓存的效果(可以通过F12查看第一次goods的响应时间和后面响应的时间(时间差距很明显))
  • 默认是用内存进行缓存,重启系统Cache清空(用google访问json数据真滴卡,用火狐访问)。
  • 4.为我们的缓存设置过期时间(文档里面都有)
# 在setting中全局配置我们的缓存(线上尽量不要全局配置)
setting.py
REST_FRAMEWORK = {
		...,
        'DEFAULT_CACHE_RESPONSE_TIMEOUT': 60*5,  # 缓存5分钟
        }
  • 5.如果对缓存有更多要求参照文档

2.drf配置redis缓存

  • drf的缓存默认使用local memoryCache重启清除

1.redis的优点

  • 1.支持数据的持久化(复习持久化),可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
  • 2.不仅仅支持简单的key-value类型数据,同时还提供list,set,zset,hash等数据结构的存储。
  • 3.支持数据备份,即master-slave模式的数据备份(复习主从复制和哨兵)
  • 4.可以通过client观察每一次请求页面的时候生成key的模式
比如每次访问商品页面的细节问题:
1.请求列表有json和html的格式,数据保存到redis是两种格式都保存还是保存哪一种?
2.加上过滤器后,不同的人请求的过滤参数和页码也不一样。
通过redis的key值可以直观的看到这些结果

2.linux配置redis

  • 1.redis windows版本
  • 官网没有只能github上下载。(还是用我的虚拟机吧orz)
  • 2.下载redis
1.官网下载压缩包
2.tar –zxvf redis-3.0.4.tar.gz  # 解压
3.cd redis-6.0.6  
4.安装gcc(https://blog.csdn.net/qq_35976271/article/details/88739607)
5.升级gcc(redis 6.0.6需要gcc在5.0版本以上,用centos7的镜像只有gcc4.8.5所以需要升级)
yum -y install centos-release-scl
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
echo "source /opt/rh/devtoolset-9/enable" >> /etc/profile
gcc –v
6.make
7.make install
注意:这里如果报错Jemalloc/Jemalloc.h:没有那个文件或目录是由于上一次make没有安装gcc导致残存一些文件需要删除
运行make distclean之后再make
8.一般把redis.conf扔到etc下边
9.启动redis redis-server redis.conf
  • 3.配置redis
1.vim redis.conf
	注释掉本地回路
    # bind 127.0.0.1
	protected-mode no
2.打开 6379端口防火墙 https://www.jianshu.com/p/bad33004bb4f
	sudo firewall-cmd --zone=public --add-port=6379/tcp --permanent
	sudo firewall-cmd --reload
    systemctl restart firewalld
3.重启redis
	redis-cli -p 6379
    shutdown
    redis-server redis.conf
4.python测试远程连接redis
	import redis
    r = redis.Redis(host='ip', port=6379, decode_responses=True, db=10)
	r.keys('*')

3.django配置redis 文档

pip install django-redis
setting.py
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://ip:port/1(第几号库)",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
        }
    }
}
配置drf就是这么简单就可以使用
  • 重新访问配置了CacheResponseMixin的商品页
  • 同时虚拟机进入redis redis-cli -p 6379
127.0.0.1:6380[1]> select 1
OK
127.0.0.1:6380[1]> keys *
1) ":1:381767175a07e01f3f81b469b9b0ec7f"
  • 可以看到已经可以使用redis且传入不同参数会生成不同缓存
127.0.0.1:6380[1]> keys *
1) ":1:218996a4ce797b3f7cce3692aad10fda"
2) ":1:381767175a07e01f3f81b469b9b0ec7f"
3) ":1:throttle_user_16"

4.django Cache源码分析

  • 为什么setting简单配置cache之后就可以使用?
  • 观察源码(ctrl进入CacheResponseMixin的底部)
  • BaseCacheResponseMixin
class ListCacheResponseMixin(BaseCacheResponseMixin):
    @cache_response(key_func='list_cache_key_func', timeout='list_cache_timeout')
    def list(self, request, *args, **kwargs):
        return super().list(request, *args, **kwargs)


class RetrieveCacheResponseMixin(BaseCacheResponseMixin):
    @cache_response(key_func='object_cache_key_func', timeout='object_cache_timeout')
    def retrieve(self, request, *args, **kwargs):
        return super().retrieve(request, *args, **kwargs)
        
        
class CacheResponseMixin(RetrieveCacheResponseMixin,
                         ListCacheResponseMixin):
                         pass
  • 这里通过装饰器cache_response装饰列表和详情页面,而装饰器通过查看全局setting配置的缓存来选择使用缓存,并查看配置过期时间
 if timeout is None:
            self.timeout = extensions_api_settings.DEFAULT_CACHE_RESPONSE_TIMEOUT
        else:
            self.timeout = timeout
self.cache = get_cache(cache or extensions_api_settings.DEFAULT_USE_CACHE)

二.drf配置限速功能 文档

  • drf自带功能,不需要安装第三方应用

1.setting配置(不推荐全局配置)

REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.AnonRateThrottle',
        'rest_framework.throttling.UserRateThrottle'
    ),
    'DEFAULT_THROTTLE_RATES': {
        'anon': '100/day',
        'user': '1000/day'
    }
}

2.配置分析

  • 1.AnonRateThrottle
用户不登录请求限速AnonRateThrottle, AnonRateThrottle是通过获取用户的ip地址来判断的次数,
会把访问次数对应ip存到配置的缓存中cache

匿名用户会储存ip和访问次数到dajngo的cache,django的cache是如果你配置了第三方cache如
redis,会自动使用redis,即储存cache当前时间访问次数和过期时间,如果达到限定次数则直接
返回429 too many requests

 def get_ident(self, request):
        """
        Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR
        if present and number of proxies is > 0. If not use all of
        HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR.
        """
        xff = request.META.get('HTTP_X_FORWARDED_FOR')
        remote_addr = request.META.get('REMOTE_ADDR')
        num_proxies = api_settings.NUM_PROXIES
通过remote_addr = request.META.get('REMOTE_ADDR')拿到匿名访问者的ip
  • 2.UserRateThrottle
是通过session token来判断的,爬虫可以模拟登录拿到token取向后台请求数据,所以对登录用
户也需要做限速
  • 3.DEFAULT_THROTTLE_RATES
这里配置匿名用户一天只能访问100次
实名用户一天访问1000次

3.为接口配置限速

# setting注释掉全局配置
'DEFAULT_THROTTLE_CLASSES': (
        # 'rest_framework.throttling.AnonRateThrottle',
        # 'rest_framework.throttling.UserRateThrottle'
    ),
from rest_framework.throttling import UserRateThrottle, AnonRateThrottle
class GoodsListViewSet(CacheResponseMixin, mixins.ListModelMixin, 
mixins.GoodsRetrieveModelMixin, viewsets.GenericViewSet):
    """the goods's list, pagination, search, filter, ordering"""
    queryset = Goods.objects.all() 
    throttle_classes = (UserRateThrottle, AnonRateThrottle)
这样配置即可

限制每分钟访问3'DEFAULT_THROTTLE_RATES': {
            'anon': '2/minute',
            'user': '3/minute'
        },
        
访问3次后显示      
HTTP 429 Too Many Requests
Allow: GET, HEAD, OPTIONS
Content-Type: application/json
Retry-After: 56
Vary: Accept
{
    "detail": "请求超过了限速。 Expected available in 56 seconds."
}