zoukankan      html  css  js  c++  java
  • redis深入学习(三)-----事务、主从复制、jedis

    reids事务

    概念

    可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其它命令插入,不许加塞

    作用

    一个队列中,一次性、顺序性、排他性的执行一系列命令

    常用命令

    正常操作事务:

    放弃事务:

     其实redis对于事务是部分支持:

     例如incr k1虽然是错误的(类似于java的运行时异常),但是其他几个结果依然可以成功操作。

    watch监控

    悲观锁/乐观锁/CAS(Check And Set) 

    1、悲观锁

    悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁

    2、乐观锁

    乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。

    乐观锁策略:提交版本必须大于记录当前版本才能执行更新

    3、CAS

    CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。

    更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。

    4、watch小结

    a、Watch指令,类似乐观锁,事务提交时,如果Key的值已被别的客户端改变,比如某个list已被别的客户端push/pop过了,整个事务队列都不会被执行

    b、通过WATCH命令在事务执行之前监控了多个Keys,倘若在WATCH之后有任何Key的值发生了变化,EXEC命令执行的事务都将被放弃,同时返回Nullmulti-bulk应答以通知调用者事务执行失败

    3阶段

    开启:以MULTI开始一个事务

    入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面

    执行:由EXEC命令触发事务

    3特性

    单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

    没有隔离级别的概念:队列中的命令没有提交之前都不会实际的被执行,因为事务提交前任何指令都不会被实际执行,也就不存在”事务内的查询要看到事务里的更新,在事务外查询不能看到”这个让人万分头痛的问题

    不保证原子性:redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚

    Redis的发布订阅 

    概念

    进程间的一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。

     

    命令

    主从复制 -----Redis的复制(Master/Slave)

    概念

    行话:也就是我们所说的主从复制,主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主

    1、一主二仆-----将军死了,士兵等待上级派新将军

     2、薪火相传

    上一个Slave可以是下一个slave的Master,Slave同样可以接收其他slaves的连接和同步请求,那么该slave作为了链条中下一个的master,可以有效减轻master的写压力。

    中途变更转向:会清除之前的数据,重新建立拷贝最新的。

    slaveof 新主库IP 新主库端口

     3、反客为主

    使当前数据库停止与其他数据库的同步,转成主数据库。-----将军死了,士兵替代他

    SLAVEOF no one

    作用

    1、读写分离

    2、容灾恢复

    配置

    1、配从(库)不配主(库)

    2、从库配置:slaveof 主库IP 主库端口

    每次与master断开之后,都需要重新连接,除非你配置进redis.conf文件。info replication可以查看当前redis服务信息,master or slave

    代表master为192.168.101.3,端口为6379

    复制原理

    1、slave启动成功连接到master后会发送一个sync命令

    2、Master接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,以完成一次完全同步

    3、全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。

    4、增量复制:Master继续将新的所有收集到的修改命令依次传给slave,完成同步

    5、但是只要是重新连接master,一次完全同步(全量复制)将被自动执行

    哨兵模式

    概念

    反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。一组sentinel能同时监控多个Master

    配置

    在redis目录下新建sentinel.conf文件,名字绝不能错

     sentinel monitor 被监控数据库名字(自己起名字) 127.0.0.1 6379 1

    上面最后一个数字1,表示主机挂掉后salve投票看让谁接替成为主机,得票数多少后成为主机

    启动

    总结:将军死了,士兵进行投票,票数合格的当选将军;此时将军又活了,回来变成小弟了。 

    缺点

    由于所有的写操作都是先在Master上操作,然后同步更新到Slave上,所以从Master同步到Slave机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave机器数量的增加也会使这个问题更加严重。

    jedis

    所需jar包

    commons-pool-1.6.jar、jedis-2.1.0.jar

    测试连通性

    public class Demo01 {
        public static void main(String[] args) {
            //连接本地的 Redis 服务
            Jedis jedis = new Jedis("127.0.0.1",6379);
            //查看服务是否运行,打出pong表示OK
            System.out.println("connection is OK==========>: "+jedis.ping());
        }
    }

    常用api

    package com.atguigu.redis.test;
    import java.util.*;
    import redis.clients.jedis.Jedis;
    
    public class Test02 {
        public static void main(String[] args) {
            Jedis jedis new Jedis("127.0.0.1",6379);
            
            //key
            Set<String> keys = jedis.keys("*");
            for(Iterator iterator = keys.iterator(); iterator.hasNext();) {
                String key = (String) iterator.next();
                System.out.println(key);
             }
             System.out.println("jedis.exists====>"+jedis.exists("k2"));
             System.out.println(jedis.ttl("k1"));
    
             //String
             //jedis.append("k1","myreids");
             System.out.println(jedis.get("k1"));
             jedis.set("k4","k4_redis");
             System.out.println("----------------------------------------");
             jedis.mset("str1","v1","str2","v2","str3","v3");
             System.out.println(jedis.mget("str1","str2","str3"));
         
            //list
             System.out.println("----------------------------------------");
             //jedis.lpush("mylist","v1","v2","v3","v4","v5");
             List<String> list = jedis.lrange("mylist",0,-1);
             for(String element : list) {
                System.out.println(element);
            }
         
            //set
             jedis.sadd("orders","jd001");
             jedis.sadd("orders","jd002");
             jedis.sadd("orders","jd003");
             Set<String> set1 = jedis.smembers("orders");
             for(Iterator iterator = set1.iterator(); iterator.hasNext();) {
                String string = (String) iterator.next();
                System.out.println(string);
            }
             jedis.srem("orders","jd002");
             System.out.println(jedis.smembers("orders").size());
             
            //hash
             jedis.hset("hash1","userName","lisi");
             System.out.println(jedis.hget("hash1","userName"));
             Map<String,String> map = new HashMap<String,String>();
             map.put("telphone","13811814763");
             map.put("address","atguigu");
             map.put("email","abc@163.com");
             jedis.hmset("hash2",map);
             List<String> result = jedis.hmget("hash2", "telphone","email");
             for(String element : result) {
                System.out.println(element);
             }
         
            //zset
             jedis.zadd("zset01",60d,"v1");
             jedis.zadd("zset01",70d,"v2");
             jedis.zadd("zset01",80d,"v3");
             jedis.zadd("zset01",90d,"v4");
         
             Set<String> s1 = jedis.zrange("zset01",0,-1);
             for(Iterator iterator = s1.iterator(); iterator.hasNext();) {
                String string = (String) iterator.next();
                System.out.println(string);
            }     
        }
    }

    事务提交

    主从复制 

    public static void main(String[] args) throws InterruptedException 
      {
         Jedis jedis_M new Jedis("127.0.0.1",6379);
         Jedis jedis_S new Jedis("127.0.0.1",6380);
         
         jedis_S.slaveof("127.0.0.1",6379);
         
         jedis_M.set("k6","v6");
         Thread.sleep(500);
         System.out.println(jedis_S.get("k6"));
      }

    jedispool

    package com.atguigu.redis.test;
    
    
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.JedisPoolConfig;
    
    
    public class JedisPoolUtil {
      
     private static volatile JedisPool jedisPool = null;//被volatile修饰的变量不会被本地线程缓存,对该变量的读写都是直接操作共享内存。
      
      private JedisPoolUtil() {}
      
      public static JedisPool getJedisPoolInstance()
     {
         if(null == jedisPool)
        {
           synchronized (JedisPoolUtil.class)
          {
              if(null == jedisPool)
             {
               JedisPoolConfig poolConfig new JedisPoolConfig();
               poolConfig.setMaxActive(1000);
               poolConfig.setMaxIdle(32);
               poolConfig.setMaxWait(100*1000);
               poolConfig.setTestOnBorrow(true);
                
                jedisPool new JedisPool(poolConfig,"127.0.0.1");
             }
          }
        }
         return jedisPool;
     }
      
      public static void release(JedisPool jedisPool,Jedis jedis)
     {
         if(null != jedis)
        {
          jedisPool.returnResourceObject(jedis);
        }
     }
    }
     
    package com.atguigu.redis.test;
    
    
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    
    
    public class Test01 {
      public static void main(String[] args) {
         JedisPool jedisPool = JedisPoolUtil.getJedisPoolInstance();
         Jedis jedis null;
         
         try 
         {
           jedis = jedisPool.getResource();
           jedis.set("k18","v183");
           
         } catch (Exception e) {
           e.printStackTrace();
         }finally{
           JedisPoolUtil.release(jedisPool, jedis);
         }
      }
    }
     

    配置总结:

    JedisPool的配置参数大部分是由JedisPoolConfig的对应项来赋值的。

    maxActive:控制一个pool可分配多少个jedis实例,通过pool.getResource()来获取;如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted。
    maxIdle:控制一个pool最多有多少个状态为idle(空闲)的jedis实例;
    whenExhaustedAction:表示当pool中的jedis实例都被allocated完时,pool要采取的操作;默认有三种。
       WHEN_EXHAUSTED_FAIL --> 表示无jedis实例时,直接抛出NoSuchElementException;
       WHEN_EXHAUSTED_BLOCK --> 则表示阻塞住,或者达到maxWait时抛出JedisConnectionException;
       WHEN_EXHAUSTED_GROW --> 则表示新建一个jedis实例,也就说设置的maxActive无用;
    maxWait:表示当borrow一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛JedisConnectionException;
    testOnBorrow:获得一个jedis实例的时候是否检查连接可用性(ping());如果为true,则得到的jedis实例均是可用的;

    testOnReturn:return 一个jedis实例给pool时,是否检查连接可用性(ping());

    testWhileIdle:如果为true,表示有一个idle object evitor线程对idle object进行扫描,如果validate失败,此object会被从pool中drop掉;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;

    timeBetweenEvictionRunsMillis:表示idle object evitor两次扫描之间要sleep的毫秒数;

    numTestsPerEvictionRun:表示idle object evitor每次扫描的最多的对象数;

    minEvictableIdleTimeMillis:表示一个对象至少停留在idle状态的最短时间,然后才能被idle object evitor扫描并驱逐;这一项只有在timeBetweenEvictionRunsMillis大于0时才有意义;

    softMinEvictableIdleTimeMillis:在minEvictableIdleTimeMillis基础上,加入了至少minIdle个对象已经在pool里面了。如果为-1,evicted不会根据idle time驱逐任何对象。如果minEvictableIdleTimeMillis>0,则此项设置无意义,且只有在timeBetweenEvictionRunsMillis大于0时才有意义;

    lifo:borrowObject返回对象时,是采用DEFAULT_LIFO(last in first out,即类似cache的最频繁使用队列),如果为False,则表示FIFO队列;

    ==================================================================================================================
    其中JedisPoolConfig对一些参数的默认设置如下:
    testWhileIdle=true
    minEvictableIdleTimeMills=60000
    timeBetweenEvictionRunsMillis=30000
    numTestsPerEvictionRun=-1

  • 相关阅读:
    C# Winform 使用Quartz
    C# datagridview显示行号
    C#时间格式问题解决,不受系统时间格式影响
    PLSQL永久激活
    C#内存回收
    Modbus的通信参数存在flash中,如果改乱了,该怎么办--FreeModbus从站设计(12)
    如何把Modbus的通信参数存在单片机的flash中--FreeModbus从站设计(11)
    为什么有的PLC需要上电停止功能,能防止PLC变砖(可编程控制器 串口通信)
    让串口和Modbus初始化的参数同步起来-STM32F103、FreeModbus从站设计(6)
    STM32F103、FreeModbus从站设计(5)-如何将FreeModbus代码加入keil工程
  • 原文地址:https://www.cnblogs.com/alimayun/p/11575372.html
Copyright © 2011-2022 走看看