学习

目录
  • Scalable network services
    • Classic Service Design
    • Classic ServerSocket Loop
    • Scalability Goals
    • Divide and Conquer
  • Event-driven Designs
  • Reactor Pattern
    • java.nio Support
    • Basic Reactor Design
    • Multithreaded Designs
    • Worker Threads
    • Worker Thread Pools
    • Handler with Thread Pool
    • Coordinating Tasks
    • Using PooledExecutor
    • Multiple Reactor Threads
    • Using Multiple Reactors
    • Using other java.nio features
    • Connection-Based Extensions

原文地址

concurrent包的大佬Doug Lea写的.介绍了下NIO的演进史?反正有助于学习NIO.
为了加深印象,挑了一些自己翻读一遍. 然而我翻了半天很多都没有道词典优雅,结果许多翻译都直接用有道词典...

<Scalable IO in Java>学习_第1张图片

Scalable network services

Classic Service Design

经典服务设计

<Scalable IO in Java>学习_第2张图片

Each handler may be started in its own thread

每个处理器(handler)可能会启动一个独占的线程.

Classic ServerSocket Loop

经典ServerSocket循环

class Server implements Runnable {
        public void run() {
            try {
                //启动监听端口
                ServerSocket ss = new ServerSocket(PORT);
                //死循环直至线程中止
                while (!Thread.interrupted())
                    //每当Server监听收到一个连接请求,启动一个线程处理连接. accept()为阻塞方法.
                    new Thread(new Handler(ss.accept())).start();
                //    or,    single-threaded,    or    a    thread    pool
            } catch (IOException ex) {    /*    ...    */ }
        }

        static class Handler implements Runnable {
            final Socket socket;

            Handler(Socket s) {
                socket = s;
            }

            public void run() {
                try {
                    byte[] input = new byte[MAX_INPUT];
                    //读数据(阻塞)
                    socket.getInputStream().read(input);
                    byte[] output = process(input);
                    //写数据(阻塞)
                    socket.getOutputStream().write(output);
                } catch (IOException ex) {    /*    ...    */ }
            }

            private byte[] process(byte[] cmd) {    /*    ...    */ }
        }
    }

Scalability Goals

实现弹性要完成的目标


  • Graceful degradation under increasing load (more clients)

  • Continuous improvement with increasing resources (CPU, memory, disk, bandwidth)

  • Also meet availability and performance goals

    • Short latencies
    • Meeting peak demand
    • Tunable quality of service
  • Divide-and-conquer is usually the best approach for achieving any scalability goal


  • 在负载增加(更多客户端接入)的情况下,可以很好的降级. 这里应该指响应上的降级而不是像以前一样暴死

  • 能随着资源(cpu,内存,磁盘,带宽)的增加提升. 可能指性能上提升

  • 同时满足可用性和性能目标.

    • 低延迟
    • 满足高峰需求
    • 服务质量可调节
  • 分治法一直都是满足任何弹性目标最好的实现

Divide and Conquer

分而治之


  • Divide processing into small tasks Each task performs an action without blocking
  • Execute each task when it is enabled Here, an IO event usually serves as trigger

<Scalable IO in Java>学习_第3张图片

  • Basic mechanisms supported in java.nio

    • Non-blocking reads and writes
    • Dispatch tasks associated with sensed IO events
  • Endless variation possible

    • A family of event-driven designs

  • 把处理过程分成小任务,每个任务执行一个没有阻塞的操作. 比如常见的{read request,decode request,process service,encode reply,send reply}

  • 当任务可用时执行,如图就是个将IO事件作为触发器的例子.

  • java.nio中支持的基础机制

    • 非阻塞读写
    • 任务事件的分发与IO事件的感知产生联系 这里应该具体指selector了,感知IO事件然后我们可以分发处理各事件.
  • 可能是不断变化的. 永远不变的是变化

    • 一系列事件驱动的设计

Event-driven Designs

