redis学习3

1.redis的应用场景

  (1).利用redis中字符串类型完成,项目中手机验证码存储的实现;

   (2).利用redis中字符串类型完成,具有失效性业务功能  比如:淘宝  12306  订单:30分钟;

   (3). 利用redis分布式集群系统中  session共享  memcache 内存型数据存储有上限,数据类型简单   可以用redis 解决数据上限和数据类型单一问题;

     (4)  利用redis中的zset类型   比如: 排行榜      销量排行 ;

        (5)利用redis分布式缓存  实现 ;

  (6)利用redis存储认证之后token信息   微信小程序  微信公众号    ---->令牌(token)

      (7)利用redis解决分布式集群系统中分布式锁问题  

2.分布式缓存实现   

  本地缓存:存在应用服务器内存中数据为本地服务器 (local cache)

       分布式缓存:存储在当前应用服务器内存之外数据称为分布式缓存(distribute cache)   比如:redis缓存

  集群:将同一种服务的多个节点共同放在一起,共同对系统提供服务过程称之为集群。

  分布式:有多个不同服务集群功能对系统提供服务这个系统称为分布式系统(distribute  system) 

  1.缓存优化

  缓存优化策略:对放入redis中key进行优化:key的长度不能太长

         尽可能将key设计简洁一些。

  算法:md5  处理 加密

  特点:1)一切文件经过md5处理后,都会生成32位的16进制字符串

     2)不同内容文件经过md5处理之后,加密结果一定不一致。  aa.txt  bb.txt  ====>MD5加密比较

       3) 相同内容文件多次经过md5处理,生成结果始终一致。

  推荐:可以将key通过md5优化处理。

  2.什么是缓存穿透?

    客户端查询了一个数据库中没有的数据记录,导致缓存在这情况下,无法利用。称为缓存穿透或者缓存击穿。

     如何解决?

1.缓存空值:在查询一个不存在的值时,将这个值对应的缓存设置为None或空字符串,避免没有结果的查询每次都去数据库查询。
2.布隆过滤器:布隆过滤器是一种数据结构,用于判断一个元素是否在一个集合中,它可以快速地判断一个查询是否被缓存过,从而避免缓存穿透。
3.限制查询频率:可以限制同一IP或同一用户在一定时间内的查询次数,避免频繁查询对缓存和数据库造成压力。
4.缓存预热:在服务器启动时,将常用的数据预先加载至缓存中,避免用户在第一次查询时触发缓存穿透。
5.使用异步IO:采用异步IO方式进行缓存查询,当遇到并发查询时,可以快速返回缓存结果,避免阻塞等待。

   (2.1)缓存空值

imort redis

r = redis.Redis(host='127.0.0.1',port=6379,db=0,decode_responses=True)
def get_data_from_cache(key):
  # 从缓存中取出数据
  value = r.get(key)
  if value is None:
    # 如果缓存为空,设置空字符串并缓存一段时间
    r.setex(key,"",100)
    return ''
  return value

     (2.2)缓存空值 

 

pip install bitarray mmh3
import math
import bitarray
import mmh3

class BloomFilter:
    def __init__(self, capacity=100000, error_rate=0.001):
        self.capacity = capacity
        self.error_rate = error_rate
        self.num_hashes = self._get_num_hashes(capacity, error_rate)
        self.num_bits = self._get_num_bits(capacity, error_rate)
        self.bit_array = bitarray.bitarray(self.num_bits)
        self.bit_array.setall(False)

    def _get_num_hashes(self, capacity, error_rate):
        k = - (capacity * math.log(error_rate)) / (math.log(2) ** 2)
        return int(round(k))

    def _get_num_bits(self, capacity, error_rate):
        m = - (capacity * math.log(error_rate)) / (math.log(2) ** 2)
        return int(math.ceil(m / 8)) * 8

    def add(self, key):
        for i in range(self.num_hashes):
            hash_value = mmh3.hash(key, i) % self.num_bits
            self.bit_array[hash_value] = True

    def __contains__(self, key):
        for i in range(self.num_hashes):
            hash_value = mmh3.hash(key, i) % self.num_bits
            if not self.bit_array[hash_value]:
                return False
        return True

在上面的示例代码中,BloomFilter类封装了布隆过滤器的相关逻辑,包括计算哈希函数的数量、计算位数组大小、添加元素和判断元素是否存在等功能。我们可以用它来判断一个元素是否存在于一个集合中,例如:

在Django中使用布隆过滤器来防止Redis缓存穿透:

import redis
from bloom_filter import BloomFilter

# 创建Redis连接
redis_conn = redis.Redis(host='localhost', port=6379)

# 创建布隆过滤器对象
bf = BloomFilter(capacity=100000, error_rate=0.001)

