資深架構師談基於HTTP2推送消息到APNs

簡介java

介紹基於HTTP2實現消息推送蘋果APNs的設計思路和架構實現,並講解採用Netty4 構建 HTTP2 長鏈接客戶端,推送消息到蘋果APNs的技術實現。git

簡單介紹從 Http一、Http1.1 到 Http2 語義的發展變化,以及 APNs 的相關知識。github

正文chrome

#1 HTTP2瀏覽器

架構師談基於HTTP2推送消息到APNs

HTTP1.0最先在網頁中使用是在1996年,那個時候只是使用一些較爲簡單的網頁上和網絡請求上,而HTTP1.1則在1999年纔開始普遍應用於如今的各大瀏覽器網絡請求中,同時HTTP1.1也是當前使用最爲普遍的HTTP協議。性能優化

在 HTTP/1.0 的時候,client每請求一項資源,都必須先創建一次 TCP 連線,而在 client 收到 server 的 response後,便會斷開TCP連線。而在 HTTP/1.1 的時代,容許同域名下的資源 request and response 後,才斷開 TCP 連線。服務器

架構師談基於HTTP2推送消息到APNs

HTTP2 是 HTTP/1.1 後的一次重大的改進,在協議層面改善了以上問題,減小資源佔用,來,直接感覺一下差別:網絡

HTTP/2 is the future of the Web, and it is here!架構

這是 Akamai 公司創建的一個官方的演示,用以說明 HTTP/2 相比於以前的 HTTP/1.1 在性能上的大幅度提高。 同時請求 379 張圖片,從Load time 的對比能夠看出 HTTP/2 在速度上的優點。併發

架構師談基於HTTP2推送消息到APNs

HTTP/2 源自 SPDY/2。SPDY 系列協議由谷歌開發,於 2009 年公開。它的設計目標是下降 50% 的頁面加載時間。當下不少著名的互聯網公司都在本身的網站或 APP 中採用了 SPDY 系列協議(當前最新版本是 SPDY/3.1),由於它對性能的提高是顯而易見的。主流的瀏覽器(谷歌、火狐、Opera)也都早已經支持 SPDY,它已經成爲了工業標準,HTTP Working-Group 最終決定以 SPDY/2 爲基礎,開發 HTTP/2。HTTP/2 標準於2015年5月以 RFC 7540 正式發表。

HTTP/2 的5個特點:

Binary Framing Layer

HTTP/2 採用二進制格式傳輸數據,而非 HTTP/1.x 的文本格式。

架構師談基於HTTP2推送消息到APNs

在 HTTP/1.X 由 OSI model 中的 Application Layer,存在着 Binary Framing Layer,記錄着 HTTP 的內容像 HEADER 中的 method、content、message 等內容,以及 Data 部分。

架構師談基於HTTP2推送消息到APNs

Frame 的基本格式以下:

架構師談基於HTTP2推送消息到APNs

一個基礎的 Stream 由 HEADER frame 與 Data frame 組成。(共有10種 frame)

而每次的 connection 能夠乘載着任意數量的 stream。

架構師談基於HTTP2推送消息到APNs

