关于即时通讯:融云技术分享全面揭秘亿级IM消息的可靠投递机制

本文由融云技术团队原创分享,原题“IM 音讯同步机制全面解析”,为使文章更好了解,对内容进行了从新演绎和细节订正。 1、内容概述即时通讯(IM)零碎最根底、最重要的是音讯的及时性与准确性,及时体现在提早,精确则具体表现为不丢、不重、不乱序。 综合思考业务场景、零碎复杂度、网络流量、终端能耗等,咱们的亿级分布式IM音讯零碎精心设计了音讯收发机制,并一直打磨优化,造成了当初的音讯牢靠投递机制。 整体思路就是: 1)客户端、服务端独特配合,相互补充;2)采纳多重机制,从不同层面保障;3)拆分上下行,别离解决。 本文依据融云亿级IM音讯零碎的技术实际,总结了分布式IM音讯的牢靠投递机制,心愿能为你的IM开发和常识学习起到抛砖引玉的作用。 学习交换: 即时通讯/推送技术开发交换5群:215477170 [举荐]挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》开源IM框架源码:https://github.com/JackJiang2...(本文已同步公布于:http://www.52im.net/thread-36...) 2、举荐浏览以下是相干文章汇总,有趣味能够一并浏览: 《零根底IM开发入门(二):什么是IM零碎的实时性?》《零根底IM开发入门(三):什么是IM零碎的可靠性?》《零根底IM开发入门(四):什么是IM零碎的音讯时序一致性?》《IM音讯送达保障机制实现(一):保障在线实时音讯的牢靠投递》《IM音讯送达保障机制实现(二):保障离线音讯的牢靠投递》《IM开发干货分享:如何优雅的实现大量离线音讯的牢靠投递》《了解IM音讯“可靠性”和“一致性”问题,以及解决方案探讨》《如何保障IM实时音讯的“时序性”与“一致性”?》《IM群聊息如此简单,如何保障不丢不重?》《从客户端的角度来谈谈挪动端IM的音讯可靠性和送达机制》《一套亿级用户的IM架构技术干货(下篇):可靠性、有序性、弱网优化等》《从老手到专家:如何设计一套亿级音讯量的分布式IM零碎》《浅谈挪动端IM的多点登录和音讯漫游原理》《齐全自已开发的IM该如何设计“失败重试”机制?》《IM开发干货分享:我是如何解决大量离线音讯导致客户端卡顿的》以下是融云技术团队分享的其它文章: 《IM音讯ID技术专题(三):解密融云IM产品的聊天音讯ID生成策略》《融云技术分享:基于WebRTC的实时音视频首帧显示工夫优化实际》《融云技术分享:融云安卓端IM产品的网络链路保活技术实际》《即时通讯云融云CTO的守业教训分享:技术守业,你真的筹备好了?》3、客户端与服务端音讯交互整体原理3.1 概述一个残缺的IM音讯交互逻辑,通常会为两段: 1)音讯上行段:即由音讯发送者通过IM实时通道发送给服务端;2)音讯上行段:由服务端依照肯定的策略送达给最终的音讯接管人。3.2 音讯上行段音讯上行段次要就是依赖IM的实时通道将消息传递给服务端。 这个阶段的音讯牢靠投递,须要从协定层进行保障,协定层须要提供牢靠、有序的双向字节流传输,咱们是通过自研的通信协议 RMTP(即 RongCloud Message Transfer Protocol)实现的。 客户端与服务端之间应用长连贯,基于 RMTP 协定传输数据。 RMTP协定交互示意图: 如上图所示,协定层通过 QoS、 ACK 等机制,保障IM音讯上行段数据传输的可靠性。 3.3 音讯上行段通过总结,音讯上行段次要有三种行为。 1)客户端被动拉取音讯,被动拉取有两个触发形式: ① 拉取离线音讯:与 IM 服务新建设连贯胜利,用于获取不在线的这段时间未收到的音讯;② 定时拉取音讯:在客户端最初收到音讯后启动定时器,比方 3-5 分钟执行一次。次要有两个目标,一个是用于避免因网络、中间设备等不确定因素引起的告诉送达失败,服务端客户端状态不统一,一个是可通过本次申请,对业务层做状态机保活。2)服务端被动-发送音讯(直发消息): 这是在线音讯发送机制之一,简略了解为服务端将音讯内容间接发送给客户端,实用于音讯频率较低,并且继续交互,比方二人或者群内的失常交换探讨。 3)服务端被动-发送告诉(告诉拉取): 这是在线音讯发送机制之一,简略了解为服务端给客户端发送一个告诉,告诉蕴含工夫戳等可作为排序索引的内容,客户端收到告诉后,根据本身数据,比照告诉内工夫戳,发动拉取音讯的流程。 这种场景实用于较多消息传递:比方某人有很多大规模的群,每个群内都有很多成员正在强烈探讨。通过告诉拉取机制,能够无效的缩小客户端服务端网络交互次数,并且对多条音讯进行打包,晋升无效数据载荷。既能保障时效,又能保障性能。 客户端服务端上行段音讯交互示意图: 4、客户端与服务端音讯交互具体实现正如上节所言,咱们将音讯的交互流程进行了拆分:即拆分出上下行。 4.1 上行在上行过程保障发送音讯程序,为了保障音讯有序, 最好的形式是依照 userId 辨别,而后应用工夫戳排序。那么分布式部署状况下,将用户归属到固定的业务服务器上(PS:指的是同一账号的不同端固定连贯到雷同的业务服务器上),会使得上行排序变得更容易。同时归属到同一个服务器,在多端保护时也更容易。 客户端连贯过程: 1)客户端通过 APP server ,获取到连贯应用的 token;2)客户端应用 token 通过导航服务,获取具体连贯的 IM 接入服务器(CMP),导航服务通过 userId 计算接入服务器,而后下发,使得某一客户端能够连贯在同一台接入服务器(CMP)。示意图如下: 小结一下就是:客户端收回音讯后,通过接入服务,依照 userId 投递到指定音讯服务器,生成音讯 Id, 根据最初一条音讯工夫,确认更新以后音讯的工夫戳(如果存在雷同工夫戳则后延)。而后将工夫戳,以及音讯 Id,通过 Ack 返回给客户端 ; 而后对上行音讯应用 userId + 工夫戳进行缓存以及长久化存储,后续业务操作均应用此工夫戳。 ...

July 26, 2021 · 1 min · jiezi

关于即时通讯:开源移动端-IM-框架-MobileIMSDK-v60-发布

一、更新内容简介本次为次要版本更新(本次更新内容见文末“MobileIMSDK v6.0更新内容 ”一节),强势降级,将同时反对TCP、UDP、WebSocket三种协定,精心封装之下,实现同一套API、三种协定同时并存。 可能是市面上惟一同时反对UDP+TCP+WebSocket三种协定的同类开源IM框架。 二、MobileIMSDK简介MobileIMSDK 是一套专为挪动端开发的原创IM通信层框架: 历经8年、久经考验;超轻量级、高度提炼,lib包50KB以内;精心封装,一套API同时反对UDP、TCP、WebSocket三种协定(可能是全网惟一开源的);客户端反对 iOS、Android、规范Java、H5、小程序(开发中..)、Uniapp(开发中..);服务端基于Netty,性能卓越、易于扩大;可与姊妹工程 MobileIMSDK-Web 无缝互通实现网页端聊天或推送等;可利用于跨设施、跨网络的聊天APP、企业OA、音讯推送等各种场景。MobileIMSDK工程始于2013年10月,起初用作某产品的即时通讯底层实现,齐全从零开发,技术自主可控!您可能须要:查看对于MobileIMSDK的具体介绍。 三、代码托管同步更新OsChina.net: 代码托管: http://git.oschina.net/jackji...我的项目材料: 点击查看更多材料GitHub.com: 代码托管: https://github.com/JackJiang2...我的项目材料: 点击查看更多材料四、MobileIMSDK设计指标让开发者专一于应用逻辑的开发,底层简单的即时通讯算法交由SDK开发人员,从而解偶即时通讯利用开发的复杂性。 五、MobileIMSDK框架组成整套MobileIMSDK框架由以下5局部组成: Android客户端SDK:用于Android版即时通讯客户端,反对Android 2.3及以上,查看API文档;iOS客户端SDK:用于开发iOS版即时通讯客户端,反对iOS 8.0及以上,查看API文档;Java客户端SDK:用于开发跨平台的PC端即时通讯客户端,反对Java 1.6及以上,查看API文档;H5客户端SDK:材料整顿中,不日正式公布;服务端SDK:用于开发即时通讯服务端,反对Java 1.7及以上版本,查看API文档。六、MobileIMSDK v6.0更新内容【重要阐明】:MobileIMSDK v6 为全新版本,新增了对WebSocket协定的优雅反对、多端互踢反对等! 查看详情 【新增重要个性】: 服务端新增WebSocket协定反对,一套API优雅反对TCP、UDP、WebSocket 3种协定;反对多端互踢性能(可应答简单的挪动端网络变动逻辑对多端互踢算法的影响);【解决的Bug】: [Andriod]解决了断线后,fireDisconnectedToServer()办法中的一处空指针隐患;[iOS] 修复了TCP版代码中,调用[ClientCoreSDK releaseCore]办法会触发主动登陆逻辑的bug;[服务端] 解决了UDP协定下,重连状况下的被踢者已被服务端登记会话后,客户端才发回登陆响应ACK应答,导致服务端谬误地向未被踢者收回已登陆者反复登陆响应的问题;【其它优化和晋升】: [Andriod]废除了SDK、Demo代码中的所有AsyncTask的应用;[Andriod]将所有可应用Lambda表达式的代码全副用Lambda进行了简化。[iOS] 解决了XCode12上编译SDK的.a包,打包成瘦子.a时报“have the same architectures (arm64) and can't be in the same fat output file”的问题;[iOS] Demo中所有应用过期的UIAlertView改为UIAlertController实现;[iOS] 解决了iOS端SDK工程中两处因类名重构导致的在XCode12.5.1上编译出错。[服务端] 将服务端Demo中的Log4j日志框架降级为最新的Log4j2;[服务端] 服务端可管制是否为每条音讯生成发送工夫戳(可辅助用于客户端的音讯排序逻辑等)。七、相干链接MobileIMSDK 的具体介绍:点击查看MobileIMSDK 的下载地址:点击下载

July 22, 2021 · 1 min · jiezi

关于即时通讯:喜马拉雅亿级用户量的离线消息推送系统架构设计实践

本文由喜马拉雅技术团队李乾坤原创,原题《推送零碎实际》,感激作者的自私分享。 1、引言1.1 什么是离线音讯推送对于IM的开发者来说,离线音讯推送是再相熟不过的需要了,比方下图就是典型的IM离线音讯告诉成果。 1.2 Andriod端离线推送真心不易挪动端离线音讯推送波及的端无非就是两个——iOS端和Andriod端,iOS端没什么好说的,APNs是惟一选项。 Andriod端比拟奇葩(次要指国内的手机),为了实现离线推送,各种保活黑科技层出不穷,随着保活难度的一直降级,能够应用的保活伎俩也是越来越少,有趣味能够读一读我整顿的上面这些文章,感受一下(文章是按工夫程序,随着Andriod零碎保活难度的晋升,一直进阶的)。 《利用保活终极总结(一):Android6.0以下的双过程守护保活实际》《利用保活终极总结(二):Android6.0及以上的保活实际(过程防杀篇)》《利用保活终极总结(三):Android6.0及以上的保活实际(被杀复活篇)》《Android P正式版行将到来:后盾利用保活、音讯推送的真正噩梦》《全面盘点以后Android后盾保活计划的实在运行成果(截止2019年前)》《2020年了,Android后盾保活还有戏吗?看我如何优雅的实现!》《史上最强Android保活思路:深刻分析腾讯TIM的过程永生技术》《Android过程永生技术终极揭密:过程被杀底层原理、APP应答被杀技巧》《Android保活从入门到放弃:乖乖疏导用户加白名单吧(附7大机型加白示例)》下面这几篇只是我整顿的这方面的文章中的一部分,特地留神这最初一篇《Android保活从入门到放弃:乖乖疏导用户加白名单吧(附7大机型加白示例)》。是的,以后Andriod系统对APP自已保活的容忍度简直为0,所以那些曾今的保活伎俩在新版本零碎里,简直通通都生效了。 自已做保活曾经没戏了,保离线音讯推送总归是还得做。怎么办?依照现时的最佳实际,那就是对接种手机厂商的ROOM级推送通道。具体我就不在这里开展,有趣味的地能够详读《Android P正式版行将到来:后盾利用保活、音讯推送的真正噩梦》。 自已做保活、自建推送通道的时代(这里当然指的是Andriod端啦),离线音讯推送这种零碎的架构设计绝对简略,无非就是每台终端计算出一个deviceID,服务端通过自建通道进行音讯透传,就这么点事。 而在自建通道死翘翘,只能依赖厂商推送通道的现在,小米、华为、魅族、OPPO、vivo(这只是支流的几家)等等,手机型号太多,各家的推送API、设计规范各不相同(别跟我提什么对立推送联盟,那玩意儿我等他3年了——详见《万众瞩目的“对立推送联盟”上场了》),这也间接导致先前的离线音讯推送零碎架构设计必须从新设计,以适应新时代的推送技术要求。 1.3 怎么设计正当呢那么,针对不同厂商的ROOM级推送通道,咱们的后盾推送架构到底该怎么设计正当呢? 本文分享的离线音讯推送零碎设计并非专门针对IM产品,但无论业务层的差异有多少,大抵的技术思路上都是相通的,心愿借喜马拉雅的这篇分享能给正在设计大用户量的离线音讯推送的你带来些许启发。 举荐浏览:喜马拉雅技术团队分享的另一篇《长连贯网关技术专题(五):喜马拉雅自研亿级API网关技术实际》,有趣味也能够一并浏览。学习交换: 即时通讯/推送技术开发交换5群:215477170 [举荐] 挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》 开源IM框架源码:https://github.com/JackJiang2...(本文同步公布于:http://www.52im.net/thread-36...) 2、技术背景首先介绍下在喜马拉雅APP中推送零碎的作用,如下图就是一个新闻业务的推送/告诉。 离线推送次要就是在用户不关上APP的时候有一个伎俩触达用户,放弃APP的存在感,进步APP的日活。 咱们目前次要用推送的业务包含: 1)主播开播:公司有直播业务,主播在开直播的时候会给这个主播的所有粉丝发一个推送开播揭示2)专辑更新:平台上有十分多的专辑,专辑上面是一系列具体的声音,比方一本儿小说是一个专辑,小说有很多章节,那么当小说更新章节的时候给所有订阅这个专辑的用户发一个更新的揭示:3)个性化、新闻业务等。既然想给一个用户发离线推送,零碎就要跟这个用户设施之间有一个分割的通道。做过这个的都晓得:自建推送通道须要App常驻后盾(就是引言里提到的利用“保活”),而手机厂商因为省电等起因广泛采取“激进”的后盾过程管理策略,导致自建通道品质较差。目前通道个别是由“推送服务商”去保护,也就是说公司内的推送零碎并不间接给用户发推送(就是上节内容的这篇里提到的状况:《Android P正式版行将到来:后盾利用保活、音讯推送的真正噩梦》)。 这种状况下的离线推送流转流程如下: 国内的几大厂商(小米、华为、魅族、OPPO、vivo等)都有本人官网的推送通道,然而每一家接口都不一样,所以一些厂商比方小米、个推提供集成接口。发送时推送零碎发给集成商,而后集成商依据具体的设施,发给具体的厂商推送通道,最终发给用户。 给设施发推送的时候,必须说分明你要发的是什么内容:即title、message/body,还要指定给哪个设施发推送。 咱们以token来标识一个设施, 在不同的场景下token的含意是不一样的,公司外部个别用uid或者deviceId标识一个设施,对于集成商、不同的厂商也有本人对设施的惟一“编号”,所以公司外部的推送服务,要负责进行uid、deviceId到集成商token 的转换。 3、整体架构设计如上图所示,推送零碎整体上是一个基于队列的流式解决零碎。 上图右侧:是主链路,各个业务方通过推送接口给推送零碎发推送,推送接口会把数据发到一个队列,由转换和过滤服务生产。转换就是上文说的uid/deviceId到token的转换,过滤下文专门讲,转换过滤解决后发给发送模块,最终给到集成商接口。 App 启动时:会向服务端发送绑定申请,上报uid/deviceId与token的绑定关系。当卸载/重装App等导致token生效时,集成商通过http回调告知推送零碎。各个组件都会通过kafka 发送流水到公司的xstream 实时流解决集群,聚合数据并落盘到mysql,最终由grafana提供各种报表展现。 4、业务过滤机制设计各个业务方能够无脑给用户发推送,但推送零碎要有节制,因而要对业务音讯有抉择的过滤。 过滤机制的设计包含以下几点(按反对的先后顺序): 1)用户开关:App反对配置用户开关,若用户敞开了推送,则不向用户设施发推送;2)文案排重:一个用户不能收到反复的文案,用于避免上游业务方发送逻辑出错;3)频率管制:每一个业务对应一个msg_type,设定xx工夫内最多发xx条推送;4)静默工夫:每天xx点到xx点不给用户发推送,免得打搅用户劳动。5)分级管理:从用户和音讯两维度进行分级管制。针对第5点,具体来说就是: 1)每一个msg/msg_type有一个level,给重要/高level业务更多发送机会;2)当用户一天收到xx条推送时,不是重要的音讯就不再发给这些用户。5、分库分表下的多维查问问题很多时候,设计都是基于实践和教训,但实操时,总会遇到各种具体的问题。 喜马拉雅当初曾经有6亿+用户,对应的推送零碎的设施表(记录uid/deviceId到token的映射)也有相似的量级,所以对设施表进行了分库分表,以 deviceId 为分表列。 但实际上:常常有依据 uid/token 的查问需要,因而还须要建设以 uid/token 到 deviceId 的映射关系。因为uid 查问的场景也很频繁,因而uid副表也领有和主表同样的字段。 因为每天会进行一两次全局推,且针对缄默用户(即不常应用APP的用户)也有专门的推送,存储方面实际上不存在“热点”,尽管应用了缓存,但作用很无限,且占用空间微小。 多分表以及缓存导致数据存在三四个正本,不同逻辑应用不同正本,经常出现不统一问题(谋求统一则影响性能), 查问代码非常复杂且性能较低。 最终咱们抉择了将设施数据存储在tidb上,在性可能用的前提下,大大简化了代码。 6、非凡业务的时效性问题6.1 基本概念推送零碎是基于队列的,“先到先推”。大部分业务不要求很高的实时性,但直播业务要求半个小时送达,新闻业务更是“欲求不满”,越快越好。 若进行新闻推送时:队列中有巨量的“专辑更新”推送期待解决,则专辑更新业务会重大烦扰新闻业务的送达。 6.2 这是隔离问题?一开始咱们认为这是一个隔离问题:比方10个生产节点,3个专门负责高时效性业务、7个节点负责个别业务。过后队列用的是rabbitmq,为此革新了 spring-rabbit 反对依据msytype将音讯路由到特定节点。 该计划有以下毛病: 1)总有一些机器很忙的时候,另一些机器在“隔岸观火”;2)新增业务时,须要额定配置msgType到生产节点的映射关系,保护老本较高;3)rabbitmq基于内存实现,推送刹时顶峰时占用内存较大,进而引发rabbitmq 不稳固。6.3 其实是个优先级问题起初咱们觉察到这是一个优先级问题:高优先级业务/音讯能够插队,于是封装kafka反对优先级,比拟好的解决了隔离性计划带来的问题。具体实现是建设多个topic,一个topic代表一个优先级,封装kafka次要是封装生产端的逻辑(即结构一个PriorityConsumer)。 ...

July 12, 2021 · 1 min · jiezi

关于即时通讯:阿里技术分享闲鱼IM基于Flutter的移动端跨端改造实践

本文由阿里闲鱼技术团队祈晴分享,本次有订正和改变,感激作者的技术分享。 1、内容概述本文总结了阿里闲鱼技术团队应用Flutter在对闲鱼IM进行挪动端跨端革新过程中的技术实际等,文中比照了传统Native与当初大热的Flutter跨端计划在一些次要技术实现上的差别,以及针对Flutter技术特点的具体技术实现,值得同样筹备应用Flutter开发IM的技术同行们借鉴和参考。 学习交换: 即时通讯/推送技术开发交换5群:215477170 [举荐]挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》开源IM框架源码:https://github.com/JackJiang2...(本文同步公布于:http://www.52im.net/thread-36...) 2、闲鱼IM现状闲鱼IM的挪动端框架构建于2016至2017年间,期间通过屡次迭代降级导致历史包袱累积多,前面又经验IM界面的Flutter化,从而造成了客户端架构更加简单。 从开发层面总结闲鱼IM挪动端以后架构次要存在如下几个问题: 1)研发效率较低:以后架构波及到Android/iOS双端的逻辑代码以及Flutter的UI代码,定位问题往往只能从Flutter UI表相倒查到Native逻辑层;2)架构档次较差:架构设计上分层不清晰,业务逻辑夹杂在外围的逻辑层以致代码变更危险大;3)性能测试略差:外围数据源存储Native内存,需经Flutter Plugin将数据源序列化上抛Flutter侧,在大批量数据源状况下性能体现较差。从产品层面总结闲鱼IM挪动端以后架构的次要问题如下: 1)定位问题艰难:线上舆情反馈千奇百怪,测试始终无奈复现相干场景,因而很多时候只能靠景象猜想实质;2)疑难杂症较多:架构的不稳定性造成呈现的问题重复呈现,以后疑难杂症次要包含未读红点计数、iPhone5C低端机以及多媒体发送等多个问题;3)问题差异性大:Android和iOS两端逻辑代码差别大,包含埋点逻辑都不尽相同,排查问题本源时双端都会有不同根因,解决方案也不雷同。3、业界的挪动端跨端计划为解决以后IM的技术痛点,闲鱼往年特起对于IM架构降级我的项目,重在解决客户端中Andriod和iOS双端一致性的痛点,初步构想计划就是实现跨端对立的Android/iOS逻辑架构。 在以后行业内跨端计划可初步归类如下图架构: 在GUI层面的跨端计划有Weex、ReactNative、H5、Uni-APP等,其内存模型大多须要通过桥接到Native模式存储。 在逻辑层面的跨端计划大抵有C/C++等与虚拟机无关语言实现跨端,当然汇编语言也可行。 此外有两个独立于上述体系之外的架构就是Flutter和KMM(谷歌基于Kotlin实现相似Flutter架构),其中Flutter运行特定DartVM,将内存数据挂载其本身的isolate中。 思考闲鱼是Flutter的前沿探索者,计划上优先应用Flutter。然而Flutter的isolate更像一个过程的概念(底层实现非应用过程模式),相比Android,同一过程场景中,Android的Dalvik虚拟机多个线程运行共享一个内存Heap,而DartVM的Isolate运行隔离各自的Heap,因此isolate之间通信形式比拟繁琐(需通过序列化反序列化过程)。 整个模型如下图所示: 若按官网混合架构实现Flutter利用,开启多个FlutterAcitivty/FlutterController,底层会生成多个Engine,对应会存在多个isolate,而isolate通信相似于过程通信(相似socket或AIDL),这里借鉴闲鱼FlutterBoost的设计理念,FlutterIM架构将多个页面的Engine共享,则内存模型就人造反对共享读取。 原理图如下: 4、闲鱼IM基于Flutter的架构设计4.1 新老架构比照如下图所示:是一个老架构计划,其外围问题次要集中于Native逻辑形象差,其中逻辑层面还设计到多线程并发使得问题倍增,Android/iOS/Flutter交互繁冗,开发保护老本高,核心层耦合较为重大,无插拔式概念. 思考到历史架构的问题,演进如下新架构设计: 如上图所示,架构从上至下顺次为: 1)业务层;2)散发层;3)逻辑层;4)数据源层。数据源层来源于推送或网络申请,其封装于Native层,通过Flutter插件将音讯协定数据上抛到Flutter侧的外围逻辑层,解决实现后变成Flutter DB的Enitity实体,实体中挂载一些音讯协定实体。 外围逻辑层将繁冗数据扁平化打包挂载到散发层中的会话内存模型数据或音讯内存模型数据,最初通过观察者模式的订阅散发到业务逻辑中。 Flutter IM重点集中革新逻辑层和散发层,将IM外围逻辑和业务层面数据模型进行封装隔离,外围逻辑层和数据库交互后将数据封装到散发层的moduleData中,通过订阅形式散发到业务层数据模型中。 此外在IM模型中DB也是重点依赖的,集体对DB数据库治理进行全面封装解,实现一种轻量级,性能佳的Flutter DB治理框架。 4.2 DB存储模型Flutter IM架构的DB存储依赖数据库插件,目前支流插件是Sqflite。 其存储模型如下: 根据上图Sqflite插件的DB存储模型会有2个期待队列: 一个是Flutter层同步执行队列;一个是Native层的线程执行队列。其Android实现机制是HandlerThread,因而Query/Save读写在会同一线程队列中,导致响应速度慢,容易造成DB SQL沉积,此外缺失缓存模型。 于是集体定制如下改良计划: Flutter侧通过表的主键设计查问时候会优先从Entity Cache层去获取,若缓存不存在,则通过Sqflite插件查问。 同时革新Sqflite插件成反对sync/Async同步异步两种形式操作,对应到Native侧也会有同步线程队列和异步线程队列,保证数据吞吐率。然而这里倡议查问应用异步,存储应用同步更稳当,次要怕呈现多个雷同的数据元model同一时间进入异步线程池中,存储先后顺序无奈无效的保障。 4.3 ORM数据库计划IM架构重度依赖DB数据库,而以后业界还没有一个齐备的数据库ORM治理计划,参考了Android的OrmLite/GreenDao,集体自行设计一套Flutter ORM数据库治理计划。 其核心思想如下: 因为Flutter不反对反射,因而无奈间接像Android的开源数据库形式操作,但可通过APT形式,将Entity和Orm Entity绑定于一身,操作OrmEntity即操作Entity,整个代码格调设计也和OrmLite极其类似。 参考代码如下: 4.4 IM内存数据模型基于Flutter的IM挪动端架构在内存数据模型次要划分为会话和音讯两个颗粒度: 1)会话内存数据模型交托于SessionModuleData:会话内存数据有一个根节点RootNotice,而后其挂载PSessionMessageNotice(这里PSessionMessageNotice是ORM映射的会话DB表模型)子节点汇合。2)音讯内存数据模型交托于MessageModuleData:音讯内存数据会有一个MessageConatiner容器治理,其外部挂载此会话中的PMessage(PMessage是ORM映射的音讯DB表模型)音讯汇合。根据上一章节,PSessionMessageNotice设计了一个OrmEnitity Cache,思考到IM中会话数是无限的,因而PSessionMessageNotice都是间接缓存到Cache中。 这种做法的益处是各地去拿会话数据元时候都是缓存中同一个对象,容易保障多次重复读写的数据一致性。而PSessionMessageNotice思考到其数量能够有限多的特殊性,因而这里将其挂载到MessageContainer的内存治理中,在退出会话的时机会校验容器中PMessage汇合的数量,适当缩容能够缩小内存开销。 模型如下图所示: 4.5 状态治理计划基于Flutter的IM挪动端架构状态治理计划比较简单,对数据源Session/Message维度应用观察者模式的订阅散发形式实现,架构相似于EventBus模式,页面级的状态治理无论应用fish-redux、scopeModel或者provider简直影响面不大,外围还是需保留一种插拔式形象更重要。 架构如下图: 4.6 IM同步模型计划以后现状的音讯同步模型: 如上图所示是,模型中存在ACCS Thread/Main Thread/Region Thread等多线程并发场景,导致易呈现多线程高并发的问题。 native的推送和网络申请同步的隔离计划通过Lock的锁机制,并且通过队列降频等形式解决,流程繁琐且易出错。整体通过Region Version Gap去判断是否有域空洞,进而执行域同步补充数据。 改良的同步模型如下: 如上图所示,在Flutter侧人造没多线程场景,通过一种标记位的转化同步异步实现相似Handler音讯队列,架构清晰简洁了很多,防止锁带来的开销以及同步问题。 ...

July 5, 2021 · 1 min · jiezi

关于即时通讯:理解IM消息可靠性和一致性问题以及解决方案探讨

