• Redis随笔


    NoSql是为了解决高并发、大规模存储、高可用、高可扩展等一系列问题而产生的数据库解决方案。
    NoSql,非关系型的数据库,全称Not only sql。它不能替代关系型数据库,只能作为关系型数据库的一个良好补充。
    目前的NoSql有:
    key-value对存储(Redis  MemcacheDB, 快, 适合做缓存)
    列存储(Hbase, 适合大规模存储)
    文档存储(MongoDB, 像SQL, 灵活)
    图形数据库(Neo4j 面向关系)

    Redis是使用C语言开发的一个高性能键值数据库。
    键值类型有:
    String 字符类型
    hashmap 散列类型
    list 列表类型
    set 集合类型, 唯一
    sortedset/zset 有序集合类型

    不同的键值类型对应不同的操作. 具体见redis文档

    Redis持久化
    1)Rdb方式
    Redis默认方式,redis通过快照将数据持久化到磁盘中。
    一旦redis被非法关闭,就会丢失最后一次持久化后的数据。
    2)Aof方式
    Redis默认不使用。Aof方式是将每次对数据库的操作记录存储到aof持久化文件中。
    开启aof方式的持久化方案: 将redis.conf中的appendonly改为yes。
    如果数据不允许丢失,那么要使用aof方式。
    同时使用aof和rdb方式时,如果redis重启,则数据从aof文件加载。

    主从复制

    作用:
    1)避免单点故障
    2)读写分离, 从库承担读的任务, 从库承担持久化的任务

    从库也可以作为其他库的主库, 如下结构能减轻主库同步压力

    复制原理:
    1)当从库和主库建立MS关系后,会向主数据库发送SYNC命令;
    2)主库接收到SYNC命令后, 开始在后台保存快照(RDB持久化,即使禁用rdb也会进行),并将期间接收到的写命令缓存起来;
    3)主库将快照文件和 缓存的写命令 发送给从库;
    4)从库接收到后,载入快照文件并且执行收到的缓存写命令 ;
    5)之后,主库每接到写命令时就会将命令发送从库,从而保证数据一致
    注:Redis目前实现了无磁盘复制功能, 不会在磁盘生成快照,而直接通过网络发送给从数据库,避免IO性能问题。
    开启无磁盘复制:repl-diskless-sync yes

    主从复制架构中的宕机恢复
    1. 从Redis宕机
    从库重新启动后会自动加入到主从架构中,自动完成数据同步(增量复制)。
    2. 主Redis宕机
    1)在从库中执行SLAVEOF NO ONE命令,断开主从关系, 并且提升从库为主库继续服务;
    2)将主库重新启动后,执行SLAVEOF命令,将其设置为从库,这时数据就能更新回来;
    手动处理容易出错, 推荐使用Redis的哨兵(sentinel)功能。

    哨兵是一个独立进程, 对Redis的运行情况进行监控, 在主库宕机后会自动将从库转为主库
    启动哨兵进程首先需要创建哨兵配置文件:
    sentinel.conf
    内容:
    sentinel monitor redisName 127.0.0.1 6379 1
    说明:
    redisName 监控主数据的名称,自定义
    127.0.0.1:监控的主数据库的IP
    6379:监控的主数据库的端口
    1:最低通过票数
    启动哨兵进程:
    redis-sentinel ./sentinel.conf

    哨兵无需配置slave,只需要指定master,哨兵会自动发现slave
    可以配置多个哨兵, 多个哨兵不仅同时监控主从数据库,哨兵之间也互为监控。

    集群

    整个Redis集群提供了16384个插槽,客户端只需要连接集群中任何一个节点即可访问整个集群
    配置核心是redis-trib.rb的ruby脚本
    1)创建并分配16384个插槽:
    ./redis-trib.rb create --replicas 0 192.168.56.102:6379 192.168.56.102:6380 192.168.56.102:6381
    --replicas 0:指定了从数据的数量为0
    2)重新分配插槽:
    ./redis-trib.rb reshard 192.168.56.102:6380
    3)删除节点:
    ./redis-trib.rb del-node 192.168.56.102:6380 4a9b8886ba5261e82597f5590fcdb49ea47c4c6c

    当集群中的任何一个节点下线,就会导致插槽区有空档不完整,集群将不可用
    所以集群一般会构建成: 集群+主从复制
    创建集群, 创建顺序为主库(3个)、从库(3个):
    ./redis-trib.rb create --replicas 1 192.168.56.102:6379 192.168.56.102:6380 192.168.56.102:6381 192.168.56.102:6479 192.168.56.102:6480 192.168.56.102:6481
    于是某台数据库宕机不会影响集群正常服务, 类似哨兵有自我恢复功能

    Jedis示例

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:spring/applicationContext*.xml")
    public class JedisTest {
        @Test
        public void jedisByConn() {  // 避免使用, 用连接池代替
            Jedis jedis = new Jedis("192.168.133.13", 6379);
            jedis.set("test", "hello redis");
            String string = jedis.get("test");
            System.out.println(string);
            jedis.close();
        }
        @Test
        public void jedisPool() {
            JedisPool pool = new JedisPool("192.168.133.13", 6379);
            Jedis jedis = pool.getResource();
            String string = jedis.get("test");
            System.out.println(string);
            jedis.close();
            pool.close();
        }
        @Test
        public void testJedisCluster() {
            Set<HostAndPort> nodes = new HashSet<HostAndPort>();
            for (int i = 0; i < 6; ++i) {
                nodes.add(new HostAndPort("192.168.133.13", 7001 + i));
            }
            JedisCluster cluster = new JedisCluster(nodes);
            cluster.set("name", "张三");
            System.out.println(cluster.get("name"));
            cluster.close();
        }
        
        @Resource(name = "jedisClientSingle")
        private JedisClient jedisClient1;
        @Test
        public void jedisSingleSpring() {
            jedisClient1.set("client1", "1000");
            String string = jedisClient1.get("client1");
            System.out.println(string);
        }
        @Resource(name = "jedisClientCluster")
        private JedisClient jedisClient2;
        @Test
        public void jedisClusterSpring() {
            jedisClient2.set("client2", "2000");
            String string = jedisClient2.get("client2");
            System.out.println(string);
        }
    }

    spring配置

    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
            <!-- 最大连接数 -->
            <property name="maxTotal" value="30" />
            <!-- 最大空闲连接数 -->
            <property name="maxIdle" value="10" />
            <!-- 每次释放连接的最大数目 -->
            <property name="numTestsPerEvictionRun" value="1024" />
            <!-- 释放连接的扫描间隔(毫秒) -->
            <property name="timeBetweenEvictionRunsMillis" value="30000" />
            <!-- 连接最小空闲时间 -->
            <property name="minEvictableIdleTimeMillis" value="1800000" />
            <!-- 连接空闲多久后释放, 当空闲时间 > 该值 且 空闲连接 > 最大空闲连接数 时直接释放 -->
            <property name="softMinEvictableIdleTimeMillis" value="10000" />
            <!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
            <property name="maxWaitMillis" value="1500" />
            <!-- 在获取连接的时候检查有效性, 默认false -->
            <property name="testOnBorrow" value="true" />
            <!-- 在空闲时检查有效性, 默认false -->
            <property name="testWhileIdle" value="true" />
            <!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
            <property name="blockWhenExhausted" value="false" />
        </bean>
        
        <!-- 单机版redis, "池"化, 避免频繁打开关闭连接  -->
        <bean id = "jedisPool" class = "redis.clients.jedis.JedisPool" destroy-method="close">  <!-- 需关闭池 -->
            <constructor-arg name = "host" value="192.168.133.13"></constructor-arg>
            <constructor-arg name = "port" value="6379"></constructor-arg>
            <constructor-arg name="poolConfig" ref="jedisPoolConfig" />   <!-- 也可不配,直接使用默认值 -->
        </bean>
    
        <!-- 集群版redis -->
        <bean id = "jedisCluster" class = "redis.clients.jedis.JedisCluster" destroy-method="close">
            <constructor-arg name = "nodes">
                <set>
                    <bean class = "redis.clients.jedis.HostAndPort">
                        <constructor-arg name = "host" value="192.168.133.13"></constructor-arg>
                        <constructor-arg name = "port" value="7001"></constructor-arg>
                    </bean>
                    <bean class = "redis.clients.jedis.HostAndPort">
                        <constructor-arg name = "host" value="192.168.133.13"></constructor-arg>
                        <constructor-arg name = "port" value="7002"></constructor-arg>
                    </bean>
                    <bean class = "redis.clients.jedis.HostAndPort">
                        <constructor-arg name = "host" value="192.168.133.13"></constructor-arg>
                        <constructor-arg name = "port" value="7003"></constructor-arg>
                    </bean>
                    <bean class = "redis.clients.jedis.HostAndPort">
                        <constructor-arg name = "host" value="192.168.133.13"></constructor-arg>
                        <constructor-arg name = "port" value="7004"></constructor-arg>
                    </bean>
                    <bean class = "redis.clients.jedis.HostAndPort">
                        <constructor-arg name = "host" value="192.168.133.13"></constructor-arg>
                        <constructor-arg name = "port" value="7005"></constructor-arg>
                    </bean>
                    <bean class = "redis.clients.jedis.HostAndPort">
                        <constructor-arg name = "host" value="192.168.133.13"></constructor-arg>
                        <constructor-arg name = "port" value="7006"></constructor-arg>
                    </bean>
                </set>
            </constructor-arg>
            <constructor-arg name="poolConfig" ref="jedisPoolConfig"></constructor-arg>  <!-- 也可不配,直接使用默认值 -->
        </bean>

    Redis与并发

    并发访问临界资源存在安全问题, 两大解决方法
    直接: 使用锁等机制进行原子性及可见性控制
    间接: 使用队列等串行化.
    Reids使用单线程, 对Redis的请求会被系统排队, 可利用这个特点检查从Redis的返回值, 以此决定访问顺序

  • 相关阅读:
    设置DataGridView垂直滚动条
    在自定义MessageBox控件里添加键盘回车事件。
    通过访问注册表,表判断系统是否装excel
    让文本框里只能输入数字
    新晋菜鸟的错误
    jdbc连接数据库以及crud(简单易懂,本人亲测可用 有源代码和数据库)
    springboot 错误求解决
    maven 导包报错
    最短路径Dijkstra
    读写者问题
  • 原文地址:https://www.cnblogs.com/myJavaEE/p/6706545.html
Copyright © 2020-2023  润新知