事件驱动 设计


  • Usually more efficient than alternatives

  • Fewer resources : Don't usually need a thread per client.

    • Less overhead : Less context switching, often less locking.
    • But dispatching can be slower : Must manually bind actions to events
  • Usually harder to program

    • Must break up into simple non-blocking actions

      • Similar to GUI event-driven actions
      • Cannot eliminate all blocking: GC, page faults, etc
    • Must keep track of logical state of service


  • 通常比其他选择更有效率

    • 更少的资源占用 : 不用总是一个client一个线程.
    • 更少的开销 : 减少了上下文切换,更少的锁.
    • 但是任务调度可能会更慢 : 必须手动绑定事件的行为.
  • 通常编码更困难

    • 必须拆解成简单的非阻塞行为.

      • 类似于GUI事件驱动操作
      • 无法消除所有阻塞 : GC , 磁盘page错误 等等
    • 必须跟踪服务的逻辑状态. 这段没理解

Reactor Pattern

reactor模式


  • Reactor responds to IO events by dispatching the appropriate handler

    • Similar to AWT thread
  • Handlers perform non-blocking actions

    • Similar to AWT ActionListeners
  • Manage by binding handlers to events

    • Similar to AWT addActionListener

  • Reactor 负责响应IO事件并将其分发到适当的handler上.

    • 类似于AWT线程
  • Handlers 负责执行非阻塞操作

    • 类似于AWT操作监听器
  • 通过将handlers绑定到事件上进行管理

    • 类似于AWT的添加操作监听器接口

java.nio Support


  • ChannelsConnections to files, sockets etc that support non-blocking reads

  • BuffersArray-like objects that can be directly read or written by Channels

  • SelectorsTell which of a set of Channels have IO events

  • SelectionKeysMaintain IO event status and bindings


  • Channels连接到文件,sockets等,支持费阻塞读

  • Buffers类似数组的对象,可由通道直接读取或写入

  • Selectors告诉哪一组通道有IO事件

  • SelectionKeys维护IO事件状态和绑定信息

Basic Reactor Design

Single threaded version

单线程版本

<Scalable IO in Java>学习_第4张图片

public class BasicReactorDesign {
    final Selector selector;
    final ServerSocketChannel serverSocket;

    /**
     * Reactor : Setup
     *
     * @param port 端口号
     * @throws IOException IO异常
     */
    BasicReactorDesign(int port) throws IOException {
        //reactor启动,打开selector
        selector = Selector.open();
        //打开ServerSocket监听端口
        serverSocket = ServerSocketChannel.open();
        serverSocket.socket().bind(new InetSocketAddress(port));
        //设置为非阻塞模式
        serverSocket.configureBlocking(false);
        //selectionKey
        SelectionKey sk = serverSocket.register(selector, SelectionKey.OP_ACCEPT);
        sk.attach(new Acceptor());
    }
    /*
    Alternatively, use explicit SPI provider:
    SelectorProvider p = SelectorProvider.provider();
    selector = p.openSelector();
    serverSocket = p.openServerSocketChannel();
    */

    /**
     * Reactor : Dispatch Loop
     */
    public void run() { // normally in a new Thread
        try {
            while (!Thread.interrupted()) {
                selector.select();
                Set selected = selector.selectedKeys();
                for (SelectionKey selectionKey : selected) {
                    dispatch(selectionKey);
                }
                selected.clear();
            }
        } catch (IOException ex) { /* ... */ }
    }

    void dispatch(SelectionKey k) {
        Runnable r = (Runnable) (k.attachment());
        if (r != null) {
            r.run();
        }
    }

    /**
     * Reactor : Acceptor
     */
    class Acceptor implements Runnable { // inner

        @Override
        public void run() {
            try {
                SocketChannel c = serverSocket.accept();
                if (c != null) {
                    new Handler(selector, c);
                }
            } catch (IOException ex) { /* ... */ }
        }
    }

    /**
     * Reactor : Handler setup
     */
    final class Handler implements Runnable {

        public static final int MAXIN = 1024;
        public static final int MAXOUT = 1024;

        final SocketChannel socket;
        final SelectionKey sk;
        ByteBuffer input = ByteBuffer.allocate(MAXIN);
        ByteBuffer output = ByteBuffer.allocate(MAXOUT);
        static final int READING = 0, SENDING = 1;
        int state = READING;

