iOS 开发中,如何实现高效的大量(如十万级)推送通知?
本問題的場境是,當App 的用戶上升到一定數量如十萬多,并且要作相對實時的廣播式推送通知時,有些同行説須要技巧實現,不然會被Apple 停止推送。而這様級别的推送,最快能在多短時間內完成所有推送?
17 条评论
分享
默认排序
按时间排序
5 个回答
提供一下我的数据,单机 8 线程推送到 57w 个 device token,用时 3 分钟,个人感觉可以接受。
服务端用的是 PyAPNs ( simonwhitaker/PyAPNs 路 GitHub),没有其他优化。如果提高线程数,性能应该还能继续提升。根据 Performance of Push Notification Service 这里的讨论,只要不超过 15 个并发连接就没有风险。
当然实际性能跟具体 payload 大小,以及服务器与 http://gateway.push.apple.com 之间的网速有关。
服务端用的是 PyAPNs ( simonwhitaker/PyAPNs 路 GitHub),没有其他优化。如果提高线程数,性能应该还能继续提升。根据 Performance of Push Notification Service 这里的讨论,只要不超过 15 个并发连接就没有风险。
当然实际性能跟具体 payload 大小,以及服务器与 http://gateway.push.apple.com 之间的网速有关。
很久之前的问题了,因为最近在做相关的系统,有些经验拿出来和大家分享下,欢迎大家提问交流。
知道大家对APNs的文档已经非常熟悉了,就不普及直接上点干货。
先说可能 遇到的问题:
直接连APNs做推送确实会有许多问题,目前我们遇到的有:
如果不加限速的话,IOS每秒峰值在8k左右,平均3k。安卓每秒可以到3w(个推)。相对来说,安卓可以通过客户端驻留内存来获得消息是否到达了手机,而ios则完全不能。ios能否收到推送完全看运气。
知道大家对APNs的文档已经非常熟悉了,就不普及直接上点干货。
先说可能 遇到的问题:
直接连APNs做推送确实会有许多问题,目前我们遇到的有:
- 未收到苹果的错误信息,直接关闭连接。
- 收到了错误信息,但连接在较长的时间(十几秒)内一直可用(不清楚之后的设备能否推送成功,现象上看是不成功)。
- 在推送结束后比较长的一段时间(一小时左右)一直收到错误信息,报告之前的某个dev_token出错。
- 当你在短时间内发送了大量的错误dev_token到APNs时,再连接,会经常被APNs关闭连接。(同题主提到的问题类似)
- 无法知道消息是否到达了用户手机。
- 问题1~3:使用发送缓存,尽量大的缓存,能把一次批量推送都缓存起来的缓存。设置缓存是为了当APNs返回错误信息时可以及时的重发受影响的消息。缓存尽量大,是因为APNs不一定什么时候会返回错误信息,可能2毫秒,也可能2秒,还有可能_(:зゝ∠)_……
- 问题4:使用反应堆模型的框架(netty,epoll之类的)去连接APNs,Why?你总不希望你的服务一直处在断线、重连循环往复的高负载状态吧。在瞬间推送许多token(错误率20%左右)到APNs的时候会出现大面积的断线和重连,即使使用了线程池,也会令系统忙于线程切换,实际的推送速度很难提高。使用netty等反应堆模型的框架可以很好的应付高并发情况下的系统负载飙升的情况。当然也不一定,外围代码写的好也可以解决这个问题,当然这个就看你们的技术水平了。
- 问题5:无法解决。
- 苹果消息的Notification identifier问题。苹果文档上关于消息的唯一标识只有4字节,当你发送的token不合法或者APNs遇到其他什么鬼问题时,苹果会把这个标识返回给你,让你知道哪个token有问题。所以必须要有identifier的清零机制,否则可能会导致标识重复,造成不可预期的后果。解决方案在下面。
- 基于上面的问题,我们决定用一个自增的int来表示Notification identifier,当APNs返回一个id时,我会将缓存中比这个id大的消息拿出来做重发。为了不影响正常的发送业务,这个步骤使用异步的方式完成,所以需要一个重发队列,每次做推送时,先从重发队列中拿消息,直到重发队列为空。重发队列也要有清空机制,因为在重发的过程中也有可能再次出错,触发重发,此时如果重发队列中还有消息,一定要清空。
- 基于坑1:使用netty的IdleStateHandler可以搞定,当连接空闲的时候将identifier清零。同时还可以清空发送缓存。
- 降速有助于提高到达率。当大批量推送到来的时候,即便有断线重发机制到达率也十分不理想,具体原因不明,猜想可能是因为GFW,可能是APNs的保护机制等等。总之就是一定要控制自身的S属性,尽量轻抚APNs的狗头。我做的一个双参数的限速,当推送累计到N条时,暂停M秒。
如果不加限速的话,IOS每秒峰值在8k左右,平均3k。安卓每秒可以到3w(个推)。相对来说,安卓可以通过客户端驻留内存来获得消息是否到达了手机,而ios则完全不能。ios能否收到推送完全看运气。
感谢楼上张斌的数据,楼主可以试下pyapns(
samuraisam/pyapns · GitHub)。
个人最终实现的结果,单线程,1分钟30万条推送,带宽在6M左右,当然这个和你推送的单条消息长度有关系,限制是256bytes。
走了一些弯路,如果想大规模推送的话,建议看下上面链接的the multi-applications model部分
个人最终实现的结果,单线程,1分钟30万条推送,带宽在6M左右,当然这个和你推送的单条消息长度有关系,限制是256bytes。
走了一些弯路,如果想大规模推送的话,建议看下上面链接的the multi-applications model部分