云计算平台故障事件与相关研究

今年来,云计算平台发生了多起故障事件,而其原因的分析以及损失估计被很多学者所研究,本文将分别列举规模较大的云计算故障事件,并加以分析,同时对于学界对云计算研究成果做综述性摘要。

经典事件

阿里云停机事件

2019年3月3日,阿里巴巴旗下阿里云发布通报称,华北2地域可用区C部分ECS服务器(云服务器)等实例出现IO HANG(IO不响应),经紧急排查处理后已全部恢复。在这一次事件中,华北相当多的互联网公司的App、网站全部瘫痪,大量程序员、运维晚上从被窝里面被拉回公司修复错误。

Amazon AWS宕机事件

2017年2月28号,一名亚马逊程序员在调试系统的时候,试图运行了一条脚本,以删除少量用于支持支付操作的服务器。但是他输错了命令,导致大量服务器被删。而被误删除的服务器集群中中,有两个非常重要的系统,一个是存放了该区域所有托管服务器的配置信息,用于处理所有GET, LIST, PUT 和 DELETE 请求的。另一个系统用于负责新服务器的分配。

为了修复这个错误,亚马逊不得不重启整个系统。对于数年没有重启过得系统,而重启系统后的完整性和安全检查耗费了非常多的时间。最终导致了震惊全球的Amazon S3宕机4个小时事件。

事后,亚马逊官方网站通告总结事件时,称整个事件的触发程序,是一个支持快速移除大量负载的命令,而我们已经将该命令进行修改,使得负载的移除更加缓慢,并且增加了足够的安全保障,当某个节点移除后,其对应的子系统剩余节点没有能力负载所有的访问,则该移除指令不会被执行。另一方面,亚马逊也修改了恢复系统,保障在将来错误发生时,恢复不再会花费那么多时间。

Azure服务器中断事件

在2012年2月28日,微软旗下的Azure云服务器发生中断,事件长达7小时,据微软官方网站通告,该中断是由于服务中一处关于闰年的计算失误导致的。问题发生后,工程师快速部署了修复代码,并在7小时候恢复了服务器的访问。

其他安全事件

对于云服务商来说,设备故障并不是唯一的灾难,安全性漏洞更为致命,在7 Most Infamous Cloud Security Breaches文章中写道,微软、Dropbox、LinkedIn、Apple iCloud、Yahoo都曾经经历过安全漏洞攻击。并产生了很大的损失。

相关研究

硬件故障是云计算平台故障中,一个非常古老的错误,有非常非常多的研究者对他进行过研究。随着云计算的发展和商业化,硬件故障所扮演的角色也在随之改变,在Wang et al. (2017)的研究中指出,这些变化有积极和消极的方面。
从积极的方面来讲,云服务商的硬件设备的质量越来越可靠,更完备的故障检测系统也被部署到了云计算平台上,从而使得故障的恢复更加高效。而且由于云计算已经是一门非常成熟的技术,面对故障,运维也有足够的经验。这一系列变化都会倾向于降低对故障事件的损失。
但是从消极的方面来讲,由于市场扩大,更多的服务商进驻云计算行业,使得运营商们更加注重成本。自然而然的,他们就会倾向于使用那些不那么可靠,但是便宜的设备。

在Lloyds ́ and AIR (2018)的研究中,对于云服务商的故障损失进行了估计,发现美国的云服务商停机3-6天对应损失可达69亿美元。其中,制造业和零售批发业首当其冲,而其中损失最严重的是财富1000强的企业。

为了控制由于云服务商故障导致的损失,催生出一个全新的保险行业,叫做网络保险(cyber-insurance),这种保险以投保者的网站的可用性作为保险项目。不同于传统的保险,网络保险作为一个新兴的品种,仍没有被大众以及保险公司所接受,一方面是人们并没有正确的认识到服务商故障的损失,另一方面是网络保险有极大的系统性风险。一个云服务商的故障可能同时美国导致124万企业的经营遭受影响,此时大规模的赔偿可能会对保险公司带来巨大的流动性风险。

对于云服务的故障原因,文章Calvesbert (2018列举了四类原因:
1)环境原因,包括自然灾害在内的,无法认为控制的故障。
2)敌对攻击,主要包括竞争对手或黑客,尝试利用网络的漏洞进行攻击。
3)意外原因,指的是日常操作维护的误操作。
4)结构性故障,由于结构缺陷、资源耗尽而产生无法预知的错误。

