在Ignite上运行微服务:第三部分

原创
2017/05/04 21:51
阅读数 7.2K

在Ignite上运行微服务:第三部分

这是关于如何在Ignite内存数据网格之上设计和实现微服务架构的系列文章的最后一篇,前两篇文章如下:

最后一篇文章描述的是集群如何与持久化存储集成以及外部应用如何发请求给微服务 -- 应用与集群无关也不会依赖Ignite的API。

这里还会提到第二部分中介绍的GitHub工程,因此,要确保将其检出到本机并且更新到最新版。

数据节点的持久化存储

Ignite是一个内存数据平台,默认将数据保持在内存中。然而,也可以将其持久化到磁盘上。比如希望确保即使集群重启数据也不会丢失。 要开启持久化,只需要解决三个小事情:

  1. 决定使用什么技术作为持久化存储(关系数据库、MongoDB、Cassandra、Hadoop等等);
  2. 找到一个已有的CacheStore接口实现,或者如果有必要也可以自己开发一个;
  3. 将实现加入缓存配置中。

就这么多了!做完之后,第一部分中描述的数据节点,就会与持久化存储进行交互,如下图所示:

1

要强调的是,如果内存中的数据发生变更,数据会被自动地传播到磁盘上,或者如果内存中没有对应该主键的值,会即时从持久化中进行数据的预加载。 下面看一下基于这个GitHub工程,如何为微服务架构实现以及插入一个自定义的持久化存储。

为了演示方便,创建了一个虚拟持久化存储实现,它实际上将数据存储在一个ConcurrentHashMap中,这个演示只是为了说明,如果需要创建一个自定义的持久化存储实现,Ignite基本上只需要实现三个方法:

 /** {@inheritDoc} */
public BinaryObject load(Long key) throws CacheLoaderException {
System.out.println(" >>> Getting Value From Cache Store: " + key);
return storeImpl.get(key);
}

/** {@inheritDoc} */
public void write(Cache.Entry entry) throws CacheWriterException {
System.out.println(" >>> Writing Value To Cache Store: " + entry);
storeImpl.put(entry.getKey(), entry.getValue());
}

/** {@inheritDoc} */
public void delete(Object key) throws CacheWriterException {
System.out.println(" >>> Removing Key From Cache Store: " + key);
storeImpl.remove(key);
}

下一步,在数据节点的配置中,通过在名为maintenance的缓存配置中添加一行代码,就可以开启这个自定义存储。

<property name="cacheStoreFactory">
  <bean class="javax.cache.configuration.FactoryBuilder" factory-method="factoryOf">
    <constructor-arg value="common.cachestore.SimpleCacheStore"/>
  </bean>
</property>

最后,要检查一下Ignite集群与持久化存储的通信,怎么做呢,在开发环境中打开GitHub工程然后启动一个数据节点的实例(DataNodeStartup文件),一个维护服务节点的实例(MaintenanceServiceNodeStartup文件)和一个车辆服务节点的实例(VehicleServiceNodeStartup文件)。所有节点互联之后,启动TestAppStartup,它会接入集群,注入数据然后调用服务。TestAppStartup执行完毕后,打开 DataNodeStartup的日志窗口,就可以看到类似下面这样的一个字符串:

 >>> Writing Value To Cache Store: Entry [key=1, val=services.maintenance.common.Maintenance [idHash=88832938, hash=1791054845, date=Tue Apr 18 14:55:52 PDT 2017, vehicleId=6]]

之所以显示这个字符串,是因为TestAppStartup触发了一个maintenance缓存的更新,它会自动地给前述虚拟持久化存储发送一个更新。

从外部应用接入

TestAppStartup是一个与部署在Ignite集群中的微服务进行交互的应用样例,某种意义上来说它是一个内部应用,因为它直接接入集群并且调用了服务网格的API。

但是对于外部应用来说,它不可能也不应该知道集群及其整体的部署,那么它怎么与微服务进行交互呢?一个简单的方案就是,Ignite服务以不同的方式监听来自外部应用的请求然后做出响应。

