Geode、Gemfire

Gemfire - 分布式缓存利器 - 简书 (jianshu.com)

简介

Geode、gemfire是Pivotal公司开发的一款开源的、分布式NoSql内存数据库,可以用来完成分布式缓存,数据持久化,分布式事务、动态扩展等功能。

Geode是Gemfire的开源版本,GemFire是商业版本,最初被用于实时性很高的华尔街金融部门,作为世界规模最大的实时交易系统之一12306就是使用的GemFire。

Geode和GemFire是一种数据管理和分布式计算平台,支持高性能的缓存和数据共享。它采用了分布式内存架构,可以处理大规模的数据量和高并发的访问请求。Geode/GemFire由Apache软件基金会维护,具有很高的可靠性和稳定性。

Geode、GemFire具有以下优点

  1. 分布式架构:可以将数据存储在多个服务器上,实现水平扩展和高可用性
  2. 高性能:使用内存作为数据存储截止,可以快速响应读写操作,通过复制和数据分区等技术实现负载均衡
  3. 复杂查询支持:支持基于SQL复杂查询,可以对分布式数据进行灵活高效的查询和分析。
  4. 事务支持:提供强一致性的分别是事务支持,确保数据的完整性和一致性。
  5. 可靠性和扩展:使用复制和数据分区等机制实现数据的可靠性和扩展性,并提供自动故障恢复和负载均衡等功能。

以下是Geode使用示例

import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionFactory;

// 创建缓存
Cache cache = new CacheFactory().create();

// 创建区域
RegionFactory<String, String> regionFactory = cache.createRegionFactory();
Region<String, String> region = regionFactory.create("myRegion");

// 设置键值对
region.put("name", "Alice");

// 获取键值对
String name = region.get("name");
System.out.println(name);   // 输出:Alice

核心概念

Region

region是Gemfire中一map的分别是实现,同时具备了查询,事务。这个是Gemfire的核心中核心,一切的一切始于此。

Replicated Region:一个Replicated Region保存所有分区的数据拷贝。

partitionedRegion:只保存一部分分区的数据拷贝

Shared-Nothing Persistence

支持非共享持久化,每一个peer持久化数据到本地磁盘,Gemfire持久化允许在磁盘维护一份配置的数据拷贝

Distributed

Distributed Member:Gemfire托管的集群成员

Distributed Transaction:跨节点,集群更新事务,分布式事务

Distrbuted Lock:分布式集群锁

Locator&Geteway

Gemfire的Locator类似zookeeper,协调客户端与服务端成员,互相发现,以及简单负载均衡(非负荷均载)

拓步结构

Peer-to-Peer

缓存嵌入应用,共享堆内存,适合小型缓存应用

client、server结构

缓存层由分别是系统来组成,是多数中大型系统首选。

分布式引入Loactor(定位器)来管理解耦,离散,分布式客户端与服务器端

上图可以看出客户端与服务器通信要先透过Locator提供的发现机制,当然鉴于此所有的服务端必须与Locator进行广播通信广播其生死状态,类似ZK。Locator通过JVM广播消息或TCP实现通信定位。每个新加入或者离开的成员都会更新Loactor,并从Loactor上发现目前可用成员列表。

另外,Locator可以提供简单负载均衡,只是基于当前服务器是否有客户端连接而已。

gemfire提供了跨节点将键值对均匀分布到节点,以及一致性哈希算法等。

如果希望指定负载均衡策略,Gemfire提供了Member Groups,可以把某些服务器分组,固定为某些客户端、某些请求服务,再获得负载均衡的优势同时也失去了分布式的优势,正所谓有利有弊。

Server内部提供了connection poor,queue以及subscription机制,以并行处理以CEP事件通知机制。同样,Gemfire客户端也提供了connection pool。

经验丰富的老司机看到这里肯定会说,全局就一个Locator一定会造成单点故障,当然分布式系统的必备。Gemfire也提供了启动多个Locator的能力。

gpt生成 Gemfire是如何保证cap的

  1. 一致性(Consistency):GemFire通过采用强一致性模型来保证数据的一致性。它使用分布式事务和复制机制来确保数据的原子性、一致性和持久性。GemFire的复制策略可配置为同步或异步复制,以满足应用程序对一致性的需求。
  2. 可用性(Availability):GemFire通过数据的复制和备份机制来提高系统的可用性。它允许将数据复制到多个节点,以实现数据的冗余存储。当某个节点发生故障或不可用时,GemFire可以自动将数据路由到其他可用节点,以保持系统的可用性。
  3. 分区容错性(Partition tolerance):GemFire使用数据分区和数据复制来实现分区容错性。数据分区将数据划分为多个分区,并将每个分区分配给不同的节点。当网络分区或节点故障发生时,GemFire可以继续在可用的节点上提供服务,确保系统的分区容错性。

多地/多数据真心WAN部署

互联网世界比较流行,行话异地多活,全国甚至全球多地多数据中心部署。大型金融系统中也是不可或缺的,如全球多金融中心部署,NY, London, HK, TK等分布式多数据中心缓存。做的好的话,可以做到任意一个数据中心瘫痪,系统自动切换到其他数据中心运营,差的话就要人工干预了,不过至少不会完全瘫痪。

多数据中心的数据同步则是靠gateway来同步的,gateway receiver与gateway sender来发送接受数据中心的变化,如上图东京如果有缓存数据变化,新增或者变化,则会通过gateway发送给纽约的集群,通过gateway receiver来更新纽约的缓存,由于跨多地,网络,所以非实时同步更新,做到最终一致性。当然sender中必须提供了queue。

