涨姿势 – 不一样的服务端长连接方案 – 客户端代理

仔细再看一次腾讯云的小程序解决方案,发现一个新大陆。

传统的 LAMP 架构,PHP-CGI  这种方式是很难处理长连接的。要么写死循环的方式来握住请求,要么使用 swoole 这种,通过 C 拓展来支持。

而 NodeJS 由于官方 DEMO 就是支持跑一个 HTTP 服务,所以处理这些长连接会方便一些(大家好懂一些,我觉得 PHP-CLI 方式也是一样的)。

信道服务

建立连接过程

  1. 小程序请求业务服务器
  2. 业务服务器和信道服务建立连接
  3. 业务服务器告诉小程序你可以和信道服务建立 ws 了
  4. 小程序和信道服务建立 ws
  5. 信道服务请求业务小程序的 ws 建立完成

连接成功后的通信方式

  1. 小程序请求信道服务,信道服务转发请求给业务
  2. 业务请求信道服务,信道服务推送到客户端

我最开始看的时候,没注意信道服务是一个云服务,琢磨着腾讯云的 SDK 难道有什么新的黑魔法来实现 PHP 的长连接。

https://github.com/tencentyun/wafer-php-server-sdk/blob/master/lib/Tunnel/TunnelService.php

看里面的代码,各种 onConnect\onRequest,看着就很像长连接的 API,但他基于 CI 是怎么实现的长连接了?看 composer.json 里面没有用什么黑魔法,搜索代码里面没没看到任何死循环。

客户端代理

为什么信道服务的 icon 是一朵云?

原来腾讯云把这个信道服务抽象成了一个 PaaS 的云服务,这根本就是一个客户端代理。而开源出来的 PHP-SDK,里面没有任何长连接的实现方案。

  • 业务服务器 -> 小程序:业务服务器只需要请求信道服务即可,信道服务接收到业务的请求后,会将 HTTP Body 部分,转成 WS 的消息推送给小程序。
  • 小程序 -> 业务服务器:则正常通过 WS 发送消息给信道服务,信道服务转成 HTTP 请求转发到业务服务器。

对于一些使用 PHP 开发的历史业务,大规模的长连接改造是非常困难,但部署一个长连接转发服务却容易很多(比如用 NodeJS 来写一个)。

腾讯云的这个思路可以帮助各种业务快速支持包括 SSE 和 WS 这两种长连接方案。并且由于业务服务器本身是 HTTP 方式,可以很容易给低版本 IE 做轮训兼容。

最后感谢腾讯云开源了他们的 wafer 方案。

Linux Kernel 4.9 & BBR

Google 真是共享了个好东西,先来看看效果。

Kernel 4.9

Linode 自带的 Kernel 4.9 没有编译 BBR 模块进来,直接切换是不行的,得手动替换 Kernel。

虽然 Ubuntu 官网的 Kernel 还没升级到4.9,但是他们官方的 ppa 已经支持4.9了,可以手动下载一个回来安装。

http://kernel.ubuntu.com/~kernel-ppa/mainline/v4.9/

根据自己的32位或者64位环境,wget 个新的 linux-imag-4.9下来

安装好之后,去 linode 后台,把 [Boot Settings] 中的的 [Kernel] 改成 [GRUB 2] ,这样 Linode 的 vps 重启后,就会使用我们刚刚安装的内核了。

BBR

网上开启 BBR 的方式,都是 echo "net.ipv4.tcp_congestion_control=bbr" >> /etc/sysctl.conf  这种暴力又不美观的方式,我是不喜欢。

仔细看了下,发现一个 /etc/sysctl.d/ 的目录,里面还有一个 README

这是一个带权重的配置目录,新的 php-fpm 目录下面也是通过这种方式来维护模块配置的。

这里面补一个 60-bbr.conf ,把开启 BBR 的规则放在这个 60-bbr.conf 里面就 ok 了。

根据 README ,执行 service procps start 就能看到效果。

More