当然,云平台的故障并不局限于大规模停机,频次更高的是局部性错误。在Chen et al. (2014)的研究中,将这类错误分类为应用错误、配置错误与云错误。配置错误是开发者认为错误配置、重复提交任务导致的,由于开发者在发现任务失败后倾向于重复提交,因此配置错误是所有故障中最多的。其次就是应用错误,其原因为云平台本身的资源限制、以及硬件错误。最后是云错误,其来源于运节点的添加、删除与维护。

总结

经过大规模的资源不可访问的问题的四种成因,意外原因和结构性故障居多,因为这两种成因比较难以估计,与之相反,敌对攻击和环境原因都会有非常完善的防范措施。因而在近现代的宕机事件中,并不常发生。同时可以发现,不同公司在事件后的翻译也不尽相同,这可以通过修复时间,以及事后事件成因分析看出。其中,亚马逊事件后,官方公布了详细的故障原因,以及改进措施,不仅给用户一个交代,也对我们的研究有很大帮助。反之另一些宕机事件,则官方没有公布调查结果,或是寥寥几句,给用户和研究者都带来 极大的困惑。

现有的研究从各个方面为降低云计算错误做了非常重要的贡献,包括损失估计,频率分析,原因总结等等。为云计算厂商优化平台算法,增加可靠性有非常积极的作用。

引用

  • AWSCloud. 2017. Summary of the Amazon S3 Service Disruption in the Northern Virginia (US-EAST-1) Region. (2017). https://aws.amazon.com/message/41926/.
  • Contel Bradford. 2018.7 Most Infamous Cloud Security Breaches.(2018).https://blog.storagecraft.com/7-infamous-cloud-security-breaches/.
  • Gian Calvesbert. 2018. Cloud Service Failure: 3 Things to Know. (2018). https://www.air-worldwide.com/Blog/Cloud-Service-Failure–3-Things-to-Know/.
  • Xin Chen, Charng-Da Lu, and Karthik Pattabiraman. 2014. Failure analysis of jobs in computeclouds: A google cluster case study. In2014 IEEE 25th International Symposium on SoftwareReliability Engineering. IEEE, 167–177.
  • Bill Laing. 2012. Windows Azure Service Disruption Update. (2012). https://azure.microsoft.com/en-us/blog/windows-azure-service-disruption-update/.
  • Lloyd ́s and AIR. 2018.Cloud Down: Impacts on the US economy. Technical Report.
  • G. Wang, L. Zhang, and W. Xu. 2017. What Can We Learn from Four Years of Data Center Hardware Failures?. In 2017 47th Annual IEEE/IFIP International Conference on Dependable Systems and Networks (DSN). 25–36. https://doi.org/10.1109/DSN.2017.26

从零开始编写并托管WordPress插件:NoBaidu抵制百度插件

最近被一篇称为《搜索引擎百度已死》的文章被刷屏了,笔者本身就非常不喜欢百度,趁放寒假没有事情干,琢磨这在自己的网站上写一个插件。当访问者从百度进入网站,则在页面顶部显示一段用户自定义的阻止标语。顺便搞清楚Wordpress插件的原理。

上图就是NoBaidu的一个截图,本文按照我的编写顺序,分为——

  • 如何编写一个Wordpress插件
  • 如何将编好的插件托管到云端

另外,插件的源代码在我的github中开源,读者可以对照理解。

如何编写一个wordpress插件

编写Wordpress插件的教程网上很多,我就不重新造轮子了,我自己是在 如何开发一个WordPress如何开发一个WordPress插件 这篇文章中学到的,其核心要义就是钩子函数——

在Wordpress渲染一个页面的时候,在很多关键位置设置钩子(比如页面渲染开头,渲染器启动后等位置),而插件可以自定义的在任何钩子上挂载自己的函数,这样当页面渲染到了指定位置时,插件可以做一些自己的事情。

比如下面代码就可以在robots.txt渲染时,运行 $this->robots_txt_edit 指定的插件处理模块。

而以NoBaidu插件为例,我们需要支持如下逻辑——

  • 当普通用户访问时,检查用户的请求头的REFERER域是不是baidu域名下的URL
  • 当用户来自百度时,注册一个钩子函数,在页面渲染开始时,加入一个固定在页面顶部的,包含了自定义文字的HTML元素。
  • 当请求robots.txt时,返回禁止Baidu爬虫的robots文字

