Halo
发布于 2022-05-24 / 129 阅读 / 0 评论 / 0 点赞

高并发模型

Actor模型

在Actor模型中主角是actor,类似一种worker。
Actor彼此之间直接发送消息,不需要经过什么中介,消息是异步发送和处理的.

组成

  1. state
    指 actor 本身的属性信息
    state只能被actor自己操作,不能被其他actor共享和操作,有效的避免加锁和数据竞争.

  2. behavior
    actor 处理逻辑,通过行为来操作自身state

  3. Mailbox
    存储消息的fifo队列,actor与actor发送消息,消息只能发送到邮箱,等待拥有邮箱的actor 去处理
    这个过程是异步的。简单来说,有时间才处理,等我把前面任务先完成

akka

示例:

//累加器
static class CounterActor extends UntypedActor {
    private int counter = 0;
    
    @Override
    public void onReceive(Object message){
        
        //如果接收到的消息是数字类型,执行累加操作,
        //否则打印counter的值
        if (message instanceof Number) {
            counter += ((Number) message).intValue();
        } else {
            System.out.println(counter);
        }
    }
}

public static void main(String[] args) throws InterruptedException {
        //创建Actor系统
        ActorSystem system = ActorSystem.create("HelloSystem");
        
        //4个线程生产消息
        ExecutorService es = Executors.newFixedThreadPool(4);

        //创建CounterActor
        ActorRef counterActor = system.actorOf(Props.create(CounterActor.class));
        
        //生产4*100000个消息
        for (int i=0; i<4; i++) {
            es.execute(()->{
                for (int j=0; j<100000; j++) {
                    counterActor.tell(1, ActorRef.noSender());
                }
            });
        }
        
        //关闭线程池
        es.shutdown();
        
        //等待CounterActor处理完所有消息
        Thread.sleep(1000);
        
        //打印结果
        counterActor.tell("", ActorRef.noSender());
        
        //关闭Actor系统
        system.shutdown();
}

reactor模型

  • Reactor模型的核心是:Reactor+Handles。
  • Reactor在一个单独的线程中运行,负责监听和分发事件,将接收到的io事件交给不同的Handle来处理响应。Handles是处理程序执行I/O事件的实际操作
  • Reactor通过调度适当的Handles来处理io事件。
  • 事件到达的底层实现是epoll 实现
  • 同时接收多个服务请求,并且依次同步的处理它们的事件驱动程序

处理顺序

  1. 等待事件 (Reactor job)
  2. 分发 “Ready-to-Read” 事件给用户处理函数( Reactor job)
  3. 读取数据 (user handler job)
  4. 处理数据( user handler job)

目前常用的Netty、Redis、Memcached、Nignx都是基于Reactor模式实现的。

java 示例

java 8 提供了两个非常有用发布者, Flux 和 Mono, 用来产生异步序列。

  • Flux 代表的是 0 to N 个响应式序列
  • Mono代表的是0或者1个响应式序列。只会触发Subscriber的onComplete和onError方法,没有onNext
public abstract class Flux<T> implements Publisher<T> 
public abstract class Mono<T> implements Publisher<T> 
<dependency>
    <groupId>io.projectreactor</groupId>
    <artifactId>reactor-core</artifactId>
</dependency>

proactor 模型

  • 事件到达的底层实现是epoll 实现
  • 异步接收和同时处理多个服务请求的事件驱动程序

处理顺序

  1. 等待事件 (Proactor job)
  2. 读取数据 (now Proactor job)
  3. 分发 “Read-Completed” 给用户处理函数 (Proactor job)
  4. 处理数据 (user handler job)

目前成熟的框架很少, 有c++ ace proactor

高并发低延迟的核心的

如何设计一个高吞吐量,低延时的系统?
通常认为没有充分利用多线程压榨多个CPU的能力是造成性能问题的原因,实际上缓存问题才是性能杀手

并发的实现

  • 第一个方法是用锁来保证. 使用锁会导致内核态的切换,但总可以确保任何时刻总有一个进程会被执行(相比之下Lock-Free如果代码逻辑出现问题,有可能所有线程都处在自旋等待状态,无法前进),锁也增加了编程的难度
  • 另一个方法是借助于CAS进行无锁编程。而借助于CAS的Lock-Free则始终是运行在用户态的(节省了效率,避免了无谓的上下文切换),相比于锁,它的编程难度更加大.

评论