写点什么

Dapr 在 Java 中的实践 之 状态管理

作者:万猫学社
  • 2022 年 8 月 08 日
  • 本文字数:3132 字

    阅读完需:约 10 分钟

Dapr在Java中的实践 之 状态管理

状态管理

状态管理(State Management)使用键值对作为存储机制,可以轻松的使长时运行、高可用的有状态服务和无状态服务共同运行在我们的服务中。


我们的服务可以利用 Dapr 的状态管理 API 在状态存储组件中保存、读取和查询键值对。


状态存储组件是可插拔的,目前支持使用 Azure CosmosDB、 Azure SQL Server、 PostgreSQL,、AWS DynamoDB、Redis 作为状态存储介质。

编写示例代码

创建一个 SpringBoot 项目,命名为:state-management,该项目的状态管理调用过程如下图:



state-management该项目的pom.xml文件中添加如下依赖:


<dependency>    <groupId>io.dapr</groupId>    <artifactId>dapr-sdk-springboot</artifactId>    <version>1.4.0</version></dependency><dependency>    <groupId>com.squareup.okhttp3</groupId>    <artifactId>okhttp</artifactId>    <version>4.9.3</version></dependency>
复制代码


注入一个DaprClient的 bean:


@Configurationpublic class DaprConfig {
private static final DaprClientBuilder BUILDER = new DaprClientBuilder();
@Bean public DaprClient buildDaprClient() { return BUILDER.build(); }}
复制代码


state-management项目中一共有 3 个接口:


  • save:保存状态

  • get:读取状态

  • delete:删除状态


具体源码如下:


package one.more.society.state.management;
import io.dapr.client.DaprClient;import io.dapr.client.domain.State;import lombok.extern.slf4j.Slf4j;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RestController;
@Slf4j@RestControllerpublic class StateManagementController {
@Autowired private DaprClient client;
private static final String STATE_STORE_NAME = "statestore"; private static final String STATE_STORE_KEY = "one.more.society";
/** * 保存状态 * * @param value value * @return */ @RequestMapping(value = "/save", method = RequestMethod.GET) public StateResponse save(String value) { log.info("save - value:{}", value); client.saveState(STATE_STORE_NAME, STATE_STORE_KEY, value).block();
StateResponse response = new StateResponse(); response.setCode(1); response.setStatus("save"); response.setValue(value); return response; }
/** * 读取状态 * * @return StateResponse */ @RequestMapping(value = "/get", method = RequestMethod.GET) public StateResponse get() { log.info("get"); State<String> value = client.getState(STATE_STORE_NAME, STATE_STORE_KEY, String.class).block(); log.info("value: {}", value.getValue());
StateResponse response = new StateResponse(); response.setCode(1); response.setStatus("get"); response.setValue(value.getValue()); return response; }
/** * 删除状态 * * @return */ @RequestMapping(value = "/delete", method = RequestMethod.GET) public StateResponse delete() { log.info("delete"); client.deleteState(STATE_STORE_NAME, STATE_STORE_KEY).block();
StateResponse response = new StateResponse(); response.setCode(1); response.setStatus("delete"); return response; }}
复制代码


另外,在application.properties中配置:


server.port=30003
复制代码

启动服务

在启动之前先用mvn命令打包:


mvn clean package
复制代码


state-management项目的目录中执行以下命令,启动state-management服务:


dapr run --app-id state-management --app-port 30003 --dapr-http-port 31003 -- java -jar target/state-management-0.0.1-SNAPSHOT.jar
复制代码


在 Dapr Dashboard 中看到:



服务都已经启动成功。


先访问http://localhost:30003/get,可以看到:



读取状态返回为 null,接下来访问http://localhost:30003/save?value=万猫学社,可以看到:



状态已经保存了,再访问http://localhost:30003/get验证一下:



状态被正确读取,再访问http://localhost:30003/delete,可以看到:



状态已经被删除了,再访问http://localhost:30003/get验证一下:



读取状态返回为 null。

状态储存组件

初始化 Dapr 后,默认为我们指定的状态储存组件是 Redis,在用户目录下的.dapr文件夹中的components文件夹中,可以找到statestore.yaml文件:


apiVersion: dapr.io/v1alpha1kind: Componentmetadata:  name: statestorespec:  type: state.redis  version: v1  metadata:  - name: redisHost    value: localhost:6379  - name: redisPassword    value: ""  - name: actorStateStore    value: "true"
复制代码


下面让我们来尝试一下,使用 MySQL 作为状态储存组件,把statestore.yaml文件修改为:


apiVersion: dapr.io/v1alpha1kind: Componentmetadata:  name: statestorespec:  type: state.mysql  version: v1  metadata:  - name: connectionString    value: "root:one.more.society@tcp(127.0.0.1:3306)/?allowNativePasswords=true"
复制代码


重新启动服务,可以看到在日志中看到使用 MySQL 作为状态储存组件:


time="09:57:35.5632633+08:00" level=info msg="Creating MySql schema 'dapr_state_store'" app_id=state-management instance=JT-243137 scope=dapr.contrib type=log ver=1.7.3time="09:57:35.5862126+08:00" level=info msg="Creating MySql state table 'state'" app_id=state-management instance=JT-243137 scope=dapr.contrib type=log ver=1.7.3time="09:57:35.6563599+08:00" level=info msg="component loaded. name: statestore, type: state.mysql/v1" app_id=state-management instance=JT-243137 scope=dapr.runtime type=log ver=1.7.3
复制代码


如果在 MySQL 中没有对应的库和表,Dapr 默认为我们自动创建一个名为dapr_state_store的库,还有一个名为state的表,如下图:



其中,state的表结构为:


CREATE TABLE `state` (  `id` varchar(255) NOT NULL,  `value` json NOT NULL,  `isbinary` tinyint(1) NOT NULL,  `insertDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,  `updateDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,  `eTag` varchar(36) NOT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
复制代码


再访问一下http://localhost:30003/save?value=万猫学社,就可以在数据库中看到对应的数据:



值得注意的是:MySQL 状态储存组件目前还处于 Alpha 状态,最好不要在生产环境使用。


更详细的配置说明见下表:



配置示例:


apiVersion: dapr.io/v1alpha1kind: Componentmetadata:  name: statestorespec:  type: state.mysql  version: v1  metadata:  - name: connectionString    value: "root:one.more.society@tcp(127.0.0.1:3306)/?allowNativePasswords=true&tls=custom"  - name: schemaName    value: "one_more_state_store"  - name: tableName    value: "one_more_state"  - name: pemPath    value: "/one/more/society/file.pem"
复制代码


最后,感谢你这么帅,还给我点赞

发布于: 刚刚阅读数: 4
用户头像

万猫学社

关注

资深研发工程师 2018.04.15 加入

微信搜索「万猫学社」,关注并回复「电子书」,免费获取12本必读技术书籍。

评论

发布
暂无评论
Dapr在Java中的实践 之 状态管理_Java_万猫学社_InfoQ写作社区