查看原文
其他

基于长连接的配置平台框架设计

李志强 58技术 2022-03-15

导读

为满足联合办公及写字楼品牌公司,开发商对房源推广及品牌宣传的增值需求,同时增加商业地产收入来源,商办产品(写字楼,联合办公)推出付费广告产品,为业主提供更多的权益,帮助提提升品牌,楼盘,房源的更多曝光,同时将更多优质房源精准推送至C端客户,帮助解决业主房源去化慢的难题。


背景

业务涉及到导航页的配置,筛选项配置,运营广告位配置。由于导航页静态化,如果有变动重新生成导航页、筛选项需要做缓存,例如增加地铁可能要reload数据重新初始化。运营广告位实时性要求较高而且每个城市,每个业务线都不同。这给广告运营平台设计提供很多难度,具体细化到下面的维度:

可视化:

由于用户为运营人员,所以可视化非常重要,而且让用户精确检索想配置界面及位置,最大程度提高人效,减少误操作。

多样性:

由于涉及到导航页,筛选项,运营广告位,城市差异性,以及自定义顺序等要求。需支持较复杂的数据结构。

多业务线:

支持联合办公、写字楼,以及后期规划的厂房、创业园区等多业务线,要求不同的业务线灵活配置,业务隔离。

实时性:

广告位产品,活动开关,黑名单相关业务对实时性要求都较高。

一致性:

涉及双网,多端(PC,APP,小程序),多集群。对数据的一致性还是有比较高的要求。

历史版本回滚:

要求记录操作历史,方便版本回溯。


为什么不使用properties

为了避免常规模式,通常将配置信息存入resource目录下的properties文件,用这种方式配置优点是比较简单。但是维护properties文件有以下几个问题:
1:无可视化界面,支持的数据结构与数据类型比较单一。
2:如遇到变更将修改配置文件,需要拉取分支,编译代码,重启线上服务器。如果是多个集群更加令人崩溃。
3:配置生效不及时,因为发版流程复杂,而且集群启动需要时间,多集群的化更加难以把握。
4:不同城市,不同环境需要差异性配置。

组件特点:

简单,易用,性能高,伸缩性高。

简单:做到核心业务不依赖中间件,从而减少维护成本和出错的可能性。

易用:客户端进入紧紧需要几行代码即可。

性能高:通过localcache,提升性能。

伸缩性:基于云平台轻松实现扩容/缩容。


架构设计


首先看架构图,主要分成三个部分可视化配置平台,配置中心,客户端程序。下面分析相关配置中心的核心设计。


数据模型

配置产品有多样性与个性化要求,但是软件设计还得兼顾统一性。这就需要抽象数据结构,在保证统一数据结构的同时,对不同场景,不同产品有一定个性化的能力。

配置中心设计了clientId-path-object数据结构:

clientId:各个client注册的id

path:表示模块名称,path路径的方式,因为这么这几不仅可以监听自己节点还可以监听子节点,使得监听维度多样化。

object:表示模块中的一条配置项,摒弃单一的string类型key-value格式,结合业务重新设计一套更加灵活的对象结构。


Cap理论应用

可用性:性能高,延时小(秒级更新)

为了配置中心支持较大吞吐量,这里采用基于HTTP异步请求处理。结合长轮询监听客户端配置项,当所监听配置项发生变化时,会立刻将最新配置项通过DeferredResult返回给客户端,从而实现配置中心高吞吐量,以及秒级更新的原因。

可靠性:基于云平台,很容易实现扩容负载以及故障转移。

分组容错性:基于对等设计架构而非典型的主从架构。使得配置节点可以提供幂等服务特性,进而支持异地跨机房部署,只在本地机房部署即可,实现异地多活。


一致性设计


增量同步设计:

数据一致性设计了一个内置msg队列,同步增量数据。而且在配置平台集群共用一个增量消息队列,内置msg队列与全量数据是强一致性。

配置中心采取pull的方式进行实时同步。考虑到配置中心集群对等设计,所以已消费状态在每个配置中心内部。通过一个线程安全的集合维护,避免配置中心重复消费增量消息。

过期机制:考虑到目前队列没有维护offsite,出队机制等,而且考虑到已消费消息集合对内存的影响,加入了过期机制。这里策略是时间过期,默认为30s。


全量同步设计:

宕机超过30s,增量消息丢失怎么处理?

如果有配置中心实例由于网络原因延迟消费或者,宕机超过30s丢消息这种情况通过全量同步机制来保证一致性。为了避免全量同步缓慢,数据传输过大等问题,采取了批量写,分页同步全量数据以及每个clientid最大配置数量。


顺序保证:

通过版本号的设计,CAS思想保障配置项为最新状态。


容灾与备份

首先client(客户端)与配置中心集群是完全分离的。配置数据会持久化到数据库并定期同步到配置中心集群的file中。配置中心集群的file与client的localcache,mirror镜像文件都有存储,而且配置中心集群多实例,HTTP作为应用层协议很容易通过域名/nginx等方式进行负载和保证高可用。

根据下图所示,client每次访问都会优先匹配最短路径,比如如果发现配置在localcache中就不会在向配置中心集群发出请求,以上情形会持续到localcache数据被删除为止。依次类推。


总结一下整个系统完全不可用的条件:

1、数据库集群不可用(主从都不可用)。

2、Configservers集群不可用(所有集群实例不可用)。

3、localcache被删除

4、mirror镜像文件被删除

同时满足以上4个条件的概率,在生产环境中是极小的。


长连接

因为涉及实时消息推送,watch机制,而zookeeper集群本身自带高可靠,高可用特性。基于Zookeeper Atomic Broadcast(Zookeeper原⼦消息⼴播协议)简称ZAB协议保证了数据一致性,有序性和容错性而且还带watch观察和触发操作。如果使用zookeeper中间件以及cluster客户端很容易实现监听以及本身和子节点的监听。

