0%

将页面设计好看,大概是所有程序员的朴素追求,命令行不在谈论范围。企业级中后台界面设计是一个很常见的场景,但是往往很多公司或者项目组,没有专业的前端和产品经理,因此就很有必要了解一下前端设计价值观(原则)。

通常来说设计价值观是用来评判是否好看,给设计提供标准,设计原则是用来践行好的设计价值观的,这里暂且将两者混合而谈。

声明作者能力有限,非前端设计/开发者,本文仅是将业界经验和自己的工作总结,欢迎找我交流补正!

这是一篇写给中后台开发者看的前端设计价值观。

资源

在开始之前推荐大家看业界优秀的文档,强烈安利!本文也只是自己根据这些的总结罢了。

  1. 腾讯 TDesign
  2. 蚂蚁 Ant Design
  3. Alibaba Fusion
  4. awesome-design-principles
  5. element-plus
  6. 网易云商Fish Design

不同企业定义的设计价值观不同,但总的来说脱离不了:清晰、高效、统一、美观、简单、可靠 ,当我们在写一个用户界面,可以用这几个原则来做衡量和取舍。

色彩

中后台设计中,色彩的使用建议是克制的,更多的是基于信息的传递、操作引导和交互反馈的目的。

通常包含主题色、功能色、中性色3部分。

数据可视化需要单独的颜色场景,本文不做介绍,需要了解的话推荐参考AntV色板

主题色

也可以称之为品牌色,主题色是产品中最核心、最高频使用的颜色,决定了产品整体的基调和风格。

应用场景包括:强调信息、引导操作,关键行动点,操作状态、重要信息高亮,图形化等场景。

大家有没有想过,科技的颜色?

不同品牌的色彩体系里,科技公司都比较倾向于蓝色色系,例如TDesign,Ant Design Pro, Fusion ,Fish Design等,我比较倾向于喜欢 Tencent Blue

1
2
3
rgba(0, 82, 217, 1)

#0052d9

如果需要选择自己的色彩,建议使用Ant Design 的基础色板,完全可以满足中后台设计中对于颜色的需求。

Ant Design 调色板的一部分

建议选择色板从浅至深的第六个颜色作为主色

阅读全文 »

面试系列笔记-Redis

本文来自

https://github.com/TrumanDu/knowledge/blob/main/%E7%BC%93%E5%AD%98.md

Redis必知知识点

String

内部编码int(8字节长整型)/embstr(小于等于44字节字符串)/raw(大于44个字节字符串)

适用场景:共享session、分布式锁,计数器、限流、缓存

List

