变通实现微服务的per request以提高IO效率
*:first-child {
margin-top: 0 !important;
}
body>*:last-child {
margin-bottom: 0 !important;
}
/* BLOCKS
=============================================================================*/
p, blockquote, ul, ol, dl, table, pre {
margin: 15px 0;
}
/* HEADERS
=============================================================================*/
h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
}
h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
font-size: inherit;
}
h1 {
font-size: 28px;
color: #000;
}
h2 {
font-size: 24px;
border-bottom: 1px solid #ccc;
color: #000;
}
h3 {
font-size: 18px;
}
h4 {
font-size: 16px;
}
h5 {
font-size: 14px;
}
h6 {
color: #777;
font-size: 14px;
}
body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
margin-top: 0;
padding-top: 0;
}
a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0;
}
h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
margin-top: 10px;
}
/* LINKS
=============================================================================*/
a {
color: #4183C4;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
/* LISTS
=============================================================================*/
ul, ol {
padding-left: 30px;
}
ul li > :first-child,
ol li > :first-child,
ul li ul:first-of-type,
ol li ol:first-of-type,
ul li ol:first-of-type,
ol li ul:first-of-type {
margin-top: 0px;
}
ul ul, ul ol, ol ol, ol ul {
margin-bottom: 0;
}
dl {
padding: 0;
}
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px;
}
dl dt:first-child {
padding: 0;
}
dl dt>:first-child {
margin-top: 0px;
}
dl dt>:last-child {
margin-bottom: 0px;
}
dl dd {
margin: 0 0 15px;
padding: 0 15px;
}
dl dd>:first-child {
margin-top: 0px;
}
dl dd>:last-child {
margin-bottom: 0px;
}
/* CODE
=============================================================================*/
pre, code, tt {
font-size: 12px;
font-family: Consolas, "Liberation Mono", Courier, monospace;
}
code, tt {
margin: 0 0px;
padding: 0px 0px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}
pre>code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}
pre {
background-color: #f8f8f8;
border: 1px solid #ccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}
pre code, pre tt {
background-color: transparent;
border: none;
}
kbd {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background-color: #DDDDDD;
background-image: linear-gradient(#F1F1F1, #DDDDDD);
background-repeat: repeat-x;
border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
border-image: none;
border-radius: 2px 2px 2px 2px;
border-style: solid;
border-width: 1px;
font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
line-height: 10px;
padding: 1px 4px;
}
/* QUOTES
=============================================================================*/
blockquote {
border-left: 4px solid #DDD;
padding: 0 15px;
color: #777;
}
blockquote>:first-child {
margin-top: 0px;
}
blockquote>:last-child {
margin-bottom: 0px;
}
/* HORIZONTAL RULES
=============================================================================*/
hr {
clear: both;
margin: 15px 0;
height: 0px;
overflow: hidden;
border: none;
background: transparent;
border-bottom: 4px solid #ddd;
padding: 0;
}
/* IMAGES
=============================================================================*/
img {
max-width: 100%
}
-->
效率
同一次业务操作过程中,往往会出现某种操作被重复执行,逻辑上来讲如果只执行一次是最理想的。这里所指的操作特指一些IO操作,比如从数据库中获取登录人的信息,也就是说如果一次请求中包含5个小逻辑,这5个小逻辑包含3次获取用户信息的操作,理想的情况是3次只有一次是从数据库中加载,其余的两次从缓存中获取。
- 多次调用,每个服务实现独自请求用户信息。
- 一次调用,多次读取。首先从Context中加载,如果失败从数据库中加载,最后将结果存入Context。
前提
限于非web环境,这里是dubbo实现的微服务。如果是web环境的话解决问题比较简单,因为我们可以充分利用Spring Framwork中提到的三个bean生命周期的特殊来解决:
- request
- session
- global
案例
将老的价格数据迁移成新的价格数据,这里大概是如下的步骤:
- 删除新老价格的关系,因为需要支持重复迁移
- 禁用之前已经存在的价格规则,规则是描述价格在某种场景下生效的逻辑
- 创建新的价格
- 创建新的规则
- 启用新规则
上面步骤的价格,规则,关系数据分别属于三个业务对象,自身都具备CRUD的服务接口,这些CRUD都需要记录操作人信息,记录的标准就是接口传入的操作人所持有的token,我们需要将这个token转换成userId,userName之类的信息与价格,规则等信息一并存储。
时序图如下:
问题:迁移一条价格多次读取用户信息效率低
由于迁移价格会涉及到多个对象的操作,而操作这些具体业务对象的接口并不支持传具体的userId,userName只支持token,所以不可避免的会在保存价格等信息时各自去根据token查询操作人信息。实测一个价格完成一次数据迁移涉及到获取用户信息的次数多达20+次,效率是比较低,如何去解决呢?
现状
由于我目前实现的微服务是无状态的,也不是web环境,所以上面提到的那些bean的作用域功能就使用不上。
目标
实现类似request作用域的功能,一次请求仅执行一次,其余的请求从缓存中获取结果以提高IO操作效率。
方案
可采用TreadLocal来当缓存,存储频繁读取的数据。增加了CacheContext,获取用户首先从CacheContext中取,如果为空则从数据库加载然后回写到Treadlocal中,下一次再请求用户信息时就可以命中缓存不需要再次从数据库中加载,显然效率得到了质的提升。
时序图如下:
实现步骤如下:
- 创建Context数据对象
缓存的容器为TreadLocal,可以定义多个需要缓存的属性,并提供一个清除所有缓存的方法。清除的方法是必做的,否则会一直停留在线程中,当线程被再次利用时会获取到上一次请求存储的数据。
@Service
public class ProductContext { private static Logger logger = Logger.getLogger(CiaServiceImpl.class);
private ThreadLocal<CiaUserInfo> ciaUserInfoThreadLocal=new ThreadLocal<>();
private void clearCiaUserInfo(){
this.ciaUserInfoThreadLocal.remove();
this.logger.info("清除getTokenInfo缓存成功");
} public void setCiaUserInfoToCache(CiaUserInfo ciaUserInfo){
this.clearCiaUserInfo();
this.ciaUserInfoThreadLocal.set(ciaUserInfo);
this.logger.info("将getTokenInfo存储到缓存中");
} public CiaUserInfo getCiaUserInfoFromCache(String token){
CiaUserInfo ciaUserInfo =this.ciaUserInfoThreadLocal.get();
if(null!=ciaUserInfo){
this.logger.info("从缓存中获取到用户信息getTokenInfo");
}
return ciaUserInfo;
} public void clearAll(){
this.clearCiaUserInfo();
this.logger.info("清除ProductContext的缓存成功");
} }
- 修改获取用户信息的服务类,结合Context操作缓存。
public CiaUserInfo getTokenInfo(String token) throws Exception { CiaUserInfo result = this.productContext.getCiaUserInfoFromCache(token);
if(null!=result){
return result;
}
else {
result=new CiaUserInfo();
} //...get user from db
this.productContext.setCiaUserInfoToCache(result);
return result;
}
- 增加注解,用来标识哪些方法是需要使用缓存的
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LocalCacheContext { /**
* 是否启动
* @return
*/
boolean enable() default true; }
- 增加拦截器
TreadLocal中存入的信息需要有效及时的释放,配合上面申明的注解来完成。
@Aspect
public class LocalCacheContextInterceptor { private Logger logger = LoggerFactory.getLogger(getClass().getName()); @Autowired
private ProductContext productContext; @Pointcut("execution(* product.service.service.impl.*.*(..))")
public void pointCut() {
} @After("pointCut()")
public void after(JoinPoint joinPoint) throws ProductServiceException {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method targetMethod = methodSignature.getMethod(); LocalCacheContext localCacheContext= targetMethod.getAnnotation(LocalCacheContext.class);
if(null!=localCacheContext){
this.productContext.clearAll();
}
} }
- 客户端调用
@LocalCacheContext
public void migrationPrice(Long priceId) throws ProductServiceException {
this.migrationPriceService.migrationPrice(priceId);
}
变通实现微服务的per request以提高IO效率的更多相关文章
- 变通实现微服务的per request以提高IO效率(三)
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- 变通实现微服务的per request以提高IO效率(二)
*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...
- 阶段5 3.微服务项目【学成在线】_day17 用户认证 Zuul_16-网关-过虑器
4.5 过虑器 Zuul的核心就是过虑器,通过过虑器实现请求过虑,身份校验等. 4.5.1 ZuulFilter 自定义过虑器需要继承 ZuulFilter,ZuulFilter是一个抽象类,需要覆盖 ...
- 与IBM的Lin Sun关于Istio 1.0和微服务的问答
北京时间 7 月 31 日,Istio 正式发布了 1.0 版本,并表示已经可用于生产环境.该版本的主要新特性包括跨集群 mesh 支持.细粒度流量控制以及在一个 mesh 中增量推出 mutual ...
- springcloud+gateway微服务整合swagger
单一的微服务集成swagger: maven: <dependency> <groupId>io.springfox</groupId> <artifactI ...
- Kubernetes才是微服务和DevOps的桥梁
一.从企业上云的三大架构看容器平台的三种视角 一切都从企业上云的三大架构开始. 如图所示,企业上的三大架构为IT架构,应用架构和数据架构,在不同的公司,不同的人,不同的角色,关注的重点不同. 对于大部 ...
- 持续提升程序员幸福指数——使用abp vnext设计一款面向微服务的单体架构
可能你会面临这样一种情况,在架构设计之前,你对业务不甚了解,需求给到的也模棱两可,这个时候你既无法明确到底是要使用单体架构还是使用微服务架构,如果使用单体,后续业务扩展可能带来大量修改,如果使用微服务 ...
- Kubernetes 微服务最佳实践
本文由个人笔记 ryan4yin/knowledge 整理而来 本文主要介绍我个人在使用 Kubernetes 的过程中,总结出的一套「Kubernetes 配置」,是我个人的「最佳实践」. 其中大部 ...
- 在 Kubernetes 容器集群,微服务项目最佳实践
转载自:https://mp.weixin.qq.com/s/WYu3gDwKKf06f_FYbO9YRg 本文主要介绍我个人在使用 Kubernetes 的过程中,总结出的一套「Kubernetes ...
随机推荐
- Hystrix框架2--超时
timeout 在调用第三方服务时有些情况需要对服务响应时间进行把控,当超时的情况下进行fallback的处理 下面来看下超时的案例 public class CommandTimeout exten ...
- Laravel5.0学习--03 Artisan命令
本文以laravel5.0.22为例. 简介 Artisan 是 Laravel 内置的命令行接口.它提供了一些有用的命令协助您开发,它是由强大的 Symfony Console 组件所驱动.利用它, ...
- 删除数据表中除id外其他字段相同的冗余信息
删除一个信息表中除id外其他字段都相同的冗余信息,如下 id name addr 1 a b 2 a b 3 b c 删除这个表中的冗余信息 即应该是 id name addr 1 a b 3 b c ...
- 当前不会命中断点。源代码与原始版本不同 (VS2012)
遇到“当前不会命中断点.源代码与原始版本不同”的问题. 在网上查的类似: 一般studio会提示将“工具”,“选项”,“调试”,“要求源文件与原始版本完成匹配”去掉勾.但是这个配置去掉治标不治本,错误 ...
- 获取进程CPU占用率
获取进程CPU占用率 // 时间转换 static __int64 file_time_2_utc(const FILETIME* ftime) { LARGE_INTEGER li; li.LowP ...
- python3.5 正则表达式
我们平时上网的时候,经常需要在一些网站上注册帐号,而注册帐号的时候对帐号名称会有一些要求. 比如: 上面的图片中,输入的邮件地址.密码.手机号 才可以注册成功. 我们需要匹配用户输入的内容,判断用户输 ...
- KnockoutJS 3.X API 第七章 其他技术(1) 加载和保存JSON数据
Knockout允许您实现复杂的客户端交互性,但几乎所有Web应用程序还需要与服务器交换数据,或至少将本地存储的数据序列化. 最方便的交换或存储数据的方式是JSON格式 - 大多数Ajax应用程序今天 ...
- python定时重跑获取数据
做大数据的童鞋经常会写定时任务跑数据,由于任务之间的依赖(一般都是下游依赖上游的数据产出),所以经常会导致数据获取失败,因为很多人发现数据失败后 都会去查看日志,然后手动去执行自己的任务.下面我实现了 ...
- 【WP开发】JSON数据的读与写
在不使用其他库的情况下,WP-RT应用中也可以处理JSON数据.主要的几个类都放到Windows.Data.Json命名空间中: IJsonValue接口作为用于封装JSON数据的规范,其中只读属性V ...
- 移动web app开发必备 - 异步队列 Deferred
背景 移动web app开发,异步代码是时常的事,比如有常见的异步操作: Ajax(XMLHttpRequest) Image Tag,Script Tag,iframe(原理类似) setTimeo ...