本文作者“商文默”,有订正和改变。 1、写在后面即时通讯网整顿的大量IM技术文章中(见本文末“参考资料”一节),无关音讯可靠性和一致性问题的文章占了很大比重,起因是IM这类零碎抛开各种目迷五色的产品性能和技术个性,保障音讯的可靠性和一致性简直是IM产品必须的素质。 试想如果一个IM连收回的音讯都不晓得对方到底能不能收到、收回的聊天内容对方看到的到底是不是“胡说八道”(重大乱序问题),这样的APP用户必定不会让他在手机上过夜(必定第一工夫卸载了),因为最根本的聊天逻辑都无奈实现,它曾经失去了IM软件自身的意义。 不过,另一个方面来讲,IM零碎是不规范的(尽管已经XMPP这种协定试图解决这个问题,但事实证明那基本不事实),各家简直都是自已的公有协定、不同的实现逻辑,这也决定了即便同一个技术问题,对于IM来说很难有固定的实现套路和规范的解决方案。 所以,对于本文来说,文中作者尽管提供了无关IM音讯“可靠性”与“一致性”问题的解决方案,但计划到底合不合理、适不适宜你,这就是仁者见仁、智者见智的事了。用人话说就是:本文内容仅供参考,具体的解决方案请务联合自已的零碎构架和实现状况,多浏览几篇即时通讯网上无关这个技术话题的文章,取其精华,找到适宜自已的技术计划和思路才是最理智的。 学习交换: 即时通讯/推送技术开发交换5群:215477170 [举荐]挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》开源IM框架源码:https://github.com/JackJiang2...(本文同步公布于:http://www.52im.net/thread-35... 2、本文引言丛所周之,即时通讯聊天(IM)零碎必须要解决音讯可靠性及音讯一致性问题(PS:如果具体IM零碎是什么你都还没弄明确,先读这篇《零根底IM开发入门(一):什么是IM零碎?》)。 这两个问题,艰深来说就是: 1)音讯可靠性:简略来说就是不丢音讯,会话一方发送音讯,音讯胜利达到对方并正确显示;2)音讯一致性:包含发送一方音讯统一及会话单方音讯统一,要求音讯不反复,不乱序。本文会从典型的IM音讯发送逻辑开始,简略易懂地说明音讯可靠性、一致性问题的原理及可参考的技术解决办法,或者技术计划并不完满,但心愿能为你的IM技术问题解决带来启发。3、典型IM音讯发送过程IM的音讯发送个别的实现过程能够分为两个阶段: 1)发送方发送音讯、服务端接管、返回音讯 ACK 给发送方;2)服务端将音讯推送到接管方。判断音讯发送是否胜利次要根据第一阶段——即服务器是否承受到音讯。 对于音讯发送者来说,音讯状态能够分为三类: 1)正在发送;2)发送胜利;3)发送失败。具体来说,这三类状态的具体意义是: 1)正在发送:发送方触发发送事件开始,到收到服务端返回音讯对应 ACK 之前;2)发送胜利:发送方收到音讯对应 ACK 回复;3)发送失败:超过肯定重发次数,未收到音讯对应 ACK 回复。对应的音讯发送流程如下图所示: 4、IM音讯可靠性限于篇幅,对于IM音讯可靠性的基本概念和具体原理倡议浏览《零根底IM开发入门(三):什么是IM零碎的可靠性?》,本文着重谈谈解决思路。 4.1 重发机制保障音讯发送第一阶段(见本文“3、典型IM音讯发送过程”一节)音讯胜利发送的办法是设立重发机制: 1)根据肯定时长内是否收到音讯对应 ACK,判断音讯是否要重发;2)如果超过预设时长,就从新发送;3)当重发次数超过预设次数,就不再重发,断定该音讯发送失败,批改音讯发送状态。PS:具体的残缺计划级代码实现,能够参考MobileIMSDK 中无关QoS机制的代码实现。 4.2 会话记录查看音讯发送第二阶段(见本文“3、典型IM音讯发送过程”一节)服务端推送音讯到接管方,如果连贯断开,会失落音讯。 所以要保障音讯残缺,就须要在建设连贯后,依据上一条音讯(曾经 ACK)工夫戳,获取会话记录,一次返回一段时间内所有音讯(PS:中大型利用中,音讯的拉取也不是个简略事件,详情能够浏览《IM开发干货分享:如何优雅的实现大量离线音讯的牢靠投递》)。 另一种保障办法是退出定时轮询,查看音讯完整性,具体的思路如下图所示。 建设连贯流程图: 4.3 须要思考的两个问题音讯重发、会话记录查看须要思考两个问题: 1)音讯是否会反复发送;2)音讯程序是否会被打乱。举两个例子。 对于音讯重发问题: 1)如果丢音讯的点在音讯达到服务端之前,服务端并没有收到音讯,发送方从新发送失落音讯,服务端接管胜利,不会产生两条雷同音讯;2)而如果服务端接管到音讯,返回 ACK 失落,这时再发送一次雷同音讯,就可能造成音讯反复。对于音讯程序问题: 1)如果发送方连发三条音讯,第一、第三条胜利被服务端接管,第二条丢了,那第三条音讯是否会被记录?2)如果这时第二条音讯达到服务端,其程序是在第三条工夫之前还是之后(服务端个别都会给记录打一个工夫戳)?5、IM音讯一致性同上节一样,对于IM音讯一致性的基本概念和具体原理倡议浏览《零根底IM开发入门(四):什么是IM零碎的音讯时序一致性?》。 5.1 应用 uuid 音讯去重对于音讯重发问题,能够给每条音讯减少属性 uuid 作为音讯惟一标识,重发消息 uuid 不变,前端依据 uuid 去重。大抵思路就是这样。 PS:对于IM来说,音讯ID也是个很大的技术话题,有趣味能够读上面这个系列: 《IM音讯ID技术专题(一):微信的海量IM聊天音讯序列号生成实际(算法原理篇)》《IM音讯ID技术专题(二):微信的海量IM聊天音讯序列号生成实际(容灾计划篇)》《IM音讯ID技术专题(三):解密融云IM产品的聊天音讯ID生成策略》《IM音讯ID技术专题(四):深度解密美团的分布式ID生成算法》《IM音讯ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现》《IM音讯ID技术专题(六):深度解密滴滴的高性能ID生成器(Tinyid)》5.2 应用向量时钟进行音讯排序对于音讯排序问题:因为在聊天中,音讯的程序对于发送方的表述有重要的影响,音讯不残缺或程序颠倒都可能造成语意不连贯,甚至误解。所以须要保障发送方发送音讯程序,而会话单方音讯排序须要思考理论状况。 在个别的认知里:状态是正在发送的音讯,应该还没有被对方看到,只有发送胜利的音讯,才会被对方看到。但在实现中,音讯发送胜利是以服务器接管音讯并返回 ACK 胜利为判断根据,而不是被对方接管到。 那么就会呈现这样一个问题:如果一条音讯状态是正在发送,此时收到一条音讯,那么收到的音讯是在正在发送的音讯之前还是之后? 这是一个上下文关系,关键问题是:发送方是以哪条所见音讯为根据发送音讯的。 这里提供一种思路:借鉴分布式系统中的向量时钟算法(见《分布式系统中的向量时钟算法》)。 先简略形容向量时钟算法: 向量时钟算法用于在分布式系统中生成事件偏序关系,并纠正因果关系。一个零碎蕴含 N 个节点,每个节点产生的音讯体中蕴含该节点的逻辑时钟,整体零碎的向量时钟由 N 维逻辑时钟组成,并在每个节点产生的音讯体中传递。简略来说,向量时钟算法的实现原理如下: ...

June 7, 2021 · 1 min · jiezi

关于即时通讯:网页端IM通信技术快速入门短轮询长轮询SSEWebSocket

本文来自“糊糊糊糊糊了”的分享,原题《实时音讯推送整顿》,有优化和改变。 1、写在后面对Web端即时通讯技术相熟的开发者来说,咱们回顾网页端IM的底层通信技术,从短轮询、长轮询,到起初的SSE以及WebSocket,应用门槛越来越低(晚期的长轮询Comet这类技术理论属于hack伎俩,应用门槛并不低),技术手段越来越先进,网页端即时通讯技术的体验也因而越来越好。 但上周在编辑《IM扫码登录技术专题》系列文章第3篇的时候突然想到,之前的这些所谓的网页端即时通讯“老技术”绝对于当红的WebSocket,并非毫无用武之地。就拿IM里的扫码登录性能来说,用短轮询技术就十分适合,齐全没必要大炮打蚊子上WebSocket。 所以,很多时候没必要自觉谋求新技术,绝对利用场景来说适宜的才是最好的。对于即时通讯网的im和音讯推送这类即时通讯技术开发者来说,把握WebSocket诚然很重要,但理解短轮询、长轮询等这些所谓的Web端即时通讯“老技术”依然大有裨益,这也正是整顿分享本文的重要起因。 学习交换: 即时通讯/推送技术开发交换5群:215477170 [举荐]挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》开源IM框架源码:https://github.com/JackJiang2...(本文同步公布于:http://www.52im.net/thread-35... 2、举荐浏览[1] 新手入门贴:史上最全Web端即时通讯技术原理详解[2] 详解Web端通信形式的演进:从Ajax、JSONP 到 SSE、Websocket[3] Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE 3、注释引言对于IM/音讯推送这类即时通讯零碎而言,零碎的要害就是“实时通信”能力。 从外表意思上来看,“实时通信”指的是: 1)客户端能随时被动发送数据给服务端;2)当客户端关注的内容在产生扭转时,服务器可能实时地告诉客户端。类比于传统的C/S申请模型,“实时通信”时客户端不须要主观地发送申请去获取本人关怀的内容,而是由服务器端进行“推送”。 留神:下面的“推送”二字打了引号,实际上现有的几种技术实现形式中,并不是服务器端真正被动地推送,而是通过肯定的伎俩营造了一种“实时通信”的假象。 就目前现有的几种技术而言,次要有以下几类: 1)客户端轮询:传统意义上的短轮询(Short Polling);2)服务器端轮询:长轮询(Long Polling);3)单向服务器推送:Server-Sent Events(SSE);4)全双工通信:WebSocket。以下注释将针对这几种技术计划,为你一一解惑。 4、本文配套Demo和代码为了帮忙读者更好的了解本文内容,笔者专门写了一个较完整的Demo,Demo会以一个繁难聊天室的例子来别离通过上述的四种技术形式实现(代码存在些许bug,次要是为了做演示用,别介意)。 残缺Demo源码打包下载: (请从同步链接附件中下载:http://www.52im.net/thread-35... Demo的运行成果(动图): 有趣味能够自行下载钻研学习。 5、了解短轮询(Short Polling)短轮询的实现原理: 1)客户端向服务器端发送一个申请,服务器返回数据,而后客户端依据服务器端返回的数据进行解决;2)客户端持续向服务器端发送申请,持续反复以上的步骤,如果不想给服务器端太大的压力,个别状况下会设置一个申请的工夫距离。逻辑如下图所示: 应用短轮询的长处:根底不须要额定的开发成本,申请数据,解析数据,作出响应,仅此而已,而后一直反复。 毛病也不言而喻: 1)一直的发送和敞开申请,对服务器的压力会比拟大,因为自身开启Http连贯就是一件比拟耗资源的事件;2)轮询的工夫距离不好管制。如果要求的实时性比拟高,显然应用短轮询会有显著的短板,如果设置interval的距离过长,会导致音讯提早,而如果太短,会对服务器产生压力。短轮询客户的代码实现(片段节选): var ShortPollingNotification = { datasInterval: null, subscribe: function() { this.datasInterval = setInterval(function() { Request.getDatas().then(function(res) { window.ChatroomDOM.renderData(res); });}, TIMEOUT);return this.unsubscribe;}, unsubscribe: function() { this.datasInterval && clearInterval(this.datasInterval);} } PS:残缺代码,请见本文“4、本文配套Demo和代码”一节。 对应本文配套Demo的运行成果如下(动图): 上面是对应的申请,留神左下角的申请数量始终在变动: 在上图中,每隔1s就会发送一个申请,看起来成果还不错,然而如果将timeout的值设置成5s,成果将大打折扣。如下图所示。 将timeout值设置成5s时的Demo运行成果(动图): 6、了解长轮询(Long Polling)6.1 基本原理长轮询的基本原理: 1)客户端发送一个申请,服务器会hold住这个申请;2)直到监听的内容有扭转,才会返回数据,断开连接(或者在肯定的工夫内,申请还得不到返回,就会因为超时主动断开连接);3)客户端持续发送申请,反复以上步骤。逻辑如下图所示: 长轮询是基于短轮询上的改良版本:次要是缩小了客户端发动Http连贯的开销,改成了在服务器端被动地去判断所关怀的内容是否变动。 所以其实轮询的实质并没有多大变动,变动的点在于: 1)对于内容变动的轮询由客户端改成了服务器端(客户端会在连贯中断之后,会再次发送申请,比照短轮询来说,大大减少了发动连贯的次数);2)客户端只会在数据扭转时去作相应的扭转,比照短轮询来说,并不是全盘接管。6.2 代码实现长轮询客户的代码实现(片段节选): ...

May 25, 2021 · 3 min · jiezi

关于即时通讯:长连接网关技术专题四爱奇艺WebSocket实时推送网关技术实践

本文由爱奇艺技术团队原创分享,原题《构建通用WebSocket推送网关的设计与实际》,有优化和改变。 1、引言丛所周之,HTTP协定是一种无状态、基于TCP的申请/响应模式的协定,即申请只能由客户端发动、由服务端进行响应。在大多数场景,这种申请/响应的Pull模式能够满足需要。但在某些情景:例如音讯推送(IM中最为常见,比方IM的离线音讯推送)、实时告诉等利用场景,须要实时将数据同步到客户端,这就要求服务端反对被动Push数据的能力。 传统的Web服务端推送技术历史悠久,经验了短轮询、长轮询等阶段的倒退(见《新手入门贴:史上最全Web端即时通讯技术原理详解》),肯定水平上可能解决问题,但也存在着有余,例如时效性、资源节约等。HTML5规范带来的WebSocket标准根本完结了这一场面,成为目前服务端音讯推送技术的支流计划。 在零碎中集成WebSocket非常简略,相干探讨与材料很丰盛。但如何实现一个通用的WebSocket推送网关尚未有成熟的计划。目前的云服务厂商次要关注iOS和安卓等挪动端推送,也短少对WebSocket的反对。本文分享了爱奇艺基于Netty实现WebSocket长连贯实时推送网关时的实际经验总结。 学习交换: 即时通讯/推送技术开发交换5群:215477170 [举荐]挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》开源IM框架源码:https://github.com/JackJiang2...(本文同步公布于:http://www.52im.net/thread-35... 2、专题目录本文是系列文章的第4篇,总目录如下: 《长连贯网关技术专题(一):京东京麦的生产级TCP网关技术实际总结》《长连贯网关技术专题(二):知乎千万级并发的高性能长连贯网关技术实际》《长连贯网关技术专题(三):手淘亿级挪动端接入层网关的技术演进之路》《长连贯网关技术专题(四):爱奇艺WebSocket实时推送网关技术实际》(* 本文)其它相干技术文章: 《相对干货:基于Netty实现海量接入的推送服务技术要点》《京东到家基于Netty的WebSocket利用实际分享》爱奇艺技术团队分享的其它文章: 《爱奇艺技术分享:轻松滑稽,解说视频编解码技术的过来、当初和未来》《爱奇艺技术分享:爱奇艺Android客户端启动速度优化实际总结》《爱奇艺挪动端网络优化实际分享:网络申请成功率优化篇》3、旧计划存在的技术痛点爱奇艺号是咱们内容生态的重要组成,作为前台零碎,对用户体验有较高要求,间接影响着创作者的创作激情。 目前,爱奇艺号多个业务场景中用到了WebSocket实时推送技术,包含: 1)用户评论:实时的将评论音讯推送到浏览器;2)实名认证:合同签订前须要对用户进行实名认证,用户扫描二维码后进入第三方的认证页面,认证实现后异步告诉浏览器认证的状态;3)活体辨认:相似实名认证,当活体辨认实现后,异步将后果告诉浏览器。在理论的业务开发中,咱们发现,WebSocket实时推送技术在应用中存在一些问题。这些问题是: 1)首先:WebSocket技术栈不对立,既有基于Netty实现的,也有基于Web容器实现的,给开发和保护带来艰难;2)其次:WebSocket实现扩散在在各个工程中,与业务零碎强耦合,如果有其余业务须要集成WebSocket,面临着反复开发的困境,节约老本、效率低下;3)第三:WebSocket是有状态协定的,客户端连贯服务器时只和集群中一个节点连贯,数据传输过程中也只与这一节点通信。WebSocket集群须要解决会话共享的问题。如果只采纳单节点部署,尽管能够防止这一问题,但无奈程度扩大撑持更高负载,有单点的危险;4)最初:不足监控与报警,尽管能够通过Linux的Socket连接数大抵评估WebSocket长连接数,但数字并不精确,也无奈得悉用户数等具备业务含意的指标数据;无奈与现有的微服务监控整合,实现对立监控和报警。PS:限于篇幅本文不具体介绍WebSocket技术自身,有趣味能够详读《WebSocket从入门到精通,半小时就够!》。4、新计划的技术指标如上节所示,为了解决旧计划中存在的问题,咱们须要实现对立的WebSocket长连贯实时推送网关。 这套新的网关须要具备如下特点: 1)集中实现长连贯治理和推送能力:对立技术栈,将长连贯作为根底能力积淀,便于性能迭代和降级保护;2)与业务解耦:将业务逻辑与长连贯通信拆散,使业务零碎不再关怀通信细节,也防止了反复开发,节约研发老本;3)应用简略:提供HTTP推送通道,不便各种开发语言的接入。业务零碎只须要简略的调用,就能够实现数据推送,晋升研发效率;4)分布式架构:实现多节点的集群,反对程度扩大应答业务增长带来的挑战;节点宕机不影响服务整体可用性,保障高牢靠;5)多端音讯同步:容许用户应用多个浏览器或标签页同时登陆在线,保障音讯同步发送;6)多维度监控与报警:自定义监控指标与现有微服务监控零碎买通,呈现问题时可及时报警,保障服务的稳定性。 5、新计划的技术选型在泛滥的WebSocket实现中,从性能、扩展性、社区反对等方面思考,最终抉择了Netty。Netty是一个高性能、事件驱动、异步非阻塞的网络通信框架,在许多出名的开源软件中被宽泛应用。 PS:如果你对Netty知之甚少,能够详读以下两篇: 《史上最艰深Netty入门长文:根本介绍、环境搭建、入手实战》《新手入门:目前为止最透彻的的Netty高性能原理和框架架构解析》WebSocket是有状态的,无奈像间接HTTP以集群形式实现负载平衡,长连贯建设后即与服务端某个节点放弃着会话,因而集群下想要得悉会话属于哪个节点有点艰难。解决以上问题个别有两种技术计划: 1)一种是应用相似微服务的注册核心来保护全局的会话映射关系;2)一种是应用事件播送由各节点自行判断是否持有会话,两种计划比照如下表所示。WebSocket集群计划:综合思考实现老本与集群规模,抉择了轻量级的事件播送计划。 实现播送能够抉择基于RocketMQ的音讯播送、基于Redis的Publish/Subscribe、基于ZooKeeper的告诉等计划,其优缺点比照如下表所示。从吞吐量、实时性、长久化、实现难易等方面思考,最终抉择了RocketMQ。 播送的实现计划比照: 6、新计划的实现思路6.1 零碎架构网关的整体架构如下图所示: 网关的整体流程如下: 1)客户端与网关任一节点握手建设起长连贯,节点将其退出到内存保护的长连贯队列。客户端定时向服务端发送心跳音讯,如果超过设定的工夫仍没有收到心跳,则认为客户端与服务端的长连贯已断开,服务端会敞开连贯,清理内存中的会话。 2)当业务零碎须要向客户端推送数据时,通过网关提供的HTTP接口将数据发向网关。 3)网关在接管到推送申请后,将音讯写入RocketMQ。 4)网关作为消费者,以播送模式生产音讯,所有节点都会接管到音讯。 5)节点接管到音讯后判断推送的音讯指标是否在本人内存中保护的长连贯队列里,如果存在则通过长连贯推送数据,否则间接疏忽。 网关以多节点形式形成集群,每节点负责一部分长连贯,可实现负载平衡,当面对海量连贯时,也能够通过减少节点的形式分担压力,实现程度扩大。 同时,当节点呈现宕机时,客户端会尝试从新与其余节点握手建设长连贯,保障服务整体的可用性。 6.2 会话治理WebSocket长连贯建设起来后,会话保护在各节点的内存中。SessionManager组件负责管理会话,外部应用了哈希表保护了UID与UserSession的关系。 UserSession代表用户维度的会话,一个用户可能会同时建设多个长连贯,因而UserSession外部同样应用了一个哈希表保护Channel与ChannelSession的关系。 为了防止用户无限度的创立长连贯,UserSession在外部的ChannelSession超过肯定数量后,会将最早建设的ChannelSession敞开,缩小服务器资源占用。SessionManager、UserSession、ChannelSession的关系如下图所示。 SessionManager组件: 6.3 监控与报警为了理解集群建设了多少长连贯、蕴含了多少用户,网关提供了根本的监控与报警能力。 网关接入了Micrometer,将连接数与用户数作为自定义指标裸露,供Prometheus进行采集,实现了与现有的微服务监控零碎买通。 在Grafana中不便地查看连接数、用户数、JVM、CPU、内存等指标数据,理解网关以后的服务能力与压力。报警规定也能够在Grafana中配置,当数据异样时触发奇信(外部报警平台)报警。 7、新计划的性能压测压测筹备: 1)压测抉择两台配置为4核16G的虚拟机,别离作为服务器和客户端;2)压测时抉择为网关凋谢了20个端口,同时建设20个客户端;3)每个客户端应用一个服务端端口建设起5万连贯,能够同时创立百万个连贯。连接数(百万级)与内存应用状况如下图所示: 给百万个长连贯同时发送一条音讯,采纳单线程发送,服务器发送实现的均匀耗时在10s左右,如下图所示。 服务器推送耗时: 个别同一用户同时建设的长连贯都在个位数。以10个长连贯为例,在并发数600、持续时间120s条件下压测,推送接口的TPS大概在1600+,如下图所示。 长连贯10、并发600、持续时间120s的压测数据: 以后的性能指标已满足咱们的理论业务场景,可反对将来的业务增长。 8、新计划的理论利用案例为了更活泼的阐明优化成果,文章最初,咱们也以封面图增加滤镜成果为例,介绍一个爱奇艺号应用新WebSocket网关计划的案例。 爱奇艺号自媒体发表视频时,可抉择为封面图增加滤镜成果,疏导用户提供提供更优质的封面。 当用户抉择一个封面图后,会提交异步的后盾解决工作。当异步工作解决实现后,通过WebSocket将不同滤镜成果解决后的图片返回给浏览器,业务场景如下图所示。 从研发效率方面思考,如果在业务零碎中集成WebSocket,至多须要1-2天的开发工夫。 如果间接应用新的WebSocket网关的推送能力,只须要简略的接口调用就实现了数据推送,开发工夫升高到分钟级别,研发效率大大提高。 从运维老本方面思考,业务零碎不再含有与业务逻辑无关的通信细节,代码的可维护性更强,零碎架构变得更加简略,运维老本大大降低。 9、写在最初WebSocket是目前实现服务端推送的支流技术,失当应用可能无效提供零碎响应能力,晋升用户体验。通过WebSocket长连贯网关能够疾速为零碎减少数据推送能力,无效缩小运维老本,进步开发效率。 长连贯网关的价值在于: 1)它封装了WebSocket通信细节,与业务零碎解耦,使得长连贯网关与业务零碎可独立优化迭代,防止反复开发,便于开发与保护;2)网关提供了简略易用的HTTP推送通道,反对多种开发语言接入,便于系统集成和应用;3)网关采纳了分布式架构,能够实现服务的程度扩容、负载平衡与高可用;4)网关集成了监控与报警,当零碎异样时能及时预警,保障服务的衰弱和稳固。目前,新的WebSocket长连贯实时网关已在爱奇艺号图片滤镜后果告诉、MCN电子签章等多个业务场景中失去利用。将来还有许多方面须要摸索,例如音讯的重发与ACK、WebSocket二进制数据的反对、多租户的反对等。 附录:更多相干技术材料[1] 无关WEB端即时通讯开发: 《新手入门贴:史上最全Web端即时通讯技术原理详解》 《Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE》 《SSE技术详解:一种全新的HTML5服务器推送事件技术》 《Comet技术详解:基于HTTP长连贯的Web端实时通信技术》 《老手疾速入门:WebSocket扼要教程》 《WebSocket详解(一):初步意识WebSocket技术》 《WebSocket详解(二):技术原理、代码演示和利用案例》 《WebSocket详解(三):深刻WebSocket通信协议细节》 ...

May 17, 2021 · 1 min · jiezi

关于即时通讯:直播系统聊天技术四百度直播的海量用户实时消息系统架构演进实践

本文原题“百度直播音讯服务架构实际”,由百度APP音讯中台团队原创分享于“百度Geek说”公众号,为了让文章内容更通俗易懂,本次已做排版优化和内容从新划分,原文链接在文末。 1、引言一套残缺的直播系统核心性能有两个: 1)实时音视频的推拉流;2)直播间音讯流的收发(包含聊天音讯、弹幕、指令等)。本文次要分享的是百度直播的音讯零碎的架构设计实际和演进过程。 实际上:直播间内用户的聊天互动,尽管模式上是常见的IM聊天音讯流,但直播音讯流不仅仅是用户聊天。 除用户聊天外:直播间内常见的用户送礼物、进场、点赞、去购买、主播举荐商品、申请连麦等互动行为的实时揭示,也是通过音讯流下发的。 此外:直播间敞开、直播流切换等非凡场景,也依赖音讯流的实时下发。 所以,直播零碎内的音讯流能够认为是直播间内主播与用户间实时互动和直播间实时控制的根底能力,也是零碎撑持。如果说实时音视频推拉流是直播零碎的灵魂,那音讯流能够说是直播零碎的骨架,它的重要性显而易见。 那么,如何构建直播的音讯零碎,又有哪些挑战须要解决,借着本文咱们一起来梳理一下。 学习交换: 即时通讯/推送技术开发交换5群:215477170 [举荐]挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》开源IM框架源码:https://github.com/JackJiang2...(本文同步公布于:http://www.52im.net/thread-35... 2、系列文章本文是系列文章中的第4篇: 《直播零碎聊天技术(一):百万在线的美拍直播弹幕零碎的实时推送技术实际之路》《直播零碎聊天技术(二):阿里电商IM音讯平台,在群聊、直播场景下的技术实际》《直播零碎聊天技术(三):微信直播聊天室单房间1500万在线的音讯架构演进之路》《直播零碎聊天技术(四):百度直播的海量用户实时音讯零碎架构演进实际》(* 本文)3、与一般IM群聊的区别直播间内的聊天音讯,常常被类比于一般的IM群聊性能。 群聊是大家比拟相熟的即时通讯(IM)场景,直播间内聊天和群聊,二者有相似性,但也有实质的区别。 比照二者的特点,直播音讯与IM群聊次要有以下区别: 1)参加人数不同:IM群聊的参加人数上千人就是很大的群了。但对于高热度的大型直播场景,例如国庆、阅兵、春晚等,单直播间累计用户是百万甚至千万量级的汇合,同时在线人数可达数百万人。 2)组织关系不同:IM用户进群退群,是绝对低频的操作,用户汇合绝对固定,用户进出的变更频度不会特地高。而用户进出直播间,是十分频繁的,高热度直播的单直播间每秒面临上万用户的进出变更。 3)持续时间不同:IM群聊建设后,聊天持续时间可能比拟长,几天到数月都有。而直播间大部分继续不超过几个小时。 4、核心技术挑战依据上节中,直播音讯和IM通聊的类比剖析,针对直播中的音讯零碎,咱们能够提炼出两个核心技术挑战。 挑战一:直播间内用户的保护 1)单直播间每秒上万用户的进出变更(理论进入直播间峰值不超过2万QPS,退出也不超过2万QPS);2)单直播间同时数百万用户在线;3)单直播间累计用户达千万量级。反对在线百万、累积千万两个汇合,每秒4万QPS更新,有肯定压力,但有反对高读写性能的存储应该能够解决,例如redis。 挑战二:百万在线用户的音讯下发 面对百万在线用户,上下行都有大量的音讯,从直播用户端视角剖析: 1)音讯的实时性:如果音讯服务端做简略消峰解决,峰值音讯的沉积,会造成整体音讯延时增大,且延时可能产生很大的累积效应,音讯与直播视频流在工夫线上产生很大的偏差,影响用户观看直播时互动的实时性;2)端体验和性能:端展现各类用户聊天和零碎音讯,个别一屏不超过10-20条。如果每秒有超过20条的音讯下发,端上展现的音讯根本会继续刷屏。再思考到有礼物音讯的特效等,大量的音讯,对端的解决和展现,带来继续高负荷。所以,对于一个长时间观看直播的用户端来说,如果呈现继续的大量音讯,端的音讯生产会有显著的性能压力,且过多音讯会有累积效应。因为技术挑战一不难解决,以下内容次要探讨技术挑战二。 5、技术设计指标综合思考上节的技术挑战和直播业务场景,咱们对于音讯零碎的需要指标有比拟显著的指标定义。 技术设计指标定义大抵如下: 1)实时性方面:端和端的音讯要达到秒级;2)性能方面:音讯服务能反对同一直播间内百万以上用户同时在线下发;3)峰值解决:对于峰值时的过多音讯,抛弃是正当适当的解决形式;4)基于正当的端用户体验,单直播间内每秒音讯数假如不超过N条。当初:问题的外围是,如何做到把不超过N条的音讯,在S秒内,下发到直播间内的百万用户(假如 N<=20,S<=2)。 6、从一般IM群聊的技术实现上找灵感6.1 一般IM群聊音讯收发剖析IM群聊数据流及压力点: 如上图所示,首先具体分析一下一般群聊的音讯收发流程: 1)对于群group-1,调配一个群公共音讯信箱group-mbox-1;2)群group-1内的用户user-1,由手机端APP-1上收回音讯msg-1;3)服务端接管到音讯msg-1,查看user-1是否有权限,如有权限,将msg-1存储到群信箱group-mbox-1,生成相应msgID-1;4)服务端查问group-1对应的用户列表groupUserList-1;5)基于groupUserList-1拆分出所有独立群用户:user-1、user-2 ... user-n;6)对于每一个用户user-i来说,须要查问用户user-i的所在设施device-i-1、device-i-2、device-i-m(因为一个账号可能登录多个设施);7)对于每个设施device-i-j来说,长连贯通道都会建设一个独立的长连贯connect-j以服务于该设施;但因为connect-j是由端上APP-1连贯到长连贯服务的,具备动态性,所以,查问device-i-j与connect-j的对应关系时,须要依赖一个路由服务route来实现查问;8)在查得connect-j后,能够通过connect-j下发msg-1的告诉groupmsg-notify-1;9)如果用户user-i正在应用device-i-j的手机端APP-1,用户user-i就能够立刻从长连贯connect-j上收到msg-1的告诉groupmsg-notify-1;10)在接管到groupmsg-notify-1后,手机端APP-1中的音讯SDK依据端本地历史音讯记录的最初一条音讯latestMsg对应的音讯ID即latestMsgID,来向服务端发动拉音讯申请fetchMsg,拉取group-1中从latestMsgID+1到最新的所有音讯;11)服务端收到拉音讯申请fetchMsg后,从group-mbox-1中取出latestMsgID+1到最新的所有音讯,返回给端;如果音讯过多,可能须要端分页拉取;12)端APP-1拉取到group-1中从latestMsgID+1到最新的所有音讯,能够做展现;在用户在会话中浏览后,须要设置所有新音讯的已读状态或者会话已读状态。6.2 一般IM群聊次要压力如果齐全重用一般群聊音讯的下发告诉到端拉取的全过程,对于user-1发的一条音讯msg-1,如果须要反对一个实时百万量级的群音讯,大略有以下几个每秒百万量级的挑战。 首先:秒级拆分出用户列表groupUserList-1,须要秒级读出百万的用户列表数据,对于存储和服务是第一个百万级挑战。 第二:对于拆分出群中的所有独立用户user-i,须要秒级查问出百万量级的device-i-j,对于存储和服务是第二个百万级挑战。 第三:对于所有device-i-j,通过动静路由服务route,须要秒级查问出百万量级的connect-j,对于存储和服务是第三个百万级挑战。 第四:对于通过长连贯connect-j下发时,须要反对秒级下发百万量级的群音讯告诉groupmsg-notify-1到对应的connect-j上,对于长连贯服务是个百万级的挑战。 第五:对于收到音讯告诉的所有端APP-1,须要反对百万QPS端从服务端拉取音讯申请fetchMsg,对于音讯信箱服务,这是也是一个百万量级的挑战;思考到理论各端latestMsgID可能不同,可能的优化形式会更简单一些,带来的性能影响会更大。 第六:如果在绝大多数用户是在线聊天的场景,设置已读状态也会有百万量级QPS对服务端的压力。 显然:齐全重用群聊的音讯流程,对音讯服务和长连贯服务带来的压力是微小的。 6.3 一般IM群聊优化计划IM群聊数据流优化后的压力点: 如上图所示,当初咱们来剖析以上每个百万量级的挑战,是否有优化的空间: 1)对于①拆分用户列表和②查问用户对应设施,如果存储上将二者合并集中起来,也就是优化直播间内用户列表的存储,扩大设施信息,能够缩小一次user->device的百万QPS查问,能够优化;2)对于④上行告诉和⑤端拉取fetchMsg的可靠消息拉取模式,思考到直播音讯容许局部折损抛弃,能够只做单向音讯下发,而不做拉取,对于大部分连贯放弃在线的用户,也是能够承受的。所以能够优化,只保留上行告诉(蕴含音讯体),而舍弃端拉取;3)对于⑥音讯设置已读,直播场景下能够思考简化舍弃。如上优化后,缩小了②⑤⑥三个百万量级压力申请,但还有①拆分用户列表③动静路由查问④长连贯下发,这三个百万量级步骤须要解决。 对于①拆分用户列表:反对百万量级用户列表查问,比拟惯例的思路是反对基于群groupID的批量查问,例如一次能够查出100个用户,1万QPS查问就能够反对到百万;基于群groupID把用户数据的存储,扩散到多个主从实例和分片上,管制好打散粒度不呈现热点,根本能做到,只是存储资源可能耗费较多。 对于③动静路由查问:外表上看,面临的问题与①相似,但却有些不同。因为群的用户列表,是基于群groupID做key,建设一个表或多个打散的表;而device-i-j的查问是齐全扩散的,也是须要批量查问能力,然而齐全扩散的设施信息查问,不能只针对特定key做优化,须要动静路由服务反对整体上达到百万QPS的查问性能。 对于④长连贯服务下发:因为长连贯服务不依赖内部的存储服务,如果整体要反对百万量级的下发能力,若长连贯单实例能反对1万的下发能力,整体上100个实例就能反对到百万量级下发。 基于以上剖析:反对百万量级的音讯下发,初见曙光。仿佛只有优化好用户列表、动静路由的存储/查问和长连贯的容量扩容,但所有的前提是须要耗费大量存储和机器资源。 思考到直播业务的理论状况,事实不容乐观: 1)一方面,平时没有热点直播时,可能单场直播并发在线用户数峰值不超过1万人,甚至不到1000;在业务初期,整体直播在线用户峰值可能也不超过10万。这就意味着,为了反对百万量级的峰值,资源整体上有几十倍的冗余;2)另一方面,如果忽然来了一场热度十分高的直播,可能须要反对的不只是100万量级音讯下发,可能是500万以上的量级(例如国庆阅兵、春晚等)。这样的话,每次大型直播得提前预估可能的在线用户峰值,如果超过以后设计容量,须要对①用户列表③动静路由查问④长连贯服务,别离扩容和压测;或者在可承受的状况下,做服务降级或拒绝服务。而实际上:在线用户峰值量级很难预计精确,这样会造成理论资源利用率很低,扩缩容的操作频繁,运维老本高。是否抉择这个计划,也是很令人纠结。 6.4 一般群聊多群组计划也有人提过拆分多个群组的计划。 例如:如果一个群组最多反对1万用户,开100个群就能够反对一百万用户;再建设一个虚构群,将这100个群关联起来,仿佛可行。 但如果仔细分析,会发现以上提到的几个问题:“①拆分用户列表、③动静路由查问、④长连贯下发”,高压力仍然存在,还是不可避免。 除此之外,多群组还会引入其余问题: 1)问题一:多群组音讯不同步。如果两个用户在一起看直播,而所属群不同,看到的音讯会齐全不同;2)问题二:直播场景用户是动静进出的,也就是说群组成员十分不稳固,在线用户峰值稳定也比拟大。如果是依据在线人数增长,动静新开群组,可能第一个群用户曾经很多了,第二个群刚开始用户比拟少;或者,在峰值期间开了比拟多的群,随着热度升高用户来到,用户变得扩散,一些群的用户可能较稀少,聊天互动较少,这时须要缩容合并群。如何均衡多个群的用户,达到好的业务成果,也是比拟难做的。基于以上剖析,咱们并没有抉择多群组计划。 7、基于组播mcast计划的音讯架构实际通过上节中类比一般IM群聊音讯的架构设计,本节将介绍咱们反对实时高并发百万量级同时在线用户的直播音讯架构——组播mcast计划的提出及演变。 7.1 跳出原有框架思考是否要采纳上节基于IM群聊的优化计划,还是能够另辟蹊径? 先临时抛开群收发音讯流程:对于音讯下发来说,如果肯定要说一个步骤是必不可少的,那肯定是长连贯下发这步了。没有通过长连贯下发,音讯就无奈最终达到用户。 当然有人说轮询拉取也能够代替长连贯下发,来获取音讯,但显然轮询拉取的性能压力和实时性与长连贯下发相比差很多,故不在探讨范畴。 如果能简化为:给长连贯服务下发音讯时指定一个相似的groupID,长连贯服务能间接拆分到所有群组用户相干的长连贯connect-j,就能够省略掉用户列表拆分和动静路由查问的百万量级查问。 这样的话:音讯下发的压力将次要由长连贯服务来接受,服务端也不须要对多个零碎扩容,直播音讯的优化可能会大为简化。 依据这个思路:相当于在长连贯服务中,对连贯connect也建设群组的概念。基于连贯组的构想,咱们设计了一套长连贯的组播mcast机制。 7.2 长连贯组播mcast基本概念基本概念总结如下: ...

