HystrixCommand 支持的参数,除了 `commandKey/observableExecutionMode/fallbackMethod` 外,都可以使用 `@DefaultProperties` 配置默认值。
* **commandKey**:用来标识一个 Hystrix 命令,默认会取被注解的方法名。需要注意:`Hystrix 里同一个键的唯一标识并不包括 groupKey`,建议取一个独一二无的名字,防止多个方法之间因为键重复而互相影响。
* **groupKey**:一组 Hystrix 命令的集合, 用来统计、报告,默认取类名,可不配置。
* **threadPoolKey**:用来标识一个线程池,`如果没设置的话会取 groupKey`,很多情况下都是同一个类内的方法在共用同一个线程池,如果两个共用同一线程池的方法上配置了同样的属性,在第一个方法被执行后线程池的属性就固定了,所以属性会以第一个被执行的方法上的配置为准。
* **commandProperties**:与此命令相关的属性。
* **threadPoolProperties**:与线程池相关的属性,
* **observableExecutionMode**:当 Hystrix 命令被包装成 RxJava 的 Observer 异步执行时,此配置指定了 Observable 被执行的模式,默认是 `ObservableExecutionMode.EAGER`,Observable 会在被创建后立刻执行,而 `ObservableExecutionMode.EAGER`模式下,则会产生一个 Observable 被 subscribe 后执行。我们常见的命令都是同步执行的,此配置项可以不配置。
* **ignoreExceptions**:默认 Hystrix 在执行方法时捕获到异常时执行回退,并统计失败率以修改熔断器的状态,而被忽略的异常则会直接抛到外层,不会执行回退方法,也不会影响熔断器的状态。
* **raiseHystrixExceptions**:当配置项包括 `HystrixRuntimeException` 时,所有的未被忽略的异常都会被包装成 HystrixRuntimeException,配置其他种类的异常好像并没有什么影响。
* **fallbackMethod**:方法执行时熔断、错误、超时时会执行的回退方法,需要保持此方法与 Hystrix 方法的签名和返回值一致。
* **defaultFallback**:默认回退方法,当配置 fallbackMethod 项时此项没有意义,另外,默认回退方法不能有参数,返回值要与 Hystrix方法的返回值相同。
## commandProperties
* * *
配置方式
Hystrix 的命令属性是由 `@HystrixProperty` 注解数组构成的,HystrixProperty 由 name 和 value 两个属性,数据类型都是字符串。
以下将所有的命令属性分组来介绍。
线程隔离(Isolation)
* **execution.isolation.strategy**: 配置请求隔离的方式,有 threadPool(线程池,默认)和 semaphore(信号量)两种,信号量方式高效但配置不灵活,我们一般采用 Java 里常用的线程池方式。
* **execution.timeout.enabled**:是否给方法执行设置超时,默认为 true。
* **execution.isolation.thread.timeoutInMilliseconds**:方法执行超时时间,默认值是 1000,即 1秒,此值根据业务场景配置。
* **execution.isolation.thread.interruptOnTimeout**: **execution.isolation.thread.interruptOnCancel**:是否在方法执行超时/被取消时中断方法。需要注意在 JVM 中我们无法强制中断一个线程,如果 Hystrix 方法里没有处理中断信号的逻辑,那么中断会被忽略。
* **execution.isolation.semaphore.maxConcurrentRequests**:默认值是 10,此配置项要在 `execution.isolation.strategy` 配置为 `semaphore` 时才会生效,它指定了一个 Hystrix 方法使用信号量隔离时的最大并发数,超过此并发数的请求会被拒绝。信号量隔离的配置就这么一个,也是前文说信号量隔离配置不灵活的原因。
统计器(Metrics)
**`滑动窗口`**: Hystrix 的统计器是由滑动窗口来实现的,我们可以这么来理解滑动窗口:一位乘客坐在正在行驶的列车的靠窗座位上,列车行驶的公路两侧种着一排挺拔的白杨树,随着列车的前进,路边的白杨树迅速从窗口滑过,我们用每棵树来代表一个请求,用列车的行驶代表时间的流逝,那么,列车上的这个窗口就是一个典型的滑动窗口,这个乘客能通过窗口看到的白杨树就是 Hystrix 要统计的数据。
**`桶`**: bucket 是 Hystrix 统计滑动窗口数据时的最小单位。同样类比列车窗口,在列车速度非常快时,如果每掠过一棵树就统计一次窗口内树的数据,显然开销非常大,如果乘客将窗口分成十分,列车前进行时每掠过窗口的十分之一就统计一次数据,开销就完全可以接受了。 Hystrix 的 bucket (桶)也就是窗口 N分之一 的概念。
* **metrics.rollingStats.timeInMilliseconds**:此配置项指定了窗口的大小,单位是 ms,默认值是 1000,即一个滑动窗口默认统计的是 1s 内的请求数据。
* **metrics.healthSnapshot.intervalInMilliseconds**:它指定了健康数据统计器(影响 Hystrix 熔断)中每个桶的大小,默认是 500ms,在进行统计时,Hystrix 通过 `metrics.rollingStats.timeInMilliseconds / metrics.healthSnapshot.intervalInMilliseconds` 计算出桶数,在窗口滑动时,每滑过一个桶的时间间隔时就统计一次当前窗口内请求的失败率。
* **metrics.rollingStats.numBuckets**:Hystrix 会将命令执行的结果类型都统计汇总到一块,给上层应用使用或生成统计图表,此配置项即指定了,生成统计数据流时滑动窗口应该拆分的桶数。此配置项最易跟上面的 `metrics.healthSnapshot.intervalInMilliseconds` 搞混,认为此项影响健康数据流的桶数。 此项默认是 10,并且需要保持此值能被 `metrics.rollingStats.timeInMilliseconds` 整除。
* **metrics.rollingPercentile.enabled**:是否统计方法响应时间百分比,默认为 true 时,Hystrix 会统计方法执行的 `1%,10%,50%,90%,99%` 等比例请求的平均耗时用以生成统计图表。
* **metrics.rollingPercentile.timeInMilliseconds**:统计响应时间百分比时的窗口大小,默认为 60000,即一分钟。
* **metrics.rollingPercentile.numBuckets**:统计响应时间百分比时滑动窗口要划分的桶用,默认为6,需要保持能被`metrics.rollingPercentile.timeInMilliseconds` 整除。
* **metrics.rollingPercentile.bucketSize**:统计响应时间百分比时,每个滑动窗口的桶内要保留的请求数,桶内的请求超出这个值后,会覆盖最前面保存的数据。默认值为 100,在统计响应百分比配置全为默认的情况下,每个桶的时间长度为 10s = 60000ms / 6,但这 10s 内只保留最近的 100 条请求的数据。
熔断器(Circuit Breaker)
* **circuitBreaker.enabled**:是否启用熔断器,默认为 true;
* **circuitBreaker.forceOpen**: **circuitBreaker.forceClosed**:是否强制启用/关闭熔断器,强制启用关闭都想不到什么应用的场景,保持默认值,不配置即可。
* **circuitBreaker.requestVolumeThreshold**:启用熔断器功能窗口时间内的最小请求数。试想如果没有这么一个限制,我们配置了 50% 的请求失败会打开熔断器,窗口时间内只有 3 条请求,恰巧两条都失败了,那么熔断器就被打开了,5s 内的请求都被快速失败。此配置项的值需要根据接口的 QPS 进行计算,值太小会有误打开熔断器的可能,值太大超出了时间窗口内的总请求数,则熔断永远也不会被触发。建议设置为 `QPS * 窗口秒数 * 60%`。
* **circuitBreaker.errorThresholdPercentage**:在通过滑动窗口获取到当前时间段内 Hystrix 方法执行的失败率后,就需要根据此配置来判断是否要将熔断器打开了。 此配置项默认值是 50,即窗口时间内超过 50% 的请求失败后会打开熔断器将后续请求快速失败。
* **circuitBreaker.sleepWindowInMilliseconds**:熔断器打开后,所有的请求都会快速失败,但何时服务恢复正常就是下一个要面对的问题。熔断器打开时,Hystrix 会在经过一段时间后就放行一条请求,如果这条请求执行成功了,说明此时服务很可能已经恢复了正常,那么会将熔断器关闭,如果此请求执行失败,则认为服务依然不可用,熔断器继续保持打开状态。此配置项指定了熔断器打开后经过多长时间允许一次请求尝试执行,默认值是 5000。
其他(Context/Fallback)
* **requestCache.enabled**:是否启用请求结果缓存。默认是 true,但它并不意味着我们的每个请求都会被缓存。缓存请求结果和从缓存中获取结果都需要我们配置 `cacheKey`,并且在方法上使用 `@CacheResult` 注解声明一个缓存上下文。
* **requestLog.enabled**:是否启用请求日志,默认为 true。
* **fallback.enabled**:是否启用方法回退,默认为 true 即可。
* **fallback.isolation.semaphore.maxConcurrentRequests**:回退方法执行时的最大并发数,默认是10,如果大量请求的回退方法被执行时,超出此并发数的请求会抛出 `REJECTED_SEMAPHORE_FALLBACK` 异常。
## threadPoolProperties
* * *
配置方式
线程池的配置也是由 HystrixProperty 数组构成,配置方式与命令属性一致。
配置项
* **coreSize**:核心线程池的大小,默认值是 10,一般根据 `QPS * 99% cost + redundancy count` 计算得出。
* **allowMaximumSizeToDivergeFromCoreSize**:是否允许线程池扩展到最大线程池数量,默认为 false;
* **maximumSize**:线程池中线程的最大数量,默认值是 10,此配置项单独配置时并不会生效,需要启用 `allowMaximumSizeToDivergeFromCoreSize` 项。
* **maxQueueSize**:作业队列的最大值,默认值为 -1,设置为此值时,队列会使用 `SynchronousQueue`,此时其 size 为0,Hystrix 不会向队列内存放作业。如果此值设置为一个正的 int 型,队列会使用一个固定 size 的 `LinkedBlockingQueue`,此时在核心线程池内的线程都在忙碌时,会将作业暂时存放在此队列内,但超出此队列的请求依然会被拒绝。
* **queueSizeRejectionThreshold**:由于 `maxQueueSize` 值在线程池被创建后就固定了大小,如果需要动态修改队列长度的话可以设置此值,即使队列未满,队列内作业达到此值时同样会拒绝请求。此值默认是 5,所以有时候只设置了 `maxQueueSize` 也不会起作用。
* **keepAliveTimeMinutes**:由上面的 `maximumSize`,我们知道,线程池内核心线程数目都在忙碌,再有新的请求到达时,线程池容量可以被扩充为到最大数量,等到线程池空闲后,多于核心数量的线程还会被回收,此值指定了线程被回收前的存活时间,默认为 2,即两分钟。
工作方式
Hystrix 内线程池的使用是基于 Java 内置线程池的简单包装,通常有以下三种状态:
* 如果请求量少,达不到 coreSize,通常会使用核心线程来执行任务。
* 如果设置了 `maxQueueSize`,当请求数超过了 coreSize, 通常会把请求放到 queue 里,待核心线程有空闲时消费。
* 如果 queue 长度无法存储请求,则会创建新线程执行直到达到 `maximumSize` 最大线程数,多出核心线程数的线程会在空闲时回收。
自定义超时配置
~~~
@HystrixCommand(commandProperties = {
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")
})
~~~
~~~
1.默认:(方法上记得要加上@HystrixCommand,否则无效):
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=3000
2.配置具体方法的超时时间
hystrix.command.serverMethod.execution.isolation.thread.timeoutInMilliseconds=3000
~~~
配置文件给commandKey配置超时时间:
```
@HystrixCommand(fallbackMethod="fallback",commandKey="userGetKey")
hystrix.command.userGetKey.execution.isolation.thread.timeoutInMilliseconds = 13000
```
- 项目介绍
- 新手入门教程
- 开发环境准备
- 基础环境要求
- 开发环境安装
- IDEA导入项目
- 通过IDEA启动项目
- VUE2前端文档
- Vue2前端快速启动
- Docker启动Vue2前端
- Vue2前端多环境
- 切换Vue2路由菜单表
- Docker启动单体后台
- 切换其他数据库
- Maven私服设置
- Docker安装软件
- docker搭建开发环境
- Docker中安装Elasticsearch
- 连接达梦数据库
- 达梦数据库多数据源
- 老版本文档
- 通过IDEA启动项目3.3
- 前端快速启动3.3
- IDEA导入项目3.3
- 快速开始
- HelloWorld
- 上线发布
- JAR部署方案
- JAR分离打包部署
- WAR部署方案
- 开启Nginx压缩
- swagger使用
- 老版本发布文档
- JAR部署方案3.3
- JAR分离打包部署3.3
- Docker单体启动项目3.3
- WAR部署方案2.4
- JAR部署方案3.4.1
- 代码生成器
- 代码生成器简介
- Online代码生成器
- GUI代码生成器
- 代码生成常见问题
- 发布后配置代码生成
- 代码生成器配置
- 代码生成器配置文件
- Online导入表过滤规则
- 自定义开发
- 生成器模板介绍
- 自定义一套模板
- 生成代码优化
- 快速生成模块
- 老版生成器文档
- 微服务开发
- 微服务解决方案
- 单体升级为微服务3.4.1+
- archetype生成微服务模块3.4+
- docker启动微服务项目3.4.1+
- 微服务项目结构说明3.4.1
- jeecg-server-cloud微服务中间件
- Sentinel集成和规则配置用法
- Admin监控用法
- Gateway网关高级配置3.4
- jeecg-boot-starter项目实战
- jeecg-boot-starter目录结构
- xxl-job定时任务集成2.4+
- rabitmq消息队列集成2.4+
- 消息总线用法2.4+
- Redisson分布式锁集成2.4+
- 防止重复提交2.4+
- 分库分表ShardingSphere3.4+
- 分库分表ShardingSphere2.4
- 分布式事务Seata集成
- 上线部署
- 微服务部署文档
- 老版本
- 单体升级为微服务2.4~3.1
- docker-compose部署3.0
- 微服务安装与快速启动
- docker-compose部署3.1
- 老版微服务文档
- 单体升级为微服务3.4
- archetype生成微服务模块3.4
- docker启动微服务项目3.4
- jeecg-cloud-module目录结构3.4
- 单体升级为微服务3.2+
- archetype生成微服务模块3.2+
- Docker启动微服务3.3+
- Gateway网关高级配置3.2
- 实战技巧
- 实战微服务模块分层
- 微服务之间调用免Token方案
- 微服务单独配置数据源3.4+
- 微服务单独配置nacos 3.4+
- 微服务单独配置数据源3.2
- 微服务单独配置nacos 3.2
- 系统日志表跨库问题
- nacos配置实现动态刷新
- 高级应用
- 微服务Feign调用示例
- skywarking链路跟踪
- 微服务和单体定义切换接口
- 安装@Redis集群搭建
- 安装@RabbitMq创建交换机
- 3.2之前限流用法
- 微服务熔断/降级/限流2.4+
- HystrixCommand配置参数详解
- 动态feign客户端
- 常见问题
- gateway接口文档不通
- 访问gateway超时
- 系统监控跨域问题修复
- gateway请求返回400
- 后端开发技巧
- 常用问题汇总
- 数据库支持说明
- 自定义注解用法
- Spring缓存注解@Cacheable
- 字典翻译注解@Dict
- 数据权限注解@PermissionData
- 日志记录注解@AutoLog
- 菜单路由配置
- 菜单配置说明
- 带参数路由菜单
- 路由菜单规则
- 菜单快速SQL
- 聚合路由菜单
- 数据快照功能如何用?
- 快速创建module模块
- 查询过滤器用法
- 系统日志怎么插入?
- 自定义sql分页实现
- redis 如何使用?
- 事务如何使用?
- 动态数据源使用
- 定时任务如何开发?
- 平台消息推送接口
- 接口敏感数据安全
- 批量插入效率建议
- 短信接口配置(阿里大鱼短信)
- 自定义注解限制重复提交
- 邮箱配置文档
- 积木报表设计器数据集使用
- 父子编码使用说明
- 我的文档安全配置
- 文档预览
- 在线多数据源
- 导入校验工具类
- druid数据库密码加密
- 自定义首页的用法
- 系统安全模式
- 数据脱敏注解
- Long类型主键导致精度丢失问题
- sql黑名单配置
- 系统文件上传
- 统一文件上传规则
- MinIO配置
- 阿里云OSS配置
- Minio版本6.0.13升级到8.0.3修改记录
- 文件上传大小限制
- VUE2前端开发
- 如何更改默认主题
- Form表单开发特殊性
- Icon图标扩展方法
- vuex使用详解
- vue路由带参总结
- 全局配置文件
- 列表自定义列实现
- 国际化改造方案
- 常用命令
- 报表开发
- 报表开发技术点
- 自定义报表组件
- 源码解读
- 自定义组件
- 前端技巧
- components包下文件描述
- JDictSelectTag字典标签
- duplicateCheck表单字段重复校验通用JS
- JVxeTable行编辑
- 组件配置文档
- 自定义组件
- 封装自定义组件
- 自定义组件增强
- 多级联动配置
- 使用示例
- 常见问题解答
- JEditableTable帮助文档
- JMultiSelectTag多选组件
- JPopup弹窗选择组件
- JSearchSelectTag字典表的搜索组件
- JSelectDepart部门选择组件
- JSelectMultiUser用户多选组件
- JSelectUserByDep根据部门选择用户
- JTreeDict分类字典树形下拉组件
- JTreeSelect树形下拉框 (异步加载)
- JInput 查询组件
- JCron 帮助文档
- JCategorySelect 帮助文档
- JUpload上传组件
- JImageUpload图片上传组件
- JSuperQuery高级查询组件
- JAreaLinkage省市县三级联动
- JEllipsis超长截取显示
- JDate 日期组件
- JCheckbox组件
- JCodeEditor组件
- JSelectMultiple多选下拉组件
- JTreeSelect树形下拉组件
- JImportModal组件
- JAsyncTreeList异步树表格
- JFormContainer使用文档
- JMarkdownEditor使用文档
- 前端开发坑(一定要注意)
- 按需加载方案
- 按需加载@减小打包
- JeecgBoot实战-按需加载方案
- 表格的换行与不换行
- 旧:表格的换行与不换行
- 主子表子表下拉框、时间框弹框被遮挡优化
- 前端依赖包package.json
- 如何实现多列表单
- 前端字典缓存用法
- 自定义首页
- 门户首页Portal权限控制
- Form升级为FormModel用法
- 动态覆盖env配置文件(新)
- 上传组件使用kkfileview实现文件预览
- 系统权限用法
- JAVA请求权限控制
- 页面按钮权限用法
- 数据表格列字段控制
- 表单权限
- 显示隐藏控制
- 禁用控制用法一
- 禁用控制用法二
- 子表行字段的禁用和隐藏控制
- 数据权限
- 数据权限规则篇
- 数据权限用法篇
- 编码对接数据权限(未用查询过滤器)
- 权限配置自定义SQL
- 子表数据权限
- 二级部门权限管理
- 填值规则(编码生成)
- 校验规则(高级校验)
- 列表列字段导出权限示例
- 备份
- 通过URL方式配置数据权限
- Online表单VUE2版
- Online开发初体验
- Online表单的菜单配置
- Online表单配置
- Online表单配置参数说明
- Online表单一对多表单配置
- Online树列表表单配置
- Online表单查询配置说明
- Online功能如何配置成菜单
- Online表单填值规则配置
- Online表单排版
- Online树列表表单配置(个性化)
- Online表单标准字段说明
- Online表单删除说明
- Online对接积木报表
- Online查询排序配置
- Online联合查询配置
- Online导入导出值转换器
- Online表单视图功能
- Online自定义查询配置
- Online表单控件
- 下拉框@多选框@单选框
- 下拉多选
- 下拉搜索
- Popup控件
- 富文本控件
- 时间控件
- 用户选择器
- 部门选择器
- 自定义树控件
- 分类字典树控件
- Online之popup使用
- 下拉联动组件
- markdown编辑器
- 省市区组件
- 开关控件
- 字段排列顺序调整
- 字段显示隐藏控制
- 控件配置Href
- 字段校验规则使用
- 控件默认值表达式
- 控件扩展参数用法
- Online权限配置
- 字段权限配置与授权
- 按钮权限配置与授权
- 数据权限配置与授权
- 联合查询数据权限规则说明
- 在线开发(增强)
- Online 自定义按钮
- Online自定义按钮基础篇
- Online自定义按钮表达式
- Online基础篇-SQL增强
- Online JS增强
- 基础篇-JS增强
- 基础篇-JS增强(表单渲染)
- 列表JS API
- 表单JS API
- JS增强自定义弹窗
- JS增强 实战示例
- 表单按钮 动态显隐字段
- 表单按钮 改变控件的值
- 修改控件值【单表/主表】
- 表单按钮修改子表数据
- 修改控件值【从表】
- 修改控件值【从改主】
- JS增强实现下拉联动
- 表单前置事件(提交/编辑/删除)
- 初始化表单默认值
- 获取vuex缓存
- Online Java增强
- online基础篇-java增强
- Online java增强 导入
- Online java增强 导出
- Online java增强 查询
- Online Java增强 http-api
- 表单类
- 列表类
- 对接表单设计器后需注意
- Online java增强配置说明
- 备份2.4
- Online java增强 导入2.4
- online java 增强 http-api
- 通过字段Href实现三级联动
- 导入数据库表支持排除表
- edu
- Online表单专题课程1
- Online表单专题课程2
- 备注
- Online权限配置(作废—老版本)
- 列表字段权限(显示与隐藏)
- 表单字段权限(隐藏和禁用)
- 列表按钮权限(隐藏)
- 列表数据权限
- 树形表单数据权限配置
- Online表单权限配置(作废—老版本)
- 功能描述
- 列表权限
- 列表字段的显示或隐藏
- 列表操作按钮的显示或隐藏
- 列表自定义按钮的显示或隐藏
- 表单权限
- 表单字段的显示或隐藏
- 表单字段的禁用或可编辑
- online表单使用常见问题
- online AI自动化测试数据制作
- Online导入开启校验用法
- Online AI模型测试用例功能详情
- Online Al模型智能测试数据制作文档
- online表单API接口
- Online报表VUE2版
- Online报表
- online报表-使用步骤
- online报表-动态参数
- 如何配置报表菜单
- Online报表权限配置
- Online报表系统变量应用
- 参数说明
- Online报表排序
- 字段href
- 字典配置
- online报表-合计
- online报表-配置分组标题
- online报表导出
- 高级实战技巧
- Websocket业务对接
- WebSocket的集成
- SAAS多租户用法
- 如何集成积木报表
- 使用jdk14启动项目【内测】
- 全局监听使用示例
- 微前端高级改造
- 逻辑删除方案
- 升级springboot2.6.3问题汇总
- postgresql数据库兼容问题
- 单体架构集成分库分表
- CAS单点登录
- CAS单点登录服务端准备
- 单点登录流程图
- 单点登录配置说明(2.3.1+)
- 单点登录配置说明(vue3)
- archive
- 2.JeecgBoot后端对接CAS步骤
- 3.JeecgBoot前端项目对接CAS步骤(2.3.0)
- 第三方登录
- 企业微信配置
- 钉钉配置
- 企业微信集成方案
- 微信第三方集成
- 钉钉和企业微信打通
- 配置开关
- 钉钉集成流程
- 企业微信集成流程
- 小技巧
- 同步部门规则
- 同步用户规则
- 同步到本地开关
- OAuth2登录(应用集成)
- 钉钉OAuth2登录
- 企业微信OAuth2登录
- JeecgUniapp开发
- 开发环境搭建
- 项目简介
- 编写Hello World页面
- 打包项目
- APP打包
- 微信小程序打包
- H5打包
- 小程序发布
- APP首页排版设计
- API接口配置
- uniapp推送
- 后台定时unipush推送配置
- websocket消息推送修改
- HBuilderX打包APP
- 1.Build-JeecgBoot项目
- 2.HBuilderX 打包APP
- HBuilder打包APP手机端安装配置教程
- bak_vant
- 小结
- 后台推送消息移动端
- 如何安装新依赖
- 代码生成列表和表单
- AutoPOI(Excel工具)
- 快速文档
- 单表数据导出多表头示例
- 单表数据多表头导入注意bak
- 导出自定义选择列导出
- @excel注解使用
- excel根据模板导出
- 一对多导出needMerge
- 单表数据导出多sheet实例
- autopoi升级到4.0版本修改记录
- 大数据量处理
- 大数据量导出示例
- 编码规范
- 代码规范
- 建表规范
- 代码格式化插件安装
- 代码质量扫描
- 更多商业功能介绍
- 表单设计器
- 仪表盘设计器
- 流程设计器
- 工作流引擎
- 大屏设计器
- 低代码应用
- 门户设计器
- APP移动办公
- APP布局设计
- OA办公
- Online图表