一次redis主从切换导致的数据丢失与陷入只读状态故障

背景

最近一组业务redis数据不断增长需要扩容内存,而扩容内存则需要重启云主机,在按计划扩容升级执行主从切换时意外发生了数据丢失与master进入只读状态的故障,这里记录分享一下。

业务redis高可用架构

该组业务redis使用的是一主一从,通过sentinel集群实现故障时的自动主从切换,这套架构已经平稳运行数年,经历住了多次实战的考验。
高可用架构大体如下图所示:
image
简单说一下sentinel实现高可用的原理:
集群的多个(2n+1,N>1)哨兵会定期轮询redis的所有master/slave节点,如果sentinel集群中超过一半的哨兵判定redis某个节点已经主观下线,就会将其判定为客观下线进行相应处理:

  1. 如果下线节点是master,选定一个正常work的slave将其选定为新的master节点。
  2. 如果下线节点是slave,将其从slave节点中移除。

如果已经被客观下线的节点恢复了正常,sentinel中超过一半哨兵确认后则将其加回可用的slave节点。
所有需要读写redis的server并不需要直接写死redis 主从配置,而是通过访问sentinel获取当前redis的主从可用状态,具体实现方式可以定时查询sentinel询问更新,也可以通过订阅机制让sentinel在主从变动时主动通知订阅方更新。
sentinel实现高可用的详细原理这里不做过多赘述,有兴趣的小伙伴可以移步参考文献中的相关资料。

具体内存扩容流程

sentinel可以在检测到故障时自动切换redis主从,也可以主动执行sentinel failover mastername 命令实现手动切换主从,所以这次的内存扩容重启流程设计如下(A代表初始master所在云主机,B代表初始slave所在云主机):

  1. 升级主机B内存配置,重启主机B
  2. 检查B重启后其上的redis slave是否重新同步master数据完成,包括:
    2.1 查看slave redis log是否异常,无异常pass
    2.2 使用info keyspace命令check master、slave 各db key数量是否一致,无异常pass
    2.3 在master写入一个测试key,在slave上check是否同步成功
    2.4 观察依赖server log是否有异常
  3. 使用sentinel failover mastername命令手动主从切换,主机A变成新slave,主机B变成新master,根据以前手动切换的经验走到这一步基本上就稳了--因为这里本质上和一次普通主从切换已经没有区别了。
  4. 升级主机A内存配置,重启主机A,执行以下check:
    4.1 查看新slave redis log是否异常
    4.2 使用info keyspace命令check 新master、新slave 各db key数量是否一致,无异常pass
    4.3 在新master写入测试key,在新slave上check是否同步成功
    4.4 观察依赖server log是否有异常

至此,若以上步骤都正常通过,一个完美的redis内存升级工作就完成了。

主从切换后数据丢失

结果正是没有想过可能会出问题的步骤3反而出现了问题,直接导致了主从切换后丢掉了部分数据,并且新master进入只读状态将近十分钟。
当时的情况是这样的:
在执行完步骤3后,check 新slave redis log无异常,正在考虑观察一会儿后执行主机A的升级重启操作,api的分钟级别异常监控触发了一小波redis相关报警。第一反应在新master与新slave上执行了info keyspace查看key数量是否已经不一致,结果发现master/slave的key数量是一致的--但是再仔细一看:和切换前的key总数百万级相比切换后key总数降到了十万级--大部分key数据被丢失了。
查看新master、新slave log都没有发现明显log可以解释为什么主从切换后会丢失一大半数据这一现象,这时小伙伴第一次提到了是不是内存不够了,当时自己略一思考马上回复到:新master刚升级了内存,不可能内容扩大后反而内存不足的,所以应该不是这个问题。
n分钟后...
小伙伴再一次提出了是不是maxmemory问题,这一下子点中了关键点,马上想到主机B升级了内存是不会有系统层面内存不足的问题,但是redis的内存使用实际上还会受到maxmemory参数限制,马上在新master上执行config get maxmemory, 只有3GB,而升级前数据实际使用内存超过了6GB!
立刻调大了新master的maxmemory参数,redis很快恢复了可读写正常状态,一大波redis只读引发的告警通知开始快速下降。

原因定位

