做者:张建鑫, 曾任IBM高级软件架构师, 滴滴高级技术专家, 现任新东方集团高级技术总监前端
古代东西方的思想家都产生过一个终极的追问,世界的本元究竟是什么? 老子说,道生一,一辈子二,二生三,三生万物,天道有常不以尧存不为桀亡。孔子说朝闻道,夕死可矣,孔子把对道的研究从,对人与天然关系的天道,转移到了研究君君臣臣父父子子的人道方向上。古希腊第一个哲学家泰勒斯说世界的本元是水,后来毕达哥拉斯回答说世界的本元是数字,古希腊哲人对道的研究始终聚焦在人与天然关系的天道方向上。对终极追问的不一样思考和回答,衍生出了,东西方在文化价值观,思考逻辑和作事方法等方面的巨大差别。mysql
咱们在企业里工做,实际上也存在一个终极追问,就是你的终极用户是谁?怎么服务好终极用户。我曾经在2B技术公司IBM工做过12年, 在2C技术公司滴滴工做过三年。 我深切感觉到,在这个问题上的不一样回答,致使了传统的IT技术公司和互联网技术公司, 在工做价值观,和工做方法等方面的不一样。nginx
一般,B端技术重功能不重体验,软件客户每一年续签一次合同,软件开发商能够经过各类手段增长用户迁移到其余竞争对手的成本,深度绑架用户,即便客户对软件有一些不满意也会续签合同。 而互联网的C端我的用户是典型的用脚投票,抛弃一个产品的时候,一声再见都不会说。 所以互联网产品技术的竞争是典型的赢者通吃,产品体验稍有不一样,短期内用户就会流失到竞争对手那里。因此互联网产品技术极度关注用户体验,和用户客诉。 IBM解决客户的客诉流程冗长,有所谓的一线二线三线技术支持,解决一个客诉动辄数月之久。 可是互联网C端技术须要时刻关注用户客诉和线上事故,争分夺秒的解决问题,甚至要求几分钟内就把问题解决掉。 因此如何避免和减小客诉, 如何快速处理线上故障,就成为区别2B,2C技术公司不一样点之一,对价值导向问题的不一样回答,也产生了彻底不一样的价值评估系,最简单的就是如何去判断一项具体工做的轻重缓急和重要程度。面试
我刚来新东方的时候, 个人团队里没人关心客诉问题,没有技术值班,上线流程很草率。 互联网公司里重要的技术方法到了IBM那里,就可能变成过分设计,变成不重要的工做,但其实没有毛病, 由于俩者的业务场景和最终用户是彻底不一样的。因此必定要认识清楚,咱们工做的end user是哪些人, 以及如何服务好最终用户。 当最终用户满意时,咱们的工做天然就会被公司承认。因此我认为不少事情不是技术问题,而是价值导向问题,价值导向对了,咱们的技术规划,架构选型就天然作对了。我是被IBM培养出来的,但到了滴滴后,只要愿意改变,同样也能作好互联网的技术工做。redis
在互联网产生以前,最大的计算机系统就是银行柜员系统,用户必须去银行网点排队办业务,银行网点人满为患,全部的交易都经过柜员处理, 你们想一想看,这实际上就是经过人工排队的消息队列进行了削峰限流,最后全部交易都集中在一台价值几亿人民币的 IBM大型计算机里, 在集中式的DB2或者Oracle数据库里完成交易。 今天互联网电商的交易量要比银行大的多,全部的系统都是分布式系统了,与之前的集中式系统相比,分布式系统最显著的特色就是容易扩容,今天银行的IT系统也都互联网化了,大多数的银行业务均可以足不出户在家自助办理了,因此咱们必须看一下什么是分布式系统算法
分布式系统是由许多计算机集群组成的,但对用户而言,就像一台计算机同样,用户感知不到背后的逻辑。分布式系统最重要的理论是2002年被科学家证实的CAP理论
C是数据一致性, A是可用性, P是分区容错性。 CAP三者之间是互相矛盾,互相影响的关系。sql
其中,最好理解的是A,A是可用性。 可用性存在两个关键指标。
首先是“有限的时间内”,其次是“返回正常的结果”,若是用户的操做请求返回的是400或者500错误,或者规定时间内没有返回结果发生了超时,那就算是发生了一次不可用。因此并非说,只有发生了线上大规模事故,所有服务不可用才是不可用,发生400,500错误或者请求超时都属于不可用。数据库
P是分区容错性:当系统发生消息丢失或局部故障时,仍然能够运行
在分布式系统中,当一项数据只在一个节点中保存时,万一放生故障,访问不到该节点的数据,整个系统就是没法容忍的。
若是这项数据复制到多个节点上,某个节点数据访问不了时,系统仍然能够从其余节点上读到数据,系统的容忍性就提升了。
可是多个数据副本又会带来一致性问题。要保证一致性,每次写操做就都要等待所有数据副本写成功,而这种等待会损害系统的可用性。
总的来讲就是,数据副本越多,分区容忍性就越高,但要复制更新的数据就越多,一致性就越差。因此CAP就是一种按下葫芦,就起了瓢的感受。后端
C是数据一致性, 分布式系统的数据一致,是指全部服务器节点在同一时间看到的数据是彻底同样的。 若是成功更新一个数据项后,全部的服务器节点都能读取到最新值,那么这样的系统就被认为是强一致性的。系统若是不能在规定时间内达成数据一致,就必须在C和A之间作出选择。注意规定时间内是很重要的。缓存
如今的系统都是分布式系统了,P是不可能放弃的,但通常来说,架构设计要尽可能减小依赖,系统依赖的基础架构组件和第三方系统越多,若是P太强了,整个系统的C和A,可能都会受到损害。 架构取舍更多的是在C和A之间作出选择。而没有分布式的CA系统就是关系型数据库,就是放弃了分布式,放弃了分布式的扩容能力。
有些场景要求数据强一致,例如与钱有关的与订单有关的系统,这种场景下,或者舍弃A,或者舍弃P。 关系型数据库是强一致的CA系统,
但若是mysql引入了从库,就会在必定程度上损害数据一致性, 但同时换来了A可用性或者读写性能的提高。
而TIDB采用raft协议,数据保存在至少三个副本里,同时它要兼容mysql,实现数据的强一致性, 因此既然,TIDB引入了P,就只能在必定程度上要舍弃A,读写性能会相应下降。可是加强了分布式的扩容能力,包括了存储和算力的扩容。 因此CAP理论告诉咱们,全部便宜都想占到是不可能的, 只能根据实际业务需求和价值判断体系,作出取舍。
BASE理论是对CAP理论的延伸,是指基本可用、软状态、和最终一致性。基本可用, 好比在规定的1秒内熔断了,没有返回结果, 那咱们又重试了两次,结果返回告终果,这个就是基本可用。 假如我重试了两次后,仍是失败了, 咱们作了一个降级处理,让用户仍然能够继续使用服务,这个也叫作基本可用。
最终一致性是指系统中的全部数据副本通过必定时间后,最终可以达到一致的状态。最终一致性是弱一致性的特殊状况。
新东方不一样业务系统对数据一致性的要求都不同, 本质区别就是具体的业务能够容忍在多长的时间限制内,达到最终的一致性。
FLP不可能原理, 请自行查找解释,此定理告诉咱们,不要试图设计一个可以容忍各类故障并保持一致的分布式系统, 这是不可能的. 分布式事务也永远没法实现单体应用级别的一致性。即便如paxos协议和raft协议也会出现没法达成共识的状况,只不过出现的可能性很低。因此说paxos是有效的一致性算法,但也不可能作到天衣无缝。
集团首席架构师 幺敬国老师在极客时间上作过zookeeper的系列专题讲座, 对raft协议是专家,我纯属外行,你们有任何问题能够请教他。
若是剥离掉具体的业务目标和产品目标,那咱们就会发现, 咱们C端技术工做的目标,其实正好就是分别对应前面讲的CAP。可是同时知足三个要求是很是难的,只能根据具体业务场景进行取舍。 Tidb的开发商的名字叫PingCap就是一个颇有雄心壮志的名字,意在无限的同时逼近这三个目标。
如今C端系统都是分布式的,舍弃P是不可能的,并且业务又会要求咱们必须保证系统的可用性,所以事实上咱们C端技术能舍弃的也只有规定时间内的数据一致性。
一般只要在数秒钟甚至数分钟,甚至1天后,能够达到最终一致就是能够接受的。 咱们牺牲了一致性,换来的就是A的大幅度提高,和性能的提高。
接下来咱们,结合APP的工做实践分别讲一下分布式系统经常使用的基础架构组件
首先讲一下缓存。刚才讲过了,数据拷贝越多, 数据一致性就越差,引入缓存必然会损害规定时间内的数据一致性,所以数据缓存时间一般不宜过久,持久化的缓存数据更是荒唐。Redis对外提供集中式的缓存服务, 只增长了一份临时数据副本。 但Guavar是基于JAVA的本地缓存,每台JAVA服务器在本地保存一份数据副本,会显著损害整个分布式系统的数据一致性,而且形成相关客诉。
除了数据一致性, 使用redis也会涉及到系统可用性问题。 Redis其实是一个CP系统。对于Redis, value越大,读写访问的延迟就越大。使用缓存时,要避免使用大Value和大Key,不然会下降可用性。大值能够采用序列化后压缩的方法。 与大值相反的另外一个应用极端是, 大Key小Value,这种Key能够经过MD5压缩来避免。 一般来说redis的平均get请求应该是数十微秒级别的,这种高速缓存部署时要和应用服务在统一的IDC, 避免跨机房部署,由于跨IDC一般会有毫秒级的延迟,从而损害系统可用性,使用缓存的意义就不大了。
此外,Redis可使用pipeline提升批量访问性能,能够想见网络请求数量会所以大幅度减小。
使用缓存时要思考如何提升缓存命中率,对应的就是如何减小缓存穿透率, 减小对第三方系统或者对数据库的压力。
理想状态下,系统中的热数据应该都存在缓存里。 一个极端是压测, 很差的压测设计是,不停地,频繁地,重复地,请求相同的测试用例,其实第一次就是预取, 数据变热后, 压测快的飞起,可是一到线上真实环境, 可能就不行了,由于线上没有那么多重复请求。但在真实业务场景下,能够跟据用户的真实的操做序列, 预测出来哪些数据将会很快会被用户访问到, 此时,咱们就能够采用预先计算和预取数据的方法,在用户后续操做发生时直接从缓存里读取数据。
此外,刚刚发生读写操做的数据,能够认为都是热数据,均可以考虑预取到缓存。
下面这张图是在剥离掉具体业务后的,APP使用缓存的架构方法。
首先讲主动更新缓存,
首先第一个操做是须要更新数据的事务操做,能够考虑主动更新缓存。对一致性要求高的业务,事务主动更新缓存时必须从数据库主库读取数据,不然会由于数据库主从延迟致使缓存数据和数据库里的不一致。 还有一种状况,缓存的值是一个集合set,须要一次更新不少数据项,这种操做没有原子性保障,就必须用事务保障,须要加锁。因此主动更新缓存的方案是不够严谨的,容易致使数据不一致。还有就是发数据更新消息,这时候数据变动MQ必须把全部信息都带上, 典型的如binlog。 若是只是通知一个变动事件,可能就会致使缓存数据和数据库不一致。因此binglog多是最不容易致使一致性问题的方案。 但有时候我就是拿不到binlog怎么办, 并且严谨的方案显然在技术上会更复杂,落地成本会更高。
我想说,不严谨的方式不必定就不能用, 时刻记住业务场景能够弥补技术上的不足,架构设计时实用主义比完美主义更适用, 更能多快好省地解决业务问题。采用什么方案,首先是要考虑业务场景是啥, 其次是要考虑,万一出问题了后果是否可控,不要追求完美。特别强调,报名续班优惠的同窗,千万不要这么玩,若是非要这么玩,出问题后果自负。
第6个操做是主动更新缓存, 缓存快过时时,发生读操做,能够考虑要主动读取源数据,更新缓存,当第三方故障,致使数据源没法读取时,能够主动延长缓存时间。 作一个降级处理,提升系统的可用性。
再讲一下本地缓存Guava。比起集中式的redis缓存,本地缓存的副本更多了,数据一致性也就更差了。若是网关不采用特别的分发策略, 本地缓存时间建议要设置的很短,为的是缩短各节点数据最终一致达成时间。
下面这张图的右边采用了一致性hash的负载均衡策略, 根据用户请求散列,保证各个服务器上的缓存数据没有交集,这样就提高了数据一致性。但这样作等于本身作了一个分布式的redis,严格讲,不可能比redis搞得好,可是好处就是,架构上减小了一层对redis的依赖,系统可用性提升,性能提升。
具体怎么取舍,仍是要看业务的实际需求。不少数据库调优的工做,最终变成了玄学。就是由于系统参数太多了。 基于CAP定理,你不可能什么好处都获得,顾此必然失彼。
其余使用缓存的小窍门还有设置缓存时间时加一个随机值,避免缓存集中过时带来的问题。剩下几个前面都涉及到了,就再也不讲了
接下来,快速讲一下消息队列。 消息队列能够应用到分布式事务,分段式提交里。 也能够帮助系统架构解耦。 能够用来作削峰限流,既不超过系统承载能力,同时又不丢失用户消息。消息队列服务的SLA是保证消息不丢,但牺牲掉了消息不重。会重复发送同一个消息。因此就要求消费者保证操做的幂等性。
消费者的拉消息模型, 好处是消费者不会过载,超过最大处理能力。坏处是消费者须要专门引入一个单独的服务进程或者线程。
消费者的推模型,消费者构型简单,跟开发一个用户接口同样。坏处是可能会过载。
常见消息队列如kafka和rabbitMQ的特色,我就很少讲了。
下面这张图,我快速讲一下数据库。
数据库的主库从库读写分离,通常会形成规定时间内的数据不一致现象,所以在须要强一致的状况下, 能够先读从库, 若是读不到,再去读主库,必定程度上能够减小主库的压力。 牺牲了一点儿数据一致性,提高了系统的可用性。
分库或者分表能够显著提高数据库的读写性能。 定时归档和分表同样,是减小单表的数据量,提高读写性能。 减小没必要要的索引,任何数据库的读写操做,即便没有使用事务, 对数据库而言也都是一个事务。 为了保障数据库的ACID属性, Insert操做必须在全部索引创建完成后才能返回,所以单表创建过多的索引会拖累数据库的性能。
分布式系统里,要尽可能避免耗时的数据库操做, 好比数据库事务操做, 联表查询等操做, 由于这些耗时操做,就是让系统在规定时间内的A达不到了。根据业务特色能够采起最终一致性的概念,结合消息队列,使用分段事务提交的方法,适当延长达到一致性的时间,来换取系统可用性的提高。
在新东方APP的做业系统里, 发做业就是一个典型的分布式事务。 此外,因为学生的报、转、退,和插班动做,产生了不少学生收不到做业,做业错乱的客诉。 所以结合消息队列,分段提交。 而且用定时任务扫表,作各类补偿操做,解决了大部分的客诉问题。
结合CAP定理,再说一句, MYSQL是CA系统, 若是mysql增长了从库,也就是引入了CAP里的P, 可是mysql主从分离的分布式属性,比起tidb的分布式属性要差一些,由于这样只是扩容了算力,而不是扩容了存储。数据库主从分离,是引入P,牺牲了C,加强了A,SQL查询变快了。 可是对于很短的,规定时间里, 要达到数据强一致的业务场景, 读写必须都走主库,但还好,这种业务场景是比较少的, 新东方的报名续班业务是一个。
结合CAP定理, Tidb是一个典型的CP系统,至少有三个数据副本,经过raft协议实现三副本数据的强一致。由于引入了P,TIDB的分布式扩展能力比mysql好,不管是存储扩容仍是算力扩容都比mysql好。并且tidb兼容mysql,保证数据的强一致性,因此tidb对于订单交易业务,是一个很好的选择。 这些年银行大大小小的不可用事故,发生了不下10起,但没据说谁的钱丢了。 因此涉及到钱和优惠券的场景, 宁肯发生服务不可用事故,也不能发生数据一致性事故, 所以CP系统保证了钱不丢,又保证了分布式扩容能力,是一个互联网时代下的很不错的选择,但规定时间内的可用性就会差一点儿。
新东方APP由我学APP发展而来, 目前也支持新东方的所有业务线的搜课服务,以及K12的学生端与教师端服务
新东方APP2019年之前的架构能够用一团乱麻来形容,架构没有分层,并且乱拉电线。主要的问题有
一、前端不止作了展示交互, 也作了各个后端系统的数据聚合工做, 前端计算聚合完的数据,还要写到后端。这其实就是10几年前游戏的作法, 黑客能够经过改动魔兽世界的客户端, 就让金币增长,或者得到特殊装备,那就是由于把不少关键的业务计算逻辑放到的客户端完成。整个架构没有符合单一职责,和开闭原则的设计规范,最后就是用APP包了一层皮出来。
二、先后端都没有熔断、降级限流等稳定性设计,听云监控看到一个请求耗时几分钟, 其实用户早都杀掉APP了。
三、没有业务上监控报警, 被动等客诉,代码里基本不写错误日志。先后端都应该有监控报警。前端页面加载失败, JS错误这些都应该上报错误日志。
四、服务器性能不好,单节点只能承载15个并发请求。不是全部问题均可以经过加机器来解决,这么差的性能已经不是加机器能够解决的了。
五、数据不一致现象严重,同一份业务数据, 在多个系统,甚至端上重复计算,分别存储,没有事务保证,不考虑并发设计,致使数据不一致的客诉不少。
系统里存在太多的单点故障。 MQ, NFS存储、定时任务。都曾经爆雷
六、研发效率低,代码里不少地方的注释写着, 此处有巨坑, 很差改, 先这样吧, 之后再说。。。这也说明,之前多是没有代码review流程,技术方案review流程的。
七、数据库处处是JOIN操做,性能极差,多表写入,并发写入都不考虑事务保护,形成数据不一致现象广泛发生,该用幂等操做设计的地方也没有用。缓存的使用也存在问题。
以上就是新东方APP架构2019年之前的样子。
新东方APP最核心的功能是学生作做业。这张图是之前,新东方APP里趣配音的做业架构,这个架构发生过不少次服务不可用事故。
你们还记得前面的定理描述, 可用性是在规定的时间内要返回正常的应答。而400应答,500应答增多就是系统服务的可用性下降了。不是非要等整个系统已经ping不到才算不可用。
因为做业,不管是上传仍是下载,都占用链接池的时间过长,因此致使其余服务都受到了影响, 下降了整个系统的可用性。
用户中心头像服务超时严重, 分析缘由也都是由于NFS存储致使的。因此为了保障做业稳定性,提高学生作做业的体验,必须拆除掉对NFS存储的严重依赖
下面这张图是目前新东方APP的趣味配音做业的架构,这个架构比较复杂,第一次分享,没有润色,稍微有点乱。
这个图里的绿色文字步骤都是降级操做。新的架构设计应用了BASE定理, 经过基本可用,最终一致等概念,显著提高了整个做业系统的可用性。
和旧的架构相比,新的架构拆除了整个用户交互过程对NFS存储的的依赖, 使用腾讯对象存储做业主力存储, NFS降级为备份。这个方案还抵挡住了好几回腾讯云的线上事故。
当腾讯云对象存储发生了故障时, NFS会被启用, 短期内会有必定的数据不一致,但因为NFS被设置成对象存储的回源地址, 所以两边存储最终仍是会一致的。
腾讯云CDN和对象存储发生过屡次故障, 持续时间从数分钟到10分钟左右不等, 咱们的新架构都抗过去了,没有发生任何稳定性问题和客诉, 曾经有一次, 新东方到腾讯云的专线流量激增, 就是由于腾讯云的CDN出了问题,没法访问,APP端发生大面积降级,带附件上传做业的比例显著增长, 查看做业结果视频的降级也同时显著增长。
除了混合云存储, 咱们作了自动弹性到腾讯云的混合云计算。 当咱们本地的视频合成服务过载时,计算任务会自动弹性到腾讯云的FAAS计算。没有发生弹性时,咱们不须要给腾讯云付钱, 发生弹性时, 每月100万次如下的计算是免费的。因此能够说, 咱们以这种方式,基本没花钱,就增强整个系统的可用性。
做业是APP最重要的功能,从咱们的价值导向判断,做业稳定性投入再多时间和精力,都是值得的。目前新东方APP的做业系统已经被改形成一个打不死的小强。
快速说一下,熔断降级限流, 前面的PPT都提到了。
这里再说一个APP熔断重试的bad case,APP团队之前的系统里,把Redis配成默认1秒熔断,20次重试。 结果有一次,redis发生故障时,拖累整个APP服务故障,全都不可用。你们记住redis是CP系统。
关于限流, 有一次,由于外部的爬虫致使APP对教务的访问增长,流量激增,最后为了系统稳定,在nginx上增长了限流处理, 保护了内部ERP系统的稳定。
快速过一下JVM优化
这一页是APP作JVM优化的实际案例。 我抽象总结一下,就是要尽可能避免,一次申请很是大的内存, 例如打开一个10几兆的图片, 例如,不分页,一次查询10几万条数据库记录。
当年轻代内存不够用的时候,这些内存会直接进入老年代,若是这些操做是比较频繁的,就会致使频繁的Full GC,损害整个系统的可用性。 优化以后,full GC频率就明显降低了
再说一下咱们作的题库改造工做,
因为B/C两端对产品技术能力模型要求不同,之前题库跟APP的技术模块是混在一块儿分不清的,致使工做效率下降, 部门合做成本提升:
C端: 大用户量, 高并发, 影响大, 直接承接外部用户流量
B端: 用户量少, 并发低,如内容系统,题库等, 承接内部用户流量
因为B/C两端支持的用户类型不一样, 面对的问题域不一样,应该拆开,提升各个部门的研发效率,和跨部门的协同效率
除了研发效率, 之前有些数据好比测评结果数据,学情数据在TPS和泡泡服务器上多处存储, 数据不一致现象很是严重, 由此发生不少很是难解决的客诉,不下定决心作B/C服务拆分,就没法完全解决相关客诉,和提高整个做业系统的稳定性。
这里说一下去年咱们的数据库迁移工做。
咱们把数据库从tidb迁移到了mysql,同时作了分库分表,和索引优化,删除了大量没有必要的索引, 查询写入性能提高了十倍以上。
这么作的缘由是,咱们APP业务尤为做业, 对数据强一致性没那么高的要求,咱们须要的就是高可用性。 TIDB是很好, 但它是一个CP系统用到这里,是场景不对。
这页PPT是听云的监控数据。APP团队技术优化工做让用户的体验更流畅,系统更稳定。
经过听云监控的图表能够看到,99百分位的请求应答性能累计提高了163倍。
经过APP客诉统计分析, 能够看到,APP用户量增长一半以上的状况下, 客诉率降低了一倍多。
这个图上是咱们本身开发了一套,APP和H5的监控告警机制,当APP的加载超时,访问错误直接上报。
经过APP向H5注入代码, 也实现了对APP上全部的H5页面的监控, H5页面中的JS错误,请求错误,均可以即时上报。
再结合公司的听云监控,运维的监控系统,咱们的监控就能够在客诉发生以前发现很多问题,也能够经过监控,发现不少系统稳定性的地雷,即时拆除。
目前APP这边日志都加了TraceID,在必定程度上能够帮助研发快速定位分布式系统的问题缘由。
但也有问题,前端后端的traceID没有打通,APP和其余系统的TraceID没有打通,须要公司级的日志监控告警的基础架构组件支持。
下图是,聚合监控告警服务实时分析日志数据,发现预警后, 告警被打倒钉钉群里, 技术值班人员能够经过密切关注钉钉告警,提前发现问题。
根据APP业务特色, 还作了一些服务化的改造。 对一些业务作了抽象剥离与解耦重构
在新的架构里,咱们清晰的引入了服务接入层, 后台作服务化改造。作各类服务拆分与解耦,重构的工做。让整个架构更清晰, 各个模块的职责更明确, 系统的稳定性更高。
新东方集团的主数据的问题有一点相似数据库从库或者是本地缓存带来的的问题,数据副本太多, 数据不一致,数据质量很是差。
各个使用主数据的系统彼此之间调用和对比数据时,也会发现数据不一致。 主数据带来的客诉,和线上故障不少。所以吴强老师下令拆除主数据服务
为此, 咱们启动了C端数据中台OnePiece项目的开发建设工做。
先说一下用户中心的头像服务。请求失败率长期超过50%
在老用户中心的头像服务里, 即便是查询头像URL这种轻量操做,代码里也要用fexist fopen这种很重的IO操做去验证头像图片上,IO耗时不比下载头像少。 此外因为头像没有放到CDN上,所以全部的头像图片下载请求都回源到应用服务器上,应用服务器又是访问本地NFS存储。因此整个系统的可用性极差。
开闭原则你们自行查找, 在这个具体案例里
符合开闭原则,就是当你采用新的数据接口的时候,你也要能够保持老接口继续可用, 同时提供新的数据服务接口
我刚接手用户中心改造工做时,就马上发现其实只要把新用户中心的数据打平, 就是老用户中心的数据接口,老用户中心的服务不使用stuID数据字段就能够了。
接着上一页PPT讲, 咱们在新用户中内心彻底接管了对老用户心中的访问。经过打平新用户中心的数据库结构实现对老用户中心服务用户的平滑迁移。
在迁移期间, 数据写入是双写的,为的是出现故障时,快速止损,快速回滚服务,快速回滚数据。迁移期间, 数据查询请求也是两边都请求。 由Apollo作一个开关,决定用那边的请求应答响应用户。 同时也是为了作一个数据对比,及时发现和修复BUG。
数据库主从分离, 自己也是牺牲了数据一致性,换取可用性。但数据库写入操做通常都是强一致的,因此在写入数据以前若是须要读取任何数据库数据,应该是强制读主库(甚至要用事务或锁包读写过程保护起来),而不能读从库,更不能去读缓存。
前面缓存那一页PPT讲了不少了这边就再也不赘述。我想强调一下, 咱们作老系统的改造和迁移时, 必定要设计好上线计划和回滚计划,在开始动手写代码以前,就写进技术方案里面。 上线以前首先就考虑,上线后出现故障怎么办? 出现故障时,是否会产生脏数据和数据丢失,发生故障时, 及时止损, 不只仅是服务的回滚恢复, 还有数据的回滚恢复。以及如何快速回滚。
用户中心更新缓存时,因为数据结构很是复杂,有多级列表,所以为了减小代码复杂性,必需要先删除缓存,再从新加载,这期间必需要加锁,有事务性保障。减小数据不一致发生的可能性。但须要数据强一致的操做仍是要强制读数据库主库。
用户中心在测试期间要用线上真实流量的回放作一次压测。 多啦A梦,这个是咱们团队的测试专家吴兴微老师开发的测试工具。 具体你们能够问他怎么作的。我不作解释
此次咱们也重构了教务中心的C端服务。目前教务中心提供的查询服务都是经过ES实现的,C端可用性不高。 此次咱们拉了教务的从库来保证C端数据查询的高可用。
因为教务的数据结构复杂,仅仅APP业务须要的查询操做就涉及到20几张表, 所以为了消灭和减小这些耗时的JOIN操做,提升系统可用性, 咱们把几个大的维表(最多有12万条记录的)加载到本地缓存里,在服务器的内存里实现JOIN操做。 由于维表数据量大,所以大批量加载数据进redis是不现实的,并且列表的聚合若是走redis,也会增长请求数量,损害redis的可用性。
交易表的聚合依然是在数据库里完成的,根据目前的业务特色聚合结果也是能够短期缓存的。在引入本地缓存组件后,请求路由上就必须使用一致性Hash,把服务器的本地缓存数据进行分区处理。这里的hash key目前肯定是校区ID,班课ID,用户ID等, 之后可能还须要持续优化策略。
最后数据中台Onepiece项目的测试方法,仍是准备用吴兴微开发的多啦A流量回放工具,用线上真实流量作测试。
测试完毕后,准备采用灰度发布加蓝绿发布的方式上线。
OnePiece也是对MDM服务的平滑迁移, 所以兼容主数据服务接口, 在迁移上线期间, 能够用Apollo开关, 一个接口一个接口的, 先10%小流量。 没有问题主键放量到100%。 全量发布后能够经过日志继续对比数据, 及时发现罕见场景下的问题。
整个系统的上线过程持续三周以上,天天都发布上线几个接口,期间研发密切观察监控和客诉,一旦发现问题, 就能够经过apollo开关, 一键快速回滚。有效地,把线上问题和风险控制在很小的范围里。
前面讲的东西其实没有什么技术含量,都是能够快速习得的经验。 咱们团队面试时,最看重的是逻辑思惟能力,写代码能力,和学习能力等硬核素质。
感谢你们! 新东方教育科技集团公司正在加速推进互联网产品技术布局,组建彻底互联网化的技术团队,很是欢迎加入, 为中国的教育发展贡献本身的一份力量。