发表于: 2020-07-14 21:47:13
1 1453
今天完成的事情:任务六的深度思考
明天计划的事情:任务七
遇到的问题:暂无
收获:
1.为什么要使用memcache?memcache有什么作用?
Memcached是一款开源性、高能、分布式内存对象缓存系统,可应用各种需要缓存的场景,其主要目的是通过降低对Database的访问来加速web应用程序。许多Web应用都将数据保存到RDBMS中,应用服务器从中读取数据并在浏览器中显示。 但随着数据量的增大、访问的集中,就会出现DB的负担加重、数据库响应恶化、 网站显示延迟等重大影响。
Memcache一般的使用目的是,通过缓存数据库查询的结果,减少数据库访问次数,以提高动态Web应用的速度、提高可扩展性。 它是一个基于内存的“key-value”存储,用于存储数据库调用、API调用或页面引用结果的直接数据,如字符串、对象等。
2.后台只允许有列表页和详情页,列表页分为搜索区和列表区和操作区,原因是什么?有没有其他设计方式,相比之下各自的好处是什么?
作为后台不需要太多的页面渲染,最主要就是对内容管理,对整体体系的构建,给用户最直观,便捷的获取信息。
http://www.woshipm.com/pd/1202556.html
后台两种设计方式:需求驱动设计(RDD),领域驱动设计(DDD)。
需求驱动设计不足:面向过程设计,贫血模型
- 创建的对象不准确,直接影响产品和开发对业务的正确把握和扩展;
- 业务逻辑分散,业务难以复用;
- 业务间耦合度高,迭代及维护成本极高;
- 名词定义不一致,开发与业务出现沟通问题。
领域驱动设计:面向对象的设计方式,对上面的补充,相对复杂的设计模式。
RDD的模式会很快捷,这个就非常适合初创型、小型的系统设计,当产品复杂到一定程度时,RDD的开发时间会指数上升,而DDD的模式则始终比较平稳,所以DDD会适合复杂的系统设计。
3.什么叫集群?缓存应该在什么情况下使用集群?有哪些实现集群的方案?
这个图我也要用用,哈哈。
集群:同一个业务,部署在多个服务器上(不同的服务器运行同样的代码,干同一件事)
在高并发,高可用,高可扩展性时候,可以使用。
缓存使用集群主要是为了保证系统的高可用,除了可以分担一台服务器的压力外,当一个缓存服务器宕机,大量缓存效会导致缓存雪崩,大量请求涌向数据库,数据库瞬时压力
过重。这是时用缓存会把宕机的主节点下的从节点上升为主节点,这也是从一方面来保证系统的高可用。
Redis实现方案有:Redis-Cluster,Codis,Redis Sharding
4.什么是压测,为什么要进行压力测试?JMETER工具的使用 ?
压测即压力测试,通过确定一个系统的瓶颈或者不能接受的性能点,来获得系统能提供的最大服务级别的测试。常用工具有两种,LoadRunner和Jmeter
压力测试是给软件不断加压,强制其在极限的情况下运行,观察它可以运行到何种程度,从而发现性能缺陷,是通过搭建与实际环境相似的测试环境,通过测试程序在同一时间内或某一段时间内,向系统发送预期数量的交易请求、测试系统在不同压力情况下的效率状况,以及系统可以承受的压力情况。然后做针对性的测试与分析,找到影响系统性能的瓶颈,评估系统在实际使用环境下的效率情况,评价系统性能以及判断是否需要对应用系统进行优化处理或结构调整。
5.Memcache和Redis可否做集群?什么样的情况下应该做集群?
可以,系统达到高可用,高并发的时候。
6.什么是脏数据,缓存中是否可能产生脏数据,如果出现脏数据该怎么处理?
脏数据:从目标中取出的数据已经过期,错误或者没有意义。缓存中会出现,数据库中进行修改数据后,没有更新到缓存,那么下次读取的还是缓存中未修改的。
首先要防止脏数据的产生,对数据库操作后一定要同步更新到缓存,并且对缓存或者数据操作增加锁等功能。
7.插入,更新和查询数据的时候,读写缓存和DB的顺序应该是怎么样的?
查询的时候先查缓存,如果缓存没有数据,再查数据库。
插入和更新的时候有两种方式:
1.先删除缓存再更新DB
结论:产生脏数据的概率较大(若出现脏数据,则意味着再不更新的情况下,查询得到的数据均为旧的数据)
比如:两个并发操作,一个是更新操作,另一个是查询操作,更新操作删除缓存后,查询操作没有命中缓存,先把老数据读出来后放到缓存中,然后更新操作更新了数据库。于是,在缓存中的数据还是老的数据,导致缓存中的数据是脏的,而且还一直这样脏下去了。
2.先更新DB再删除缓存(使用场景多)
结论:产生脏数据的概率较小,但是会出现一致性的问题;若更新操作的时候,同时进行查询操作,则查询得到的数据是旧的数据。但是不会影响后面的查询。(代价较小)
( 一个是查询操作,一个是更新操作的并发,首先,没有了删除cache数据的操作了,而是先更新了数据库中的数据,此时,缓存依然有效,所以,并发的查询操作拿的是没有更新的数据,但是,更新操作马上让缓存的失效了,后续的查询操作再把数据从数据库中拉出来。而不会像文章开头的那个逻辑产生的问题,后续的查询操作一直都在取老的数据。)
8.JVM缓存和Memcache这种缓存的区别在哪里?是否可以不使用Memcache,只用虚拟机内存做缓存?
jvm缓存比memcache快,但是jvm内存有限,所以还是需要memcache来缓存
9.缓存应该在Service里,还是应该存放在Controller里,为什么?
我会放在service
在Controller中:
好处:可以单个Controller进行控制,每个controller中有各自对数据的键,以及缓存时间等。
坏处:每个controller需要写一份几乎一模一样的冗余代码。即使你写一个公共的方法,那也要在各个地方写上这个公共方法。
在Model中:
好处:统一管理,复用性高,controller层不需要理会数据是从缓存中获取还是从mysql中获取,controller完全解放出来了。
坏处:没法对单个controller进行控制了,controller失去了对缓存的控制权。
10.什么叫穿透DB?什么情况下会发生,穿透DB后会发生什么事情?
https://blog.csdn.net/liyantianmin/article/details/54862186
穿透DB:大量请求透过缓存(比如redis)集中的访问数据库,导致数据库崩溃。
解决这个问题有几种思路:
比如一个key是testKey,失效时间是30s
1.定期从DB里查询数据,再刷到缓存里
缺点:有些业务的key可能是变化的,不确定的。而且不好界定哪些数据是应该查询出来放到缓存中的,难以区分冷热数据
2.当缓存取到为null时,加锁去查询DB,只允许一个线程去查询DB
缺点:这种方式不太靠谱,不多讨论。 而且如果是多个web服务器的话,还是有可能有并发的操作
3.在向缓存写入value时,同时写入当前机器在时间作为过期时间
当get得到数据时,如果当前时间 – 过期时间 > 5s,则后台启动一个任务去查询DB,更新缓存
当然,这里的后台任务必须保证同一个key,只有一个线程在执行查询DB的任务,不然这个还是高并发查询DB
缺点:是要把过期时间和value合在一起序列化,取出数据后,还要反序列化。 很不方便
网上大部分文章提到的全都是前面两种方式,有少数文章提到第3种方式。 下面提出一种基于两个key的方法:
4.两个key,一个key用来存放数据,另一个用来标记失效时间
比如key是testKey,设置失效时间为30s,则另一个key为expire_testKey,失效时间为25s。用multiget,同时取出testKey和expire_testKey,如果expire_testKey的为null,则后台启动一个任务加锁去查询DB,更新缓存。集群式的部署的,如何实现只允许一个任务执行,用到memcached的add命令,或redis的setnx命令。设置expire_testKey超时过间为3s,防止后台任务失败或者阻塞。
缺点:内存翻倍,而且程序上要维护2个key。
5.两个key,时间存到value里,结合add/setnx来保证原子性更新缓存
最近重新思考了下这个问题。 发现第4种两个key的办法比较耗memcached的内存,因为key数翻倍了。 结合第3种方式,重新设计了下,思路如下。
仍然使用2个key方案,但是expire_testKey相当于锁。只允许add/setnx成功的线程去更新数据。更新成功后把expire_testKey进行删除。由于这个expire_testKey存在时间较短,不会占用太多缓存内存。
优点:节省内存,数据是自然冷热适应的,不用担心集群带来并发风险
11.什么叫命中率?正常来讲,命中率应该控制在多少?
终端用户访问加速节点时,如果该节点有缓存住了要被访问的数据时就叫做命中,如果没有的话需要回原服务器取,就是没有命中。取数据的过程与用户访问是同步进行的,所以即使是重新取的新数据,用户也不会感觉到有延时。 命中率=命中数/(命中数+没有命中数), 缓存命中率是判断加速效果好坏的重要因素之一。
控制95%以上。
12.什么样的数据适合存在缓存中?缓存的淘汰算法有哪些?
查询一些不经常修改的数据。
淘汰算法
OPT最佳替换算法:算法核心是算法所淘汰的数据是以后永远不会访问的,或者是在最长时间内不再访问的那条数据。但是人们无法预知未来哪个页面才会被访问。OPT算法即为命中率最高的算法。
FIFO先进先出算法:见其名知其意。
LRU最近最久未使用算法:数据结构:链表,当访问一条数据时,如果数据在缓存中,则将该数据移动到链表头部。如果数据不在缓存中,则把数据插入到链表头部。如果链表满了,则把链表尾部的数据删除,然后把该数据插入到链表头部。
CLOCK时钟算法:
简单的CLOCK算法是给每个缓存数据关联一个访问标志位。
新添加到缓存循环链表中的数据,或者在循环链表中被访问的数据,都把访问标志位设置为1。
有个指针指向最早添加到循环链表中的数据。
当链表满了,需要删除的时候,从当前指针开始,如果当前指针指向的数据的标志位为1,则置位0,指向下一位置。直到当前指针指向的数据的标志位为0,则淘汰此数据。
13.什么叫一致性哈希,通常用来解决什么问题?
https://www.jianshu.com/p/735a3d4789fc
一致性哈希是一种特殊的哈希算法,目的是解决分布式缓存的问题。 在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系。一致性哈希解决了简单哈希算法在分布式哈希表( Distributed Hash Table,DHT) 中存在的动态伸缩等问题 。
14.缓存的失效策略有哪几种,分别适合什么场景?
redis 提供 6种数据淘汰策略:
1. voltile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
2. volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
3. volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
4. allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
5. allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
6. no-enviction(驱逐):禁止驱逐数据
15.Memcache和Redis的区别是什么?
MemCache | Redis |
---|---|
支持简单数据类型 | 数据类型丰富(支持Set、List等类型) |
不支持数据持久化存储 | 支持数据磁盘持久化存储 |
不支持主从同步 | 支持主从同步 |
不支持分片 | 支持分片 |
1、 Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等。
2、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储。
3、虚拟内存--Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘
4、过期策略--memcache在set时就指定,例如set key1 0 0 8,即永不过期。Redis可以通过例如expire 设定,例如expire name 10
5、分布式--设定memcache集群,利用magent做一主多从;redis可以做一主多从。都可以一主一从
6、存储数据安全--memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化)
7、灾难恢复--memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复
8、Redis支持数据的备份,即master-slave模式的数据备份。
16.怎么预估自己系统可承载的日活数?
用 jmeter 去进行压测,看看最大承载量在多少,在多大的时候TPS开始下降。
17.什么是JMeter?Jmeter是否可以在多台机器上分布式部署?为什么要分布式部署?
在使用Jmeter进行接口的性能测试时,由于Jmeter 是JAVA应用,对于CPU和内存的消耗比较大,所以,当需要模拟数以万计的并发用户时,使用单台机器模拟所有的并发用户就有些力不从心,甚至会引起JAVA内存溢出错误。为了让jmeter工具提供更大的负载能力,这时可以使用Jmeter提供的分布式功能来启动多台电脑来分压测试
18.什么是TPS,什么是每秒并发数,什么是90%Line?分别应该到达多少算符合系统上线的要求?
TPS包括一条消息入和一条消息出,加上一次用户数据库访问
响应时间(RT)
响应时间是指系统对请求作出响应的时间。
吞吐量(Throughput)
吞吐量是指系统在单位时间内处理请求的数量。
并发用户数
并发用户数是指系统可以同时承载的正常使用系统功能的用户的数量。
90%Line:90%用户的响应时间
接口的平均访问时间应低于200ms
评论