00:00
在CP这一章的最后呢,我们来讲一讲它的底层原理,那就是状态机相关的内容。其实我们知道弗link cp对于复杂事件的检测过程,关键就在于pattern啊,那就是模式的定义。在CP里边,我们定义模式的方法其实跟正则表达式非常的相似,那我们知道正则表达式呢,它也就是定义了一个模板,然后去寻找字符串上匹配符合模板的字符序列,而flink cp呢,它是在事件流上去寻找符合我们的pattern定义的复杂事件序列。所以本质上来讲,我们可以用处理正则表达式的方法去处理CP的中间的状态。那在整个CP进行复杂事件处理的过程当中,我们会发现它基本上可以分为这么几步啊,就是首先我们应该有一个初始的状态,比如说我们一开始这种定义的过程啊,首先应该有一个初始模式,这就相当于假如说当前匹配的话,那就进入我们接下来等待检测的过程当中了。
01:10
哎,那如果说继续到来一个事件的话,又匹配一步,又前进一步,那如果说一旦出现不匹配的事件,导致我们整个组合模式都已经不能正常匹配的话,那就相当于整个回滚,所有的事件丢掉,回到最初始等待第一个初始事件的这个过程。所以我们会发现啊,这其实就相当于一个状态的跳转,每一步状态的跳转呢,都跟当前的状态以及输入的数据有关。其实我们有所了解的话就会知道啊,这其实就是一个状态机啊,那本质上来讲,CP的底层原理就是一个非确定有限状态自动机啊,简称叫做NFA底层源码里边啊,它本身就实现了这样一个NFA相应的类,那它的原理呢,其实是涉及到了很多数学知识的,我们只要知道它是一个自动状态机,而且它跟正则的底层原理是一致的就可以了。
02:14
那接下来呢,我们就用一个具体的例子来说明一下啊,状态机到底是怎么样去工作的,这样的话我们就能更深刻的去理解CP的底层原理了。我们还是回顾一下之前讲过的那个经典的案例,那就是要去检测用户连续三次登录失败的复杂事件,之前我们使用了CP啊,那直接定义这样的一个模式啊,可以是先定义一个begin,定义一个第一次登录失败的事件,然后后面next next也可以呢,更简单的,我们在这里直接定义一个登录失败事件,然后TIMES3加上一个consecutive,指定它的严格径邻关系就可以了。哎,那这个过程其实非常的简单啊,但是我们自然会想到,如果说我们不用CP给我们提供好现成的这种API的调用,那怎么样去自己实现呢?呃,之前也提到过,使用底层的处理函数当然可以实现。
03:11
这个过程当中我们就需要定义各种不同的状态啊,那假如说我们真的是做一个这个简单的状态编程啊,那就是来了一个事件之后,判断是否符合我们的筛选标准,然后把它做一个保存,然后再来一个事件,继续判断,继续保存,哎,那这个过程if的判断分支逻辑会非常的复杂,我们当前是有三个登录失败的事件,可能还比较容易理解,那如果要是更多的话,这个复杂度就会指数上升啊,那整个代码可读性就会越来越差,所以如果说我们真的想从底层去做一个状态编程的实现的话,那更好的方式其实就是实现一个状态机。那状态机这一部分呢,其实听起来很高大上,关键点就在于我们要搞清楚整个处理的过程当中,状态到底是怎么样去转移的,所以我们可以看一下这张图,就是整个我们要处理的这个检测三次登录失败,那到底是要判断它的什么样的一个状态,首先初始状态,初始状态当然就是什么数据都没有,最一开始的状态,那就是以你手我们先定义这样一个状态,然后接下来呢,基于初始状态,当然就有可能有两种情况。
04:29
来了一个登录失败的事件,也有可能来了一个登录成功的事件,其实我们知道如果来的是登录成功事件的话,那就没什么好说的啊,相当于我们当前的这个模式,连续三次登录失败,那就直接已经得退出了嘛,完全不符合啊,所以就直接进入一个terminal状态,那所谓的terminal啊,终止状态呢,其实就直接会重置回初始状态去啊,所以本质上啊,一旦遇到这个success的事件来了之后,相当于这个你手状态就没有改变。
05:01
然后如果说他要是遇到了一个非事件呢,失败的事件,那接下来他就真正进入了下一个阶段,那就是要等待第二次登录失败了,哎,所以我们把这个中间状态叫做S1。S1的这个状态呢,接下来又可以接收不同类型的事件,如果来了一个success,那没什么好说的,还是进入特命的终止状态,然后直接返回到盈手就可以了,那如果要是再来一个费用呢?啊,那再来一个费用的话,当前就已经有了两次登录失败的事件,现在就进入到了S2对应的这个状态,另外一个新的状态。进入S2之后,相当于我们现在就是已经有了两次连续的登录失败,就等第三次登录失败了,所以接下来同样有费和success接收两种类型事件的可能,如果是success,那还是啊,之前我们所有的积累全部都作废,直接退回到引你手舒适状态,而如果要是这个时候来了一个费用呢?诶,那就真正进入到了match的状态,就真正进入到了匹配可以输出当前的一个报警信息了,真正检测到了连续三次登录失败。
06:16
那注意这个时候他的状态又做什么样的一个调整呢?诶,那就要考虑到接下来如果说我们再来了登录成功或者失败的事件,会做什么样的处理,那当然了,如果接下来来了成功事件的话,还是直接退回到一手啊,我们之前所有的状态遇到成功事件的时候都是退回到一一手,这个没有问题,那如果接下来再来一个失败事件呢,那其实就类似于我们说的啊,假如是连续的四次登录失败。按照我们之前CP的处理方式,它其实会哦,就是前三个直接要输出一次报警信息,那后三个这也是一个连续三次的登录失败,也会输出一个报警信息。所以本质上来讲,如果我们检测到第三个登陆失败事件的时候,当前的状态。
07:06
还可以继续检测。他输出一次当前的报警信息,另外呢,还要退回到S2状态,也就是有两个连续登录失败的这个状态,来等待下一次输入,如果是费的话,继续输出。这就是我们对于当前状态转移的一个基本的分析判断。所以在这个过程当中,其实啊,我们这里的这个terminal和match,本质上来讲不应该叫做状态机里边的一个状态,因为一到了这个状态之后,它立刻就重置就跳转了啊,本质上来讲,这里的terminal跟手是一个状态,另外这里的match呢,跟这里的S2是一个状态,但是因为进入match的这个状态的时候呢,我们要做一个对应报警信息的输出。进入terminal这个状态的时候呢,哎,我们要做一个恢复到初始状态啊,清空所有状态这样一个操作,那所以呢,有了这两个状态作为一个标记位的话,我们的代码可读性就会更强,所以接下来我们就在代码里边去做一个具体的尝试。
我来说两句