April 27, 2021 · 1 min · jiezi

关于即时通讯:干货分享使用融云通讯能力库-IMLib-实现单群聊的阅读回执

明天的干货分享是对于“浏览回执”性能,这是一个很广泛的性能,然而针对应用融云的 SDK 去实现,还是有些坑在等着咱们的,上面就开始分(bì)享(kēng)喽~ 分享之前先做一些筹备工作,先找到咱们须要调用的接口文档 文档:https://docs.rongcloud.cn/v4-platform/views/im/noui/guide/platform-ios/message/receipt/private-p.html?match=imlib-ios官网:https://www.rongcloud.cn/依据不同的会话类型以及音讯的发送方和接管方,要别离解决 单聊 接管方 :在浏览音讯后,调用 RCIMClient 类的发送浏览回执接口,参数如下: conversationType 单聊会话类型 targetId 音讯的会话 ID time 会话最初一条音讯的发送工夫(sentTime) /*! 发送某个会话中音讯浏览的回执 @param conversationType    会话类型 @param targetId            会话 ID @param timestamp           该会话中已浏览的最初一条音讯的发送工夫戳 @param successBlock        发送胜利的回调 @param errorBlock          发送失败的回调[nErrorCode: 失败的错误码] @discussion 此接口只反对单聊, 如果应用 IMLib 能够注册监听 RCLibDispatchReadReceiptNotification 告诉,应用 IMKit 间接设置RCIM.h 中的 enabledReadReceiptConversationTypeList。 @warning 目前仅反对单聊。 @remarks 高级性能 */ ...

March 17, 2021 · 2 min · jiezi

关于即时通讯:自定义融云会话列表-cell-选中背景

我的项目用的融云,IMKit SDK(自带 UI),然而在应用会话列表的时候,cell 选中和长按的时候默认是灰色的。设计说须要改啊,那就钻研一下如何批改吧。废话不多说,间接继承 RCConversationListViewController,而后重写以下办法 1.以下代码是去掉选中色彩的 (void)willDisplayConversationTableCell:(RCConversationBaseCell )cell atIndexPath:(NSIndexPath )indexPath {cell.selectionStyle = UITableViewCellSelectionStyleNone;} 2.以下代码是重写色彩的,想配啥色请随便 (void)willDisplayConversationTableCell:(RCConversationBaseCell )cell atIndexPath:(NSIndexPath )indexPath {UIView *backView = [[UIView alloc] init];backView.backgroundColor = [UIColor redColor];cell.selectedBackgroundView = backView;} SDK 凋谢进去的 .h 类对办法正文写的很具体,倡议大家多看一下,这样能够疾速集成,少走弯路。也是造就集成第三方库的好习惯。融云(www.rongcloud.cn)

March 17, 2021 · 1 min · jiezi

关于即时通讯:集成融云-IMLib-时如何实现一套类似于-IMKit-的用户信息管理机制

背景咱们在设计聊天类 APP 都会有一套残缺的用户信息存储机制,用来保留咱们的通讯录列表,以及每个用户的头像、昵称、姓名、等等一系列的用户信息,避免咱们过多的进行服务器申请,对用户体验很差。这篇文章就简略的给大家创立一套用户信息机制来提供一个简略的思路。场景如下: 目前咱们集成了融云的 IMLib SDK , 融云 IMLib SDK 仅提供了音讯数据的存储与查问。用户信息和 UI 界面须要咱们本人来保护,而融云的 IMKit 尽管提供了用户信息的治理,然而局部 UI 还是和咱们产品设计不符的,那么如何设计一套相似于 IMKit 的用户信息管理机制,就是咱们面临的问题。 融云SDK: https://docs.rongcloud.cn/v4/ 思考咱们在实现这套机制的时候都须要哪些内容? 首先咱们要进行存储,存储那就须要保护一个数据库。参考融云 IMKit 发现有上面一个配置/*! 是否将用户信息和群组信息在本地长久化存储,默认值为NO @discussion 如果设置为NO,则SDK在须要显示用户信息时,会调用用户信息提供者获取用户信息并缓存到Cache,此Cache在App生命周期完结时会被移除,下次启动时会再次通过用户信息提供者获取信息。 如果设置为YES,则会将获取到的用户信息长久化存储在本地,App下次启动时Cache会依然无效。 */@property (nonatomic, assign) BOOL enablePersistentUserInfoCache; 通过测试以及融云业余技术人员的答复,发现这个配置起到的作用就是本次的用户信息是否会进行数据库存储。 这里的数据库存储是指当此配置失效时,会在本地进行数据库文件的创立。而不失效的时候,是不创立的。如果不创立的话还须要存储的话,那应该就是存储到内存了。 而咱们是须要每次登陆都有一些用户信息的,那不须要应用内存了,须要咱们进行数据库存储,所以咱们须要筹备一个 db 的治理类,解决所有的数据库操作。须要一个整体治理用户信息的入口 manager ,用来整顿一些根本信息。以及提供用户信息管理的代理入口。须要存储哪些用户信息以及筹备对用的 model 类。筹备每种对象的缓存类。实现以 融云 SDK 为例,以一个用户的 userinfo 为例大体来绘制一下整个流程图。 首先整顿一些各个类的用途,大体内容如下:UserInfoDBHelper: 数据库治理 import <Foundation/Foundation.h>import "UserInfo.h"NS_ASSUME_NONNULL_BEGIN@interface UserInfoDBHelper : NSObject (void)createDB;(UserInfo )getUserInfo:(NSString )userId;(void)refreshUserInfo:(UserInfo *)userInfo;@endNS_ASSUME_NONNULL_END UserInfo: 用户信息模型 import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGIN@interface UserInfo : NSObject/** id name url */@endNS_ASSUME_NONNULL_END ...

March 16, 2021 · 1 min · jiezi

关于即时通讯:如何设置融云用户信息

