本文由 Ron Zavner 撰写。
近年来,我们看到越来越多的应用程序不再构建在关系型数据库上,而是建立在分布式环境上。发生这种情况是因为它们需要可扩展性和高可用性,而且还需要能够提供高吞吐量和低延迟,这是传统都关系型数据库无法实现的。现在,分布式环境和内存数据网格比几年前更先进,但比关系型数据库更复杂。
由于分布式数据网格以分布式方式存储数据,创建分布式数据库,因此有一些操作不太直观,例如连接查询和聚合查询。假设我们想要将一个员工对象和它的部门对象一起取出。 “在数据库中,这可以通过简单的查询轻松完成。但是,对于分布式内存数据网格,我们甚至不知道员工对象和它的部门对象是否在同一个节点上(除非我们将它们路由到一起,这并不总是最佳实践)。
对于集合来说,这更加困难 - 比方说,我们想要获取所有员工的平均,最低和最高工资。在SQLit
中就像下面这样简单:
Select avg(salary) from employees group by department_id
我们可以试着使其更加复杂,例如,查询每个部门的平均工资:
Select avg(salary) from employees group by department_id
或者只查询薪水高于 X 的部门:
Select avg(salary) from employees group by department_id having avg(salary) > X
我们如何在分布式数据网格中执行这些任务?数据在节点之间进行分区。实现这一目标的一种方法就是map reduce class
。 map函数将运行在每个节点上,只计算该节点上员工的平均工资,并将结果返回给 reducer。 Reducer 运行在客户端上,然后聚合从不同节点获得的所有结果。这种方法非常高效,因为实际的业务逻辑在服务器端运行(有助于减少延迟),这样我们只需将每个节点的聚合数据返回给客户端(数据量很小)。map reduce
的缺点是它不像 SQL 查询那么直观。我们需要创建具有业务逻辑的类来进行操作,所以我们可以用简单的 API 或 SQL 查询来轻松地进行描述。
比如,我们可以使用如下所示的代码:
query = new SQLQuery(Person.class, “”);
groupByResult = groupBy(gigaSpace, query, new GroupByAggregator()
.groupBy(“department”)
.selectAverage(“salary”));
Or the more complicated query:
groupByResult = groupBy(gigaSpace, query, new GroupByAggregator()
.groupBy(“department”)
.selectAverage(“salary”)
.selectCount()
.having(new GroupByFilter() {
@Override
public boolean process(GroupByValue groupByValue) {
return groupByValue.getDouble(“avg(salary)”) > 18000;
}
}));
总而言之,如果我们想要进行 SQL 查询,比如聚合查询,我们需要克服分布式数据网格的非直观限制。