layout: post

title: 2016-04-25-信息系统实践手记5-CACHE设计一例

key: 20160425

tags: 业务 场景 CACHE 系统分析 系统设计 缓存

modify_date: 2016-04-25

信息系统实践手记5-CACHE设计一例

说明:

正文:

  • 信息系统实践手记系列是系笔者在平时研发中先后遇到的大小的问题,其中比较典型的内容加以收集和分享。
  • 信息系统实践手记目录:博客园(或查看源码的README.MD文件)

摘要:

  • 此文描述了对CACHE缓存的一些理解。

正文

1.CACHE是啥?

最近一直在了解scala,Spark,Python,数据挖掘,以及复杂科学的一些内容,在充实和忙碌之余,虽兴趣浓厚,但体力不支,疲劳的很,无奈耽搁了实践手记。
原本计划2周挂出一篇来分享,实在抱歉。要分享的东西太多,码字太费时间,有时候甚至觉得开会也许更好(很多人反感开会,那是因为没开过高效的会)!其实很多东西主要还是考自己去走,去体会。
闲话不说,切入正题。
很多研发人员,尤其是开发程序的同志,找到一个cache框架或类库可用,比如hibernate的cache功能,然后就一股脑用上去。虽然会有效果,很愉悦,是好事,既增加经验,也体会了框架的魅力和效率,
但其实还有东西可以进一步去领会。究竟为啥要用CACHE?CACHE是啥?什么样的场景用什么样的CACHE?很少有人问。
那CACHE到底是啥呢?还真难于表述清晰,但有一些要点:
  • CACHE的产生是为了缓解处理链上不同节点之间速度不协调的情况。举例若干:

    • 计算机系统:一般有速度梯度:CPU内部寄存器(register)IO>内存IO>磁盘IO>网络IO,为协调它们之间传递数据的速度差,就可设置缓存结构,叫CACHE;

      • 说明1:以上说的是一般情况,不考虑特别的磁阵RAID,高速SCSI,千兆或万兆网络等;
      • 说明2:CPU内部也分L1,L2,L3等多级寄存器结构,当做多级CACHE使用,早先的386/486处理器没分那么多层次;
    • 地铁系统:有时候出事故,人特多,站内站外由管理员把守入口分批放人到1层大厅,则1层大厅是一个CACHE;管理员分批从大厅放人到B1层站台,则B1站台也是一个CACHE;当CACHE快撑满的时候,管理员就会喊“慢慢来,不要挤,暂时关闭,大家耐心等待!”,于是人就被囤积在不同的CACHE里,以便协调地铁运量和人流涌入的速度差问题。
    • 工厂流水线:另一个典型例子是工厂的流水线。以前老式流水线每个工位站1个人,处理1个装配动作,比如给黄小鸭玩具装上1条腿。一个工件,如果流经10个处理节点,那就会有10个人来处理10个步骤。显然,老板期望流水线一直处于充满状态,则最高效的源源不断有产出。但意外总会发生,比如某工件N流转到Px节点,Px节点的工人很累,处理较慢,导致Px-1步骤流出的工件不断堆积,而这个Px处理节点处理台的工件堆积场所,就是一个BUFFER缓存区(也就是CACHE),它越来越满,就提醒Px的工人,加紧干,否则一旦CACHE撑爆,就无法克服(追上)速度差(时间差)的问题!(画外音:可以看出流水线机制的高效和科学,以及“残酷”)。
    • 生产者消费者模式:经典的程序设计模式“生产者和消费者”模型也有一个CACHE的设计,就是协调生产和消费的速度差,类似“工厂流水线”
  • CACHE实际上是用空间上的代价来缓解时间上的不协调。

    • 你肯定要问“既然速度有差异,那CACHE再大也没用?”,的确,再大的CACHE也是用来临时克服速度差异的,它期望可以用空间暂时的堆积追回偶发导致的时间不协调(速度差是绝对的,这个在设计场景之前就知道,但速度不协调是偶发的,这个要区别开!)。如果永远无法“追回来”,那么再大的CACHE也会有问题,那么就是设计上的问题,就不是CACHE机制可以解决的。
    • 处理节点Px往往速度不同,所以必须用不同算法来安排。比如:
      • 通过编译器编译的源码,会根据OS的不同及其内存页面调度算法,互相结合,处理好代码的摆放,并充分考虑到CPU/MEM/DISK/NETWORK的差异;保持MEM代码段高命中,降低页丢失中断,等等。
      • 程序本身也应该充分利用诸如“多线程”,“并发计算”,“分布式计算”等方法,来从宏观的算法层面,解决掉速度差异,从而适当的利用CACHE来防止偶发的速度不协调,而不是算法本身有永久性的硬伤“速度不匹配”。可以适当的使用一些主流成熟前三名的框架来解决实际问题。
      • 程序终究是要达成业务需要的,也就是完成功能目标(Feature)。而功能和业务本身是有特点的,有时空特性的,是高并发业务?还是随机业务?业务的时空特性如何?是否和上下班高峰有关? 是否和网站的维护周期有关?是否和购物的时间段有关?总之从业务触发,需要专业的领域知识(行业支持),并且需要深厚的技术功底,这样的从场景出发的系统分析和系统设计行为,是何其重要!这方面的人才非常紧缺。
  • CACHE所处理的时空不协调,可能是偶发的,也可能是来自于业务模型;

    • 通过上述的不同层次(编译器,OS,程序,框架类库,业务场景分析)的讨论,基本上能妥善的处理业务,达成场景,使用必要的CACHE结构。但业务模型总是会偶发时空不一致,尤其是在当今多任务的计算机架构(以前主机时代只有大型机是多进程的,现在微机也是多任务并细化到线程)。很容易计算力不够需要增加更多CPU的core,数据量大没地方放,就增加MEM,MEM增加后也会导致低速的磁盘IO和网络IO也变大。
    • 另外在对业务模型不断调优和扩容的过程中,不协调也会自然产生的,而如果程序模型比较优秀,相关必要的地方本来就有CACHE,那么CACHE将为程序运作提供余地。
    • 即便是简单的业务模型,而且调优完成,且一直正常运作。但也可能因为“网络故障,CPU失效,内存或磁盘损坏,某个计算节点离线”等问题而打破平衡。这时候,甚至连写LOG日志来记录状态也显得很奢侈或捉襟见肘。此时,如果程序在框架设计上已经未雨绸缪的安排了充分和必要的CACHE,则完全可以提升健壮性,甚至在偶发灾难冲击中坚强运行,恢复运作。
  • 客观世界和程序世界都是复杂的,而复杂系统经常引发意外和不协调,CACHE则应运而生:

    • CPU里面的微指令集中用到了L1,L2,L3,它们就是各级CACHE;
    • MEM,DISK,网卡等设备,无论在硬件的接口驱动程序BIOS中,还是在程序员编制的应用程序中,都安排了CACHE,来处理设备受到外界速度不匹配的冲击。
    • 程序设计中很多模式,比如消费者生产者,就必然有CACHE存在,以缓解生产和消费的速度不匹配;
    • 真实世界的仓库存货,小超市囤货,高架路上的紧急停车带,上下岔道区域,展览会门口的回形排队护栏,流水线的每个节点的BUFFER缓冲带等等,都是CACHE的好例子;