紧张又刺激的故障处理就这么过去了,在优先处理完丢失key数据恢复工作之后,开始回顾整理故障的详细原因,总共有如下几个疑问:

  1. 明确记得上个月给主机A、B上的redis都通过config set maxmemory设置为了7GB,为什么出现问题时查询B上redis 的maxmemory配置却变成了3GB?
  2. 如果主机B的maxmemory是3GB,其作为slave时为什么从master同步超过6GB的数据时不会有问题?--在主从切换前无论是查看info keyspace还是在master上写入测试key同步check都是OK的。
  3. 为什么主从切换后主机B上的key数据会丢失?这个是因为maxmemory设置过小,是故障的直接原因。
  4. 为什么新master由于maxmemory参数超限进入只读状态且删除部分数据后,新master中实际数据占用的大小依然超过>3GB?

如上四个疑问除了问题3已经明确了,剩下三个问题都让人疑惑--事出诡异必有妖,经过一番探寻得出其答案:

  1. 上个月修改redis maxmemory时,只通过config set命令修改了其运行时配置,而没有修改对应配置redis.conf上maxmemory的值,主机B上redis在重启后就会从redis.conf上载入该maxmemory,该配置正是3GB,同时maxmemory参数是redis节点独立的配置,slave并不会从master同步该值。
  2. 在redis5.0版本之后,redis引入了一个新的参数replica-ignore-maxmemory,其官方文档定义如下:
Maxmemory on replicas
By default, a replica will ignore maxmemory (unless it is promoted to master after a failover or manually). It means that the eviction of keys will be handled by the master, sending the DEL commands to the replica as keys evict in the master side.
This behavior ensures that masters and replicas stay consistent, which is usually what you want. However, if your replica is writable, or you want the replica to have a different memory setting, and you are sure all the writes performed to the replica are idempotent, then you may change this default (but be sure to understand what you are doing).
Note that since the replica by default does not evict, it may end up using more memory than what is set via maxmemory (since there are certain buffers that may be larger on the replica, or data structures may sometimes take more memory and so forth). Make sure you monitor your replicas, and make sure they have enough memory to never hit a real out-of-memory condition before the master hits the configured maxmemory setting.
To change this behavior, you can allow a replica to not ignore the maxmemory. The configuration directives to use is:
replica-ignore-maxmemory no

大意是redis作为slave时默认会无视maxmemory参数,这样可以保证主从的数据始终保持一致。当master/slave实际数据大小均小于其maxmemory设置时,这个参数没有任何影响,而这次丢失数据的原因正是因为主机B重启后作为slave时maxmemory(3GB)小于实际数据大小(6GB+),此时replica-ignore-maxmemory 默认开启保证作为slave时直接无视maxmemory的限制,而当执行sentinel failover mastername将主机B切换为新master后,新master不会受replica-ignore-maxmemory影响,发现自身maxmemory<实际数据大小后直接开始主动淘汰key,从而导致了数据丢失。
4. 至于主机B作为master执行淘汰key策略并最终进入只读状态后,其实际数据大小依然>3GB的原因,则是由于线上redis配置的策略是volatile-lru策略,该策略只会淘汰有过期时间的key,对于不过期的key是不淘汰的。

总结

总的来看这次故障的根本原因还是个人对于redis的配置、操作经验不足,如果在调整运行时maxmemory时能做到以下二者之一,这次故障就不会出现了:

  1. 调整运行时maxmemory时同时调整配置文件maxmemory保持一致。
  2. 将配置文件maxmemory设置为0--表示不限制内存使用。

正是因为对redis的认识和经验不足,没有想过到运行时配置与静态配置不一致可能导致的问题,这次不可避免的踩坑了。
但是,作为一个本职RD,半路接手基本靠自学的兼职运维,要考虑到maxmemory的运行配置与静态配置一致性问题好像也确实不是那么的理所当然?。
处理完这次故障后,特意在网上搜索了一番redis主从切换的注意事项、踩坑文章,想看看有没有人提到类似的坑,但是并无所获,难道这个坑真的没其他人踩(分享)过?陷入思考...
如果有经验丰富的小伙伴看到这里,也欢迎不吝赐教指导一下redis主从的切换的各类常识与常见大坑!