一个数据中心的集群是靠Locator来维系发现各个服务器的,对于跨多数据中心,Gemfire则通过每个集群的distributed-system-id,依靠remote-locators来发现数据中心集群是否存活。

DataRegion

上文介绍过,Region是Gemfire中用来管理的,存储数据的核心数据结构,本身实现了Map接口,类似于ConcurrentMap,同时支持分布式跨物理节点。

Region同时支持嵌套,子Region。Region又区分为Patitioned,Replicated, Distributed non-replicated, Non-distributed(local)。

Gemfire的Data Region的读写操作支持同步读,同步写,异步写。

数据分布模型支持D-no-Ack, D-Ack, Global(锁)。

此外,Region还进行分布式支持以下高阶:

  • 溢出至磁盘持久化(LRU)
  • 持久化到磁盘
  • 跨节点数据同步
  • 外部数据源(数据库)延迟加载数据
  • OQL

Replicated Region

Replicated Region在每个Gemfire成员上同步的保存一份完整的数据拷贝。Proxy:数据不存在本地缓存,Proxy成员提供了Region的访问,需要其他成员配置Region的Non-proxy拷贝用以存放数据

显然这是以空间换时间;这种Data Region适用于小型数据集并且读很频繁的操作;

PartitionedRegion

Partitioned Region顾名思义,将数据分散,每个成员近保存数据一部分,时间换空间;

既然分区存储了,一定是适合大数据的数据集了,以及写/修改较多的数据集,并提供给了分布式并行查询,处理, MapReduce。

OQL

Region提供类SQL, 基于SQL-92子集的OQL查询,注意可以跨分布式节点以及并行查询,这点是很多缓存不具备的,尽管简单。

SELECT, WHERE, DISTINCT, COUNT, IN, LIKE, 嵌套自查询,Map查询( p['key'] = '1.0' ),ORDER BY,。

注意,OQL仅支持COUNT,不支持其它SUM, MIN, MAX。

另外,OQL支持Limit, 类似TOP:

SELECT * FROM /Region1 limit 100;

这里还提供高阶的Join, 大多数No-SQL都不支持,这里因为更类似二维表格,也提供了Join操作, 如下:

SELECT * FROM /Region1 r1, /Region2 r2 WHERE r1.status = r2.status;

可见,还是相对较熟悉,强大。当然这里的Join仅支持内连接,并不支持左右连接,毕竟没有那么强大。

既然可以提供OQL查询,支持Join, 那老司机又问是否可以做Index? 还真可以。

当然也支持代码动态创建了。当然,没有免费的午餐,与RDBMS类似,索引是把双刃剑,提供索引必然会降低修改,更新性能,提升查询性能。

用惯了Oracle了老鸟,这里居然也支持HINT,好吧。

当然,也不建议用过度负载的OQL,毕竟不是强大的RDBMS,况且考虑到兼容性,可移植性,以及没有那么强大的调试支持。

事务支持

实物的操作首先作用在主拷贝节点,然后分不到其他成员中。

  • 运行事务代码的成员被称作事务初始化器
  • 管理事务和数据的成员被称为事务数据节点

Gemfire提供了分布式事务支持,难能可贵,在分布式世界里,提供分布式事务可比较重!所以尽量少用,开销太大,甚至可能全局死锁。

Gemfire同样提供了分布式锁支持,可以显示创建分布式锁, 在任何一个时间点,

工作原理

在并发访问缓存的时候, 事务之间是隔离的。每一个事务都有自己的私有空间,包括已经读取的数据及其变更;当一个数据条目进入事务时,将在事务视图/空间生成一个数据状态的快照,此事务能保存数据的原始状态,快照的另一个作用则用于题解恢复写冲突。

当事务提交成功时,事务视图中的记录被合并到缓存上,如果提交失败或者回滚,则所有变更将放弃。提交事务时,Gemfire采用了两阶段提交协议, Two-Phase commit Protocol。

Gemfire甚至支持了JTA分布式事务:

惨不忍睹,自己官方文档都放不下该图,可见复杂。不推荐,不建议。

通常,非必需,不建议使用分布式事务,因为会大大降低整体的性能,这与使用缓存的本意背驰。

分布式锁

Gemfire也提供了分布式锁支持,在任何一个时间节点,Gemfire系统保证只有一个线程可以用于该锁。另外线程将锁定整个服务,防止系统中其它线程锁定这个服务。可见其成本之高。

分布式锁分为隐式锁与显示锁。大多数情况下,系统自动利用隐式锁进行数据操作。锁服务从系统成员接受锁请求,并放入队列,按顺序授予锁。授予者负责运行锁服务。

当分布式锁服务创建时,分布式系统中某个成员通过选举成为分布式锁服务的授予者,授予者负责管理这个锁。当这个成员出现故障时,锁授予功能将被迁移到其它成员,且不丢失锁状态;这些细节处处可以看到分布式设计的目标及精髓。

MapReduce

Gemfire与时俱进,提供了在分布式节点进行Map Reduce的操作函数。

函数用Java自行编写,部署,运行。Gemfire支持两种形式的函数运行模式,方式1,提前注册并部署自定义函数到每个成员,运行时指定函数名字,显然不灵活,高耦合,每次改动函数都要全局部署;方式2,运行时动态ship函数,所谓ship function rather than data;更加现代的模式(从Gemfire 6.x开始支持)当然为了做到这种高效,必然要RPC + 序列化,所谓有利有弊,好处显然易见,首选推荐。

Last modification:January 15, 2024
如果觉得我的文章对你有用,请随意赞赏