Scala Either, Left And Right

Scala中的Either是一个有趣的类,它代表两个可能的类型的其中一个类型的值。这两个值之间没有交集。
Either是抽象类,有两个具体的实现类: LeftRight
Either可以作为scala.Option的替换,可以用scala.util.Left替换scala.None,用scala.Right替换scala.Some
一般在时实践中使用scala.util.Left作为Failure,而scala.util.Right作为成功的值。
另一个类似的类是scala.util.Try

阅读全文

Socket分片:基于Netty的Java实现

最近Nginx发布了1.9.1版,其中一个新的特性就是支持socket的SO_REUSEPORT选项。这个socket的SO_REUSEPORT选项已经有许多现实世界的应用。对NGINX而言,它通过将连接均衡的分给多个进程以提升性能。SO_REUSEPORT已经在一些操作系统上实现了支持。这个选项允许多个socket监听同一个IP地址+端口。内核负载均衡这些进来的sockets连接,将这些socket有效的分片。
尽管Java很早就有一个特性请求:JDK-6432031,但是时至今日,Oracle JDK依然不支持这个选项,因此我们只能通过hack的方式在Java中使用此特性。

Google已经在内部服务器中开启了这个特性: SO_REUSEPORT
Scaling Techniques for Servers with High Connection Rates

阅读全文

akka actor的运行原理

最近在调研Scala web框架的性能时遇到一些问题, 比如生成巨多的Actor,GC时间过长,CPU使用率太高, 执行Actor的Receive是遇到耗时操作的问题等。怀疑Akka的调度器有些问题,特意整理了一些Akka调度器的背景知识,以及从源代码分析一下Actor是怎么执行地。

阅读全文

使用四种框架分别实现百万websocket常连接的服务器

事实上,最近我又增加了几个框架,现在包括 Netty, Undertow, Jetty, Spray, Vert.x, Grizzly 和 Node.js七种框架。
测试数据可以看下一篇文章: 七种WebSocket框架的性能比较

著名的 C10K 问题提出的时候, 正是 2001 年。这篇文章可以说是高性能服务器开发的一个标志性文档,它讨论的就是单机为1万个连接提供服务这个问题,当时因为硬件和软件的限制,单机1万还是一个非常值得挑战的目标。但是时光荏苒,随着硬件和软件的飞速发展,单机1万的目标已经变成了最简单不过的事情。现在用任何一种主流语言都能提供单机1万的并发处理的能力。所以现在目标早已提高了100倍,变成C1000k,也就是一台服务器为100万连接提供服务。在2010年,2011年已经看到一些实现C1000K的文章了,所以在2015年,实现C1000K应该不是一件困难的事情。

本文是我在实践过程中的记录,我的目标是使用spran-websocket,netty, undertow和node.js四种框架分别实现C1000K的服务器,看看这几个框架实现的难以程度,性能如何。开发语言为Scala和Javascript。

当然,谈起性能,我们还必须谈到每秒每个连接有多少个请求,也就是RPS数,还要考虑每条消息的大小。
一般来说,我们会选取一个百分比,比如每秒20%的连接会收发消息。我的需求是服务器只是push,客户端不会主动发送消息。 一般每一分钟会为这一百万群发一条消息。
所以实现的测试工具每个client建立60000个websocket连接,一共二十个client。实际不可能使用20台机器,我使用了两台AWS C3.2xlarge(8核16G)服务器作为客户端机。每台机器10个客户端。
服务器每1分钟群发一条消息。消息内容很简单,只是服务器的当天时间。

最近看到360用Go实现的消息推送系统,下面是他们的数据:

目前360消息推送系统服务于50+内部产品,万款开发平台App,实时长连接数亿量级,日独数十亿量级,1分钟内可以实现亿量级广播,日下发峰值百亿量级,400台物理机,3000多个实例分布在9个独立集群中,每个集群跨国内外近10个IDC。

四个服务器的代码和Client测试工具代码可以在github上下载。 (其实不止四种框架了,现在包括Netty, Undertow, Jetty, Spray-websocket, Vert.x, Grizzly 和 Node.js 七种框架的实现)

测试下来可以看到每种服务器都能轻松达到同时120万的websocket活动连接,只是资源占用和事务处理时间有差别。120万只是保守数据,在这么多连接情况下服务器依然很轻松,下一步我会进行C2000K的测试。

阅读全文

平均值,众数,中值和标准差

最近在使用Metrics测试服务器性能的时候,Histogram类型会统计下面的数据:

1
2
3
4
5
6
7
8
9
10
11
12
Message latency for eb810c24-8565-43ea-bc27-9a0b2c910ca4
count = 693831
min = 627
max = 735
mean = 633.06
stddev = 9.61
median = 631.00
75% <= 633.00
95% <= 640.00
98% <= 651.00
99% <= 670.00
99.9% <= 735.00

特地整理一下几个统计指标(平均值,众数,中值和标准差)的含义。

阅读全文

CQRS 和 Event sourcing

CQRS全称为Command Query Responsibility Segregation。 CQRS并不是一个完整的架构,而是一个小的模式。这个模式首先由Greg Young 和 Udi Dahan提出,Martin Flower有一篇文章专门介绍这个模式,微软也有一个专门教程介绍CQRS。
CQRS描述起来很简单,就是命令和查询职责分离。

阅读全文

Scala中的协变,逆变,上界,下界等

Scala中的协变逆变和Java中的协变逆变不一样,看起来更复杂。 本文对Scala中的这些概念做一总结。
首先看几个概念:

  • covariant 协变。使你能够使用比原始指定的类型的子类
  • Contravariance 逆变。使你能够使用比原始指定的类型的父类。
  • Invariance 不变。你只能使用原始指定的类型,不能协变和逆变
  • Upper bounds 上界。
  • Lower bounds 下界。

阅读全文

Kafka的一个配置参数

Kafka默认的消息大小为1000012,参数的名称为message.max.bytes.

1
2
3
kafka.server.KafkaConfig:
val messageMaxBytes = props.getIntInRange("message.max.bytes", 1000000 + MessageSet.LogOverhead, (0, Int.MaxValue))

但是对于topic来说,这个参数的名称却叫max.message.bytes,和前面的参数的名称很容易弄混。 Kafka应该将这两个参数统一成一个。
因此,如果你想对Boker统一设置的话,你需要在server.properties中设置:

1
message.max.bytes=1000000

如果针对单个的topic设置,你需要:

1
bin/kafka-topics.sh --zookeeper localhost:2181 --create --topic ABC --config max.message.bytes=1000000

另外,你还需要为Consumer设置fetch.message.max.bytes
为Boker设置replica.fetch.max.bytes (至少和message.max.bytes一样,最大Int.MaxValue)

stackoverflow针对这个问题有个问答
需要针对Boker和Consumer同时配置:

  • Boker
    1 replica.fetch.max.bytes
    2 message.max.bytes
  • Consumer
    3 fetch.message.max.bytes
    需要重启服务器。
    尤其第二项,如果没有配置,你不会得到任何的异常信息或者警告,很难发现此类问题。
    值设的太大也不好,因为会占用太大的内存用于数据传输(消费或者复制)