如何序列化 JBoss 流口水 KieBase 集合以进行外部存储?



这实际上可能与Drools本身无关,但可能只是一个Java原生解决方案。我只是一个彻头彻尾的Java菜鸟,继承了一个项目,所以我试图理解最佳实践。

我们有一个基于规则的多租户系统,客户可以在其中动态配置业务规则。我们将每个客户端的编译规则存储在如下所示的ConcurrentHashMap

ConcurrentMap<String, KieBase> rules = new ConcurrentHashMap<>();

其中string是表示每个唯一客户端的 UUID。然而,这样做的问题是水平扩展计算是一个问题,因为这只是一个内存中的哈希图,每次更改都会重新编译。如果我们将其横向扩展,则每个客户端都需要侦听新规则更改,并在每次发生时重新编译,这感觉像是一种浪费,因为它们总是会产生相同的结果。

我的最终目标是将这些计算规则存储在 JVM 之外,以便多个实例可以共享编译的规则,并且这些实例中的任何一个都可以安全地同时重新编译特定客户端的规则,而可能需要该客户端规则的所有其他实例将等待

所以我的想法是使用 Redis 作为 k/v 锁/存储,其中键是client_id,值是 Drools KieBase 对象的序列化版本。重新计算将使用事务(或一些类似的锁定算法)锁定该键上的 redis 存储,以便需要该client_id的 KieBase 的其他实例将等到编译完成并写回数据库。

所以我有几个问题:

  1. 这个 KieBase 对象的序列化是 Drools 特定的东西,还是 Java 中是否有针对任何对象的通用编组序列化机制(是否推荐这样做?
  2. 像Reddisson这样的东西会完全符合我的需求吗?如果是这样,有没有人有一个片段可以指出我正确的方向?我基本上需要为每个客户端锁定一个密钥,以便在计算一个实例时阻止多个实例,但我最好不想锁定整个数据库,只是锁定哈希映射中的一个条目。

一个简单的 ObjectOutputStream 足以序列化 KieBase 对象。下面是它用于写入文件,但您可以通过写入 ByteArrayOutputStream 并以任一形式获取结果来创建字符串或 byte[]。

KieBase kieBase = kieContainer.getKieBase();
FileOutputStream fos = new FileOutputStream( OUTPATH );
ObjectOutputStream oos = new ObjectOutputStream( fos );
oos.writeObject( kieBase );
oos.close();
FileInputStream fis = new FileInputStream( OUTPATH );
ObjectInputStream ois = new ObjectInputStream( fis );
KieBase kieBase1 = (KieBase)ois.readObject();
ois.close();

至于锁定,这取决于您是否需要针对并行运行的多个应用程序(在网络中)锁定外部表示,或者是否有单个(服务器)应用程序将所有内容保留在 HashMap 中。在后一种情况下,任何 Java 对象都有一个监视器:

synchronized( idString ) {
idString.wait();    // or overloaded form with timeout
}
// different thread 
synchronized( idString ){
idString.notify();
}

你可以参考Brian Goetz的书"Java Concurrency in Practice"。

编辑任何像样的数据库都有写锁定机制。此外,在您的情况下,您甚至可以使用简单的文件存储和文件锁定进行管理,这些存储和文件锁定可在MS Windows和所有Unice上使用。

最新更新