只有理解了自然现象,业务规律和程序能力边界,才能深入体会如何在程序设计中,在什么样的业务场景下使用怎样的CACHE设计,以便到达好处和结果。不建议只为了技术用技术,必须明确使用的目的为何,才能正确的使用。

2.CACHE设计一例

这里简单举一个例子,还是前几篇分享的客户端和服务器,它们是提供GIS地图服务的服务器和客户端;而这个提供GIS业务的服务器就用到很多CACHE; 撇开客户端业务展现不说,很多后台服务是由做GIS业务的应用SERVER提供,简称为GS,而GS需要从设备管理平台,简称DS获取设备信息;

  • 因为DS不提供设备信息的订阅(很遗憾),则无法使用高效的观察者模式来获取设备变更信息,而只能由GS通过阶段同步(轮询模型)来花巨大的代价向DS获取其实很少变化的设备更新信息。为了阶段同步,GS只能在内存(或DB)做了一个CACHE,来存放比如每30分钟的同步信息;
  • 最先是X分钟同步,按照经典做法,同步数据放在DB。但为提升速度,解决业务场景的高速要求和DB处理的慢速情况,将DB的数据“上提”到内存的CACHE中,以后做业务直接查CACHE,处理CACHE;这里就自然的引发了一个问题,CACHE的脏数据需要同步回到DB,因为数据存在于两个地方,一个CACHE是临时的,一个DB是持久化的,那么它们之间也有同步问题,这是使用CACHE经常要面临的情况。其实最后因为原来程序框架做的不佳,导致了批量修改完成后,还遗留了不少小尾巴,只能case by case的修复,不细说。
  • 我们GS平台,还和第三方,比如一个城市的路口卡口管理平台(简称KS)对接,上次讲过平台对接问题了,这里假设顺利对接。那么KS的数据,也会阶段性的同步到我们GS来。一个典型的应用是GS向KS订阅了一种“告警A”,当KS发生事件A而发出“告警A”时,将会推送到GS平台,那么GS平台分发给客户端。这里显然有速度的不协调,如果告警频繁,GS一时处理不过来,那么就要CACHE,怎么弄?也可以不用自己写代码,我们GS和GS的客户端是通过ActiveMQ的消息中间件来传递消息。订阅之后,不同主题的消息和用户就会有自己的BUFFER来存放,即便KS平台突发大量告警A到GS,GS来不及分发,那就放入MQ自己管理的缓存队列,MQ自己处理。当然这里我们看到了上面讨论过的CACHE的几个问题:
    • 如果KS平台的“告警A”一直高频持续发送,那么最终GS接收代码来不急放入MQ,或者来得及放入MQ,但MQ终将崩溃。所以这里就遇到了前几篇提到的平台对接中,对两个有交互的平台之间的信令和数据的“时空特性”一定要定义清晰,比如我们GS和KS就定义了最高并发不能超过1秒10条(10CAPS),否则GS拒绝而不是通过CACHE尽量容纳和处理。万事都有限度,讨论清楚就行!
    • 这里还有一个隐蔽问题,大家不知道看出来没有。这里假设我GS的JAVA接收代码,从网络socket套接字获取的批量字节流,速度极快,放入MQ几乎不花时间。如果没有这个假设,而且放入速度的确很慢,那么MQ不会最终“爆炸”,首先奔溃的及时GS的接收代码片段。这个判断,一般是根据程序员的经验和业界的经验来确定的。它总是非常快,放入message,一般总是比消费处理message快不少。
  • CACHE也能存在于高层次和高抽象级别的。比如当前的hibernate库支持对象到DATA MODEL的映射,而业务是针对对象,不是直接赤裸的和数据交互的。针对对象的操作比如func1()也是可以CACHE缓存的,以便第二次同样的调用func1()的时候,极大的提升速度和效率。 这里当然也会看到一个脏数据和失效的问题,不再讨论。