能夠用 chrome 內部自帶的工具(chrome://net-internals/)查看 HTTP2 流量,但這個包信息量比較少,結構不如咱們熟悉的 Fiddler or Wireshark 清晰。

用 wireshark 抓包:

架構師談基於HTTP2推送消息到APNs

一個包內有多個不一樣的 Steam ID

架構師談基於HTTP2推送消息到APNs

Multiplexing

Multiplexing 容許單一的 tcp 有多重請求/迴應,也就是說 client 和 server 能夠將 http 請求/迴應分解成不藕合的 frame,而後隨機發送,最後在另外一端根據 stream ID 將 freame 組合起來。

架構師談基於HTTP2推送消息到APNs

Request Prioritization

在 HTTP/2 中,stream 有著 priority 的屬性,而藉由 Priorty frame,即可以創建起 priority tree。

架構師談基於HTTP2推送消息到APNs

Header Compression

在 client 和 server 個維護一個 HPACK,採用 hash 的方式來記錄 HEADER 的內容。也就是說當 client 要請求資源前會先去 HPACK 查找缺失的資源,接著請求缺乏的資源。

架構師談基於HTTP2推送消息到APNs

Server Push

在 Binary Framing Layer 提過,frame 共有10種。在這裡會利用 PUSH_PROMISE 的frame,它用於 server 主動發送資源給 client。

架構師談基於HTTP2推送消息到APNs

#2 APNs

APNs 是 Apple Push Notification service 的簡稱(注意 APNs 的大小寫, s不須要大寫)。

反人類的舊APNs協議設計

在介紹新版 APNs 前,讓咱們來吐槽下舊的基於二進制的 APNs 協議設計是多麼反人類:

在理論上,推送分發的服務器要打開一個同 APNs 網關服務器的鏈接,並保持這個鏈接。但在舊的協議下,APNs 服務卻不保證 socket 能維持這個鏈接。若是通道上沒有消息往來,空閒下來到話,socket將被路由掐斷。也就是說:APNs 鏈接說斷就斷,而你無能爲力。有意思的是:在舊的協議下,若是服務器響應成功的話,你將不會收到任何迴應,可是若是服務器響應失敗(例如,使用了一個非法的 Push token),服務器將返回了一個錯誤編碼,並關閉這個socket。最重要的是,你必須從新發送使用這個無效 token 之後發送的全部推送(詳情見示意圖)。所以,你可能一直不能肯定你的推送是否成功的被 APNs 服務器接收。

成功了不響應,失敗了才響應,這個是最大的反人類。因而許多開發者想到了一個很 tricky 的辦法:利用這個「漏洞」,好比在每發送10條後故意發送一個錯誤的token,若是APNs有響應了,就能夠確認 APNs 是處在可用狀態的,進而確認這10條消息是發送成功的。若是沒有響應就說明可能鏈接已經中斷,那麼這10條消息極可能是丟失的,而後作進一步的處理。但代價顯而易見:將致使大家的推送系統性能低下。蘋果有一個名爲"feedback"的服務,咱們能夠定時調用這個服務來獲取invalid tokens的列表。這個服務你只要調用一次就能夠得到全部的invalid tokens 列表。invalid token越多,大家的推送系統性能將越低。並且 APNs 只要一發生錯誤就關閉這個鏈接,而後從新鏈接。也就是「重啓」 socket 鏈接。

示意圖:

架構師談基於HTTP2推送消息到APNs

圖中的 PN2 去哪裏了?它被放到了 feedback 列表裏,等待下次你調用 feedback 服務,而後重發。

爲何Apple要在舊APNs中設計出「重啓」的策略?

爲了效率。

就像PC機出問題,咱們總說「重啓能解決90%的問題」。

那麼接下來就讓咱們看看Apple爲解決這些問題而推出的基於 HTTP/2 的全新 APNs 協議。

基於 HTTP/2 的全新 APNs 協議

來看下新版的 APNs 的新特性:

# Request 和 Response 支持JSON網絡協議

# APNs支持狀態碼和返回 error 信息

- APNs推送成功時 Response 將返回狀態碼200,遠程通知是否發送成功不再用靠猜了!

- APNs推送失敗時,Response 將返回 JSON 格式的 Error 信息。

# 最大推送長度提高到4096字節(4Kb)

# 能夠經過 "HTTP/2 PING" 心跳包功能檢測當前 APNs 鏈接是否可用,並能維持當前長鏈接。

# 支持爲不一樣的推送類型定義 「topic」 主題

#不一樣推送類型,只須要一種推送證書 Universal Push Notification Client SSL 證書。

示意圖:

架構師談基於HTTP2推送消息到APNs

其中最大的變化就是基於了 HTTP/2 協議,採用了長鏈接設計,並提供 「HTTP/2 PING」 心跳包功能檢測、維持當前 APNs 鏈接,解決了老 APNs 沒法維持鏈接的問題。並且新增的狀態碼特性,也解決了這個問題:沒法獲知消息是否成功地從大家的推送系統投遞到了 APNs 上。理論上,大家能夠保證消息是100%投遞到了APNs的,由於你能夠準確的知道哪條消息到達了APNs,哪些沒到。重發特定失敗消息成爲可能。

#3 APNs的開源項目

基於 Socket 的 APNs-PUSH

1. https://github.com/notnoop/java-apns

2. https://github.com/RamosLi/dbay-apns-for-java

基於 HTTP2 的 APNs-PUSH

1. https://github.com/CleverTap/apns-http2

A Java library for sending notifications via APNS using Apple's new HTTP/2 API. This library uses OkHttp. Previous versions included support for Jetty's client, however, we've removed that due to instability of the Jetty client.

Note: Ensure that you have Jetty's ALPN JAR (OkHttp requires it) in your boot classpath. See here for more information. This is required until Java 9 is released, as Java 8 does not have native support for HTTP/2.

2. https://github.com/linkedkeeper/apns-http2

A Java library for sending notifications via APNS using Apple's new HTTP/2 API. This library uses Netty4.

Note: This is required until Java 7 is released.

總結

從基於 Socket 的 notnoop 和 dbay 實現 APNs 推送,到基於 HTTP2 的 linkedkeeper 的 APNs 推送,不斷深刻了解 APNs 和 HTTP2 等,以及基於 Netty4 構建 APNs-HTTP2 客戶端,已在京東 POP 實現業務化運行,從性能和即時性都有明顯的提高。在此我向你們推薦一個架構學習交流羣。交流學習羣號: 744642380, 裏面會分享一些資深架構師錄製的視頻錄像:有Spring,MyBatis,Netty源碼分析,高併發、高性能、分佈式、微服務架構的原理,JVM性能優化、分佈式架構等這些成爲架構師必備的知識體系。還能領取免費的學習資源,目前受益良

相關文章
相關標籤/搜索