最近在应用融云,因为第一次应用,遇到了一个小坑,在这里记录一下,心愿能帮忙到后续开发者 问题是应用了融云的 IMKit 组件,也就是自带 UI 的,对于疾速试错的产品来说,工期必须短,所以应用 IMKit 是十分不便的,省去了很大部分工夫去搞界面。然而应用过程中发现,没有用户的头像和昵称。起初通过浏览文档发现,须要设置“用户信息提供者”代理办法。SDK 在须要显示头像和昵称的时候,会通过这个代理找开发者索取用户信息,开发者只有遵循代理,且实现代理办法,返回用户信息即可。 上代码: 1.遵循代理 @interface AppDelegate () <RCIMUserInfoDataSource>@end 2.设置代理 (BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary )launchOptions {//必须先初始化[[RCIM sharedRCIM] initWithAppKey:"开发者本人的 appkey"];[[RCIM sharedRCIM] connectWithToken:"以后用户的 token" dbOpened:^(RCDBErrorCode code) {} success:^(NSString *userId) { } error:^(RCConnectErrorCode errorCode) { }];//设置以后用户信息RCUserInfo *currentUser = [[RCUserInfo alloc] initWithUserId:@"tiezhu" name:@"铁柱" portrait:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1573646812313&di=116350f184eda99d91393304fa83a6ea&imgtype=0&src=http%3A%2F%2Fimg.jinse.com%2F712431_image3.png"];[RCIM sharedRCIM].currentUserInfo = currentUser;//设置代理[RCIM sharedRCIM].userInfoDataSource = self; } 3.实现代理办法 (void)getUserInfoWithUserId:(NSString )userId completion:(void (^)(RCUserInfo userInfo))completion {//这里最好是从开发者本人服务器获取用户信息,而后返回。此处仅为示例RCUserInfo *user = nil;if ([userId isEqualToString:@"tiezhu"]) {user = [[RCUserInfo alloc] initWithUserId:@"tiezhu" name:@"铁柱" portrait:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1570172426&di=01d14daa81f320235376d9c4dede0493&imgtype=jpg&er=1&src=http%3A%2F%2Fgss0.baidu.com%2F-vo3dSag_xI4khGko9WTAnF6hhy%2Fzhidao%2Fpic%2Fitem%2Fd788d43f8794a4c240e9466f0ef41bd5ac6e39af.jpg"];}if (completion) {completion(user);}} ...

March 16, 2021 · 1 min · jiezi

关于即时通讯:融云聊天页面长按消息后翻译功能的实现方法

我的项目要求实现“翻译”的性能,融云 SDK 自身没这个性能,所以只能曲线救国了,通过自定义音讯来实现,上面是性能实现相干内容。 资源链接:官网:https://www.rongcloud.cn/ 自定义音讯文档:https://docs.rongcloud.cn/v4/views/im/ui/guide/private/conversation/msgsend/ios.html#createcustom 实现思路创立自定义 cell,与 SDK 内置的文本音讯进行绑定。因为他们内置的文本音讯 cell 不反对扩大显示翻译的内容,所以须要应用自定义 cell。在聊天页面将自定义 cell 与内置的文本音讯进行绑定。重写长按音讯 cell 的办法,判断如果是文本音讯,减少“翻译”按钮。点击“翻译”按钮,对文本内容进行翻译,并将翻译好的内容设置到数据源中。刷新 UI,会触发自定义 cell 中的回调办法,在回调办法中从新设置高度,并增加 UI,对数据源中翻译好的内容进行展现。代码局部创立自定义 cell 继承于 RCTextMessageCell,m 文件中代码如下,具体成果可自行调整 import "RCDTextMessageCell.h" define RCDScreenWidth [UIScreen mainScreen].bounds.size.widthdefine Font_Size 16define Extra_BackgroupView_CornerRadius 6.f@interface RCDTextMessageCell ()//翻译内容的 Label@property (strong, nonatomic) UILabel *extraLabel;//翻译内容的背景图@property (strong, nonatomic) UIView *extraBackgroundView;@end@implementation RCDTextMessageCell (CGSize)sizeForMessageModel:(RCMessageModel *)modelwithCollectionViewWidth:(CGFloat)collectionViewWidthreferenceExtraHeight:(CGFloat)extraHeight {//翻译好的内容NSString *extra = model.extra;CGSize superSize = [super sizeForMessageModel:model withCollectionViewWidth:collectionViewWidth referenceExtraHeight:extraHeight];if (extra.length > 0) {CGSize extraSize = [RCDTextMessageCell getTextLabelSize:extra];CGFloat finalHeight = superSize.height + extraSize.height;return CGSizeMake(superSize.width, finalHeight);}else {return superSize;} ...

March 16, 2021 · 2 min · jiezi

关于即时通讯:30-分钟集成融云-IM-即时通讯

最近公司要做一个社交 app,对于工夫就是金钱的当今社会,招聘大量人才去搭建通信零碎必定是不划算的,破费人力物力财力做进去的 app,可能还没人用。那就瞎了。所以毋庸置疑,一拍即合,用第三方的。就开始了对于目前市面上支流的第三方 IM SDK 进行调研。其中有腾讯云,网易云信,融云,环信等。列出了一堆比照条件,最初领导拍板用哪个。末端程序员是没有选择权的。好好搬砖就能够了~要明确本人的身份,嘎嘎 过程不说了,最初抉择了用融云,废话不多说,间接勒~这里只介绍一下如何疾速集成,让俩人聊起来,这也算是一个里程碑啊。对于程序员来说,聊不起来可就毁了,领导都特么奶凶奶凶的~~~ 1.先到融云官网 (https://www.rongcloud.cn/) 进行注册(注册按钮本人找吧),这个能够让你们产品经理或者啥领导去做,能够用公司的邮箱,别用本人的吧,前期本人换了地儿,对公司也是损失不是。注册后增加利用,拿到 appkey 2.xcode 创立一个新工程,或者找本人公司的我的项目,这里我举荐应用 pod 形式治理第三方,方便快捷,省时省力。因为手动形式太落后了,且配置繁琐,稍有脱漏就会报错,有些报错排查起来费时费力费神费电,所以还是老老实实的用 pod 吧。不听老人言,吃亏在眼前,听哥的没错,融云文档写了如何用 pod,几行命令的事。弄完后,也就是把 SDK 集成好了,跑一下工程,如果不报错,恭喜你兄嘚,马上能够聊天了,看下一步 3.须要在 appDelegate 中导入头文件。#import <RongIMKit/RongIMKit.h>。对了,咱们用的是带界面的 SDK,疾速集成不麻烦。 4.初始化 SDK (BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary )launchOptions {//下边引号内须要替换为你的 appkey,别特么一成不变的抄哈,嘎嘎[[RCIM sharedRCIM] initWithAppKey:@"融云开发者后盾的 AppKey"];return YES;} 5.这一步该连贯融云了兄嘚 (BOOL)application:(UIApplication )application didFinishLaunchingWithOptions:(NSDictionary )launchOptions {[[RCIM sharedRCIM] initWithAppKey:@"获取到的 AppKey"];[[RCIM sharedRCIM] connectWithToken:@"开发者的 server 通过申请 server api 获取到的 token 值"dbOpened:^(RCDBErrorCode code) {}success:^(NSString *userId) {}error:^(RCConnectErrorCode status) {}]; return YES; } 敲黑板1:在这我得多说你几句,必须要看胜利回调和失败回调的调用,进了 success 就是胜利了,进了 error 就是谬误了。谬误了你要看 status 状态码啊,依据错误码来找问题。我在调试过程中就遇到了 RC_CONN_TOKEN_INCORRECT 错误码,顾名思义:token 不正确。这个就要找本人的服务端人员看是哪里问题导致的 token 不正确了。 ...

March 16, 2021 · 1 min · jiezi

关于即时通讯:融云的聊天页面在-iOS14-出现崩溃的解决办法

降级 Xcode12 后,模拟器都是 iOS14 了,运行本人的我的项目,到了聊天页面就解体,具体解体信息为Thread 1: "-[_UIPageControlIndicatorContentView setImage:]: unrecognized selector sent to instance。 从解体看,猜想是因为短少了某个办法导致了解体,提了个工单给融云,他们的技术支持服务还是挺到位的,很快给了回答,他们对这个问题曾经做了及时处理(其实他们曾经发了站内信和邮件,本人没留神????),更新了官网下载和 pod 上的 SDK,卸载现有 SDK,从新下载 2.10.4 以上版本 SDK 就能够了。 并且这个解体只针对应用 imkit的,应用 imlib 的用户没事儿,上面是他们在工单外面回复的具体内容: 通过 Xcode 12 打包 App,在 iOS 14 版本中我司发现 2.x 、4.0.0 、4.0.0.1 版本的 IMKit SDK 与 iOS 14 呈现了兼容问题,该问题会引起 App 解体,针对该问题进行了紧急的修复您能够在如下版本取得批改后的 SDK 版本:1、iOS IMKit SDK 版本为 4.0.0 和 4.0.0.1 的客户务必降级至 4.0.1+ 版本。2、iOS IMKit SDK 版本为 2.x 客户务必降级至 2.10.6-DEV 或者 2.10.4-Stable( 9 月 18 日公布的版本),这两个版本已针对该问题进行了修复(1)请务必于 2020 年 9 月 18 日当前从新下载获取 SDK,更新您的 App,下载地址:https://www.rongcloud.cn/down...(2)应用 Pod 集成的客户,请参考文档先清理 Pod 缓存,文档地址:https://docs.rongcloud.cn/v4/...3、基于 iOS IMLib SDK 集成的客户不受影响。 ...

March 16, 2021 · 1 min · jiezi

关于即时通讯:使用融云-SDK-避坑指南之-iOS13-推送失败

融云 SDK 反对苹果推送,当我应用的设施降级到 iOS13 及以上时,推送忽然就不能用了????,通过半天的排查,终于找到了问题,原来是 deviceToken 格局变了,具体能够参考 https://blog.csdn.net/yingBi2014/article/details/103457160 问题起因:因为 iOS13当前,苹果的 deviceToken 格局变了,然而上传给融云的 deviceToken 解决形式还是应用的老形式,导致了推送无奈收到。 解决办法: 降级融云的 SDK,他们提供了新的接口,须要降级到 2.9.25 当前的版本,能够适配新格局的 deviceToken,且坚硬老版本。 (void)application:(UIApplication *)applicationdidRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {[[RCIMClient sharedRCIMClient] setDeviceTokenData:deviceToken];} 如果不想降级 SDK,那就得独自解决一下 (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { NSString *token = [self getHexStringForData:deviceToken]; [[RCIMClient sharedRCIMClient] setDeviceToken:token];} (NSString )getHexStringForData:(NSData )data {NSUInteger len = [data length];char chars = (char )[data bytes];NSMutableString *hexString = [[NSMutableString alloc] init];for (NSUInteger i = 0; i < len; i ++) {[hexString appendString:[NSString stringWithFormat:@"%0.2hhx", chars[i]]];}return hexString;} ...

March 16, 2021 · 1 min · jiezi

关于即时通讯:融云即时通讯SDK集成-通知检查

背景:最近公司新上的app要加上即时通讯的性能, 本人疾速实现一个当然是不可能的了(我的项目deadline也顶不住哇).就从各家成熟的SDK厂商选来选去的, 各有各的好也各有各的有余.最初点兵点将,选了融云家的SDK(老板说了算hhhh). 他家的官网和文档地址: 官网:https://www.rongcloud.cn/ 文档:https://docs.rongcloud.cn/v4 这个工作当然还是落在我的头上. 集成结束后, 也踩了不少坑. 所以这篇文章给大家总结下排查融云音讯的本地告诉和远端推送的方法. 心愿能够帮忙到正在看这篇文章的你. 什么是本地告诉:当我的App接入了融云的即时通讯sdk后, 便领有了即时通讯的能力. sdk与融云服务器建设长连贯, 当音讯收回后, 先走到融云的服务器, 再转发给相应的用户. 这里挪动端到服务端, 服务端到挪动端, 走的通道都是长连贯. 无论你的app是在前台还是在后盾, 只有没有被杀死, 那么长连贯是始终在的. 所以音讯能够即时的发送达到给接收者. 融云把这种走长连贯达到的音讯, 在告诉栏展现的告诉叫做本地告诉. 也就是音讯是顺利发送到接收者端了, 逻辑能够走到音讯接管监听那里. 融云sdk外部实现了音讯达到后的本地告诉, 也赋予了开发者自行实现音讯达到后进行本地告诉的权力. 本地告诉的查看:这里我总结了一下接入融云sdk后, 对于本地告诉接管不顺利的排查. 大抵能够分为这么几条: 1.是否设置了 setOnReceiveMessageListener 监听, 并且 onReceived 办法返回的为 true。 RongIM.setOnReceiveMessageListener(new RongIMClient.OnReceiveMessageListener() { @Override public boolean onReceived(Message message, return true; } }); 如果 onReceived 办法返回值为 true 则是监听做了拦挡, 则不会走告诉逻辑。 2.发送的音讯是否是自定义音讯。 如果是自定义音讯, 则请查看自定义音讯的 MessageTag 的注解是否设置了 flag 的值为 MessageTag.ISCOUNTED 或 MessageTag.ISPERSISTED) 。 以上面为例。 ...

March 16, 2021 · 1 min · jiezi

关于即时通讯:融云即时通讯SDK集成-定制UI二-添加自定义表情库

背景:最近公司新上的app要加上即时通讯的性能, 本人疾速实现一个当然是不可能的了(我的项目deadline也顶不住哇).就从各家成熟的SDK厂商选来选去的, 各有各的好也各有各的有余.最初点兵点将,选了融云家的SDK(老板说了算hhhh). 他家的官网和文档地址: 官网:https://www.rongcloud.cn/ 文档:https://docs.rongcloud.cn/v4 这个工作当然还是落在我的头上. 我是应用的他们家的带UI的sdk,(他们家有带UI和不带UI的两种sdk, 不带UI的sdk就是只有即时通讯能力, 所有的UI都须要开发者自定实现, 带UI的sdk封装了一些根本的界面,例如会话列表, 和他人聊天的会话界面.)当然这些曾经集成了UI的sdk并不能齐全满足一个产品的需要, 所以这篇文章跟大家讲下如何增加一套自定义的表情包. 成果如下哈: 尽管这里有点难看了哈哈, 不过是为了给大家展现办法嘛, 就不论那么多了. 能够看到底下除了默认的emoji的表情包, 还多了一个tab, 我是从QQ表情搞了一套, 间接就加在这里了. 一个可恶的小猪猪????哈哈哈. 增加步骤须要改变的有这么几个类: AndroidEmoji: 管制emoji图标资源, 编码, 以及相应展现的类 RongExtension: 会话界面除去聊天气泡与title bar的整个下方输出区域 IEmoticonTab: 表情tab DefaultExtensionModule: 表情tab的下层控件. 对于AndroidEmoji这个类, 能够间接照抄, 把资源文件替换成本人筹备好的图标, 以及编码/形容 public class ConversationListAdapter extends BaseAdapter<UIConversation> { private final static String TAG = "ConversationListAdapter"; LayoutInflater mInflater; Context mContext; @Override public long getItemId(int position) { UIConversation conversation = getItem(position); if (conversation == null) return 0; return conversation.hashCode(); } protected class ViewHolder { public View layout; public View leftImageLayout; public View rightImageLayout; public View leftUnReadView; public View rightUnReadView; public AsyncImageView leftImageView; public TextView unReadMsgCount; public ImageView unReadMsgCountIcon; public AsyncImageView rightImageView; public TextView unReadMsgCountRight; public ImageView unReadMsgCountRightIcon; public ProviderContainerView contentView; } public ConversationListAdapter(Context context) { super(); mContext = context; mInflater = LayoutInflater.from(mContext); } public int findGatheredItem(Conversation.ConversationType type) { int index = getCount(); int position = -1; while ((index-- > 0)) { UIConversation uiConversation = getItem(index); if (uiConversation.getConversationType().equals(type)) { position = index; break; } } return position; } public int findPosition(Conversation.ConversationType type, String targetId) { int index = getCount(); int position = -1; while (index-- > 0) { if (getItem(index).getConversationType().equals(type) && getItem(index).getConversationTargetId().equals(targetId)) { position = index; break; } } return position; } @Override protected View newView(Context context, int position, ViewGroup group) { View result = mInflater.inflate(R.layout.rc_item_conversation, null); ViewHolder holder = new ViewHolder(); holder.layout = findViewById(result, R.id.rc_item_conversation); holder.leftImageLayout = findViewById(result, R.id.rc_item1); holder.rightImageLayout = findViewById(result, R.id.rc_item2); holder.leftUnReadView = findViewById(result, R.id.rc_unread_view_left); holder.rightUnReadView = findViewById(result, R.id.rc_unread_view_right); holder.leftImageView = findViewById(result, R.id.rc_left); holder.rightImageView = findViewById(result, R.id.rc_right); holder.contentView = findViewById(result, R.id.rc_content); holder.unReadMsgCount = findViewById(result, R.id.rc_unread_message); holder.unReadMsgCountRight = findViewById(result, R.id.rc_unread_message_right); holder.unReadMsgCountIcon = findViewById(result, R.id.rc_unread_message_icon); holder.unReadMsgCountRightIcon = findViewById(result, R.id.rc_unread_message_icon_right); result.setTag(holder); return result; } @Override protected void bindView(View v, int position, final UIConversation data) { ViewHolder holder = (ViewHolder) v.getTag(); if (data == null) { return; } /通过会话类型,取得对应的会话provider.ex: PrivateConversationProvider/ IContainerItemProvider provider = RongContext.getInstance().getConversationTemplate(data.getConversationType().getName()); if (provider == null) { RLog.e(TAG, "provider is null"); return; } View view = holder.contentView.inflate(provider); provider.bindView(view, position, data); //设置背景色 if (data.isTop()) holder.layout.setBackgroundDrawable(mContext.getResources().getDrawable(R.drawable.rc_item_top_list_selector)); else holder.layout.setBackgroundDrawable(mContext.getResources().getDrawable(R.drawable.rc_item_list_selector)); ConversationProviderTag tag = RongContext.getInstance().getConversationProviderTag(data.getConversationType().getName()); int defaultId; if (data.getConversationType().equals(Conversation.ConversationType.GROUP)) { defaultId = R.drawable.rc_default_group_portrait; } else if (data.getConversationType().equals(Conversation.ConversationType.DISCUSSION)) { defaultId = R.drawable.rc_default_discussion_portrait; } else { defaultId = R.drawable.rc_default_portrait; } // 1:图像靠左显示。2:图像靠右显示。3:不显示图像。 if (tag.portraitPosition() == 1) { holder.leftImageLayout.setVisibility(View.VISIBLE); holder.leftImageLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mOnPortraitItemClick != null) mOnPortraitItemClick.onPortraitItemClick(v, data); } }); holder.leftImageLayout.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { if (mOnPortraitItemClick != null) mOnPortraitItemClick.onPortraitItemLongClick(v, data); return true; } }); if (data.getConversationGatherState()) { holder.leftImageView.setAvatar(null, defaultId); } else { if (data.getIconUrl() != null) { holder.leftImageView.setAvatar(data.getIconUrl().toString(), defaultId); } else { holder.leftImageView.setAvatar(null, defaultId); } } if (data.getUnReadMessageCount() > 0) { holder.unReadMsgCountIcon.setVisibility(View.VISIBLE); setUnReadViewLayoutParams(holder.leftUnReadView, data.getUnReadType()); if (data.getUnReadType().equals(UIConversation.UnreadRemindType.REMIND_WITH_COUNTING)) { if (data.getUnReadMessageCount() > 99) { holder.unReadMsgCount.setText(mContext.getResources().getString(R.string.rc_message_unread_count)); } else { holder.unReadMsgCount.setText(Integer.toString(data.getUnReadMessageCount())); } holder.unReadMsgCount.setVisibility(View.VISIBLE); holder.unReadMsgCountIcon.setImageResource(R.drawable.rc_unread_count_bg); } else { holder.unReadMsgCount.setVisibility(View.GONE); holder.unReadMsgCountIcon.setImageResource(R.drawable.rc_unread_remind_list_count); } } else { holder.unReadMsgCountIcon.setVisibility(View.GONE); holder.unReadMsgCount.setVisibility(View.GONE); } holder.rightImageLayout.setVisibility(View.GONE); } else if (tag.portraitPosition() == 2) { holder.rightImageLayout.setVisibility(View.VISIBLE); holder.rightImageLayout.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mOnPortraitItemClick != null) mOnPortraitItemClick.onPortraitItemClick(v, data); } }); holder.rightImageLayout.setOnLongClickListener(new View.OnLongClickListener() { @Override public boolean onLongClick(View v) { if (mOnPortraitItemClick != null) mOnPortraitItemClick.onPortraitItemLongClick(v, data); return true; } }); if (data.getConversationGatherState()) { holder.rightImageView.setAvatar(null, defaultId); } else { if (data.getIconUrl() != null) { holder.rightImageView.setAvatar(data.getIconUrl().toString(), defaultId); } else { holder.rightImageView.setAvatar(null, defaultId); } } if (data.getUnReadMessageCount() > 0) { holder.unReadMsgCountRightIcon.setVisibility(View.VISIBLE); setUnReadViewLayoutParams(holder.rightUnReadView, data.getUnReadType()); if (data.getUnReadType().equals(UIConversation.UnreadRemindType.REMIND_WITH_COUNTING)) { holder.unReadMsgCount.setVisibility(View.VISIBLE); if (data.getUnReadMessageCount() > 99) { holder.unReadMsgCountRight.setText(mContext.getResources().getString(R.string.rc_message_unread_count)); } else { holder.unReadMsgCountRight.setText(Integer.toString(data.getUnReadMessageCount())); } holder.unReadMsgCountRightIcon.setImageResource(R.drawable.rc_unread_count_bg); } else { holder.unReadMsgCount.setVisibility(View.GONE); holder.unReadMsgCountRightIcon.setImageResource(R.drawable.rc_unread_remind_without_count); } } else { holder.unReadMsgCountIcon.setVisibility(View.GONE); holder.unReadMsgCount.setVisibility(View.GONE); } holder.leftImageLayout.setVisibility(View.GONE); } else if (tag.portraitPosition() == 3) { holder.rightImageLayout.setVisibility(View.GONE); holder.leftImageLayout.setVisibility(View.GONE); } else { throw new IllegalArgumentException("the portrait position is wrong!"); } MessageContent content = data.getMessageContent(); if (content != null && content.isDestruct()) { RongIMClient.getInstance().getMessage(data.getLatestMessageId(), new RongIMClient.ResultCallback<Message>() { @Override public void onSuccess(Message message) { if (message == null) { EventBus.getDefault().post(new Event.MessageDeleteEvent(data.getLatestMessageId())); } } @Override public void onError(RongIMClient.ErrorCode e) { } }); } } protected void setUnReadViewLayoutParams(View view, UIConversation.UnreadRemindType type) { ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams(); Context context = view.getContext(); if (type == UIConversation.UnreadRemindType.REMIND_WITH_COUNTING) { params.width = (int) context.getResources().getDimension(R.dimen.rc_dimen_size_18); params.height = (int) context.getResources().getDimension(R.dimen.rc_dimen_size_18); params.leftMargin = (int) mContext.getResources().getDimension(R.dimen.rc_dimen_size_44); params.topMargin = (int) context.getResources().getDimension(R.dimen.rc_dimen_size_5); } else { params.width = (int) context.getResources().getDimension(R.dimen.rc_dimen_size_9); params.height = (int) context.getResources().getDimension(R.dimen.rc_dimen_size_9); params.leftMargin = (int) context.getResources().getDimension(R.dimen.rc_dimen_size_50); params.topMargin = (int) context.getResources().getDimension(R.dimen.rc_dimen_size_7); } view.setLayoutParams(params); } private OnPortraitItemClick mOnPortraitItemClick; public interface OnPortraitItemClick { void onPortraitItemClick(View v, UIConversation data); boolean onPortraitItemLongClick(View v, UIConversation data); } public void setOnPortraitItemClick(OnPortraitItemClick onPortraitItemClick) { this.mOnPortraitItemClick = onPortraitItemClick; }} ...

March 16, 2021 · 5 min · jiezi

关于即时通讯:融云清空历史消息-Android-端

融云清空历史音讯 Android 端 先调用获取历史音讯。/** 依据会话类型的指标 Id,回调形式获取N条历史音讯记录。* @param conversationType 会话类型。不反对传入 ConversationType.CHATROOM。@param targetId         指标 Id。依据不同的 conversationType,可能是用户 Id、讨论组 Id、群组 Id。@param oldestMessageId 最初一条音讯的 Id,获取此音讯之前的 count 条音讯,没有音讯第一次调用应设置为:-1。@param count           要获取的音讯数量。@param callback         获取历史音讯记录的回调,依照工夫程序从新到旧排列。*/public void getHistoryMessages(Conversation.ConversationType conversationType, String targetId, int oldestMessageId, int count, RongIMClient.ResultCallback<List<Message>> callback) {RongIMClient.getInstance().getHistoryMessages(conversationType, targetId, oldestMessageId, count, callback);} 再调用删除的接口。/** 删除指定的一条或者一组音讯,回调形式获取是否删除胜利。* @param messageIds 要删除的音讯 Id 数组。@param callback   是否删除胜利的回调。*/public void deleteMessages(final int[] messageIds, final RongIMClient.ResultCallback<Boolean> callback) {RongIMClient.getInstance().deleteMessages(messageIds, new RongIMClient.ResultCallback<Boolean>() {@Overridepublic void onSuccess(Boolean bool) {if (bool)RongContext.getInstance().getEventBus().post(new Event.MessageDeleteEvent(messageIds));if (callback != null)callback.onSuccess(bool);}@Overridepublic void onError(RongIMClient.ErrorCode e) {if (callback != null)callback.onError(e);}});} ...

March 16, 2021 · 1 min · jiezi

关于即时通讯:简单五步轻松构建本土Clubhouse

最近 Clubhouse 一码难求,取得泛滥互联网圈和投资圈人士的关注,一时之间风靡寰球。 但受限于各方面起因,Clubhouse 目前还是存在很多限度,比方采纳邀请机制、只能 iOS 用户下载以及国内 Apple 账号无奈下载等。 就产品自身而言,作为一个初创的即时语聊产品,Clubhouse 也不可避免地存在如房间被动退出、语音提早性等问题,而这也是国外用户反映普遍存在的问题。 尽管如此,Clubhouse 的忽然火爆,还是让咱们看到了即时语聊市场的宏大需要,声音社交仍有宽泛的空间。 为了更快地帮忙国内一些行将或者曾经开始着手搭建即时语音聊天的企业理解 Clubhouse,抢占先机,本篇文章将从产品设计、技术实现以及在搭建中可能存在的技术难点几个维度,对 Clubhouse 进行全面的剖析和解读。 只需五步,即可轻松构建外乡「Clubhouse」! 架构设计客户端组件: 封装实现客户端与应用服务 Clubhouse Server 的交互,封装实现与音视频的交互 网关代理: 应用服务的网关服务 Clubhouse Server: 仿 ClubHouse 应用服务 网易 G2 音视频 RTC 服务: 提供稳固晦涩、搞品质、全平台的点对点和多人实时音视频通话服务,其中包含: 网易云信 IM SDK网易云信 G2 SDK架构图如下: 外围流程合成一下需要,除去用户标签、房间标签和话题举荐,Clubhouse 的性能大略分为以下几个板块: 房间列表创立/退出房间管理员邀请用户举手发言来到房间其中,整体的房间管制须要在网易云信 G2 音视频 SDK 的根底之上,借助服务端来管制;退出房间后的音视频能力,则间接由 SDK 提供;另外服务端告诉则由网易云信 IM SDK 提供的长链接服务来负责传递。具体流程图如下: 第一步:获取房间列表在这一步中,咱们调用服务端接口获取到房间列表。 第二步:创立/退出房间在这一步中,不论是创立房间还是退出房间,都会调用服务端提供的 /clubRoom/join 接口。在用户退出到 channelName 房间时,应用服务器会判断 channelName 是否存在。如果对应房间不存在,会创立一个房间并退出同时返回相应的房间信息;如果传入 channelName 存在,则用户间接退出该房间。当获取到服务端返回的房间信息时,再调用 G2 SDK 的退出房间 API joinChannelWithToken,真正退出音频房间。当退出房间胜利后,G2 SDK 会抄送音讯至应用服务器,更新用户在房间中的状态。 ...

February 8, 2021 · 1 min · jiezi

关于即时通讯:阿里技术分享电商IM消息平台在群聊直播场景下的技术实践

本文由淘宝音讯业务团队李历岷(花名骨来)原创分享,首次发表于公众号“淘系技术”,有订正和改变。 1、引言本文来自淘宝音讯业务团队的技术实际分享,剖析了电商IM音讯平台在非传统IM利用场景下的高发并、强互动群聊和直播业务中的技术特点,总结并分享了在这些场景下实现大量多对多实时音讯散发投递的一些架构方面的设计实际。 目前,阿里的IM音讯业务团队负责新批发畛域 IM 音讯平台的建设,通过 IM即时通讯产品(push、聊天机器人、单聊、群聊、音讯号和聊天室)构建连贯消费者和商家的沟通和触达渠道,每天解决百亿级的生产规模,撑持了直播互动、客服服务、商家群经营、品牌资讯、营销推送等电商畛域 BC 互通的业务场景。 (本文同步公布于:http://www.52im.net/thread-3252-1-1.html) 2、技术背景2020年双11,第一次扭转节奏,从光棍节变成双节棍,从一个峰变成了两个峰,在新的挑战下,如何做好技术保障,做好技术撑持,所有技术人都进入了一个新的学习过程。 新的局势下,显著特点是时间跨度长、流动周期长以及用户互动玩法更多。从单用户CC分享到群内分享,以及直播间互动音讯等,作为电商的IM音讯平台,承接着整个互动的场地。 用户在整个“互动音讯”场景下,能够进行实时分享、聊天、客服沟通、商家优惠、商家优惠活动和红包以及商品秒杀等。 “音讯”作为用户和用户之间架起“连贯”的重要桥梁,音讯连贯了用户和用户、用户和商家、用户和平台等。 如何做到高并发强互动下音讯有序地出现在用户背后,是音讯团队亘古不变的主题,尤其是在用户的互动行为不确定性状况下,在面对不确定性的流量和规模时,零碎应该怎么做到“丝般顺滑”的体验呢?本文将带着读者一起来进行深入探讨。 3、强互动音讯场景的技术挑战不同于传统社区IM音讯平台,电商IM音讯平台有自已的互动场景特点。 3.1 直播间淘宝直播带来新的流量变动,百万在线曾经成为常态化,大量的直播间7X24小时直播带货,用户在直播频道页频繁地进出不同的直播间。 有时候被某个直播间吸引,停在那里等着优惠、红包和宝贝,随着主播在直播间喊一嗓子,推送一张宝贝卡片,几十万人一拥而上秒杀。这样的场景每天都在演出 ... 3.2 互动PK群主互动玩法“超级星秀猫瓜分20亿红包”开启的时候,意味着大量互动拉赞、分享到好友、分享到群成为流量的入口,无论淘口令/图片等。 大量的音讯卡片被转发、二次转发带来的分享裂变效应,每天09:00和早晨22:00成为沉闷的峰值,每个组队的用户拉群互赞,这样的场景从10月20日到11月11日继续每天固定时段演出 ... 3.3 不确定性流量分享面板入口一次列表排布扭转,营销流动的一次优惠推送,直播频道页一次经营流动都可能导致直播间/群的流量霎时稳定。 纷涌而至的用户带来了大量的互动行为,各种点击/分享/音讯发送络绎不绝。 如何应答这样的流量和规模,作为平台零碎,必须可能做到应答不确定性流量能力和机制,必须从流量入口到流量进口端到端思考整体的全链路架构,是否存在单点瓶颈和缺口。 尤其在大促后期,零碎架构梳理、强弱依赖梳理、上下游链路串联、破坏性压测、脉冲流量压测和全链路压测保障和优化,以及配合相干的流量管制、预案爱护、业务流量隔离机制、资源调控等伎俩,才得以做到“不确定性流量”向“确定性流量”转变,才能够更大程度上保障系统高可用和极致用户体验。 4、强互动群聊中的音讯架构实际4.1 传统IM中“写扩散”架构的瓶颈随着2018年淘系电商首推“双11合伙人打算”,更简略间接的双11玩法,给公众带来更多期待和惊喜。 尤其是盖楼互赞流动更是把“群聊”推上风口浪尖, 在手淘APP外部分享比在微信和钉钉等社交/企业软件分享更加便捷和高效,用户不停地在群内互动分享拉赞、通过好友助力晋升盖楼积分。 基于传统的IM架构技术,尤其在群内聊天或者分享,每条音讯依照群内人数进行写扩散,依照主互动500人群规模来计算,均匀群大小320+,1:N的写入必然导致写入DB的RT以及存储压力,依照DB库承接120w/s写入速度,导致音讯上行3K/s的极限,而理论参加互动分享的用户在峰值的时候远大于这部分互动分享和聊天音讯流量。 其次集群的写入不可能齐全给IM聊天音讯,还有其它的营销流动、交易、物流等告诉类型的音讯。 基于传统IM的“写扩散”架构,在高并发、强互动场景下遇到了瓶颈,导致音讯大量的提早下推,影响最终用户体验。 4.2 “读扩散”架构的利用基于写扩散架构的音讯扩散比是1:N,那是否做到音讯扩散比是1:1呢? 答案是必定的:针对群内的音讯能够分为“非个性化音讯”和“个性化音讯”,所谓“非个性化音讯”就是大家看到都是一样的,应该只须要写一条数据,群内成员能够共享取这条数据(所谓“个性化音讯”,指定某个成员发送的单边音讯,譬如进群欢送语等)。 在群内,99.99%都是“非个性化音讯”,也就是能够从1:N压缩到1:1写入。 基于这个实践假如,须要思考“读扩散”让每个用户的音讯从对应的“群会话音讯队列同步“数据,而不是从”用户队列同步“数据。 其中同步队列围绕队列offset偏移量进行,通过队列的自增syncId保障有序,每个客户端保护相应的队列的同步位点,采取“客户端存储位点的去中心化“计划,实现”上行音讯的推拉“联合。 通过队列位点syncId进行比对,如果服务端音讯队列syncId-客户端队列syncId=1,示意云端音讯无空洞,否则携带客户端的队列和对应的syncId到云端从新同步区间数据,实现最终一致性。 传统的IM产品:腾讯QQ、腾讯微信、网易云通信、抖音IM、钉钉IM、脉脉IM、支付宝IM。 PS:市面上APP80%都具备IM聊天能力,均采取写扩散简略模式进行云端音讯同步。4.3 “读扩散”、“写扩散”技术计划比照4.3.1)写扩散技术: 长处: 1)整体架构简洁,计划简略,保护用户同步队列实现数据同步机制;2)无论是单聊还是群聊等会话音讯,写入用户维度同步队列,集中获取同步数据;3)推和拉状况下,存储模型和数据处理简略,且人造反对个性化数据。毛病: 1)群会话音讯,人造存在1:N写入扩散比,存储压力N倍压力,在线用户收到音讯提早增大;2)多个群内音讯队列混合在同步队列,无优先级解决能力,无奈针对互动群等做隔离。4.3.2)读扩散技术: 长处: 1)升高写扩散N倍的DB存储压力,缩小上行在线用户端到端扩散的RT工夫;2)晋升音讯上行集群整体的吞吐量,用户体验更晦涩;3)端到端实现会话级别的同步优先级队列,实现差异化服务。毛病: 1)整体架构偏简单,须要保护每个动静会话音讯同步队列,端侧须要实时感知新增的动静同步队列;2)客户端冷启动须要扩散读取多个会话音讯同步队列数据,对于存储会带来读QPS压力。4.4 读写扩散混合模式外围在于架构的演进推动“读写扩散混合模式“落地,联合两者的长处进行云端一体化数据同步技术,笼罩几千万互动群用户,保障整体峰值上行音讯以及用户在群内端到端提早体验,做到一条上行音讯500ms以内达到群内其余用户端侧,让整体用户体验晋升显著,群内强互动成为可能。 5、电商直播互动中的音讯架构实际5.1 技术挑战电商直播出现大直播若干个(大于30W同时在线)、中直播间几百个、小直播几万个这样散布,尤其是晚会和主播带来的热点直播间效应,对系统整体的IM音讯架构存在热点带来重大挑战。 热点问题的产生须要从不确定性的流量起源说起。 直播间人员规模人造和群聊不一样(单个群<=500人),一个直播间能够冲破40万-200万之间设施同时在线。 直播间在另一个层面是“非凡的群”,群保护了群和群成员强关系,直播间保护直播和设施之间的订阅弱关系,在扩散维度群依照500人进行分库分表切片模式散发上行音讯,直播间须要以直播间几十万设施作为分段切片进行散发。同时直播间的指令音讯如果不加以干涉,会造成超大的流量热点和扩散问题。那么针对这个问题如何应答? 直播间互动全链路和外围解决节点繁难时序图如下: 即:观众互动音讯 -> 网关接入 -> 利用零碎Buffer(秒级直播间维度音讯) -> 编码、合并、批量音讯流 -> 直播间维度设施扩散 -> 设施长连通道推送 -> 设施接管 -> 解码音讯 -> 业务解决。 ...

December 18, 2020 · 1 min · jiezi

关于即时通讯:集成融云-IMLib-时如何实现一套类似于-IMKit-的用户信息管理机制

背景咱们在设计聊天类 APP 都会有一套残缺的用户信息存储机制,用来保留咱们的通讯录列表,以及每个用户的头像、昵称、姓名、等等一系列的用户信息,避免咱们过多的进行服务器申请,对用户体验很差。这篇文章就简略的给大家创立一套用户信息机制来提供一个简略的思路。场景如下:目前咱们集成了融云的 IMLib SDK , 融云 IMLib SDK 仅提供了音讯数据的存储与查问。用户信息和 UI 界面须要咱们本人来保护,而融云的 IMKit 尽管提供了用户信息的治理,然而局部 UI 还是和咱们产品设计不符的,那么如何设计一套相似于 IMKit 的用户信息管理机制,就是咱们面临的问题。 融云SDK:https://docs.rongcloud.cn/v4/ 思考咱们在实现这套机制的时候都须要哪些内容? 首先咱们要进行存储,存储那就须要保护一个数据库。参考融云 IMKit 发现有上面一个配置/*! 是否将用户信息和群组信息在本地长久化存储,默认值为NO @discussion 如果设置为NO,则SDK在须要显示用户信息时,会调用用户信息提供者获取用户信息并缓存到Cache,此Cache在App生命周期完结时会被移除,下次启动时会再次通过用户信息提供者获取信息。 如果设置为YES,则会将获取到的用户信息长久化存储在本地,App下次启动时Cache会依然无效。 */@property (nonatomic, assign) BOOL enablePersistentUserInfoCache;通过测试以及融云业余技术人员的答复,发现这个配置起到的作用就是本次的用户信息是否会进行数据库存储。 这里的数据库存储是指当此配置失效时,会在本地进行数据库文件的创立。而不失效的时候,是不创立的。如果不创立的话还须要存储的话,那应该就是存储到内存了。 而咱们是须要每次登陆都有一些用户信息的,那不须要应用内存了,须要咱们进行数据库存储,所以咱们须要筹备一个 db 的治理类,解决所有的数据库操作。须要一个整体治理用户信息的入口 manager ,用来整顿一些根本信息。以及提供用户信息管理的代理入口。须要存储哪些用户信息以及筹备对用的 model 类。筹备每种对象的缓存类。实现以 融云 SDK 为例,以一个用户的 userinfo 为例大体来绘制一下整个流程图。 首先整顿一些各个类的用途,大体内容如下:UserInfoDBHelper: 数据库治理 #import <Foundation/Foundation.h>#import "UserInfo.h"NS_ASSUME_NONNULL_BEGIN@interface UserInfoDBHelper : NSObject- (void)createDB;- (UserInfo *)getUserInfo:(NSString *)userId;- (void)refreshUserInfo:(UserInfo *)userInfo;@endNS_ASSUME_NONNULL_ENDUserInfo: 用户信息模型 #import <Foundation/Foundation.h>NS_ASSUME_NONNULL_BEGIN@interface UserInfo : NSObject/** id name url */@endNS_ASSUME_NONNULL_ENDUserInfoCache: 用户信息读取类 ...

November 6, 2020 · 1 min · jiezi

关于即时通讯:如何设置融云用户信息

最近在应用融云,因为第一次应用,遇到了一个小坑,在这里记录一下,心愿能帮忙到后续开发者 问题是应用了融云的 IMKit 组件,也就是自带 UI 的,对于疾速试错的产品来说,工期必须短,所以应用 IMKit 是十分不便的,省去了很大部分工夫去搞界面。然而应用过程中发现,没有用户的头像和昵称。起初通过浏览文档发现,须要设置“用户信息提供者”代理办法。SDK 在须要显示头像和昵称的时候,会通过这个代理找开发者索取用户信息,开发者只有遵循代理,且实现代理办法,返回用户信息即可。 上代码: 1.遵循代理 @interface AppDelegate () <RCIMUserInfoDataSource>@end2.设置代理 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { //必须先初始化 [[RCIM sharedRCIM] initWithAppKey:"开发者本人的 appkey"]; [[RCIM sharedRCIM] connectWithToken:"以后用户的 token" dbOpened:^(RCDBErrorCode code) { } success:^(NSString *userId) { } error:^(RCConnectErrorCode errorCode) { }]; //设置以后用户信息 RCUserInfo *currentUser = [[RCUserInfo alloc] initWithUserId:@"tiezhu" name:@"铁柱" portrait:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1573646812313&di=116350f184eda99d91393304fa83a6ea&imgtype=0&src=http%3A%2F%2Fimg.jinse.com%2F712431_image3.png"]; [RCIM sharedRCIM].currentUserInfo = currentUser; //设置代理 [RCIM sharedRCIM].userInfoDataSource = self;}3.实现代理办法 - (void)getUserInfoWithUserId:(NSString *)userId completion:(void (^)(RCUserInfo *userInfo))completion { //这里最好是从开发者本人服务器获取用户信息,而后返回。此处仅为示例 RCUserInfo *user = nil; if ([userId isEqualToString:@"tiezhu"]) { user = [[RCUserInfo alloc] initWithUserId:@"tiezhu" name:@"铁柱" portrait:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1570172426&di=01d14daa81f320235376d9c4dede0493&imgtype=jpg&er=1&src=http%3A%2F%2Fgss0.baidu.com%2F-vo3dSag_xI4khGko9WTAnF6hhy%2Fzhidao%2Fpic%2Fitem%2Fd788d43f8794a4c240e9466f0ef41bd5ac6e39af.jpg"]; } if (completion) { completion(user); }}到此就搞定了兄嘚,值一杯秋天的奶茶 ...

November 6, 2020 · 1 min · jiezi

关于即时通讯:零基础IM开发入门四什么是IM系统的消息时序一致性

本文援用了沈剑《如何保障IM实时音讯的“时序性”与“一致性”?》一文的图片和内容(因为太懒,图没从新画),原文链接在文末。 1、引言本文接上篇《零根底IM开发入门(三):什么是IM零碎的可靠性?》,解说IM零碎中音讯时序的一致性问题。 所谓的一致性,在IM中通常指的是音讯时序的一致性,那就是: 1)聊天音讯的上下文连续性;2)聊天音讯的相对工夫序。再具体一点,IM音讯的一致性体现在: 1)单聊时:要保障发送方收回聊天音讯的程序与接管方看到的程序统一;2)群聊时:要保障所有群员看到的聊天音讯,与发送者收回音讯时的相对工夫序是统一的。IM零碎中音讯时序的一致性问题是个看似简略,实则十分有难度的技术热点话题之一,本文尽量以艰深简显的文字为你解说IM音讯时序一致性问题的产品意义、产生起因、解决思路等。 学习交换:即时通讯/推送技术开发交换5群:215477170 [举荐]挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK(本文同步公布于:http://www.52im.net/thread-3189-1-1.html) 2、系列文章《零根底IM开发入门(一):什么是IM零碎?》《零根底IM开发入门(二):什么是IM零碎的实时性?》《零根底IM开发入门(三):什么是IM零碎的可靠性?》《零根底IM开发入门(四):什么是IM零碎的音讯时序一致性?》(* 本文)《零根底IM开发入门(五):什么是IM零碎的安全性? (稍后公布)》《零根底IM开发入门(六):什么是IM零碎的的心跳机制? (稍后公布)》《零根底IM开发入门(七):如何了解并实现IM零碎音讯未读数? (稍后公布)》《零根底IM开发入门(八):如何了解并实现IM零碎的多端音讯漫游? (稍后公布)》3、音讯时序的一致性,对于IM的意义现如今,因为挪动互联网的遍及,现代人的理论社交关系,简直齐全是靠IM这种即时通讯社交工具所组织起来的,IM这种工具的重要性显而易见。 IM在现代人的生存中,越来越重要,但也越来平时。当初想分割一个人,第一工夫想到的不是打个电话,而是发个“微信”或“QQ”。是的,IM这玩意承载的意义越来越多。 音讯时序的一致性问题,对于IM的意义,毫无疑问带来的不只是简简单单的所谓用户体验问题。咱们来看看例子。 假如:你跟女神的表白正进入到要害阶段,聊着聊着就因为这烂IM,导致聊天音讯前言不搭后语,此刻1000公里外你的女神真一脸蒙逼的盯着手机看你的“醉话”,结果是如许重大——这半年来的“舔狗”生存、忍无可忍,算是白白被程序员这群“格子衫”、“地中海”们给祸患了。 再往重大了说,就因为这烂IM,让你失去了这难得的借助女神低劣基因,革新家族后辈颜值的绝佳机会,无不让人痛心疾首。。。 下面这个例子,说的还只是单聊,如果是群聊,则问题可能还会被有限放大:试想一个技术交换群,正在强烈的争吵着“php是世界最好语言”这种话题的时候,突然就想砸手机了,不是因为吵的太凶,而因为音讯程序全乱齐全没法看,曾经重大影响键盘侠们踊跃发表集体意见了。 4、凭什么说保障音讯时序的一致性很艰难?4.1 根本认知在一般IM用户的眼里,音讯无非是从一台手机传递到另一台手机而已,保障时序有何艰难? 是的,普通用户这么认为,从技术上讲,他只是单纯的将IM音讯的收发过程了解为单线程的工作模式而已。 实际上,在IM这种高性能场景下,服务端为了谋求高吞吐、高并发,用到了多线程、异步IO等等技术。 在这种状况下,“高并发”与“程序”对于IM服务端来说,原本就是矛盾的,这就有点鱼与熊掌的滋味了(两者很难兼得)。 所以,要实现IM场景下的音讯时序一致性,须要做出衡量,而且要思考的技术维度相当多。这就导致具体技术施行起来没有固定的套路,而因为开发者技术能力的参差不齐,也就使得很多IM零碎在理论的成果上会有较大问题,对于用户而言也将间接在产品体验上反馈进去。 上面将具体阐明技术难点所在。 4.2 没有全局时钟 如上图所示,一个真正堪用的生产零碎,显示不可能所有服务都跑在一台服务器上,分布式环境是必定的。 那么:在分布式环境下,客户端+服务端后盾的各种后盾服务,都各自散布在不同的机器上,机器之间都是应用的本地时钟,没有一个所谓的“全局时钟”(也没方法做到真正的全局时钟),那么所谓的音讯时序也就没有真正意义上的时序基准点。所以音讯时序问题显然不是“本地工夫”能够齐全决定的。 4.3 多发送方问题 服务端分布式的状况下,不能用“本地工夫”来保障时序性,那么是否用接管方本地工夫示意时序呢? 遗憾的是,因为多个客户端的存在(比方群聊时),即便是一台服务器的本地工夫,也无奈示意“相对时序”。 如上图所示:相对时序上,APP1先收回msg1,APP2后收回msg2,都发往服务器web1,网络传输是不能保障msg1肯定先于msg2达到的,所以即便以一台服务器web1的工夫为准,也不能精准形容msg1与msg2的相对时序。 4.4 多接管方问题 多发送方不能保障时序,假如只有一个发送方,是否用发送方的本地工夫示意时序呢?遗憾的是,因为多个接管方的存在,无奈用发送方的本地工夫,示意“相对时序”。 如上图,相对时序上,web1先收回msg1,后收回msg2,因为网络传输及多接管方的存在,无奈保障msg1先被接管到先被解决,故也无奈保障msg1与msg2的解决时序。 4.5 网络传输与多线程问题 既然多发送方与多接管方都难以保障相对时序,那么假如只有繁多的发送方与繁多的接管方,是否保障音讯的相对时序一致性呢? 论断是乐观的,因为网络传输与多线程的存在,这依然不行。 如上图所示,web1先收回msg1、后收回msg2,即便msg1先达到(网络传输其实还不能保障msg1先达到),因为多线程的存在,也不能保障msg1先被解决完。 5、如何保障相对的音讯时序一致性?通过上一章内容的总结,咱们曾经对IM中音讯时序一致性问题所产生的原因,有了较为粗浅的意识。 从纯技术的角度来说,假如: 1)只有一个发送方;2)一个接管方;3)上下游连贯只有一条socket连贯;4)通过阻塞的形式通信。这样的状况下,难道不能保障先收回的音讯被先解决,进而被先展现给音讯的接收者吗? 是的,能够! 但理论生产状况下不太可能呈现这种IM零碎,必竟单发送方、单接管方、单socket连贯、阻塞形式,这样的IM一旦做进去,产品经理会立马死给你看。。。 6、实用的优化思路6.1 一对一单聊的音讯一致性保障思路假如两人一对一聊天,发送方A顺次收回了msg1、msg2、msg3三条音讯给接管方B,这三条音讯该怎么保障显示时序的一致性(发送与显示的程序统一)? 咱们晓得,发送方A顺次收回的msg1、msg2、msg3三条音讯,到底服务端后,再由服务端直达收回时,这个程序因为多线程的网络的问题,是有可能乱序的。 那么后果就可能是这样: 如上图所示,会呈现与收回时的音讯时序不统一问题(收到的音讯程序是:msg3、msg1、msg2)。 不过,实际上一对一聊天的两个人,并不需要全局音讯时序的统一(因为聊天只在两人的同一会话在产生),只须要对于同一个发送方A,发给B的音讯时序统一就行了。 常见优化计划,在A往B收回的音讯中,加上发送方A本地的一个相对时序(比方本机工夫戳),来示意接管方B的展示时序。 那么当接管方B收到音讯后,即便极其状况下音讯可能存在乱序达到,但因为这个乱序的时间差对于普通用户来说体感是很短的,在UI展示层依照音讯中自带的相对时序排个序后再显示,用户其实是没有太多感知的。 6.2 多对多群聊的音讯一致性保障思路假如N个群友在一个IM群里聊天,应该怎么保障所有群员收到音讯的显示时序一致性呢? 首先:不能像一对聊天那样利用发送方的相对时序来保障音讯程序,因为群聊发送方不单点,工夫也不统一。 或者:咱们能够利用服务器的单点做序列化。 如上图所示,此时IM群聊的发送流程为: 1)sender1收回msg1,sender2收回msg2;2)msg1和msg2通过接入集群,服务集群;3)service层到底层拿一个惟一seq,来确定接管方展现时序;4)service拿到msg2的seq是20,msg1的seq是30;5)通过投递服务讲音讯给多个群友,群友即便接管到msg1和msg2的工夫不同,但能够对立依照seq来展示。这个办法: 1)长处是:能实现所有群友的音讯展现时序雷同;2)毛病是:这个生成全局递增序列号的服务很容易成为零碎瓶颈。还有没有进一步的优化办法呢? 从技术角度看:群音讯其实也不必保障全局音讯序列有序,而只有保障一个群内的音讯有序即可,这样的话,“音讯id序列化”就成了一个很好的思路。 上图这个计划中,service层不再须要去一个对立的后端拿全局seq(序列号),而是在service连接池层面做细小的革新,保障一个群的音讯落在同一个service上,这个service就能够用本地seq来序列化同一个群的所有音讯,保障所有群友看到音讯的时序是雷同的。 对于IM的零碎架构下应用怎么样实现音讯序列化,或者说全局音讯ID的生成计划,这又是另一个很热门的技术话题。 ...

November 4, 2020 · 1 min · jiezi

关于即时通讯:零基础IM开发入门三什么是IM系统的可靠性

本文编写时援用了“聊聊IM零碎的即时性和可靠性”一文的局部内容和图片,感激原作者。 1、引言上一篇《零根底IM开发入门(二):什么是IM零碎的实时性?》讲到了IM零碎的“立足”之本——“实时性”这个技术特色,本篇次要解说IM零碎中的“可靠性”这个话题,内容尽量做到只讲原理不深刻开展,避开深层次的技术性探讨,确保通俗易懂。 浏览对象:本系列文章次要浏览对象为零IM根底的开发者或产品经理,指标是通知你“IM零碎是什么?”,尽量不深入探讨具体的技术实现,确保通俗易懂,老少皆宜。 如您想从技术维度零碎学习IM技术并着手自已的IM开发(即解决“IM零碎要怎么做?”这个疑难),请从此文开始:《新手入门一篇就够:从零开发挪动端IM》。 学习交换: 即时通讯/推送技术开发交换5群:215477170[举荐]挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK(本文同步公布于:http://www.52im.net/thread-3182-1-1.html) 2、系列文章《零根底IM开发入门(一):什么是IM零碎?》《零根底IM开发入门(二):什么是IM零碎的实时性?》《零根底IM开发入门(三):什么是IM零碎的可靠性?》(* 本文)《零根底IM开发入门(四):什么是IM零碎的音讯时序一致性?》《零根底IM开发入门(五):什么是IM零碎的安全性? (稍后公布)》《零根底IM开发入门(六):什么是IM零碎的的心跳机制? (稍后公布)》《零根底IM开发入门(七):如何了解并实现IM零碎音讯未读数? (稍后公布)》《零根底IM开发入门(八):如何了解并实现IM零碎的多端音讯漫游? (稍后公布)》3、注释概述一般来说,IM零碎的音讯“可靠性”,通常就是指聊天音讯投递的可靠性(精确的说,这个“音讯”是狭义的,因为还存用户看不见的各种指令,为了艰深,统称“音讯”)。 从用户行为来讲,音讯“可靠性”应该分为两种类型: 1)在线音讯的可靠性:即发送音讯时,接管方以后处于“在线”状态;2)离线音讯的可靠性:即发送音讯时,接管方以后处于“离线”状态。从具体的技术体现来讲,音讯“可靠性”蕴含两层含意: 1)音讯不丢:这很直白,收回去的音讯不能像进了黑洞一样,一脸懵逼可不行;2)音讯不重:这是丢音讯的背面,音讯反复了也不能容忍。对于“音讯不丢”这个特色来说,细化下来,它又蕴含两重含意: 1)已明确被对方收到;2)已明确未被对方收到。是的,对于第1)重含意好了解,第2)重含意的意思是:当对方没有胜利收到时,你的im零碎也必须要感知到,否则,它同样属于被“丢”领域。 总之,一个成型的im零碎,必须蕴含这两种音讯“可靠性”逻辑,能力堪用,缺一不可。 音讯的可靠性(不失落、不反复)无疑是IM零碎的重要指标,也是IM零碎实现中的难点之一。本文以下文字,将从在线音讯的可靠性和离线音讯的可靠性进行探讨。 4、典型的在线音讯收发流程先看上面这张典型的im音讯收发流程: 是的,这是一个典型的服务端中转型IM架构。 所谓“服务端中转型IM架构”是指:一条音讯从客户端A收回后,须要先通过 IM 服务器来进行直达,而后再由 IM 服务器推送给客户端B,这种模式也是目前最常见的 IM 零碎的音讯散发架构。 你可能会说,IM不能够是P2P模式的吗?是的,目前来说支流IM根本都是服务器直达这种形式,P2P模式在IM零碎中用的很少。 起因是以下两个很显著的弊病: 1)P2P模式下,IM运营者很容易被用户架空(无奈监管到用户行为,用户涉黄了怕不怕?);2)P2P模式下,群聊这种业务状态,很难实现(我要在千人群中发消息给,不可能我自已来散发1000次吧)。话题有点跑偏,咱们回到正题:在下面这张图里,客户A发送音讯到服务端、服务端直达音讯给客户B,假如这两条数据链接中应用的通信协议是TCP,你认为在TCP所谓牢靠传输协定加持下,真的能保障IM聊天音讯的可靠性吗? 答案是否定的。咱们持续看下节。 5、TCP并不能保障在线音讯的“可靠性”接上节,在一个典型的服务端中转型IM架构中,即便应用“牢靠的传输协定”TCP,也不能保障聊天音讯的可靠性。为什么这么说? 要答复这个问题,网上的很多文章,都会从服务端的角度举例:比方音讯发送时操作系统解体、网络闪断、存储故障等等,总之很形象,不太容易了解。 这次咱们从客户端角度来了解,为什么应用了牢靠传输协定TCP的状况下IM聊天音讯依然不牢靠的问题。 具体来说:如何确保 IM 音讯的可靠性是个绝对简单的话题,从客户端发送数据到服务器,再从服务器送达指标客户端,最终在 UI 胜利展现,其间波及的环节很多,这里只取其中一环「接收端如何确保音讯不失落」来探讨,粗略聊下我接触过的两种设计思路。 说到牢靠送达:第一反馈会联想到 TCP 的可靠性。数据的牢靠送达是个通用性的问题,无论是网络二进制流数据,还是下层的业务数据,都有可靠性保障问题,TCP 作为网络基础设施协定,其可靠性设计的可靠性是毋庸置疑的,咱们就从 TCP 的可靠性说起。 在 TCP 这一层:所有 Sender 发送的数据,每一个 byte 都有标号(Sequence Number),每个 byte 在到达接收端之后都会被接收端返回一个确认信息(Ack Number), 二者关系为 Ack = Seq + 1。简略来说,如果 Sender 发送一个 Seq = 1,长度为 100 bytes 的包,那么 receiver 会返回一个 Ack = 101 的包,如果 Sender 收到了这个Ack 包,阐明数据的确被 Receiver 收到了,否则 Sender 会采取某种策略重发下面的包。 ...

October 29, 2020 · 1 min · jiezi

关于即时通讯:社交软件红包技术解密十一最全解密微信红包随机算法含代码实现

本文内容编写时,参考了网上的材料,详见“参考资料”局部,感激分享者。 1、引言这个系列文章曾经整顿了10篇,但都没有波及到具体的红包算法实现,次要有以下两方面起因。 一方面是各社交/IM产品中的红包性能同质化重大,红包算法的“可玩性”便是“外围竞争力所在”,这是同质化性能的差异化竞争思路,不会轻易公开。 另一方面,市场上还存在各种抢红包插件这类灰产存在,一旦公开这些算法,很可能又被这帮插件开发者们搞出什么幺蛾子。 所以,这样的状况下,如果要做社交/IM产品中的红包性能,红包轻易算法该怎么实现,基本上只能自已推敲,很难找到大厂算法间接套用。 本着即时通讯网一贯的im常识流传精力,我收集整理并参考了大量的网上材料,综合了比拟靠谱的信息起源,便有了本文。本文依据无限的材料,分享了微信红包随机算法实现中的一些技术要点,并整顿了两种比拟靠谱的红包算法实现思路(含可运行的实现代码),心愿能给你的红包算法开发带来启发。 申明:本文材料整顿自网络,仅供学习钻研之用,如有不妥,请告诉作者。 学习交换: - 即时通讯开发交换5群:215477170 [举荐]- 挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》- 开源IM框架源码:https://github.com/JackJiang2011/MobileIMSDK  [举荐]本文已同步公布于“即时通讯技术圈”公众号,欢送关注: ▲ 本文在公众号上的链接是:点此进入,原文链接是:http://www.52im.net/thread-3125-1-1.html 2、系列文章《社交软件红包技术解密(一):全面解密QQ红包技术计划——架构、技术实现等》《社交软件红包技术解密(二):解密微信摇一摇红包从0到1的技术演进》《社交软件红包技术解密(三):微信摇一摇红包雨背地的技术细节》《社交软件红包技术解密(四):微信红包零碎是如何应答高并发的》《社交软件红包技术解密(五):微信红包零碎是如何实现高可用性的》《社交软件红包技术解密(六):微信红包零碎的存储层架构演进实际》《社交软件红包技术解密(七):支付宝红包的海量高并发技术实际》《社交软件红包技术解密(八):全面解密微博红包技术计划》《社交软件红包技术解密(九):谈谈手Q春节红包的设计、容灾、运维、架构等》《社交软件红包技术解密(十):手Q客户端针对2020年春节红包的技术实际》《社交软件红包技术解密(十一):最全解密微信红包随机算法(含演示代码)》(* 本文)3、微信红包算法要点汇总这是目前能找到的仅有的一份,有微信团队人员参加的微信红包算法技术要点的探讨材料。分享于2015年,差不多是微信红包刚火没多久,大略是微信技术团队的人过后没有当初这些技术之外的顾虑,所以作了无限的分享,材料难得,本次重新整理了一下,能够作为参考资料应用。以下是材料注释。 材料起源:来自InfoQ的某架构群的技术探讨,由朱玉华整顿(集体博客是:zhuyuhua.com(目前已无法访问))。 材料背景:起因是有敌人在朋友圈征询微信红包的架构,于是在微信团队成员参加探讨的状况下,我(指“朱玉华”)整顿了这次探讨的技术要点,也就是上面的内容(内容为问答模式)。 3.1、算法实现的技术要点问:微信的金额什么时候算? 答:微信金额是拆的时候实时算进去,不是事后调配的,采纳的是纯内存计算,不须要估算空间存储。 为什么采取实时计算金额?起因是:实时效率更高,估算才效率低下。估算还要占额定存储。因为红包只占一条记录而且有效期就几天,所以不须要多大空间。就算压力大时,程度扩大机器是。 问:对于实时实时性,为什么明明抢到红包,点开后发现没有? 答:2014年的红包一点开就晓得金额,分两次操作,先抢到金额,而后再转账。 2015年的红包的拆和抢是拆散的,须要点两次,因而会呈现抢到红包了,但点开后告知红包曾经被领完的情况。进入到第一个页面不代表抢到,只示意过后红包还有。 问:对于调配算法,红包里的金额怎么算?为什么呈现各个红包金额相差很大? 答:随机,额度在 _0.01_ 和残余平均值 _2_ 之间。 例如:发 _100_ 块钱,总共 _10_ 个红包,那么平均值是 _10_ 块钱一个,那么收回来的红包的额度在 _0.01_元~_20_元之间稳定。 当后面 _3_ 个红包总共被领了 _40_ 块钱时,剩下 _60_ 块钱,总共 _7_ 个红包,那么这 _7_ 个红包的额度在:_0.01_~(_60/7 * 2_)=_17.14_之间。 留神:这里的算法是每被抢一个后,剩下的会再次执行下面的这样的算法(Tim老师也感觉上述算法太简单,不知基于什么样的思考)。 这样算下去,会超过最开始的全副金额,因而到了最初面如果不够这么算,那么会采取如下算法:保障残余用户能拿到最低1分钱即可。 如果后面的人手气不好,那么前面的余额越多,红包额度也就越多,因而理论概率一样的。 问:红包的设计 答:微信从财付通拉取金额数据过去,生成个数/红包类型/金额放到redis集群里,app端将红包ID的申请放入申请队列中,如果发现超过红包的个数,间接返回。依据红包的逻辑解决胜利失去令牌申请,则由财付通进行一致性调用,通过像比特币一样,两边保留交易记录,交易后交给第三方服务审计,如果交易过程中呈现不统一就强制回归。 问:并发性解决:红包如何计算被抢完? 答:cache会抵制有效申请,将有效的申请过滤掉,理论进入到后盾的量不大。cache记录红包个数,原子操作进行个数递加,到 0 示意被抢光。财付通依照 _20万笔_每秒入账筹备,但理论还不到 _8万每秒_。 问:通如何放弃8w每秒的写入? 答:多主sharding,程度扩大机器。 问:数据容量多少? 答:一个红包只占一条记录,有效期只有几天,因而不须要太多空间。 问:查问红包调配,压力大不? 答:抢到红包的人数和红包都在一条cache记录上,没有太大的查问压力。 问:一个红包一个队列? 答:没有队列,一个红包一条数据,数据上有一个计数器字段。 问:有没有从数据上证实每个红包的概率是不是均等? 答:不是相对均等,就是一个简略的拍脑袋算法。 问:拍脑袋算法,会不会呈现两个最佳? 答:会呈现金额一样的,然而手气最佳只有一个,先抢到的那个最佳。 问:每领一个红包就更新数据么? 答:每抢到一个红包,就cas更新残余金额和红包个数。 问:红包如何入库入账? 答:数据库会累加曾经支付的个数与金额,插入一条支付记录。入账则是后盾异步操作。 问:入帐出错怎么办?比方红包个数没了,但余额还有? 答:最初会有一个take all操作。另外还有一个对账来保障。 问:既然在抢的时候有原子减了就不应该呈现抢到了拆开没有的状况? 答:这里的原子减并不是真正意义上的原子操作,是Cache层提供的CAS,通过比拟版本号一直尝试。 问:cache和db挂了怎么办? 答:主备 +对账。 问:为什么要拆散抢和拆? 答:总思路是设置多层过滤网,层层筛选,层层缩小流量和压力。 这个设计最后是因为抢操作是业务层,拆是入账操作,一个操作太重了,而且中断率高。 从接口层面看,第一个接口纯缓存操作,搞压能力强,一个简略查问Cache挡住了绝大部分用户,做了第一道筛选,所以大部分人会看到曾经抢完了的提醒。 ...

August 26, 2020 · 3 min · jiezi

关于即时通讯:脑残式网络编程入门九面试必考史上最通俗大小端字节序详解

1、引言最近在从头重写 MobileIMSDK 的TCP版,自已组织TCP数据帧时就遇到了字节序大小端问题。所以,借这个机会独自整顿了这篇文章,心愿能加深大家对字节序问题的了解,增强对IM这种基于网络通信的程序在数据传输这一层的常识掌控状况。 程序员在写应用层程序时,个别不须要思考字节序问题,因为字节序跟操作系统和硬件环境无关,而咱们编写的程序要么不须要跨平台(比方只运行在windows),要么须要跨平台时会由Java这种跨平台语言在虚拟机层屏蔽掉了。 但典型状况,当你编写网络通信程序,比方IM聊天利用时,就必须要思考字节序问题,因为你的数据在这样的场景下要跨机器、跨网络通信,必须解决不同零碎、不同平台的字节序问题。 * 浏览对象:本文属于计算机基础知识,特地适宜从事网络编程方面工作(比方IM这类通信零碎)的程序员浏览。面视时,面视官个别都会聊到这个知识点。 本文已同步公布于“即时通讯技术圈”公众号,欢送关注: ▲ 本文在公众号上的链接是:点此进入 ,原文链接是:http://www.52im.net/thread-3101-1-1.html 2、什么是字节序?字节序,是指数据在内存中的寄存程序,当字节数大于1时须要思考(只有一个字节的状况下,比方char类型,也就不存在程序问题啦)。 从下图中,能够直观的感触到什么是字节序问题: (上图片改编自《C语言打印数据的二进制格局-原理解析与编程实现》) 3、字节序的分类字节序常被分为两类: 1)Big-Endian(大端字节序):高位字节排放在内存的低地址端,低位字节排放在内存的高地址端(这是人类读写数值的办法);2)Little-Endian(小端字节序):低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。举个具体的例子,0x1234567 的大端字节序和小端字节序写法如下: 如上图所示:大端小端字节序最小单位1字节,即8bit;大端字节序就是和咱们平时写法的程序一样,从低地址到高地址写入0x01234567;而小端字节序就是和咱们平时的写法反过来,因为字节序最小单位为1字节,所以从低地址到高地址写入0x67452301。 4、为什么会存在大端、小端字节序问题?4.1 比拟正当的解释一个比拟正当的解释是说:计算机中电路优先解决低位字节,效率比拟高,因为计算机都是从低位开始的,所以计算机外部解决都是小端字节序。 而人类人类读写数值的办法,习惯用大端字节序,所以除了计算机的外部处,其余的场理合都是大端字节序,比方:网络传输和文件贮存时都是用的大端字节序(对于网络字节序,会在前面持续开展阐明)。 大小端字节序问题,最有可能是跟技术算硬件或软件的创造者们,在技术创建之初的一些技术条件或集体习惯无关。 所以大小端问题,体现在理论的计算机工业利用来上,不同的操作系统和不同的芯片类型可能都会有不同。 4.2 常见的操作系统和芯片应用的字节序具体来说:DEC和Intel的机器(X86平台)个别采纳小端,IBM、Motorola(Power PC)、Sun的机器个别采纳大端。 当然,这不代表所有状况。有的CPU即能工作于小端, 又能工作于大端,比方:Arm、Alpha、摩托罗拉的PowerPC。  而且,具体这类CPU是大端还是小端,和具体设置也无关。如:Power PC反对小端字节序,但在默认配置时是大端字节序。 一般来说:大部分用户的操作系统(如:Windows、FreeBsd、Linux)是小端字节序。少部分,如:Mac OS 是大端字节序。 4.3 如何判断用的是什么字节序?怎么判断我的计算机里应用的是大端还是小端字节序呢? 上面的这段代码能够用来判断计算机是大端的还是小端。判断的思路是:确定一个多字节的值(上面应用的是4字节的整数),将其写入内存(即赋值给一个变量),而后用指针取其首地址所对应的字节(即低地址的一个字节),判断该字节寄存的是高位还是低位,高位阐明是Big endian,低位阐明是Little endian。 include <stdio.h>int main (){  unsigned int x = 0x12345678;  char*c = (char*)&x;  if(*c == 0x78) {    printf("Little endian");  } else{    printf("Big endian");  }  return 0;} 5、“大端”、“小端”名字由来依据网上的材料,据说名字的由来跟乔纳森·斯威夫特的驰名讥刺小说《格列佛游记》无关。 书中的故事是这样的:一般来说,大家都认为吃鸡蛋前,原始的办法是突破鸡蛋较大的一端。可是当今皇帝的祖父小时候吃鸡蛋,一次按古法打鸡蛋时碰巧将一个手指弄破了,因而他的父亲,过后的皇帝,就下了一道敕令,命令整体臣民吃鸡蛋时突破鸡蛋较小的一端,违令者重罚。 君子国内部决裂成Big-endian和Little-endian两派,区别在于一派要求从鸡蛋的大头把鸡蛋突破,另一派要求从鸡蛋的小头把鸡蛋突破。 小人国国王扭转了关上鸡蛋的方位与理由,并由此导致了批改法律、引发和平和宗教改革等一序列事件的产生。 《格列佛游记》中的这则故事,本来是借以讥刺英国的政党之争。而在计算机工业中,也借用了这个故事来代指大家在数据贮存字节程序中的一致,并把“大端”(Big-endian)、“小端”(Little-endian)的名字,沿用到了计算机中。  (上图片改编自《“字节序”是个什么鬼?》) 或者,借用这个故事来命名大小端字节序问题,无非就是想通知大家,所谓的“大端”、“小端”实际上可能无关计算机性能,更多的只是创造者们在创建计算机之初,代入了集体的一些约定俗成的习惯而已。 6、什么是网络字节序?6.1 字节序问题给网络通信带来的困扰对于搞网络通信利用(比方IM、音讯推送、实时音视频)开发的程序员来说,自已写通信底层的话是肯定会遇到大小端问题的,对于网络字节序这个知识点是肯定要必知必会。(当然,你要是很没谋求的认为,反正我公司就让租租第3方,能用就行,具体通底层怎么写我才不想掉头发去思考那么多。。。。 那哥也救不了你。。) ...

August 13, 2020 · 1 min · jiezi

关于即时通讯:Web端即时通讯实践干货如何让WebSocket断网重连更快速

本文作者网易智慧企业web前端开发工程师马莹莹。为了晋升内容品质,收录时有订正和改变。 1、引言在一个欠缺的即时通讯IM利用中,WebSocket是极其要害的一环,它为基于Web的即时通讯利用提供了一种全双工的通信机制。但为了晋升IM等理论利用场景下的音讯即时性和可靠性,咱们须要克服WebSocket及其底层依赖的TCP连贯对于简单网络状况下的不稳定性,即时通讯的开发者们通常都须要为其设计一套残缺的连贯保活、验活以及断片网重连计划。 就断网重连而言,其重连响应速度将重大影响了下层利用的“即时性”和用户体验。试想关上网络一分钟后,微信的网络不能即时感知到socket连贯的复原,无奈即时收发聊天音讯的话,是不是很解体? 因而,如何在简单网络场景下,更即时疾速地感知网络变动,并疾速复原WebSocket的可用性,就变得尤为重要。本文将基于笔者的开发实际,分享WebSocket在不同状态下、不同的网络状态下,应该如何实现疾速断网重连。 * 浏览对象:本文适宜有过IM底层网络理论开发教训,或者对底层网络实现有较深理解的开发者浏览。如果对底层网络理解甚少,倡议跳过本文,间接浏览网络本文开端附录局部的根底后再回头来看。 * 内容点评:本文内容没有高大上,但比拟干货,实用性较高,内容也很艰深,倡议可具体浏览。文中虽讲的是WebSocket,但思维能够延长利用到基于TCP协定的同类技术中。 本文已同步公布于“即时通讯技术圈”公众号,欢送关注: ▲ 本文在公众号上的链接是:点此进入,原文链接是:http://www.52im.net/thread-3098-1-1.html 2、准备常识本文中将要分享的内容是基于实际总结,如果你对Web端的即时通讯常识还一头雾水,务必先读:《新手入门贴:史上最全Web端即时通讯技术原理详解》、《Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE》。 限于篇幅,本文不会深究WebSocket技术细节,如有趣味请零碎学习: 《老手疾速入门:WebSocket扼要教程》《WebSocket详解(一):初步意识WebSocket技术》《WebSocket详解(二):技术原理、代码演示和利用案例》《WebSocket详解(三):深刻WebSocket通信协议细节》《WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)》《WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)》《WebSocket详解(六):刨根问底WebSocket与Socket的关系》3、疾速理解WebSocketWebsocket诞生于2008年,在2011年成为国际标准,当初所有的浏览器都已反对(详见《老手疾速入门:WebSocket扼要教程》)。它是一种全新的应用层协定,是专门为web客户端和服务端设计的真正的全双工通信协议,能够类比HTTP协定来理解websocket协定。 (图片援用自《WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)》) 它们的不同点: 1)HTTP的协定标识符是http,WebSocket的是ws;2)HTTP申请只能由客户端发动,服务器无奈被动向客户端推送音讯,而WebSocket能够;3)HTTP申请有同源限度,不同源之间通信须要跨域,而WebSocket没有同源限度。它们的相同点: 1)都是应用层的通信协议;2)默认端口一样,都是80或443;3)都能够用于浏览器和服务器间的通信;4)都基于TCP协定。两者和TCP的关系图: (图片援用自《老手疾速入门:WebSocket扼要教程》) 无关Http和WebSocket的关系,能够详读: 《WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)》《WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)》无关WebSocket和Socket的关系,能够详读:《WebSocket详解(六):刨根问底WebSocket与Socket的关系》. 4、WebSocket重连过程拆解首先思考一个问题,何时须要重连? 最容易想到的是WebSocket连贯断了,为了接下来能收发音讯,咱们须要再发动一次连贯。 但在很多场景下,即使WebSocket连贯没有断开,实际上也不可用了。 比方以下场景: 1)设施切换网络;2)链路两头路由解体(常识是一条socket连贯对应的网络通路上,会存在很多路由设施);3)链路的前端进口不可用(比方家庭WiFi中,网络连接失常,但理论运营商的宽带曾经欠费被停机);4)服务器负载继续过高无奈响应等。这些场景下的WebSocket都没有断开,但对下层来说,都没方法失常的收发数据了。 因而在重连前,咱们须要一种机制来感知连贯是否可用、服务是否可用,而且要能疾速感知,以便可能疾速从不可用状态中复原。 一旦感知到了连贯不可用,那便能够弃旧图新了,弃用并断开旧连贯,而后发动一次新连贯。这两个步骤看似简略,但若想达到快,且不是那么容易的。 首先:是断开旧连贯,对客户端来说,如何疾速断开?协定规定客户端必须要和服务器协商后能力断开WebSocket连贯,然而当客户端曾经分割不上服务器、无奈协商时,如何断开并疾速复原? 其次:是疾速发动新连贯。此快非彼快,这里的快并非是立刻发动连贯,立刻发动连贯会对服务器带来不可预估的影响。重连时通常会采纳一些退却算法,提早一段时间后再发动重连。但如何在重连距离和性能耗费间做出衡量?如何在“失当的工夫点”疾速发动连贯? 带着这些疑难,咱们来细看下这三个过程: 5、疾速重连要害1:疾速感知何时须要重连5.1 场景须要重连的场景能够细分为三种: 1)连贯明确断开了;2)连贯没断然而不可用了;3)连贯对端的服务不可用了。对于第一种场景:这很简略,连贯间接断开了,必定须要重连了。 对于后两者:无论是连贯不可用,还是服务不可用,对下层利用的影响都是不能再收发即时消息了。 5.2 心跳包被动探测网络可用性所以从下面这个角度登程,感知何时须要重连的一种简略粗犷的办法就是通过心跳包超时:发送一个心跳包,如果超过特定的工夫后还没有收到服务器回包,则认为服务不可用,如下图中左侧的计划(这种办法最间接)。 那如果想要疾速感知呢,就只能多发心跳包,放慢心跳频率。然而心跳太快对挪动端流量、电量的耗费又会太多,所以应用这种办法没方法做到疾速感知,能够作为检测连贯和服务可用的兜底机制。 5.3 被动监听网络状态扭转如果要检测连贯不可用,除了用心跳检测,还能够通过判断网络状态来实现,因为断网、切换wifi、切换网络是导致连贯不可用的最间接起因,所以在网络状态由offline变为online时,大多数状况下须要重连下,但也不肯定,因为webscoket底层是基于TCP的,TCP连贯不能敏锐的感知到应用层的网络变动,所以有时候即使网络断开了一小会,对WebSocket连贯是不会有影响的,网络复原后,依然可能失常地进行通信。 因而在网络由断开到连贯上时,立刻判断下连贯是否可用,能够通过发一个心跳包判断,如果可能失常收到服务器的心跳回包,则阐明连贯仍是可用的,如果期待超时后仍没有收到心跳回包,则须要重连,如上图中的右侧。这种办法的长处是速度快,在网络复原后可能第一工夫感知连贯是否可用,不可用的话能够疾速执行复原,但它只能笼罩应用层网络变动导致WebSocket不可用的状况。 5.4 小结综上所述: 1)定时发送心跳包检测的计划贵在稳固,可能笼罩所有场景,但速度不即时(心跳距离是固定的);2)判断网络状态的计划速度快,无需期待心跳距离,较为灵活,但笼罩场景较为局限。因而,咱们能够联合两种计划: 1)定时以不太快的频率发送心跳包,比方40s/次、60s/次等,具体能够依据利用场景来定;2)而后在网络状态由offline变为online时立刻发送一次心跳,检测以后连贯是否可用,不可用的话立刻进行复原解决。这样在大多数状况下,下层的利用通信都能较快从不可用状态中复原,对于少部分场景,有定时心跳作为兜底,在一个心跳周期内也可能复原。 6、疾速重连要害2:疾速断开旧连贯通常状况下,在发动下一次连贯前,如果旧连贯还存在的话,应该先把旧连贯断开。 这样做的目标: 1)一来能够开释客户端和服务器的资源;2)二来能够防止之后误从旧连贯收发数据。咱们晓得WebSocket底层是基于TCP协定传输数据的,连贯两端别离是服务器和客户端,而TCP的TIME_WAIT状态是由服务器端维持的,因而在大多数失常状况下,应该由服务器发动断开底层TCP连贯,而不是客户端。 也就是说: 1)要断开WebSocket连贯时,如果是服务器收到批示要断开WebSocket,那它应该立刻发动断开TCP连贯;2)如果是客户端收到批示要断开WebSocket,那它应该发信号给服务器,而后期待底层TCP连贯被服务器断开或直至超时。那如果客户端想要断开旧的WebSocket,能够分为WebSocket连贯可用和不可用两种状况来探讨。 具体如下: 1)当旧连贯可用时,客户端能够间接给服务器发送断开信号,而后服务器发动断开连接即可;2)当旧连贯不可用时,比方客户端切换了wifi,客户端发送了断开信号,然而服务器收不到,客户端只能迟迟期待,直至超时能力被容许断开。超时断开的过程相对来说是比拟久的,那有没有方法能够快点断开? 下层利用无奈扭转只能由服务器发动断开连接这种协定层面的规定,所以只能从应用逻辑动手,比方在下层通过业务逻辑保障旧连贯齐全生效,模仿连贯断开,而后在发动新连贯,复原通信。 这种办法相当于尝试断开旧连贯不行时,间接弃之,而后就能疾速进入下一流程,所以在应用时肯定要确保在业务逻辑上旧连贯已齐全生效。 比方: 1)保障丢掉从旧连贯收到所有数据;2)旧连贯不能妨碍新连贯的建设3)旧连贯超时断开后不能影响新连贯和下层业务逻辑等等。7、疾速重连要害3:疾速发动新连贯有IM开发教训的同学应该有所理解,遇到因网络起因导致的重连时,是万万不能立刻发动一次新连贯的,否则当呈现网络抖动时,所有的设施都会立刻同时向服务器发动连贯,这无异于黑客通过发动大量申请耗费网络带宽引起的拒绝服务攻打,这对服务器来说几乎是劫难(即:服务端雪崩效应)。 所以在重连时通常采纳一些退却算法,提早一段时间再发动重连,如下图中左侧的流程。 如果要疾速连上呢?最间接的做法就是缩短重试距离,重试距离越短,在网络复原后就能越快的复原通信。然而太频繁的重试对性能、带宽、电量的耗费就比较严重。 如何在这之间做一个较好的衡量呢? ...

August 5, 2020 · 1 min · jiezi

关于即时通讯:Web端即时通讯实践干货如何让WebSocket断网重连更快速

本文作者网易智慧企业web前端开发工程师马莹莹。为了晋升内容品质,收录时有订正和改变。 1、引言在一个欠缺的即时通讯IM利用中,WebSocket是极其要害的一环,它为基于Web的即时通讯利用提供了一种全双工的通信机制。但为了晋升IM等理论利用场景下的音讯即时性和可靠性,咱们须要克服WebSocket及其底层依赖的TCP连贯对于简单网络状况下的不稳定性,即时通讯的开发者们通常都须要为其设计一套残缺的连贯保活、验活以及断片网重连计划。 就断网重连而言,其重连响应速度将重大影响了下层利用的“即时性”和用户体验。试想关上网络一分钟后,微信的网络不能即时感知到socket连贯的复原,无奈即时收发聊天音讯的话,是不是很解体? 因而,如何在简单网络场景下,更即时疾速地感知网络变动,并疾速复原WebSocket的可用性,就变得尤为重要。本文将基于笔者的开发实际,分享WebSocket在不同状态下、不同的网络状态下,应该如何实现疾速断网重连。 * 浏览对象:本文适宜有过IM底层网络理论开发教训,或者对底层网络实现有较深理解的开发者浏览。如果对底层网络理解甚少,倡议跳过本文,间接浏览网络本文开端附录局部的根底后再回头来看。 * 内容点评:本文内容没有高大上,但比拟干货,实用性较高,内容也很艰深,倡议可具体浏览。文中虽讲的是WebSocket,但思维能够延长利用到基于TCP协定的同类技术中。 本文已同步公布于“即时通讯技术圈”公众号,欢送关注: ▲ 本文在公众号上的链接是:点此进入,原文链接是:http://www.52im.net/thread-3098-1-1.html 2、准备常识本文中将要分享的内容是基于实际总结,如果你对Web端的即时通讯常识还一头雾水,务必先读:《新手入门贴:史上最全Web端即时通讯技术原理详解》、《Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE》。 限于篇幅,本文不会深究WebSocket技术细节,如有趣味请零碎学习: 《老手疾速入门:WebSocket扼要教程》《WebSocket详解(一):初步意识WebSocket技术》《WebSocket详解(二):技术原理、代码演示和利用案例》《WebSocket详解(三):深刻WebSocket通信协议细节》《WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)》《WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)》《WebSocket详解(六):刨根问底WebSocket与Socket的关系》3、疾速理解WebSocketWebsocket诞生于2008年,在2011年成为国际标准,当初所有的浏览器都已反对(详见《老手疾速入门:WebSocket扼要教程》)。它是一种全新的应用层协定,是专门为web客户端和服务端设计的真正的全双工通信协议,能够类比HTTP协定来理解websocket协定。 (图片援用自《WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)》) 它们的不同点: 1)HTTP的协定标识符是http,WebSocket的是ws;2)HTTP申请只能由客户端发动,服务器无奈被动向客户端推送音讯,而WebSocket能够;3)HTTP申请有同源限度,不同源之间通信须要跨域,而WebSocket没有同源限度。它们的相同点: 1)都是应用层的通信协议;2)默认端口一样,都是80或443;3)都能够用于浏览器和服务器间的通信;4)都基于TCP协定。两者和TCP的关系图: (图片援用自《老手疾速入门:WebSocket扼要教程》) 无关Http和WebSocket的关系,能够详读: 《WebSocket详解(四):刨根问底HTTP与WebSocket的关系(上篇)》《WebSocket详解(五):刨根问底HTTP与WebSocket的关系(下篇)》无关WebSocket和Socket的关系,能够详读:《WebSocket详解(六):刨根问底WebSocket与Socket的关系》. 4、WebSocket重连过程拆解首先思考一个问题,何时须要重连? 最容易想到的是WebSocket连贯断了,为了接下来能收发音讯,咱们须要再发动一次连贯。 但在很多场景下,即使WebSocket连贯没有断开,实际上也不可用了。 比方以下场景: 1)设施切换网络;2)链路两头路由解体(常识是一条socket连贯对应的网络通路上,会存在很多路由设施);3)链路的前端进口不可用(比方家庭WiFi中,网络连接失常,但理论运营商的宽带曾经欠费被停机);4)服务器负载继续过高无奈响应等。这些场景下的WebSocket都没有断开,但对下层来说,都没方法失常的收发数据了。 因而在重连前,咱们须要一种机制来感知连贯是否可用、服务是否可用,而且要能疾速感知,以便可能疾速从不可用状态中复原。 一旦感知到了连贯不可用,那便能够弃旧图新了,弃用并断开旧连贯,而后发动一次新连贯。这两个步骤看似简略,但若想达到快,且不是那么容易的。 首先:是断开旧连贯,对客户端来说,如何疾速断开?协定规定客户端必须要和服务器协商后能力断开WebSocket连贯,然而当客户端曾经分割不上服务器、无奈协商时,如何断开并疾速复原? 其次:是疾速发动新连贯。此快非彼快,这里的快并非是立刻发动连贯,立刻发动连贯会对服务器带来不可预估的影响。重连时通常会采纳一些退却算法,提早一段时间后再发动重连。但如何在重连距离和性能耗费间做出衡量?如何在“失当的工夫点”疾速发动连贯? 带着这些疑难,咱们来细看下这三个过程: 5、疾速重连要害1:疾速感知何时须要重连5.1 场景须要重连的场景能够细分为三种: 1)连贯明确断开了;2)连贯没断然而不可用了;3)连贯对端的服务不可用了。对于第一种场景:这很简略,连贯间接断开了,必定须要重连了。 对于后两者:无论是连贯不可用,还是服务不可用,对下层利用的影响都是不能再收发即时消息了。 5.2 心跳包被动探测网络可用性所以从下面这个角度登程,感知何时须要重连的一种简略粗犷的办法就是通过心跳包超时:发送一个心跳包,如果超过特定的工夫后还没有收到服务器回包,则认为服务不可用,如下图中左侧的计划(这种办法最间接)。 那如果想要疾速感知呢,就只能多发心跳包,放慢心跳频率。然而心跳太快对挪动端流量、电量的耗费又会太多,所以应用这种办法没方法做到疾速感知,能够作为检测连贯和服务可用的兜底机制。 5.3 被动监听网络状态扭转如果要检测连贯不可用,除了用心跳检测,还能够通过判断网络状态来实现,因为断网、切换wifi、切换网络是导致连贯不可用的最间接起因,所以在网络状态由offline变为online时,大多数状况下须要重连下,但也不肯定,因为webscoket底层是基于TCP的,TCP连贯不能敏锐的感知到应用层的网络变动,所以有时候即使网络断开了一小会,对WebSocket连贯是不会有影响的,网络复原后,依然可能失常地进行通信。 因而在网络由断开到连贯上时,立刻判断下连贯是否可用,能够通过发一个心跳包判断,如果可能失常收到服务器的心跳回包,则阐明连贯仍是可用的,如果期待超时后仍没有收到心跳回包,则须要重连,如上图中的右侧。这种办法的长处是速度快,在网络复原后可能第一工夫感知连贯是否可用,不可用的话能够疾速执行复原,但它只能笼罩应用层网络变动导致WebSocket不可用的状况。 5.4 小结综上所述: 1)定时发送心跳包检测的计划贵在稳固,可能笼罩所有场景,但速度不即时(心跳距离是固定的);2)判断网络状态的计划速度快,无需期待心跳距离,较为灵活,但笼罩场景较为局限。因而,咱们能够联合两种计划: 1)定时以不太快的频率发送心跳包,比方40s/次、60s/次等,具体能够依据利用场景来定;2)而后在网络状态由offline变为online时立刻发送一次心跳,检测以后连贯是否可用,不可用的话立刻进行复原解决。这样在大多数状况下,下层的利用通信都能较快从不可用状态中复原,对于少部分场景,有定时心跳作为兜底,在一个心跳周期内也可能复原。 6、疾速重连要害2:疾速断开旧连贯通常状况下,在发动下一次连贯前,如果旧连贯还存在的话,应该先把旧连贯断开。 这样做的目标: 1)一来能够开释客户端和服务器的资源;2)二来能够防止之后误从旧连贯收发数据。咱们晓得WebSocket底层是基于TCP协定传输数据的,连贯两端别离是服务器和客户端,而TCP的TIME_WAIT状态是由服务器端维持的,因而在大多数失常状况下,应该由服务器发动断开底层TCP连贯,而不是客户端。 也就是说: 1)要断开WebSocket连贯时,如果是服务器收到批示要断开WebSocket,那它应该立刻发动断开TCP连贯;2)如果是客户端收到批示要断开WebSocket,那它应该发信号给服务器,而后期待底层TCP连贯被服务器断开或直至超时。那如果客户端想要断开旧的WebSocket,能够分为WebSocket连贯可用和不可用两种状况来探讨。 具体如下: 1)当旧连贯可用时,客户端能够间接给服务器发送断开信号,而后服务器发动断开连接即可;2)当旧连贯不可用时,比方客户端切换了wifi,客户端发送了断开信号,然而服务器收不到,客户端只能迟迟期待,直至超时能力被容许断开。超时断开的过程相对来说是比拟久的,那有没有方法能够快点断开? 下层利用无奈扭转只能由服务器发动断开连接这种协定层面的规定,所以只能从应用逻辑动手,比方在下层通过业务逻辑保障旧连贯齐全生效,模仿连贯断开,而后在发动新连贯,复原通信。 这种办法相当于尝试断开旧连贯不行时,间接弃之,而后就能疾速进入下一流程,所以在应用时肯定要确保在业务逻辑上旧连贯已齐全生效。 比方: 1)保障丢掉从旧连贯收到所有数据;2)旧连贯不能妨碍新连贯的建设3)旧连贯超时断开后不能影响新连贯和下层业务逻辑等等。7、疾速重连要害3:疾速发动新连贯有IM开发教训的同学应该有所理解,遇到因网络起因导致的重连时,是万万不能立刻发动一次新连贯的,否则当呈现网络抖动时,所有的设施都会立刻同时向服务器发动连贯,这无异于黑客通过发动大量申请耗费网络带宽引起的拒绝服务攻打,这对服务器来说几乎是劫难(即:服务端雪崩效应)。 所以在重连时通常采纳一些退却算法,提早一段时间再发动重连,如下图中左侧的流程。 如果要疾速连上呢?最间接的做法就是缩短重试距离,重试距离越短,在网络复原后就能越快的复原通信。然而太频繁的重试对性能、带宽、电量的耗费就比较严重。 如何在这之间做一个较好的衡量呢? ...

August 5, 2020 · 1 min · jiezi

关于即时通讯:IM开发干货分享有赞移动端IM的组件化SDK架构设计实践

本文由有赞技术团队原创分享,原题“有赞 APP IM SDK 组件架构设计”,即时通讯网收录时有订正和改变,感激原作者的自私分享。 1、引言本文次要以Android客户端为例,记录了有赞旗下 App 中应用自研 IM,并将IM提炼成组件化SDK的设计思路。此项工作由有赞挪动开发组 IM SDK 团队独特探讨实现。 在有赞产品中,存在大量须要交易单方沟通交流的场景,比方,客户征询商家产品信息,售前售后简略的答疑和维权等。另外,有赞业务还存在一些非凡的简单场景,如供应商、分销商、客户三方之间须要同步沟通,会同时存在多种沟通角色。 此时须要较为欠缺的即时通信(IM)解决方案,然而因为有赞针对不同的商户和应用场景有多个APP,APP自行实现IM性能代价较大,且保护起来人力扩散,于是,IM SDK我的项目便应运而生了,APP 通过接入此给件化SDK,能够疾速实现IM基本功能。 学习交换: - 即时通讯/推送技术开发交换5群:215477170[举荐]- 挪动端IM开发入门文章:《新手入门一篇就够:从零开发挪动端IM》本文已同步公布于“即时通讯技术圈”公众号,欢送关注: ▲ 本文在公众号上的链接是:https://mp.weixin.qq.com/s/ANp1kuj65Ww5RpABl2M9RQ,原文链接是:http://www.52im.net/thread-3088-1-1.html 2、相干文章《从游击队到正规军(一):马蜂窝旅游网的IM零碎架构演进之路》《从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实际总结》(* 举荐)《从游击队到正规军(三):基于Go的马蜂窝旅游网分布式IM零碎技术实际》《一套海量在线用户的挪动端IM架构设计实际分享(含具体图文)》《从零到卓越:京东客服即时通讯零碎的技术架构演进历程》《一套原创分布式即时通讯(IM)零碎实践架构计划》《蘑菇街即时通讯/IM服务器开发之架构抉择》《自已开发IM有那么难吗?手把手教你自撸一个Andriod版繁难IM (有源码)》《适宜老手:从零开发一个IM服务端(基于Netty,有残缺源码)》《拿起键盘就是干:跟我一起徒手开发一套分布式IM零碎》3、设计指标本次IM组件化SDK的设计指标有以下几点: 1)IM 主流程稳固可用:音讯传输具备高可靠性;2)UI 组件间接集成进入SDK,并反对可定制化;3)富媒体发送集成进入SDK,并可按需定制须要的富媒体类型;4)实现音讯传输层SDK,与带有UI的SDK的性能拆散,业务调用方既能够应用音讯传输SDK,解决音讯,而后自行处理UI,也能够应用带有UI组件的SDK,一步实现较为齐备的IM性能。4、整体构造下图中简要形容了有赞客户端中IM零碎的根本构造 : 如上图所示,各分层的职责分工如下: 1)音讯通道层:保护Socket长连贯作为音讯通道,音讯收发流程次要在这一层中实现;2)长久化层:次要将音讯存入数据库中,富媒体文件存入文件缓存中,不便第二次展现音讯时候,从本地加载,而不是网络层获取;3)逻辑解决层:实现各种音讯相干的逻辑解决,如排序,富媒体文件的预处理等;4)UI显示层:将数据在UI上进行出现。5、设计要点1:Socket长连贯的创立与保护IM SDK 所有数据收发流程,均通过Socket长连贯实现,如何保护一个稳固Socket通道,是IM零碎是否稳固的重要一环。  上面形容下Socket通道几个重要的流程。 1)创立流程(连贯) : 如图上所示,当IM SDK初始化后,业务调用连贯申请接口,会开始连贯的创立过程,创立胜利后,会实现鉴权操作,当创立和鉴权都实现后,会开启音讯收发线程,为了维持长连贯,会有心跳机制,特地的,会开启一个心跳轮询线程。 2)心跳机制 : 心跳机制,是IM零碎设计中的常见概念,简略的解释就是每隔若干工夫发送一个固定信息给服务端,服务端收到后及时回复一个固定信息,如果服务端若干工夫内没有收到客户端心跳信息则视客户端断开,同理如果客户端若干工夫没有收到服务端心跳回值则视服务端断开。    当长连贯创立胜利后,会开启一个轮询线程,每隔一段时间发送心跳音讯给服务器端,以维持长连贯。 无关IM心跳方面的专项文章,请见: 《手把手教你用Netty实现网络通信程序的心跳机制、断线重连机制》《为何基于TCP协定的挪动端IM依然须要心跳保活机制?》《挪动端IM实际:实现Android版微信的智能心跳机制》《挪动端IM实际:WhatsApp、Line、微信的心跳策略剖析》《一文读懂即时通讯利用中的网络心跳包机制:作用、原理、实现思路等》《正确理解IM长连贯的心跳及重连机制,并入手实现(有残缺IM源码)》《一种Android端IM智能心跳算法的设计与实现探讨(含样例代码)》《手把手教你用Netty实现网络通信程序的心跳机制、断线重连机制》3)重连流程 : 重连被触发时,如果该次连贯胜利,退出重连。反之重连失败后,会判断以后重连的次数是否超过预期值(这里设为6次),并对重连次数计数,如果超过就会退出重连,反之休眠预设的工夫后再次进行重连操作。 重连触发条件分为三种: a. 被动连贯不胜利(被动连贯Socket,如果连贯失败,会触发重连机制);b. 网络被被动断开(失常建设连贯,操作过程中,网络被断开,通过零碎播送触发重连);c. 服务器没响应,心跳没回值(服务端心跳预设工夫内没回值,客户端认为服务端曾经断开,触发重连)。无关重连机制的深刻学习,能够浏览以下两篇: 《正确理解IM长连贯的心跳及重连机制,并入手实现(有残缺IM源码)》《手把手教你用Netty实现网络通信程序的心跳机制、断线重连机制》4)网络状态判断: TCP API并没有提供一个牢靠的办法判断以后长连贯通道状态,isConnected()和isClosed()仅仅通知你以后的Socket状态,不是是长连贯断开是一回事。 isConnected()通知你是否Socket与Romote host放弃连贯,isClosed()通知你是否Socket被敞开。  如果你判断长连贯通道是否被敞开,只能通过和流操作相干的以下办法: a. read() return -1;b. readLine() return null;c. readXXX() throw EOPException for any other XXX;d. write 将抛出IOException: Broken pipe(通道被敞开)。所以SDK封装isConnected(办法的时候,是依据这几种状况综合判断以后的通道状态,而不是仅仅通过Socket.isConnected()或者Socket.isClosed()。 ...

July 29, 2020 · 2 min · jiezi

IM群聊消息的已读未读功能在存储空间方面的实现思路探讨

1、引言IM系统中,特别是在企业应用场景下,消息的已读未读状态是一个强需求。 以阿里的钉钉为例,钉钉的产品定位是用于商务交流,其“强制已读回执”功能,让职场人无法再“假装不在线”、“假装没收到”。更有甚者,钉钉的群聊“强制已读回执”功能,甚至能够知道谁读了消息,谁没有读消息(老板的福音啊)。 ▲ 钉钉里的群聊消息已读未读功能效果 功能看起来很酷,但用起来是一言难尽(上班族心里苦.... )。实际上,技术实现也并不容易。 那么,对于已读未读状态: 1)如果是私聊:消息的阅读状态比较容易实现,在性能和存储上也不存在问题;2)如果是群聊:考虑到存储和处理性能,特别当处于一个云环境时,如何高效地处理群聊的已读未读状态是一个非常值得探讨的话题。这里提到的“高效”含3个方面: 1)存储空间;2)处理速度;3)传输字节数。本文将从服务端的角度来探讨已读未读状态,在具体的技术实现上对于存储空间占用方面的思路差异。能力有限,权当个人笔记,欢迎交流。 学习交流: - 即时通讯/推送技术开发交流5群:215477170[推荐]- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》本文已同步发布于“即时通讯技术圈”公众号,欢迎关注: ▲ 本文在公众号上的链接是:https://mp.weixin.qq.com/s/yUkKPOBsdqLlxiFrGmwFRQ,原文链接是:http://www.52im.net/thread-3054-1-1.html 2、内容点评在收录本文前,Jack Jiang建议原作者对某些具体的技术点进行更深入的分享,但因作者工作较忙,本文中的某些关键技术点未来的及作进一步展开。 所以,本文可以作为IM聊天消息(主要是群聊)中已读未读功能的基本实现思路方面的参考,但不建议盲目迷信文中的结论或方案,避免被一些不够具体的技术指标而误导。 3、相关文章如果你还想了解更多有关IM群聊中已读未读功能的实现逻辑,可以进一步阅读干货文章《IM群聊消息的已读回执功能该怎么实现?》(强烈推荐)。 如果你对IM中的已读未读功能有产品方面的痛点困惑,可以参考一下微信对已读未读功能的设计定位,详见《IM热门功能思考:为什么微信里没有消息“已读”功能?》。 更多IM群聊技术方面的文章详见文本附录部分。 4、已读未读状态交互流程发送者发送的IM聊天消息,在接收者阅读消息后,是否要求阅读者通知已读,可能是由系统配置、组织配置、群组配置等决定,也可能由发送者根据业务需求决定。以下的讨论,均假设消息需要已读未读状态。 客户端与服务端之间,关于阅读状态的命令只需3个,每个命令含请求和应答。 4.1 通知消息已读(私聊、群聊通用)当小宝阅读了一条或若干条消息,需向服务端发送消息已读通知:“众爱卿发的x+y+z消息,朕已阅”。 服务端收到小宝的已读通知时,需完成以下事项: 1)存储消息的已读状态;2)返回应答给小宝;3)向已读列表的消息的原始发送者通知消息已读。对于第“3)”步: 1)私聊的场合,比较好理解,就是发送给私聊的对方;2)群聊的场合,可很不一样:因为小宝发送的已读消息列表,可能是由众爱卿发送的。考虑这种假设:张三、李四、王五发出的群聊消息,被小宝一下都阅读了,那么小宝发出的已读通知包含的消息列表,需要被IMS分解成3个已读通知(3个不同的消息列表),分别通知给张三、李四、王五,通知内容是“_爱卿(不含'"众")发的这些消息,朕已阅_”。下面是大致的逻辑流程图: 4.2 查询消息的未读人数(私聊、群聊通用)消息的发送者,加载消息列表到聊天窗口时,可能需要展示消息是否被已读。 对群聊而言,显示的信息可能是n人未读的提示,那么需要向服务端查询消息的未读人数,由于客户端可能在UI显示自己发出的多条消息,需支持一次请求查询多条消息。 以未读人数的方式来表示消息的阅读状态,统一了私聊、群聊的查询,使得客户端-服务端间的接口更简单,同时使客户端的实现逻辑更统一。 就像下面这样: 1)对于私聊:如果未读人数n>0,表示消息未读;2)对于群聊:直接显示n人未读即可,当然,当n等于0时表示全部已读。4.3 查询群消息的已读、未读人员清单(群聊)当客户端希望显示某一条群聊消息的已读、未读人员列表,需向服务端发起查询。 大致的逻辑流程图如下: 5、几种具体的已读未读状态存储思路探讨5.1 基本约定群聊的阅读状态比私聊复杂,因此这里着重讨论群聊的阅读状态。 假设群成员数是n,各个客户端立即IM服务端发送已读通知。服务端需存储每个人的阅读状态,包括那些未读的成员。由于群的成员清单可能变化,比如今天增加了一个成员,则昨天发的消息、与今天发的消息,其接收者列表不一样。 即: 1)同一个群的不同消息,对应的接收者列表可能不一样。2)换言之,每一条消息都需要记录完整的接收者列表和已读人员列表。为了方便讨论,本章假设群成员有640人为前提。 5.2 存储思路1每一条消息都维护: 1)接收人员列表receiver_list;2)已读人员列表read_list。具体是: 1)IM Server收到一条消息时,用全体群成员构建receiver_list;2)IM Server收到群成员对这条消息的已读通知时,将此成员加入到read_list。客户端获取此消息的数据: 1)当需要获取未读人数时,用receiver_list的个数减去read_list的个数;2)当需要获取已读、未读人员列表时,需用receiver_list减去read_list得到未读人员列表。那么,思路1每条消息的存储空间是: 640个ID + 不定数量的已读人员ID5.3 存储思路2每一条消息维护: 1)未读人员列表unread_list;2)已读人员列表read_list。具体是: 1)IM Server收到一条消息时,用全体群成员构建unread_list;2)IM Server收到群成员对这条消息的已读通知时,将此成员从unread_list移出,同时加入到read_list。客户端获取此消息的数据: 1)当需要获取未读人数时,直接计算unread_list的个数;2)当需要获取已读、未读人员列表时,直接返回unread_list和read_list。那么,思路2每条消息的存储空间是: 未读人员ID + 已读人员ID,合计640个ID思路2的实现,占用的空间是案1的0.5倍~1.0倍。即案2占用的空间少,但在每次收到客户端的已读通知时,比案1多了一个操作:从unread_list进行减员。 5.4 存储思路3(我的实现)5.4.1)探讨5.2节、5.3节的不足: 5.2节、5.3节这两种思路,都能满足功能需求,但存在巨大的存储浪费。 ...

