扩容成本直降2000万!山东移动精华实践分享!

本次分享的这个项目通过引入可横向扩展的分布式缓存架构,针对访问频繁的相关表如字典表和三户资料数据,通过应用改造,放到分布式缓存中进行管理,并和数据库互动,大幅降低数据库访问次数,从而达到提高应用效率、降低扩容压力的目的。


项目上线后,实现了应用效率提升和扩容投资降低的目的,实际上线运行情况表明,针对访问最频繁的top 30的表进行缓存处理后,整个数据库访问次数下降30%,关键业务处理性能提升15%。

一.项目实施背景

随着各类业务的发展,对运营商核心OLTP数据库处理能力提出了越来越高的要求,尤其承载核心用户资料数据的crm系统,压力越来越大。传统的性能优化方法,如主机扩容、数据库优化跟不上业务需求压力增长速度,且扩容成本很高,投资巨大。

传统性能优化方法基本基于主机和数据库,但数据库如Oracle方面难以实现横向扩展,扩展能力受限。应用层,可以通过增加服务器数量实现扩容,但是在核心数据库层,由于采取Oracle rac构建,其基于共享存储的机制造成系统io压力越来越集中,io的瓶颈难以通过简单扩容实现,节点数扩展越多,性能下降越明显,同时单台数据库服务器的处理能力也是有限度的,难以无限制的增加,只能通过拆分数据库来进行性能的扩展,但是又增加了数据迁移的难度。

上述背景要求我们寻找一种新的性能优化方法,可以降低核心数据库压力,同时又能实现可扩展的灵活架构方案,从而更好的实现高效低成本。

二.方案做法

1技术方案

通过在应用层引入分布式缓存技术Memcache,实现可灵活横向扩展的基于x86的分布式缓存架构,针对访问频繁的相关表如字典表和三户资料数据,通过应用改造,放到分布式缓存中进行管理,并和数据库互动,大大降低数据库访问次数,从而达到提高应用效率、降低扩容压力的目的。

整体架构如下(简单示意):


图1应用架构图

即在现有三层架构,web层->cics层->database层基础上,增加Memcache缓存层(上图红色部分),使在应用访问数据库时,可以将数据缓存在Memcache集群中。

针对TOP N业务进行改造,以山东公司为例,top 10业务占总业务量的80%以上,即仅仅改造10个业务,即可实现性能效果大大大提升。


2Memcache介绍

Memcached是一个高性能的分布式内存对象缓存系统,用于减轻数据库负载,目前在互联网行业应用较为广泛。它通过在内存中缓存数据和对象来减少读取数据库的次数。本项目采用Memcache实现缓存机制,也可以采用其他缓存软件如redis等实现。

Memcached基于一个存储键/值对的hashmap。其守护进程(daemon)是用C写的,但是客户端可以用任何语言来编写,并通过Memcached协议与守护进程通信。



图2 Memcache原理图

3应用访问逻辑改造

增加缓存层后,应用的访问逻辑需要改变,主要表现在,增加缓存前通过直接访问数据库实现,直接写SQL即可,但增加缓存后,需要增加针对缓存的处理,通过应用逻辑实现数据的获取。

应用针对缓存访问方法和步骤如下:

1.每个会话访问表时,先判断数据是否在缓存中,如是则从缓存取,否则从数据库取,并同时写入缓存;

2.如有多个缓存,则在缓存前置分发器,根据一定规则分发到不同的缓存处理;

3.缓存取不到或缓存故障下,直接从数据库中取,前台返回无任何影响;

4.数据更新时直接更新数据库,并同步触发缓存更新逻辑;

5.更新缓存时第一份缓存和数据库同步更新,然后触发其他缓存间的同步更新,由于是在缓存间的数据同步操作,性能影响几乎可以忽略不计。

详细数据访问流程如下图引入缓存后的数据读写流程图所示:


图3引入缓存后的数据读写流程图

下面分场景介绍缓存访问逻辑:

数据加载场景:

1.  先到分发器分配的一份缓存中查询,数据是否在该缓存中,如果在直接返回;

2.  如果不在,从物理库读数据;

3.  将读取的数据装载到缓存1,同步触发对缓存2…n进行加载。任何一个缓存操作失败,则标记为不可用,后续不再分发业务;

4.  同时把数据结果返回给业务。

数据更新场景:

1.  先到分发器分配的一份缓存查询,更新前的数据是否在缓存中;

2.  先更新物理库;

3.  根据第一步判断如果在缓存,则把物理库的更新变化刷新到缓存,否则启用装载流程,装载到缓存,如有多个缓存同步进行更新,任何一个缓存操作失败,则标记为不可用,后续不再分发业务;

4.  把数据结果返回给业务。

业务连续性保护机制:

IT系统不可避免会出现故障,当Memcache server不可用时,异常处理机制如下,将不影响业务运行:


图4缓存高可用措施流程

1.  当某一台server不可用时,根据key查询MemCached中数据,返回server不可用错误,则执行数据库查询,在配置多套集群情况下,也可从其他集群访问。

2.  当故障的server恢复后,自动按照正常流程访问 。

