编者按
“大牛 V 课堂”是 Geekbang 核心栏目,通过邀约专业领域内的互联网顶级大牛分享专业知识和见解,让你了解专业领域内含金量最高的知识。关注 geekbang01 公众号,遇见下一位大牛。
正文
本文是根据腾讯微信开放平台基础部资深专家蔡润达在 QCon 技术大会上的分享整理而成,有所删减,内容主要涵盖了以下要点:
- 微信公众号设计
- 多平台账号体系
- 消息触达机制和策略
- H5 和 Native 的完美融合
微信公众号设计
我们在设计的时候,考虑到传统企业以前在整个发展历程中,一开始有自己的一些办公室或者一些门店,他触达终端用户的一些渠道无非是通过传统的海报或者传单,成本是比较高昂的,任何一个开发者想去涉猎都非常难。后来随着互联网的发展,开始有了一个全新的东西,任何一个人或者企业可以去创建自己的网站,将自己企业的一些业务搬到网站上面。
时间飞逝,很快就有了移动互联网,在移动互联网里面会诞生一种全新的产品形态,是移动应用。企业可以去创建自己的 APP,将自己的主营业务从 PC Web 上面挪到移动互联网的 APP 上面,用户接触起来更简单,体验更好。在这样一种前提下,我们推出了微信公众号,认为可以帮开发者更节省一些开发成本,他可以很轻易的地去创建一种全新的体验,以公众账号的形态去存在。
这里简单列举一个案例,在这些能力上,他可以去创建自己的菜单、导航,最终还可以把它完整的一些业务流程,以一种比较轻量的方式,以 H5 的方式跟微信有一个深度的结合,在这里面可以完成以前 APP 上面可以完成的下单、购买种种一系列闭环的行为,这就是我们所认知的一个公众号。
要完整地让开发者有这样一个完美闭环的体验,我们需要关注哪些东西?需要设计这个生态里必不可少的哪些东西呢? 第一个是一个多平台账号体系,企业在接入公众号以后,并不会说它就没有了其他渠道,其他的产品形态,它还可以拥有自己的一些 APP、网站,都可以打通,这才是一个跟企业互补的东西。 第二,是一个触达能力,如果以这样一个公众号的形态给到用户,还必须有一个强有力的帮企业去触达终端用户的方式,我们认为微信作为天然的一个 IM,也是一个超高频的应用,消息是最有杀伤力的一个东西,所以我们在消息触达机制上花了很多功夫,设计出很多种不同的策略,去满足不同的场景。 除了消息以外,我们发现在整个移动互联网的发展过程中,其实除了 PC 上的流量会慢慢地被移动 APP 所替代,基于消息的这种交互体验还是不够丰富,我们必须补上最后的一环,就是 H5 上给到更强的一种体验,那在这里我们通过 JSSDK 的方式,将微信的一些原生的功能,通过 JSSDK 的方式提供给 H5,增强 H5 的体验。
多平台账号体系
接下来我们看一下多平台账号体系。用户在微信里面可以去关注一个公众账号,可以发一个消息给到公众账号,一个公众账号拿到的不是真正的用户名,我们的设计是想保护用户的隐私,最终它拿到的是一个 open ID。企业有网站,有 APP,有 H5,在这三种不同的场景下面,它依然需要解决的是一个问题是,公众账号得到的一个用户是一个 open ID,那我 APP 网站和 H5 上面必须解决同样一个问题,它也得获得他们的 open ID,我们的解决方案是,我们通过开放平台提供统一的一个微信登录的方式,让开发者都能够打通所有的链路里面所有的用户身份,它通过 open ID 可以关联唯一的一个微信用户,通过绑定企业自己的一个账号体系,可以跟它原本的会员体系、用户体系也完全打通。我们认为一个用户如果在 APP 上下了一个单,回到公众账号看不到,是很不可接受的一种体验,所以我们认为在整个设计环境里面,这是至关重要的一环。
在这里披露一下一些简单的数据,公众账号现在有超过 1 千万的注册,一个普通微信用户关注一个公众账号,这种我们称为关注关系,这种关注关系达到几十亿的级别,就是十亿量级,所有在 H5 上面所做的授权登录,就是一个微信用户可能没有关注一个公众号,我只是登录了你的 H5 上面,然后有用 H5 OAuth 的这种授权关系也达到了十亿级别,APP 的也同样达到了十亿级别,我们在支撑这么大的量级的时候,需要额外考虑的一个重点问题不是简单地讲,开发者可以调用就完了,需要考虑的两个重要的点,一个是高性能高可用,两个个最基本的要求,我们认为还必须做到的一点是快速的横向扩展,其实我们的多平台账号体系不仅仅面对外部用户,我们在对腾讯内部的一些游戏 APP 的应用上面,同样也是借助了同样一套体系,所以外面的开发者可以非常放心我们的服务质量。我们一开始在发布游戏的时候,基本上是日新增可以达到千万级别,活跃可以达到非常恐怖的一个活跃度。所以在这里面对我们的设计要求是要有很强的横向扩展性。
接下来就简单讲一下我们怎么去支撑这样一个东西,一个是高性能的保障。这里简单把我们整个多平台账号体系分为几块,一个是 API 层,另外一个是 router 和 monitor,还有 DB Cluster,我们通过这几个东西怎么样去解决呢?所有的 DB 其实存储了刚刚前面提到的所有的关系,所有的关系落地到 DB,但是我们提供给到开发者的所有的访问,都建立了很多 cache,我们的 cache 有多份的内存镜像,通过异步广播的一个方式去同步各个节点。cache 中的任何一台机器当掉,都会自动的有服务器重启它,重启的时候它会自动去热加载这些数据到内存里面,然后多份的内存数据保证说,大量的类似检查都全部是落在内存上面,而已经当掉的一些机器会自动去加载一些数据到达内存里面,在它没有加载完成之前不会提供服务,所以我们保证能够提供一种很高的并发的查询,同时又能够保持一个短时间的响应时间。
router 和 monitor 解决的是什么呢?这里我们认为很重要的一点是,解决一个横向扩展性,因为每一分钟都有很多人在上面去注册一些应用,你无法想象说哪一天,可能是一年前的一个应用突然间火起来了,或者说有一个公众账号突然间就火起来,我们无法预知,所以我们认为快速横向扩展能力是我们平台赖以生存的一个很重要的法宝。
所有的开发者,不管是写客户端或者是后台,都会遇到一个问题,比如说我有一行数据库记录,可能代表着我有一个用户 A,应用了一个 APP1,或者我关注一个公众账号 A。随着我的应用的一个增长,如果一个应用突然间爆发,它的粉丝可能从几百突然间增长到上万、几十万、上百万,甚至上千万,都是有可能的,比如说春节的红包,谁都想象不到,突然间它就火起来了,指的是红包第一次发布的时候。或者某一款应用,比如说之前刷爆朋友圈的足记,它突然间就火起来了,这种是无法预知的。所以通过这种硬哈希的方式去定位到某一个分片上面,就会导致这个分片上面的数据会过载,会严重影响它的服务,当然对整个平台是 OK 的,但是开发者会受影响,或者说跟它处于同一个分片的一些小用户量的应用会严重受到服务质量的影响。
我们怎么去解决这个问题?前面刚刚那张图有一个 router 和 monitor 这两个东西,我们的 router 其实是非常关键的一环,它解决的是一个 hashcode 的哈希方式,在这里面我们引入了动态路由方式,换句话说之前的那个哈希函数现在是被一个 router 的服务所替代,以前可能是 0 到 999 这个 hash range,可能是 hashcode 到 table1 的,而通过这种方式,我们可以以任何不同的力度,我们下一个分片可以做到按千级别的,甚至唯一的一个 key 就可以独享一张表,都是没问题的。在这种方式上,它的整个路由是非常动态、非常灵活的。基于这种路由,我们可以实现什么样的一个特性呢?我们 table,首先 DB 是以 table 作为资源管理,第二是 router 不同力度的一个哈希分布,它可以 100、1000 或者 10000 等等。另外是 router 可以支持一个实时线上的数据迁移,这个我们认为是所有做这种开放平台也赖以生存的一个法则。 前面提到可能某一个 APP,它在上架的前几个月可能都很弱,表现相对比较弱,但是突然间某一天,它在微信 SNS 社交力量的推动下,朋友圈的推动下,突然间爆发性指数性的增长,在这个时候,可能它之前就是使用到只是一个分片,那我们的 monitor 会在实时性上去发现这样一个快速增长的应用,然后启动一些线上的实时数据的一个迁移,我们的迁移力度可以细致到行,当然为了我们的迁移效率,我们企业不是一行一行迁,是一批一批的迁,但是迁只影响这一个分片里面所迁移的这些行,其他不受影响的这些行都是可读可写的,只有被迁移的这些行是不可写的。
在这种情况下,我们认为我们能够得到一种快速的一个横向跨的能力,应用能够在快速发展的过程中,我们保持我们里程数据迁移对开发者的透明,开发者不用担心说我的应用突然间从 10 万级别变成 100 万级别的时候,腾讯是不是会需要有人去跟他沟通,你要升级服务什么的。这些我们在接入公众账号这套体系的时候,我们对开发者透明,开发者完全不需要担心这个事情,我们自己帮他解决。
消息的触达机制和策略
第二个我想分享的一个重点是,我们的消息触达机制和策略,这个图是 iOS 原生的一个 notification list,现在的苹果和安卓手机上面的推送会非常多,上面可以看到它有很多可能是几天前,有些是马上发过来的,不同的实时性都混在一起,我很难去看到这些东西,除非它推送给我的时候马上点进去,否则我就要靠那个未读数去提醒。我们认为这种在处理起来是非常低效的,因为它是以应用去聚合的,你要不断去看一遍这个 list 找到你最感兴趣的内容,并且下拉这个动作是非常低频的一种操作,我们认为用户要快速做这种信息的筛选,唯一的可能是放到一种更高频的场景,来帮助用户快速的去完成信息的整理和处理。我们认为微信的会话列表会是更高效的一种方式。 在这里面公众账号可以通过一些群发,甚至是特定的模板消息的定向发送,可以推送到微信里面。我们在这里有一个列表是可以看到的,当你在聊天的时候,你会看到我有一条未读,马上点进去,同样会有推送,但是带给的是微信给了你一个更高频次打开的机会,所以你的整个信息的处理速度和效率应该是优于苹果的 iOS 的这种推送。
所以我们在设计这个消息触达里面的时候,设计了多种多样的一些机制,其中有一个是包括群发,可能很多人已经在用了,在这里面我们可以针对用户的各种属性,location,包括一些分组,去做筛选,去做定向的一些推送,开发者因为我们的群发 API,其实他可以做到更细力度的一个推送,我们原则上,一个月一个用户只要不重复收到四条以上都是 OK 的,所以换句话说开发者可以做非常非常细力度的,通过程序化对用户进行编组,根据不同的用户画像去做推送,我们个人认为说这种一条内容对所有全员的推送是非常低效的,未来我们也会在这一个群发上的支持,去支持更多的特性、属性的一些推送。 我们还想说的是,除了群发推送以外,还有一些渠道是更实时,更具有互动性的。
第一个是模板消息,模板消息我举个例子,比如说京东购物用微信登录的时候,完成购买,你会收到一条推送,交易完成订单的任何一个状态都很轻松到微信里面去跟踪。如果是你绑定一个建设银行卡的话,你刷一笔款项的时候,它马上会给你发一条模板消息,替代原有的一个短信。另外一个就是客服,在这里面我们认为公众号可能给大家感觉,一开始是一个机器或者一个程序,一堆配置跟用户在沟通,我们想营造出一个真真实实的人跟你在沟通的这种情况,所以我认为这种情况是更具有价值的,那推出客服消息,在这里面你可以看到究竟是哪一位客服在跟你聊天,我们在做这样一个东西的时候,也是同样简单披露几个数据,我们公众号同样有 1 千万家左右,所有公众号的下行消息达到了几十亿,而现在最大的一个模板消息下发量招商银行,已经是一天可以达到千万级别,就是所有的刷卡消费都是走我们这个渠道去下发,我们非常欢迎所有的企业,如果有这种特定的场景下,可以用我们的模板消息,来进行强触达。
如果用户没有关注公众账号这种情况下,在模板消息也是同样可以 work 的,我们有一个叫服务通知的地方会把它聚合起来,并且同样会也微信公众号的 logo 在里面。 在做到这样一个量级的时候,我们需要额外的去关注一些什么东西呢?第一是不同级别的送达速度有要求,第二是群发可以接受比较慢,但是模板消息不能容忍,我们正常情况下的模板消息一般是一秒以内到达。另外我们还需要处理一个消息的瞬时尖峰,应用的过载保护,还有应用间的一些隔离。我们认为这些都是非常重要的。再举一个例子,为什么会有大量的过载保护的一些设计的考虑。小米在我们平台上每个月都会做一些活动,抽一些手机之类的,米粉是很忠诚的。我们在这里面,它下发以后,通常会有跟着的一个波峰出来,但这个波峰对我们整个系统可能就体现不出来,但是对它的号而言,它整个消息使用量就会上去。
我们的解决方案是,通过多级的优先队列,不同级别的优先队列,跟资源调度有一个分布式的漏水桶服务,去调度一些资源。 简单来说是这样的,我们会把所有的资源给全局的公众账号,保证一个最少的可使用资源,这个可使用资源肯定是绝对可以保证的,然后超过这些阈值的时候,我们会在全局有一个应用,应用系统资源去调度,这个时候会看我们哪一个集群、哪一个队列里面是比较空闲的,就会把你给调度到那边去,从而保证我们全局的资源是最高使用的。
H5 和 Native 的完美融合
接下来我们来讲一下 H5 和 Native 的完美融合,在我们的设计里面,除了消息、账号体系这些解决了以外,不足以支撑丰富的一个服务形态的展现,如果要解决这一环的话,必须要做到这一点。我们认为这个对开发者来说,应该提高他们的开发效率,因为微信本来就有这个能力的,为什么要重新再做一遍呢?在微信上提供了一个 JSSDK,我们认为这个 JSSDK 是一个能力的延展,是将微信原生的一些能力延展出去给到开发者,第二,它使开发变得更简单更高效,第三,是一个完全标准化的东西。我们举个例子,如果我们用 H5 自己去开发传图要怎么做,首先给大家写一个 H5,然后自己在那里可能就去传输这些图片,但是不要忽略用户的网络环境是非常复杂的,有 edge,有 WiFi,有 3G/4G,但是它有一个特征是不稳定,你很难预期你的用户在什么样的网络环境下刚好对你这个应用感兴趣,就点开了,如果在信号不好的 3G 或者 4G,最糟就是 edge,这个情况下传统一张大图,我们可以想像他的体验是非常差的。我们如果要去解决这种很异常的网络环境,用最原生的 POST 的方式去提交一些数据是非常差的,那我要怎么样去解决它呢?
我们是这样去做的,首先 H5 通过 JSSDK 去调用微信的传图接口,这个时候我们会给它返回一个叫 Server ID、Local ID,如果它要马上传完以后,马上想在 H5 上面展示出来,我们可以给他一个 Local ID,这个时候他无需任何网络,马上可以在 H5 上显示这张图。另外本质上他把这个传图的任务委托给微信,微信通过原生,我们聊天的传图功能,把这张图片上传到我们的 server 里面,然后再异步返回给他一个叫 ServerID 的一个东西,在这个过程中,他不需要去处理复杂的网络情况,这个复杂网络情况的处理交给微信来做,而他只需要保证自己稳定的两个链路是 OK 的。
首先即使在不稳定的情况下,传输一个只有十几个字节的 ServerID 是非常简单的一个事情,另外他在这里的 Server 到我们的 Open API 之间的网络环境是相对比较稳定的,它要去处理这个图片的重新拉回来,自己再存起来,相对来说是比较简单的一个事情,它不需要处理,它不需要去面对 edge、WiFi 跟信号不好的 3G 这样的一种网络情况。
所以我们在这里面有了一些能力所有的整合跟延展,这里面我们除了最传统的刚刚说的音频、视频以外,我们把右上角的那个界面控制也同样开放给开发者,他可以去设置我在什么情况下,我这一个界面就是不想被用户分享出去的,直接上面那个分享按钮就不见了。我不允许你去 copy 我的链接,同样上面那个按钮就不见了,这是我们界面的东西。 同时还会有一些设备接入,比如说发现一些设备的 api,它有一些业务,跟我们卡券打通,跟啥与啥打通,我能不能调用微信里面的扫一扫识别条码,没问题,开放给你,所有都有。
本文是根据腾讯微信开放平台基础部资深专家蔡润达在 QCon 技术大会上的分享整理而成,有所删减,感兴趣的读者可以点击这里查看视频。
作者的微信公众号“老崔瞎编”,关注 IT 趋势,承载前沿、深入、有温度的内容。感兴趣的读者可以搜索 ID:laocuixiabian,或者扫描下方二维码加关注。
评论