首页 文章 精选 留言 我的

精选列表

搜索[java],共10000篇文章
优秀的个人博客,低调大师

Java 开源开发平台 O2OA V7.2.0 发布,新增系统配置图形化模块和企业文件模块!

O2OA V7.2.0 发布,新增了平台配置中的【系统配置图形化模块】和企业网盘【企业文件模块】。 O2OA V7.2.0中,新增了【系统配置图形化模块】,在系统配置中点击界面配置,可以对系统界面进行个性化的更改,比如选择进入系统时的状态,以及系统皮肤的更换等。 ​ 在O2OA V7.2.0新版本系统配置中,新增服务器配置,可以更直观地看到服务器信息。 ​ 在O2OA V7.2.0系统配置中,点击资源部署,就能部署您自定义开发的O2OA组件(从官方获取的组件也可直接进行部署)。 ​ 在O2OA V7.2.0系统配置中,点击系统信息,可以更直观地看到每个模块的运行情况,集群情况。 ​ 在资源部署中,可以用前端来部署web资源和自定义程序。 ​ 选择数据库配置,可以看到该版本现已支持在前端直接进行数据库配置,操作更为便捷。 ​ 在消息配置中,新版本支持前端配置消息类型、消息模板,并通过脚本对消息进行过滤发送。 ​ O2OA V7.2.0中,在原有的企业网盘功能基础上,新增了企业网盘中的【企业文件模块】。 企业文件分为我的收藏(关联某个共享区,可以有多个共享工作区的收藏)和共享工作区(共享工作区类似群文件夹,可以作为公司的文件管理,也可以作为某个工作组的的文件管理)两大块,细分下有以下功能点: ①默认任何人都可以在企业文件下创建共享工作区; ​ ②管理人员(创建人员即为管理人员)可以设置共享区的管理权限(个人、组织或群组)、编辑权限(个人、组织或群组)、查看权限(个人、组织或群组); ​ ​ ③默认子目录和文件继承父级目录的权限,但可以变更任何子目录权限,一但子目录权限有变更将不会再继承父目录的权限变更; ​ ​ ④共享区工作区管理员可以增删改查共享区下所有文件或目录; ⑤编辑权限用户可以创建目录或上传文件,只能删除自己上传的文件; ⑥查询权限用户可以转存到个人文件夹、在线预览文件或者下载文件; ​ ⑦搜索共享工作区文件; ⑧用户可以收藏共享工作区到我的收藏。 O2OA V7.2.0 还包含其他的功能更新和问题修正,让平台更稳定,用户操作更方便: 功能新增 [平台安全]新增支持国密加密功能 [平台架构]应用,中心,web三个服务器可以合并运行 [平台配置]新增系统配置图形化模块 [数据库]新增支持分库数据存储功能 [流程引擎]新增加签功能 [流程引擎]新增base64编码附件上传接口 [流程平台]流程实例维护 [企业网盘]新增企业文件模块,文件支持基于onlyoffice预览 [企业社区]新增匿名发帖、设置帖子编辑者、禁言的功能 [流程管理]流程启动界面新增了列式启用流程的内容管理分类的功能 [流程管理]流程图中新增了数据发布类型节点功能,可发布数据到内容管理及数据表 [流程表单]新增表单组件区段合并以后的展现功能 [流程表单]新增数据表格组件、数据模板组件启用区段时查看他人编辑内容的功能 [前端通用]新增流程表单、内容管理表单的绿色皮肤和模板;新增视图、查询视图的绿色皮肤 [内容管理]新增文档发布关联html到webServer下的接口 功能优化 [平台架构]新增定时执行thread dump功能 [系统配置]配置文件简化 [平台配置]平台配置调整 [数据库]默认索引调整 [组织管理]界面适配平台主体色切换功能 [考勤管理]界面适配平台主体色切换功能 [会议管理]界面适配平台主体色切换功能 [日程安排]界面适配平台主体色切换功能 [流程管理]优化了流程图列表界面,增加了分类展现 [流程表单]优化了流程记录组件,增加了组织层次名分类 [流程表单]优化了单选、多选组件,增加了每行显示个数的配置 [流程表单] 优化了表单,增加了控制所有组件只读的配置 [流程表单]优化了提交界面,增加点击路由填入默认意见的功能 [内容管理]对流程发布的内容管理文档,允许使用流程表单打开了 [内容管理]栏目列表页适配平台主体色切换功能 [内容管理]增加string和datetime的备用字段,分页查询增加可依据datetime字段查询 [内容管理]优化了内容管理角色,增加CMSCreator角色支持,该角色允许创建栏目并可管理自己创建的栏目 [内容管理]优化了栏目管理员权限,栏目管理员可对当前栏目的所有设计进行管理 [内容管理]修改文档data数据同时映射到备用字段中 [内容管理]优化了文档分页功能,列表返回增加是否已读信息 [门户页面]优化了树组件,每个节点增加json属性,可以获取原始数据 [数据中心]优化了视图导出功能,导出excel不限制导出行数、多出多值字段归并处理 [移动办公]Android端app升级64位,去除老旧的32位程序,适配Android12 [移动办公]移动端app升级了企业网盘 [移动办公]企业微信、钉钉推送的工作消息升级为卡片消息 [移动办公]ios端app工作附件上传支持文件和图片 问题修复 [平台安全]安全漏洞修复 [流程引擎]修复了增加待办权限判断错误的问题 [脚本执行]修复了无法正确翻译javaScirpt原生数组的问题 [平台附件]修复了在线打开TXT和HTML文件显示乱码的问题 [平台附件]修复了附件sftp协议上传不支持指定根目录的问题 [个人设置]修复了密码修改初始提示不对的问题 [人员组织]修复了oauth无法执行脚本的问题 [人员组织]修复了人员组织导入导出缺少群组身份成员问题 [流程表单]修复了侧边操作条设置样式无效的问题 [内容管理]修复了内容管理文档分类管理员权限没有生效的问题 [内容管理]修复了内容管理date类型字段映射到文档备用字段不生效的问题 [数据中心]修复了视图在不同应用下同名称已完成工单过滤不生效的问题 [数据中心]修复了数据中心导入模板导入数据到自建表异常的问题 [数据中心]修复了数据中心视图列值为数组时分类报错的问题 [服务管理]修复了调试设置鉴权的接口报错的问题 [日程安排] 修复了无个人日历时未加载日程界面的问题 [移动办公]修复了ios推送消息没有升级的问题 [移动办公]修复了移动端表单关闭的api无效的问题 [移动办公]修复了Android端打卡权限申请一直弹出的问题

