栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Redis学习记录

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Redis学习记录

一、Redis五大数据类型

1. 字符串String
setnx为redis分布式锁底层
2. 列表List
3. 集合Set
4. 哈希Hash
value为K-V形式
5. 有序集合Zset
真实需求:
充10元可享vip1;
充20元可享vip2;
充30元可享vip3;


二、持久化

1. RDB
在指定的时间间隔内,将内存中的数据集的快照写入磁盘;默认保存在/usr/local/bin中,文件名dump.rdb;(自动备份,也可以执行命令 save手动备份)

优势and劣势

  • 优:适合大规模数据恢复,对数据完整性和一致行要求不高;
  • 劣:一定间隔备份一次,意外down掉,就失去最后一次快照的所有修改

2. AOF

  • 以日志的形式记录每个写操作;
  • 将redis执行过的写指令全部记录下来(读操作不记录);
  • 只许追加文件,不可以改写文件;
  • redis在启动之初会读取该文件从头到尾执行一遍,这样来重新构建数据;

3. 总结

  • RDB:只用作后备用途,建议15分钟备份一次就好
  • AOF:
    • 在最恶劣的情况下,也只丢失不超过2秒的数据,数据完整 性比较高,但代价太大,会带来持
      续的IO
    • 对硬盘的大小要求也高,默认64mb太小了,企业级最少都是5G以上;
    • master/slave才是新浪微博的选择

三、事务
  • 可以一次执行多个命令,是一个命令组,一个事务中,所有命令都会序列化(排队),不会被插
    队;
  • 一个队列中,一次性,顺序性,排他性的执行一系列命令
    reids-check-aof --fix appendonly.aof
  • 三特性
    • 隔离性:所有命令都会按照顺序执行,事务在执行的过程中,不会被其他客户端送来的命令
      打断
    • 没有隔离级别:队列中的命令没有提交之前都不会被实际的执行,不存在“事务中查询要看到
      事务里的更新,事务外查询不能看到”这个头疼的问题
    • 不保证原子性:冤有头债有主,如果一个命令失败,但是别的命令可能会执行成功,没有回
  • 三步走
    开启multi
    入队queued
    执行exec

四、Redis的发布订阅

进程间的一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。例如:微信订阅号;订阅一个或多个频道


五、主从复制
  • 就是 redis集群的策略
  • 配从(库)不配主(库):小弟可以选择谁是大哥,但大哥没有权利去选择小弟
  • 读写分离:主机写,从机读

1. 血脉相传

  • 一个主机理论上可以多个从机,但是这样的话,这个主机会很累
  • 我们可以使用java面向对象继承中的传递性来解决这个问题,减轻主机的负担,形成祖孙三代

2. 谋权篡位

  • 1个主机,2个从机,当1个主机挂掉了,只能从2个从机中再次选1个主机
  • 国不可一日无君,军不可一日无帅
  • 手动选老大
  • 模拟测试:1为master,2和3为slave,当1挂掉后,2篡权为master,3跟2
  • 当1再次回归,2和3已经形成新的集群,和1没有任何的关系了。所以1成为了光杆司令

3. 复制原理

  • 全量复制:Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份slave接收到数据
    文件后,存盘,并加载到内存中;(步骤1234)
  • 增量复制:Slave初始化后,开始正常工作时主服务器发生的写操作同步到从服务器的过程;(步
    骤56)
    • 但,只要是重新连接master,一次性(全量复制)同步将自动执行;
  • Redis主从同步策略:主从刚刚连接的时候,进行全量同步;全同步结束后,进行增量同步。
  • 当然,如果有需要,slave 在任何时候都可以发起全量同步。
  • redis 策略是,无论如何,首先会尝试进行增量同步,如不成功,要求从机进行全量同步。

4. 哨兵模式

  • 自动版的谋权篡位
  • 有个哨兵一直在巡逻,突然发现!!!!!老大挂了,小弟们会自动投票,从众小弟中选出新的老
  • Sentinel是Redis的高可用性解决方案(因为主机负责写入,不能没有主机):
    • 由一个或多个Sentinel实例组成的Sentinel系统可以监视任意多个主服务器,以及所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级,为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求

六、Jedis(Java操作Redis)

java和redis打交道的API客户端


	redis.clients
	jedis
	3.1.0

1. 连接redis

public static void main(String[] args) {

	Jedis jedis = new Jedis("192.168.204.141",6379);
	String pong = jedis.ping();
	System.out.println("pong = " + pong);
}

// 运行前:
// 1.关闭防火墙 systemctl stop firewalld.service
// 2.修改redis.conf [ bind 0.0.0.0 ] 允许任何ip访问,以这个redis.conf启动redis服务
(重启redis)
// redis-server /opt/redis5.0.4/redis.conf

2. 事务


七、JedisPool

redis的连接池技术


	commons-pool
	commons-pool
	1.6

“一个池”使用单例模式进行优化

public class JedisPoolUtil {

    private JedisPoolUtil(){}

    private volatile static JedisPool jedisPool = null;
    private volatile static Jedis jedis = null;

    // 返回一个连接池
    private static JedisPool getInstance(){
        // 双层检测锁(企业中用的非常频繁)
        if(jedisPool == null){ // 第一层:检测体温
            synchronized (JedisPoolUtil.class){  // 排队进站
                if(jedisPool == null) { //第二层:查看健康码
                    JedisPoolConfig config = new JedisPoolConfig();
                    config.setMaxTotal(1000);
                    config.setMaxIdle(30);
                    config.setMaxWaitMillis(60*1000);
                    config.setTestOnBorrow(true);
                    jedisPool = new JedisPool( config, "192.168.204.141",6379 );
                }
            }
        }
        return jedisPool;
    }

