hazelcast 使用_使用Hazelcast以编程风格进行练习

hazelcast 使用

前一周,我们在线程之间共享了数据,以解决现在众所周知的词频问题。 第二天,我作为开发者倡导者加入了Hazelcast 。 因此,我认为使用Hazelcast In-Memory-Data-Grid来改进先前的解决方案将非常有趣。

这是《编程风格练习》重点系列的 18 帖子。其他帖子包括:

  1. 以编程风格介绍练习
  2. 以编程风格进行练习,将内容堆叠起来
  3. 编程风格的练习,Kwisatz Haderach风格
  4. 编程风格的练习,递归
  5. 具有高阶功能的编程风格的练习
  6. 以编程风格进行练习
  7. 以编程风格进行练习,回到面向对象的编程
  8. 编程风格的练习:地图也是对象
  9. 编程风格的练习:事件驱动的编程
  10. 编程风格的练习和事件总线
  11. 反思编程风格的练习
  12. 面向方面的编程风格的练习
  13. 编程风格的练习:FP&I / O
  14. 关系数据库风格的练习
  15. 编程风格的练习:电子表格
  16. 并发编程风格的练习
  17. 编程风格的练习:在线程之间共享数据
  18. 使用Hazelcast以编程风格进行练习 (本文)
  19. MapReduce风格的练习
  20. 编程风格的练习总结

什么是内存中数据网格?

根据Wikipedia所说,数据网格是:

[…]一种体系结构或服务集,使个人或用户组能够出于研究目的访问,修改和传输大量地理上分散的数据

让我们放弃研究目的。 上面定义的重要部分是,数据网格包含大量数据并且分布在节点之间

这种体系结构的主要问题在于它需要执行以下步骤:

  1. 从磁盘读取数据
  2. 将其加载到内存(RAM)
  3. 在那里处理
  4. 最后写回磁盘

虽然处理部分实际上是非常快的,因为它发生在内存中,但读/写部分却不是。 因此,数据网格的整体性能受到访问和读取/写入存储所花费的时间的限制。 为了更好地理解该问题,在撰写本文时,这是公认的指标:

存储 访问时间 读写速度

Random Access Memory (RAM)

~5 ns

> 10 GB/s

Solid-State Disk (SSD)

< 1 millisecond

200 MB/s to +3.5 GB/s

Hard Drive Disk (HDD)

3-10 milliseconds

< 200 MB/s

资料来源:

  • 固态硬盘(Wikpedia)
  • SSD和RAM的速度是否相同? (Quora)

如果可以删除磁盘部件,则数据网格将与执行该数据网格的速度一样快。 这就是IMDG的全部要点:权衡持久性以获得高速和低延迟。

设置Hazelcast IMDG

Hazelcast能够以两种不同的模式运行:

  1. 客户端服务器
  2. 嵌入式的

嵌入式模式易于设置。 只需将Hazelcast核心JAR添加到应用程序的类路径中,就可以启动将自动加入任何其他Hazelcast集群的嵌入式实例。 请注意,虽然广播是默认设置,但可以通过配置可以加入哪些集群来进行更多选择。

使用Maven,开始嵌入Hazelcast只是在POM中添加单个依赖项即可:

pom.xml


  
  
    
    
       com.hazelcast 
       hazelcast 
       3.12.2 
    
  

到那时,可以创建Hazelcast实例和相关的数据结构。

分布式数据结构和IMap

Hazelcast全部涉及分布式数据结构 :列表,集合,队列,地图等。

其中, IMap接口特别受关注。 本质上,可以将IMap视为Java的ConcurrentMap分布式版本 。 实际上, IMap继承自ConcurrentMap

除了标准并发地图的功能外, IMap还提供以下功能:

  • 全部或仅特定条目的转换
  • 围绕所有标准操作的丰富事件监听器模型
  • 功放统计
  • 特定条目的锁定功能
  • 还有更多...