除此之外,还需要一些额外的代码,来保证我们的插件可以正常使用

  • 在用户是管理员的时候,生成插件设置页面,在其中可以设置显示的自定义抵制文字,用户选择是否组织百度爬虫,以及抵制文字是显示在顶端还是页面中部等等…
  • 编写插件安装、卸载时的逻辑,保证安装时初始化配置信息,卸载时删除配置信息,做到无残留

上述的逻辑,都集中到了下面的代码中,该代码使用一个类包裹了所有的函数(其作用类似于C++中的Namespace,用于最小化命名冲突)

看懂了上面的代码,是不是觉得Wordpress编写插件非常简单? 上述代码中引用的其他php代码,大家可以在我的github中自行查阅。

将自己写好的插件托管到wordpress云端

WordPress官网的Plugin目录最低端,有一个Add Your Plugin分区,这个分区详细介绍了该如何将你的Wordpress插件托管至wordpress.org,一般来说,读完上述的文章,你就已经能够自主把自己的插件丢到云端了。不过我准备从自己的经历出发,来大致讲一讲流程。

WordPress.org自己维护了一个svn仓库,最终会获得自己插件的专属仓库,你可以使用svn提供的版本控制,自行升级、修订等等。而想要获得自己插件的svn仓库,你就需要把自己的插件的最初版提交给官方审核。提交入口在这里。这里写几个提交的注意事项吧——

  • 最重要的是要知道php没有命名空间之说,所以一切全局变量都应该防止冲突。一个比较取巧的做法就是像上文一样,将你自己的程序包裹在一个class里面,而class以自己的插件名称命名。(我就因为配置的class命名为MySettingClass被官方打回来了)
  • 不要有额外的文件,之前写插件的时候,把网上别人插件的代码拷贝到了自己的目录,本来只是想照着抄一抄,结果忘删了,这个也被审核人发现了。
  • README.txt按照官方的标准格式写。

网站上面说的是7个工作日,结果我第一天晚上提交了初版的zip包,第二天早上就收到了审核者的邮件。按照要求修改了一些类名,并删除了无关文件后,我直接把zip包附在了回复中,第三天早上就拿到了通过的消息,并且获得了svn仓库的访问权限。开源社区真的非常强大👍

第一次要求修改的邮件
成功通过审核

接下来就是上传仓库了,如果读者会使用git的话,就别自己去学svn了,照着官方指南走一遍,就完全学会了。和git的pull, add, commit, push, tag如出一辙。

当你的first commit上传到远程仓库,并且readme.txt没有什么问题的话,你应该是可以立即在插件商店中搜索到自己写的插件的。

到这里我们在wordpress上面第一个插件就做好啦!

如果你觉得本文有用的话,欢迎到我的github仓库Star或Contribute~

让我们一起抵制Baidu吧~

参考文章

  • 【一个前人的代码】:http://ju.outofmemory.cn/entry/222836
  • 【如何开发Wordpress插件】:https://www.wpdaxue.com/writing_a_plugin.html
  • 【官方文档】:https://wordpress.org/plugins/developers/

Visdom教程(3):绘制折线图

这是Visdom教程的第三篇文章,主要讲了绘制折线图的方法。


Visdom中,使用函数vis.line绘制折线图,该函数参数表如下——

折线的Y坐标是必要参数。它可以是一个一维数组表示一条直线,也可以是二维数组表示多条折线。该函数的调用可以看示例代码的demo1函数。

line函数还可以设置update参数为’append’。在这种情况下,可以每次只传入新增的数据。示例代码demo2即使一个使用append优化了的绘制深度学习loss函数的例子。

Visdom教程(2):实时展示图片

这是Visdom教程的第二篇文章。主要讲了如何使用Visdom在本地查看服务器上的一个图片。


我们常常使用Visdom实时展示模型训练时刻的图像输出。Visdom支持展示numpy数组形式的若干张图片。展示图片用到了如下两个函数

  • visdom.image(img, win)
  • visdom.images(imgs, win)

第一个函数在win指定的窗口,展示单张图片,而第二个函数则用来展示一系列图片。

  • img是一个表示图片的numpy数组,形状(3,width,height)或者(width,height)形状
  • imgs是表示一系列图片的numpy数组,形状为(batch, 3, width, height)。
  • win表示窗口id,应该可以为任意类型。如果不指定win,服务端将自动新建一个窗口放图片,然后你的浏览器中将堆满密密麻麻的图片窗口。

下面是一个例子——

Visdom教程(1):开启Visdom服务

这是Visdom教程系列文章的第一篇,主要介绍了Visdom的安装。


Visdom是一个Python的远程可视化工具,经常用于配合深度学习训练进行可视化。