        Handler(Selector sel, SocketChannel c) throws IOException {
            socket = c;
            c.configureBlocking(false);
            // Optionally try first read now
            sk = socket.register(sel, 0);
            sk.attach(this);
            sk.interestOps(SelectionKey.OP_READ);
            sel.wakeup();
        }

        boolean inputIsComplete() {/* ... */}

        boolean outputIsComplete() {/* ... */}

        void process() {/* ... */}

        //Reactor 5: Request handling
        @Override
        public void run() {
            try {
                if (state == READING) {
                    read();
                } else if (state == SENDING) {
                    send();
                }
            } catch (IOException ex) { /* ... */ }
        }

        void read() throws IOException {
            socket.read(input);
            if (inputIsComplete()) {
                process();
                state = SENDING;
                // Normally also do first write now
                sk.interestOps(SelectionKey.OP_WRITE);
            }
        }

        void send() throws IOException {
            socket.write(output);
            if (outputIsComplete()) {
                sk.cancel();
            }
        }

    }

}

Multithreaded Designs

多线程设计


  • Strategically add threads for scalability

    • Mainly applicable to multiprocessors
  • Worker Threads

    • Reactors should quickly trigger handlers

      • Handler processing slows down Reactor
    • Offload non-IO processing to other threads

  • Multiple Reactor Threads

    • Reactor threads can saturate doing IO

    • Distribute load to other reactors

      • Load-balance to match CPU and IO rates

  • 有策略地添加线程以实现可伸缩性

    • 主要适用于多处理器(多核)
  • 工作者线程组

    • rector线程组应该可以快速触发handler线程组.

      • handler线程组根据处理能力可以降级reactor. 我的理解
    • 将非IO处理操作转移至其他线程组

  • 复数reactor线程

    • reactor线程组能做IO操作至饱和

    • 将负载分摊给其他reactor. 不知是否如此翻译

      • 负载均衡CPU与IO的比率

Worker Threads

worker线程组


  • Offload non-IO processing to speed up reactor thread

    • Similar to POSA2 Proactor designs
  • Simpler than reworking compute-bound processing into event-driven form

    • Should still be pure nonblocking computation

      • Enough processing to outweigh overhead
  • But harder to overlap processing with IO

    • Best when can first read all input into a buffer
  • Use thread pool so can tune and control

    • Normally need many fewer threads than clients

  • 卸下非IO处理来提速reactor线程

    • 类似于POSA2的Proactor设计
  • 比无界计算处理重构成事件驱动形式更简单

    • 应该仍然是纯粹的非阻塞计算

      • 足够的处理能力比因此引入的开销更有价值
  • 但难与IO重叠处理

    • 最好在第一次读取所有输入到缓冲区
  • 使用线程池,这样可以调优和控制

    • 通常需要的线程比客户机少得多

Worker Thread Pools

<Scalable IO in Java>学习_第5张图片

Handler with Thread Pool

可拿此handler带入原basic design版本.直接变成上图形式.

  class Handler implements Runnable {
        // uses util.concurrent thread pool
        static PooledExecutor pool = new PooledExecutor(...);
        static final int PROCESSING = 3;
        // ...
        synchronized void read() { // ...
            socket.read(input);
            if (inputIsComplete()) {
                state = PROCESSING;
                pool.execute(new Processer());
            }
        }
        synchronized void processAndHandOff() {
            process();
            state = SENDING; // or rebind attachment
            sk.interest(SelectionKey.OP_WRITE);
        }
        class Processer implements Runnable {
            public void run() { processAndHandOff(); }
        }
    }

Coordinating Tasks