July 2, 2020 · 1 min · jiezi

从游击队到正规军二马蜂窝旅游网的IM客户端架构演进和实践总结

一、引言移动互联网技术改变了旅游的世界,这个领域过去沉重的信息分销成本被大大降低。用户与服务供应商之间、用户与用户之间的沟通路径逐渐打通,沟通的场景也在不断扩展。这促使所有的移动应用开发者都要从用户视角出发,更好地满足用户需求。 论坛时代的马蜂窝,用户之间的沟通形式比较单一,主要为单纯的回帖回复等。为了以较小的成本快速满足用户需求,当时采用的是非实时性消息的方案来实现用户之间的消息传递。 随着行业和公司的发展,马蜂窝确立了「内容+交易」的独特商业模式。在用户规模不断增长及业务形态发生变化的背景下,为用户和商家提供稳定可靠的售前和售后技术支持,成为电商移动业务线的当务之急。 本文由马蜂窝电商业务 IM 移动端研发团队分享了马蜂窝电商业务 IM 移动端的架构演进过程,以及在IM技术力量和资源有限的情况下所踩过的坑等。 系列文章: 《从游击队到正规军(一):马蜂窝旅游网的IM系统架构演进之路》《从游击队到正规军(二):马蜂窝旅游网的IM客户端架构演进和实践总结》(* 本文)学习交流: - 即时通讯/推送技术开发交流5群:215477170 [推荐]- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》(本文同步发布于:http://www.52im.net/thread-2796-1-1.html) 二、设计思路与整体架构我们结合 B2C,C2B,C2C 不同的业务场景设计实现了马蜂窝旅游移动端中的私信、用户咨询、用户反馈等即时通讯业务;同时为了更好地为合作商家赋能,在马蜂窝商家移动端中加入与会话相关的咨询用户管理、客服管理、运营资源统计等功能。 目前 IM 涉及到的业务如下: 为了实现马蜂窝旅游 App 及商家 IM 业务逻辑、公共资源的整合复用及 UI 个性化定制,将问题拆解为以下部分来解决: 1)IM 数据通道与异常重连机制:解决不同业务实时消息下发以及稳定性保障; 2)IM 实时消息订阅分发机制:解决消息定向发送、业务订阅消费,避免不必要的请求资源浪费; 3)IM 会话列表 UI 绘制通用解决方案:解决不同消息类型的快速迭代开发和管理复杂问题。 整体实现结构分为 4 个部分进行封装,分别为下图中的数据管理、消息注册分发管理、通用 UI 封装及业务管理。 三、技术原理和实现过程3.1、通用数据通道对于常规业务展示数据的获取,客户端需要主动发起请求,请求和响应的过程是单向的,且对实时性要求不高。但对于 IM 消息来说,需要同时支持接收和发送操作,且对实时性要求高。为支撑这种要求,客户端和服务器之间需要创建一条稳定连接的数据通道,提供客户端和服务端之间的双向数据通信。 3.1.1 数据通道基础交互原理 为了更好地提高数据通道对业务支撑的扩展性,我们将所有通信数据封装为外层结构相同的数据包,使多业务类型数据使用共同的数据通道下发通信,统一分发处理,从而减少通道的创建数量,降低数据通道的维护成本。 常见的客户端与服务端数据交互依赖于 HTTP 请求响应过程,只有客户端主动发起请求才可以得到响应结果。结合马蜂窝的具体业务场景,我们希望建立一种可靠的消息通道来保障服务端主动通知客户端,实现业务数据的传递。目前采用的是 HTTP 长链接轮询的形式实现,各业务数据消息类型只需遵循约定的通用数据结构,即可实现通过数据通道下发给客户端。数据通道不必关心数据的具体内容,只需要关注接收与发送。 3.1.2 客户端数据通道实现原理 客户端数据通道管理的核心是维护一个业务场景请求栈,在不同业务场景切换过程中入栈不同的业务场景参数数据。每次 HTTP 长链接请求使用栈顶请求数据,可以模拟在特定业务场景 (如与不同的用户私信) 的不同处理。数据相关处理都集中封装在数据通道管理中,业务层只需在数据通道管理中注册对应的接收处理即可得到需要的业务消息数据。 3.2、消息订阅与分发在软件系统中,订阅分发本质上是一种消息模式。非直接传递消息的一方被称为「发布者」,接受消息处理称为「订阅者」。发布者将不同的消息进行分类后分发给对应类型的订阅者,完成消息的传递。应用订阅分发机制的优势为便于统一管理,可以添加不同的拦截器来处理消息解析、消息过滤、异常处理机制及数据采集工作。 3.2.1 消息订阅 业务层只专注于消息处理,并不关心消息接收分发的过程。订阅的意义在于更好地将业务处理和数据通道处理解耦,业务层只需要订阅关注的消息类型,被动等待接收消息即可。 ...

October 18, 2019 · 2 min · jiezi

拿起键盘就是干跟我一起徒手开发一套分布式IM系统

1、引言老读者应该还记得我在去年国庆节前分享过一篇《技术干货:从零开始,教你设计一个百万级的消息推送系统》,虽然我在文中有贴一些伪代码,依然有些朋友希望能直接分享一些可以运行的源码。好吧,质疑我穷我无话可说(因为是真穷。。),怀疑我撸码的能力那是绝对不行,所以这次准备拉起键盘大干一场——徒手撸套分布式IM出来!^_^! 本文记录了我开发的一款面向IM学习者的 IM系统——CIM(全称:CROSS-IM),同时提供了一些组件帮助开发者构建一款属于自己可水平扩展的 IM。 通过学习本文和CIM代码,你可以获得以下知识: 1)如何从头开发一套IM(CIM的客户有点弱,见谅见谅);2)如何设计分布式的IM架构;3)如何将你的分布式IM架构用代码和相关技术实现出来。本文配套的CIM源码地址: 主要镜像:https://github.com/crossoverJie/cim备用镜像:https://github.com/52im/cim以下文章与本文类似或相关,同样有助于您的IM开发入门: 《自已开发IM有那么难吗?手把手教你自撸一个Andriod版简易IM (有源码)》《适合新手:从零开发一个IM服务端(基于Netty,有完整源码)》《拿起键盘就是干:跟我一起徒手开发一套分布式IM系统》《浅谈IM系统的架构设计》《简述移动端IM开发的那些坑:架构设计、通信协议和客户端》《一套海量在线用户的移动端IM架构设计实践分享(含详细图文)》《一套原创分布式即时通讯(IM)系统理论架构方案》《一套高可用、易伸缩、高并发的IM群聊、单聊架构方案设计实践》* 友情提示:阅读本文和CIM源码,需要您具备一定的网络编程、IM理论等知识等,如果您还不具备这些,请先阅读《新手入门一篇就够:从零开发移动端IM》,完全来的及! 学习交流: - 即时通讯/推送技术开发交流5群:215477170[推荐]- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》(本文同步发布于:http://www.52im.net/thread-2775-1-1.html) 2、关于作者 crossoverJie(陈杰): 90后,毕业于重庆信息工程学院,现供职于重庆猪八戒网络有限公司。 3、运行演示本次特地录了两段视频演示(群聊、私聊),点击下方链接可以查看视频版 Demo。 CIM 私聊视频演示:https://www.bilibili.com/video/av39405821CIM 群聊视频演示:https://www.bilibili.com/video/av394055014、架构设计下面来看看具体的架构设计: 架构说明: 1)CIM 中的各个组件均采用 SpringBoot 构建;2)采用 Netty + Google Protocol Buffer 构建底层通信;3)Redis 存放各个客户端的路由信息、账号信息、在线状态等;4)Zookeeper 用于 IM-server 服务的注册与发现。整体主要由以下模块组成: 1)cim-server——IM 服务端:用于接收 client 连接、消息透传、消息推送等功能。支持集群部署;2)cim-forward-route——消息路由服务器:用于处理消息路由、消息转发、用户登录、用户下线以及一些运营工具(获取在线用户数等);3)cim-client——IM 客户端:给用户使用的消息终端,一个命令即可启动并向其他人发起通讯(群聊、私聊);同时内置了一些常用命令方便使用。5、逻辑流程图整体的流程也比较简单,流程图如下: 流程解释如下: 1)客户端向 route 发起登录;2)登录成功从 Zookeeper 中选择可用 IM-server 返回给客户端,并保存登录、路由信息到 Redis;3)客户端向 IM-server 发起长连接,成功后保持心跳;4)客户端下线时通过 route 清除状态信息。所以当我们自己部署时需要以下步骤: 1)搭建基础中间件 Redis、Zookeeper;2)部署 cim-server,这是真正的 IM 服务器,为了满足性能需求所以支持水平扩展,只需要注册到同一个 Zookeeper 即可;3)部署 cim-forward-route,这是路由服务器,所有的消息都需要经过它。由于它是无状态的,所以也可以利用 Nginx 代理提高可用性;4)cim-client 真正面向用户的客户端;启动之后会自动连接 IM 服务器便可以在控制台收发消息了。更多使用介绍可以参考快速启动。 ...