Visdom的工作原理是先在远端服务器上面运行一个Server,该服务器将绑定localhost:8097,同时,任意远端运行的Python程序可以通过引入visdom包,实现与该Server的交互。

Visdom服务端假设在服务器上的8097端口,我们只需要执行

安装visdom,并且执行

打开服务端,此时服务端将自动监听8097端口。

下面是一个最简单的visdom程序,该程序在example环境中,新建了一个text_window号窗口,里面写上了Here is the text这句话。

值得注意的是,Visdom中的环境可以理解为工作区,比如一个训练神经网络的程序,训练loss折线图可以输出到train环境中,而模型的内部可视化信息则输出到model环境中。这样可以使我们的工程井井有条。

我们既可以直接通过 server_of_hostname:8097 访问可视化界面,也可以通过ssh命令,将服务器上面的端口映射到本地,并进一步通过 localhost:8097 访问。

ssh name@host.com -p 3522 -L 8097:*:8097 .

 

ICMP攻击及防范

ICMP协议概述

IP协议本身无法处理诸如“得到一个包发送失败的事实”,“对网络进行诊断”这些操作。ICMP协议就是为了上述操作而包含在IP协议中的一个子协议。

ICMP协议(Internet Control Message Protocol)全称Internet控制报文协议,是TCP/IP协议族的一个子协议,用于在主机,路由器之间传递控制信息。最常见的是我们使用的ping命令就是通过发送ICMP包实现的。

ICMP包位于IP包内部,ICMP的包头一般来说紧跟着IP包头(通常IP包头为20字节,则ICMP包头从第21字节开始)。

ICMP包包含Type, Code, Checksum和Data域,其中Type指定了ICMP的类别,可大致分为两类——一种是请求及其回应,另一种是错误信息反馈。

以Echo请求为例,一个Type=8的包发向目标IP,如果目标服务器成功收到,回复一个Type=0请求。倘若中间出现路由错误,则中间路由器返回一个Type=3的包。

ICMP攻击及其防范

ICMP攻击有非常多不同的种类,接下来将列举一些常见的攻击。

ICMP隧道

首先讲一讲ping指令的原理,ping指令首先发送一个ICMP的ECHO REQUEST包给目标IP,并在data域包含一个唯一的16位标识符(这个标识符在Linux中是顺序生成的,而在Windows中是随机生成的),通常操作系统还会在data域后面添加一些无用的信息使得ICMP包长到达一个指定的长度。目标主机收到了ping指令后,将data域原封不动包裹在一个ECHO REPLY包中发回来。

对于一个ICMP ECHO REQUEST/REPLY包,由于其做的是类似于网络控制方面的事情,故通常不会被防火墙在意(除非防火墙一一分析每个包的内在data域有没有异常),而其data域可以携带任意的数据,因此可以借助ICMP包实现一个从服务器发送消息的程序。我在github上面也找到了一个实现ICMP隧道的程序,大家可以参考一下。

对于ICMP tunneling的攻击,有一些非常原始的防范方式,包括限制包的大小以及直接丢弃所有的ICMP包。但是在实际上这些方式都不可行。也有一些比较复杂的防范方式,包括在本机监听包,并在发现异常是,通过网络中的控制节点拦截攻击的流量。

DDOS攻击

PING FLOOD攻击

两个对称的主机,攻击者在一个主机上使用多线程发送大量包向目标主机。只要攻击者的主机的带宽大于被攻击者,被攻击者的带宽就会被完全占满,而真正的包无法到达。

对于这类攻击,可以在子网入口的路由器上设置过滤表,拦截攻击者IP。

Smurf攻击

Smurf-attack是一种原始的DOS攻击,攻击者伪造目标主机的IP为source IP,并发送一个广播的ICMP ECHO REQUEST指令。当指令被网络的其他主机回应后,回应的ECHO REPLY将涌入目标主机,导致目标主机瘫痪。

一般Smurf-attack攻击的解决方式有——对于主机,设置相应的网段,不在该网段的ICMP ECHO REQUEST都不会被相应。或者是对于一个子网路由器,丢弃掉发入子网的广播ECHO REQUEST。由于现在新的路由器都默认disable广播流量,因此smurf攻击基本已经成为历史了。

伪造IP的方式不一定在攻击者主机上面实现,比如在 DNS Amplification Attack 攻击中,攻击者可以通过UDP包,将目标主机的真实地址关联一个无关的IP,注入DNS服务器,将大量无关请求全部导向目标主机。