协调任务?


  • Handoffs

    • Each task enables, triggers, or calls next one Usually fastest but can be brittle
  • Callbacks to per-handler dispatcher

    • Sets state, attachment, etc
    • A variant of GoF Mediator pattern
  • Queues

    • For example, passing buffers across stages
  • Futures

    • When each task produces a result
    • Coordination layered on top of join or wait/notify

  • Handoffs 咋翻译?

    • 每个任务启用、触发或调用下一个任务.
    • 通常是最快的,但也可能很脆弱
  • 对每个per-handler dispatch都有回调

    • 设置状态,附件等
    • GoF Mediator模式的一种变体
  • 队列

    • 举个例子: 将缓冲区buffer传递过各个阶段.
  • Futures

    • 当每个任务产生一个结果
    • 协调层在join或wait/notify的顶部

Using PooledExecutor

使用线程池. 从这篇文章看来,这部分是介绍线程池的使用?


  • A tunable worker thread pool

  • Main method execute(Runnable r)

  • Controls for:

    • The kind of task queue (any Channel)

    • Maximum number of threads

    • Minimum number of threads

    • "Warm" versus on-demand threads

    • Keep-alive interval until idle threads die

      • to be later replaced by new ones if necessary
    • Saturation policy

    • block, drop, producer-runs, etc


  • 一个可调节工作线程池

  • 主要方法为execute(Runnable r)

  • (需要?)控制:

    • 任务队列的类型(任何Channel)

    • 最大线程数

    • 最小线程数

    • "预热"以应对随机应变的线程

    • 保持活动时间间隔,直到空闲线程死亡

      • 如有必要,以后再用新的代替
    • 饱和策略

      • 阻塞,抛弃,producer-runs(这东西怎么翻译?)等.

Multiple Reactor Threads

多Reactor线程


  • Using Reactor Pools

    • Use to match CPU and IO rates

    • Static or dynamic construction

      • Each with own Selector, Thread, dispatch loop
    • Main acceptor distributes to other reactors


  • 使用reactor池

    • 用于匹配CPU和IO速率(这个IO rates不知道怎么翻译?)

    • 静态或动态构造器(还是该翻译成结构呢?)

      • 每个(应该指每个reactor线程)都有自己的selector,线程,调度loop(调度组件.)
    • 主接收器(指负责accept的reactor吧)分发给其他reactor

    Selector[] selectors; // also create threads
    int next = 0;
    class Acceptor { // ...
        public synchronized void run() { ...
            Socket connection = serverSocket.accept();
            if (connection != null)
                new Handler(selectors[next], connection);
            if (++next == selectors.length) next = 0;
        }
    }

Using Multiple Reactors

<Scalable IO in Java>学习_第6张图片

Using other java.nio features

使用其他java.nio特性


  • Multiple Selectors per Reactor

    • To bind different handlers to different IO events
    • May need careful synchronization to coordinate
  • File transfer

    • Automated file-to-net or net-to-file copying
  • Memory-mapped files

    • Access files via buffers
  • Direct buffers

    • Can sometimes achieve zero-copy transfer
    • But have setup and finalization overhead
    • Best for applications with long-lived connections

  • 每个reactor有多个selector

    • 将不同的处理程序绑定到不同的IO事件
    • 可能需要小心地使用同步来协调
  • 文件转换

    • 自动[文件到网络]或[网络到文件]的复制
  • 内存映射文件

    • 通过缓冲区访问文件
  • 直接缓冲区

    • 是否可以实现零拷贝
    • 但是有初始化和销毁的开销
    • 最适合具有长期连接的应用程序

Connection-Based Extensions

基于连接的扩展

这部分并不是很明白在讲啥.可能在讲更多的扩展模型


  • Instead of a single service request

    • Client connects
    • Client sends a series of messages/requests
    • Client disconnects
  • Examples

    • Databases and Transaction monitors
    • Multi-participant games, chat, etc
  • Can extend basic network service patterns

    • Handle many relatively long-lived clients
    • Track client and session state (including drops)
    • Distribute services across multiple hosts

  • 并不是单个服务请求

    • 客户端连接
    • 客户端发送一系列的消息/请求
    • 客户端断开连接
  • 样例

    • 数据库和事务监视器
    • 多人游戏、聊天等
  • 可以扩展基本的网络服务模式

    • 处理许多寿命相对较长的客户机
    • 跟踪客户端和会话状态(包括丢弃)
    • 跨多个主机分发服务

你可能感兴趣的:(学习)