October 15, 2019 · 2 min · jiezi

融云技术分享解密融云IM产品的聊天消息ID生成策略

本文来自融云技术团队原创分享,原文发布于“融云全球互联网通信云”公众号,原题《如何实现分布式场景下唯一 ID 生成?》,即时通讯网收录时有部分改动。 1、引言对于IM应用来说,消息ID(或称序列号)是个看似不起眼,但非常重要的东西之一。 消息ID的使用贯穿了IM技术逻辑的方方面面,比如: 1)聊天消息的顺序保证;2)聊天消息QoS送达保证机制时的去重; 3)特定聊天消息的精确查找和匹配; 4)聊天消息的已读未读处理; 5)聊天消息的送达回执; 6)群聊消息的扩散读拉取标记; 7)... ... 但,IM系统高度个性化的特性(设计上没有统一的标准和思路),包括聊天消息ID的生成算法在内,每个产品都有自已的思路和考量。 常见的消息ID生成策略有: 1)UUID:这种方法简单直观,可以很好的保证唯一性,但对于技术洁癖的人来说ID长度会有点长; 2)使用时间戳长整数:这个最偷懒,用在吞吐量不大的场景下,凑活也能用,但存在重复的风险,也无法保证分布式下的唯一性; 3)使用twitter开源的snowflake算法:在分布式高并发的情况下,这也是个不错的选择; 4)按用户使用独立的ID生成空间生成顺序的ID:比如微信的消息序列号生成策略就很不错。 从某种意义上来讲,消息ID的生成策略决定了IM应用层某些功能实现的难易度,好的消息ID生成策略会让IM产品的开发越做越顺,反之越做越别扭。 本文要分享的是融云即时通讯云产品中的聊天消息ID生成算法和策略,一个19字节的ID就能包含:时间戳、消息类型、会话ID、序列号,小ID、大用途,值得借鉴! 免责申明:本文来自融云官方技术团队的分享,仅用于技术交流学习和研究目的,请勿用于非法用途,文中如涉及商业秘密,请告之我处理! 特别说明:仅出于技术研究和学习目的来分享此文,并未收取任何好处,所以此文不是广告,我也不是托。如有不妥,请告之! 学习交流: 即时通讯/推送技术开发交流5群:215477170[推荐]移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》 (本文同步发布于:http://www.52im.net/thread-27...) 2、相关文章《微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)》《微信技术分享:微信的海量IM聊天消息序列号生成实践(容灾方案篇)》 3、技术背景对于一套分布式部署的 IM 系统,要求每条消息的 ID 要保证在集群中全局唯一且按生成时间有序排列。如何快速高效的生成消息数据的唯一 ID ,是影响系统吞吐量的关键因素。 那么,融云是如何做到生成全局唯一消息 ID 的呢? 首先需要明确下 ID 生成的核心需求: 1)全局唯一; 2)有序。 4、设计思路融云消息数据的唯一 ID 长度采用 80 Bit。 每 5 个 Bit ,进行一次 32 进制编码,转换为一个字符,字符取值范围是:数字 “2 ~ 9 ”和字母“A ~ B”。其中,已经去掉容易造成肉眼混淆的,数字 0 和 1 (余下可用的数字是8个),及字母 O 和 I(余下可用的字母是24个),总可用字符就是32个(刚好可按32进制进行编码)。 ...

September 19, 2019 · 2 min · jiezi

互联网医疗的前世今生与未来

一、互联网医疗的这20年从20世纪90年代到现在,我们经历了PC时代、移动时代以及正在进入的物联时代,互联网医疗1.0也伴随着“大智云物移”行业的发展与相关政策的开放正式进入到2.0时代。笔者很荣幸作为一名行业大军中的参与者,一路伴随互联网医疗从萌芽期至今,也亲眼见证了互联网医疗行业从市场参与者、产品形态、社会影响力、政府政策等各方面的发展变化。例如:互联网医疗政策方面,从最开始禁止的态度,到现在的鼓励甚至强制要求;市场产品方面,从最开始的挂号预约APP到现在的贯穿诊前、诊中、诊后的互联网医疗应用;社会影响力方面,从最开始的无所适从到现在的无人不用。医疗是一个极其特别的行业,它关乎每个人的生命健康、关乎国计民生,它更显学术与严谨,是伴随人类从一颗受精卵到一把灰的特殊行业,因此医疗是一个值得认真探讨的课题。本篇文章将会从中国医疗的现状说起,深入讨论互联网与医疗的碰撞以及互联网医疗的未来。 二、中国医疗的现状与特点1.中国的患者、医院与医生因工作原因,去过全国很多医院,每次走进医院最大的感触就是:诸多行业中还是医院的“生意”好!尽管医生不爱笑,尽管医院很拥挤,不做营销不接受讲价,但大家生了病都会积极的过来聆听医生的“教诲”。中国的患者中有两类人:一类是“小病百度、大病手术”,病久了直接就得被转去三甲医院。另一类患者是感冒发烧都要跑到三甲医院挂个专家号看看。这两类患者都会导致三甲医院人满为患、基层医院医疗资源不能充分利用。另一方面,由于中国医疗体系、晋升体制等多重原因,导致优秀医学生、优质医生都聚集在大城市大医院,久而久之患者会觉得只有到三甲医院才能找到好医生,而基层医生太“水”容易耽搁病情。这种非良性循环会导致基层只能越来越“基层”。医院作为“市场”中罕见的“卖方”比“买方”强势的服务机构,一直是高高在上。中国的医院共细分为7个层级,分级的作用是满足不同层次、不同患者的需要。然而患者的求医心理以及其他多重因素,致使分级反而固化和扩大了这种差距,使得患者都往省会城市和直辖市的大医院走,患者就医导向混乱,最终造成患者流量分布不均,出现大医院和基层医院发展极其不均衡的现象。此外,由于医院科室多、流程多,且很多流程和制度陈旧、效率低,往往是“医生动动嘴、患者跑断腿”,这也是百姓对医院怨声载道主要来由。在相当长一段时期内,几乎所有医院均是“以药养医”,医生的价值体现、收入高低依赖于药品器械的使用量,医生所学多年的医学专业知识的价值被低估。长此以往导致现在很多患者无论看中医还是西医如果医生开的药太少,患者就会没有安全感,会觉得这医生是不是太“水”,这点儿药能不能把病吃好。2.中美医疗对比没有对比就没有伤害,为了更客观和具象的认识中国的医疗状况,我们随便感受几组中美医疗的扎心对比(以下数据来源于多方渠道,有兴趣的同学可以自行了解详细信息与数据):这些看似简单粗暴的数据,每一项都值得我们深入思考其背后的形成原因。表格中数据同时反应了发展中国家与发达国家很多方面的巨大差别,包括经济水平、医疗服务质量、标准化的临床水平、医疗科研水平、教育模式、医护收入与社会地位等方面。之所以拿中美医疗相关数据做对比,因为按照联合国定义,美国属于标准的发达国家,在各方面都领跑世界,而中国是高速发展中国家,很多方面急需改善和提升,需要向发达国家学习和看齐。3.中国医疗当下最根本矛盾结合中国医疗现状分析以及上面粗暴的数据对比不难发现:中国医疗目前最根本矛盾,是医疗各种资源总体供给短缺与人民群众日益增长的健康需求,通俗点来讲就是各种不足:医生不足、护士不足、医疗资源投入不足、人均可支配医疗费用不足等总体上的不足。当前的医疗资源总体供给与人民群众日益增长的健康需求不成正比,这是医疗体制、医患关系中存在的根本矛盾。因为这个最根本矛盾,引发了我们所看到的种种医疗问题和现象。 三、互联网与医疗的极端碰撞我们都说互联网波及到哪个行业,哪个行业就会被颠覆,已经颠覆的比如金融、零售、餐饮、制造、出行、通信等行业;正在颠覆的比如我们今天所谈的医疗行业。互联网只是一种网络,一种传输信息与数据的载体,最关键的是我们利用这张网来做什么事情。从某个角度来说,互联网和医疗是两个属性相反的极端行业,互联网是非常前沿、开放、共享、智能、重体验的代表,而医疗则是非常滞后、保守、严谨、封闭、伦理性的传统行业,这两个冰与火的极端行业将会碰撞出怎样的火花?1.看衰和看好的两拨人从互联网+医疗的萌芽期到今天,一直都有各种行业专家和资深从业者发表看衰或看好的见解与看法。笔者本人是看好的,但也不否认那些看衰的观点,哲学中讲世间万物都是对立统一的,凡事物都有其两面性。不同的人,不同的经历和背景,不同的认知过程,则看法不同。比如作为大城市的人很难看到现在一些偏远山路地区是如何用大屏视频做党建的,比如身处三甲医院聚集的一线城市很难知道多少农村的医疗条件是有多么的落后。在观点不同的两派人中,其中看衰派认为:互联网医疗喊了那么多年一直未见起色,泡沫较大,医疗相关参与者的利益链极其复杂很难被撼动,互联网医疗一直在医疗边缘游走无法深入核心地带,服务方、支付方、患者方的商业结构与地位也一直没有变化,所有的高潮呐喊与尝试都将是徒劳,互联网医疗最多只能是大医院扩张的工具。而看好派认为:受制于多种因素,不同时代发展速度不尽相同,比如不同工业时代所经历的时长并不相同,但不代表它没有在往前发展甚至可能已经悄然而至到下一个时代了。近些年随着“大智云物移”的蓬勃发展与互联网政策的逐渐明朗清晰,互联网医疗不再像以前那样始终只能游走于高墙之外,而是逐渐进入医院、进入体制。传统医疗的诸多诟病相信一定能通过互联网的方式来进行解决和改善,尤其当我们清晰的看到政府对互联网医疗的态度从懵逼到禁止、从观望到鼓励、直到现在很多省市区域已经开始实行强制性医疗互联网化建设考核指标这一现象。笔者对看衰派想表达的是,很多事情,因为我们时时刻刻身处在它的变化之中,所以你几乎感受不到它在变化,但并不代表它没有变化,推动这么一个古老陈旧的行业往前走实非易事也非一日之功。2.互联网如何切入并改善/解决医疗矛盾过去,车马慢,书信远。现如今,天涯咫尺。互联网从来不是去真正的“颠覆”医疗行业,它不会改变那些需要发生的关键行为,互联网是作为一种缩小空间与时间、改变方式方法、提升效率的工具出现,比如医生与病人的交流从必须面对面到现在可以通过互联网技术发展到远程视频通话与诊断。互联网医疗方式它使得多年的医疗诟病与根本矛盾得以改善。图-1是笔者对当下医疗根本矛盾与解决思路的粗浅分析,3种思路简单总结就是:合适的人做合适的事、增加资源总量、最大化“压榨”现有医疗资源。已经落地的分级诊疗、医联体、远程医疗、互联网医院等政策,基本就是这样的思路和目标。 图-1思路1中的分级诊疗策略,其关键点在于强制性和引导性的改变患者就医习惯,就是“小病去社区、大病去医院、康复回社区、慢病在社区”,合适的资源用到合适的位置。那么问题来了,短期内,在现有的基层医疗服务能力和患者对基层的信任度不足的情况下,如何过渡,确定小病还是大病或者说疑难杂症的判断与筛查,这时候就需要上下级医院之间充分的互动与信息数据共享,上级来协助基层将经验和理论知识下沉到基层,提升和强化基层的医疗服务能力,逐步帮扶基层起到真正的分流作用。这时候就需要借助互联网这个工具,除了需要医疗数据、患者病历等信息的共享,其他核心能力比如单方音视频通话、多方音视频通话、远程图文交流、远程彩超、远程心电等一系列远程医疗系统平台的搭建。可以想象,未来如果在家门口的社区诊所或药店就能找到好医生,还有多少人愿意舍近求远去拥挤不堪的大医院呢?思路2中,加快新晋医学生和年轻医生的成长速度,通过互联网有效、灵活的方式进行被动和主动式学习,在单位时间内快速增加可用的医生护士资源,从而解决医疗资源短缺的问题。例如目前在北京、上海、杭州已经有很多三甲医院通过内部视频直播、外部视频直播的方式进行临床经验的分享与交流,专家教授的医学讲座与手术示教直播让学生来观摩,建立了有效的经验分享、医学生学习渠道。中国护理杂志通过制作视频点播内容上传后供相关医生护士进行医学知识的学习,通过互联网的多重渠道与方式,有效的加速了医学知识与临床经验的分享与传播。思路3, 随着政策对大医院的控制和对基层的扶植日益加强,大医院的虹吸能力受限,但由于基层医院对病人的吸引力并不强,双方此时都到了比较尴尬的境地。医联体的出现就刚好满足了双方的发展需求:大医院帮助基层提升医疗服务能力,基层医院作为大医院的“延长触角”,可以在替大医院分流的情况下还能为大医院带来更多的患者流量,可谓一箭双雕、皆大欢喜。另外,由于互联网医院禁止线上出诊,这对于将医联体做大后大兴医院来说,可以拥有很多联合体内的下级医院对“自己”的患者进行出诊,病人只需要在基层医院挂号初诊后即可合法使用互联网医院服务。医联体模式中除了需要分级诊疗中那些互联网化的工具与系统,更加核心的需求是协同,它要求上级医疗机构、基层卫生服务机构、疾控机构、卫生管理机构等在信息化发展的基础上,探求信息的互联互通、业务紧密协同的智慧医疗服务。而协同的关键点在于信息数据的实时互通与共享,各医疗系统和流程的对接打通,例如医联体牵头医院通过搭建IM即时通讯与视频服务大平台,对接各兄弟医院的现有账号体系,在满足内部医患护沟通协作、医学交流的同时,进行兄弟医院的跨域互通、学术交流与联合会诊。在搭建过程中,国内一些云服务厂商例如网易云信,可以直接提供即时通讯能力,大大提高医院间的协同效率。武汉协和医院就是基于网易云信的平台搭建了多方联合会诊系统,进行日常的医疗协作与远程联合会诊,有效推动医联体策略的落地与实施,提升了武汉协和医院的服务效率与影响范围,最大化发挥现有资源的价值。2018年发布的《新规》对互联网医疗、互联网医院和远程医疗都做了明确的规范和指引,在政府政策鼓励、市场大趋势、以及互联网势不可挡的优势下,很多大型医院已经开始建设互联网医院,比如在线挂号预约、诊前咨询、自我诊断、电子报告、电子处方、诊间扫码支付、视频问诊、在院患者线上管理、医患互动、院后随访、患者教育与管理、远程家庭医生服务等等。互联网医院拥有更加人性化、更加注重患者体验的“基因”,且能有效的减轻医院人工工作量、提升医院工作效率、节省医院运营成本。通过互联网智慧医疗服务模式,借助互联网技术,构建线上客户服务体系,放大与提升医院的服务能力。 四、任重道远医疗行业的特殊性与现有市场结构,再加上多年的体制影响下,互联网医疗一定不会是靠着追风口的那三分钟热度与冲动就能做大做好的事情,也不是一年半载就能摸透或者轻易进去捞一笔钱的行业,它需要各方参与者以及社会全体共同努力与长期耕耘才能完成的大事。互联网医疗的发展一定会受到很多利益相关者的阻挠与怠慢,但历史的车轮从来不会因为任何人的消极缓慢而停止。积一时之跬步,臻千里之遥程,参与者只有从现在开始潜心沉淀,才能在未来的几万亿市场中获得重大的自我突破。 想要阅读更多技术干货、行业洞察,欢迎关注网易云信博客。了解网易云信,来自网易核心架构的通信与视频云服务。 网易云信(NeteaseYunXin)是集网易18年IM以及音视频技术打造的PaaS服务产品,来自网易核心技术架构的通信与视频云服务,稳定易用且功能全面,致力于提供全球领先的技术能力和场景化解决方案。开发者通过集成客户端SDK和云端OPEN API,即可快速实现包含IM、音视频通话、直播、点播、互动白板、短信等功能。

July 2, 2019 · 1 min · jiezi

从强提醒说起社交场景下的万有隐力

2018年的最后一天,微信推出了上线以来的第7个大版本:微信v7.0。在微信v7.0里,微信推出了三个大功能:即刻视频,好看和强提醒。分别代表了社交场景下的3个热点:流媒体、Timeline、即时通讯。作为一个即时通讯行业的从业者,看到“强提醒”这样的功能在微信上亮相,想和大家聊聊这背后的碰撞和演变。 打开新版微信,在你关心的联系人会话页面点击右上角,除了过去的置顶聊天和消息免打扰,新增了一个强提醒开关。打开开关,微信会将对方3小时内发送的第一条消息全屏提醒,并伴随着震动。无论你是打开了微信app。直到你点击“我知道了”。这样的设计,让人几乎无法错过这条消息的内容。 身边的许多朋友在第一时间体验了微信之后跟我讨论,说这样的交互形式,和之前微信尽量避免打扰的设计思路不同,“让我想起了被QQ‘窗口抖动’支配的恐惧。”有些朋友这样说。从我自己的理解角度,社交产品的设计思路,往往是在“安静”,“即时”,“丰富”三元素之间平衡的过程。稍不注意,则会顾此失彼:关注即时和丰富而忽视“安静“的应用,往往会遇到打扰用户导致app卸载数据上升的问题。微信自诞生以来,每个版本的设计理念,的确给人“Less is more”的感觉。宁可牺牲信息的丰富性,也绝不增加用户的打扰负担。 社交产品三元素 但,微信强提醒和QQ抖屏,除了在交互上给人的强烈感外,几乎完全不一样。 “隐力”作用二三事最早的QQ屏幕抖动,还是十多年前PC时代的桌面QQ。许多人会习惯挂着QQ,同时浏览网页、玩小游戏。当你发出的消息对方迟迟没有回复时,往往是因为对方没有注意右下角的闪烁。发送一条屏幕抖动,你的会话框会显示到最前,同时声音和屏幕开始抖动,强迫对方看到自己的消息。所以在功能逻辑上,微信强提醒是主动设置强提醒,而QQ抖屏则是被动接受对方的强提醒。这背后,就不得不提人与人之间的社交关系了。人是社会化的群居生物,俗话说“有人的地方就有江湖“,在人与人的社交行为当中,往往暗含着各种各样的”隐力“,它看不见摸不着,却无形中影响着人的社交行为:有的人隐力强大,有的人则相反。这就造成了在我们的社交行为中,除了有对等的社交关系外,往往还有不对等的社交关系。而社交应用,作为社交关系的互联网载体,也将这两种关系延申出来。“隐力”顾名思义,是指隐藏在社交关系中的作用力。在不对等的社交关系中,强势方对弱势方的“隐力”更强,表现出的主导性会更明显。更多的会使用“抖屏”这样的强制提醒功能,确保对方接受自己的信息。仔细回忆一下,是不是经常在社交网络上看到“客户爸爸”、“给大佬递茶”这样的表情包,这些本质上也是“隐力“不对等在社交应用上的体现。 那么问题来了,与现在很多人用QQ办公不同,早期的QQ更多服务于陌生网友、朋友同学这些对等社交关系下的IM场景,窗口抖动这么带有强制色彩,并体现了发送方“隐力”强于接收方特点的功能,是不是会和整体产品调性有出入呢?有些用户不想被动接收窗口抖动,会不会造成打扰?其实许多人不知道,窗口抖动的接收是可以关闭的,以TIM(办公版QQ)桌面端为例,点开设置界面,就有“允许接收窗口抖动”的选项,点击取消后,就不会收到窗口抖动了。 窗口抖动是IM应用内强制提醒的一种尝试。显然对于它可能带来的弊端,开发设计团队也提供了Plan B,在十多年前那个强调信息丰富和投递即时的年代,这样做也足够避免用户流失了。 与窗口抖动同时,还有另一个IM功能出现,叫做“已读回执”,已读回执诞生的背景,是早期IM消息投递到达率不高,为了确保消息到达,通过已读回执的形式,确保发送方知道接收方是否收到并打开了这条消息。随着IM技术愈发成熟,时至今日接入网易云信这样的IM云服务厂商,已经无需担心丢消息的现象,但这一功能依旧保存了下来。因为这一功能在办公场景下有了新的应用场景。并且衍生出了“群聊已读回执” 说起办公场景,就不得不说到“钉钉”这款产品。江湖传闻说,群已读回执、打卡、DING一下是钉钉用户最害怕的三个功能,作为办公IM应用,DING一下这个功能被设计的非常重:DING一下可以选择应用内、短信、电话的形式强制通知;接收方无需安装app,甚至无需开启移动数据就能接收;接收方接到电话,可以直接语音回复。 DING一下的应用场景,从催办流程,紧急找人到重要信息的传达,都体现了“隐力”作用:当领导传递重要指示时,DING一下,无论对方在做什么都能确保收到消息。而DING一下场景中,发送方的“隐力”显然更为强大,在不对等社交关系中,占据主动一方。这一点和微信强提醒恰恰相反。 随着移动互联网的普及,@TA功能也逐渐深入到社交场景当中。最开始是Twitter、FB、微博等Timeline产品,后来逐渐的BBS论坛、即时通讯app也都实现了这一功能。在QQ、微信等应用的群聊场景里,可以指定@对象为某个用户或某几个用户,对于群主还可以@全员,在微信里@全员的功能和发布群公告功能合二为一。 比起上面几种形式,@TA的交互更柔和:除了在联系人列表页的红色字体外,和普通的消息提醒逻辑并没有太大区别。这是因为@TA的定位是避免重要信息丢失在海量消息中:移动互联网时代的IM社交,每个人都有大量的群消息,许多群甚至做了免打扰处理,而@人功能可以确保重要信息能正常提醒,而又非完全强制的形式。这也体现了当前互联网社交生态圈里,“安静不打扰”的重要程度在不断上升。 设计思路的转变 以强制性强弱和设置方在社交关系中的“隐力”强弱,我们建立二维坐标系。可以看到,上面提到的四个IM强制提醒功能各不相同:DING一下和窗口抖动,显然设置方更为强势一些,强制性也非常强,@TA作为同类产品,强制性弱,发送方和接收方的“隐力”关系相对平等,而微信强提醒则完全处于另一个象限:设置方处于“隐力”关系弱势,强制性也非常强。所幸的是,即便强提醒的产品设计给人一种“自虐”功能的印象,对于提醒尺度上,微信可以说是小心翼翼:设置的强提醒仅对设置后的第一条消息生效;3个小时后没有收到消息,强提醒自动取消,从功能上,并不会给设置方带来消息提醒打扰。 最后我整理了一下几种功能的详细对比。目前大部分app的即时通讯服务都会选择由网易云信等IM云服务商提供技术能力,所以在技术实现上,可以说没有太多后顾之忧。如果你的app也想在社交场景上玩些新套路,欢迎我们一起交流沟通。虽然我们很难改变世界,但世界的确因我们每个人的努力而改变! 想要阅读更多技术干货文章,欢迎关注网易云信博客。了解网易云信,来自网易核心架构的通信与视频云服务。__网易云信(NeteaseYunXin)是集网易18年IM以及音视频技术打造的PaaS服务产品,来自网易核心技术架构的通信与视频云服务,稳定易用且功能全面,致力于提供全球领先的技术能力和场景化解决方案。开发者通过集成客户端SDK和云端OPEN API,即可快速实现包含IM、音视频通话、直播、点播、互动白板、短信等功能。

June 28, 2019 · 1 min · jiezi

BBR在实时音视频领域的应用

小议BBR算法 BBR全称Bottleneck Bandwidth and RTT,它是谷歌在2016年推出的全新的网络拥塞控制算法。要说明BBR算法,就不能不提TCP拥塞算法。 传统的TCP拥塞控制算法,是基于丢包反馈的协议。基于丢包反馈的协议是一种被动式的拥塞控制机制,其依据网络中的丢包事件来做网络拥塞判断。即便网络中的负载很高时,只要没有产生拥塞丢包,协议就不会主动降低自己的发送速度。 TCP在发送端维护一个拥塞窗口cwnd,通过cwnd来控制发送量。采用AIMD,就是加性递增和乘性递减的方式控制cwnd,在拥塞避免阶段加性增窗,发生丢包则乘性减窗。这个拥塞控制算法的假定是丢包都是拥塞造成的。 TCP拥塞控制协议希望最大程度的利用网络剩余带宽,提高吞吐量。然而,由于基于丢包反馈协议在网络近饱和状态下所表现出来的侵略性,一方面大大提高了网络的带宽利用率;但另一方面,对于基于丢包反馈的拥塞控制协议来说,大大提高网络利用率同时意味着下一次拥塞丢包事件为期不远了,所以这些协议在提高网络带宽利用率的同时也间接加大了网络的丢包率,造成整个网络的抖动性加剧。TCP拥塞控制算法的假定是丢包都是拥塞造成的,而事实上,丢包并不总是拥塞导致,丢包可能原因是多方面,比如:路由器策略导致的丢包,WIFI信号干扰导致的错误包,信号的信噪比(SNR)的影响等等。这些丢包并不是网络拥塞造成的,但是却会造成TCP 控制算法的大幅波动,即使在网络带宽很好的情况下,仍然会出现发送速率上不去的情况。比如长肥管道,带宽很高,RTT很大。管道中随机丢包的可能性很大,这就会造成TCP的发送速度起不来。 Google 的BBR出现很好的解决了这个问题。BBR是一种基于带宽和延迟反馈的拥塞控制算法。它是一个典型的封闭反馈系统,发送多少报文和用多快的速度发送这些报文都是每次反馈中不断调节。BBR算法的核心就是找到两个参数,最大带宽和最小延时。最大带宽和最小延时的乘积就是BDP(Bandwidth Delay Product), BDP就是网络链路中可以存放数据的最大容量。知道了BDP就可以解决应该发送多少数据的问题,而网络最大带宽可以解决用多大速度发送的问题。如果网络比作一条高速公路,把数据比作汽车,最大带宽就是每分钟允许通行的汽车数量,最小RTT就是没有拥堵情况下,汽车跑一个来回需要的时间,而BDP就是在这条路上排满汽车的数量。 BBR如何探测最大带宽和最小延时BBR是如何探测最大带宽和最小延时呢?首先有一点就是最大带宽和最小延时是无法同时得到的。 如图所示,横轴是网络链路中的数据量,纵轴分别是RTT和带宽。可以发现在RTT不变的时候,带宽一直在上升,没有达到最大,因为这个时候网络没有拥塞,而带宽停止上涨的时候RTT持续变大,一直到发生丢包。因为这个时候,网络开始拥塞,报文累积在路由器的buffer中,这样延时持续变大,而带宽不会变大。图中BDP的竖线所标识的就是理想情况下最大带宽和最小延时。很明显,要找到BDP, 很难在同一时刻找到最小的RTT和最大带宽。这样最小RTT和最大带宽必须分别探测。探测最大带宽的方法就是尽量多发数据,把网络中的buffer占满,带宽在一段时间内不会增加,这样可以得到此时的最大带宽。探测最小RTT的方法就是尽量把buffer腾空,让数据交付延时尽量低。由此,BBR就引入了基于不同探测阶段的状态机。 状态机分为4个阶段,Startup,Drain,ProbeBW, ProbeRTT。Startup类似于普通拥塞控制里的慢启动,增益系数是 2ln2,每一个来回都以这个系数增大发包速率,估测到带宽满了就进入 Drain状态,连续三个来回,测得的最大瓶颈带宽没有比上一轮增大 25%以上,就算带宽满了。进入 Drain状态,增益系数小于 1,也就降速了。一个包来回,把 Startup状态中产生的拍队排空,怎样才算队列空了?发出去还没有 ACK 的数据包量 inflight,与 BDP 进行比较,inflight < BDP 说明空了,道路不那么满了,如果 inflght > BDP 说明还不能到下一个状态,继续 Drain。ProbeBW是稳定状态,这时已经测出来一个最大瓶颈带宽,而且尽量不会产生排队现象。之后的每个来回,在 ProbeBW状态循环(除非要进入下面提到的 ProbeRTT状态),轮询下面这些增益系数,[5/4, 3/4, 1, 1, 1, 1, 1, 1],如此,最大瓶颈带宽就会在其停止增长的地方上下徘徊。大部分时间都应该处于 ProbeBW状态。前面三种状态,都可能进入 ProbeRTT状态。超过十秒没有估测到更小的 RTT 值,这时进入 ProbeRTT状态,把发包量降低,空出道路来比较准确得测一个 RTT 值,至少 200ms 或一个包的来回之后退出这个状态。检查带宽是否是满的,进入不同的状态:如果不满,进入 Startup状态,如果满,进入 ProbeBW状态。BBR算法不会因为一次或者偶然的丢包就大幅降低吞吐量,这样就比TCP就有较强的抗丢包能力。 如图所示,cubic在丢包率上升的时候,吞吐量下降很快。而BBR在5%以上的丢包才会出现明显的吞吐量下降。BBR与基于丢包反馈的cubic和基于延时反馈的vegas算法的本质区别在于,BBR无视随机丢包,无视时延短暂波动,采用了实时采集并保留时间窗口的策略,保持对可用带宽的准确探知。事实上,丢包并不一定会造成带宽减少,延迟增加也不一定会造成带宽减少,cubic无法判断是否拥塞造成的丢包,vegas对延时增加过于敏感,会导致竞争性不足。BBR可以区分出噪声丢包和拥塞丢包,这样意味着,BBR比传统TCP拥塞控制算法具有更好的抗丢包能力。 BBR在实时音视频领域的应用实时音视频系统要求低延时,流畅性好,而实际网络状态却是复杂多变的,丢包,延时和网络带宽都在时刻变化,这就对网络拥塞控制算法提出了很高的要求。它需要一种带宽估计准确,抗丢包和抖动能力好的拥塞控制算法。目前Google的webrtc提供了GCC控制算法,它是一种发送侧基于延迟和丢包的控制算法,这个算法的原理在很多地方都有详细描述,这里不再赘述。GCC用于实音视频的主要问题还在于在带宽发生变化时,它的带宽跟踪时间比较长,这样就会造成带宽突变的时候无法及时准确探测带宽,可能造成音视频卡顿。既然BBR有良好的抗丢包能力,自然也被想到应用到实时音视频领域。但是,BBR并不是为处理实时音视频设计的,所以需要对一些问题做一些优化。第一,BBR在丢包率达到25%以上,吞吐量会断崖式下降。这是由BBR算法的pacing_gain数组[5/4, 3/4, 1, 1, 1, 1, 1, 1]的固定参数决定的。在pacing_gain数组中,其增益周期的倍数为5/4,增益也就是25%,可以简单理解为,在增益周期,BBR可以多发送25%的数据。在增益期,丢包率是否抵消了增益比25%?也就是说,x是否大于25。假设丢包率固定为25%,那么,在增益周期,25%的增益完全被25%的丢包所抵消,相当于没有收益,接下来到了排空周期,由于丢包率不变,又会减少了25%的发送数据,同时丢包率依然是25%...再接下来的6个RTT,持续保持25%的丢包率,而发送率却仅仅基于反馈,即每次递减25%,我们可以看到,在pacing_gain标识的所有8周期,数据的发送量是只减不增的,并且会一直持续下去,这样就会断崖式下跌。 怎样才能对抗丢包,这就需要在每个周期考虑丢包率,把丢包率补偿进去。比如丢包率达到25%的时候,增益系数就变成50%,这样就可以避免由于丢包带来的反馈减损,然而,你又如何判断这些丢包是噪声丢包还是拥塞丢包呢?答案在于RTT,只要时间窗口内的RTT不增加,那么丢包就不是拥塞导致的。第二,BBR的最小RTT有个10s超时时间,在10s超时后,进入ProbeRTT 状态,并持续最小200ms,此状态下,为了排空拥塞,inflight只允许有4个包,这会导致音视频数据在这段时间内堆积在发送队列中,使得时延增加。可行的解决办法是,不再保留ProbeRTT状态,采用多轮下降的方式排空拥塞,然后采样最小RTT,也就是在infight > bdp的时候,设置pacing gain为0.75,用0.75倍带宽作为发送速率,持续多轮,直到inflight < bdp, 此外,最小RTT的超时时间改成2.5s,也就是说不采用非常激进的探测方式,避免了发送速率的大幅波动,可以改善探测新的带宽过程中发送队列中产生的延时。第三,开始提到pacing gain数组上探周期为1.25倍带宽,随后是0.75倍带宽周期,这两个RTT周期之间会出现发送速率的剧烈下降,这可能会使音视频数据滞留在buffer中发不出去,引入不必要的延时。解决办法可以考虑减小上探周期和排空周期的幅度,比如使用[1.1 0.9 1 1 1 1 1 1]这种pacing gain参数,这样做的优点就是可以保证媒体流的平稳发送,发送速率不会大幅波动,缺点是,网络带宽改善的时候,上探时间会变长。第四,BBR探测新带宽收敛慢的问题原始的BBR算法的收敛性受到pacing gain周期影响,带宽突降的时候,BBR需要多个轮次才会降到实际带宽。这是由于BBR每轮只能降速一次,而pacing gain的6个RTT的保持周期大大加长了这个时间。解决的办法就是随机化pacing gain的6个保持周期,如果是0.75倍周期,就一次降速到位,这样可以极大的减少BBR的收敛时间。最后,BBR算法看似简单,但是应用到实时音视频却没有那么简单,需要大量的实验优化,谷歌也在webrtc中引入BBR,目前仍在测试中。本文提到的改进方法是网易云信在这方面的一些尝试,希望能够抛砖引玉,有更多有兴趣的人能够为BBR应用到实时音视频领域出力。 ...

June 28, 2019 · 1 min · jiezi

技术详解实现互动直播全过程

本文主要整理互动直播中各端的逻辑,重点是与前端相关的教师端IM的部分和Web/Wap学生端。希望通过这份整理,对于前端在维护时可以尽快的理解互动直播的流程,提高项目的可维护性;对于客户端和教师端来说,可以了解到前端提供的接口和消息的实现。也能提高对整个请麦过程的理解,便于联调和后期的定位问题。 相关阅读推荐《连麦互动直播方案全实践1:什么是连麦互动直播?》《连麦互动直播方案全实践2:网易云信连麦互动直播方案的演变过程》《连麦互动直播方案全实践3:网易云信连麦互动的实现方案》 概 况互动直播涉及到服务端,教师客户端,iOS/Android学生端,Web/Wap学生端。本文重点介绍的是请麦的交互流程,前端请麦模块的设计,前端互动和聊天组件的设计。对于聊天室本身的聊天功能的实现,因为接入云信IM SDK,主要是通过Api调用封装实现的,就不细说了。在设计系统之前,首先需要考虑以下几个问题:• 各端的需求定义以及功能划分,各端如何交互• 各端之间的协议• 客户端请麦与教师端接收• 客户端进入互动直播房间后互动信息的同步带着以上几个问题,我们先整理一下可以依赖的的服务,通过网易云提供的以下服务如下图所示,结合自有系统的需求设计,让我们能迅速集成IM和互动直播的功能。• 云信IM服务提供了一整套即时通讯基础能力,可以将即时通讯、实时网络能力快速集成至企业自身应用中。• 云信的互动直播功能,支持主播和观众实时连麦互动。 架 构我们的基本需求主要是以下三部分: 学生在App客户端进入聊天室,可以发起请麦;在教师端可以对学生的请麦进行同意或拒绝的处理;在教师同意某位学生的请麦后,这位学生可以进入直播间进行互动。结合需求整理出以下的基本请麦,连麦,互动的流程, 如下图,不同样式的数据流向代表不同的协议。 这里有几个概念补充介绍一下:1、客户端云信IM的SDK,客户端通过云信IM发送P2P消息到教师端2、客户端互动直播SDK,客户端接入互动直播3、教师端云信SDK,接受p2p消息4、教师端互动直播SDK,与客户端直播互动5、Web端云信IM的SDK,发送接收消息6、自定义消息,各端发送信息的数据结构 设计与实现实现这节主要介绍上一节概述中提到的教师客户端 ,Web/Wap学生端的实现。主要包括以下几部分:流程细化、教师IM模块、Web学生端模块、配置、优势、存在的问题。 流程细化 先来介绍一下教师端的实现,按照下图中的标号顺序,对其中的一些细节做补充说明。教师端主要有两部分,一部分是native,本文中称为教师端native,另一部分是Web页面,本文中称为教师IM。教师端native和教师IM通过jsbridge以及自定义消息进行通信。首先,整理一下教师端native与教师IM通信的jsbridge如下: notifyQueueChangenotifyVolumenotifyCustomMsgcheckUpdatenotifyLiveStatus结合以上的流程图,再对流程进行一下细化说明:1、客户端初始化各端通过请求服务端获取统一的聊天室地址2、教师端初始化教师IM,在初始化后,通过服务端请求(getPresenterLiveInfo),获取聊天室地址,取得聊天室单例,通知教师端native聊天室就绪,获取互动直播数据。3、请麦的过程• 客户端发送p2p消息到教师端native,教师端native通过jsbridge, 调用教师IM的notifyCustomMsg,教师IM更新自身维护的请麦请求等待队列。• 教师IM点击同意或拒绝,通过消息通知教师端native,教师端native通过P2P通知请麦的客户端• 客户端通过互动直播SDK,连麦进入直播间,通过互动直播SDK发送消息给教师端native• 教师端native调用notifyQueueChange方法,更新教师IM中各列表• 教师IM,异步请求(informServer)更新服务端上下麦队列,发送自定义消息(im-sdk),广播通知各客户端。 教师IM模块结合流程图以及上面的流程细化说明,对前端的模块进行设计和拆分,如下图。 这里的LivePcChat是Tab中的聊天组件,LiveInteractivePresenter是处理互动操作的组件,XXcache是封装对应数据层操作的组件。具体的组件实例,调用,数据请求和处理的过程,如下图所示的时序图: Web学生端模块对于Web/Wap学生端,因为Web/Wap学生端本身还未开发请麦的功能。这里以Web学生端为例介绍一下Web/Wap学生端在互动列表和聊天互动中的实现。本身聊天室部分与教师端的聊天室是复用聊天组件的,因而这里也先把模块划分一下。可以参考教师端的组件划分,对比一下教师端和学生端复用的部分组件,下图是web学生端的组件拆分。 从下表的对比可以看到,除了请麦相关的处理逻辑,教师端IM和Web学生端在IM的其他功能是可以复用的。 配置互动直播是在原来的直播基础上做的迭代,所以这里要保证互动直播在教育各产品线的可配置性。这里所说的配置与教育公共组件池其他的模块和组件接入的配置类似,也是依赖于教育通用组件cache-base,通过在直播页面或者工程单页加载时(机构后台),读取config中的配置,一键配置。 优劣分析采用这套设计的优点是1、所有的服务端请求都是通过web页面发送,减少教师端维护的成本;2、模块的可配置性,在不同的业务线,可以通过配置来决定是否接入互动直播;3、组件颗粒化,在不同的模块中,教师端可以接入聊天组件和互动组件,请麦组件,学生端可以只接入互动列表组件;4、最大程度的依赖了现有的云信sdk实现的功能,能在较短的时间实现需求。 存在的问题1、请麦的流程比较复杂,因为涉及到多端,各端调试比较浪费时间,这也是整理此文的目的。在打通对各端流程的认识后,各端在调试中都能首先定位到出问题的端,然后才能有的放矢的在某一个环节中发现问题。2、因为是在原来的迭代基础上进行的,很多组件没有封装成教育规范的组件,不过逻辑清晰的前提下,可以在后面的迭代中优化掉。3、优化前端实现的方法。 总 结通过本文整理一下互动直播中各端的逻辑,便于后期接入对互动直播流程的理解。对客户端和教师端来说,可以了解到前端提供的接口和消息的实现。如果在后续另外的工程中,需要接入互动直播模块,能够快速的接入和调试,同时可以就以上提出来的存在的问题做进一步优化。 另外,想要获取更多产品干货、技术干货,记得关注网易云信博客。

June 26, 2019 · 1 min · jiezi

视频编解码的理论和实践2Ffmpeg视频编解码

近几年,视频编解码技术在理论及应用方面都取得了重大的进展,越来越多的人想要了解编解码技术。因此,网易云信研发工程师为大家进行了归纳梳理,从理论及实践两个方面简单介绍视频编解码技术。 相关阅读推荐《视频直播关键技术:流畅、拥塞和延时追赶》《视频直播技术详解:直播的推流调度》《音视频通话:小议音频处理与压缩技术》《视频编解码的理论和实践1:基础知识介绍》 1、Ffmpeg介绍《视频编解码的理论和实践1:基础知识介绍》介绍了视频编码的基础知识,本篇文章,我们一起看看实际应用中的视频编码是如何操作的。在实际工程项目中,ffmpeg是应用最多的多媒体处理框架,它提供了音视频采集、编解码、图像处理,格式转换等功能,并且拥有很强的扩展能力,通过ffmpeg可以很容易集成第三方库(例如:x264、openh264等),通过这种能力,它可以实现更强大的功能。Ffmpeg由下面几个部分构成:Libavformat:音视频格式处理Libavcodec:音视频编解码Libavfilter:音视频滤镜Libavdevice:音视频设备采集Libswscale:图像缩放、转换Libswresample:音频重采样Ffmpeg:一个命令行的转码工具Ffplay:一个命令行播放器Ffprobe:简单的媒体格式分析工具 2、Ffmpeg视频编码视频编码是ffmpeg提供的基本功能之一,通过ffmpeg可以很容易实现视频编码操作。使用ffmpeg进行视频编码之前需要把x264、openh264等第三方编解码库集成到ffmpeg中才能使用。编码步骤如下:(1) 注册编码器(2) 根据名字或者ID查找你想使用的编码器(例如x264、x265、openh264等)(3) 创建一个编码器上下文对象(4) 在编码器上下文对象中设置编码器参数(5) 打开编码器(6) 读取一帧图像进行编码,一直重复该过程,直到处理结束(7) 关闭编码器示例代码如下:avcodec_register_all(); // 注册所有可用的编码器codec = avcodec_find_encoder_by_name(“libx264”); // 查找编码器ctx = avcodec_alloc_context3(codec); // 创建编码器上下文ctx->width = 1280; // 设置编码器参数ctx->height = 720;// ….其他的参数设置avcodec_open2(ctx, codec, NULL); // 打开编码器while(read_frame(frame)){ AVPacket pkt; // 存放编码之后的数据int got_output = 0; // 是否成功编码得到一个图像avcodec_encode_video2(ctx, &pkt, frame, &got_output); // 编码if(got_output){ // 得到编码后的数据,进行后续操作}}avcodec_free_context(&ctx); // 关闭编码器 可以看到,ffmpeg隐藏了大部分的编码细节,调用者不需要了解预测、变换、量化、熵编码等细节,这些细节都已经被ffmpeg封装好了,开发者只要把编码参数设置好,然后调用相关的接口函数,即可实现视频编码功能。当然,这知识最基本的编码功能,要想在画面质量和压缩率之间取得平衡,必须了解视频编码的细节,然后设置相应的参数。 3、Ffmpeg视频解码Ffmpeg自带了H264的视频解码器,开发者可选择直接使用ffmpeg自带的H264解码器或者第三方的解码库进行视频解码。和视频编码一样,解码操作的大部分细节都已经被ffmpeg隐藏起来了,开发者只需要设置好相关的解码参数,然后调用接口函数就可以实现解码功了。解码流程如下:(1) 注册解码器(2) 查找解码器(3) 创建解码器上下文对象(4) 设置解码参数(5) 打开解码器 (6) 读取数据进行解码,直到结束(7) 关闭解码器代码示例如下:avcodec_register_all(); //注册解码器codec = avcodec_find_decoder_by_name(“h264”); // 查找解码器ctx = avcodec_alloc_context3(codec); // 创建解码器上下文对象//…设置解码参数avcodec_open2(ctx, codec, NULL); // 打开解码器while(read_packet(pkt)){ ...

June 26, 2019 · 1 min · jiezi

视频编解码的理论和实践1基础知识介绍

近几年,视频编解码技术在理论及应用方面都取得了重大的进展,越来越多的人想要了解编解码技术。因此,网易云信研发工程师为大家进行了归纳梳理,从理论及实践两个方面简单介绍视频编解码技术。 相关阅读推荐《视频直播关键技术:流畅、拥塞和延时追赶》《视频直播技术详解:直播的推流调度》《音视频通话:小议音频处理与压缩技术》 1、视频介绍视频的本质是图像序列,根据视觉暂留的原理,每秒播放20~25张图像,就会形成连续平滑的视觉效果,人眼将无法区分其中单幅的图像,就这样连续的画面叫做视频。每秒播放的图像数量叫作帧率。图像是由像素构成的,在彩色图像中,每个像素由R、G、B三个分量构成,每个分量用一个字节存储。分辨率用于描述图像的尺寸,例如分辨率1280x720就表示图像宽度是1280个像素、高度是720个像素。 2、压缩视频的原因为什么要对视频进行压缩?假如有一段时长为60秒视频,它的分辨率是1280x720,帧率是25,那么这段视频的大小等于:60 x 25 x 1280 x 720 x 3 = 4147200000字节,大约是3955MB,如此庞大的数据,如果不进行压缩,那么磁盘空间将会很快被占满。多媒体数据占了互联网数据量的80%以上,其中大部分都是图像视频数据,未压缩之前的视频非常庞大,不利于存储和传输,因此很有必要对视频进行压缩,视频压缩也叫作视频编码,它利用视频中存在的空间冗余和时间冗余,剔除人眼不敏感的信息,达到数据压缩的目的。3、视频压缩的依据视频能够进行压缩的根本原因是信息冗余,视频中存在两种冗余信息:(1) 空间冗余。对于视频的每一帧图像,在一定尺度范围内,像素的变化是非常平缓的,像素之间非常相似,这就是空间冗余。(2) 时间冗余。视频是由连续变化的图像构成的,在一个很短的时间内,相邻图像之间的变化很小,因此相邻图像很相似,这就是时间冗余。 4、视频编码的原理和细节由于视频中存在大量的信息冗余,想要对视频进行压缩,就必须找到去除冗余信息的方法,标准的视频编码过程包含下面几个步骤:(1) 预测编码。所谓预测就是利用前面像素值来推算当前的像素值。根据前面的知识我们知道,在空间或者时间上相邻的像素是很相似,因此只要预测方法合适,预测值和实际值会很接近,假设当前像素的实际值是X,预测值是P,那么X和P之间的残差A=X-P。如果我们只对残差数据进行编码,那么将会大大压缩数据量。这就是预测编码的原理。预测编码可以分为空间预测(帧内预测)和时间预测(帧间预测)两种。预测编码可以分为下面几个步骤:i. 利用前面已经编码并重构像素块预测当前像素块的值ii. 求当前像素和预测像素的差值iii. 对像素差值进行编码iv. 把编码后的数据传输到解码端,在解码端按照同样的方法对像素值进行预测,再加上残差,就可以重构得到原始图像了。为了得到最佳的预测值,编码器通常需要使用不同预测方法进行预测,然后根据某个评判标准(一般是SAD、STAD、RDO等)得到最优的预测值(注意不是预测值越接近实际值就越优,所谓最优是计算复杂度、失真和码率之间的综合考量),特别对于帧间预测来说,在预测的时候要在参考帧中找到当前块的匹配块,需要大量的计算,因此预测模块一般是编码器中计算量最大的模块,而预测方法的好坏也直接决定了视频的压缩率。(2) 变换编码。变化编码本身不会对数据进行压缩,变换的目的是把空域信息转换为频域信息,去除了信息之间的相关性,在接下来的编码操作中可以得到更高的压缩比,变化编码是为下一步的量化编码做准备的。在视频编码中常见的变换方法是DCT变换和哈达玛变换。(3) 量化编码。量化是视频产生失真的根本原因。经过预测编码、变换编码之后得到的数据被称为变换系数,虽然变换系数相对于原始数据数来说已经很小了,但是系数值的变化范围仍然很大,利用量化把变换系数的连续取值转换成有限的离散值,这样可大大提高压缩率。假设有这样一组数据[16,96,100,600,50],量化参数是25,那么量化之后数据是round([16 / 25, 96 / 25, 100 / 24, 600 / 25, 50 / 25]) = [0,4,4,24,2],可以看到,量化之前的数据范围是16~600,需要大量的比特数才能表示,量化之后的数据范围是0~24,只需要少量比特数就可以表示,实现了压缩数据的目的。编码是一个不可逆的操作,它是失真产生的根本原因。(4) 环路滤波。环路滤波和压缩没有很大关系,却和视频的画面质量有很大关系。视频编码是以块为单位进行的,在经过量化模块时,可能每个块选择的量化系数不同,导致每个块产生的失真不一样,造成像素块的边界不连续,因此人眼观看视频的时会有方块效应(也就是有很多马赛克现象)。为了提高视频质量,有必要对方块效应进行消除,这就是环路滤波模块的功能。经过量化操作之后的数据块,再经过反量化、反变换,然后进行重构,接着进入去方块滤波进行去方块操作,得到的像素块就可以作为参考像素块给预测模块使用。环路滤波是一个可选模块。(5) 熵编码。熵编码的目的是去除统计冗余,实现数据的进一步压缩。这么说可能有点抽象,举个例子,假设有这样一组数据[0,4,4,24,2],如果使用定长编码来进行编码,这段数据可以表示为[00000,00100,00100,11000,00010],每个数据需要5 bit来表示,这段数据的总长度是5 bit x 5=25 bit;如果我们使用哈夫曼来编码,这个数组中每个元素概率值分别如下:数值0的概率是20%,数值4的概率是40%,数值24的概率是20%,数值2的概率是20%,即[20%,40%,20%,20%],根据每个元素的概率构造哈夫曼树(节点中括号内的是数组元素值),如下图所示,因此这段数据可以表示为[0,10,110,111],数据的总长度是11 bit。 由此可见使用哈夫曼编码可以去除统计冗余,实现数据压缩的目的,哈夫曼编码就是一种熵编码方法,但是由于哈夫曼编码对错误非常敏感,不适合实际应用,因此实际应用中通常使用变长编码(CAVLC)和算术编码(CABAC)作为熵编码算法。算术编码利用一个0到1之间的浮点数来描述一个信号序列,然后用这个浮点数来表示这个信号序列,极大的压缩了数据。算术编码可以使用一个简单的例子说明,假设有一个二进制串“10101110”,符号0和1的概率值都是50%,算术编码的过程如下:(1) 设置定一个区间,通常这个区间我们设定为[0,1),然后使用low指向区间的下界,用high指向区间的上界,现在low指向0,rhigh指向1.(2) 输入每一个符号,按照符号的不同对low和high进行调整,调整方法如下面公式所示,最后把low指向的浮点数作为这个符号串的码字,表示这个二进制串,可以看到算术编码的压缩效率比哈夫曼编码高很多,在x264中使用CABAC(上下文自适应的二进制算数编码)作为熵编码算法。 以上就是编解码技术的基础知识介绍,该系列第二篇文章将会介绍视频编解码技术的实践。更多即时通讯、音视频技术的干货文章,请关注网易云信博客。

June 26, 2019 · 1 min · jiezi

从0到1构建网易云信IM私有化

本文来源于MOT技术管理课堂杭州站演讲实录,全文 2410 字,阅读约需 5分钟。网易云信资深研发工程师张翱从私有化面临的问题及需求说起,分享了网易云信IM私有化的解决方案和具体实践。想要阅读更多技术干货、行业洞察,欢迎关注网易云信博客。了解网易云信,来自网易核心架构的通信与视频云服务。私有化的源起在做公有云平台的过程中,我们接触到很多客户,有许多客户和我们反馈:“你们的云平台服务很好、线上也很稳定,但我们希望能把云平台搬到自己的环境里部署起来”。在进一步了解情况后,我们也得到了客户要求私有化的几个诉求点:私密性要求一些企业出于数据保密及安全方面的顾虑,希望能把关键数据安放在自建机房或者数据中心,对网络访问进行严格控制;另外像银行金融机构以及政府部门会受到监管合规等方面的限制,私密性甚至是一个硬指标。自主性要求希望能够自主掌控IM系统,这类客户一般自身便具有较强的开发和运维团队。数据资产化要求公有云上的客户需要依赖我们的数据开放能力,而在私有化部署后客户能够一手掌握存储的原始数据以及使用过程产生的所有日志信息,使数据真正转变为企业资产,满足灵活多样的数据分析需求进而增值。本地化应用要求一些企业对应用时延有较高要求,公有云平台无法满足,从而需要进行本地私有化部署。另外和现有企业内部信息系统整合,构建沟通交流协作大平台的需求成为企业选择私有化部署的一种考量。由于私有化的呼声持续增长,我们决定启动私有化项目,那么从服务提供者的角度我们需要什么样的私有化呢?复用业务代码复用公有云代码,不重复造轮子,减少与公有云代码版本的差异性,使私有化系统最大限度继承公有云上的能力,降低测试开发维护成本。适配不同环境具有私有化需求的客户来自各行各业,私有化部署环境也会各不相同,系统除了能在网易蜂巢、阿里云、华为云等主流云平台上跑起来,也需要能够适配企业自建数据中心的虚拟机以及物理机环境。部署高效可复制部署流程标准化自动化。我们所追求的私有化,不是耗费1-2个月的工作量为企业部署一套定制化系统,而是高效可复制的。另外针对目前企业中IM相关的企业办公等场景的部署规模等实际情况,标准化部署我们走的是相对轻量化的路线,有效降低企业的部署成本。服务稳定可靠这其实是一个分布式系统的基本要求,内部各个组件高可用可扩展,消除单点。私有化面临的问题明确了需求后我们再来看看所面临的一些问题。公有云的主体架构如下,主要由客户端层、网关接入和路由层、业务层、中间件、数据存储层以及监控系统组成,其中接入层根据不同的连接方式以及应用场景拆分为多个服务,业务层根据不同业务逻辑划分出漫游、推送、历史消息以及抄送等服务。在这些服务里面会涉及到JAVA、C、Golang等多种技术栈,当这些服务混合部署到各种环境中,如何解决依赖管理以及可能发生的底层库冲突,怎么通过技术让这个过程变得简单高效,是我们面临的主要问题。下面我们来看如何解决落地。私有化解决方案概括起来主要是围绕Docker技术从主机、容器、镜像和编排四个层面来解决主机主机上除了标准的操作系统,初始化只需要安装Docker引擎、Supervisor和MetricBeat。其中,Supervisor起到管理容器实例的作用,当容器出现状况时起到一定的故障恢复的作用;MetricBeat是ELK技术栈中的监控agent,能够向监控系统上报主机的资源使用情况以及各个容器的健康状况。最小化依赖组件,就降低了出现依赖冲突的可能性,达到兼容更多云主机、虚拟机以及物理机环境的目的。镜像主机上最小化依赖项,那么每个服务依赖管理的任务就落到了镜像这个层面上。每个镜像对应一种服务并且自我管理依赖,多个镜像对应的容器之间相互隔离。比如服务A依赖jdk7,而服务B必须跑在jdk8版本上,如果这两个服务没有容器化而是跑在同一主机环境下,我们就需要显式指定所使用的JAVA路径,增加额外的复杂度。更坏的情况,如果出现底层库的版本冲突,可能会导致不同服务无法部署在一个主机上,这显然是我们不想看到的。但通过Docker与生俱来的隔离特性,我们能很好地规避这个问题。容器镜像实例化后我们便得到了运行中的容器,不同于单进程容器的是,我们使用Supervisor作为容器入口,再由Supervisor来管理容器中的多个进程,这些进程有主次之分,主进程对外提供服务,次进程一般包括MetricBeat和FileBeat,前者起到主进程监控和业务监控的功能,后者是ELK生态中的日志采集组件。编排将多个同类容器组成集群,将非同类容器进行配置并连接可达,是编排的基本功能。往往说起Docker容器编排,大家首先想到的是kubernetes(以下简称k8s),不同于容器云等场景,在企业IM场景中用户数普遍为几十万左右,对应的集群主机数量一般不超过10台,在这种规模下将k8s整合进去代价较大。于是我们考虑轻量的方式,就是使用Ansible。对于Ansible,做过运维的同学应该比较熟悉,它基于SSH采用无agent架构,是集群管理的有力工具。虽然丢失了k8s中容器动态管理以及故障自我恢复等高级功能,但通过前面提到的在主机和容器层面引入Supervisor管理的方式,在一定程度上保留了容器管理和故障恢复的能力。Ansible虽然轻量,但通过丰富的功能模块、角色定义,能够具备强大的脚本表达能力,我们在此基础上编写主机初始化流程,各个服务的高可用集群如基于keepalived虚拟ip的MySQL主从或者双主集群以及基于OpenResty负载均衡双主集群。除了技术架构上的四个层面,在ansible部署脚本之上我们封装了http接口并开发了可视化的安装向导。此外我们还提供管理平台和运维平台kibana,这些可视化平台能够方便交付工程师和运维工程师在安装部署、集群管理、应用管理以及运维监控等方面提高效率,真正做到从部署到交付后运维的全流程高效可复制。最后,我们把验收工作比作交付的最后一公里,由于PaaS产品并不像SaaS那样能够做到开箱即用的效果,我们提供了demo程序进行测试,覆盖iOS/AOS/Web/PC等主流客户端,具备单聊、群聊、聊天室、双人及多人音视频通话等场景便于客户在场景中验证核心能力。Demo程序开放源代码,便于后续接入集成。云信实战经验总结那么,从IM私有化实践中我们可以得到什么经验?总结为以下五点:1) 标准OS提供计算资源,兼容异构环境2) Docker实现程序包封装和运行时资源隔离3) Ansible实现分布式集群高可用部署4) 可视化平台使部署及管理高效可复制5) 多端demo验证突破交付最后一公里以上就是网易云信IM私有化实践的分享,期待和大家共同探讨、交流。网易云信(NeteaseYunXin)是集网易18年IM以及音视频技术打造的PaaS服务产品,来自网易核心技术架构的通信与视频云服务,稳定易用且功能全面,致力于提供全球领先的技术能力和场景化解决方案。开发者通过集成客户端SDK和云端OPEN API,即可快速实现包含IM、音视频通话、直播、点播、互动白板、短信等功能。

