1. 概述
Apache Geode 是一个分布式内存数据网格,支持缓存和数据计算功能。
本教程将带你了解 Geode 的核心概念,并通过一些 Java 客户端代码示例来快速上手。
2. 环境准备
首先,我们需要下载并安装 Apache Geode,并配置好 gfsh 环境。可以参考 Geode 官方文档 进行操作。
其次,本教程会生成一些文件系统内容,建议创建一个临时目录用于隔离这些操作。
2.1. 安装与配置
在临时目录下,我们先启动一个 Locator 实例:
gfsh> start locator --name=locator --bind-address=localhost
✅ Locator 负责 Geode 集群成员之间的协调,同时也支持通过 JMX 进行管理。
接着,启动一个 Server 实例,用于承载一个或多个数据 Region:
gfsh> start server --name=server1 --server-port=0
⚠️ 这里 --server-port=0
表示让 Geode 自动选择一个可用端口。如果省略该参数,默认使用 40404 端口。
✅ Server 是集群中的一个可配置成员,以长时间运行的进程方式存在,负责管理数据 Region。
最后,创建一个 Region:
gfsh> create region --name=baeldung --type=REPLICATE
✅ Region 是我们实际存储数据的地方。
2.2. 验证环境
我们可以通过以下命令验证环境是否配置正确:
查看集群成员:
gfsh> list members
Name | Id
------- | ----------------------------------------------------------
server1 | 192.168.0.105(server1:6119)<v1>:1024
locator | 127.0.0.1(locator:5996:locator)<ec><v0>:1024 [Coordinator]
查看 Region 信息:
gfsh> describe region --name=baeldung
..........................................................
Name : baeldung
Data Policy : replicate
Hosting Members : server1
Non-Default Attributes Shared By Hosting Members
Type | Name | Value
------ | ----------- | ---------------
Region | data-policy | REPLICATE
| size | 0
| scope | distributed-ack
此外,临时目录下应该生成了 locator
和 server1
两个子目录。
看到这些输出,说明环境已经准备就绪 ✅
3. Maven 依赖
接下来,我们开始编写客户端代码。
要在 Java 项目中使用 Geode,需要添加 Apache Geode Java 客户端 依赖:
<dependency>
<groupId>org.apache.geode</groupId>
<artifactId>geode-core</artifactId>
<version>1.6.0</version>
</dependency>
我们从最基础的数据存取开始。
4. 简单的数据存取
我们演示如何存储单个值、批量值,以及自定义对象。
首先,连接到 Geode 的 baeldung
Region:
@Before
public void connect() {
this.cache = new ClientCacheFactory()
.addPoolLocator("localhost", 10334)
.create();
this.region = cache.<String, String>
createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY)
.create("baeldung");
}
4.1. 存储单个值
@Test
public void whenSendMessageToRegion_thenMessageSavedSuccessfully() {
this.region.put("A", "Hello");
this.region.put("B", "Baeldung");
assertEquals("Hello", region.get("A"));
assertEquals("Baeldung", region.get("B"));
}
4.2. 批量存储
@Test
public void whenPutMultipleValuesAtOnce_thenValuesSavedSuccessfully() {
Supplier<Stream<String>> keys = () -> Stream.of("A", "B", "C", "D", "E");
Map<String, String> values = keys.get()
.collect(Collectors.toMap(Function.identity(), String::toLowerCase));
this.region.putAll(values);
keys.get()
.forEach(k -> assertEquals(k.toLowerCase(), this.region.get(k)));
}
4.3. 存储自定义对象
先定义两个类:
public class CustomerKey implements Serializable {
private long id;
private String country;
// getters and setters
// equals and hashcode
}
public class Customer implements Serializable {
private CustomerKey key;
private String firstName;
private String lastName;
private Integer age;
// getters and setters
}
✅ 注意事项:
- 实现
Serializable
接口 - 类必须同时存在于应用和 Geode Server 的 classpath 中
打包应用后,重启 Server 并指定 classpath:
gfsh> stop server --name=server1
gfsh> start server --name=server1 --classpath=../lib/apache-geode-1.0-SNAPSHOT.jar --server-port=0
创建新的 Region:
gfsh> create region --name=baeldung-customers --type=REPLICATE
客户端代码中连接该 Region:
@Before
public void connect() {
this.customerRegion = this.cache.<CustomerKey, Customer>
createClientRegionFactory(ClientRegionShortcut.CACHING_PROXY)
.create("baeldung-customers");
}
存储自定义对象:
@Test
public void whenPutCustomKey_thenValuesSavedSuccessfully() {
CustomerKey key = new CustomerKey(123);
Customer customer = new Customer(key, "William", "Russell", 35);
this.customerRegion.put(key, customer);
Customer storedCustomer = this.customerRegion.get(key);
assertEquals("William", storedCustomer.getFirstName());
assertEquals("Russell", storedCustomer.getLastName());
}
5. Region 类型
5.1. 复制型 Region(Replicated Region)
✅ 特点:数据在多个 Server 之间完全复制。
添加一个新 Server:
gfsh> start server --name=server2 --classpath=../lib/apache-geode-1.0-SNAPSHOT.jar --server-port=0
由于我们使用的是 --type=REPLICATE
,Geode 会自动将数据复制到新 Server。
验证复制是否成功:
gfsh> stop server --name=server1
gfsh> query --query='select e.key from /baeldung.entries e'
Result : true
Limit : 100
Rows : 5
Result
------
C
B
A
E
D
✅ 数据仍然可访问,说明复制成功。
⚠️ 但这种 Region 是纯内存的,Server 崩溃后数据会丢失。如果需要持久化,可使用 --type=REPLICATE_PERSISTENT
。
5.2. 分区型 Region(Partitioned Region)
✅ 特点:数据被分片存储在不同的 Server 上。
创建分区 Region:
gfsh> create region --name=baeldung-partitioned --type=PARTITION
插入数据:
gfsh> put --region=baeldung-partitioned --key="1" --value="one"
gfsh> put --region=baeldung-partitioned --key="2" --value="two"
gfsh> put --region=baeldung-partitioned --key="3" --value="three"
查询验证:
gfsh> query --query='select e.key, e.value from /baeldung-partitioned.entries e'
Result : true
Limit : 100
Rows : 3
key | value
--- | -----
2 | two
1 | one
3 | three
停止 server1 后再次查询:
gfsh> stop server --name=server1
gfsh> query --query='select e.key, e.value from /baeldung-partitioned.entries e'
Result : true
Limit : 100
Rows : 1
key | value
--- | -----
2 | two
⚠️ 只返回部分数据,说明数据已丢失。
✅ 如果既要分区又要高可用,可以使用:
PARTITION_REDUNDANT
:分区 + 冗余PARTITION_PERSISTENT
:分区 + 持久化PARTITION_REDUNDANT_PERSISTENT
:分区 + 冗余 + 持久化
6. 对象查询语言(OQL)
Geode 支持类似 SQL 的查询语言 OQL。
示例:查找 firstName 为 "Allan" 的客户:
Map<CustomerKey, Customer> data = new HashMap<>();
data.put(new CustomerKey(1), new Customer("Gheorge", "Manuc", 36));
data.put(new CustomerKey(2), new Customer("Allan", "McDowell", 43));
this.customerRegion.putAll(data);
执行查询:
QueryService queryService = this.cache.getQueryService();
String query =
"select * from /baeldung-customers c where c.firstName = 'Allan'";
SelectResults<Customer> results =
(SelectResults<Customer>) queryService.newQuery(query).execute();
assertEquals(1, results.size());
7. 函数执行(Function Execution)
Geode 支持将计算逻辑发送到数据所在节点执行。
7.1. 定义 Function
实现 Geode 的 Function
接口:
public class UpperCaseNames implements Function<Boolean> {
@Override
public void execute(FunctionContext<Boolean> context) {
RegionFunctionContext regionContext = (RegionFunctionContext) context;
Region<CustomerKey, Customer> region = regionContext.getDataSet();
for ( Map.Entry<CustomerKey, Customer> entry : region.entrySet() ) {
Customer customer = entry.getValue();
customer.setFirstName(customer.getFirstName().toUpperCase());
}
context.getResultSender().lastResult(true);
}
@Override
public String getId() {
return getClass().getName();
}
}
7.2. 部署 Function
gfsh> deploy --jar=./lib/apache-geode-1.0-SNAPSHOT.jar
7.3. 执行 Function
@Test
public void whenExecuteUppercaseNames_thenCustomerNamesAreUppercased() {
Execution execution = FunctionService.onRegion(this.customerRegion);
execution.execute(UpperCaseNames.class.getName());
Customer customer = this.customerRegion.get(new CustomerKey(1));
assertEquals("GHEORGE", customer.getFirstName());
}
8. 总结
本教程带你快速了解了 Apache Geode 的核心功能:
- 基本的存储与查询
- 自定义对象的使用
- 复制与分区 Region 的区别
- OQL 查询支持
- Function 执行机制
所有示例代码可在 GitHub 获取。