本文来自网易云社区

作者:张伟

背景

限时购是网易考拉目前比较常用的促销形式,但是前期创建一个限时购活动时需要各个BU按照指定的Excel格式进行选品提报,为了保证提报数据准确,运营需要人肉校验很多信息:

  • 是否已经参加了限时购

  • 在线价与活动价的对比校验

  • 大促价格校验

  • 是否有互斥活动

  • 库存检查

  • SKU 完整性

  • 价格预警检查

  • 商品可用性校验

这么多人肉的校验数据来自不同的系统,获取数据,检查数据;这是一件很繁琐且工作量巨大的事情。在这样的背景下,促销服务提供了限时购促销校验小工具,极大减少了运营人员配置限时购的工作量。

实现

上图是操作界面和校验结果格式示例,用户只需要按照模版将数据导入,在导入的时候完成数据基本格式校验!通过格式校验后,点击【校验】即可完成对数据的各种数据校验并将校验数据结果写到导出文件中,只需要根据到处文件提示进行修改即可。

优化

上文只是对该功能的一个简单介绍,在具体实现过程中需要调用各种服务,需要从商品基础服务获取商品信息,类目数据,供应商信息,SKU规格信息,限购信息包含,仓库信息等! 该工具上线初期,虽然功能得到了需求方的认可,但是性能问题比较突出;卡顿比较严重!为了给运营提供一个更好用的工具,通过优化代码结构,将代码中涉及到循环处理的地方都改为批量调用!此时性能有了一个明显的改善,但是校验数据量比较大的情况下还是会存在一定的性能问题,通过分析发现是因为调用外部系统耗时较大,此时通过dubbo异步并发调用的优化方式进行优化,使得该工具性能得到了极大提升。

dubbo 异步工具

在工作中总会有一些服务响应时间会和请求参数中的数量正相关,或者服务提供者明确限制了请求参数的大小,此时该如何进行优化呢? 在很多代码中都可以发现这样都写法

for(x:y){xxxService.xxx(p);
}

使用循环同步的调用方式进行处理,这样该方法的响应时间就会随着请求参数的个数增长而进行增长。有没有更好的方式呢?下面就介绍一下使用dubbo异步的方式完成对该方法的优化

使用xml配置完成异步调用

       基于 NIO 的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小。

在 consumer.xml 中配置:

<dubbo:reference id="fooService" interface="com.alibaba.foo.FooService"><dubbo:method name="findFoo" async="true" /></dubbo:reference><dubbo:reference id="barService" interface="com.alibaba.bar.BarService"><dubbo:method name="findBar" async="true" /></dubbo:reference>

调用代码:

// 此调用会立即返回nullfooService.findFoo(fooId);// 拿到调用的Future引用,当结果返回后,会被通知和设置到此FutureFuture<Foo> fooFuture = RpcContext.getContext().getFuture(); // 此调用会立即返回nullbarService.findBar(barId);// 拿到调用的Future引用,当结果返回后,会被通知和设置到此FutureFuture<Bar> barFuture = RpcContext.getContext().getFuture(); // 此时findFoo和findBar的请求同时在执行,客户端不需要启动多线程来支持并行,而是借助NIO的非阻塞完成// 如果foo已返回,直接拿到返回值,否则线程wait住,等待foo返回后,线程会被notify唤醒Foo foo = fooFuture.get();
// 同理等待bar返回Bar bar = barFuture.get(); // 如果foo需要5秒返回,bar需要6秒返回,实际只需等6秒,即可获取到foo和bar,进行接下来的处理。