在 /etc/sysctl.d/目录下还无意发现一个 10-network-security.conf,里面默认开启了 tcp_syncookies 来防范常见的 SYN-flood 类型的 DDoS。

JavaScript Cookbook 2nd 之 Function

昨晚翻了一下,虽然都是一些旧知识,不过深入下去对照着其他资料一起看,还是能发现一些有意思的地方。

函数式编程

反正之前我是没搞懂函数式和命令式的区别,也很疑惑函数式编程中,如果出现分支怎么办,昨晚总算弄明白了。

传统的命令式编程,我们会这样写业务逻辑

而函数式编程,我们则可以这样写业务逻辑。

这里可能会有一个疑惑,互斥的 processA 和 processB 怎么进入了同一个处理流程,这样和需求就不符合了?

在这种情况下,我们还需要在 processA 和 processB 的内部,把退出条件补上。

调用栈

JS 在执行的时候,有一个函数调用栈,栈里面放着一个个的函数调用帧,这些帧保存着所属函数所需的所有变量信息。

函数调用会在内存形成一个“调用记录”,又称“调用帧”(call frame),保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用帧上方,还会形成一个B的调用帧。等到B运行结束,将结果返回到A,B的调用帧才会消失。如果函数B内部还调用函数C,那就还有一个C的调用帧,以此类推。所有的调用帧,就形成一个“调用栈”(call stack)。

浏览器拦截 window.open

我们发现有时候执行 window.open(),能正常打开新窗口或者新的标签页,而有时却又不行,会被浏览器拦截。

其原因是浏览器会根据当前调用栈,找到最初的caller,如果不是用户触发的,则拦截。

尾调用优化

由于函数调用的时候会生成新的调用帧,当递归调用的时候,调用栈中的调用帧增长会非常厉害,最终导致内存耗尽而触发 RangeError。

如果把函数调用放在函数块的最后一条语句,且不在使用外层函数的变量了,则外层函数所占用的调用帧已无存在意义。在进入内层函数的时候,可以直接用内层函数的调用帧替换掉外层函数的调用帧,从而大大减少内存占用。

其他

Partial Application 的模式,用来做 Library 和 SDK 都挺好的。一个可定制性高的底层接口,再通过类似 _.partial() 的方式,提供一个开箱即用的上层接口。就像 $.ajax()$.get() 一样。

_.defer()_.memoize() 可以用在有大运算量的业务场景。

preconnect & more

Resource Hints

preconnect 出现在 w3 组织 16 年制订 《Resource Hints》

《Resource Hints》是一套预加载机制的 w3 标准化产物,在没有标准化之前,我们常用诸如 XMLHttpRequest 等手段来预加载我们未来会使用到的资源。

《Resource Hints》文档通过 <link> 标签,定义了4个新的属性值。

PreConnect

文档一定定义了4个新属性值,今天由于某个案例,我们只讨论 preconnect。

The user agent should attempt to initiate a preconnect and perform the full connection handshake (DNS+TCP for HTTP, and DNS+TCP+TLS for HTTPS origins) whenever possible, but is allowed to elect to perform a partial handshake (DNS only for HTTP, and DNS or DNS+TCP for HTTPS origins), or skip it entirely, due to resource constraints or other reasons.

The optimal number of connections per origin is dependent on the negotiated protocol, users current connectivity profile, available device resources, global connection limits, and other context specific variables. As a result, the decision for how many connections should be opened is deferred to the user agent.

preconnect 用于客户端与目标资源服务器,在请求资源前,预先完成 DNS 查询 + TCP 握手(如果是 HTTPS,会把 TLS 握手也预先完成),当客户端需要请求目标资源的时候,下一个 TCP 首包就可以直接发送 HTTP 的有效载荷,省去握手耗时。

需要注意规范仅仅是一个建议行为,具体处理细节由浏览器根据当时环境决定。

Caniuse

qq20161206-02x

恩,Chrome、Firefox、Android 5.x 开始支持这个特性。 继续阅读“preconnect & more”

来聊聊 DOM 中的Node、Element、Text

Node

Node 是整个 DOM 的主要数据类型。