转载请注明出处,原文地址:http://www.cnblogs.com/AcAc-t/p/redis_master_switch_failure.html

参考

http://redis.io/docs/management/replication/
http://www.cnblogs.com/buttercup/p/14051301.html
http://zhuanlan.zhihu.com/p/151740247
http://www.cnblogs.com/AcAc-t/p/redis_master_switch_failure.html
http://zhuanlan.zhihu.com/p/320651292

签名:拥抱开源,拥抱自由
本文转载于网络 如有侵权请联系删除

相关文章

  • AKShare-另类数据-新能源汽车细分市场

    作者寄语乘联会业务板块包括乘用车、商用车、新能源。目前,乘联会共拥有会员单位147家,覆盖了国内全部乘用车厂商、部分商用车厂商(主要微客、微卡、轻客、轻卡及皮卡厂商)以及大部分造车新势力企业(汽车初创企业)。更新接口"car_cpca_energy_sale"#乘联会-新能源细分市场乘联会-新能源细分市场接口:car_cpca_energy_sale目标地址:http://data.cpcaauto.com/FuelMarket描述:获取乘联会-新能源细分市场汽车销量数据限量:单次返回本年度和上年度月份的销量数据输入参数名称类型必选描述----输出参数-品牌名称类型默认显示描述月份objectY-{前一个年份}年float64Y注意单位:万辆{当前年份}年float64Y注意单位:万辆接口示例importakshareasak car_cpca_energy_sale_df=ak.car_cpca_energy_sale() print(car_cpca_energy_sale_df) 复制数据示例月份2020年2021年 01月4.147815.5388 12月1

  • 小胖:远哥,spring 中的 bean 是线程安全的吗?

    结论:不是线程安全的Spring容器中的Bean是否线程安全,容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性,但是具体还是要结合具体scope的Bean去研究。Spring的bean作用域(scope)类型singleton:单例,默认作用域。prototype:原型,每次创建一个新对象。request:请求,每次Http请求创建一个新对象,适用于WebApplicationContext环境下。session:会话,同一个会话共享一个实例,不同会话使用不用的实例。global-session:全局会话,所有会话共享一个实例。线程安全这个问题,要从单例与原型Bean分别进行说明。「原型Bean」对于原型Bean,每次创建一个新对象,也就是线程之间并不存在Bean共享,自然是不会有线程安全的问题。「单例Bean」对于单例Bean,所有线程都共享一个单例实例Bean,因此是存在资源的竞争。如果单例Bean,是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Sprin

  • 一个支持国密SM2/SM3/SM4/SM9/ZUC/SSL的密码工具箱

    转:https://blog.csdn.net/xuq09/article/details/91815366TheGmSSLProject 网址:http://gmssl.org/docs/quickstart.html在网上闲逛时发现一个工具。SSL支持国密算法。看着比较高大上。还没有用呢。记下来。备用。快速上手指南介绍GmSSL的编译、安装和gmssl命令行工具的基本指令。下载源代码(zip),解压缩至当前工作目录$unzipGmSSL-master.zip复制编译与安装Linux平台(其他平台的安装过程见编译与安装)$./configno-safno-sdfno-skfno-sofno-zuc $make $sudomakeinstall复制安装之后可以执行gmssl命令行工具检查是否成功$gmsslversion GmSSL2.0-OpenSSL1.1.0d复制SM4加密文件$gmsslsms4-e-in<yourfile>-out<yourfile>.sms4 entersms4-cbcencryptionpassword:<your-passw

  • mxget 的Python实现,优雅地下载你喜欢的音乐

    mxget下载安装$pip3install-Umxget复制mxget要求Python版本不低于3.5.3。功能特性聚合国内各大音乐平台的资源,支持在线搜索和下载试听。单曲、专辑、歌单以及歌手热门歌曲,只需一步,就能搞定!支持自动嵌入音乐标签/下载歌词。利用Goroutines的先天优势快速并发下载。支持库调用和RESTfulAPI。重要说明mxget开发的初衷只是免去你须要频繁在各大网站切换听歌的烦恼,而不是为了破解音乐平台的数字版权限制。它无法下载受版权保护的数字音乐,音频也仅提供标准音质(128kbps)下载。如果你喜欢高音质/无损资源,请支持正版。任何组织/个人不得将本项目用于商业或者其它非法用途,因此造成的责任和风险由使用者自行承担!支持的音乐平台音乐平台平台标识专用识别码网易云音乐netease/nc1000QQ音乐tencent/qq1001咪咕音乐migu/mg1002酷狗音乐kugou/kg1003酷我音乐kuwo/kw1004虾米音乐xiami/xm1005千千音乐qianqian/baidu/bd1006下载安装goget-ugithub.com/winterss

  • 测试技术修为:测试应该关注java.util.List.subList的坑

    java中有一个返回子列表的方法:publiclist<E>subList(intfromIndex,inttoIndex){ subListRangeCheck(fromIndex,toIndex,size); returnnewSubList(this,0,fromIndex,toIndex); }复制返回一个fromIndex为起点,toIndex为终点(不包含终点)的子列表。从上实现代码中可以看到,先检查一下单签的fromIndex和toIndex是否合法,如果不合法,那么就退出了该函数逻辑。要是合法,可以看出其返回了一个this也就是原始列表的部分元素视图,这样就形成了一个子列表。这也导致了,如果针对原来的list或者是sublist返回的list的修改(这里的修改是不涉及list大小),都是对同一段内存存储的数据做修改。(这种修改叫做非结构修改)如果发生结构性修改的是原来的list(不包括由于返回的子list导致的改变),那么返回的子list语义上将会是undefined。在AbstractList(ArrayList的父类)中,undefined的具体表现形式

  • filebeat导向kafka多topic

    filebeat导向kafka多topic多行匹配之前使用filebeat去行读取GC日志,没有使用多行合并,配置如下:#pattern支持正则表达式,很爽 multiline.pattern:'^\[.+\]' multiline.negate:true multiline.match:"after"复制区配效果pattern:'^b' negate:true match:"after" 日志内容: b c b 匹配结果为:bcb两段官方文档如何使用negate和match组合合并多行日志有很好的说明,记得文档一定坚持看完kafka多topicfields自定义字段及值,会在output输出时会做为map形式输出,在codec.string中可以使用%{[]}调用容器中需要读取GC及Log4j产生的日志,在kafka端想创建两个独立的topic,不想共用同topic这时需要filebeat动态支持根据fields定义字段切换topic,配置如下:filebeat: prospectors: -type:l

  • $$watcher when is it filled

    CreatedbyWang,Jerry,lastmodifiedonJun06,2016

  • 【区块链技术工坊46期】PPIO蒋鑫:椭圆曲线密码学简介

    1.活动基本信息1)题目: 【区块链技术工坊46期】椭圆曲线密码学简介2)议题: 目前区块链项目如火如荼,几乎所有的区块链都会用到钱包,我们也经常听说椭圆曲线这个密码学术语,那么它们之间有没有什么关系?“加密货币”,到底是不是加了密的货币?为什么***和以太坊等众多区块链项目选用的是椭圆曲线而不是RSA?大名鼎鼎的SonyPS3上的私钥是如何被盗的?请报名者带好笔记本电脑,且看PPIO区块链开发工程师蒋鑫的技术分享。议题纲要: 1)椭圆曲线的重要性 2)RSA算法回顾 3)群论 4)椭圆曲线上加法的定义 5)基于椭圆曲线的签名和验签 6)安全性问题 7)ECC与RSA的比较3)嘉宾: 蒋鑫,PPIO区块链高级开发工程师,7年安卓系统开发经验,2年安全开发经验,1年区块链开发经验,南京大学硕士毕业。曾组织“安卓安全小分队(ASS)”发现第二个AndroidMasterKey漏洞。4)活动定位 区块链技术工坊系列活动,由HiBlock,下笔有神科技,兄弟区块链,HPB芯链,墨客联合主办,聚焦于深度分享区块链知识,实现小会技术交友。区块链技术工坊一直以来坚持4F原则:Frency-每周三晚上

  • 列表复制 之 直接赋值 浅拷贝 和 深度拷贝的分析

    列表复制之直接赋值浅拷贝和深度拷贝的分析 1.三者简述 a.直接赋值:用等号=,其实就是对象的引用b.浅拷贝:用copy(),拷贝父对象,但是不会拷贝内部子对象c.深度拷贝:用deepcopy,是采用的模块copy中的deepcopy方法,完全拷贝父对象和子对象2.程序举例 现创建一个列表a,列表里的子对象也是列表,并进行赋值,浅拷贝,和深度拷贝操作:如图所示,b是赋值所得,c是浅拷贝所得,d是深度拷贝所得,注意在使用深度拷贝之前,先要调用copy模块:importcopy此时可以看到四者的值一样2.1直接赋值和拷贝(浅或深)之间的区别 在列表a后面添加一个新的元素【0,0,0】:可以看到,我只改变了列表a,但是b也跟着变化了,c和d却没有变化说明:赋值操作其实不是真的拷贝,它只是令变量b指向了a所指向的对象,他们两个其实共同指向一个对象,类似于C++中的引用!改变其中一个,另一个会接着改变。而拷贝操作,无论深浅,都是相当于新建了一个新的列表,这个列表c和d与源列表a其实是独立的,所以列表c和d并无变化! 2.2浅拷贝和深度拷贝的区别 现在对列表a的子对象进行操作!比如令其第一个列表增

  • Java 8 中的拉姆达表达式是什么?

    Java8中的拉姆达表达式是什么?拉姆达表达式就是一个匿名函数。在C#中,拉姆达表达式是一个委托类型,因此拉姆达表达式可以赋值给一个委托变量。 Java中,没有委托,Java的设计者只能想出一些曲折的方法来实现拉姆达表达式,这种方式就是用接口。这种接口叫做函数式接口。但是这个接口比较特殊,必须是只有一个抽象方法(接口中的方法,无论是否加abstract,都是抽象的,加不加都可以)。如果还需定义别的抽象方法,那只能定义Object类中的同名方法,事实上,例如toString和Clone这种方法的声明并不是抽象的,JavaAPI中某些接口重新声明Object类中的方法,目的是为了关联javadoc中的注释而已。下面是一个合法的函数式接口:@FunctionalInterface publicinterfacemyFunctionalInterface{ intdosomething(intc,intb); StringtoString();//sametoObject.toString inthashCode();//sametoObject.hashCode booleanequals(

  • 人民日报发推欢迎Google重返大陆,FB上长文阐述详细立场

    李根发自凹非寺 量子位报道|公众号QbitAI关键性风向标出现。最近各种猜测和报道不断涌出的背景下,人民日报昨日在社交平台Twitter上发出一个明确的信号:“欢迎Google重返中国大陆,但必须遵守中国法律。所有在中国的外国互联网公司,都应尊重中国的互联网管理。”如上图所示,这条推特还附带了一个短链接。 这个短链接,直接指向人民日报在另一社交平台Facebook上发表的文章。这篇文章的标题是:StabilityprerequisiteforChina’sinternetopeningup(《稳定是中国互联网开放的前提》)。在这篇文章里,人民日报说:知道了最近Google要推出中国定制版搜索引擎的传闻,也知道西方媒体和政界对这件事都很关注,也知道很多人因此指责Google。人民日报表态:欢迎Google回归中国大陆,但前提条件是遵守中国法律的要求。这篇文章认为,Google八年前没能理解中国市场,2010年选择退出是一个“巨大的错误,让该公司错过了中国大陆互联网发展的黄金机会”,在Google缺席的8年里,中国移动互联网用户数量翻了一倍多。因此人们相信Google会回归,从2010年到

  • [ Java学习基础 ] Java的抽象类与接口

    一、抽象类1.抽象类 Java语言提供了两种类:一种是具体类;另一种是抽象子类。2.抽象类概念:在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。  由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。在Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。  在[Java学习基础]Java的继承与多态中介绍多态时,使用过几何图形类示例,其中Figure(几何图形)类中有一个onDraw(绘图)方法,Figure有两个子类Ellipse(椭圆形)和Triangle(三角形),Ellipse和Triangle覆盖onDraw方法。  作为父类Figure(几何图形)并不知道在实际使用时有多少个

  • 大玩家入场无人车:亚马逊、苹果的野心和秘密(还有人要上天)

    李杉陈桦编译整理 量子位报道|公众号QbitAI大玩家还在不断涌入无人车领域。最近又有两家真正的科技巨头,被首次证实已经开始涉足无人车。一家是市值超4300亿美元的亚马逊,另一家是市值超7500亿美元的苹果公司。亚马逊涉足无人车,一点也不令人意外。真正令人意外的是,亚马逊的无人车团队组建超过一年后,才刚刚为外界所知。成立这个团队的直接目的,其实并不是开发无人车或者无人卡车,而是为更宏伟的计划提供支持:组建自己的配送和物流网络。亚马逊最担心的问题是:应该如何使用无人驾驶卡车、铲车、无人机和包括无人驾驶汽车在内的其他技术来提升配送速度,尽快将包裹送到用户手中。自动化技术可以通过很多方式为亚马逊提供帮助——该公司已经在工厂和仓库中采取了很多措施,而无人驾驶卡车也可以帮助其应对驾驶员短缺,甚至避免人类驾驶员的疲劳驾驶问题。意料之中的是,该报道透露,亚马逊的团队对自动驾驶卡车很感兴趣。由无人机来解决最后一公里配送问题显然对亚马逊很有吸引力,首尾相连的机器的确蕴含着很多机会,而未来的无人驾驶专车网络也可以负责配送小型包裹。如果与无人驾驶汽车和驾驶舱配合使用,就连Hyperloop超级高铁技术也有可

  • 上传淘宝网图片获取相似商品信息

      点击上面的按钮,上传图片,返回该图片相似商品信息     我们上传图片过程中,获取到图片上传url,以及需要携带的请求头信息, 废话不多说,直接上代码   """ author:MrYang data:2019/09/25 """ importrequests fromrequests_toolbeltimportMultipartEncoder importre importjson fromfake_useragentimportUserAgent importos #pipinstallfake-useragent先安装此模块,生成随机user-agent classTaoBaoSimilarityGoods(): def__init__(self,image_path): self.ua=UserAgent() self.headers={ 'accept':'application/json,text/javascript,*/*;q=0.01', 'accept-encoding':'gzip,deflate,br', '

  • exec 和 spawn 的区别

    参考资料: difference-between-spawn-and-exec-of-node-js-child_process process_child 最近在用nodejs的child_process模块调用系统的shell脚本,但是发现遇到一些问题 child_process.exec方法调用shell脚本发现内容过长会抛错Error:maxBufferexceeded(和options.maxBuffer有关) child_process.spawn方法调用shell脚本发现控制台无法监听用户的输入(和options.stdio设置有关) nodejs调用shell后,shell里面的命令找不到(和options.env有关) nodejs如何传入env到shell里(和options.env有关) spawn和exec的区别 总体来说spawn返回一个stream,exec返回一个buffer child_process.spawn返回一个有输出流和错误的流的对象,你可以监听它们从而获取数据,输出流有数据和结束事件,child_process.spawn适合用在处理

  • iOS开发UIEvent事件简介

    1、UIEvent简介   UIEvent是代表iOS系统中的一个事件,一个事件包含一个或多个的UITouch;   UIEvent分为四类:UIEventType typedefNS_ENUM(NSInteger,UIEventType){ UIEventTypeTouches,//触摸事件类型iOS3.0之后可以用 UIEventTypeMotion,//摇晃事件类型iOS3.0之后可以用 UIEventTypeRemoteControl,//遥控事件类型iOS4.0之后可以用 UIEventTypePressesNS_ENUM_AVAILABLE_IOS(9_0),//物理按钮事件类型iOS9.0之后可以用 };复制   子事件类型:UIEventSubtype typedefNS_ENUM(NSInteger,UIEventSubtype){ //事件没有子类型iOS3.0之后可以用 UIEventSubtypeNone=0, //事件子类型晃动的设备iOS3.0之后可以用 UIEventSubtypeMotionShake=1, //遥控的事件子类型iOS4.0之后

  • 每日一题 LeetCode 486. 预测赢家 【递推】【前缀和】【动态规划】

    题目链接 https://leetcode-cn.com/problems/predict-the-winner/ 题目说明 题解 主要方法:递推;动态规划;前缀和 解释说明: 求前缀和pre_nums,pre_nums[0]=0,pre_nums[1+i]=sum(nums[0……i]) 动态规划、递推: 数据表示:设立二维数组dp,dp[i][j]表示区间[i,j]内先取者能取得的最大值。dpnums 初始状态:遍历nums数组求得长度为1的区间[i,i]内的最大值,即dp[i][i]=nums[i] 动态方程:先后遍历长度l,起点i,dp[i][j][i,j]内最大值=pre_nums[j+1]-pre_nums[i]nums[i,j]的总和-min(dp[i][j-1]取尾端,则减去下一个人相应的最大值[i,j-1],dp[i+1][j])取首端,则减去下一个人相应的最大值[i+1,j]; 数据输出:比较全部最大值与总和的一半returndp[0][size-1]>=sum/2 代码示例: classSolution: defPredictTheWi

  • 傅里叶变换1.基本函数

    #topicsh2{background:rgba(43,102,149,1);border-radius:6px;box-shadow:001pxrgba(95,90,75,1),1px1px6px1pxrgba(10,10,0,0.5);color:rgba(255,255,255,1);font-family:"微软雅黑","宋体","黑体",Arial;font-size:15px;font-weight:bold;height:24px;line-height:23px;margin:12px0!important;padding:5px05px10px;text-shadow:2px2px3pxrgba(34,34,34,1)} 在信号与系统分析中,有两类函数特别重要,可以称之为构建傅里叶变化的基石(BuildingBlocks).本文主要讨论着这两类函数以及一些后续课程需要的知识 1.第一类函数是三角函数信号(SinusoidalSignals) x(t)=Acos(ωt+θ). x(t)=Acos(ωt+θ)   ω称之为角频率,含义是一秒转过多少弧度值(r

  • docker container commands

    dockercontainer Estimatedreadingtime:       2minutes   Description Managecontainers Usage dockercontainerCOMMAND 复制 Childcommands Command Description dockercontainerattach Attachlocalstandardinput,output,anderrorstreamstoarunningcontainer dockercontainercommit Createanewimagefromacontainer’schanges dockercontainercp Copyfiles/foldersbetweenacontainerandthelocalfilesystem dockercontainercreate Createanewcontainer dockercontainerdiff Ins

  • 多个重要的多项式算法以及源码

    多个重要的多项式算法以及源码: 拉格朗日,牛顿插值,高斯,龙贝格,牛顿迭代,牛顿-科特斯,雅克比,秦九昭,幂法,高斯塞德尔 1.拉格朗日插值多项式,用于离散数据的拟合 1#include<stdio.h> 2#include<conio.h> 3#include<alloc.h> 4floatlagrange(float*x,float*y,floatxx,intn)/*拉格朗日插值算法*/ 5{inti,j; 6float*a,yy=0.0;/*a作为临时变量,记录拉格朗日插值多项式*/ 7a=(float*)malloc(n*sizeof(float)); 8for(i=0;i<=n-1;i++) 9{a[i]=y[i]; 10for(j=0;j<=n-1;j++) 11if(j!=i)a[i]*=(xx-x[j])/(x[i]-x[j]); 12yy+=a[i]; 13} 14free(a); 15returnyy; 16} 17main() 18{inti,n; 19floatx[20],y[20],xx,yy; 20print

  • 字符串(String、StringBuffer、StringBuilder)进阶分析

    转载自https://segmentfault.com/a/1190000002683782 我们先要记住三者的特征: String字符串常量 StringBuffer字符串变量(线程安全) StringBuilder字符串变量(非线程安全) 一、定义 查看API会发现,String、StringBuffer、StringBuilder都实现了CharSequence接口,内部都是用一个char数组实现,虽然它们都与字符串相关,但是其处理机制不同。 String:是不可改变的量,也就是创建后就不能在修改了。 StringBuffer:是一个可变字符串序列,它与String一样,在内存中保存的都是一个有序的字符串序列(char类型的数组),不同点是StringBuffer对象的值都是可变的。 StringBuilder:与StringBuffer类基本相同,都是可变字符换字符串序列,不同点是StringBuffer是线程安全的,StringBuilder是线程不安全的。 使用场景 使用String类的场景:在字符串不经常变化的场景中可以使用String类,例如常量的声明、少量的

相关推荐

推荐阅读