Hazelcast ( www.hazelcast.com)是一种内存数据网格 in-memory data grid,提供Java程序员关键任务交易和万亿级内存应用。

Hazelcast的集群属于“无主节点”,这意味着它不是一个客户端 - 服务器系统。有一个集群的领导者,默认是最老的成员,管理数据是如何在系统间分布,但是,如果该节点当机,那么是下面一个旧的节点接管。

你所用的数据结构Maps List和队列都是保存在内存中。如果集群中的一个节点死亡,数据不会丢失,但如果多个节点同时当机,那么你就麻烦了。

下面以BigWideWorl为案例说明Hazelcast的使用,首先依赖包导入:

<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
<version>3.1</version>
</dependency>

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;       
  }       
}

nextUser()方法可以随机获得一个用户的名称,用户集合由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(); 
  } 
}

Users其实类似一个Map集合。下面是用户类:

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(); 
  } 
}

用户User必须实现序列化接口。

客户端调用代码如下:

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的实例。然后,它无限循环抓住抓取下一个随机的用户名。如果是已经登录的用户,那么注销该用户。如果没有登录的用户,然后登录用户后显示。

运行该代码:

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集合每次显示出改变,关键是:一个应用的Map大小变化会影响其他窗口应用内的大小,好像大家共用一个Users的Map集合。

发布者和订阅者实现

假设有一个模型:

public class StockPrice implements Serializable {

private static final long serialVersionUID = 1L;

private final BigDecimal bid;

private final BigDecimal ask;

private final String code;

private final String description;

private final long timestamp;

/** 
   * Create a StockPrice for the given stock at a given moment 
   */ 
  public StockPrice(BigDecimal bid, BigDecimal ask, String code, String description, 
      long timestamp) { 
    super(); 
    this.bid = bid; 
    this.ask = ask; 
    this.code = code; 
    this.description = description; 
    this.timestamp = timestamp; 
  }

public BigDecimal getBid() { 
    return bid; 
  }

public BigDecimal getAsk() { 
    return ask; 
  }

public String getCode() { 
    return code; 
  }

public String getDescription() { 
    return description; 
  }

public long getTimestamp() { 
    return timestamp; 
  }

@Override 
  public String toString() {

StringBuilder sb = new StringBuilder("Stock - "); 
    sb.append(code); 
    sb.append(" - "); 
    sb.append(description); 
    sb.append(" - "); 
    sb.append(description); 
    sb.append(" - Bid: "); 
    sb.append(bid); 
    sb.append(" - Ask: "); 
    sb.append(ask); 
    sb.append(" - "); 
    SimpleDateFormat df = new SimpleDateFormat("HH:MM:SS"); 
    sb.append(df.format(new Date(timestamp))); 
    return sb.toString(); 
  } 
}

要求将股票的买入卖出价格在任何时间发布给做市商。

发布者代码:

public class MarketMaker implements Runnable {

private static Random random = new Random();

private final String stockCode;

private final String description;

private final ITopic<StockPrice> topic;

private volatile boolean running;

public MarketMaker(String topicName, String stockCode, String description) { 
    this.stockCode = stockCode; 
    this.description = description; 
    this.topic = createTopic(topicName); 
    running = true; 
  }

@VisibleForTesting 
  ITopic<StockPrice> createTopic(String topicName) { 
    HazelcastInstance hzInstance = Hazelcast.newHazelcastInstance(); 
    return hzInstance.getTopic(topicName); 
  }

public void publishPrices() {

Thread thread = new Thread(this); 
    thread.start(); 
  }

@Override 
  public void run() {

do { 
      publish(); 
      sleep(); 
    } while (running); 
  }

private void publish() {

StockPrice price = createStockPrice(); 
    System.out.println(price.toString()); 
    topic.publish(price); 
  }

@VisibleForTesting 
  StockPrice createStockPrice() {

double price = createPrice(); 
    DecimalFormat df = new DecimalFormat("#.##");

BigDecimal bid = new BigDecimal(df.format(price - variance(price))); 
    BigDecimal ask = new BigDecimal(df.format(price + variance(price)));

StockPrice stockPrice = new StockPrice(bid, ask, stockCode, description, 
        System.currentTimeMillis()); 
    return stockPrice; 
  }

private double createPrice() {

int val = random.nextInt(2010 - 1520) + 1520; 
    double retVal = (double) val / 100; 
    return retVal; 
  }

private double variance(double price) { 
    return (price * 0.01); 
  }

private void sleep() { 
    try { 
      TimeUnit.SECONDS.sleep(2); 
    } catch (InterruptedException e) { 
      e.printStackTrace(); 
    } 
  }

public void stop() { 
    running = false; 
  }

public static void main(String[] args) throws InterruptedException {

MarketMaker bt = new MarketMaker("STOCKS", "BT.L", "British Telecom"); 
    MarketMaker cbry = new MarketMaker("STOCKS", "CBRY.L", "Cadburys"); 
    MarketMaker bp = new MarketMaker("STOCKS", "BP.L", "British Petrolium");

bt.publishPrices(); 
    cbry.publishPrices(); 
    bp.publishPrices();

}

}

其中代码关键是:

ITopic<StockPrice> createTopic(String topicName) { 
    HazelcastInstance hzInstance = Hazelcast.newHazelcastInstance(); 
    return hzInstance.getTopic(topicName); 
  }

这是设置Hazelcast,创建一个主题topic用于股票发布。真正发布是在run方法中的topic.publish(price);

订阅者代码如下:

public class Client implements MessageListener<StockPrice> {

public Client(String topicName) { 
    HazelcastInstance hzInstance = Hazelcast.newHazelcastInstance(); 
    ITopic<StockPrice> topic = hzInstance.getTopic(topicName); 
    topic.addMessageListener(this); 
  }

/** 
   * @see com.hazelcast.core.MessageListener#onMessage(com.hazelcast.core.Message) 
   */ 
  @Override 
  public void onMessage(Message<StockPrice> arg0) { 
    System.out.println("Received: " + arg0.getMessageObject().toString()); 
  }

public static void main(String[] args) {

new Client("STOCKS"); 
  }

}

下面是运行,需要配合两个包:hazel cast-3.1.jar and guava-13.0.1.jar.

java -cp ./:/Users/Roger/tmp/mm/guava-13.0.1.jar:/Users/Roger/tmp/mm/hazelcast-3.1.jar com.captaindebug.hazelcast.pubsub.MarketMaker

下面是订阅者运行:

java -cp ./:/Users/Roger/tmp/mm/guava-13.0.1.jar:/Users/Roger/tmp/mm/hazelcast-3.1.jar com.captaindebug.hazelcast.pubsub.Client