常见的 NodeType :

  • 1 – ELEMENT_NODE 表示 element 元素
  • 2 – ATTRIBUTE_NODE 表示属性
  • 3 – TEXT_NODE 表示元素或属性中的文本内容
  • 4 – CDATA_SECTION_NODE 表示文档中的 CDATA 区段(文本不会被解析器解析)
  • 8 – COMENT_NODE 表示注释
  • 9 – DOCUMENT_NODE 表示整个文档(DOM 树的根节点)
  • 11 – DOCUMENT_FRAGMENT_NODE 表示轻量级的 Document 对象

1所表示的ELEMENT_NODE 很常见,我们平时用的 div 等标签,其类型都是 ELEMENT_NODE。

3有一个很经典的案例,在旧版的 React 中,如果一段文本模板存在变量,你会发现最终输出的字符串,在可变部分是被套了一层 span 标签的。但新版的 React 不需要了,这是因为新版 React 把每一个可变的文本,单独用一个TEXT_NODE 来存放。这里果真记错了,React v15是改用 COMENT_NODE 来包裹连续文本中的可变文本。为什么要包裹而不直接保留一份 TextNode 的引用呢?React v15 CHANGELOG

11也有一个经典案例,Vue.js 的1.x 版本就是使用的 documentFragment 来做 virtualDOM。documentFragment 支持完整的 DOM 操作,但由于本身不在文档流中,频繁操作不会导致浏览器频繁执行 parseHTML。

Element

这个没什么好说的,平常用得最多的了。

我们平常习惯在 jQuery 选择器后面加索引,操作的就是元素节点。

Text

Text 节点表示 HTML 或者 XML 文档中的一系列纯文本。

Text 节点没有子节点,不可再分。

那怕是简单的 Element 节点,其文案内容,都是在 Text 节点上。

结语

富文本编辑器真是前端界里面的深坑,后续还有 Range 和 Selection 相关内容。

参考

又备案了

恩,N 年前我在又拍云那有800多 G 的流量,终于可以用完了。

公共 CDN 服务,回源策略真是赞,无脑使用就好。

有一个问题,你愿意把你的 SSL 证书的 key 交给第三方 CDN 去保管吗?

git cherry-pick

QQ20160707-1

有一个 hotfix分支,merge 到 master 后,忘了 merge 回 develop就被删掉了,咋办

这个时候可以祭出 git 的 cherry-pick 功能,将某个分支上面指定的几条 commit,提交到另外一条分支上

QQ20160707-2

恩,本来有用 git-flow 脚本的,但是遇到过几次命令执行失败后,还是老老实实自己去切分支 merge 了

ckeditor 从入门到放弃

真心复杂

有一个 CKEDITOR 的全局空间,

有一个 CKEDITOR.instances的全局实例引用

有 Classic 编辑和 Inline 编辑两种模式

有 Plugin 也有 Widget

有自成一体的编译打包工具,与 AMD\CMD\UMD社区不兼容

官方兼容性

  • Desktop environments:Internet Explorer:
    • 8.0 and 9.0 – close to full support,
    • 10 and 11 – full support,
    • 9.0 Quirks Mode and 9.0 Compatibility Mode – limited support.
    • Firefox, Chrome, Safari, Microsoft Edge, Opera (Latest stable release) – full support.
  • Mobile environments:
    • Safari (iOS 6+) – close to full support,
    • Chrome (Android) – close to full support,
    • Internet Explorer Mobile (Windows Phone 8.1+) – support under evaluation.

继续阅读“ckeditor 从入门到放弃”

通过ipv6绕开网页认证

在一个需要Web认证的WiFi网络下,无意中nettop发现有一条tcp6的链接是Established状态,搜一下发现大部分Web认证,都仅仅拦截ipv4的流量。

6.47.46

正常情况,如果没用通过Web认证,打开任意网页,都会被302重定向去登录页。

QQ20160504-0@2x

对比已经很明显了,基本上这个网络已经可以随意使用了。

新版SS同时监听ipv4和ipv6的配置改了,变成如下格式