内部编码:`ziplist(同时满足:所有字符串元素的长度都小于64字节,元素数量小于512个)、quicklist

适用场景:消息队列,文章列表

1
2
3
4
lpush+lpop=Stack(栈)
lpush+rpop=Queue(队列)
lpsh+ltrim=Capped Collection(有限集合)
lpush+brpop=Message Queue(消息队列)

ziplist是一段连续内存,节省内存空间。

quicklist 存储了一个双向列表,每个列表的节点是一个ziplist,

Set

内部编码intset(整数集合)、hashtable(哈希表)如果集合中的元素都是整数且元素个数小于512个,使用intset编码,否则使用hashtable编码

适用场景:用户标签,生成随机数抽奖、社交需求

Hash

内部编码ziplist(压缩列表)哈希类型元素个数小于512个,所有值小于64字节的话,使用ziplist编码,否则使用hashtable(哈希表)

适用场景

SortSet

内部编码ziplist(压缩列表)skiplist(跳跃表)当有序集合的元素个数小于128个,每个元素的值小于64字节时,使用ziplist编码,否则使用skiplist(跳跃表)编码

适用场景:排行榜,社交需求(如用户点赞)。

其他

  • Geospatial 存储地理位置信息
  • Hyperloglog 基数统计算法的数据结构,可以用来统计数量
  • Bitmap 位图,解决大数据利器
阅读全文 »

MongoDB 是通用、基于文档的分布式数据库。支持完整的 ACID 事务,具有强大的查询语言等。属于NoSQL数据库。

基本概念

SQL术语/概念 MongoDB术语/概念 解释/说明
database database 数据库
table collection 数据库表/集合
row document 数据记录行/文档
column field 数据字段/域
index index 索引
table joins 表连接,MongoDB不支持
primary key primary key 主键,MongoDB自动将_id字段设置为主键

SQL术语/概念MongoDB术语/概念解释/说明databasedatabase数据库tablecollection数据库表/集合rowdocument数据记录行/文档columnfield数据字段/域indexindex索引table joins表连接,MongoDB不支持primary keyprimary key主键,MongoDB自动将_id字段设置为主键SQL术语/概念MongoDB术语/概念解释/说明databasedatabase数据库tablecollection数据库表/集合rowdocument数据记录行/文档columnfield数据字段/域indexindex索引table joins表连接,MongoDB不支持primary keyprimary key主键,MongoDB自动将_id字段设置为主键

适用场景与选型

MongoDB定位与优点

  • OLTP数据库
  • ACID事务
  • 横向扩展能力,数据量和并发量增加时候架构可以自动扩展
  • JSON数据结构 ,适合微服务/REST API
  • 灵活模型,适合迭代开发,数据模型多变的场景

基于功能选择

支持功能
亿及以上数据量
灵活表结构
高并发读/写
跨地区集群
分片集群
地理位置查询
聚合计算
异构数据
大宽表

支持功能亿及以上数据量灵活表结构高并发读/写跨地区集群分片集群地理位置查询聚合计算异构数据大宽表支持功能亿及以上数据量灵活表结构高并发读/写跨地区集群分片集群地理位置查询聚合计算异构数据大宽表### 基于场景选择

  • 移动应用
  • 商品信息
  • 内容管理
  • 物联网
  • Saas
  • 主机分流
  • 实时分析
  • 关系型数据库替换
阅读全文 »

常用垃圾回收器

  • CMS
  • G1
  • ZGC

通过如下命令,可以查看垃圾回收器的使用情况

1
$ java -XX:+PrintCommandLineFlags -version

jdk1.8 如下:

1
2
3
4
5
6
7
8
9
10
-XX:InitialHeapSize=534944128
-XX:MaxHeapSize=8559106048
-XX:+PrintCommandLineFlags
-XX:+UseCompressedClassPointers
-XX:+UseCompressedOops
-XX:-UseLargePagesIndividualAllocation
-XX:+UseParallelGC
openjdk version "1.8.0_181-1-redhat"
OpenJDK Runtime Environment (build 1.8.0_181-1-redhat-b13)
OpenJDK 64-Bit Server VM (build 25.181-b13, mixed mode)

jdk1.8 -XX:+UseParallelGC 默认使用的是Parallel垃圾回收器

jdk11 如下:

1
2
3
4
-XX:G1ConcRefinementThreads=10 -XX:GCDrainStackTargetSize=64 -XX:InitialHeapSize=534944128 -XX:MaxHeapSize=8559106048 -XX:+PrintCommandLineFlags -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC -XX:-UseLargePagesIndividualAllocation
openjdk version "11.0.6" 2020-01-14
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.6+10)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.6+10, mixed mode)

jdk11 -XX:+UseG1GC默认使用的垃圾回收器是G1

理解JVM垃圾回收有用的资源

  1. 新一代垃圾回收器ZGC的探索与实践
  2. JVM系列–还不会选择合适的垃圾收集器?
  3. Java——七种垃圾收集器+JDK11最新ZGC
  4. JVM调优

jvm启动参数

java启动参数共分为三类;
其一是标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容;
其二是非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足,且不保证向后兼容;
其三是非Stable参数(-XX),此类参数各个jvm实现会有所不同,将来可能会随时取消,需要慎重使用;

常用非标准参数

通过 java -X 可以查看支持的非标准参数

1
2
3
4
-Xms6g //最小堆
-Xmx6g //最大堆
-Xss1m //线程栈的大小
-Xmn200m //设置年轻代大小为200M

常用非Stable参数

通过java -XX:+PrintFlagsFinal -version可以查看支持的非Stable参数

  • -XX:+<option>:代表启用 true
  • -XX:-<option>:代表禁用 false
1
2
-XX:+PrintGC
-XX:+PrintGCDetails

G1

G1全称为Garbage-First,意为垃圾优先,哪一块的垃圾最多就优先清理它。

常用参数

1
2
-XX:+UseG1GC //使用G1回收器
-XX:MaxGCPauseMillis=20 // 最大暂停时间为20ms 越小意味着堆小,回收频繁

ZGC

ZGC(The Z Garbage Collector)是JDK 11中推出的一款低延迟垃圾回收器,它的设计目标包括:

  • 停顿时间不超过10ms;
  • 停顿时间不会随着堆的大小,或者活跃对象的大小而增加;
  • 支持8MB~4TB级别的堆(未来支持16TB)。
1
2
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC 
-XX:ConcGCThreads=2 -XX:ParallelGCThreads=6

超低延迟(TP999 < 20ms)和高延迟(TP999 > 200ms)服务收益不大,吞吐量优先的场景,ZGC可能并不适合。

更多信息参考:新一代垃圾回收器ZGC的探索与实践

jvm性能查看工具

jstat

利用jvm内建的指令对java应用程序的资源和性能进行实时的命令行监控,包括针对heap size和垃圾回收情况的监控

1
2
3
4
$ jstat -gc 14724 1000 2 //间隔1s,统计两次
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
19968.0 22528.0 0.0 0.0 429056.0 185319.3 395264.0 33163.2 59160.0 55725.5 7808.0 7049.8 8 0.063 3 0.156 0.219
19968.0 22528.0 0.0 0.0 429056.0 185855.6 395264.0 33163.2 59160.0 55725.5 7808.0 7049.8 8 0.063 3 0.156 0.219

参数含义:
S0C:年轻代的第一个survicor(幸存区)的容量(字节)
S1C:年轻代的第二个survicor(幸存区)的容量(字节)
S0U:年轻代的第一个survicor(幸存区)已经使用的空间(字节)
S1U:年轻代的第二个survicor(幸存区)已经使用的空间(字节)
EC:年轻代中的Eden(伊甸园)的容量
EU:年轻代中的Een(伊甸园)已经使用的容量
OC:年老代的容量
OU:年老代已经使用的空间
MC:metadata的容量
MU:metadata已经使用的空间
CCSC:压缩类空间的大小
CCSU:压缩类空间的使用大小
YG:从应用程序启动到采样时年轻代中gc次数
YGCT:从应用程序启动到采样时年轻代中gc所用时间(s)
FGC:从应用程序启动到采样时年老代gc次数
FGCT:从应用程序启动到采样时年老代(全gc)gc所用时间(s)
GC: 从应用程序启动到采样时gc用的总时间(s)

jmap

查看jvm的内存分配情况

1
2
3
$ jmap -heap 14724
$ jmap -dump:format=b,file=D:\test\heap.hprof 14724
$ jmap -histo:live 14724 //只统计活的对象数量

jstack

查看java程序的线程运行情况

1
$ jstack 14724

jinfo

1
2
$ jinfo 14724 //查看jvm系统详细参数及环境变量
$ jinfo -flag MaxHeapSize 14724 //查看最大堆内存

最佳实践

输出GC日志

jdk11

1
java -Xlog:gc*:file=gc.log,filecount=10,filesize=10m

jdk8

1
-XX:+PrintGCDetails -Xloggc:<PATH_TO_GC_LOG_FILE>

dump

1
2
3
#出现 OOM 时生成堆 dump:
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/home/jvmlogs/

《如何成为学习高手》笔记

作者从5个方面分享了如何更好的学习,成为学习高手,花费一天时间走马观花,只是在个别章节里收益匪浅,按照文章的划分总结一下自己的收获。

底层思维

告别伪勤奋

1、花大量时间做容易的环节。

解决思路是:在你“踮一踮脚能够够得到”的层面去学习、去做事,只有去完成那些让你感到需要思考、需要克服困难的任务,才称得上“真勤奋”。

2、从来不去检测自己获得了什么。

解决思路是:学的东西,要立刻检测,检测自己有没有记住,检测自己是不是会做题。对于真正的勤奋来说,再功利主义也不为过。你要看到反馈,你要立刻看到反馈。一切不以检测和输出为目的的努力,都是耍流氓。

3、只是埋头苦学,从来不总结规律。

解决思路是:学习这件事,不仅包括对知识的学习,还包括对学习方法的学习。你要学会观察、分析、总结自己是如何学习的,对方法进行针对性的调整和完善,并且有意识地指导自己接下来的努力方向。

4、道德许可效应让你原地徘徊,沉迷于已经努力的幻觉之中。

解决思路是:将你想做的事情最简化,去掉所有花里胡哨的,不搞形式主义,直接开始。

掌握考试思维:成为一个特别会考试的人

1、考试,最重要的是“输出”,需要主动回想知识点,把它们从脑袋里调取出来,针对问题给出答案。你要学会用考试的思维去学习。

2、你要去研究考试题,包括它的出题范围和出题思路,去分析考试时,题目要求你怎样回忆知识点、怎样运用知识点。然后,据此决定学习的时候,如何学,以及学什么。

3、在学习的过程中,做到即用即学和即学即用,才能对知识点有透彻的理解和记忆,并且在考试中,做到更为高效准确地调取,以及运用。

4、检索式练习”是最为有效的学习方式,它是指通过提问和主动回想的方式,去巩固知识点。你在回想知识点的时候,所付出的认知努力越大,学习和记忆的效果就越好。

阅读全文 »

Elasticsearch在EventHub项目中的实战应用

前言

Event Hub是一个高度可缩放、分布式、基于时间序列的事件中心,能够实时的处理流式事件并进行告警和提醒。

Event Hub作为Newegg事件信息中枢,产品化新蛋各产品资源及平台底层基础设施服务生命周期与运转中的重要事件信息,并构建完善的事件消费渠道与流程,支撑线上监控与运维。

Event Hub产品化提供的事件信息,由Newegg内部各产品模块与底层基础设施服务获取,经过聚合,判定和收敛再最终呈现。信息源来自各模块底层的系统日志与监控项,保障客户透传客户的信息准确性与价值。关于Event Hub更详细介绍,请查看Newegg的事件中心之Event Hub

为了实现事件的多维度查询,事件的追溯性,我们将事件存储在elasticsearch中。我们设计了两个index:event_hub_currentevent_hub_history

事件是具有时间序列特征的,我们会在event_hub_historyindex中写入每条事件信息,通过事件唯一ID,在event_hub_current中更新事件信息,随着时间的流逝,大多数情况我们关注的结果。如果你了解过实时计算,可以参照Stream和Table。一个是流式的,一个是结果。

阅读全文 »

Elasticsearch速览学习笔记

声明:本来是打算春节期间在官网学习,温故一下相关知识,。无意间发现铭毅天下Elasticsearch文章很全,对快速了解一些知识点,很有帮助。尤其是知识星球里的内容,奈何收费。别人辛勤劳动成果,当然无可厚非。我就借鉴了他的知识图谱,确定自己的学习点,再结合官网文档和他的公众号。引用的地方已经标注,特此声明。

如果没钱没时间,收藏我这边篇笔记就好。如果你舍得花钱,有充足的时间,推荐去购买一下他的知识星球。

基本知识点

分词必知

当字段类型为text的时候会进行分词,默认分词器是standard

两个地方会出现分词,一个是indexing,一个是search。文档索引的时候肯定会分词,search时候针对search查询语句内容分析。默认的话是两者保持一致。某些场景下可以在search中设置分词

分词器分为三个部分:Tokenizers (分词)、Token filters(修改分词例如小写,删除分词,增加分词)、Character filters(用在分词前去除字符)

Test分词器

1
2
3
4
5
POST _analyze
{
"analyzer":"standard",
"text": "The quick brown fox. 1"
}

排查当前index分词的结果

1
2
3
4
5
GET kibana_sample_data_logs/_analyze
{
"field": "my_text",
"text": "Is this déjà vu?"
}

配置一个分析器,去掉英文修饰词

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
PUT my-index-000001
{
"settings": {
"analysis": {
"analyzer": {
"std_english": {
"type": "standard",
"stopwords": "_english_"
}
}
}
},
"mappings": {
"properties": {
"my_text": {
"type": "text",
"analyzer": "standard",
"fields": {
"english": {
"type": "text",
"analyzer": "std_english"
}
}
}
}
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
POST my-index-000001/_analyze
{
"field": "my_text",
"text": "The old brown cow"
}
// [ the, old, brown, cow ]
POST my-index-000001/_analyze
{
"field": "my_text.english",
"text": "The old brown cow"
}
// [ old, brown, cow ]
阅读全文 »

春雷行动-前端技术之CSS必备知识

前言

这篇文章不是教程,也不是让读者能够学会和掌握CSS,而是我的学习笔记。文章的目的是让我实践,系统的了解一下一些必备知识,仅此而已。

如果你需要这方面的知识详细学习的话,推荐你看参考的链接。内容全部来源于此。

正文

五种经典布局

1.空间居中

1
2
3
4
.parent{
display: grid;
place-items: center;
}

核心代码是place-items属性,那个是它的简写形式place-items: <align-items> <justify-items>; 两者相同的话可以省略。

左上角 place-items: start;

右下角place-items: end;

2.并列式布局

并列式布局就是多个项目并列。容器设置成 Flex 布局,内容居中(justify-content)可换行(flex-wrap

1
2
3
4
5
.container{
display: flex;
justify-content: center;
flex-wrap: wrap;
}

项目上面只用一行flex

1
2
3
.col{
flex: 1 1 300px;
}

flex属性是flex-growflex-shrinkflex-basis这三个属性的简写形式 flex: <flex-grow> <flex-shrink> <flex-basis>;

  • flex-basis:项目的初始宽度。
  • flex-grow:指定如果有多余宽度,项目是否可以扩大。
  • flex-shrink:指定如果宽度不足,项目是否可以缩小。

flex: 0 1 300px; 表示项目初始宽度是300,宽度不够的话可以缩小,但是不可以扩大。flex: 1 1 300px;,表示项目始终会占满所有宽度。

阅读全文 »

Newegg的事件中心之Event Hub

万事皆事件

事件是信息的一种承载媒介,描述特定对象某一瞬间的非持续性变化,与唯一时刻和唯一对象关联。例如:某台计算机从运行状态变更为关机,程序运行开始和结束,办公大楼停电等。事件是对象在两个不同状态中的变更瞬间的记录。

对于事件,我们关注时间点,什么事件,什么状态。在企业中存在大量的事件,系统事件,监控事件,业务事件等,通过对事件的治理和挖掘,能够发现很多价值,解决切实的痛点。基于以上思考,我们构建了Event Hub。

Event Hub简介

Event Hub是一个高度可缩放、分布式、基于时间序列的事件中心,能够实时的处理流式事件并进行告警和提醒。

Event Hub作为Newegg事件信息中枢,产品化新蛋各产品资源及平台底层基础设施服务生命周期与运转中的重要事件信息,并构建完善的事件消费渠道与流程,支撑线上监控与运维。

Event Hub产品化提供的事件信息,由Newegg内部各产品模块与底层基础设施服务获取,经过聚合,判定和收敛再最终呈现。信息源来自各模块底层的系统日志与监控项,保障客户透传客户的信息准确性与价值。

目前应用场景

企业级监控/告警平台

在Event Hub之前公司监控存在一些问题:

  • 告警不可追溯
  • 告警不可指派
  • 状态可变更很弱
  • 监控信息可视化很弱
  • 没有更好的统计报表

为了解决以上问题,治理企业级监控问题,我们在Event Hub中基于现存的问题,构建了企业级监控平台。俗话说,先挑软柿子捏。

作为企业级监控平台,Event Hub 立足于能够助力发现、定位、解决问题,保障系统与服务整体的稳定与性能。引入事件作为监控的信息载体,能更准确与直接描述资源底层基础设施服务的运行状态,助力更高效发现、定位从而解决问题。致力于提交信息描述准确性,减少延迟,传递更多的信息,完善监控信息维度,使用通用事件引擎对告警类信息加工处理,尽而告警。

1611048694361

阅读全文 »

Java NIO扫盲篇

概述

对于java世界,想了解高性能网络编程。那么就必须了解NIO,和常用的网络编程框架,以及高性能的网络编程模式。这里面缺一不可,本篇只是管中窥豹,将自己学习的过程和笔记记录下来,希望给工作中很难接触这方面的同学带来一点点帮助!

Java NIO是什么?

NIO 是一种同步非阻塞的 I/O 模型,在 Java 1.4 中引入了 NIO 框架,对应 java.nio 包,提供了 ChannelSelectorBuffer 等抽象。

NIO 中的 N 可以理解为 Non-blocking,不单纯是 New。它支持面向缓冲的,基于通道的 I/O 操作方法。 NIO 提供了与传统 BIO 模型中的 SocketServerSocket 相对应的 SocketChannelServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞 I/O 来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。

NIO 的基本流程

通常来说 NIO 中的所有 IO 都是从 Channel(通道) 开始的。

  • 从通道进行数据读取 :创建一个缓冲区,然后请求通道读取数据。
  • 从通道进行数据写入 :创建一个缓冲区,填充数据,并要求通道写入数据。

NIO 核心组件

NIO 包含下面几个核心的组件:

  • Channel(通道)
  • Buffer(缓冲区)
  • Selector(选择器)

通道与流的不同之处在于通道是双向的。而流只是在一个方向上移动(一个流必须是 InputStream 或者 OutputStream 的子类), 而 通道 可以用于读、写或者同时用于读写。

如何使用?

内存映射文件 I/O

内存映射文件 I/O 是一种读和写文件数据的方法,它可以比常规的基于流或者基于通道的 I/O 快得多。

下面代码行将文件的前 1024 个字节映射到内存中,map() 方法返回一个 MappedByteBuffer,它是 ByteBuffer 的子类。因此,可以像使用其他任何 ByteBuffer 一样使用新映射的缓冲区,操作系统会在需要时负责执行映射。

1
MappedByteBuffer mbb = fc.map(FileChannel.MapMode.READ_WRITE, 0, 1024);

这里多说一句,在Kafka源码中索引就大量使用了内存映射文件。

文件NIO

读文件

读取文件涉及三个步骤:(1) 从 FileInputStream 获取 Channel,(2) 创建 Buffer,(3) 将数据从 Channel 读到 Buffer

第一步:获取通道

1
2
FileInputStream fis = new FileInputStream("C:\\demo.txt");
FileChannel fileChannel = fis.getChannel();

然后创建Buffer,这里选择的间接缓冲

1
2
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
//ByteBuffer buffer = ByteBuffer.allocateDirect( 1024 ); 直接缓存,速度更快,JVM层面尽肯能避免多次拷贝

最后将数据从 Channel 读到 Buffer

1
fileChannel.read(byteBuffer)

写文件

几乎和读文件一样。

首先从 FileOutputStream 获取一个通道

1
2
FileOutputStream fos = new FileOutputStream("C:\\demo.txt");
FileChannel channel = fos.getChannel();

下一步是创建一个缓冲区并在其中放入一些数据

1
2
3
4
5
6
ByteBuffer buffer = ByteBuffer.allocate( 1024 );
for (int i=0; i<byteBuffer.limit(); ++i) {
buffer.put( byteBuffer.get(i));
}

buffer.flip();

最后一步是写入缓冲区中:

1
channel.write(buffer);

套接字NIO

NIO 实现了 IO 多路复用中的 Reactor 模型

  • 一个线程(Thread)使用一个选择器 Selector 通过轮询的方式去监听多个通道 Channel 上的事件,从而让一个线程就可以处理多个事件。
  • 通过配置监听的通道 Channel 为非阻塞,那么当 Channel 上的 IO 事件还未到达时,就不会进入阻塞状态一直等待,而是继续轮询其它 Channel,找到 IO 事件已经到达的 Channel 执行。

创建选择器

1
Selector selector = Selector.open();

将通道注册到选择器上

1
2
3
ServerSocketChannel channel = ServerSocketChannel.open();
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_ACCEPT);

注册的具体事件,主要有以下几类:

  • SelectionKey.OP_CONNECT
  • SelectionKey.OP_ACCEPT
  • SelectionKey.OP_READ
  • SelectionKey.OP_WRITE

监听事件

1
int num = selector.select();

使用 select() 来监听到达的事件,它会一直阻塞直到有至少一个事件到达。

处理事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
while (true) {
int num = selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = keys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
// ...
} else if (key.isReadable()) {
// ...
}
keyIterator.remove();
}
}

高性能网络编程

Reactor模式

Reactor模式+任务池模式

多Reactor模式

参考

  1. Java NIO

  2. Scalable IO in Java

  3. 《Scalable IO in Java》笔记