网络信息收集

通过ICMP攻击可以用来收集网络拓扑结构,首先,通过ECHO REQUEST可以探知一个主机的存在性,而通过一个TTL依次递减的一系列ECHO REQUEST包,观察其ICMP Time Exceeded 包的发送源即可获得一条网络的边。

甚至通过ECHO REPLY包,我们还可以探知目标机器的OS类型。返回TTL=128的机器是Windows系的,而TTL=64的机器是Linux系的。同时,对于一个任意Code域非空的ICMP包,Windows系主机将返回一个Code域为0的包,而Linux则不会。进一步,不同的系统版本对于TIMESTAMP REQ包的回应也不尽相同,我们可以借此更进一步确认。

这类行为因为不会造成严重的后果,故一般没有进行防范。

Ping of Death攻击

通过发送若干段IP超大包,并让目标主机接受后,拼接出一个大小超过65536的包,导致栈溢出。这种攻击仅发生在早起服务器上,新的服务器都通过修改其收包算法的边界条件判定解决了这个攻击。

总结

对于ICMP攻击的防范一般都需要用户服务器精细配置防火墙,或是在边界路由器中设置过滤规则。普通的丢弃ICMP包也是可行的,但是会使得很多网络诊断工具不可用。在参考了有限资料后,我认为ICMPv4和ICMPv6在上述攻击的防御上几乎没有区别,ICMPv6协议本身没有增加额外的防范机制的支持。

参考文献

ICMPv4 and ICMPv6: https://notes.shichao.io/tcpv1/ch8/

ICMP attacks:  https://resources.infosecinstitute.com/icmp-attacks/#gref

ICMP tunnels: https://www.notsosecure.com/icmp-tunnels-a-case-study/

ICMP floods: https://www.cloudflare.com/learning/ddos/ping-icmp-flood-ddos-attack/

Express的Session不同步问题

近期使用express做项目,发现遇到了一个神奇的bug,从现象上来看是用户的session并不同步。具体来说有如下现象——

  • 页面A在session中加入了某个字段。并输出session,发现字段已经成功加入。
  • 页面A通过setTimeout设置5秒后再次输出session,发现字段仍然存在。
  • 页面B在页面A加载后的5秒内访问同用户的session,发现字段不见了。

经过研究,解决方式为在session创建时,指明resave选项为false——

resave字段为false的时候,倘若一个请求未修改session本身,则session不会重新写回内存。通常倘若两个同时发生的请求,只有一个修改了session。当resave为true时,未修改session的请求的session写回操作很容易覆盖另一个请求对于session的修改。

在Vue.js中使用Quill富文本编辑器自定义块级元素

再一次开发中,我试图在vue.js搭建的网站中引入富文本编辑器,我是用了vue2-editor. 这个库将开源富文本编辑器Quill包装进了vue.js的组件中。从易用性角度来说,非常令人满意。

不过,在我们的设计中,我们尝试使用富文本实现一个问卷系统,例如对于选择题,我们希望把一个包含了四个选项的“不可分割块级元素”作为一个整体,像插入图片一样插到富文本编辑器中。

实际上,插入块级元素本身是有先例可循的,比如视频插入模块,可以再富文本编辑器中插入一个iframe块。其代码可在github上面看到——

仿照上面的代码,我们实现我们自己的题目添加控件——

这是我们设计的独立功能模块,通过命令  Quill.register(SelectProblemEmbeder); 进行引入。在保存时,我们需要同时保存富文本的HTML信息,以及DELTAS信息,HTML信息可以用于渲染内容,可以通过vue2-editor暴露在外的content获取,而DELTAS信息可以用于保存富文本编辑的状态,供后续恢复。可以使用 let quill_deltas = JSON.stringify(this.quill.getContents());得到。其中, this.quill 是通过$refs获取到的模块内部信息。恢复时,我们读取上一次编辑的DELTAS信息,使用 this.quill.setContents(quill_deltas); 即可回复之前的状态。

汇编解析C语言函数结构体struct参数的方式

本文介绍在x86汇编中没有加优化选项时的函数体struct传参和返回的方法。

结构体返回值

测试代码

我们先讲讲较为简单的函数返回结构体的方法——

上面的代码实现了一个非常简单的返回结构体的例子,对应的汇编代码如下——

分析

在上面的程序中,内层  return_struct 函数在被调用时,有两个有意义的寄存器,分别是 %rdi 记录了在function1中定义的那个结构体的位置, %rsi 记录传入的n。

