Flink容错机制第五篇 Akka基本概念

    xiaoxiao2025-01-13  24

    上一篇谈到Flink的checkpoint通信的消息驱动用到了Akka,这篇就简介一下Akka的actor模型,并尽可能复习一些以往的框架和多线程知识。

    一,基础概念

    了解Akka是什么之前,要知道一些我们常见且常用的基础概念。

    1. 并发与并行(Concurrency & Parallelism)

    并发和并行概念类似但有不同,并发指的是两个或多个任务能一同进行下去,但不一定会在同时执行。举个例子,我们把任务分块并有序执行这些混合任务的任务块。而并行指的是时间上确切地同时执行。

    2. 同步和异步(Synchronous & Asychronous)

    同步指方法调用的线程会等到结果返回或抛出异常再进行下去;异步指方法调用的线程允许等到过程中去做其他事,等到结果返回会通过额外机制通知该线程取结果(比如registered callback, a Future, or a message)

    3. 阻塞与非阻塞(Blocking & Non-blocking)

    阻塞指某个线程可以无限期延误其他线程的机制,比如互斥锁机制就是这样,如果一个线程得到锁资源,其他线程只能等待资源释放。非阻塞更开放,被延误的线程不用挂起,可以做其他的事。

    4. 死锁,饥饿,活锁(Deadlock, Starvation, Live-lock)

    死锁是指两个或两个以上的进程(或线程)在执行过程中,因争夺资源而造成的一种互相循环等待的现象。

    饥饿是指在为了解决死锁情况,我们通过算法为线程指定优先级,而这样可能会导致有些优先级低的线程永远抢占不到资源而饿死。

    活锁和死锁一样,是一种没有线程得到资源的情况。如果两个线程有两份相同的资源,他们会各自尝试获取资源同时检测是否有其他线程尝试获取,如果检测到了他们就会尝试获取其他资源。而这种情况会导致两个线程互相谦让导致都得不到资源。

    5. 竞争冒险(Race condition)

    指一个系统或者进程的输出依赖于不受控制的事件出现顺序或者出现时机,如果计算机中的两个进程同时试图修改一个共享内存的内容,在没有并发控制的情况下,最后的结果依赖于两个进程的执行顺序与时机。而且如果发生了并发访问冲突,则最后的结果是不正确的。

    二,什么是Akka及Akka的actor模型

    Akka是一个分布式工具集,用于协调远程计算资源来进行一些工作。Akka是actor并发模型的一种体现。所以要了解Akka,核心就要了解Actor模型。

    Actor模型与OOD

    Actor模型是一种并发计算的理论模型,在面向对象编程语言中,对象的特点之一就是能够被直接调用:一个对象可以访问或修改另一个对象的属性,也可以直接调用另一个对象的方法。多线程环境下需要进行同步并加锁。 Actor和对象的不同之处在于其不能直接读取修改或调用。Actor通过消息传递的方式和外界通信,即Actor可以发送消息,接收消息并回复消息,而且消息传递是异步的,无论是处理消息还是回复,Actor对外界都没有依赖。 Actor每次同步处理一个消息,依赖邮箱(等待Actor处理的一个工作队列)完成收发消息。

    优点 所以利用Actor模型的好处之一就是,当每个Actor各司其职时,每个任务都可以并行,使得Actor模型分析并发事件非常容易。 Actor另一个好处是可以消除共享状态,因为每个Actor每次只处理一条信息,所以可以在Actor内部安全地保存状态不必考虑竟态条件下的多线程安全问题。

    三,Akka与并发

    Actor被称作为响应式平台,因为Actor需要做到尽可能对请求做出相应,根据不同工作负载进行伸缩扩展,考虑容错,并有一套使用消息不直接进行方法调用的事件驱动。 针对于并发的事件驱动,Akka采用Promise和future的并行操作管理,这种异步编程模型在netty等框架中也有使用。

    Future与Promise

    Future 模式相当于一个占位符,代表一个操作的未来的结果,使用Future机制时,我们调用耗时任务会立刻返回一个Future实例,使用该实例能够以阻塞的方式或者在未来某刻获得耗时任务的执行结果,还可以添加监听事件设置后续程序。下面是Future使用的例子:

    public class FutureDemo1 { public static void main(String[] args) throws ExecutionException, InterruptedException { long l = System.currentTimeMillis(); ExecutorService executorService = Executors.newSingleThreadExecutor(); Future<Integer> future = executorService.submit(new Callable<Integer>() { @Override public Integer call() throws Exception { System.out.println("执行耗时操作..."); timeConsumingOperation(); return 100; } }); //<1> //其他耗时操作..<3> System.out.println("计算结果:" + future.get());//<2> System.out.println("主线程运算耗时:" + (System.currentTimeMillis() - l) + " ms"); } static void timeConsumingOperation() { try { Thread.sleep(3000); } catch (Exception e) { e.printStackTrace(); } } }

    Future 有两种模式:将来式和回调式(Netty中)。而回调式会出现回调地狱的问题,由此衍生出了 Promise 模式来解决这个问题。这才是 Future 模式和 Promise 模式的相关性。

    在Future机制中,业务逻辑所在任务执行的状态(成功或失败)是在Future中实现的,而在Promise中,可以在业务逻辑控制任务的执行结果,相比Future,更加灵活。Actor使用future和Promise做事件响应实现响应式的事件驱动。

     

     

     

    最新回复(0)