热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

一次线上小问题的思考

2019独角兽企业重金招聘Python工程师标准tn-零售平台事业部-底层研发部-A组今天,技术经理让我处理一个问题:app首页的产品列表

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

    tn-零售平台事业部-底层研发部-A组    

    今天,技术经理让我处理一个问题:app首页的产品列表,第9个,第11个,两个产品一模一样。

    先讲一下项目的架构:

232049_uxpI_1380557.png

    注:每个箭头都有相反方向的对应箭头,我懒,不画了。

    portal负责app首页、频道页的大部分服务端功能,主要用于聚合信息,cms是中间层,调用搜索,获取产品信息。ror是搜索项目,具体处理请求,通过solr获取数据。portal,cms我都做过一部分,ror没做过,具体细节不清楚,只知道是操作solr的。

    一个请求的处理过程是这样:APP send a request to portal, and portal query data from cache(redis) firstly, if get something from cache, send response to app, if not, send request to cms, then get data from cms. When cms get a request from portal, it query data from cache, if get nothing,  send a request to ror and get data from it.  m站有自己的服务端,是php的。php也是先查缓存, 再查portal。

      可以看出,这是多个微服务组成的系统,各个应用间通过restful方式相互调用。好处是解耦,坏处是重复造轮子,资源利用率不高,前前后后多少个缓存?

        在谈谈我是怎么解决技术经理的问题的。首先,app是分页,每页10条,向portal请求产品列表的,第一页的第9个,第二页的第1个,两个产品完全一样!我看了看m站,没有出现问题,有可能php的缓存把它保护了。再看看cms,先是 cms不走缓存,发现app相同的产品排在第11个(第2页第一个),然后cms走缓存,app相同的产品排在第9个。于是,我大概知道原因了。portal缓存了第1页的老数据,缓存了第2页的新数据。我删了portal的产品列表的缓存,问题解决了。

        我告诉经理解决了,问题的原因是缓存不一致,方案是删缓存。经理让我想想有没有更好的方法。我想了想,将思考写入此文。

        首先,缓存不一致,是因为前前后后有很多缓存,每个缓存的存活时间是1小时。所以会出现缓存不一致的问题,这本质上是分布式一致性的问题。(那就有了分布式锁,分布式一致性)。

        那么,就有两种思路:1,能不能只有一套缓存,portal,cms共用一套缓存。(我只能管到这两个项目,其他的我也不知道,也管不了,也没有权限操作)那就不存在缓存不一致了。2,可以保留多套缓存,但能不能提供  缓存更新通知 缓存同步\异步刷新?

        思路一:

        思路一是简单粗暴的,还节省了缓存服务器,真省钱。前面提到,我们是微服务,各应用间通过restful接口实现调用,这种方式有好处——业务逻辑封装在应用内部,外部调用方不可见(高内聚),A系统出了问题,不会太多的影响B系统(低耦合)。坏处是每次调用需要一次http链接,建立链接是耗时的,还存在网络故障、延时的风险,所以每个应用自己有一套缓存,避免每次都要调接口,提升性能(所以就有了缓存不一致问题,即——分布式一致性问题,关于分布式cap,详见http://www.cnblogs.com/bangerlee/p/5328888.html)。那么如何做到只有一套缓存呢?见下图:

002216_IZhD_1380557.png

        如图所示,大概都画清楚了。四个黄条分表代表  过滤器-控制器-业务层-数据层。图中,缓存放在了dao之后,其实,也可以放在filter-controller之间,controller-business之间,business-dao之间。

        先讲dao之后。他要保证的核心,是确保:只有cms能往缓存写数据,portal,以及其他任何应用,都没有写权限!你能想象,cms刚写完,portal就把它改了,删了吗?另外,由于现在用的是redis,是单线程操作的,不用过多考虑并发场景下的异常情况,memcache等多线程操作的cache就复杂了。除了保证,缓存只有cms能写,还要考虑portal从缓存没有读到数据的情形。是缓存过期了?还是缓存里本来就不该存在这次请求对应的数据?针对这个问题,有两种思路:
        1 没有获取到缓存时,直接调用cms的restful接口,cms本身不读缓存(portal就没读到,cms就没必要读了),而是直接从后台获取数据,如果有,返回给portal,可以在返回给portal之前,同步/异步写到缓存里。如果并发量大,可以使用redis setnx语句,避免多次写同一个key,也可以将写任务提交到任务队列,提高性能。如果cms没有从后台获取到数据,最好返回一个无害的默认值(降级),并设置缓存,记录请求的上下文到日志,便于日后分析。为什么呢?防止缓存击穿。假设有这样一个流程:恶意用户用一个恶意入参请求portal,portal从缓存没有取到数据,调用cms,cms调用ror,也没取到,也没设一个默认值到缓存,就返回了。这样,恶意用户重复这个流程100万次,portal会取100万次缓存,调100万次cms,调100万次ror,ror调100万次solr,这会产生灾难性的后果!如果在缓存设个默认值,时间不用长,5分钟,30分钟,避免缓存击穿造成的严重后果。(时间不能长,是因为可能存入大量无害的默认信息,失效时间长了,影响缓存的容量以及性能。另外,恶意用户短时间内发现恶意请求不起破坏性效果,就极有可能换个恶意请求了)。当然,也可以采用防刷、限流的方式,熔断、降级,甚至封号,加黑名单。。。

        2 portal始终只从缓存读,没读到就直接返回null或无害的默认值。这就要cms保证缓存的完整性、及时性、有效性。cms必须将全量的数据存入缓存(只有这样,才满足portal只从缓存取数据的基本条件)。缓存时间可以为永久,或者短时间缓存。如果缓存时间短,如1h,则可以做个定时任务,如半小时,定时更新全量的缓存,要保证半小时更新完所有缓存,这只能尽量保证数据的及时性,有效性。如果缓存永久,必须有一个通信机制,让cms知道要更新哪些数据,如mq等。另外,更新缓存要考虑数据备份,防止因为异常,导致缓存出问题。

     缓存也可放在filter-controller之间,这里离用户最近,性能也最好。但这就相当于把business层处理完的数据存入了cache,这违反了只有cms有写权限的原则!解决方法是将portal,cms两个项目合并。但这就不是微服务了。缓存放在其他地方也是同理。

 

        以上是一套缓存的分析,下面分析多套缓存的方案。

        多套缓存,即保持现有架构不变。那就要解决多个缓存之间的不一致问题——本质上是分布式一致性的问题。关于分布式cap,详见http://www.cnblogs.com/bangerlee/p/5328888.html。当cms缓存失效、更新时,通过消息机制jms通知portal删除或跟新缓存,这是异步的。如果对一致性要求不极致,这样就可以了,改造成本也小,加个mq就行了(如果要求更低,什么都不用改,等缓存自己失效,现在就是这样的)。如果要求强一致性,就要引入分布式事务,可以基于mysql,redis,或者zookeeper。个人建议基于curator,采用  分布式锁+分布式事务, http://ifeve.com/zookeeper-leader/    http://curator.apache.org/    http://zookeeper.apache.org

 


转:https://my.oschina.net/u/1380557/blog/893648



推荐阅读
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 这是原文链接:sendingformdata许多情况下,我们使用表单发送数据到服务器。服务器处理数据并返回响应给用户。这看起来很简单,但是 ... [详细]
  • CentOS 7部署KVM虚拟化环境之一架构介绍
    本文介绍了CentOS 7部署KVM虚拟化环境的架构,详细解释了虚拟化技术的概念和原理,包括全虚拟化和半虚拟化。同时介绍了虚拟机的概念和虚拟化软件的作用。 ... [详细]
  • 一句话解决高并发的核心原则
    本文介绍了解决高并发的核心原则,即将用户访问请求尽量往前推,避免访问CDN、静态服务器、动态服务器、数据库和存储,从而实现高性能、高并发、高可扩展的网站架构。同时提到了Google的成功案例,以及适用于千万级别PV站和亿级PV网站的架构层次。 ... [详细]
  • 本文介绍了在Ubuntu下制作deb安装包及离线安装包的方法,通过备份/var/cache/apt/archives文件夹中的安装包,并建立包列表及依赖信息文件,添加本地源,更新源列表,可以在没有网络的情况下更新系统。同时提供了命令示例和资源下载链接。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 本文介绍了在Mac上搭建php环境后无法使用localhost连接mysql的问题,并通过将localhost替换为127.0.0.1或本机IP解决了该问题。文章解释了localhost和127.0.0.1的区别,指出了使用socket方式连接导致连接失败的原因。此外,还提供了相关链接供读者深入了解。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 本文介绍了在使用Python中的aiohttp模块模拟服务器时出现的连接失败问题,并提供了相应的解决方法。文章中详细说明了出错的代码以及相关的软件版本和环境信息,同时也提到了相关的警告信息和函数的替代方案。通过阅读本文,读者可以了解到如何解决Python连接服务器失败的问题,并对aiohttp模块有更深入的了解。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • 在编写业务代码时,常常会遇到复杂的业务逻辑导致代码冗长混乱的情况。为了解决这个问题,可以利用中间件模式来简化代码逻辑。中间件模式可以帮助我们更好地设计架构和代码,提高代码质量。本文介绍了中间件模式的基本概念和用法。 ... [详细]
author-avatar
缅甸环球国际
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有