Hazelcast 内存数据网格的更多相关文章

  1. 内存数据网格hazelcast的一些机制原理

    hazelcast作为一个内存数据网格工具,还算比较优秀,听说有Apache顶级项目使用它,值得研究下,使用文档可以直接看官方文档,但机制原理相关的资料基本没有,本人硬撸源码写的一些东西,跟大家分享一 ...

  2. 内存数据网格IMDG简单介绍

    1 简单介绍 将内存作为首要存储介质不是什么新奇事儿,我们身边有非常多主存数据库(IMDB或MMDB)的样例.在对主存的使用上.内存数据网格(In Memory Data Grid,IMDG)与IMD ...

  3. 内存数据网格IMDG简介

    1 简介 将内存作为首要存储介质不是什么新鲜事儿,我们身边有很多主存数据库(IMDB或MMDB)的例子.在对主存的使用上,内存数据网格(In Memory Data Grid,IMDG)与IMDB类似 ...

  4. ZeroMQ接口函数之 :zmq_send_const – 从一个socket上发送一个固定内存数据

    ZeroMQ API 目录 :http://www.cnblogs.com/fengbohello/p/4230135.html ——————————————————————————————————— ...

  5. 【jQuery EasyUI系列】创建CRUD数据网格

    在上一篇中我们使用对话框组件创建了CRUD应用创建和编辑用户信息.本篇我们来创建一个CRUD数据网格DataGrid 步骤1,在HTML标签中定义数据网格(DataGrid) <table id ...

  6. 关于内存数据与 JSON

    闲话: 正在用 WebBroker 写一个小网站,感受颇多: 1.如果是写一个小东西,应该先考虑下 WebBroker,因为它是分分钟即可上手的. 2.如果要写一个大东西,或许也应该考虑下 WebBr ...

  7. easyui数据网格视图(Datagrid View)的简单应用

    下面介绍datagrid的数据网格详细视图和数据网格的分组视图 1.先引用的js和css文件 1)包含eauyui必备的四个文件easyui.css,icon.css, jquery-min.js.j ...

  8. Linux就这个范儿 第18章 这里也是鼓乐笙箫 Linux读写内存数据的三种方式

    Linux就这个范儿 第18章  这里也是鼓乐笙箫  Linux读写内存数据的三种方式 P703 Linux读写内存数据的三种方式 1.read  ,write方式会在用户空间和内核空间不断拷贝数据, ...

  9. Linux就这个范儿 第15章 七种武器 linux 同步IO: sync、fsync与fdatasync Linux中的内存大页面huge page/large page David Cutler Linux读写内存数据的三种方式

    Linux就这个范儿 第15章 七种武器  linux 同步IO: sync.fsync与fdatasync   Linux中的内存大页面huge page/large page  David Cut ...

随机推荐

  1. LNK2019: 无法解析的外部符号(函数实现没有加namespace前缀导致)

    问题描述: 在A.h中,我写了如下函数 namespace XXX { void func(); } 在A.cpp中,我写了如下实现 #include "A.h" using na ...

  2. 本地运行storm时报错

    java.lang.NoClassDefFoundError: backtype/storm/topology/IRichSpout at java.lang.Class.getDeclaredMet ...

  3. Unix系统编程()lseek系统调用

    之前知道lseek这个系统调用可以改变文件的偏移量,或者叫偏移量或指针. 文件偏移量是指执行下一个read或者write操作的文件起始位置,会以相对于文件头部起始点的文件当前位置来表示. 除非指定了O ...

  4. php 计算时间添加

    $Date_1=date("Y-m-d");$Date_2="2015-10-11";$d1=strtotime($Date_1);$d2=strtotime( ...

  5. 第一百四十节,JavaScript,封装库--浏览器检测

    JavaScript,封装库--浏览器检测 在函数库编写一个,浏览器检测对象 /** sys浏览器检测对象,对象下有两个属性,liu_lan_qi属性和xi_tong属性 * liu_lan_qi属性 ...

  6. 抽象窗口工具包AWT (Abstract Window Toolkit) 是 API为Java 程序提供的建立 图形用户界面

    抽象窗口工具包AWT (Abstract Window Toolkit) 是 API为Java 程序提供的建立 图形用户界面GUI (Graphics User Interface)工具集,AWT可用 ...

  7. ubuntu卸载vmware player

    sudo vmware-installer -u vmware-player 转自: http://zhidao.baidu.com/link?url=lapkBNBGIUz_mo6603CQgi_2 ...

  8. Linux文件的打包与压缩

    打包命令: tar tar 的选项与参数非常的多!我们只讲几个常用的选项,更多选项您可以自行 man tar 查询罗! [root@www ~]# tar [-j|-z] [cv] [-f 创建的档名 ...

  9. 获取WPF的DataGrid控件中,是否存在没有通过错误验证的Cell

     /// <summary>         /// 获取DataGrid的所有行是否存在验证错误.         /// </summary>         /// &l ...

  10. AutoMapper整理收集

    http://www.cnblogs.com/jobs2/p/3503990.html http://www.cnblogs.com/1-2-3/p/AutoMapper-Best-Practice. ...