1、业务连续性挑战
在银行业,业务连续性是一个非常重要的领域。
当业务系统或业务场景出现故障后,快速通过切换实现我们的恢复目标,是我们容灾切换非常重要的能力。我们往往将业务场景切换过程分为以下三个阶段:
当每一个子系统都建成同城容灾的能力后,我们就可以认为我们的业务具备了同城级别的容灾能力。换言之,当我们的业务场景出现故障时,我们可以通过切换对应的系统快速恢复故障。IT架构往往分成系统、子系统以及应用三个层次,系统由多个实现特定业务功能的子系统组成,每一个子系统又由多个实现特定业务逻辑的应用组成。我们在建设容灾能力时,目前选择子系统作为容灾建设的最小单位,原因有以下几点:
上文中我们讲到通过子系统建设容灾能力,子系统在切换时,其实是将故障机房的一些服务全部拉出,然后把流量和服务切换到服务正常的同城机房。那么对于一个完成改造的子系统而言,它的服务分成三层,切换时需要对这三层的一些组件做解绑动作。最上面的一层是互联网的流量,例如我们公网的GLSB和 HTTP DNS等流量,也有一些广域网的专线,还有一些负载均衡的服务。 当流量进入内网后,我们通过内网的GSLB与负载均衡的切换实现HTTP层的流量调度。 对于一些微服务的流量,我们通过注册中心的 一些流量 拉入拉出实现流量的切换。除了以上三种,银行中还有一个比较特殊的服务模式——跑批,即晚上对当天的交易进行复核,跑批的结果会直接影响第二天银行能否顺利开门,也会间接影响我们服务的可能性。 在这个过程中,我们会对作业在哪个地方去跑等做一些切换控制。理论上,当子系统完成了一些架构改造后,通过这些流量的调度切换,就可以完成我们的工程切换。但实际上,也有一些长尾问题,比如有些子系统做一些双活的改造成本很高,或它是一些比较老的外购系统,这样的系统比例不高,但很重要。所以我们支持这些子系统切换的时候,提供了一些更加灵活的切换能力,比如我们支持做一些应用配置的修改,或者执行自定义的脚本,甚至会提供一些数据库层面的数据修改能力,让那些非标的子系统具备自动化、快速切换的能力,提高应急切换效率。 在数据库层面,更多的是像 Oracle、Mysql或MongoDB等数据库组件的切换。
在切换过程中,每一个类型的切换,我们内部都称之为一个原子的预案,切换工具会对这些原子预案进行预案编排。在执行前,我们有一个检查阶段,来确保目前处于适合切换的状态,才能执行。当完成执行动作后,我们还需要通过验证来确保执行目标的达成,但具体步骤不是由我们的工具提供,这些能力是由数据库团队或平台架构团队的变更能力提供。而我们的平台是通过HTTP的方式,让他们对执行、检查的步骤进行快速编排。这种检查、执行、验证的编排模式,让大家的切换能力变得更加标准化,也更加安全。当我们完成切换后,往往还需要对服务进行恢复,切换是从双活变到单活的过渡,当故障恢复后或演练要回切时,我们也会把单活的能力回退到双活的模式,这时候会有一个回退的编排。在回退编排中要做一些检查、执行和验证动作的编排。由于每一个原子预案都是很基础的预案,风险非常大。所以当我们的预案要发布时,会请每个领域的专家对预案的内容进行评估,甚至做一些测试来保证预案能达到相应效果,保证预案本身的安全性。
1)故障场景关联当我们有了原子预案能力以及明确的系统切换清单后,我们就可以在子系统层面编排子系统的预案,这个预案内容可能会包含一些应用、网络以及数据库的操作。当做子系统切换时,这些动作需要同步切换。但是我们可以将对应的故障场景进行区分,尽可能降低切换范围。2)串并执行编排我们完成双活改造后,切换对象之间的切换都是独立的,所以我们默认通过一些并行切换的方式提升整体切换效率。但是因为有一些长尾问题,例如有些子系统在切换之前需要先关闭一些流量才能执行后面的切换动作,所以我们最终提供的是串并行结合的编排能力。3)预案版本管理因为架构一直在发生变化,当架构发生变化之后,工具能够捕获到这种变化,我们会将这些变化信息同步给对应的预案维护人,他们可以通过这些提示信息对预案进行实时更新,以免发生价格变化后预案更新不及时的情况。4)演练状态标识预案维护后是未验证的状态,只有当子系统完成一次演练后,我们才会认为这个预案处于安全有效的状态,所以我们会在预案没有演练前,提示其切换过程中可能存在的风险。以上4个能力是子系统预案编排过程中比较关键的能力。当我们的子系统具备了预案管理能力后,我们再去做业务场景的编排会更容易。我们只需要明确业务场景中包含了哪些子系统,并按照故障恢复的优先顺序设定切换执行的批次即可。
在执行过程中我们会提供预案执行过程的看板,展示目前切换的耗时与执行成功与否,以及每一类组件切换的进度和状态。在执行过程中,如果说有一些步骤或一些预案执行失败,我们也可以通过一些下钻查看具体的报错原因。
上文讲的是如何通过工具体系提高业务系统的可能性,其实工具的可用性相比业务系统的可能性要求更高,因为发生故障时,你期望通过工具对业务系统进行恢复。我们在工具建设过程中,提出了更高的可能性要求。1)多活切换工具及其关键依赖,我们会在三个数据中心进行部署。这三个数据中心包含我们的同城机房,生产机房,还有第三地机房。我们会默认把主服务部署在第三地机房。这样当同城和生产机房出现问题时,工具可以快速接管服务,实施切换动作。切换工具,其关键依赖,以及变更能力是工具的核心能力,发生故障时这些能力不能出现任何问题,所以我们会定期对这些强依赖或关键依赖做一些容灾切换演练。2)降级登录等能力是切换工具的弱依赖,切换工具的核心能力是切换。当这些能力出现故障时,我们要尽量避免它对我们核心切换能力产生影响,所以我们会定期通过故障注入或者主动降级来做一些弱依赖的降级演练,确保弱依赖发生故障时,核心功能不受影响。3)性能我们也会对切换原子预案的执行性能做一些测试。我们在每一个原子预案上线前,会要求预案提供方提供性能测试的基准,明确指出每一个原子预案执行的并行度是多少,以及在对应并行度下切换的SLA是多少。这种情况下,工具可以对原子预案的执行做流控,保证切换过程的稳定性。
在应急或演练时,我们会有一个切换成功的标准:切换完成后,业务的关键指标没有明显波动,目标机房要承载100%的生产流量,应用层和基础层对应服务的一些能力满足对应的SLA要求。这需要我们给演练的实施人提供信息汇聚的能力,包括业务层、应用层以及基础架构层面的监控能力。
除监控能力外,我们也会以清单形式展示对应组件的情况。异常展示是分层的,只有出现异常时,我们才会下钻查看实际部署的异常展示。另外,我们也会将告警、变更等体现生产系统异常或存在关联影响的动作在服务节点进行标识,及时提示生产变更的潜在风险。
以上提到的展示能力都依赖于运维数据中台实现。在运维数据中台中,我们会将服务之间的调用关系以及CMDB的一些部署信息组合成一张拓扑关系网,并在每一个拓扑节点上附加一些配置属性、监控的 url 地址以及变更等信息,丰富每一个拓扑节点的数据。当有了拓补和信息之后,我们就可以快速提供可观测性能力,包括预案维护过程中识别架构变化的能力,以及一些自动化验证的能力。
1)影响范围评估我们的演练是为了提高生产的稳定性,所以我们在演练过程中,会对演练的影响范围做评估,主要包括以下几方面:
第二个风险是流程控制层面的风险。一个完整的流程,对降低演练过程的风险非常有帮助。流程的存在,也能够提升演练的有效程度。对于演练过程中发现的一些问题,我们可以通过问题管理的一些流程跟进,关注它的持续解决。但是流程的存在也会产生一些成本。因为流程本身非常复杂,有较高的学习和培训成本,并且在有制度无管控的情况下,达不到期望的管理效果,同时,完整的流程实施还会产生巨大的人力成本。所以我们将线下流程变到线上时,对这些信息做了一些梳理,通过一些强流程的控制,对那些存在变更风险或流程风险的地方做了设置的关卡,来规避一些流程中的风险。对于一些本身很复杂的流程,我们通过提示及引导的方式大大降低用户演练门槛。
我们在工具层面做了一些信息优化,来提升流程的效率。没有工具之前,单次演练的累计时长加起来可能长达三天时间,如果考虑它的起始时间,甚至可能长达一个月。当我们将演练线上化后,我们工具从四个方面提升了演练效能,缩短了演练时长。1)演练人员协同线上化演练可以通过识别,实现风险评估、方案制定和演练验证等环节的信息协作录入,这样的话我们演练的负责人只需要对结果做review和确认就可以完成演练的制定,大大降低了沟通协同成本。2)流程信息集成线上化演练可以集成变更管控、问题管理、审批管理等流程系统,并且在演练过程中自动完成流程信息的关联与状态翻转。3)辅助技术验证线上化演练可以通过面向不同演练对象建立标准化的技术验证格式和指标减少验证成本,还能够自动生成验证信息,大幅降低演练中验证信息的填写成本,显著缩短演练时间。4)运营决策分析线上化演练可以通过对演练过程信息的埋点,建立数字化的过程度量能力,并且通过多纬度的统计分析建立演练质量的运营分析能力,提高演练流程的质量和效率。有了上述能力后,单次演练的平均投入时间从原来的3天减少到2小时,效率提升了10倍以上,同时形成了常态化演练的条件,可以大幅提高我们演练的覆盖率。
上文讲述的内容是通过演练的方式验证切换预案内容本身的有效性,除此之外还应该验证人员的有效性以及流程的有效性。这些有效性往往通过培训或桌面沙盘模拟,以及应急响应演练来实现,因此我们开发了一套模拟执行的机制。通过模拟执行的方式,可以提升我们一线团队、一线同事对于切换流程的熟悉程度,也可以验证我们流程的有效性。
我们在做大规模演练的时候,会产生一些指挥层面的需求。比如我们的演练负责人需要关注参加当次演练的人员信息以及所设计业务监控的正常程度,并且需要关注切换过程中数据中心的流量变化。那么通过我们的指挥大屏,指挥官可以清晰看到数据中心运行信息。在演练过程中,我们也会将每个子系统的切换进度在大屏上进行展示。
1)容灾能力提升我们实现了容灾切换平台后,整个切换时长得到了大幅提升。目前我们一个子系统端到端的切换RTO小于10分钟,缩短至了原来的三分之一。对于应用类的切换,RTO的值更小,因为应用类切换的成本主要是不同系统之间的操作成本,当我们去按照一个预案批量执行时,基本上几秒钟就可以完成。2)业务切换能力那么因为我们建立了业务场景与子系统之间的关系,子系统又完成了预案管理的闭环,所以我们具备了业务场景切换的预案维护的闭环能力。当业务场景出现故障时,我们可以快速通过子系统的切换实现业务场景的一键恢复。3)应急方式丰富原来我们发现一些故障的时候,往往是通过重启、扩容、回稳这传统的三把斧方式恢复故障。有了切换能力后,我们有了更快速的方式,可以通过切换来快速恢复服务,同时切换的方式也是经过验证的,所以它也是一种较为安全的故障恢复手段。
除了业务连续性能力提升之外,我们还发现了额外的惊喜。1)常规变更我们原来去做一些技术架构层面的变更,无论是应用运维还是技术架构的同事都非常担心,变更可能产生一些较大规模的故障。当我们具备切换能力后,再进行机房维护时,我们就会提前将这些应用的流量及相关一些子系统的流量切换到我们的通讯机房,保障变更过程中的安全性。当我们完成技术架构变更时,再分批将流量切回来,大大提升了安全系数。2)蓝绿发版原来我们行业的发版主要集中在周二和周四,对于一些关键系统,这个时间点往往在周二周四的凌晨两三点钟,对于运维人员很不友好。当我们有了切换能力后,发布过程的安全性提升了,可用于发版的时间段延长,同时发版后业务异常支持快速回退。Q&A很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
我正在从erb文件切换到HAML。我将hamlgem添加到我的系统中。我创建了app/views/layouts/application.html.haml文件。我应该只删除application.html.erb文件吗?此外,仍然有/public/index.html文件被呈现为默认页面。我想创建自己的默认index.html.haml页面。我应该把它放在哪里以及如何使系统呈现该文件而不是默认索引文件?谢谢! 最佳答案 是的,您可以删除任何已转换为HAML的View的ERB版本。至于你的另一个问题,删除public/index/h
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
我认为我的问题最好用一个例子来描述。假设我有一个名为“Thing”的简单模型,它有一些简单数据类型的属性。像...Thing-foo:string-goo:string-bar:int这并不难。数据库表将包含具有这三个属性的三列,我可以使用@thing.foo或@thing.bar之类的东西访问它们。但我要解决的问题是当“foo”或“goo”不再包含在简单数据类型中时会发生什么?假设foo和goo代表相同类型的对象。也就是说,它们都是“Whazit”的实例,只是数据不同。所以现在事情可能看起来像这样......Thing-bar:int但是现在有一个新的模型叫做“Whazit”,看起来
我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion
参见下面的示例,我想最好使用第二种方法,但第一种也可以。哪种方法最好,使用另一种的后果是什么?classTestdefstartp"started"endtest=Test.newtest.startendclassTest2defstartp"started"endendtest2=Test2.newtest2.start 最佳答案 我肯定会说第二种变体更有意义。第一个不会导致错误,但对象实例化完全过时且毫无意义。外部变量在类的范围内不可见:var="string"classAvar=A.newendputsvar#=>strin
如果我构建了一个应用程序来访问来自Gmail、Twitter和Facebook的一些数据,并且我希望用户只需输入一次他们的身份验证信息,并且在几天或几周后重置,那会怎样是在Ruby中动态执行此操作的最佳方法吗?我看到很多人只是拥有他们客户/用户凭证的配置文件,如下所示:gmail_account:username:myClientpassword:myClientsPassword这看起来a)非常不安全,b)如果我想为成千上万的用户存储此类信息,它就无法工作。推荐的方法是什么?我希望能够在这些服务之上构建一个界面,因此每次用户进行交易时都必须输入凭据是不可行的。
我正在使用Devise在Rails应用程序中,并希望通过API公开一些模型数据,但应该像应用程序一样限制对API的访问。$curlhttp://myapp.com/api/v1/sales/7.json{"error":"Youneedtosigninorsignupbeforecontinuing."}很明显。在这种情况下是否有访问API的最佳实践?我更喜欢一步验证+获取数据,但这只是为了让客户的工作更轻松。他们将使用JQuery在客户端提取数据。感谢您提供任何信息!凡妮莎 最佳答案 我建议您按照以下帖子中的选项2:使用APIke
我正在开发一个Rails2.3.1网站。在整个网站中,我需要一个用于在各种页面(主页、创建帖子页面、帖子列表页面、评论列表页面等)上创建帖子的表单——只要说这个表单需要在由各种Controller)。这些页面中的每一个都显示在相应的Controller/操作中检索到的各种其他信息。例如,主页列出了最新的10篇文章、从数据库中提取的内容等。因此,我已将帖子创建表单移动到它自己的部分中,并将该部分包含在所有必要的页面中。请注意,部分POST中的表单到/questions(路由到PostsController::create——这是默认的Rails行为)。我遇到的问题是当Posts表单没有正
我的Rails应用程序在rails4.0.2上,我在使用locale变量和params[:locale]切换翻译时遇到问题官方railsguide.我在mysite有一个单页网站.我的国际化路线:scope"(:locale)",locale:/en|de/do#myrouteshereend我的应用程序Controllerbefore_filter:set_localedefset_localeI18n.locale=params[:locale]||I18n.default_locale#Rails.application.routes.default_url_options[:l