redis学习笔记

redit允许的数据结构

StringHashListSetSortedSet

相关文章:https://juejin.im/post/5db66ed9e51d452a2f15d833

BloomFilter原理(布隆过滤器)

布隆过滤器(英语:Bloom Filter)是1970年由一个叫布隆的小伙子提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

上述描述引自维基百科,特点总结为如下:

  • 空间效率高的概率型数据结构,用来检查一个元素是否在一个集合中
  • 对于一个元素检测是否存在的调用,BloomFilter会告诉调用者两个结果之一:可能存在或者一定不存在。

相关文章:http://oserror.com/backend/bloomfilter/

总结:

  1. BloomFilter 仅仅只能确定该元素可能存在,存在false positive现象。
  2. BloomFilter对于某些数据能确定一定不存在。(效率很高)
  3. BloomFilter不允许自删的情况
  4. BloomFilter的大小有公式可查
  5. 其优势相对于:set、hash、bit。在允许一定的错判的情况下,其效率很高

常见使用常见:防止击穿

参考:https://juejin.im/post/5db69365518825645656c0de

           https://blog.csdn.net/jdsjlzx/article/details/43916241

Guava 中已经存在封装的布隆过过滤器

参考地址:https://juejin.im/post/5cc5aa7ce51d456e431adac5

https://www.jianshu.com/p/b60b0a3e8b9c

package com.ocean.cache;
 
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
 
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
 
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 
import com.google.common.base.Charsets;
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import com.ocean.dao.UserDao;
import com.ocean.dto.UserDto;
 
/**
 * 缓存击穿
 * @author 
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:config/spring/spring-dao.xml",
        "classpath:config/spring/spring-bean.xml",
        "classpath:config/spring/spring-redis.xml"})
public class CacheBreakDownTest {
    private static final Logger logger = LoggerFactory.getLogger(CacheBreakDownTest.class);
    
    private static final int THREAD_NUM = 100;//线程数量
    
    @Resource
    private UserDao UserDao;
    
    @Resource
    private RedisTemplate redisTemplate;
    
    private int count = 0;
    
    //初始化一个计数器
    private CountDownLatch countDownLatch = new CountDownLatch(THREAD_NUM);
    
    private BloomFilter<String> bf;
    
    List<UserDto> allUsers;
    
    @PostConstruct
    public void init(){
        //将数据从数据库导入到本地
        allUsers = UserDao.getAllUser();
        if(allUsers == null || allUsers.size()==0){
            return;
        }
        //创建布隆过滤器(默认3%误差)
        bf = BloomFilter.create(Funnels.stringFunnel(Charsets.UTF_8), allUsers.size());
        //将数据存入布隆过滤器
        for(UserDto userDto : allUsers){
            bf.put(userDto.getUserName());
        }
    }
    
    @Test
    public void cacheBreakDownTest(){
        for(int i=0;i<THREAD_NUM;i++){
            new Thread(new MyThread()).start();
            //计数器减一
            countDownLatch.countDown();
        }
        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    
    class MyThread implements Runnable{
 
        @Override
        public void run() {
            try {
                //所有子线程等待,当子线程全部创建完成再一起并发执行后面的代码
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //随机产生一个字符串
            String randomUser = UUID.randomUUID().toString();
//          String randomUser = allUsers.get(new Random().nextInt(allUsers.size())).getUserName();
            String key = "Key:"+randomUser;
            
            //如果布隆过滤器中不存在这个用户直接返回,将流量挡掉
            if(!bf.mightContain(randomUser)){
                System.out.println("bloom filter don't has this user");
                return;
            }
            //查询缓存,如果缓存中存在直接返回缓存数据
            ValueOperations<String,String> operation = (ValueOperations<String, String>) redisTemplate.opsForValue();
            synchronized (countDownLatch) {
                Object cacheUser = operation.get(key);
                if(cacheUser!=null){
                    System.out.println("return user from redis");
                    return;
                }
                //如果缓存不存在查询数据库
                List<UserDto> user = UserDao.getUserByUserName(randomUser);
                if(user == null || user.size() == 0){
                    return;
                }
                //将mysql数据库查询到的数据写入到redis中
                System.out.println("write to redis");
                operation.set("Key:"+user.get(0).getUserName(), user.get(0).getUserName());
            }
        }
        
    }
}

雪崩、穿透和击穿:

雪崩:缓存失效,大量请求打到数据库中。数据库也接着失效。

缓存穿透:缓存中查不到,每次你去数据库里查,也查不到。

缓存击穿:缓存击穿,就是说某个 key 非常热点,访问非常频繁,处于集中式高并发访问的情况,当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求数据库,就像是在一道屏障上凿开了一个洞。

参考文章:https://zhuanlan.zhihu.com/p/74880843

Redis 语法

参考文章:https://www.runoob.com/redis/redis-sorted-sets.html

 

redis多线程情况下避免读脏数据的悲观锁解决方案

学习地址:http://www.yelook.com/2227.html

redis 中能实现插旗子的语句叫做 setnx 。用法是 SETNX key value 。实现的功能是,当 key 值在 redis 库中不存在时,则建立这个 key 并设置对应的 value,且返回1。如果 key 值在库中存在时,则属于set失败,会返回0。

setnx 这个命令可以视为插旗子的动作,既可以检查旗子在不在,又能做到如果没有旗子在的时候插上去,此命令具有原子性。

所以思路图如下:

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
尚硅谷是一个教育机构,他们提供了一份关于Redis学习笔记。根据提供的引用内容,我们可以了解到他们提到了一些关于Redis配置和使用的内容。 首先,在引用中提到了通过执行命令"vi /redis-6.2.6/redis.conf"来编辑Redis配置文件。这个命令可以让你进入只读模式来查询"daemonize"配置项的位置。 在引用中提到了Redis会根据键值计算出应该送往的插槽,并且如果不是该客户端对应服务器的插槽,Redis会报错并告知应该前往的Redis实例的地址和端口。 在引用中提到了通过修改Redis的配置文件来指定Redis的日志文件位置。可以使用命令"sudo vim /etc/redis.conf"来编辑Redis的配置文件,并且在文件中指定日志文件的位置。 通过这些引用内容,我们可以得出结论,尚硅谷的Redis学习笔记涵盖了关于Redis的配置和使用的内容,并提供了一些相关的命令和操作示例。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Redis学习笔记--尚硅谷](https://blog.csdn.net/HHCS231/article/details/123637379)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Redis学习笔记——尚硅谷](https://blog.csdn.net/qq_48092631/article/details/129662119)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值