为啥采用长连接?

1:基于公司推进云服务化,支持动态扩容、缩容。相比非云平台架构会降低成本与业务提效。

2:更加轻量级,减少对中间件依赖。

3:基于集群对等设计,提供幂等服务,任意一点水平扩展,支持异地多活,跨机房部署。

4:长连接基于http协议,支持跨语言。


客户端设计

 

多监听策略

场景:

比如品牌筛选,城市A有品牌A,品牌B,品牌C三个品牌筛选项。如果运营人员降低品牌B,并在城市B中加入品牌D。监听怎么做呢?

如果监听品牌B本身,那么变更信息传递给业务模型父级品牌筛选?

如果面对新增品牌没有事先监听又怎么办?

方案:

方式1:监听品牌筛选,将品牌A,品牌B,品牌C整体作为value。

方式2:监听品牌筛选,将品牌A,品牌B,品牌C作为子节点。

方式1采用典型的key,value结构,业务演化困难比如筛选项包含品牌筛选,价格筛选。鉴于筛选项变更频率极低做了cache,如果方式1思路是不是监听一个新的key-筛选项,value为品牌筛选+价格筛选所有的筛选项。在加入城市呢?更复杂

方式1不灵活,比如如果有需求只想监控品牌A,监控品牌A图片logo等信息变化方式1就的维护两个单独key。

鉴于产品的需求,采用了树形数据结构的设计,比如继续拿筛选项举例:

设计数据结构/筛选项

/品牌筛选

/品牌A

/品牌B

/价格筛选

可以注册监听N1:”/筛选项/品牌筛选”,也可以同时注册监听N2:”/筛选项/品牌筛选/品牌A”当品牌A发生变化会通知监听N1和监听N2。

差异化事件类型:

不仅提供两种监听策略:节点本身以及子节点。还细化事件类型,新增/删除问题一类事件,修改为一类事件。为什么这么设计?主要考虑到新增/删除的处理可能涉及到初始化(init)/卸载(destroy)。而修改事件只是属性的修改。举例:比如扩城可能涉及很多数据load,构建该城市首页,而修改首页某个热门商圈,直接替换即可。


客户端内存设计:

考虑到配置是一个典型的读多写少场景,加入了localcache,提高性能。读取顺序为localcache-远程配置中心-镜像文件。

为了规避localcache对client内存影响,用lru思想自定义一个线程安全的lrucache数据结构,而且规范每个客户端最大配置项数量。

null值处理:

对于不存在的key,置空写入localcache,避免频繁访问不存在的key对Configservers压力过大的问题。

懒加载:

考虑到启动客户端是未必所有配置都需要通过长连接来进行检测,所有采用懒加载机制。不仅可以提升性能,减少无意义检测,还能减少配置中心负担,延迟客户端内存使用率。

数据预热:

为了规避客户端重新启动时本地缓存失效,造成对server请求瞬时突增,所以启动时候对数据进行预加载。同时考虑到镜像文件可能过期导致脏数据,采用了优先镜像文件中keys集合校验功能,返回最新结果采用覆盖策略。具体流程图如下图:

 


客户端断线重连:

设置守护线程,周期性检测客户端连接、配置同步,提高异常情况下配置稳定性和时效性;重新连接后会根据client监听列表同步相关数据。

client_api:

客户端具有简单易用,灵活监听等特点。比如获取配置项,监听子节点相关事件,分别调用相关方法即可。

举例:检测品牌筛选项

如果品牌筛选项有子品牌的更新和新增,会回调update方法,通过updateFilter来调整筛选的值和顺序。并且将该筛选项进行缓存策略。提升列表页业务性能。

 

通过回调函数可以看到,可以回传变更节点参数,也可以根据不同的事件类型有不同的处理。

 


性能测试

通过ab测试,基于http协议测试组件性能。经过多次测试大致测试情况如下,通过Time per request:1.336ms可以看出配置平台性能是非常优秀的。


效果演示

列表页可以看到配置位有多端,多业务,多城市,开始和结束时间等特点。这里支持快速检索。

 

新增界面,看到根据业务进行设计,方便运营人员快速定位,快速填写。

 

客户端的界面:可以看到红框界面就是通过配置运营后台进行配置后呈现的效果,当运营人员修改后,客户端也秒级更新。


总结与展望

通过产品需求,构建了一个可视化,动态化,高性能的平台。已满足背景内容中产品的所有需求。通过封装api,简化客户端接入,实现目前商业地产业务线快速迭代。

该平台大大降低了运营人员配置成本,为动态配置、个性化配置提供支撑。也为业务线商业化,提升平台付费客户的转化率,丰富售卖产品类型,提供支撑。

上文主要分享给大家在做动态配置项目中遇到的问题以及一些解决方案。配置这个事情是永恒的话题,业务动态配置,系统动态配置,开关/灰度动态配置,营销动态配置每个方向的设计都会有差异,但是核心思路是一样的。这里仅仅给大家抛砖引玉,望大家都有收获。


参考文献:

https://mwhittaker.github.io/blog/an_illustrated_proof_of_the_cap_theorem/


作者简介:
李志强:58同城房产事业群-商业地产技术部-开发工程师

福利环节

 为了鼓励优质内容传播,【58技术】公众号近期会持续推出不定期活动奖励。

  1. 留言区发表关于本篇文章的看法,即可参与此次活动

  2. 活动奖励:将由作者本人在评论里抽取五名读者,送出58技术定制版代码台历~

  3. 活动时间:截至2020年12月25日。




您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存