10个基于java的cms网站内容管理系统(会员系统如何实现高性能和高可用性?的重要内容是什么?)
优采云 发布时间: 2022-04-01 11:1610个基于java的cms网站内容管理系统(会员系统如何实现高性能和高可用性?的重要内容是什么?)
一、背景
会员制是与公司各业务线的主要订货流程密切相关的基础制度。如果会员系统出现故障,用户将无法下单,影响公司所有业务线。因此,会员系统必须保证高性能和高可用,并提供稳定高效的基础服务。
随着同程与鳄鱼龙的合并,越来越多的系统需要开通同程APP、鳄鱼龙APP、同程微信小程序、鳄鱼龙微信小程序等多平台会员系统。比如在微信小程序的交叉营销中,如果用户购买了优采云票,想给他发酒店红包,需要查看用户的统一会员。因为优采云门票采用单程会员制,而酒店采用鳄鱼龙会员制,只有找到对应的鳄鱼龙会员卡号后,才能将红包挂到会员账户。除了上面提到的交叉营销,还有很多场景需要查询统一会员,比如订单中心、会员等级、里程、发红包、频繁出差、实名制、各种营销活动等等。因此,会员系统中的请求数越来越多,并发量也越来越大。今年五一假期第二次,并发tps甚至超过20000。在如此大的流量冲击下,会员系统如何实现高性能和高可用?这是本文的重要部分。会员系统如何实现高性能和高可用性?这是本文的重要部分。会员系统如何实现高性能和高可用性?这是本文的重要部分。
二、ES 高可用解决方案
1. ES双中心主备集群架构
同程艺龙与其他两家公司整合后,整个平台各系统会员总数超过10亿。如此庞大的数据量,业务线的查询维度也非常复杂。有的业务线基于手机号,有的基于微信unionid,有的基于鳄鱼龙卡号查询会员信息。这么大的数据量,这么多的查询维度,我们选择ES来存储统一的会员。ES集群在整个会员体系架构中非常重要,那么如何保证ES的高可用呢?
首先,我们知道ES集群本身是高可用的,如下图所示:
当ES集群的某个节点宕机时,会将其他节点对应的replica shard升级为primary shard,继续提供服务。但即便如此,这还不够。比如ES集群全部部署在A机房,现在A机房突然断电。我该怎么办?例如,如果服务器硬件出现故障,ES 集群中的大部分机器都宕机了怎么办?或者突然有一个非常火爆的抢购活动,带来一波非常大的流量,直接秒杀ES集群。我该怎么办?面对这些情况,让运维小哥赶紧去机房解决吗?这是很不现实的,因为会员制直接影响到公司所有业务线下单的主要流程,并且故障恢复的时间必须很短。如果运维兄弟需要人工干预,那么这个时间太长了,绝对不能容忍。ES的高可用呢?我们的解决方案是ES双中心主备集群架构。
我们有两个机房,分别是A机房和B机房。我们在A机房部署ES主集群,在B机房部署ES备份集群。成员在ES主集群读写,数据通过MQ同步到ES备份集群。此时如果ES主集群崩溃,通过统一配置,将成员系统的读写切换到B机房的ES备份集群,这样即使ES主集群挂掉,也可以进行failover短时间内达到。
确保会员系统稳定运行。最后,主ES集群故障恢复后,打开开关,将故障期间的数据同步到主ES集群。数据同步后,将成员系统的读写切换到主ES集群。
2. ES流量隔离三集群架构
双中心ES主备集群做到了这一步,感觉应该没有什么大问题,但是去年恐怖的交通冲击让我们改变了主意。那是一个假期。某企业发起营销活动。在一个用户的请求中,会员系统被循环调用了10次以上,导致会员系统的tps暴涨,几乎炸毁了ES集群。这件事让我们感到害怕。这让我们意识到,我们必须优先考虑调用者,并实施更精细的隔离、断路器、降级和限流策略。首先,我们整理了所有调用者,并将它们分为两大类请求类型。第一类是与用户主要订购流程密切相关的请求。这种请求非常重要,应该得到高优先级的保证。第二类与营销活动有关。这种类型的请求有一个特点。他们的请求量很大,tps很高,但是不影响下单的主要流程。基于此,我们搭建了一个ES集群,专门用于处理高tps的营销尖峰请求,使其与ES主集群隔离,不会受到某个营销活动的流量影响。过程。如下所示:我们搭建了一个ES集群,专门用来处理高tps的营销尖峰请求,使其与ES主集群隔离,不会受到某个营销活动的流量影响。过程。如下所示:我们搭建了一个ES集群,专门用来处理高tps的营销尖峰请求,使其与ES主集群隔离,不会受到某个营销活动的流量影响。过程。如下所示:
3. ES集群深度优化与提升
讲完了ES双中心主备集群的高可用架构,下面我们来深入讲解一下ES主集群的优化。有一段时间,我们很苦恼,就是每次到了吃饭的时间,ES集群就开始报警,这让我们每次吃饭都慌了。那为什么要在午餐时间报警呢?因为流量比较大,ES线程数猛增,CPU直线上升,查询时间增加,又传给所有调用者,造成更大范围的延迟。那么如何解决这个问题呢?通过深入ES集群,我们发现了以下问题:
经过以上优化,效果非常显着。ES集群的CPU大大降低,查询性能大大提高。ES集群的CPU使用率:
会员系统的界面需要时间:
三、会员Redis缓存解决方案
很长一段时间,会员系统都没有做缓存。主要有两个原因:首先,上面提到的ES集群性能非常好,每秒并发3万多秒,99行耗时5毫秒左右,足以应对各种困难。场景。其次,有些业务要求会员之间的绑定关系实时一致,而会员制是发展了10多年的老制度。它是一个由许多接口和许多系统组成的分布式系统。因此,只要有一个接口考虑不到位,缓存没有及时更新,就会导致脏数据,从而导致一系列问题,比如:用户在微信上看不到订单。 APP、APP、微信的会员等级、里程等。不合并,微信和APP不能跨市场等等,那为什么还要缓存呢?就是因为今年票的盲盒事件,带来了太多的瞬时并发。会员制度虽然安然无恙,但仍有一些心存疑虑。为了安全起见,我最终决定实现一个缓存方案。
1. ES延迟近一秒导致Redis缓存数据不一致的解决方法
在实现成员缓存方案的过程中,我们遇到了一个由ES引起的问题,会导致缓存数据不一致。我们知道 ES 运行数据是近乎实时的。向 ES 添加一个 Document 并立即检查。找不到。需要 1 秒钟才能找到它。如下所示:
为什么ES的近实时机制会导致redis缓存数据不一致?具体来说,假设用户退出了他的 APP 帐户。此时需要更新ES,删除APP账号与微信账号的绑定关系。ES的数据更新是近实时的,即1秒后就可以查询到更新的数据。而在这1秒内,有一个查询用户的会员绑定关系的请求。它首先检查redis缓存,发现没有,然后在ES中检查,找到了,但是它找到了更新前的旧数据。. 最后,请求将查询到的旧数据更新到redis缓存并返回。这样,1秒后,用户在ES中的会员数据更新了,但是redis缓存的数据还是老数据,导致redis缓存和ES数据不一致。如下所示:
面对这个问题,如何解决?我们的想法是在更新 ES 数据时添加一个 2 秒的 redis 分布式并发锁。为了保证缓存数据的一致性,然后删除redis中成员的缓存数据。如果此时有查询数据的请求,首先获取分布式锁,发现成员ID已经加锁,说明ES刚刚更新的数据还没有生效,那么之后redis缓存就不会更新了此时查询数据,直接返回。这避免了缓存数据的不一致。如下所示:
上面的方案乍一看似乎没问题,但仔细分析可能还是会导致缓存数据不一致。比如更新请求添加分布式锁之前,正好有一个查询请求获取分布式锁,此时没有锁,所以可以继续更新缓存。但就在他更新缓存之前,线程被阻塞了。这时候更新请求来了,加了分布式锁,删除了缓存。当更新请求完成操作时,查询请求的线程就会活跃起来。此时执行更新缓存,将脏数据写入缓存。你找到了吗?问题的主要症结在于“删除缓存”和“更新缓存”的并发冲突。只要它们相互排斥,问题可以解决。如下所示:
缓存方案实施后,统计缓存命中率达到90%+,大大缓解了ES的压力,会员系统的整体性能也得到了很大的提升。
2. Redis 双中心多集群架构
接下来我们来看看如何保证Redis集群的高可用。如下所示:
关于 Redis 集群的高可用,我们采用了双中心多集群的模型。在A机房和B机房各部署一个Redis集群,更新缓存数据时,双写,只有两个机房的redis集群都写入成功,才会返回成功。查询缓存数据时,最近查询在机房,减少延迟。这样,即使A机房整体出现故障,B机房仍然可以提供完整的会员服务。
四、高可用会员主库方案
如前所述,所有平台成员的绑定关系数据存在于ES中,成员的注册详情数据存在于关系数据库中。起初,成员使用的数据库是SqlServer。直到有一天,DBA找到我们,说单个SqlServer数据库已经存储了超过十亿的成员数据,服务器已经达到物理极限,不能再扩展了。按照现在的增长趋势,用不了多久整个SqlServer数据库就会崩溃。想一想,那是什么样的灾难场景:会员数据库崩溃,会员系统崩溃;如果会员制崩溃,整个公司的所有业务线都会崩溃。想想就让人不寒而栗,于是我们立即开始了迁移DB的工作。
1. MySql双中心Partition集群解决方案
经过调研,我们选择了双中心分库分表的MySql集群方案,如下图:
共有超过 10 亿个数据成员。我们将主成员库划分为1000多个shard,每个shard分成一百万左右,足够使用了。MySql集群采用1主3从的架构。主库放在A机房,从库放在B机房。两个机房之间通过专线同步数据,延时在1毫秒以内。会员系统通过DBRoute读写数据,写入的数据路由到主节点所在机房A,读取的数据路由到本地机房,可以就近访问,减少网络延迟。这样,双中心MySql集群架构大大提高了可用性。
双中心MySql集群搭建完成后,我们进行了压力测试。经测试,每秒并发可以达到2万以上,平均耗时在10毫秒以内,性能达标。
2. 会员主库平滑迁移计划
接下来的工作就是将会员系统的底层存储从SqlServer切换到MySql。这是一项风险很大的工作,存在以下困难:
基于以上痛点,我们设计了“全同步、增量同步、实时流量灰度切换”的技术方案。
首先,为了保证数据的无缝切换,采用了实时双写方案。由于业务逻辑的复杂性以及SqlServer和MySql的技术差异,在双写mysql的过程中,可能会写入不成功,一旦写入失败,SqlServer和MySql的数据就会不一致,即绝对不允许。. 所以我们采用的策略是在试运行的时候,主要写SqlServer,然后通过线程池异步写MySql。如果写入失败,请重试 3 次。如果仍然失败,请记录日志,然后手动调查原因。继续双写,直到运行一段时间没有双写失败。通过以上策略,在大多数情况下可以保证双写操作的正确性和稳定性。即使试运行时SqlServer和MySql的数据不一致,也可以完全基于SqlServer再次构建MySql的数据。,因为我们在设计双写策略的时候,会保证SqlServer可以写成功,也就是说SqlServer中的数据是最完整、最正确的。如下所示:
说完了双写,我们再来看看“读数据”是怎么灰度化的。整体思路是通过A/B平台逐步灰度化流量。一开始100%的流量从SqlServer数据库中读取,然后逐渐切流量去读取MySql数据库,先1%,如果没有问题,再逐步释放流量,最后100%全部流量转到 MySql 数据库。在流量逐渐灰化的过程中,需要一个验证机制。只有验证无误,才能进一步扩大流量。那么这个验证机制是如何实现的呢?解决方法是通过异步线程在一个查询请求中比较SqlServer和MySql的查询结果是否一致。如果不一致,记录日志,然后手动检查不一致的原因。完全解决不一致性后,流量逐渐变灰。如下所示:
因此,总体实施过程如下:
首先,在一个漆黑风大的夜晚,流量最小的时候,完成从SqlServer到MySql数据库的全量数据同步。然后,启用双写。这时候如果用户注册了,就会实时双写到两个数据库。那么,在全量同步和实时双写开启之间,这段时间两个数据库的数据还是不同的,所以需要再次增量同步,完成数据,防止数据不一致。剩下的时间就是监控各种日志,看双写有没有问题,看数据对比是否一致,等等。这段时间最长,也最容易出问题。如果有些问题比较严重,导致数据不一致,就需要从头来过,完全基于SqlServer构建MySql数据库,然后重新灰度流量直到结束。, 100%的流量全部灰度到MySql,此时大功告成,灰度逻辑下线,所有读写切到MySql集群。
3. MySql和ES主备集群解决方案
经过这一步,感觉主成员库应该没问题,但是dal组件的一次严重故障改变了我们的想法。失败是可怕的。公司内的许多应用程序无法连接到数据库,创建的订单数量直线下降。这让我们意识到,即使数据库好了,dal组件异常,仍然会导致会员系统挂掉。因此,我们再次对主成员库的数据源进行异构,将数据双写到ES,如下图:
如果dal组件出现故障或者MySql数据库挂掉,可以将读写切换到ES,等待MySql恢复,然后将数据同步到MySql,最后再将读写切换回MySql数据库。如下所示:
五、异常成员管理
会员制不仅要保证系统的稳定性和高可用性,还要保证数据的准确性和正确性。比如分布式并发失败,导致一个用户的APP账号绑定到别人的微信小程序账号,会产生非常不好的影响。首先,一旦绑定了两个账号,两个用户下的酒店、机票和优采云机票订单就可以互相看到了。想一想,别人可以看到你订的酒店订单,如果你不受欢迎,你会抱怨吗?除了可以看到其他人的订单,还可以操作订单。比如用户在APP的订单中心看到别人订的机票订单,他认为不是自己的订单,所以取消了订单。这会带来非常严重的客户投诉。众所周知,机票的取消费用是相当高的,不仅影响了用户的正常出行,而且造成了比较大的经济损失,非常不好。
对于这些异常的会员账号,我们进行了详细的审核,通过非常复杂和烧脑的逻辑识别出这些账号,并对会员界面进行了深入的优化和管理,在代码逻辑层堵塞了相关漏洞,并完成异常会员的账户。治理工作。如下所示:
六、展望:更精细的流量控制和降级策略
没有一个系统可以保证100%没有问题,所以我们必须有一个面向故障的设计,也就是更精细的流控和降级策略。
1. 更精细的流控策略
热点控制。对于hack dan的场景,相同的member id会有大量的重复请求,形成热号。当这些账户的访问超过设定的阈值时,就会执行限流策略。
基于主叫账号的流控规则。这个策略主要是为了防止调用者的代码bug导致的大流量。例如,在一个用户请求中,调用者循环多次调用会员接口,导致会员系统的流量多次爆炸。因此,应为每个调用账户设置流量控制规则,当超过阈值时,将实施限流策略。
全局流量控制规则。我们的会员系统每秒可以承受超过 30,000 tps 的并发请求。如果此时有可怕的流量调用,tps高达10万,不如让这波流量干掉会员数据库和es。超过会员系统限制的流量会快速失效,至少30000tps以内的会员请求可以正常响应,整个会员系统不会崩溃。
2. 更精细的降级策略
基于平均响应时间的降级。成员接口还依赖于其他接口。当调用其他接口的平均响应时间超过阈值时,进入准降级状态。如果接下来 1s 内传入请求的平均响应时间持续超过阈值,那么在下一个时间窗口内,会自动熔断。
根据异常数量和异常比例进行降级。当成员接口依赖的其他接口发生异常时,如果一分钟内的异常数量超过阈值,或者每秒异常总数与吞吐量的比值超过阈值,则进入降级状态,并在下一个时间窗口内自动融合。
目前,我们最大的痛点是会员通话账号的管理。在公司,如果要呼叫会员接口,必须申请呼叫账号。我们会记录账户的使用场景,设置流量控制规则和降级策略。但在实际使用过程中,申请账号的同事可能会换到其他部门。这时候,他也可以调用会员系统。为了省事,他不会再申请会员账号,而是直接使用之前的账号。这使得我们无法判断会员账户的具体使用场景,也无法实施更精细的流量控制和降级策略。因此,接下来,我们将对所有的调用账户进行一一梳理。这是一项非常庞大而繁琐的任务,
原版的