当前位置: 首页 > news >正文

分布式设计与开发(六)------让memcached分布式

memcached是应用最广的开源cache产品,它本身不提供分布式的解决方案,我猜想一方面它想尽量保持产品简单高效,另一方面cache的key-value的特性使得让memcached分布式起来比较简单。memcached的分布式主要在于客户端,通过客户端的路由处理来搭建memcached集群环境,因此在服务端,memcached集群环境实际上就是一个个memcached服务器的堆积品,环境的搭建比较简单。下面从客户端做路由和服务端集群环境搭建两方面来谈如何让memcached分布式

客户端做路由

客户端做路由的原理非常简单,应用服务器在每次存取某key的value时,通过某种算法把key映射到某台memcached服务器nodeA上,因此这个key所有操作都在nodeA上,结构图如下所示:

存储某个key-value

取某个key-value

因此关键在于算法的选择,最基本的要求就是能让数据平均到所有服务器上。这自然而然让我想到了hash算法,spymemcached是一个用得比较广的java客户端,它就提供了一种简单的hash算法,实现类为ArrayModNodeLocator,从key映射到node的源码如下:

public MemcachedNode getPrimary(String k) { return nodes[getServerForKey(k)]; } private int getServerForKey(String key) { int rv=(int)(hashAlg.hash(key) % nodes.length); assert rv >= 0 : "Returned negative key for key " + key; assert rv < nodes.length : "Invalid server number " + rv + " for key " + key; return rv; }

从上面可知它是把所有node放在数组里,通过hash算法把key映射到某index,然后通过这个index在数组里取node

再则需要考虑如何容错,比如当某个node当掉了,如何自动地转到其他node上,上面的简单hash路由策略采用的方法是在数据组里顺序向下轮询node,找第一个工作正常的node即可。

最后要考虑当需要移除node或添加node的时候,如何有效地调整映射关系,这自然又让我们想到一致性hash算法,关于一致性hash算法就不多说,博文分布式设计与开发(二)------几种必须了解的分布式算法 有所涉及,这里可以看看spymemcached是如何利用这个算法来做路由的,实现类为KetamaNodeLocator,从key映射到node的源码如下:

public MemcachedNode getPrimary(final String k) { MemcachedNode rv=getNodeForKey(hashAlg.hash(k)); assert rv != null : "Found no node for key " + k; return rv; } MemcachedNode getNodeForKey(long hash) { final MemcachedNode rv; if(!ketamaNodes.containsKey(hash)) { // Java 1.6 adds a ceilingKey method, but I'm still stuck in 1.5 // in a lot of places, so I'm doing this myself. SortedMap<Long, MemcachedNode> tailMap=ketamaNodes.tailMap(hash); if(tailMap.isEmpty()) { hash=ketamaNodes.firstKey(); } else { hash=tailMap.firstKey(); } } rv=ketamaNodes.get(hash); return rv; }

这段代码非常清晰,就是通过ketamaNodes这个数据结构按照一致性hash算法把node分区,每次都把映射到一个分区的key对于到负责这个分区的node上。

从上面几段代码和图示,我们大致能弄明白在客户端如何做路由来让memcached分布式,其实在大多数的项目中,以上这些简单的处理办法就足够了

memcached服务端集群

由上面可知一般的应用中memcached服务端集群不用做太多工作,部署一堆memcached服务器就可以了,大不了就是要做好监控的工作,但像facebook这样的大型互联网应用,并且又是那么依赖memcached,集群的工作就很有学问了。今年Qcom的会议上facebook就介绍了是如何通过扩展memcached来应付这么多数据量的,ppt可见Facebook的扩展Memcached实战。这个PPT比较抽象,我没看得太懂,并且facebook也只是蜻蜓点水,没透露太多的细节,但公司的资深架构师陈大峰同学做了些解析,才多多少少有点眉目。facebook所有数据的存取都基本上是在memcached上完成,后端的数据库mysql仅仅只是做持久化的作用,由于数据量巨大,做了类似与mysql的读写分离的结构,结构图如下所示:

其中非常重要的一点,当West的memcached要向East同步数据的时候,它没有采取memcached之间的同步,而是走MySQL replication,如下图所示:

这么做的原因我没法搞得太清楚,大概是比较信赖MySQL replication的简单稳定吧,并且像sns这种应用本身就不需要即时一致性,只要最终一致就行了。

另外在数据分布上是很有讲究的,facebook上面有很多很热的数据,比如LadyGaGa发布一条消息,将会有千万的人收到这个消息,如何把LadyGaGa和普通的用户同等对待就很可能会把这个memcached节点搞垮,甚至访问冲向后面的数据库后会把数据搞垮,如下图所示:

因此就需要一些策略来控制这些热点数据和热点访问,这些策略细节是什么facebook没说太清楚,一般说来可以把热点数据分布到其他节点,另外对于数据库可以加锁控制流量,只有拿到锁的访问才能直接访问数据库,没拿到的需要等候和竞争。

另外一个数据分布的难题是每个用户可能会有成百上千的好友,而这些好友的数据分布在成百上千台的memcached的节点,这样一个客户端就需要连接成千上万的memcached的节点,如下图所示:

这种问题一般说来可以采取数据重组,把有关联的数据重组在一起,而不是分布在n台机器上。

以上的这些facebook的实践只能说是走马观花地看看了,从我们可以看到一个简简单单memcached也能完成这么多玩样来,可以猜想到facebook的那些天才工程师们在亿万数据压力下被逼出了多少创新的设计,这些设计不一定适用于我们,不了解情景也没办法深究里面的细节,我们要做的是围绕我们自己的应用,让memcached玩出点味道来。

相关文章:

  • poj 2421 Constructing Roads 解题报告
  • 发布一个基于 Reactor 模式的 C++ 网络库
  • 定长度结构体数组、不定长度结构体指针初始化
  • 软考--数据库SQL
  • C++默认参数不能是一个引用
  • 【转】一致性哈希算法
  • 面试时,我说谎了——Leo网上答疑44
  • 转载百度百科上的强回复,关于spring的IOC和DI
  • CakePHP 编程笔记
  • EPiServer 简单项目总结
  • 小修改,让mvc的验证锦上添点花(1)
  • linux根目录各文件夹的含义
  • 不能从实体机给虚拟机进行文件拷贝
  • SSH整合的基本步骤
  • Delphi XE5的Android开发平台搭建 【转载】
  • 《Java编程思想》读书笔记-对象导论
  • 30天自制操作系统-2
  • 77. Combinations
  • Angular Elements 及其运作原理
  • download使用浅析
  • ES6系列(二)变量的解构赋值
  • macOS 中 shell 创建文件夹及文件并 VS Code 打开
  • nginx 负载服务器优化
  • React+TypeScript入门
  • text-decoration与color属性
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • ucore操作系统实验笔记 - 重新理解中断
  • webpack4 一点通
  • 初探 Vue 生命周期和钩子函数
  • 多线程事务回滚
  • 构建工具 - 收藏集 - 掘金
  • 函数式编程与面向对象编程[4]:Scala的类型关联Type Alias
  • 区块链将重新定义世界
  • 设计模式 开闭原则
  • 阿里云ACE认证之理解CDN技术
  • ​2020 年大前端技术趋势解读
  • ​RecSys 2022 | 面向人岗匹配的双向选择偏好建模
  • ​比特币大跌的 2 个原因
  • # 透过事物看本质的能力怎么培养?
  • #etcd#安装时出错
  • #Java第九次作业--输入输出流和文件操作
  • #NOIP 2014# day.1 生活大爆炸版 石头剪刀布
  • #pragam once 和 #ifndef 预编译头
  • #我与Java虚拟机的故事#连载04:一本让自己没面子的书
  • $.ajax()参数及用法
  • $.ajax,axios,fetch三种ajax请求的区别
  • (MATLAB)第五章-矩阵运算
  • (二)hibernate配置管理
  • (二)什么是Vite——Vite 和 Webpack 区别(冷启动)
  • (机器学习-深度学习快速入门)第一章第一节:Python环境和数据分析
  • (剑指Offer)面试题34:丑数
  • (算法二)滑动窗口
  • (转)iOS字体
  • (转)ObjectiveC 深浅拷贝学习
  • .axf 转化 .bin文件 的方法