    // 返回jedis对象
    public static Jedis getJedis(){
        if(jedis == null){
            jedis = getInstance().getResource();
        }
        return jedis;
    }
}

测试类

public class Test_JedisPool {
    public static void main(String[] args) {
        Jedis jedis1 = JedisPoolUtil.getJedis();
        Jedis jedis2 = JedisPoolUtil.getJedis();

        System.out.println(jedis1==jedis2);
    }
}

八、高并发下的分布式锁
  • 经典案例:秒杀,抢购优惠券等
    
        
            org.springframework
            spring-webmvc
            5.2.7.RELEASE
        
        
        
            org.redisson
            redisson
            3.6.1
        
        
        
            org.springframework.data
            spring-data-redis
            2.3.2.RELEASE
        
        
        
            redis.clients
            jedis
            3.1.0
        
        
        
            com.fasterxml.jackson.core
            jackson-databind
            2.9.8
        
    
    
        
            
                org.apache.tomcat.maven
                tomcat7-maven-plugin
                2.2
                
                    8002
                    /
                
                
                    
                        
                        package
                        
                            run
                        
                    
                
            
        
    

synchronized锁的一个进程下的线程并发,如果分布式环
境,多个进程并发,这种方案就失效了!只能解决一个tomcat的并发问题

1. 实现分布式锁的思路
  • . 因为redis是单线程的,所以命令也就具备原子性,使用setnx命令实现锁,保存k-v
    • 如果k不存在,保存(当前线程加锁),执行完成后,删除k表示释放锁
    • 如果k已存在,阻塞线程执行,表示有锁
  • 如果加锁成功,在执行业务代码的过程中出现异常,导致没有删除k(释放锁失败),那么就会造
    成死锁(后面的所有线程都无法执行)!
    • 设置过期时间,例如10秒后,redis自动删除
  • 高并发下,由于时间段等因素导致服务器压力过大或过小,每个线程执行的时间不同
    • 第一个线程,执行需要13秒,执行到第10秒时,redis自动过期了k(释放锁)
    • 第二个线程,执行需要7秒,加锁,执行第3秒(锁 被释放了,为什么,是被第一个线程的
      finally主动deleteKey释放掉了)
    • 。。。连锁反应,当前线程刚加的锁,就被其他线程释放掉了,周而复始,导致锁会永久失
  • 给每个线程加上唯一的标识UUID随机生成,释放的时候判断是否是当前的标识即可
  • 问题又来了,过期时间如果设定?
    • 如果10秒太短不够用怎么办?
    • 设置60秒,太长又浪费时间
    • 可以开启一个定时器线程,当过期时间小于总过期时间的1/3时,增长总过期时间(吃仙丹续
      命!)

九、Redisson
  • Redis 是最流行的 NoSQL 数据库解决方案之一,而 Java 是世界上最流行(注意,我没有说“最
    好”)的编程语言之一。
  • 虽然两者看起来很自然地在一起“工作”,但是要知道,Redis 其实并没有对 Java 提供原生支持。
  • 相反,作为 Java 开发人员,我们若想在程序中集成 Redis,必须使用 Redis 的第三方库。
  • 而 Redisson 就是用于在 Java 程序中操作 Redis 的库,它使得我们可以在程序中轻松地使用
    Redis。
  • Redisson 在 java.util 中常用接口的基础上,为我们提供了一系列具有分布式特性的工具类。
@Controller
public class TestKill {

    @Autowired
    private Redisson redisson;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @RequestMapping("kill")
    // 只能解决一个tomcat的并发问题:synchronized锁的一个进程下的线程并发,如果分布式环境,多个进程并发,这种方案就失效了!
    public @ResponseBody synchronized String kill() {

        // 定义商品id
        String productKey = "HUAWEI-P40";
        // 通过redisson获取锁
        RLock rLock = redisson.getLock(productKey); // 底层源码就是集成了setnx,过期时间等操作
        // 上锁(过期时间为30秒)
        rLock.lock(30, TimeUnit.SECONDS);

        try{
        // 1.从redis中获取 手机的库存数量
        int phoneCount = Integer.parseInt(stringRedisTemplate.opsForValue().get("phone"));
        // 2.判断手机的数量是否够秒杀的
        if (phoneCount > 0) {
            phoneCount--;
            // 库存减少后,再将库存的值保存回redis
            stringRedisTemplate.opsForValue().set("phone", phoneCount + "");
            System.out.println("库存-1,剩余:" + phoneCount);
        } else {
            System.out.println("库存不足!");
        }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            // 释放锁
            rLock.unlock();
        }
        return "over!";
    }


    @Bean
    public Redisson redisson(){
        Config config = new Config();
        // 使用单个redis服务器
        config.useSingleServer().setAddress("redis://192.168.204.141:6379").setDatabase(0);
        // 使用集群redis
        // config.useClusterServers().setScanInterval(2000).addNodeAddress("redis://192.168.204.141:6379","redis://192.168.204.142:6379","redis://192.168.204.143:6379");
        return (Redisson)Redisson.create(config);
    }
}
  • 实现分布式锁的方案其实有很多,我们之前用过的zookeeper的特点就是高可靠性,现在我们用的
    redis特点就是高性能。
  • 目前分布式锁,应用最多的仍然是“Redis”
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/855113.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号