• 【JAVAEE基础学习(14)】--简述redis


    web2.0:
        由于上网设备与用户的激增使得网络访问数据量增大导致所有互联网平台压力激增。
        这使得整个互联网结构从原来的单点架构{
            一个网址->一个web服务器->一个数据库
        }转变为分布式架构{
            一个网址->
            多个代理服务器(用于请求分发{负载均衡},执行机制默认为轮循)->
            多个服务器的集群(将服务器分成不同集群:数据库集群,缓存数据库集群,文件集群,缓存集群)

        }这解决了原来单点架构中存在的{
            应用服务器的cpu及缓存压力--集群方式解决;
                分布式解决session问题:{
                    一、cookie(不安全;网络负担效率低)
                    二、存在文件服务器或数据库里(产生大量io效率问题)
                    三、session复制(session数据冗余,结点越多浪费越大)
                    四、缓存数据库,完全在内存中,速度快,数据结构简单(主流)
                }

            数据库服务器的的io压力{
                mysql单表数据存储量上限1000万,当数据量超1000万则考虑拆表(水平切表,垂直切库)
                将数据库集群设计为主从复制以实现读写分离,主写分读
                以上解决方案破坏了一定的业务逻辑来换取性能
            }
        }

    NoSQL{
        特点:快(基于键值对的存储方式)
        使用场景{
            高并发;数据量大;可扩展性要求高
        }不适用{
            需要事务支持
            需要即席(马上查,马上有结果)查询
            要sql的结构化查询存储
        }与memcache区别{
            memcache:不支持持久化;支持类型单一;采用多线程+锁机制
            redis:支持持久化;支持多种数据结构存储;采用单线程+io复用机制
        }
    }

    数据库排行:https://db-engines.com/en/ranking

    redis的基础知识{
        五大数据类型:string,list,set,zset(sorted set),hash
        每一个命令都是原子性的
        为了保证效率,数据均存于内存中
        会周期性把更新的数据写入磁盘中或者修改操作写入追加的记录文件,在此基础上主从同步
        redis的string类型可以存储二进制数据且数据安全
    }


    redis安装相关命令

    1. rpm -Uvh *.rpm --nodeps --force
    2. gcc -v
    3. g++ -v
    4. make distclean
    5. make install
    6. cd /usr/local/bin


    前台启动:{
        redis -server
        端口:6379、
    }
    后台启动

    1. mkdir /myredis
    2. cp /opt/redis-3.2.5/redis.conf /myredis
    3. cd /myredis
    4. ll
    5. vim redis.conf
    6. :set nu
    7. 61行注释
    8. 80行改no
    9. 128改yes
    10. :wq
    11. redis-server /myredis/redis.conf
    12. ps -ef|grep redis
    13. redis-cli
    14. redis-cli -p 端口 -h 指定ip
    15. ping
    16. 在redis中关闭redis服务:shutdown+ctrl+C
    17. ps -ef|grep redis
    18. 在用户层关闭redis:redis-cli -p 6379 shutdown


    redis效率高的原因{
        底层:单线程+io复用
        一个线程在检查多个文件就绪状态时,可以使用select,poll,epoll、进行检测
        select:循环机制,不停去检查哪一个文件就绪了(效率极低,99%循环可能都是做无用功)
        poll:poll改进select机制,由某一个文件的就绪状态通知,从所有的任务中查找到底是哪个就绪了,然后来完成就绪任务
        epoll:epoll是对poll的改进,可以直接获取到底是哪个文件就绪,并且直接处理,不用进行任何询问
    }


    redis的基本使用{

    1. redis一共16个库,从0号库开始
    2. 切换库:select 号数
    3. 查看库中表数据:dbsize
    4. 建立数据:set11
    5. 清当前库:flushdb
    6. 请所有库:flushall
    7. 查看当前库的所有键值:keys *
    8. 查看某个键值存不存在:exists 键
    9. 查看键的值类型:exists 键
    10. 删除某个键值:del 键
    11. 设置某一键值10秒过期:expire 键 10
    12. 查看某一键值还剩多少秒过期(过期时返回-2):ttl 键

    string类型命令

    1. 存(或覆盖)键值:
    2. set11
    3. 存(不覆盖)键值:
    4. setnx 键11
    5. 获取值:
    6. get
    7. 追加值:
    8. append 键 追加值
    9. 查看某个键值存不存在(返回数值大于0表示存在):
    10. exists 键
    11. 查看值的长度:
    12. strlen 键
    13. 对数值类型数据进行自增:
    14. incr 键
    15. 对数值类型数据进行自减:
    16. decr 键
    17. 对数值类型数据加100
    18. incrby 键 100
    19. 对数值类型数据减100
    20. decrby 键 100
    21. 批量插入键值对:
    22. mset 键112233
    23. 批量获取键值对:
    24. mget 键112233
    25. 批量插入(不覆盖)键值(只要插入键有一个存在值,此语句报废,由于原子性):
    26. msetnx 键112233
    27. 在某个键值对中取得指定开头,指定长度的子串:
    28. getrange 键 起始索引 指定长度
    29. 对键值中的子字符进行替换或在字符串末尾添加字符:
    30. setrange 键 指定索引 替换字符
    31. 限时存储键值对:
    32. setex 键 限时(秒为单位) 值
    33. 取出指定键的值并且给指定键赋新值:
    34. getset 键 新值


        list类型命令{
            底层为双向链表

            从左边放数据(实际存储格式:第一个值在做右端,最后一个值在最左端):lpush list 值1 值2 值3
            从右边放数据(实际存储格式:第一个值在做左端,最后一个值在最右端):rpush list 值1 值2 值3
            取(删除)最左端值:lpop list
            取(删除)最右端值:rpop list
            显示最左端从0号的4号的所有元素:lrange list 0 4
            显示所有数据:lrange list 0 -1
            显示指定0号的元素:lindex list 0
            展示list的长度: llen list
            在指定元素前面插入指定数据:linsert list before 指定元素 带插入元素
            从左边删除指定个数的元素:lrem list 指定数量 指定元素
        }
        set类型命令{
            redis中的set可以自动排除重复值,set是一个string类型的无序集合,
            其底层是一个value为null的hash表,所以增删查复杂度均为o(1)

            查看数据:smembers set
            向指定集合中放数据:sadd 自定义set 值1 值2 ... 值4
            返回数据长度:scard set集合
            删除指定元素:srem set集合 指定值1 指定值2
            随机删除并且返回被删除的元素:spop myset
            随机展示set集合中的指定个数的元素:srandmember 指定set 指定个数
            取两个集合的交集:sinter 自定义set1 自定义set2
            取两个集合的并集:sunion 自定义set1 自定义set2
            取差集,只取自定义set1中独有的元素: sdiff 自定义set1 自定义set2
            取差集,只取自定义set2中独有的元素: sdiff 自定义set2 自定义set1
        }
        hash类型命令{
            redis中的hash是string类型的field和value映射表即键值对集合,适用于存储对象
            在redis中存储用户数据的方式:map>。这种存储方式比map好在避免了对象的序列化和反序列化;这种存储方式比map好在避免了key的长度过长

            向hash表中存储一个对象{
                单条输入{
                    hset 对象名称1 name 名字
                    hset 对象名称1 age 年龄
                    hset 对象名称1 phone 电话
                }
                
                多条输入:hmset 对象名称2 name 名字值 age 年龄值 phone 电话值
            }
            取hash集合中指定对象的名字:hget 对象名称 name
            查看hash集合中指定对象的指定属性是否存在(返回1表示存在):hexists 对象名称 指定属性
            查看hash集合中指定对象的属性(不是属性值):hkeys 对象名称
            查看hash集合中指定对象的属性值: hvals 对象名称
            对hash集合中指定对象的数值属性进行加值(可以加负值)操作:hincrby 对象名称 age 2
            对hash集合中指定对象的属性进行添加(不覆盖)操作
                (属性有值,命令不执行,属性没有值,命令执行成功):hsetnx 对象名称 age 77
        }
        Zset类型命令{
            zset是一个有顺序不重复的string类型集合,时间复杂度为o(1)

            向zset集合中添加元素:zadd zset名称 评分数值1 值1 评分数值2 值2 评分数值3 值3
            展示zset集合中指定下标间的元素(默认按数值从小到大展示):zrange zset名称 起始下标 终止下标
            展示zset集合中指定下标间的元素和其评分数值(默认按数值从小到大展示):zrange zset名称 起始下标 终止下标 withscores
            展示zset中指定评分间的数据:zrangebyscore zset名称 指定评分1 指定评分2
            展示zset中指定评分间的数据和其数值:zrangebyscore zset名称 指定评分1 指定评分2 withscores
            展示zset中指定评分间的数据和其数值带分页:zrangebyscore zset名称 指定评分1 指定评分2 withscores limit 开始索引 查询条数
            展示zset中指定评分间且评分从大到小的数据和其数值带分页:zrevrangebyscore zset名称 指定评分1 指定评分2 withscores limit 开始索引 查询条数
            给指定的值加评分:zincrby zset名称 增加的分数 指定的值
            删除zset中的值:zrem zset名称 指定的值
            统计指定评分间的元素个数:zcount zset名称 起始评分 终止评分
            查询指定值在集合中的排名(从小到大排,从0开始计):zrank zset名称 指定值

        }
        分页中用于计算开始索引的公式:(pagenum-1)*pagesize
    }

    linux下的四种安装方式{
        1.RPM
            rpm -qa|grep 目标软件名称    查询所有安装过rpm软件 | 过滤找到目标软件
            rpm -e 目标软件名称      卸载rpm的目标软件
            rpm -ivh 目标软件名称全称(包含版本)     安装rpm版本的目标软件

        2.Yum
            yum list|grep 目标软件      查询已经安装的目标软件
            yum install 目标软件        安装目标软件

        3.tar
            tar -zxvf 目标软件  解压即安装(java,tomcat)


        4.mank &&make install
            如redis

    }

    在vim中跳到指定行号:
        指定行号+shift+g


    redis事务{
        redis事务的主要作用就是串联多个命令防止别的命令插队
        mysql事务是将多个语句串联不可分割;
        mysql隔离级别:1(未提交读),2(已提交读),4(重复读),8(可序列化)

        Multi:将命令组队
        Exec:将组好队的命令执行
        discard:取消命令队

        实例一{
            组队成功,提交成功
            set k1 v1
            set k2 v2
            exec
        }
        实例二{
            组队报错,提交失败
            set k1 v1
            set k2
            exec
        }
        实例三{
            组队成功,提交失败
            1.set k1 v1
            2.incr k1     //对字符串v1执行++操作
            3.set k2 v2
            4.exec

            执行结果:只有1、3成功,2是失败的,这与mysql区别在于,mysql要么全部执行,要么全都不执行
        }
    }

    redis事务{
        悲观锁{
            类比串行
            在数据库中有行锁,表锁
        }
        乐观锁{
            支持并行,会对数据添加版本号,在同时操作事务后,执行时就看哪一个事务先提交,只要有一个事务提交,数据版本号马上改变,后面的事务便无法再提交因为版本号不同的原因,在提交事务后,如果再有事务同时操作数据,情况同上。乐观锁多用于数据的读,以提高数据的吞吐量。redis是利用check_and_set机制实现事务
        }
        实例一:{
            set balance 100
            watch balance   //添加乐观锁
            multi
            decrby balance 10
            incrby balance 10
            exec    //自动释放乐观锁,执行discard也会释放乐观锁
        }
        当redis执行已经添加乐观锁的事务时,乐观锁中的事务要么一起执行,要么一起不执行
        unwatch对所有的key取消乐观锁

        事务三特性:单独隔离的操作;无隔离级别的概念;不保证原子性
    }


    秒杀案例{
        库存表
        秒杀成功用户表
        使用压力测试工具ab发起get请求{
            ab -n 1000 -c 100 http://ip:端口/项目名称/请求路径?username=值
        }发起post请求{
            先写一个postfile无后缀名称的文件内容为{
                username=值&
            }
            再:ab -n 1000 -c 100 -p postfile -T 'application/x-www-form-urlencoded' http://ip:端口/项目名称/请求路径
        }
        出现问题一{
            问题:超卖
            解决方法:加乐观锁
        }
        出现问题二{
            问题:请求并发量超过一定数量,服务器拒绝连接
            解决(在测试命令中加-r):ab -n 5000 -c 1000  -r  -p postfile -T 'application/x-www-form-urlencoded' http://ip:端口/项目名称/请求路径
        }
        问题三{
            问题:连接超时
            解决:设置连接池缓解
            几个参数:
                MaxTotal:最大连接数
                maxIdle:最小空闲连接数
                MaxWaitMilis:最大等待时间
                testOnBorrow:测试连接可用性
        }
        问题四{
            问题:库存遗留问题
            原因:乐观锁导致
            解决:使用LUA脚本(嵌入式脚本语言,常用于编写插件、外挂)
            注:只有redis2.6以上版本才能使用lua脚本
            解决实质:redis通过lua解决争抢问题,实际上是redis利用其单线程的特性,用任务队列的方式解决多任务并发问题
        }
    }

    redis持久化RDB(Redis DataBase){
        原理:采用时间间隔的方式进行数据的快照存盘
        备份原理:redis把内存数据保存到硬盘的过程中会单独复制一个进程,这个进程会先将数据写到一个临时文件中,等持久化过程结束,再用这个临时文件替换上次持久好的文件
        注:RDB方式比AOF方式更加高效,RDB的缺点是最后一次持久化后的数据可能丢失
        备份操作{
            做备份的命令:
                cp dump.rdb dump.rdb.bak
            在有部分文件的情况下误删了数据正确的做法是马上停止redis服务器,然后执行
                cp dump.rdb.bak dump.rdb
            即可恢复数据
        }
        优点:适合大规模数据恢复;对数的完整性、一致性要求不高,节省磁盘空间,恢复速度快
        缺点:Fork时,内存中克隆了一份数据,大约2倍的膨胀性需要考虑,在数据庞大是比较消耗性能,会损失最后一次快照后的所有修改
        
    }
    redis持久化(Append Of File){
        持久化策略:
            以日志的形式记录每个写操作(增量保存),只记录写操作,只要一产生写操作,aof马上记录,
            只允许追加文件不可以修改文件,因此aof保存的数据最全,
        AOF配置:
            由于AOF默认不开启,所以要开启需要到redis.cnf中,找到593行appendonly on设置为yes
        AOF回复:
            1.自然恢复:
                cp appendonly.aof.bak appendonly.aof
            2.手动恢复:
                vim appendonly.aof然后再appendonly.aof中修改特殊内容(如误删命令flushall),
                然后保存appendonly.aof,再重启redis服务器
            3.appendonly.aof内容修改有误:
                redis服务器无法启动,此时可以通过/uer/local/bin/redis-check-aof --fi appendonly.aof
                进行修复,但会导致一部分数据丢失
        AOF同步频率设置:
            appendfsync always:每次redis的写入都立刻记入日志,性能较差,但数据最全
            appendfsync everysec:每秒同步,若服务器宕机,本秒数据丢失
            appendfsync no:redis不主动进行同步,把同步时机交给操作系统

        rewrite重写机制:
            合并同类项{把好几项相同添加操作合并为一句添加操作,且数据总数目不变}
            触发重写机制:
                auto-aof-rewite-peroentage:设置重写基准值,文件达到100%时开始重写(文件是原来重写后文件的2倍时触发)
                auto-aof-rewite-min-size:设置重写的基本值,最小文件64MB。达到这个值开始重写
    }

    主从复制:{
        将Master写操作主机和Slave读主机分离,扩展性能,缓解数据库压力
            "一主二从"环境搭建:
                在一个linux操作系统中:
                    创建三个配置文件{
                        include /myredis/redis.conf
                        pidfile /var/run/redis_指定的三个端口号.pid
                        port 指定的三个端口号
                        dbfilename dump指定的三个端口号.rdb
                        slave-priority 10 //设定优先级别,值越小当备用机优先级别越高

                        实例{
                            include /myredis/redis.conf
                            pidfile /myredis/redis6380.pid
                            port 6380
                            dbfilename dump6380.rdb
                        }
                        启动三个redis服务器:redis-server /myredis/redis指定.conf
                        查看进程:ps -ef|grep redis
                        登录redis数据库后,查看主从状态:info replication
                        配置主从状态-配从不配主:slaveof 192.168.174.125 6379
                        主机挂机,重启如初,从机挂机需要重新设置:slaveof ip 端口

                    }
                    vim中全局替换:
                    %s/目标字符串/替换字符串
                    主从复制原理:
                        当主机有从机时,主机会启用bgsave将数据存在RDB文件中,从机拿主机的RDB文件替换从机原来的RDB文件

        注:
            当RDB与AOF同时开启,系统默认取AOF的数据(即使指定输入 cp dump.rdb.bak dump.rdb 命令也只会取aof的数据)
            AOF是一个文本文件,对数据不敏感可以使用RDB,不建议单独使用aof,因为可能出现bug,禁用RDB{执行save ""}
    }

  • 相关阅读:
    TCP/IP_第八章_静态路由_实验案例一
    element之自定义表格超出显示省略号并显示文字提示(tooltip)
    美团2024届秋招笔试第一场编程[汇总](上课口胡一下)
    redis高可用
    单线程介绍、ECMAScript介绍、操作系统Windows、Linux 和 macOS
    [Unity3d] 网络开发基础【个人复习笔记/有不足之处欢迎斧正/侵删】
    点到直线的距离直线的交点及夹角
    java - IDEA IDE - 设置字符串断点
    Oracle数据库:oracle内连接inner join on,多表查询各种自链接、内连接、外连接的练习示例
    从优先队列到实现堆排序
  • 原文地址:https://blog.csdn.net/qq_55865959/article/details/126937243