表格存储新手指南:Java SDK异步接口的使用

简介: 本篇文章主要会介绍下表格存储的Java SDK提供的异步接口,如何使用以及应用场景。

本篇文章主要会介绍下表格存储的Java SDK提供的异步接口,如何使用以及应用场景。


为什么需要异步?

异步提供了一个non-blocking, event-driven的编程模型,能够将系统不同层级的模块进行层次化的解耦,能够利用多核并行执行任务,提高性能。

现如今,一个大型的系统,系统级调优的最关键一步,就是异步化。异步化最常改造的是远程RPC或者数据库访问部分,表格存储作为一个底层数据库产品,需要提供异步接口来适应这个潮流。


在表格存储内部,我们也有一些使用异步来优化系统的例子,就拿Java SDK来说,可以看下以下两篇文章:

1. 使用NIO来优化Java SDK的性能

2. 基于Java SDK异步接口,提供高并发、高吞吐率的数据导入接口



如何使用?

异步接口的使用和同步接口没有太大区别,使用同样的请求参数,唯一的不同在于返回结果的处理上。同步接口会同步的返回调用结果,而异步接口会返回Future类型的结果,或者直接通过Callback来通知结果。

Future的使用

    private static void listTableWithFuture(OTSClientAsync client) {
        // 通过Future同步的等待结果返回。
        try {
            OTSFuture<ListTableResult> future = client.listTable();
            ListTableResult result = future.get(); // 同步的等待
            System.out.println("\nList table by listTableWithFuture:");
            for (String tableName : result.getTableNames()) {
                System.out.println(tableName);
            }
        } catch (OTSException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        }

        // 通过Future,间歇性的等待结果返回。
        try {
            OTSFuture<ListTableResult> future = client.listTable();

            while (!future.isDone()) {
                System.out.println("Waiting for result of list table.");
                Thread.sleep(10); // 每隔10ms检查结果是否返回
            }

            ListTableResult result = future.get();
            System.out.println("\nList table by listTableWithFuture:");
            for (String tableName : result.getTableNames()) {
                System.out.println(tableName);
            }
        } catch (OTSException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

Callback的使用

    private static void listTableWithCallback(OTSClientAsync asyncClient) {
        final AtomicBoolean isDone = new AtomicBoolean(false);
        OTSCallback<ListTableRequest, ListTableResult> callback = new OTSCallback<ListTableRequest, ListTableResult>() {
            @Override
            public void onCompleted(OTSContext<ListTableRequest, ListTableResult> otsContext) {
                isDone.set(true);
                System.out.println("\nList table by listTableWithCallback:");
                for (String tableName : otsContext.getOTSResult().getTableNames()) {
                    System.out.println(tableName);
                }
            }

            @Override
            public void onFailed(OTSContext<ListTableRequest, ListTableResult> otsContext, OTSException ex) {
                isDone.set(true);
                ex.printStackTrace();
            }

            @Override
            public void onFailed(OTSContext<ListTableRequest, ListTableResult> otsContext, ClientException ex) {
                isDone.set(true);
                ex.printStackTrace();
            }
        };

        asyncClient.listTable(callback); // 将callback扔给SDK,SDK在完成请求接到响应后,会自动调用callback

        // 等待callback被调用,一般的业务处理逻辑下,不需要这一步等待。
        while (!isDone.get()) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

案例一:如何突破BatchWriteRow的行数限制,一次性导入N行数据

    private static void batchWriteRow(OTSClientAsync asyncClient, String tableName) {
        // BatchWriteRow的行数限制是100行,使用异步接口,实现一次批量导入1000行。
        List<OTSFuture<BatchWriteRowResult>> futures = new ArrayList<OTSFuture<BatchWriteRowResult>>();
        int count = 10;
        // 一次性发出10个请求,每个请求写100行数据
        for (int i = 0; i < count; i++) {
            BatchWriteRowRequest request = new BatchWriteRowRequest();
            for (int j = 0; j < 100; j++) {
                RowPutChange rowChange = new RowPutChange(tableName);
                RowPrimaryKey primaryKey = new RowPrimaryKey();
                primaryKey.addPrimaryKeyColumn(COLUMN_GID_NAME, PrimaryKeyValue.fromLong(i * 100 + j));
                primaryKey.addPrimaryKeyColumn(COLUMN_UID_NAME, PrimaryKeyValue.fromLong(j));
                rowChange.setPrimaryKey(primaryKey);
                rowChange.addAttributeColumn(COLUMN_NAME_NAME, ColumnValue.fromString("name" + j));
                rowChange.addAttributeColumn(COLUMN_AGE_NAME, ColumnValue.fromLong(j));

                request.addRowChange(rowChange);
            }
            OTSFuture<BatchWriteRowResult> result = asyncClient.batchWriteRow(request);
            futures.add(result);
        }

        // 等待结果返回
        List<BatchWriteRowResult> results = new ArrayList<BatchWriteRowResult>();
        for (OTSFuture<BatchWriteRowResult> future : futures) {
            try {
                BatchWriteRowResult result = future.get(); // 同步等待结果返回
                results.add(result);
            } catch (OTSException e) {
                e.printStackTrace();
            } catch (ClientException e) {
                e.printStackTrace();
            }
        }

        // 统计返回结果
        int totalSucceedRows = 0;
        int totalFailedRows = 0;
        for (BatchWriteRowResult result : results) {
            totalSucceedRows += result.getSucceedRowsOfPut().size();
            totalFailedRows += result.getFailedRowsOfPut().size();
        }

        System.out.println("Total succeed rows: " + totalSucceedRows);
        System.out.println("Total failed rows: " + totalFailedRows);
    }


案例二:如何实现batch getRange

    private static void batchGetRange(OTSClientAsync asyncClient, String tableName) {
        // 一次性查询多个范围的数据,设置10个任务,每个任务查询100条数据。
        // 每个范围查询的时候设置limit为10,100条数据需要10次请求才能全部查完。
        int count = 10;
        OTSFuture<GetRangeResult>[] futures = new OTSFuture[count];
        for (int i = 0; i < count; i++) {
            futures[i] = sendGetRangeRequest(asyncClient, tableName, i * 100, i * 100 + 100);
        }

        // 检查是否所有范围查询均已做完,若未做完,则继续发送查询请求
        List<Row> allRows = new ArrayList<Row>();
        while (true) {
            boolean completed = true;
            for (int i = 0; i < futures.length; i++) {
                OTSFuture<GetRangeResult> future = futures[i];
                if (future == null) {
                    continue;
                }

                if (future.isDone()) {
                    GetRangeResult result = future.get();
                    allRows.addAll(result.getRows());

                    if (result.getNextStartPrimaryKey() != null) {
                        // 该范围还未查询完毕,需要从nextStart开始继续往下读。
                        long nextStart = result.getNextStartPrimaryKey().getPrimaryKey().get(COLUMN_GID_NAME).asLong();
                        long rangeEnd = i * 100 + 100;
                        futures[i] = sendGetRangeRequest(asyncClient, tableName, nextStart, rangeEnd);
                        completed = false;
                    } else {
                        futures[i] = null; // 若某个范围查询完毕,则将对应future设置为null
                    }
                } else {
                    completed = false;
                }
            }

            if (completed) {
                break;
            } else {
                try {
                    Thread.sleep(10); // 避免busy wait,每次循环完毕后等待一小段时间
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        // 所有数据全部读出
        System.out.println("Total rows scanned: " + allRows.size());
    }

示例代码可从这里下载。

相关实践学习
阿里云表格存储使用教程
表格存储(Table Store)是构建在阿里云飞天分布式系统之上的分布式NoSQL数据存储服务,根据99.99%的高可用以及11个9的数据可靠性的标准设计。表格存储通过数据分片和负载均衡技术,实现数据规模与访问并发上的无缝扩展,提供海量结构化数据的存储和实时访问。 产品详情:https://www.aliyun.com/product/ots
目录
相关文章
|
10月前
|
Java API 开发工具
百宝箱开放平台 ✖️ Java SDK
百宝箱提供Java SDK,支持开发者集成其开放能力。需先发布应用,准备Java 8+及Maven环境,通过添加依赖安装SDK,并初始化客户端调用对话型或生成型智能体,实现会话管理、消息查询与文件上传等功能。
1857 0
百宝箱开放平台 ✖️ Java SDK
|
Java
探索Java新境界!异步+事件驱动,打造响应式编程热潮,未来已来!
【8月更文挑战第30天】在现代软件开发中,系统响应性和可扩展性至关重要。Java作为主流编程语言,提供了多种机制如Future、CompletableFuture及事件驱动编程,有效提升应用性能。本文探讨Java异步编程模型与事件驱动编程,并介绍响应式模式,助您构建高效、灵活的应用程序。
294 4
|
Java Apache 开发工具
【Azure 事件中心】 org.slf4j.Logger 收集 Event Hub SDK(Java) 输出日志并以文件形式保存
【Azure 事件中心】 org.slf4j.Logger 收集 Event Hub SDK(Java) 输出日志并以文件形式保存
376 1
|
存储 Java API
MinIO Java SDK 7.1.4 升级到 8.5.17 需要注意什么
现在我需要你帮我分析对比这个两个sdk在对外的接口设计上是否有不兼容的变更
1405 5
|
存储 Java API
【Azure 存储服务】Java Storage SDK 调用 uploadWithResponse 代码示例(询问ChatGTP得代码原型后人力验证)
【Azure 存储服务】Java Storage SDK 调用 uploadWithResponse 代码示例(询问ChatGTP得代码原型后人力验证)
282 0
|
监控 Java
java异步判断线程池所有任务是否执行完
通过上述步骤,您可以在Java中实现异步判断线程池所有任务是否执行完毕。这种方法使用了 `CompletionService`来监控任务的完成情况,并通过一个独立线程异步检查所有任务的执行状态。这种设计不仅简洁高效,还能确保在大量任务处理时程序的稳定性和可维护性。希望本文能为您的开发工作提供实用的指导和帮助。
581 17
|
JSON 前端开发 API
使用微信JS-SDK调用发票接口的完整开发指南
本文介绍了如何使用微信JS-SDK的`chooseInvoiceTitle`接口来调用微信的发票功能。通过微信发票接口,用户可以选择开具个人或单位发票,并获取相关发票信息,如抬头、税号、公司地址等。在文中,详细描述了JS-SDK的初始化、发票接口的调用方式,并提供了完整的代码示例。文章还介绍了如何处理返回的发票信息,帮助开发者快速集成微信发票功能。
1028 2
JAVA并发编程系列(13)Future、FutureTask异步小王子
本文详细解析了Future及其相关类FutureTask的工作原理与应用场景。首先介绍了Future的基本概念和接口方法,强调其异步计算特性。接着通过FutureTask实现了一个模拟外卖订单处理的示例,展示了如何并发查询外卖信息并汇总结果。最后深入分析了FutureTask的源码,包括其内部状态转换机制及关键方法的实现原理。通过本文,读者可以全面理解Future在并发编程中的作用及其实现细节。
|
JavaScript Java 中间件
Java CompletableFuture 异步超时实现探索
本文探讨了在JDK 8中`CompletableFuture`缺乏超时中断任务能力的问题,提出了一种异步超时实现方案,通过自定义工具类模拟JDK 9中`orTimeout`方法的功能,解决了任务超时无法精确控制的问题,适用于多线程并行执行优化场景。
588 0
|
Java 开发工具
通过Java SDK调用阿里云模型服务
在阿里云平台上,可以通过创建应用并使用模型服务完成特定任务,如生成文章内容。本示例展示了一段简化的Java代码,演示了如何调用阿里云模型服务生成关于“春秋战国经济与文化”的简短文章。示例代码通过设置系统角色为历史学家,并提出文章生成需求,最终处理并输出生成的文章内容。在实际部署前,请确保正确配置环境变量中的密钥和ID,并根据需要调整SDK导入语句及类名。更多详情和示例,请参考相关链接。