你也可以设置是否等待消息发出:

  • sent="true" 等待消息发出,消息发送失败将抛出异常。

  • sent="false" 不等待消息发出,将消息放入 IO 队列,即刻返回。

    <dubbo:method name="findFoo" async="true" sent="true" />

    如果你只是想异步,完全忽略返回值,可以配置 return="false",以减少 Future 对象的创建和管理成本:

    <dubbo:method name="findFoo" async="true" return="false" />

    关于使用xml配置完成异步的缺点

    如果在xml中配置会导致工程中所有引用者都使用了异步方法,修改成本较高

    dubbo异步调用工具

    通过编码方式实现dubbo的异步调用,通过使用RpcContext.getContext().asyncCall()完成异步调用,考虑到促销这边需要将分页大小到最小值限制为200,在促销优化中使用该方式进行优化,效果明显

    /**
    * Desc:Dubbo异步调用辅助工具类
    *
    * @author wei.zw
    * @since 2017年7月14日 下午4:36:08
    * @version v 0.1
    */public class RpcAsyncUtil {  private static final Logger logger = LoggerFactory.getLogger(RpcAsyncUtil.class);  /*** dubbo异步调用,将远程调用结果组合后返回;本次耗时取决于最大的耗时* * @param paramList*            需要进行远程调用所有参数列表长度* @param pageSize*            一次远程调用使用的列表最大长度* @param syncCallable*            具体dubbo调用* @return* @author wei.zw*/public static <T, R> List<R> async(List<T> paramList, int pageSize, final SyncCallable<T, R> syncCallable) {      if (pageSize < 200) {pageSize = 200;}List<List<T>> subList = ListUtils.subList(paramList, pageSize);List<Future<List<R>>> futures = new ArrayList<>();      for (final List<T> sub : subList) {futures.add(RpcContext.getContext().asyncCall(new Callable<List<R>>() {              @Overridepublic List<R> call()throws Exception {                  return syncCallable.call(sub);}}));}List<R> result = new ArrayList<>();      try {          for (Future<List<R>> future : futures) {List<R> list = future.get();              if (CollectionUtils.isNotEmpty(list)) {result.addAll(list);}}} catch (Exception e) {logger.warn(ToStringBuilder.reflectionToString(syncCallable) + ",调用异常", e);          throw new RpcException(e);}      return result;}  public static interface SyncCallable<T, R> {      /*** 该方法中只能是一个远程调用,不能使用其他方法* * @param params* @return* @author wei.zw*/public List<R> call(List<T> params);}  public static interface SyncMapCallable<T,K, R> {      /*** 该方法中只能是一个远程调用,不能使用其他方法* * @param params* @return* @author wei.zw*/public Map<K, R> call(List<T> params);}
    }
  • 使用示例:

Mybatis批处理

final SqlSession session= getGenericSqlSessionFactory().openSession(ExecutorType.BATCH);for( ){
session.update();
}
session.commit();