January 21, 2019 · 1 min · jiezi

即时通讯App怎样才能火?背后的技术原理,可以从这5个角度切入

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~本文由腾讯云视频发表于云+社区专栏关注公众号“腾讯云视频”,一键获取 技术干货 | 优惠活动 | 视频方案社交场景iMessage隐藏的省话费小秘密融合通信原理通过短信和IM的结合,可以实现从APP内到APP外的沟通。若你的朋友没有安装应用,你也可以在应用内,导入通讯录好友,给其发消息,只是这个“消息”,会以短信的形式触达。企业办公沟通场景休假旅行,老板电话,这2个词总能凑一起融合通信原理通过IM与呼叫中心结合,企业可以在APP内发起互联网IP电话,经过“中转机”,转为传统电话。企业间沟通的场景甲方和乙方又有了个安全高效的沟通途径融合通信原理两家企业通过对接各自的IM系统,可实现企业通讯录互通,适合于合作伙伴企业间的沟通。警察应急指挥场景网络不佳的情况,采用对讲机,可以向总部大屏幕同步现场情况融合通信原理通过对讲机通信和IM的结合,可以满足一些极端恶劣环境下的消息同步,从对讲机到指挥中心、微信群、app内的消息同步。智能客服场景过(现)去(在),在大众点评上联系商家,只能拨打商家预留的电话,现(将)在(来),“联系商家”入口悄然变成了智能客服,你永远不知道对面是真实的人还是AI机器人融合通信原理通过IM、视频通话、呼叫中心和大数据系统的结合,从APP、小程序内唤起智能客服、视频通话,可以极大的提升用户体验。如何打通IM、传统外呼中心、视频通话答案尽在“融而开放、合以创新”T-HIM融合通信技术开发实战时间:2018.9.8 13:30 -19:30 周六地点:北京市海淀区中关村创业大街10号楼天使汇极客咖啡3楼问答请问小程序即时通讯如何接入发送消息?相关阅读IM即时通讯实现原理iOS 即时通讯 + 仿微信聊天框架 + 源码开发一款即时通讯App,从这几步开始 【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识

October 26, 2018 · 1 min · jiezi