3.  集群中其他可用的server按照正常流程访问。

三.运行效果

通过将top 10的业务涉及访问最频繁的30个表改造为Memcache访问机制,数据库整体压力降低30%,top 10关键业务平均响应时间降低15%。

1、应用效率提升明显

2、成本压力大大降低

数据库压力降低40%,去掉计划内的增长15%,相当于整体下降核心系统25%的扩容能力,经计算可降低扩容成本2000万元。

附:统计的各表访问次数下降情况

Q & A

Q1:对于缓存数据是不是需要业务改造?

A1:是的,需要应用做比较大的改造,以前我们的CRM应用都是直接sql获取数据,现在通过key-value方式,几乎关键业务全部修改了一遍。

Q2:刚才提到“针对访问频繁的相关表如字典表和三户资料数据,通过应用改造,放到分布式缓存中进行管理”,针对更新频繁的表(如受理日志等)是不是不适合通过此类方式改造优化?

A2:针对读多写少的表,非常适合,但是对读写差不多或写多读少的表,效果要差。我们统计过,我们正在改造的核心表,读写比例在8:2以上。

Q3:Memcache选择的什么版本?

A3:版本1.4,比较老。

Q4:根据第一步判断如果在缓存,则把物理库的更新变化刷新到缓存,否则启用装载流程,装载到缓存,如有多个缓存同步进行更新,任何一个缓存操作失败,则标记为不可用,后续不再分发业务。如何恢复这个故障的缓存节点?

A4:目前还是监控,然后人工恢复。

Q5:能否透露一下Memcache的集群规模?

A5:目前40个x86节点。

Q6:缓存层到DB层需要做哪些设置呢?DB层的缓存是否还有作用?

A6:不需要设置,通过应用负责链接,数据库的缓存仍然起作用,但只是在通过sql获取数据时,然后程序写到Memcache,之后再发生读,则从缓存,不从数据库。

Q7:怎样保持缓存和数据库中的数据实时一致?

A7:主要采取这个逻辑实现:数据更新时直接更新数据库,并同步触发缓存更新逻辑。都需要应用来实现。

Q8:单个节点容量在多少?文中提到的同步,40个节点数据是冗余还是分片的?

A8:单个节点在30G内存,40个节点分了4个集群,集群内是分片。

Q9:缓存前置分发器依据规则分发数据,如果增加新的业务和服务器,这个规则是能自定义并能指向新增加的服务器?

A9:是通过客户端应用来分发的,hash算法,新增服务器,需要进行缓存迁移,因版本较低,还没用到集群,但可以通过预分片设置了大量的分片,新增服务器时可以方便把一些分片迁移到新机器。

Q10:除了Memcache,redis还有其他竞争性方案吗?

A10:其他如MongoDB,也可部分代替缓存功能,还有可以采用内存库,但感觉效率比缓存差一些。

Q11:Oracle的TT能否实现类似的缓存功能?有无可能,因为缓存和数据库的更新没立即同步,导致应用读取了老的缓存里的数据?

A11:TT是关系型内存数据库,不是缓存,适合替代Oracle物理库,二者比较难以实现一致性的同步,我们的场景是由应用同步写物理库和缓存,使二者一致。

Q12:Memcache的集群规模是如何评估的?应用如何选择查询哪个缓存节点?会不会数据存放在节点1,而应用访问节点5以致没找到数据而访问数据库?

A12:目前是按照放到内存的表的实际占用量评估的,目前数据存放在哪个节点是由应用控制的,根据模数放在不同的节点,后续查询也按照这个定位节点。新版本支持集群后会更灵活。

Q13:如何选择要缓存的表?除了根据读多写少,还有哪些评判?

A13:选择要缓存的表,一是需要读多写少,还有要在整个数据库个系统中的读量处于前面的位置,否则优化了用处不大,还有就是尽量delete操作不要太频繁。

Q14:能否举例说明,在实现某个查询功能时,原先没使用缓存时,SQL是怎么写得的?改用缓存功能后?代码改成怎么样了?

A14:没使用缓存:SQL语句即可:select a from tab where b=1; 使用缓存:java语言和数据库语言结合: function get_data($key)   {     $data =$this->cache->get($key);     if($data != null)      return $data;     else     {      if($this->cache->getresultcode() == memcached::res_notfound)      {         //do the databse query here andfetch data        $this->cache->set($key,$data_returned_from_database);      }       else       {        error_log('no data for key '.$key);       }    }

Q15:怎样保持缓存和数据库中的数据实时一致?

A15:我们是通过应用逻辑实现,比如在更新数据库时,同步更新缓存,任何时候数据的变化都要先更新数据库,再更新缓存。

Q16:对于缓存数据的业务改造,为什么不考虑直接使用redis?

A16:redis也可以,也是选择之一,我们只是因为有人熟悉Memcache所以才选取了现在的方案。

作者介绍朱祥磊

·        山东移动BOSS系统架构师;

·        负责业务支撑系统架构规划和建设;

·        获国家级创新奖1项、通信行业级科技进步奖2项、移动集团级业务服务创新奖3项;

·        申请发明专利13项。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值