Aerospike进阶

107 阅读9分钟

前提:Aerospike必须要在5.0版本以后,有些操作甚至只在6.0有

1.查询所有的namespace|set|key

(1) 查询Aerospike集群下的所有的namespace

public class Test {
    public static void main(String[] args) {
        // 创建 ClientPolicy 对象
        ClientPolicy policy = new ClientPolicy();

        // 设置主机地址和端口号
        String host = "10.204.196.243";
        int port = 3000;

        // 创建 Aerospike 客户端
        AerospikeClient client = new AerospikeClient(policy, host, port);

        try {
            // 获取所有节点的信息
            InfoPolicy infoPolicy = new InfoPolicy();
            Node[] nodes = client.getNodes();//获取集群的节点信息
            for (Node node : nodes) {
                String response = Info.request(infoPolicy, node, "namespaces");
                if (response != null && !response.isEmpty()) {
                    System.out.println("Node: " + node);
                    System.out.println("Namespaces: " + response);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭客户端
            client.close();
        }
    }
}

(2) 查询当前namespace对应的set表下的所有key

image.png

需要补充参数:ScanPolicy策略、namespace、setName、ScanCallback回调函数、bin可变形参

        ClientPolicy clientPolicy = new ClientPolicy();
        AerospikeClient client = new AerospikeClient(clientPolicy,"10.204.196.243",3000);
        ScanPolicy scanPolicy = new ScanPolicy();
        client.scanAll(scanPolicy, "mediav", "test_batch", new ScanCallback() {
            @Override
            public void scanCallback(Key key, Record record) throws AerospikeException {
                System.out.println("key:"+key);
                System.out.println("Record:"+record);
            }
        });

补充-1 ScanCallback函数

将每次scan扫完的record都调用这个方法;scan如果中断了会报以下异常

com.aerospike.client.AerospikeException.ScanTerminated AerospikeException.ScanTerminated

如果引发任何异常,则到其他节点的并行扫描线程也将被终止,并且异常将通过启动的扫描调用传播回去。

如果ScanPolicy.concurrentNodes设置为true且ScanPolicy.maxConcurrentNodes设置不为1,那么你的scanCallback函数必须是线程安全的

3.异步操作API—底层解决了线程不安全问题,需要服务器的as版本>4.9

小案例

public class Test2 {
    public static void main(String[] args) throws InterruptedException {
        //不能直接使用同步的client,初始化一个异步的client
//创建EventLoops
        EventPolicy eventPolicy = new EventPolicy();
        EventLoops eventLoops = new NioEventLoops(eventPolicy,4);

//初始化异步as客户端需要指定EventLoops
        ClientPolicy clientPolicy = new ClientPolicy();
        clientPolicy.eventLoops=eventLoops;

        AerospikeClient aerospikeClient = new AerospikeClient(clientPolicy,"10.204.196.243",3000);
        WritePolicy wp = new WritePolicy();
        wp.generationPolicy= GenerationPolicy.EXPECT_GEN_GT;
//开始准备异步写入
        EventLoop eventLoop = eventLoops.next();

        WriteListener writeListener = new WriteListener() {
            @Override
            public void onSuccess(Key key) {
                System.out.println("写入成功");
                System.out.println(key.toString());
                System.out.println(aerospikeClient.get(null,key));
            }

            @Override
            public void onFailure(AerospikeException exception) {
                System.out.println("写入异常");
                System.out.println(exception.toString());
            }
        };
        Key key = new Key("mediav","test_async",1);
        aerospikeClient.delete(null,key);
        String[] arr=new String[20];
        for (int i = 0; i < arr.length; i++) {
            arr[i]="test-"+i;
        }
        for(int i=0;i<20;i++){
            Bin bin1 = new Bin("name",arr[i]);
            Bin bin2 = new Bin("age",18+i);
            aerospikeClient.put(eventLoop, writeListener,null,key,bin1,bin2);
            Record record = aerospikeClient.get(null, key);
            System.out.println(i+1+"record:"+record);
        }

        TimeUnit.SECONDS.sleep(5);
        System.out.println("最终的record:"+aerospikeClient.get(null,key));
		//关闭顺序不能变
        aerospikeClient.close();
        eventLoops.close();

    }
}

(1) EventPolicy和EventLoops底层解析

<1> EventPolicy

EventPolicy是异步策略,用于控制异步事件处理方式的配置类,它定义了如何处理异步操作的回调和事件调度。

EventPolicy ep = new EventPolicy();
ep.maxCommandsInProcess=10;//用于限制事件循环中最大允许的并发命令数量。默认是0,表示立即执行所有异步操作。
ep.maxCommandsInQueue=8;//每个事件循环的延迟队列中可存储的最大异步命令数量(就是等待线程的最大数量)。默认是0,表示无限制。
ep.queueInitialCapacity=256;//初始化延迟队列的容量。默认是256。
ep.minTimeout=100;//最小超时时间。默认是100ms。

<2> EventLoops

EventLoops 是一组线程,专门用于处理网络 I/O 事件。每个 EventLoop 线程负责监听和处理网络连接上的读写事件。API通过ClientPolicy可以配置 EventLoops的数量以及每个EventLoop中的线程数量,可以确保异步操作的高效处理。

每个 EventLoops 实例都可以在多个 AerospikeClient 实例之间共享。EventLoops 实例的事件循环数应近似于计算机上为 AerospikeClient 处理保留的 CPU 内核数。支持 Netty 和直接 NIO 事件循环。

//NIO声明

EventPolicy eventPolicy = new EventPolicy();//创建事件循环策略
EventLoops eventLoops = new NioEventLoops(eventPolicy, 4);//使用eventPolicy策略并设置NIO循环数为4
底层调用如下

参数解析
	  @param policy		事件循环策略
	  @param size		NIO事件循环数
	  @param daemon		如果相关线程应作为守护进程运行,则参数 daemon 为 true
	  @param poolName	事件循环线程池名称


//Netty声明

EventPolicy eventPolicy = new EventPolicy();
EventLoopGroup group = new NioEventLoopGroup(4);//指定事件循环的类型是NIO类型,并设置实例的线程数
EventLoops eventLoops = new NettyEventLoops(eventPolicy, group);

<3> 异步写入操作

image.png

需要传的参数是EventLoop、WriteListener监听者、写入策略、Key、Bin可变形参

public static void main(String[] args) throws InterruptedException {
        //不能直接使用同步的client,初始化一个异步的client
//创建EventLoops
        EventPolicy eventPolicy = new EventPolicy();
        EventLoops eventLoops = new NioEventLoops(eventPolicy,4);
//初始化异步as客户端需要指定EventLoops
        ClientPolicy clientPolicy = new ClientPolicy();
        clientPolicy.eventLoops=eventLoops;

        AerospikeClient aerospikeClient = new AerospikeClient(clientPolicy,"10.204.196.243",3000);
        WritePolicy wp = new WritePolicy();
        wp.generationPolicy= GenerationPolicy.EXPECT_GEN_GT;
		//开始准备异步写入,eventLoops.next()是以轮询方式返回下一个eventloop对象
        EventLoop eventLoop = eventLoops.next();
		//声明写操作监听者(是一个匿名内部类,需要重写两个方法,分别是写入成功和写入失败的情况)
        WriteListener writeListener = new WriteListener() {
            @Override
            public void onSuccess(Key key) {
                System.out.println("写入成功");
                System.out.println(key.toString());
                System.out.println(aerospikeClient.get(null,key));
            }

            @Override
            public void onFailure(AerospikeException exception) {
                System.out.println("写入异常");
                System.out.println(exception.toString());
            }
        };
    	Key key = new Key("ns1","test_async");
		Bin bin = new Bin("test","test_async");
		aerospikeClient.put(eventLoop, writeListener,null,key,bin);
 
		TimeUnit.SECONDS.sleep(5);
 
		client.close();
		eventLoops.close();
    }
}

3.批量操作—Maven的as版本要6.0.0以上并且服务器上的asClient版本要在6.0.0以上

(1) operate操作以及Operation类—put/get的底层

<1> client.operate()操作

image.png

(1)多个Operation的执行顺序

在单条记录上的操作将按照在 operate() 调用中指定的顺序应用。Aerospike 保证这些操作是原子性的,即所有操作要么全部成功,要么全部失败,且在第一个操作和最后一个操作之间不会有其他线程影响该记录。

操作顺序有时很重要。例如,假设希望 Aerospike 在插入新商品前返回购物车中商品的总价,并在插入商品后再次返回总价。可以修改程序如下:

Record record = client.operate(null, key, 
        Operation.get("cost"),
        Operation.append(new Bin("items", itemDescr + ",")),
        Operation.add(new Bin("totalItems", 1)),
        Operation.add(new Bin("cost", cost)),
        Operation.get("cost")
    );
//下面是代码解析
在此示例中,首先获取 cost bin 的值,更新后再次获取。这样做在 Aerospike 中是有效的,但返回的结果会是什么呢?幸运的是,Record 对象有一个有用的 toString() 方法,因此可以在返回 Record 后立即添加以下代码来查看返回值:
System.out.println(record);
结果如下:
(gen:1),(exp:0),(bins:(cost:59.25))
(gen:2),(exp:0),(bins:(cost:[59.25, 89.2]))
(gen:3),(exp:0),(bins:(cost:[89.2, 109.15]))

<2> Operation类

方法描述
add(Bin)将 bin 增加传入的 Bin 值。如果 bin 不存在,将用传入的值创建该 bin。如果传入的值或数据库中现有的值非数值类型,将抛出 AerospikeException,并返回 ResultCode.BIN_TYPE_ERROR 代码。
append(Bin)将传入的字符串值添加到 bin 字符串的末尾。如果 bin 不存在,将用传入的值创建 bin。如果传入的值或数据库中现有的值非字符串类型,将抛出 AerospikeException,返回 ResultCode.BIN_TYPE_ERROR
get()返回记录中所有 bin 的内容。
get(String)返回指定 bin 的内容。如果该 bin 不存在,则不返回任何内容。
put(Bin)将 bin 的内容设置为传入的值。

image.png

声明Operation=对象,需要传Type、binName、Value
Operation.Type:是个枚举,有WRITE、ADD等
binName:对那个bin进行操作
Value:操作的类型内容是什么
//案例如下
        Operation operation1 = new Operation(Operation.Type.APPEND,"name",new Value.StringValue("_test"));//在name字段后拼接_test
        Operation operation2 = new Operation(Operation.Type.WRITE,"age",new Value.IntegerValue(1));//插入一个age字段值为1
        Operation operation3 = new Operation(Operation.Type.ADD,"age",new Value.IntegerValue(7));//将age字段的值+7

<3> ListOperation和MapOperation

(1)ListOperation

先来理解列表

现有一列表:[1, 4, 7, 3, 9, 26, 11],把他插入到set中

列表147392611
索引0或-71或-62或-53或-44或-35或-26或-1
排名0或-72或-53或-41或-64或-36或-15或-2

注意:

ListOperation是支持负索引的,index-1表示倒数第一位

下面表格是简单的CRUD操作;

方法描述
ListOperation.size(String binName)返回list的大小
ListOperation.get(String binName,int index)获取指定索引位置的元素
ListOperation.getByIndex(String binName,int index,int returnType)返回指定索引元素的returnType数据
ListOperation.getByRank(String binName,int rank,int returnType)返回按照元素大小排序后排行第rank个元素的returnType数据
ListOperation.insert(String binName,int index,Value value)在对应bin的指定位置插入元素,并返回长度
ListOperation.set(String binName,int index,Value value)将对应bin下的指定索引的元素设置为指定值
ListOperation.append(String binName,Value value)对指定的List类型bin末尾追加一个元素,并返回长度
ListOperation.appendItems(String binName,List list)对指定的List类型bin末尾追加多个元素,并返回长度
ListOperation.remove(String binName,int index)删除指定索引位置的元素,并返回删除的个数
ListOperation.pop(String binName,int index)将指定位置的元素出列,在bin中删除该元素并返回该元素
ListOperation.trim(String binName,int index,int count)保留指定索引之后count个元素,其余全部删除,返回删除的个数
ListOperation.clear(String binName)清空对应bin,默认不返回结果
ListOperation.setOrder(String binName,ListOrder order)对指定的list类型bin进行排序,返回null。order可选参数:ListOrder.ORDERED(排序)、ListOrder.UNORDERED(未排序,默认)
ListOperation.sort(String binName,int sortFlags)对指定的list类型bin进行排序,默认不返回结果。sortFlags可选参数:ListSortFlags.DEFAULT(保留重复值)、ListSortFlags.DROP_DUPLICATES(去除重复值)
(2)MapOperation

比如:{a:1, b:2, c:30, y:30, z:26}

abcyz
12303026
索引0 或 -51 或 -42 或 -33 或 -24 或 -1
排名0 或 -51 或 -43 或 -24 或 -12 或 -3

下面表格是简单的CRUD操作

方法描述
MapOperation.size(String binName)返回map的大小
MapOperation.getByKey(String binName,Value key,int returnType)根据key返回元素的returnType数据
MapOperation.getByValue(String binName,Value value,int returnType)根据value返回元素的returnType数据
MapOperation.getByIndex(String binName,int index,int returnType)根据索引位置返回对应元素的returnType数据
MapOperation.getByRank(String binName,int rank,int returnType)返回排序后第rank位置元素的returnType数据
MapOperation.put(MapPolicy policy,String binName,Value key,Value value)在map中放入新键值对,并且返回map的大小,policy不可为null
MapOperation.putItems(MapPolicy policy,String binName,Map<Value,Value> map)批量放入键值对,并且返回map的大小,policy不可为null
MapOperation.clear(String binName)清空map
MapOperation.removeByKey(String binName,Value key,int returnType)删除指定key的元素,并根据returnType返回被删除元素
MapOperation.removeByValue(String binName,Value value,int returnType)删除指定值的元素,并根据returnType返回被删除元素
MapOperation.removeByIndex(String binName,int index,int returnType)删除指定索引位置的元素,并根据returnType返回删除元素
MapOperation.removeByRank(String binName,int rank,int returnType)删除排序后第rank位置元素的returnType数据