LinkedIn 即时通信系统的优化
前言
LinkedIn 的即时通信系统目前单台机器可以处理数十万的持久连接,这是不断调优的结果。
最近,他们在官网博客中发布了优化过程,介绍了即时通信系统的技术选型、调优的重点。
基础技术构成
即时通信技术的基本要求就是server能够向client推送数据,需要通过持久连接实现,而不是传统的“请求-响应”模式。
对于这个需求,LinkedIn 选择了 Server-sent events (SSE)
来实现。
SSE 特点是简单、兼容性好,client只需要和server建立一个普通的HTTP连接,当server中有事件发送时,就会向client推送数据流。
配合 SSE 的 EventSource 接口被所有现代浏览器支持,iOS 与 Android 中也有现成的库,所以 SSE 的兼容性不成问题,这也是 LinkedIn 没有选择 Websockets 原因。
开发语言使用 JAVA,编程模型选用 Actor模型,Akka是一个优秀的Actor库。
开发框架使用了 Play,他可以很好的集成 EventSource 与 Akka。
优化过程
- socket最大连接数限制
LinkedIn 刚开始做性能测试时,发现并发连接始终无法超过128个,这肯定是不正常的,应用服务器处理上千并发连接是很轻松的,后来发现是一个系统内核参数的限制:
net.core.somaxconn
这个参数控制的是允许积压的TCP连接数量, 当一个连接请求过来时,如果数量达到上限了,就会被拒绝掉,128是很多系统的默认值。
可以在 /etc/sysctl.conf
中进行调整。
- 临时端口的限制
负载均衡器每次连接到一个server节点时,都会使用一个 临时端口,当连接终止时,这个端口会再次可用。
而持久连接不会像普通HTTP连接那样终止,所以,负载均衡器的临时端口就可能被耗尽。
这一点需要在选择负载均衡器时特别注意。
- 文件描述符的限制
在加大测试压力后,出现了一个异常:
java.net.SocketException: Too many files open
这说明文件描述符不够用了,在 Linux 中,一切皆文件,例如访问标准的文件、连接网络socket 等等,都需要文件描述符。
对于运行中进程的文件描述符限制,可以这样查看:
$ cat /proc/<pid>/limits
...
Max open files 30000
假设想调整到 200000,修改 /etc/security/limits.conf
:
<process username> soft nofile 200000
<process username> hard nofile 200000
系统级的文件描述符限制的调整是在 /etc/sysctl.conf
中:
fs.file-max
小结
这里整理的是几个通用的优化点,原文中有更详细的描述,还有两点对JVM的调优,有兴趣的朋友可以看下原文,地址:
https://engineering.linkedin.com/blog/2016/10/instant-messaging-at-linkedin--scaling-to-hundreds-of-thousands-
- 震惊了!这样的js面试题让所有人-男默女泪
- 前端知识学了却不会用,都是没走心
- var a="xx";a=a+"ss";a的值变了,但"xx"字符串并没有变
- 先行者计划--1109微课总结 | 《通过二个demo初识webPack》
- 先行者计划--1107微课 《什么是Vuex?》| 文字简版
- 脱离前端菜鸟层次的二个关键点
- 【课堂笔记】先行者 3.0版本的vueJs课程的第三次课
- ASP.NET:创建Linked ValidationSummary, 深入理解ASP.NET的Validation
- 【课堂笔记】先行者 3.0版本的vueJs课程的第二次课
- 用Python做证券指数的三种策略分析
- 明确告诉你,眼界不够,JS再好也成不了好前端
- 手把手教你整合最优雅的SSM框架
- WCF后续之旅(9):通过WCF的双向通信实现Session管理[上篇]
- 周末小贴士之“什么是语法糖”?有啥意义?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 蓝桥杯 试题 基础练习 阶乘计算
- Java Lamada
- 试题 基础练习 高精度加法
- C# devExpress GridControl 行中行 子行 多级行
- 蓝桥杯 试题 基础练习 Huffuman树
- 蓝桥杯 试题 基础练习 2n皇后问题(包含n皇后问题讲解)
- 蓝桥杯 试题 基础练习 报时助手
- 蓝桥杯 试题 基础练习 回形取数
- 了解RefreshScope这篇短文就够了
- Educational Codeforces Round 83 (Rated for Div. 2) A~~E
- Codeforces Round #627 (Div. 3) 题解
- 牛客练习赛59 A~~D
- Codeforces Round #628 (Div. 2) A~~D
- AtCoder Beginner Contest 160 A ~ E
- SwiftUI:创建底部导航栏 tabBar