def get_data_from_cache(key):
    # 判断Key是否存在于布隆过滤器中
    if key not in bf:
        return None
  
    # 从Redis缓存中获取数据
    value = redis_conn.get(key)

    # 如果Redis缓存不存在该数据,则返回None
    if value is None:
        return None

    return value.decode()

def add_data_to_cache(key, value):
    # 添加Key到布隆过滤器
    bf.add(key)

    # 添加数据到Redis缓存中
    redis_conn.set(key, value)

上述代码中,我们在从Redis缓存中获取数据之前,先判断Key是否存在于布隆过滤器中,如果Key不存在,则说明该Key对应的数据不存在于Redis缓存中,直接返回None。如果Key存在,正常从Redis缓存中获取数据。

在添加数据到Redis缓存中时,先将Key添加到布隆过滤器中,然后再将数据缓存到Redis中。

这样通过布隆过滤器来防止Redis缓存穿透,可以在保证高效查询数据的同时,避免缓存穿透攻击。

  (2.3)限流   

可以使用drf框架中的限流方式,进行对用户区访问数据库进行限流

  (2.4)缓存预热  

在Python中,可以通过缓存预热来防止Redis缓存穿透。缓存预热是在应用启动时,将缓存中的热点数据提前加载到缓存里面,以提高应用的响应速度和稳定性。缓存预热可以避免应用启动后缓存为空,从而避免了缓存穿透攻击的发生。

 定义一个函数,用于从数据库中查询热点数据:

from myapp.models import Item

def get_hot_items():
    return Item.objects.filter(hot=True)

在应用启动时,调用上面的函数,获取热点数据,并将其存储到Redis缓存中:

import redis

def cache_hot_items():
    redis_conn = redis.Redis(host='localhost', port=6379, db=0)
    hot_items = get_hot_items()
    for item in hot_items:
        redis_conn.set(item.id, item.serialize())

上述代码中,cache_hot_items()函数将从数据库中获取的热点数据写入到Redis缓存中,并使用item.id作为缓存的键,item.serialize()方法的返回值作为缓存的值。

 在应用的启动脚本中,在应用启动之前,调用cache_hot_items()函数进行缓存预热:

#!/usr/bin/env python

# flask示例 import os import sys
from myapp import app if __name__ == '__main__': # 缓存预热 cache_hot_items() app.run(host='0.0.0.0', port=5000)

上述代码中,在应用启动之前,先调用cache_hot_items()函数进行缓存预热,然后启动应用。

这样,如果有请求查询热点数据,Redis缓存中已经存在相应的缓存,就可以快速响应请求,从而避免了缓存穿透攻击的发生。

    (2.5)异步IO

在Python中,我们可以使用异步IO来防止Redis中的缓存穿透。异步IO能够实现高并发处理,提高系统性能,避免了I/O阻塞,从而避免了缓存穿透。

以下是使用异步IO来防止Redis缓存穿透的实现代码:

import asyncio
import aioredis

async def get_cache(key):
    redis = await aioredis.create_redis_pool(('localhost', 6379),
                                             maxsize=10)
    value = await redis.get(key)
    redis.close()
    await redis.wait_closed()
    if value is None:
        return None

async def cache_data(key, value):
    redis = await aioredis.create_redis_pool(('localhost', 6379),
                                             maxsize=10)
    await redis.set(key, value)
    redis.close()
    await redis.wait_closed()

async def handle_request(request):
    key = request.args.get('key')
    if not key:
        return Response(status=400)
    value = await get_cache(key)
    if not value:
        value = await get_data_from_database(key)
        if not value:
            await cache_data(key, "")
            return Response(status=404)
        await cache_data(key, value)
    return Response(value)

上述代码中,我们使用了Python的异步IO库asyncio。我们通过定义两个异步函数get_cachecache_data来处理Redis的缓存读和写操作,而handle_request函数则用于处理HTTP请求。当有请求到达的时候,会先尝试从Redis中读取缓存数据,如果读取到缓存数据,则直接返回,否则我们会从数据库中查询对应的数据,并将查询结果写入到Redis中。如果在数据库中也不存在对应的数据,则我们会将其作为Null值写入到Redis中。

通过使用异步IO来实现Redis缓存穿透功能可以提高系统的性能,高并发下能够保证系统的稳定性。

   3.什么是缓存雪崩? 

    定义:系统运行时的某一个时刻,突然系统中的缓存全部失效,恰好在这个时期涌来大量客户端请求,导致所有模块缓存无法利用,大量请求涌向数据库导致的极端情况,数据库阻塞或者挂起。

    缓存存储:业务系统非常大,模块多  业务数据不同,不同模块在放入缓存时,都会设置一个缓存超时时间。

     如何解决? 1.永久存储(不推荐); 2.  针对不同的业务数据,设置不同的超时时间 (推荐)

    

 

 

 

  

posted on 2023-05-17 22:49  一先生94  阅读(16)  评论(0)    收藏  举报

导航