PS:关于事务问题 Mybatis与Spring集成时,如果外面存在事务,则获取到的connection是同一个

  public SqlSession openSession(ExecutorType execType) {    return openSessionFromDataSource(execType, null, false);}private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {Transaction tx = null;    try {      final Environment environment = configuration.getEnvironment();      final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);      //从environment中获取dataSource,并根据dataSource创建事务tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);      final Executor executor = configuration.newExecutor(tx, execType);      return new DefaultSqlSession(configuration, executor, autoCommit);} catch (Exception e) {closeTransaction(tx); // may have fetched a connection so lets call close()throw ExceptionFactory.wrapException("Error opening session.  Cause: " + e, e);} finally {ErrorContext.instance().reset();}}public SpringManagedTransaction(DataSource dataSource) {notNull(dataSource, "No DataSource specified");    this.dataSource = dataSource;}  private void openConnection() throws SQLException {    //从dataSouce中获取connectionthis.connection = DataSourceUtils.getConnection(this.dataSource);    this.autoCommit = this.connection.getAutoCommit();    this.isConnectionTransactional = isConnectionTransactional(this.connection, this.dataSource);    if (this.logger.isDebugEnabled()) {      this.logger.debug(          "JDBC Connection ["+ this.connection+ "] will"+ (this.isConnectionTransactional ? " " : " not ")+ "be managed by Spring");}}

最佳实践

这样在需要进行批处理的使用只需要调用基类中的方法,而且不需要关注事务问题,即使在方法内部调用也存在事务问题。

网易云大礼包:https://www.163yun.com/gift

本文来自网易实践者社区,经作者张伟授权发布。

相关文章:
【推荐】 微服务监控探索
【推荐】 网易易盾验证码的安全策略

转载于:https://www.cnblogs.com/zyfd/p/9565161.html

限时购校验小工具dubbo异步调用实现限相关推荐

  1. dubbo异步调用传递性解决方法

    2019独角兽企业重金招聘Python工程师标准>>> 解决dubbo异步调用传递性: RpcContext.getContext().setAttachment(Constants ...

  2. 基于Qt5.15的CRC校验小工具开发项目

    基于Qt5.15的CRC校验小工具开发项目 前言 一.开发准备 二.开发流程 1.Qt配置与界面设置 2.控件基本配置 3.CRC算法介绍 4.信号与槽的四个响应事件 5.打包发布 总结 前言 近期用 ...

  3. Dubbo异步调用实现

    具体原理和介绍参看dubbo官方文档: http://dubbo.apache.org/zh-cn/docs/user/demos/async-call.html 1. 当使用异步调用时建议要和原有a ...

  4. dubbo 异步调用

    前言 下图为dubbo的官方RPC效果图,相信使用过dubbo开发的同学对这张原理图并不陌生: 在使用dubbo开发得过程中,对于开发者来说,一个服务提供者的应用,一个消费者应用,外加一个注册中心即可 ...

  5. html小工具在线翻译,调用百度API写了一个js翻译小工具

    目前还未完成的功能有:textarea高度自适应,移动端与pc端都写了. 效果如图: html: js翻译工具 textarea:disabled{ background-color: #fff; } ...

  6. Dubbo的异步调用

    文章目录 dubbo异步调用 2.6版本中dubbo异步调用的实现 2.7版本dubbo 客户端Consumer异步调用 使用CompletableFuture签名的接口 1.调用远程服务: 2. 使 ...

  7. 基于dubbo实现异步调用

    1.前言 Java中常见的实现异步调用的方式: 1.ThreadPool 2.CompletableFuture 3.MQ 4.BlockingQueue 5.Fork/Join 那么作为一款优秀的R ...

  8. 转wordpress小工具制作前台后台全解析

    wordpress主题制作中对边栏的处理一直是我们比较烦恼的,我们希望边栏的变化更多更复杂,今天我们就来具体讲解下wordpress边栏小工具的制作. 一.让你的主题显示小工具 有些相当简单的主题你会 ...

  9. Dubbo 同步、异步调用的几种方式

    我们知道,Dubbo 缺省协议采用单一长连接,底层实现是 Netty 的 NIO 异步通讯机制:基于这种机制,Dubbo 实现了以下几种调用方式: 同步调用 异步调用 参数回调 事件通知 同步调用 同 ...

最新文章

  1. 根据awr报告查看最慢的sql语句
  2. 漫画|你还记得原生的JDBC怎么连接数据库吗?
  3. 斐波那契数列规律的计算。
  4. ORACLE使用JOB定时备份数据库
  5. exoplayer 纯java,Exoplayer不播放任何视频
  6. 什么是好的错误消息? 讨论一下Java系统中的错误码设计
  7. 大整数乘法(信息学奥赛一本通-T1174)
  8. 京瓷打印机更换墨盒后显示缺粉_京瓷1800打印机更换墨盒后仍然提示添加墨粉,怎么解决啊?...
  9. angular2学习笔记之服务和http
  10. 乱码问题的原理及解决方法
  11. 新网站收录及备忘录网址
  12. 从布朗运动到Black–Scholes
  13. 直播源php代理用什么主机,流媒体直播系统_流媒体直播php源码_流媒体直播源码...
  14. 防沉迷系统?游戏运营商笑了!
  15. 全局阙值分割中的直方图算法和熵算法
  16. smart夏季的笑话
  17. 微信公众号排版的使用
  18. clover安装黑苹果10.15.3常见问题集合
  19. PostgreSQL学习手册
  20. 【X3D: Expanding Architectures for Efficient Video Recognition】

热门文章

  1. Ubuntu 14.04.4官方默认更新源sources.list
  2. iOS开发笔记--Layer 图层圆角、边框 、底纹其他常用操作
  3. CGGeometry.h详解
  4. android使用webview加载flash文件
  5. 用xargs处理带空格文件名
  6. PL/SQL第三课(学习笔记)
  7. Call for Papers | IEEE/IAPR IJCB 2022 会议
  8. 无中生有!没有视觉信号的视觉语音增强
  9. 直播预告 | 视觉SLAM在AR应用上的关键性问题探讨
  10. CV Code|计算机视觉开源周报20200602期~文末送书