[JAVA] Apache Geode-Easy way to execute logic on the server side

Introduction

In Apache Geode, which is one of the distributed system type KVS implementations, it is common to use a function called Function Execution when you want to execute some logic on the server side. However, since Functoin Execution is highly functional, the amount of coding other than setting items and actual logic tends to be large, and specific logic is executed only once on one of the cache server nodes regardless of the data arrangement in the cluster and returned. It may be a little daunting to use it in simple cases where you don't even ask for a value.

In this article, I will show you how to execute logic on the server side more easily with Apache Geode without using the Function Execution function. Hereinafter, the entity that executes arbitrary logic will be referred to as a "command". The method in this article has been confirmed to work with Apache Geode 1.6.0.

Purpose

In this article, as a simple server-side logic execution example, the following contents will be set and implemented without using the Function Execution function.

--Execute the command to delete all data in the specified region (that is, execute Regoin # clear) only once on any cache server node in the cluster, no return value

How it works

The logic is executed on the server side without using the Function Execution function by the following mechanism.

  1. Prepare a dedicated region to execute logic (hereinafter, Command region) --A proxy region is fine because it does not store data ( refid = REPLICATED_PROXY)
  2. In the Command region, the command object is the value and the put --key is not used, so any value
  3. Execute the command passed as a value with CacheWriter that was previously assigned to the Command region on the server side.

Here, the reason for using CacheWriter instead of the commonly used CacheListner is that the former basically allows all the assigned cache servers to react and the command to be executed twice. This is because the latter runs on one of the granted cache servers, whereas it is sexual.

For reference, the execution image diagram is posted below. 20180926-executionImage.png

Creating a command

As a policy, assuming that a class is prepared individually for each command, the following command interface is defined in order to standardize the logic for executing commands with CacheWriter.

Command.java


public interface Command {
  public void process();
}

Next, in the form of implementing this, write the data deletion command class of the specified region as follows. Execute Region # clear with the process method defined in the command interface based on the region ( regionName) specified when instantiating this command class.

ClearRegionCommand.java


import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.Region;

import java.io.Serializable;

public class ClearRegionCommand implements Command, Serializable {
  private String regionName;
  
  public ClearRegionCommand(String regionName) {
    this.regionName = regionName;
  }
  
  public void process() {
    Region region = CacheFactory.getAnyInstance().getRegion(this.regionName);
    if (region != null) {
      region.clear();
    }
  }
}

Note that the command object itself is sent to the server over the network, so it must be implemented as a serializable object. Here, java.io.Serializable has been implemented, but since it is Apache Geode, PDX can be used as the object serialization technology.

And then there is the implementation of CacheWriter that executes the command. In the beforeCreate method, get the command object from the event generated by put and execute the process method. By the way, CacheWriter is often defined in the cache configuration file (hereinafter, cache.xml), and Declarable is implemented just in case.

ProcessCommandCacheWriter.java


import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheWriterException;
import org.apache.geode.cache.Declarable;
import org.apache.geode.cache.EntryEvent;
import org.apache.geode.cache.util.CacheWriterAdapter;

import java.util.Properties;

public class ProcessCommandCacheWriter extends CacheWriterAdapter<Integer,Command> implements Declarable {
  public void beforeCreate(EntryEvent<Integer,Command> event) throws CacheWriterException {
    Command command = event.getNewValue();
    command.process();
  }

  public void initialize(Cache cache, Properties properties) { }

  public void close() {}
}

CacheWriter settings

Here, it is set using cache.xml. It will be assigned to the Command region where REPLICATE_PROXY is set in refid. The Example region will be the sample region to be executed by the command implemented this time, Regoin # clear.

cache.xml


<?xml version="1.0" encoding="UTF-8"?>
<cache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://geode.apache.org/schema/cache"
       xsi:schemaLocation="http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd"
       version="1.0" lock-lease="120" lock-timeout="60" search-timeout="300" is-server="false" copy-on-read="false">

    <cache-server port="0" />

    <region name="Example" refid="REPLICATE" />

    <region name="Command" refid="REPLICATE_PROXY">
        <region-attributes>
            <cache-writer>
                <class-name>ProcessCommandCacheWriter</class-name>
            </cache-writer>
        </region-attributes>
    </region>
</cache>

CLASSPATH setting

Commands submitted by the client are executed on the server, so you need to set the server's CLASSPATH to the paths to various related classes. The command class body (here, ClearRegionCommand) can be dynamically set with the gfsh deploy command if necessary, but at least the path to the following classes must be set when starting the server. There is.

-- CacheWriter class (here, ProcessCommandCacheWriter class) --Command interface (here, Command interface)

The interface doesn't seem to be able to set the CLASSPATH with the gfsh deploy command

Command input from client

Create a command object and code it in the Command region as put as a value, as shown below.

ClientCache cache = new ClientCacheFactory()
  .set("cache-xml-file", "client-cache.xml")
  .create();
cache.getRegion("Command").put(0, new ClearRegionCommand("Example"));

For reference, the following is a sample cache.xml on the client side.

client-cache.xml


<?xml version="1.0" encoding="UTF-8"?>
<client-cache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://geode.apache.org/schema/cache"
       xsi:schemaLocation="http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd"
       version="1.0" copy-on-read="false">

    <pool name="MyPool" subscription-enabled="true">
        <locator host="xxx.xxx.xxx.xxx" port="xxxxx" />
    </pool>

    <region name="Example">
        <region-attributes pool-name="MyPool" refid="CACHING_PROXY" />
    </region>

    <region name="Command">
        <region-attributes pool-name="MyPool" refid="PROXY" />
    </region>
</client-cache>

Finally

Summarizing it as an article, I feel that there are more codes and settings than I expected in the case of Function Executoin, but I think that it is easy for users to input commands from the client in one line. I am.

Furthermore, with the method introduced this time, by adding the Gateway Sender setting to the Command region, it is possible to perform the feat of executing arbitrary logic even in another cluster with the Gateway Receiver set via the WAN. If you are interested and in demand, give it a try.

Recommended Posts

Apache Geode-Easy way to execute logic on the server side
[Java] How to retrieve the parameters passed from html on the server side
Migration from Eclipse to IntelliJ (on the way)
Ssh login to the app server on heroku
The key to running Docker on Raspberry Pi 4 (Ubuntu server 20.04)
Sample to create one-time password on server side and client side
How to disable Set-Cookie from API on the front side
How to run React and Rails on the same server
How to display 0 on the left side of the standard input value
Logic to draw a circle with ASCII art on the console
How to place and share SwiftLint config files on the server
Programming with ruby (on the way)
Verify the ID token obtained from Firebase on the server side (Java + SpringBoot)
Get the event that the iOS application moves to the back on the View side
How to use Apache Derby on Eclipse
Kick ShellScript on the server from Java
How to change the timezone on Ubuntu
Execute Java code stored on the clipboard.
Pre-processing to display on the browser (compiler)
What to do if the rails server doesn't run out on AWS cloud9
How to share on the host side (windows) and guest side (CentOS 7) with VirtualBox