7月,我写了一个博客向Java开发人员介绍erlang,重点介绍了这两种语言之间的一些异同。 erlang虚拟机具有许多令人印象深刻的内置功能,其中之一是它们独立于位置并且可以互相通信。 这意味着可以通过编写很少的代码行在VM之间同步数据。 如果您有一个网络集群的服务器都在做相同的事情,这真是个好消息。
您可能会争辩说,即使JVM无法执行最基本的进程间通信,也可能缺少某些东西。 但是,Java却持相反的观点,它具有基本的VM,然后在需要时在其上分层放置不同的服务。 这是否正确只是一个见解,我将其作为未来博客的主题,因为Hazelcast Guys似乎已经解决了JVM之间相互交谈的问题; 这是本博客的重点。
那么,什么是Hazelcast?
Hazelcast新闻稿是这样的:“ Hazelcast( www.hazelcast.com )正在通过开放源代码重塑内存数据网格。 Hazelcast提供了一个嵌入式库,任何Java开发人员都可以在几分钟之内包含该库,从而使他们能够构建优雅而简单的关键任务,事务性和万亿级内存应用程序。”
那么,这到底意味着什么?
好的,那只是营销/公关障碍。 在现实生活中,什么是Hazelcast? 可以使用代码简洁地给出答案。 假设您正在编写一个应用程序,并且需要一个Map<String,String>
而在生产环境中,您将在集群中拥有多个应用程序实例。 然后编写以下代码:
HazelcastInstance instance = Hazelcast.newHazelcastInstance(); loggedOnUsers = instance.getMap("Users");
…意味着由您的应用程序的一个实例添加到地图的数据可用于您的应用程序的所有其他实例2
您可以从中得出几点。 首先,Hazelcast节点是“无主节点”,这意味着它不是客户端-服务器系统。 有一个集群领导者,默认情况下是集群中最老的成员,它负责管理数据在系统中的分布方式。 但是,如果该节点发生故障,则下一个最旧的节点将接管。
拥有一堆分布式的地图,列表,队列等,意味着一切都保存在内存中。 如果集群中的一个节点死亡,那么您就可以了,不会有数据丢失; 但是,如果多个节点同时死亡,那么您将遇到麻烦,并且由于系统没有时间重新平衡自身,您将丢失数据。 不用说,如果整个集群都死了,那么您将遇到大麻烦。
那么,为什么Hazelcast是个好选择?
- 它是开源的。 通常这是一件好事……
- Hazelcast刚刚收到了巨额现金注入,以“商品化”该产品。 有关更多信息,请在这里和这里看看。
- 罗德·约翰逊(Rod Johnson)是的,斯普林先生现在是Hazelcast的董事会成员。
- 它只是工作1 。
- 入门非常容易。
场景
为了演示Hazelcast,请想象您正在编写一个应用程序,在这种情况下,该应用程序由MyApplication
类建模,然后有一个很大的用户世界,由BigWideWorld
类建模。 正如预期的那样,来自BigWideWorld
用户登录并注销了您的应用程序。 您的应用程序非常受欢迎,并且您正在集群中运行它的多个实例,因此,当用户登录该应用程序的实例时,它将其详细信息(由User
类建模)存储在Map
以及Map
的内容与您的应用程序其他实例保存的地图同步。
POM配置
首先要做的是设置POM.xml,只有一个条目需要考虑:
<dependency><groupId>com.hazelcast</groupId><artifactId>hazelcast</artifactId><version>3.1</version></dependency>
编码
BigWideWorld
是代码的起点,对于这么大的概念而言,这是一个很小的类。 它有一个方法nextUser()
,它从应用程序所有用户的集合中随机选择下一个要登录或注销的用户的名称。
public class BigWideWorld { private static Random rand = new Random(System.currentTimeMillis()); private final Users users = new Users(); private final int totalNumUsers = users.size(); public String nextUser() { User user = users.get(rand.nextInt(totalNumUsers)); String name = user.getUsername(); return name; } }
用户集合由Users
类管理。 这是一个示例代码便捷类,其中包含许多硬编码用户的详细信息。
public class Users { /** The users in the database */ private final User[] users = { new User("fred123", "Fred", "Jones", "fredj@a.com"), new User("jim", "Jim", "Jones", "jimj@a.com"), new User("bill", "Bill", "Jones", "bill@a.com"), new User("ted111", "Edward", "Jones", "tedj@a.com"), new User("annie", "Annette", "Jones", "annj@a.com"), new User("lucy", "Lucy", "Jones", "lucyj@a.com"), new User("jimj", "James", "Jones", "jimj@a.com"), new User("jez", "Jerry", "Jones", "fredj@a.com"), new User("will", "William", "Jones", "willj@a.com"), new User("shaz", "Sharon", "Jones", "shazj@a.com"), new User("paula", "Paula", "Jones", "pauj@a.com"), new User("leo", "Leonardo", "Jones", "leoj@a.com"), }; private final Map<String, User> userMap; public Users() { userMap = new HashMap<String, User>(); for (User user : users) { userMap.put(user.getUsername(), user); } } /** * The number of users in the database */ public int size() { return userMap.size(); } /** * Given a number, return the user */ public User get(int index) { return users[index]; } /** * Given the user's name return the User details */ public User get(String username) { return userMap.get(username); } /** * Return the user names. */ public Set<String> getUserNames() { return userMap.keySet(); }
}
此类包含一些数据库类型的调用,例如get(String username)
返回给定名称的用户对象,或者get(int index)
返回数据库中的给定用户,或者size()
返回数字。数据库中的用户数量。
用户由User
类描述; 一个简单的Java bean:
public class User implements Serializable { private static final long serialVersionUID = 1L; private final String username; private final String firstName; private final String lastName; private final String email; public User(String username, String firstName, String lastName, String email) { super(); this.username = username; this.firstName = firstName; this.lastName = lastName; this.email = email; } public String getUsername() { return username; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public String getEmail() { return email; } @Override public String toString() { StringBuilder sb = new StringBuilder("User: "); sb.append(username); sb.append(" "); sb.append(firstName); sb.append(" "); sb.append(lastName); sb.append(" "); sb.append(email); return sb.toString(); }
}
继续讨论博客的症结所在,这就是MyApplication
类。 本博客中的大多数代码只是橱窗装饰,重要的代码在MyApplication
的构造函数中。 该构造包含两行代码。 第一个使用新的Hazelcast实例,而第二个使用该实例创建名称空间为“ Users”的Map<String, User>
。 这就是所需的所有Hazelcast特定代码。 其他方法: logon()
, logout()
和isLoggedOn()
仅管理用户。
使用简单的Main
类将以上所有内容捆绑在一起:
public class Main { public static void main(String[] args) throws InterruptedException { BigWideWorld theWorld = new BigWideWorld(); MyApplication application = new MyApplication(); while (true) { String username = theWorld.nextUser(); if (application.isLoggedOn(username)) { application.logout(username); } else { application.logon(username); } application.displayUsers(); TimeUnit.SECONDS.sleep(2); } } }
此代码创建BigWideWorld
和MyApplication
的实例。 然后,它无限循环地抓住下一个随机用户名。 如果用户已经登录,则该用户注销。 如果用户未登录,则该用户登录。然后将显示已登录的用户,以便您查看正在发生的情况。
运行应用
构建应用程序后,打开终端并导航到project target/classes
目录。 然后输入以下命令:
java -cp /your path to the/hazelcast-3.1/lib/hazelcast-1.jar:. com.captaindebug.hazelcast.gettingstarted.Main
运行时,您将获得如下所示的输出:
Logged on users:
User: fred123 Fred Jones fredj@a.com
User: jimj James Jones jimj@a.com
User: shaz Sharon Jones shazj@a.com
User: paula Paula Jones pauj@a.com
User: lucy Lucy Jones lucyj@a.com
User: jez Jerry Jones fredj@a.com
User: jim Jim Jones jimj@a.com
7 -- 14:54:16-17
接下来,打开更多终端并运行您的应用程序的更多实例。
如果您跟踪输出,则可以看到用户登录和注销,并且每次更改都显示用户Map
。 一个应用程序的地图更改反映在其他实例中的线索可能很难发现,但可以从地图的总大小(输出最后一行的第一个数字)中得出。 每次显示地图时,都会有一个用户登录或注销。 但是,总大小可能会改变一个以上,这意味着其他实例的更改已影响您正在查看的地图的大小。
因此,您有一个简单的应用程序,当四个实例正在运行时,它们保持同步并知道哪些用户已登录。
它应该可以在大型群集中工作,但我从未尝试过。 显然,在大型集群中,您必须对配置文件进行一些改动,但这超出了本博客的范围。
1好的,足够的市场营销能力。 总的来说,它确实是“有效的”,但是请记住,它是由像您和我这样的开发人员编写的软件,它确实具有功能和特质 。 举例来说,如果你还在使用2.4版本,然后立即升级。 这会有内存泄漏,这意味着它在感觉到时“只是默默地停止工作”。 最新版本是3.1。
2我选择了Map
作为示例,但对于其他集合类型(如List
, Set
和Queue
也是如此,另外,Hazelcast还具有许多其他功能,这些功能超出了本博客的范围,包括大量并发实用程序和发布/订阅消息传递。
- 该博客的代码可在github上找到: https : //github.com/roghughe/captaindebug/tree/master/hazelcast
翻译自: https://www.javacodegeeks.com/2013/11/getting-started-with-hazelcast.html