在函数进入时,两个寄存器都被保存到了内存里面,接下来按部就班实现C++中的逻辑。重点部分在第30-35行,使用了三个位移操作赋值了五个值。最初理解代码,尝试寻找拷贝内存的语句时,将这三句话直接排除在外,实际上,由于结构体里面是5个整形,而使用64位寄存器,一次可以拷贝两个整数,因此三次拷贝恰好可以用最快的时间完成拷贝。

结论

因此,结构体返回的方式是将返回的结构体的起始位置指针放入 %rdi 寄存器,并在子程序中通过该寄存器定位修改结构体的内容。

结构体传参

测试代码

首先设计样例代码如下——

反汇编出的信息如下——

分析

有了上面的铺垫,我们可以迅速找到在30-35行有一段结构体的拷贝——将位于局部变量中的结构体拷贝到了在28行分配的一段连续空间中,而拷贝操作都是由 %rax 定位的。有意思的是,当我们认为 %rax 正是一个向子程序定位结构体的指针是,发现在子程序中 %rax 的寄存器中的值并没有被使用,反而是使用了 %rsp 进行定位。从另一个方面思考其实也并不奇怪,结构体参数本身是不能通过寄存器传参的,实际上,传参使用了最简单的方式——“通过压栈方式传参”,参数按照“从右到左”的顺序压栈,倘若遇到结构体,则压栈的内容变得多一些而已。

结论

结构体作为参数传入使用压栈方式传参,参数按照“从右到左”的顺序压栈,特别的,当参数为结构体,将结构体整体压栈。

rcaudio:实时录音的音频特征处理库

简介

rcaudio是一个实时的录音,并处理录制的音频的库,使用rcaudio,你可以不用自己编写任何代码,而实现——

  • 获取原始的音频数据
  • 实时监测音量
  • 实时分析录音(歌曲)的节拍,并加以预测

安装

rcaudio是我的第一个放在了pypi.org的工程,因此可以使用pip安装 pip install rcaudio .其中该工程依赖 pyaudio ,倘若出现了无法找到头文件的错误,可直接重装覆盖系统默认的

rcaudio的源码地址为:https://github.com/mhy12345/rcaudio,欢迎push&issue

使用

CoreRecorder

CoreRecorder  是提取原始音频信息的类. 其本身会额外开一个进程,当成员函数 start() 被调用后,录音开始,音频数据会出存在一个队列 CoreRecorder.buffer 中。

如下是一个以字符形式输出录音的波形图的小程序

SimpleRecorder

在多数较为复杂的情况中,我们可以使用 SimpleRecorder ,从效率角度出发,推荐只实例化一次 SimpleRecorder因为绑定了录音部分,所以他会占用掉相当一部分的运行资源。

通过调用 SimpleRecorder 的成员函数 register() ,我们可以将多个 Analyzer 类绑定。

当成员函数 start() 被调用后,录音自动开始,同时起绑定的所有 Analyzer 实例也同时开始运行。

Analyzer

所有继承于 BaseAnalyzer 的类都是一个 Analyzer ,其功能是从原始的音频数据中提取出用户希望的信息。如下例子中,一个 VolumeAnalyzer 用于实时询问音量。

下面例子中,一个 BeatAnalyzer 用于分析节拍并进行预测。(这里的预测会有1~2s的延迟)。 BeatAnalyzer 本质上是通过在当前最后可用的若干 rec_time 时间的数据,提取起节拍信息,进而校准当前的节拍器。校准的具体算法可以参考我的另一篇文章python实现音频节拍的实时识别

多个Analyzer同样可行,比如如下程序在分析节拍的同时,通过音量判断乐曲是否结束。

如果你需要自定义音频特征的提取函数,不妨试试重写 FeatureAnalyzer 的 data_process 成员函数(其传入一个一维数组表示特定时间段的音频原始数据,返回这段时见的特征)。 默认的 data_process 函数计算了过零率。

注意事项

大部分的函数都存在1-2s的延时,个人认为如果不是把所有细节都在实时环境中重写一遍,是很难避免的。在 BeatAnalyzer 中,我使用了很多技巧来让用户看起来好像是事实的,而在 FeatureAnalyzer 如果特征的处理速度太慢,可能这个延时会被无限放大。如果这种情况真的发生,你可以考虑减少采样率sr,或者自己重写一个Analyzer来取舍一些不太重要的步骤。

最后

如果这个工程真的帮助你了的话,不妨给我一个Star哦,你的支持是我的动力!要是有pull request那我就幸福死了ovo