优秀的个人博客,低调大师

工作3年的Java程序员,轻松拿到阿里P6Offer,只因为他搞明白了Redis这几个问题!!

Redis中的多路复用模型 Redis6用到了多线程?那多线程应用在哪些地方,引入多线程后,又改如何保证线程安全性呢? 同时,如何在性能和线程安全性方面做好平衡? 关于Redis的单线程模型 在Redis6.0之前,我们一直说Redis是单线程,所以并不会存在线程安全问题,而这个单线程,实际上就是在做数据IO处理中,是用的主线程来串行执行,如图4-7所示。 Redis基于Reactor模式设计开发了自己的一套高效事件处理模型,这个事件处理模型对应的就是Redis中的文件事件处理器,这个文件事件处理器是单线程运行的,这也是为什么我们一直强调Redis是线程安全的。 既然Redis是基于Reactor模型实现,那它必然用了I/O多路复用机制来监听多个客户端连接,然后把感兴趣的事件(READ/ACCEPT/CLOSE/WRITE)注册到多路复用器中。 文件事件处理器中使用I/O多路复用模型同时监听多个客户端连接,并且根据当前连接执行的任务类型关联不同的事件处理器(连接应答处理器、命令请求处理器、命令回复处理器)来处理这些事件。 这样设计的好处: 文件事件处理器实现了高性能的网络IO通信模型 通过单线程的方式执行指令,避免同步机制的性能开销、避免过多的上下文切换、整体实现比较简单,不需要考虑多线程场景中的各种数据结构的线程安全问题。 <center>图4-7</center> 其实严格意义上来说,在Redis4.x版本就支持了多线程,只是,负责客户端请求的IO处理使用的是单线程。但是针对那些非常耗时的命令,Redis4.x提供了异步化的指令来处理,避免因为IO时间过长影响到客户端请求IO处理的线程。比如在 Redis v4.0 之后增加了一些的非阻塞命令如 UNLINK(del命令的异步版本)、FLUSHALL ASYNC、FLUSHDB ASYNC。 Redis6.0之后的多线程? 在Redis6.0中引入了多线程,可能很多同学会误以为redis原本的单线程数据IO变成了多线程IO,那作者不就是在打自己的脸吗? 对于Redis来说,CPU通常不是瓶颈,因为大多数请求不是属于CPU密集型,而是I/O密集型。而在Redis中除了数据的持久化方案之外,它是完全的纯内存操作,因此执行速度是非常快的,所以数据的IO并不是Redis的性能瓶颈,Redis真正的性能瓶颈是在网络I/O,也就是客户端和服务端之间的网络传输延迟,所以Redis选择了单线程的IO多路复用来实现它的核心网络模型。 前面我们说过,单线程设计对于Redis来说有很多好处。 避免过多的上上下文切换开销 避免同步机制的开销,涉及到数据同步和事务操作时,避免多线程影响所以必然需要加同步机制保证线程安全性。但是加锁同时也会影响到程序的执行性能。 维护简单,引入多线程之后,不管是对数据结构的设计,还是在程序代码的维护上,都会变得很复杂。 所以既然Redis的数据I/O不是瓶颈,同时单线程又有这么多好处,那Redis自然就采用单线程了。既然是这样,那么Redis 6.0引入多线程,一定不是优化数据IO性能,那么我们先来分析一下Redis性能瓶颈主要体现在哪些方面,无非就是三个方面。 网络IO CPU核心数 内存 由于CPU核心数并不是redis的瓶颈,所以影响Redis性能的因素只有网络IO和内存,而内存属于硬件范畴,比如采用容量更大、吞吐量更高的内存进行优化就行,因此也不是属于Redis可优化的空间,所以最终我们发现Redis的性能瓶颈还是在网络IO上。 而在Redis6.0之前,使用的是单线程Reactor模型,单线程模型是指对于客户端的请求,主线程需要负责对这个请求的完整IO过程进行处理,如图4-8所示,从socket中读取数据和往socket中写数据都是比较耗时的网络IO操作,解析请求和内存交互耗时可能远小于这个网络IO操作。 <center>图4-8</center> 按照前面我们对多Reactor多线程的理解,那我们能不能改成主从多Reactor多线程模型呢?主Reactor负责接收客户端连接,然后分发给多个Reactor进行网络IO操作。很显然,这样做就会导致Redis编程了一个多线程模型,这对Redis的影响较大,因为多线程带来的线程安全问题和底层复杂的数据结构的操作都非常棘手,所以Redis 6.0并没有这么做。 Redis 6.0中将处理过程中最耗时的Socket读取、请求解析、单独用一个线程来处理,剩下的命令执行操作仍然由单线程来完成和内存的数据交互,这样一来,网络IO操作就变成了多线程了,但是核心部分仍然是线程安全的,如图4-9所示。 <center>图4-9</center> 为什么说Redis6.0是一个特殊的多线程,原因就在这里,Redis主要针对网络IO这块引入了多线程的方式来提升了网络IO性能,但是真正执行命令的操作仍然是由主线程来完成。因此,总的来说,我们仍然可以说Redis是单线程模型。 Redis 6.0如何开启多线程 Redis 6.0默认多线程是禁止的,也就是仍然只是使用主线程来完成网络IO,如果需要开启,则修改redis.conf配置文件中的如下属性 # 默认是关闭,设置为yes打开 io-threads-do-reads no #默认线程数量是4,官方建议是4核机器上设置为2~3个,8核机器上设置6个 io-threads 4 引入多线程之后的性能提升 图4-20是美团技术团队使用阿里云服务器压测GET/SET命令在4个线程IO时性能上的对比结果,可以明显的看到,Redis 在使用多线程模式之后性能大幅提升,达到了一倍。 Redis Server 阿里云 Ubuntu 18.04 , 8CPU 2.5GHZ,8G内存,主机型号: ecs.ic5.2xlarge Redis Benchmark client: 阿里云 Unbuntu 18.04 , 8CPU 2.5GHZ,8G内存,主机型号:ecs.ic5.2xlarge <center>图4-20</center> 内存回收策略 很多同学了解了Redis的好处之后,于是把任何数据都往Redis中放,如果使用不合理很容易导致数据超过Redis的内存,这种情况会出现什么问题呢? Redis中有很多无效的缓存,这些缓存数据会降低数据IO的性能,因为不同的数据类型时间复杂度算法不同,数据越多可能会造成性能下降 随着系统的运行,redis的数据越来越多,会导致物理内存不足。通过使用虚拟内存(VM),将很少访问的数据交换到磁盘上,腾出内存空间的方法来解决物理内存不足的情况。虽然能够解决物理内存不足导致的问题,但是由于这部分数据是存储在磁盘上,如果在高并发场景中,频繁访问虚拟内存空间会严重降低系统性能。 所以遇到这类问题的时候,我们一般有几种方法。 对每个存储到redis中的key设置过期时间,这个根据实际业务场景来决定。否则,再大的内存都会虽则系统运行被消耗完。 增加内存 使用内存淘汰策略。 设置Redis能够使用的最大内存 在实际生产环境中,服务器不仅仅只有Redis,为了避免Redis内存使用过多对其他程序造成影响,我们一般会设置最大内存。 Redis默认的最大内存maxmemory=0,表示不限制Redis内存的使用。我们可以修改redis.conf文件,设置Redis最大使用的内存。 # 单位为byte maxmemory <bytes> 2147483648(2G) 如何查看当前Redis最大内存设置呢,进入到Redis-Cli控制台,输入下面这个命令。 config get maxmemory 当Redis中存储的内存超过maxmemory时,会怎么样呢?下面我们做一个实验 在redis-cli控制台输入下面这个命令,把最大内存设置为1个字节。 config set maxmemory 1 通过下面的命令存储一个string类型的数据 set name mic 此时,控制台会得到下面这个错误信息 (error) OOM command not allowed when used memory > 'maxmemory'. 使用内存淘汰策略释放内存 设置了maxmemory的选项,redis内存使用达到上限。可以通过设置LRU算法来删除部分key,释放空间。默认是按照过期时间的,如果set时候没有加上过期时间就会导致数据写满maxmemory。 Redis中提供了一种内存淘汰策略,当内存不足时,Redis会根据相应的淘汰规则对key数据进行淘汰。 Redis一共提供了8种淘汰策略,默认的策略为noeviction,当内存使用达到阈值的时候, 所有引起申请内存的命令会报错。 volatile-lru,针对设置了过期时间的key,使用lru算法进行淘汰。 allkeys-lru,针对所有key使用lru算法进行淘汰。 volatile-lfu,针对设置了过期时间的key,使用lfu算法进行淘汰。 allkeys-lfu,针对所有key使用lfu算法进行淘汰。 volatile-random,从所有设置了过期时间的key中使用随机淘汰的方式进行淘汰。 allkeys-random,针对所有的key使用随机淘汰机制进行淘汰。 volatile-ttl,删除生存时间最近的一个键。 noeviction,不删除键,值返回错误。 前缀为volatile-和allkeys-的区别在于二者选择要清除的键时的字典不同,volatile-前缀的策略代表从redisDb中的expire字典中选择键进行清除;allkeys-开头的策略代表从dict字典中选择键进行清除。 内存淘汰算法的具体工作原理是: 客户端执行一条新命令,导致数据库需要增加数据(比如set key value) Redis会检查内存使用,如果内存使用超过 maxmemory,就会按照置换策略删除一些 key 新的命令执行成功 了解并手写LRU算法 LRU是Least Recently Used的缩写,也就是表示最近很少使用,也可以理解成最久没有使用。也就是说当内存不够的时候,每次添加一条数据,都需要抛弃一条最久时间没有使用的旧数据。 标准的LRU算法为了降低查找和删除元素的时间复杂度,一般采用Hash表和双向链表结合的数据结构,hash表可以赋予链表快速查找到某个key是否存在链表中,同时可以快速删除、添加节点,如图4-21所示。 双向链表的查找时间复杂度是O(n),删除和插入是O(1),借助HashMap结构,可以使得查找的时间复杂度变成O(1) Hash表用来查询在链表中的数据位置,链表负责数据的插入,当新数据插入到链表头部时有两种情况。 链表满了,把链表尾部的数据丢弃掉,新加入的缓存直接加入到链表头中。 当链表中的某个缓存被命中时,直接把数据移到链表头部,原本在头节点的缓存就向链表尾部移动 这样,经过多次Cache操作之后,最近被命中的缓存,都会存在链表头部的方向,没有命中的,都会在链表尾部方向,当需要替换内容时,由于链表尾部是最少被命中的,我们只需要淘汰链表尾部的数据即可。 <center>图4-21</center> 下面我们通过一段代码实现一个简单的LRU算法,加深大家对于LRU算法的理解。 public class LRUCache { private Node head; private Node tail; private final HashMap<String,Node> nodeHashMap; private int capacity; public LRUCache(int capacity){ this.capacity=capacity; nodeHashMap=new HashMap<>(); head=new Node(); tail=new Node(); head.next=tail; tail.prev=head; } private void removeNode(Node node){ if(node==tail){ tail=tail.prev; tail.next=null; }else if(node==head){ head=head.next; head.prev=null; }else { node.prev.next=node.next; node.next.prev=node.prev; } } private void addNodeToHead(Node node){ node.next=head.next; head.next.prev=node; node.prev=head; head.next=node; } private void addNodeToTail(Node node){ node.prev=tail.prev; node.prev.next=node; node.next=tail; tail.prev=node; } //当链表中的某个缓存被命中时,直接把数据移到链表头部,原本在头节点的缓存就向链表尾部移动 public void moveNodeToHead(Node node){ removeNode(node); addNodeToHead(node); } public String get(String key){ Node node=nodeHashMap.get(key); if(node==null){ return null; } //刷新当前节点的位置 moveNodeToHead(node); //返回value值 return node.value; } public void put(String key,String value){ Node node=nodeHashMap.get(key); if(node==null){ //不存在 //如果当前存储的数据量达到了阈值,则需要淘汰掉访问较少的数据 if(nodeHashMap.size()>=capacity){ removeNode(tail); //移除尾部节点 nodeHashMap.remove(tail.key); } node=new Node(key,value); nodeHashMap.put(key,node); addNodeToTail(node); }else{ node.value=value; //刷新当前节点的位置 moveNodeToHead(node); } } public static void main(String[] args) { LRUCache lruCache=new LRUCache(3); lruCache.put("1","1"); lruCache.put("2","2"); lruCache.put("3","3"); // lruCache.get("3"); // 增加一个访问次数之后,被清理的元素就会发生变化 System.out.println(lruCache.nodeHashMap); lruCache.put("4","4"); System.out.println(lruCache.nodeHashMap); } } class Node{ //双向链表中的节点类,存储key是因为我们在双向链表删除表尾的值时,只是返回了一个节点, //所以这个节点要包括key值,这样我们的哈希表才可以删除对应key值的映射 public String key; public String value; Node prev; Node next; public Node(){} public Node(String key, String value) { this.key = key; this.value = value; } } Redis中的LRU算法 实际上,Redis使用的LRU算法其实是一种不可靠的LRU算法,它实际淘汰的键并不一定是真正最少使用的数据,它的工作机制是: 随机采集淘汰的key,每次随机选出5个key 然后淘汰这5个key中最少使用的key 这5个key是默认的个数,具体的数值可以在redis.conf中配置 maxmemory-samples 5 当近似LRU算法取值越大的时候就会越接近真实的LRU算法,因为取值越大获取的数据越完整,淘汰中的数据就更加接近最少使用的数据。这里其实涉及一个权衡问题, 如果需要在所有的数据中搜索最符合条件的数据,那么一定会增加系统的开销,Redis是单线程的,所以耗时的操作会谨慎一些。 为了在一定成本内实现相对的LRU,早期的Redis版本是基于采样的LRU,也就是放弃了从所有数据中搜索解改为采样空间搜索最优解。Redis3.0版本之后,Redis作者对于基于采样的LRU进行了一些优化: Redis中维护一个大小为16的候选池,当第一次随机选取采用数据时,会把数据放入到候选池中,并且候选池中的数据会更具时间进行排序。 当第二次以后选取数据时,只有小于候选池内最小时间的才会被放进候选池。 当候选池的数据满了之后,那么时间最大的key就会被挤出候选池。当执行淘汰时,直接从候选池中选取最近访问时间小的key进行淘汰。 如图4-22所示,首先从目标字典中采集出maxmemory-samples个键,缓存在一个samples数组中,然后从samples数组中一个个取出来,和回收池中以后的键进行键的空闲时间,从而更新回收池。 在更新过程中,首先利用遍历找到的每个键的实际插入位置x,然后根据不同情况进行处理。 回收池满了,并且当前插入的key的空闲时间最小(也就是回收池中的所有key都比当前插入的key的空闲时间都要大),则不作任何操作。 回收池未满,并且插入的位置x没有键,则直接插入即可 回收池未满,且插入的位置x原本已经存在要淘汰的键,则把第x个以后的元素都往后挪一个位置,然后再执行插入操作。 回收池满了,将当前第x个以前的元素往前挪一个位置(实际就是淘汰了),然后执行插入操作。 <center>图4-22</center> 这样做的目的是能够选出最真实的最少被访问的key,能够正确不常使用的key。因为在Redis3.0之前是随机选取样本,这样的方式很有可能不是真正意义上的最少访问的key。 LRU算法有一个弊端,加入一个key值访问频率很低,但是最近一次被访问到了,那LRU会认为它是热点数据,不会被淘汰。同样, 经常被访问的数据,最近一段时间没有被访问,这样会导致这些数据被淘汰掉,导致误判而淘汰掉热点数据,于是在Redis 4.0中,新加了一种LFU算法。 LFU算法 LFU(Least Frequently Used),表示最近最少使用,它和key的使用次数有关,其思想是:根据key最近被访问的频率进行淘汰,比较少访问的key优先淘汰,反之则保留。 LRU的原理是使用计数器来对key进行排序,每次key被访问时,计数器会增大,当计数器越大,意味着当前key的访问越频繁,也就是意味着它是热点数据。 它很好的解决了LRU算法的缺陷:一个很久没有被访问的key,偶尔被访问一次,导致被误认为是热点数据的问题。 LFU的实现原理如图4-23所示,LFU维护了两个链表,横向组成的链表用来存储访问频率,每个访问频率的节点下存储另外一个具有相同访问频率的缓存数据。具体的工作原理是: 当添加元素时,找到相同访问频次的节点,然后添加到该节点的数据链表的头部。如果该数据链表满了,则移除链表尾部的节点 当获取元素或者修改元素是,都会增加对应key的访问频次,并把当前节点移动到下一个频次节点。 添加元素时,访问频率默认为1,随着访问次数的增加,频率不断递增。而当前被访问的元素也会随着频率增加进行移动。 <center>图4-23</center> 持久化机制的实现及原理 Redis的强劲性能很大程度上是由于它所有的数据都存储在内存中,当然如果redis重启或者服务器故障导致redis重启,所有存储在内存中的数据就会丢失。但是在某些情况下,我们希望Redis在重启后能够保证数据不会丢失。 将redis作为nosql数据库使用。 将Redis作为高效缓存服务器,缓存被击穿后对后端数据库层面的瞬时压力是特别大的,所有缓存同时失效可能会导致雪崩。 这时我们希望Redis能将数据从内存中以某种形式同步到硬盘上,使得重启后可以根据硬盘中的记录来恢复数据。 Redis支持两种方式的持久化,一种是RDB方式、另一种是AOF(append-only-file)方式,两种持久化方式可以单独使用其中一种,也可以将这两种方式结合使用。 RDB:根据指定的规则“定时”将内存中的数据存储在硬盘上, AOF:每次执行命令后将命令本身记录下来。 4.3.1 RDB模式 RDB的持久化方式是通过快照(snapshotting)完成的,它是Redis默认的持久化方式,配置如下。 # save 3600 1 # save 300 100 # save 60 10000 Redis允许用户自定义快照条件,当符合快照条件时,Redis会自动执行快照操作。快照的条件可以由用户在配置文件中配置。配置格式如下 save <seconds> <changes> 第一个参数是时间窗口,第二个是键的个数,也就是说,在第一个时间参数配置范围内被更改的键的个数大于后面的changes时,即符合快照条件。当触发条件时,Redis会自动将内存中的数据生成一份副本并存储在磁盘上,这个过程称之为“快照”,除了上述规则之外,还有以下几种方式生成快照。 根据配置规则进行自动快照 用户执行SAVE或者GBSAVE命令 执行FLUSHALL命令 执行复制(replication)时 根据配置规则进行自动快照 修改redis.conf文件,表示5秒内,有一个key发生变化,就会生成rdb文件。 save 5 1 # 表示3600s以内至少发生1个key变化(新增、修改、删除),则重写rdb文件 save 300 100 save 60 10000 修改文件存储路径 dir /data/program/redis/bin 其他参数配置说明 参数 说明 dir rdb文件默认在启动目录下(相对路径) config get dir 获取 dbfilename 文件名称 rdbcompression 开启压缩可以节省存储空间,但是会消耗一些CPU的计算时间,默认开启 rdbchecksum 使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。 如果需要关闭RDB的持久化机制,可以参考如下配置,开启save,并注释其他规则即可 save "" #save 900 1 #save 300 10 #save 60 10000 用户执行SAVE或者GBSAVE命令 除了让Redis自动进行快照以外,当我们对服务进行重启或者服务器迁移我们需要人工去干预备份。redis提供了两条命令来完成这个任务 save命令 如图4-24所示,当执行save命令时,Redis同步做快照操作,在快照执行过程中会阻塞所有来自客户端的请求。当redis内存中的数据较多时,通过该命令将导致Redis较长时间的不响应。所以不建议在生产环境上使用这个命令,而是推荐使用bgsave命令 <center>图4-24</center> bgsave命令 如图4-25所示,bgsave命令可以在后台异步地进行快照操作,快照的同时服务器还可以继续响应来自客户端的请求。执行BGSAVE后,Redis会立即返回ok表示开始执行快照操作,在redis-cli终端,通过下面这个命令可以获取最近一次成功执行快照的时间(以 UNIX 时间戳格式表示)。 LASTSAVE 1:redis使用fork函数复制一份当前进程的副本(子进程) 2:父进程继续接收并处理客户端发来的命令,而子进程开始将内存中的数据写入硬盘中的临时文件 3:当子进程写入完所有数据后会用该临时文件替换旧的RDB文件,至此,一次快照操作完成。 注意:redis在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的,也就是说任何时候RDB文件都是完整的。 这就使得我们可以通过定时备份RDB文件来实现redis数据库的备份, RDB文件是经过压缩的二进制文件,占用的空间会小于内存中的数据,更加利于传输。 bgsave是异步执行快照的,bgsave写入的数据就是for进程时redis的数据状态,一旦完成fork,后续执行的新的客户端命令对数据产生的变更都不会反应到本次快照 Redis启动后会读取RDB快照文件,并将数据从硬盘载入到内存。根据数据量大小以及服务器性能不同,这个载入的时间也不同。 <center>图4-25</center> 执行FLUSHALL命令 该命令在前面讲过,会清除redis在内存中的所有数据。执行该命令后,只要redis中配置的快照规则不为空,也就是save 的规则存在。redis就会执行一次快照操作。不管规则是什么样的都会执行。如果没有定义快照规则,就不会执行快照操作。 执行复制(replication)时 该操作主要是在主从模式下,redis会在复制初始化时进行自动快照。这个会在后面讲到; 这里只需要了解当执行复制操作时,即时没有定义自动快照规则,并且没有手动执行过快照操作,它仍然会生成RDB快照文件。 RDB数据恢复演示 准备初始数据 redis> set k1 1 redis> set k2 2 redis> set k3 3 redis> set k4 4 redis> set k5 5 通过shutdown命令关闭触发save redis> shutdown 备份dump.rdb文件(用来后续恢复) cp dump.rdb dump.rdb.bak 接着再启动redis-server(systemctl restart redis_6379),通过keys命令查看,发现数据还在 keys * 模拟数据丢失 执行flushall redis> flushall shutdown(重新生成没有数据的快照,用来模拟后续的数据恢复) redis> shutdown 再次启动redis, 通过keys 命令查看,此时rdb中没有任何数据。 恢复之前备份的rdb文件(之前保存了数据的rdb快照) mv dump.rdb.bak dump.rdb 再次重启redis,可以看到之前快照保存的数据 keys * RDB文件的优势和劣势 一、优势 1.RDB是一个非常紧凑(compact)的文件,它保存了redis 在某个时间点上的数据集,这种文件非常适合用于进行备份和灾难恢复。 2.生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。 3.RDB 在恢复大数据集时的速度比AOF的恢复速度要快。 二、劣势 1、RDB方式数据没办法做到实时持久化/秒级持久化。因为bgsave每次运行都要执行fork操作创建子进程,频繁执行成本过高 2、在一定间隔时间做一次备份,所以如果redis意外down掉的话,就会丢失最后一次快照之后的所有修改(数据有丢失)。 如果数据相对来说比较重要,希望将损失降到最小,则可以使用AOF方式进行持久化。 4.3.2 AOF模式 AOF(Append Only File):Redis 默认不开启。AOF采用日志的形式来记录每个写操作,并追加到文件中。开启后,执行更改Redis数据的命令时,就会把命令写入到AOF文件中。 Redis 重启时会根据日志文件的内容把写指令从前到后执行一次以完成数据的恢复工作。 AOF配置开关 # 开关 appendonly no /yes # 文件名 appendfilename "appendonly.aof" 通过修改redis.conf重启redis之后:systemctl restart redis_6379。 再次运行redis的相关操作命令,会发现在指定的dir目录下生成appendonly.aof文件,通过vim查看该文件内容如下 *2 $6 SELECT $1 0 *3 $3 set $4 name $3 mic *3 $3 set $4 name $3 123 AOF配置相关问题解答 问题1:数据都是实时持久化到磁盘吗? 虽然每次执行更改Redis数据库内容的操作时,AOF都会将命令记录在AOF文件中,但是事实上,由于操作系统的缓存机制,数据并没有真正地写入硬盘,而是进入了系统的硬盘缓存。在默认情况下系统每30秒会执行一次同步操作。以便将硬盘缓存中的内容真正地写入硬盘。 在这30秒的过程中如果系统异常退出则会导致硬盘缓存中的数据丢失。一般来说能够启用AOF的前提是业务场景不能容忍这样的数据损失,这个时候就需要Redis在写入AOF文件后主动要求系统将缓存内容同步到硬盘中。在redis.conf中通过如下配置来设置同步机制。 参数 说明 appendfsync everysec AOF持久化策略(硬盘缓存到磁盘),默认everysec <br /> 1 no 表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快,但是不太安全; <br /> 2 always 表示每次写入都执行fsync,以保证数据同步到磁盘,效率很低;<br /> 3 everysec表示每秒执行一次fsync,可能会导致丢失这1s数据。通常选择 everysec ,兼顾安全性和效率。 问题2:文件越来越大,怎么办? 由于AOF持久化是Redis不断将写命令记录到 AOF 文件中,随着Redis不断的运行,AOF 的文件会越来越大,文件越大,占用服务器内存越大以及 AOF 恢复要求时间越长。 例如set gupao 666,执行1000次,结果都是gupao=666。 为了解决这个问题,Redis新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。 可以使用命令下面这个命令主动触发重写 redis> bgrewriteaof AOF 文件重写并不是对原文件进行重新整理,而是直接读取服务器现有的键值对,然后用一条命令去代替之前记录这个键值对的多条命令,生成一个新的文件后去替换原来的 AOF 文件。 重写触发机制如下 参数 说明 auto-aof-rewrite-percentage 默认值为100。表示的是当目前的AOF文件大小超过上一次重写时的AOF文件大小的百分之多少时会再次进行重写,如果之前没有重写过,则以启动时AOF文件大小为依据 auto-aof-rewrite-min-size 默认64M。表示限制了允许重写的最小AOF文件大小,通常在AOF文件很小的情况下即使其中有很多冗余的命令我们也并不太关心 在启动时,Redis会逐个执行AOF文件中的命令来将硬盘中的数据载入到内存中,载入的速度相对于RDB会慢一些 问题:重写过程中,AOF文件被更改了怎么办? Redis 可以在 AOF 文件体积变得过大时,自动地在后台对 AOF 进行重写: 重写后的新 AOF 文件包含了恢复当前数据集所需的最小命令集合。 重写的流程是这样, 主进程会fork一个子进程出来进行AOF重写,这个重写过程并不是基于原有的aof文件来做的,而是有点类似于快照的方式,全量遍历内存中的数据,然后逐个序列到aof文件中。 在fork子进程这个过程中,服务端仍然可以对外提供服务,那这个时候重写的aof文件的数据和redis内存数据不一致了怎么办?不用担心,这个过程中,主进程的数据更新操作,会缓存到aof_rewrite_buf中,也就是单独开辟一块缓存来存储重写期间收到的命令,当子进程重写完以后再把缓存中的数据追加到新的aof文件。 当所有的数据全部追加到新的aof文件中后,把新的aof文件重命名正式的文件名字,此后所有的操作都会被写入新的aof文件。 如果在rewrite过程中出现故障,不会影响原来aof文件的正常工作,只有当rewrite完成后才会切换文件。因此这个rewrite过程是比较可靠的。 <center>图4-26</center> Redis允许同时开启AOF和RDB,既保证了数据安全又使得进行备份等操作十分容易。如果同时开启后,Redis重启会使用AOF文件来恢复数据,因为AOF方式的持久化可能丢失的数据更少。 AOF的优劣势 优点: 1、AOF 持久化的方法提供了多种的同步频率,即使使用默认的同步频率每秒同步一次,Redis 最多也就丢失 1 秒的数据而已。 缺点: 1、对于具有相同数据的的Redis,AOF 文件通常会比 RDB 文件体积更大(RDB存的是数据快照)。 2、虽然 AOF 提供了多种同步的频率,默认情况下,每秒同步一次的频率也具有较高的性能。在高并发的情况下,RDB 比 AOF 具好更好的性能保证。 关注[跟着Mic学架构]公众号,获取更多精品原创

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册