END

2016-04-25-信息系统实践手记5-CACHE设计一例的更多相关文章

  1. 信息系统实践手记5-CACHE设计一例

    说明:信息系统实践手记系列是系笔者在平时研发中先后遇到的大小的问题,也许朴实和细微,但往往却是经常遇到的问题.笔者对其中比较典型的加以收集,描述,归纳和分享. 摘要:此文描述了笔者接触过的部分信息系统 ...

  2. 信息系统实践手记6-JS调用Flex的性能问题一例

    说明:信息系统实践手记系列是系笔者在平时研发中先后遇到的大小的问题,也许朴实和细微,但往往却是经常遇到的问题.笔者对其中比较典型的加以收集,描述,归纳和分享. 摘要:此文描述了笔者接触过的部分信息系统 ...

  3. 2016.04.25,英语,《Vocabulary Builder》Unit 18

    capit, from the Latin word for 'head', caput ['keɪpət] n.头,首 , turns up in some pretty important pla ...

  4. java 时间格式化(2016.04.12 12:32:55)

    输入的时间格式如:2016.04.12 12:32:55所示: 想要获取一定格式的日期,时间的方法 String startString = "2016.04.25 12:25:44&quo ...

  5. 2016-04-25-信息系统实践手记6-JS调用Flex的性能问题一例

    layout: post title: 2016-04-25-信息系统实践手记6-JS调用Flex的性能问题一例 key: 20160425 tags: GIS JS FLEX 技术选型 性能 API ...

  6. 学习图像算法阶段性总结 (附一键修图Demo) 2016.04.19更新demo

    今天特别感慨,自己从决定研究图像处理,势必要做出一键修图算法. 经历了,三个多月的书籍积累,三个多月的算法调整以及优化. 人是一种奇怪的动物,当你做不到的时候,你以为做到了,自己会感觉很爽,很有成就感 ...

  7. KaOS 2016.04 发布,桌面 Linux 发行版

    KaOS 2016.04 发布了,KaOS是一份桌面Linux发行,其特色在于最新版本的KDE桌面环境及其他流行的使用Qt工具包的软件程序.它最初基于Arch Linux,但从2013年四月起,开发者 ...

  8. 2018/04/25 基于 编译安装的 PHP7 安装 swoole 扩展

    在上一篇文章我们知道了如何去编译安装一个自己需要的 PHP 版本. 2018/04/25 PHP7的编译安装 这里还没有完,我们还需要安装我们的扩展,才算完成今天的任务. -- 下载扩展 还是官网下载 ...

  9. Understand:高效代码静态分析神器详解(一) | 墨香博客 http://www.codemx.cn/2016/04/30/Understand01/

    Understand:高效代码静态分析神器详解(一) | 墨香博客 http://www.codemx.cn/2016/04/30/Understand01/ ===== 之前用Windows系统,一 ...

随机推荐

  1. Jenkins系列之七——前端app自动打包

    了两周终于搞掂了,期间各种搜教程.各种懵逼,各种坑对小白来还是很难的额.废话不多说直接开撸~~~ 一.介绍下什么是Gradle Gradle是一个基于JVM的构建工具,是一款通用灵活的构建工具,支持m ...

  2. Spring Boot - 获取所有的Bean信息

    前言 Spring Boot启动的时候需要加载许多Bean实现最小化配置,本文将尝试找出Spring启动后加载的所有Bean信息: 通过ApplicationContext 去获取所有的Bean 通过 ...

  3. MySQL SQL语句执行顺序

    MySQL的语句一共分为11步,如下图所标注的那样,最先执行的总是FROM操作,最后执行的是LIMIT操作.其中每一个操作都会产生一张虚拟的表,这个虚拟的表作为一个处理的输入,只是这些虚拟的表对用户来 ...

  4. springboot情操陶冶-@SpringBootApplication注解解析

    承接前文springboot情操陶冶-@Configuration注解解析,本文将在前文的基础上对@SpringBootApplication注解作下简单的分析 @SpringBootApplicat ...

  5. JS判断滚动条到底部,页面是否有滚动条

    要判断页面滚动条是否到底,需要了解三个属性: scrollHeight:获取元素内容高度的度量,包括由于溢出导致的视图中不可见内容,说直白点,算上了滚动条不可见的那部分高度. clientHeight ...

  6. 使用 Mutex 实现进程间同步

    我们知道 Mutex 互斥量是可以用在线程间同步的,线程之间共享进程的数据,mutex 就可以直接引用.而进程有自己独立的内存空间,要怎样将它应用在进程间同步呢?为了达到这一目的,可以在 pthrea ...

  7. 【转载】C#常用数据库Sqlserver中DATEPART() 函数

    在Sqlserver数据库中,DATEPART() 函数用于返回日期/时间的单独部分,比如年.月.日.小时.分钟等等.DatePart()函数的语法为: DATEPART(datepart,date) ...

  8. WPF window 子窗口反馈效果(抖动/阴影渐变)

    当设置了owner的子窗口显示后,点击子窗口外部,需要一种反馈机制(反馈动画). 实现: 1.触发源 每次点击子窗口外部,即母窗口时,事件捕捉如下 HwndSource hwndSource = Pr ...

  9. List集合遍历整理

    遍历List集合的三种方式 0. 首先准备测试数据 List<String> list = new ArrayList<String>(); list.add("Ja ...

  10. Java学习笔记之——Manth类和String类

    (1) Math:常用的数学运算,都是静态方法 方法摘要 static double abs(double a) 返回 double 值的绝对值. static float abs(float a) ...