Hazelcast API的设计使其无法实例化分布式数据结构,例如IMap 。 获取此类数据结构句柄的入口点是通过Hazelcast实例。 这是API的简化摘要:

有了它,创建Hazelcast实例并在地图上获取手柄很简单:

valhazelcastInstance=Hazelcast.newHazelcastInstance() (1)
valfreqSpace=hazelcastInstance.getMap<String,Int>("map") (2)
  1. 创建一个新实例
  2. 获取分布式地图上的句柄

迁移代码以使用Hazelcast

仍然只有更新才能迁移到Hazelcast。 需要从Hazelcast实例获取执行程序服务,而不是从标准Ja​​va API获取该服务。 这将转换为以下代码:

valexecutorService=hazelcastInstance.getExecutorService("executorService")

还有一个不太重要的警告。 由于映射可能分布在不同的JVM之间-这就是分布式系统的重点-存储的对象需要可序列化 :在Java中,这意味着它们需要实现Serializable接口。 鉴于代码的当前状态,情况并非如此:顶级Kotlin函数和其周围的Callable包装器均不可序列化。 因此,需要一个完整的类来实现必要的类层次结构:

classProcessWords(valwords:List<String>):
                         Callable<Unit>,Serializable,HazelcastInstanceAware{ (1)  (2)

  privatelateinitvarhazelcastInstance:HazelcastInstance

  overridefunsetHazelcastInstance(hazelcastInstance:HazelcastInstance){ (1)
    this.hazelcastInstance=hazelcastInstance
  }

  overridefuncall(){ (2)
    valfrequencies=hazelcastInstance.getMap<String,Int>("map") (3)
    valstopWords=read("stop_words.txt").flatMap{it.split(",")}
    words.forEach{
      if(!stopWords.contains(it))
        frequencies.merge(it,1){count,value->
            count+value
        }
    }
  }
}

valcallables=words.chunked(words.size/4).map{ProcessWords(it)} (2)
executorService.invokeAll(callables) (4)
  1. HazelcastInstanceAware允许注入...一个Hazelcast实例。 IExecutorService将在执行任务时注入它。
  2. 以前的版本是可运行的。 如上所述,不能使用标准Executors类将其包装在Callable 。 需要将Runnable.run()函数更改为Callable.call() ,但是由于不需要返回结果,因此绑定类型可以安全地为Unit
  3. 从注入的Hazelcast实例中获取一个,而不是使用共享的并发哈希图
  4. 无需更改任何内容! 与以前的版本一样,它将阻塞直到所有线程终止

此时,可以通过在多个JVM上运行来扩展代码。 当然,我们仍然需要正确处理单词输入。 那只需要使用IList

与本系列的其他文章一样,上述代码只是一个练习,旨在证明它是多么容易:使用嵌入在应用程序中的Hazelcast从标准java.util.concurrent API迁移到Hazelcast API使用Hazelcast无法获得表现的展示,尤其是在测试数据集数量有限的情况下。 刚开始,如果您运行测试,您会注意到,在JVM启动时,Hazelcast的初始化会花费一些时间。 然后,merge()实现不是特定于Hazelcast的,并且默认为ConcurrentHashMap之一:它不是分布式友好的。 也许这样的优化将成为未来帖子的主题。

结论

一旦程序正确处理了多线程,就可以轻松迁移到Hazelcast。 它的API完全映射到java.util.concurrent

虽然抽象是相同的,但这并不意味着实现是相同的。 人们需要了解使用分布式数据结构所带来的约束。

这篇文章的完整源代码可以在Github上找到。

更进一步:

  • Hazelcast IMDG文档
  • Hazelcast分布式计算
  • java.util.concurrent概述

翻译自: https://blog.frankel.ch/exercises-programming-style/18/

hazelcast 使用

你可能感兴趣的:(hazelcast 使用_使用Hazelcast以编程风格进行练习)