比如,当MaintenanceService的一个实例部署进集群后,它通过一个预定义的端口开启一个服务套接字来接收远程的连接(查看MaintenanceServiceImpl可以了解更多细节)。那么使用ExternalTestApp启动一个外部应用之后,它就会使用服务套接字与服务连接,然后获得每个车辆的维护调度,ExternalTestApp的输出大致如下:

>>> Getting maintenance schedule for vehicle:0
>>> Getting maintenance schedule for vehicle:1
>>> Getting maintenance schedule for vehicle:2
>>> Getting maintenance schedule for vehicle:3
>>> Getting maintenance schedule for vehicle:4
>>> Getting maintenance schedule for vehicle:5
>>> Getting maintenance schedule for vehicle:6
  >>> Maintenance{vehicleId=6, date=Tue Apr 18 14:55:52 PDT 2017}
>>> Getting maintenance schedule for vehicle:7
>>> Getting maintenance schedule for vehicle:8
>>> Getting maintenance schedule for vehicle:9
>>> Shutting down the application.

在这个系列中,展示了在Ignite集群中如何部署和维护一个基于微服务的解决方案。这个方案不需要关注微服务生命周期以及高可用性等事情,交给Ignite就行了,只需要关注实际业务逻辑即可。再者,所有的数据以及微服务都是在整个集群中分布的,这就意味着不用再担心性能和容错性-Ignite都已经解决了。

展开阅读全文
打赏
4
24 收藏
分享
加载中
李玉珏博主

引用来自“慕子曦”的评论

您好,李老师,我刚开始学习ignite没多长时间,遇到一点问题希望您能帮我解答。我使用cache.loadCache(null, CodeInfoKey.class, "select * from code_info");的时候。如果数据库某个(假设为name)字段值是NULL,这个是后load进去的数据类型就是Object类型的。当我再次使用put的时候,就会报错。字段类型不符合,一个是Object,另外一个是String类型。请问有什么方发可以是初始化load的数据类型与model一致。
私聊
2018/10/19 08:29
回复
举报
您好,李老师,我刚开始学习ignite没多长时间,遇到一点问题希望您能帮我解答。我使用cache.loadCache(null, CodeInfoKey.class, "select * from code_info");的时候。如果数据库某个(假设为name)字段值是NULL,这个是后load进去的数据类型就是Object类型的。当我再次使用put的时候,就会报错。字段类型不符合,一个是Object,另外一个是String类型。请问有什么方发可以是初始化load的数据类型与model一致。
2018/10/18 21:53
回复
举报
李玉珏博主

引用来自“jutleo”的评论

李老师,我想问一下,servicegrid客户端接入时,需要使用接口部分,nodefilter部分?
在一个正常的使用场景中,客户端提供给第三方使用,提供的API理论上只有ignite-core.jar 及 接口部分, 如何做到精简客户端接入呢?
目前测试中发现对等类的加载机制不完善,嵌入方式会存在一些问题,莫名其妙的报类找不到,但是可以正常运行,采用中间件启动需要整体打包放在ignite的libs目录下。
正常Ignite的服务调用是需要通过Ignite的代理进行访问,然后返回接口的实现,所以依赖ignite-core.jar包,但是是以客户端的形式运行的。
如果要解除这个依赖,或者要做瘦客户端,那么你需要在Ignite集群的服务端封装一个服务,做请求的转发,这种情况负载平衡你是需要考虑的。
2017/05/29 21:41
回复
举报
李老师,我想问一下,servicegrid客户端接入时,需要使用接口部分,nodefilter部分?
在一个正常的使用场景中,客户端提供给第三方使用,提供的API理论上只有ignite-core.jar 及 接口部分, 如何做到精简客户端接入呢?
目前测试中发现对等类的加载机制不完善,嵌入方式会存在一些问题,莫名其妙的报类找不到,但是可以正常运行,采用中间件启动需要整体打包放在ignite的libs目录下。
2017/05/29 17:36
回复
举报
更多评论
打赏
4 评论
24 收藏
4
分享
返回顶部
顶部