替代了什么
基于内存的数据库。
替代了关系数据库,因为关系数据库太重了,准备工作需要创建数据库、表,操作数据的时候又需要建立连接,连接很耗资源。
memcache就是为了替代关系数据库,准确的说,是减轻(不是真的替代)关系数据库的负担,把部分数据放到内存数据库里。
什么样的数据适合放到内存数据库?
1.非持久化数据
如果需要持久化,就放到关系数据库。
临时存储。不经常变动的数据。实时性要求不高的数据。
2.数据要小
内存里只放最重要的数据,因为内存一般比较小。
满足上面的条件,就比较适合放内存数据库。
应用场景
1.手机验证码 //也是一种标识id
2.各种标识id //防止订单重复提交
3.用户id //其实也可以放缓存,但是最佳实践一般是放会话里
为什么要用
因为它是内存数据库,比关系数据库更快。
怎么用
1.服务器
c语言写的。
启动服务器即可。
2.客户端
多种方式。
可以图形用户界面客户端,
web,
jar包 //java
java-最常用的开源jar包是XMemCached
支持的数据类型
指的是value,支持的数据类型。 key,都是字符串类型,无论是memcache,还是redis。
1.memcache
字符串
对象
2.redis
字符串
对象
list
set
有序集合
map
工作实践-支付系统
token/order对象,防止重复提交。
分布式
是分布式,可以集群部署。支持分布式。
多个节点怎么安装?与web服务器的关系?
?
多个节点,数据是怎么存储的?备份情况是怎么样的?
1.服务器是分布式的
memcache的分布式只是服务器的分布式。
2.数据不是分布式的
每个服务器的数据都不一样,每个服务器只维护自己的数据。如果这个服务器挂了,这个服务器的数据就真的挂了。
那现在数据怎么办?缓存服务器的数据是来自数据库,第一次请求的时候,缓存没有数据,就从数据库取,后面从缓存取。现在缓存挂了数据也没了,这个服务器不可用。如果有新的请求,就又回到第一次请求的时候一样,从数据库取,不过这个时候换了一台缓存服务器,后面的请求就从这个新的缓存服务器取。
怎么知道是否需要换一个新的缓存服务器?有路由算法,专门去选择一个可用的缓存服务器。
总而言之,memcache的数据非分布式,即不是那种所有缓存服务器的数据统一一致,一台缓存服务器数据有更新,会通知其他的所有缓存服务器也同步更新。不是这样。jboss cache是这样,数据是分布式统一管理/统一同步更新。
最后总结,memcache的运行步骤就是:
1.选择一个缓存服务器
路由算法。
2.写数据
key会经过hash算法,hash后的值包含了目标缓存服务器的唯一标识信息(IP+端口)。
3.读数据
根据key的hash算法,选择写数据时的同一台服务器读数据。
高并发
是高并发,速度快。
1.网络io多路复用
2.多线程
但不是每个连接一个线程,是一个线程处理多个连接。
支持编程语言
基本上都支持。
包括:java,c,c++等。
底层实现
map数据结构。
访问速度
1 //因为是map数据结构
并发数量
每秒数百万请求。
Queries on slow machines should run in well under 1ms. High end servers can serve millions of keys per second in throughput.
跑起来玩一下
1.生产环境
安装在多台服务器
2.测试环境 安装在同一台服务器,使用不同的端口即可。
面试题
和redis的区别
1.value支持的数据类型
memcache只有字符串和对象。
redis除了字符串和对象,还有list set 有序set map。
2.持久化
memcache不支持持久化,纯内存数据库。
redis支持持久化。
3.单线程
memcache是多线程,但不是tomcat这种每个连接请求一个线程,而是一个线程处理多个请求。
redis只有一个线程,即单线程。
memcache是互联网分层架构中,使用最多的的KV缓存。面试的过程中,memcache相关的问题几乎是必问的,关于memcache的面试提问,你能回答到哪一个层次呢?
画外音:很可能关乎,你拿到offer的薪酬档位。
第一类问题:知道不知道
这一类问题,考察用没用过,知不知道,相对比较好回答。
关于memcache一些基础特性,使用过的小伙伴基本都能回答出来:
(1)mc的核心职能是KV内存管理,value存储最大为1M,它不支持复杂数据结构(哈希、列表、集合、有序集合等);//redis-value的数据结构不只是字符串
(2)mc不支持持久化;
(3)mc支持key过期;
(4)mc持续运行很少会出现内存碎片,速度不会随着服务运行时间降低;
(5)mc使用非阻塞IO复用网络模型(redis也是非阻塞,多连接复用单线程),使用监听线程/工作线程的多线程模型(redis是单线程);
面对这类封闭性的问题,一定要斩钉截铁,毫无犹豫的给出回答。
多线程
1.非阻塞多路复用
多连接共用一个线程 //redis是只有一个线程,memcache是多个线程——但是也不是每个连接一个线程(比如,tomcat这样的web服务器是每个连接请求一个线程)
2.多线程
可以利用多核
memcache为什么要使用非阻塞IO复用网络模型,使用监听线程/工作线程的多线程模型,有什么优缺点?
目的是提高吞吐量。
多线程能够充分的利用多核,但会带来一些锁冲突。
面对这类半开放的问题,有些并没有标准答案,一定要回答出自己的思考和见解。
为什么这么设计?
第二类问题:为什么(why),什么(what)
这一类问题,考察对于一个工具,只停留在使用层面,还是有原理性的思考。
memcache为什么不支持复杂数据结构?为什么不支持持久化?
业务决定技术方案,mc的诞生,以“以服务的方式,而不是库的方式管理KV内存”为设计目标,它颠覆的是,KV内存管理组件库,复杂数据结构与持久化并不是它的初衷。
当然,用“颠覆”这个词未必不合适,库和服务各有使用场景,只是在分布式的环境下,服务的使用范围更广。设计目标,诞生背景很重要,这一定程度上决定了实现方案,就如redis的出现,是为了有一个更好用,更多功能的缓存服务。
画外音:我很喜欢问这个问题,大部分候选人面对这个没有标准答案的问题,状态可能是蒙圈。
key过期的几种方式
一般就两种
1.时间到了就过期
主动
2.用的时候,才去判断是否过期
被动,也就是懒的意思
memcache是用什么技术实现key过期的?
懒淘汰(lazy expiration)。
内存满了之后,如何清理数据,即选择哪种算法?
1.按时间先后顺序来
旧的key,可以删除
2.按使用次数最少的来
使用次数少,说明key不常用,可以删除
算法实现原理
算法源码
内存分配
是硬核知识,必须吃透原理,到源码级别!
memcache为什么能保证运行性能,且很少会出现内存碎片?
提前分配内存。
细节
参考
mp.weixin.qq.com/s/zh9fq_e2B… //58同城-什么剑写的
工作实践
支付系统
1.用户量小的系统
用户量
几十万个用户。
节点数量
服务
中间件 //多台服务器,集群/分布式。节点数量是个位数。
数据库 //分库,但是每个分库只有一个节点,没有集群。只有数据备份。
内存 //平均每个服务占几G,几十个服务,加起来几百G。
2.用户量大的系统-核心支付系统
用户量
几十万个商家。
数百万数千万的用户。
节点数量
服务
中间件 //多台服务器,集群/分布式。节点数量是十位数。
数据库 //分库,并且每个分库集群。同地多活,即多机房。有数据备份。
内存 //平均每个服务占几G,几百个服务,加起来几千G。
内存管理
为什么没有碎片?
提前分配
数据结构
1.key/value对
即所谓的item
2.块chunk //memcache内存分配的最小单位
包含多个key/value对
3.平板slab
包含多个chunk
4.页page
包含多个slab
不要管这几个名字是怎么叫的,只需要理解清楚内存分配的实现原理即可。
内部构造的实现方式
内存管理
1.怎么申请
2.怎么释放
3.怎么节约内存?为什么这样能节约内存?
怎么申请?
不是c语言自带的malloc/free。//memcache早期是采用这种方式,但是这种方式会导致内存碎片,就是内存利用不足,具体来说就是,你申请了1M,但是实际只使用了0.5M,那么剩下的意见申请但是没有利用也不能释放的0.5M就这样被浪费掉了。
而是,memcache的自己设计的解决方案:page/slot/chunk/item。//具体来说是,现在申请的内存是根据负载因子划分成不同大小的更小的内存块,比如1.申请了20M内存2.假设负载因子是2,那么划分的更小内存块的大小分别是1M 2M 4M 8M等等,类似这样。(早期的负载因子固定是2,后面觉得这样浪费内存太多,多添加了一个配置参数负载因子,默认值是1.25)。这是怎么申请内存,怎么划分内存。具体怎么使用这些更小的内存块呢?就是申请内存的时候,根据申请内存的大小和内存块的大小相比,选择刚好合适大小的内存块,或者比申请内存大一点的内存块。
还要注意一点,就是相同大小的内存块(item),组成一个chunk(就是chunk数组)。
内存块不会被释放,会被重复利用。
内存管理的缺点
还是会有一点点的浪费,但是比之前要浪费的少一点。
参考
memcache全面剖析 //日本人写的一个小册子,总共只有几十页
高可用
节点自动扩缩容
基于zookeeper的监听数据机制Watch。即节点的增加和删除,会写到watch,watch会主动通知订阅者,而且消费者每次请求的时候也会获取服务器节点集合。
注:节点的扩缩容,和dubbo服务的扩缩容区别?一个是自动,无需重启;一个是需要重启服务提供者和服务消费者,因为代码变了(配置文件和代码都变了),除非做到两点,即实现1.定时任务动态加载配置文件 2.动态加载jar。
参考
docs.linuxtone.org/ebooks/NOSQ… //日本人写的教程,除了这个网上书籍很少
2.书籍
李智慧老师的《大型网站技术架构 核心原理与案例分析》
曾宪杰老师的《大型网站系统与Java中间件实践》
3.网上资料
www.cnblogs.com/xrq730/p/49…
segmentfault.com/a/119000001…