微服务改造中解决跨库问题的思路

  今年一直在和团队做微服务的架构改造(相关的一些详情,有兴趣的朋友,可以参见之前的这篇分享)。但是做过改造的朋友都知道 从“All-In-One” 到 “Micro-Service” 都需要迈过的一个坎,那就是垂直分库, 根据不同的子服务,将数据库拆分为不同的子服务库。
  
  那么问题就来了,在开始做微服务改造前,我发现在摇旺的老系统中,有很多后台报表或者前端详情页所需的数据是通过SQL Join来完成的。但是,我们微服务改造后,每个服务背后的数据库已经在分布不同的实例中了,所以我们已经不能继续简单在SQL中使用join了,那么解决“跨库Join”就摆上了议事日程。
  
  通过讨论和调研,垂直分库后,对于“跨库查询”的解决,可以采用以下几个思路:
  
  1. 依赖字段较少:字段冗余
  
  A库中的Tab1表需要关联B库中的Tab2表中的字段F, 我们就将字段F冗余到表Tab1中,那么查询时候,Tab1和Tab2就不需要做Join,单独查A库中的Tab1表就可以解决问题。
  
  这是一个野路子,因为这是违反正常的范式设计的,但在依赖字段较少的情况下还是可以解决问题的,达到空间来换取时间的目的。不过这个方法最大的短板在于2点: 1. 依赖字段不能太多,2. 数据一致性问题。Tab2中的F字段一但改变,必须要同步到Tab1中,否则就会引起脏数据的问题。所以,需要在业务代码建立必要的同步机制,如果出错,还需要考虑引入人工补偿。
  
  2. 依赖字段较多:表同步
  
  在很多场景下,我们字段的依赖是很多的,乃至查询的时候可能需要跨多张表,这个时候方法1就无法直接用了,我们就需要进行表级别的数据同步,可以采用ETL工具来做到跨库的表同步。不过需要注意的是,数据同步不建议实时性过高,否则数据库的性能会受到比较大的影响。所以对于实时性不高的查询要求,表同步还是比较奏效的。
  
  3. 静态字段依赖:数据字典表
  
  对于不同库中的静态字段,可以建立一张数据字典表,可以将这类表在其他每个数据库中均保存一份,从而避免跨库join查询。如果静态数据表中的某些字段数据需要修改,可以采用一套脚本统一更新。
  
  4. 服务层代码进行数据组装
  
  通过各种服务查询到一个数据集,通过代码进行二次组装,然后生成我们需要返回给前端的对象。在实践过程中,对于处理过的查询集,我们可以将它们缓存在我们的分布式缓存中,减少服务间的RPC调用次数和数据库的查询压力。同时,注意设置好过期时间,把控好数据一致性和有效性。
  
  const Koa = require(‘koa‘);
  
  const Router = require(‘koa-router‘);
  
  const redis = require(‘redis‘);
  
  const { promisify } = require(‘util‘);
  
  let app = new Koa();
  
  let router = new Router();
  
  let redisClient =www.yongshiyule178.com/ createRedisClient({
  
  // ip为docker-compose.yml配置的redis-server别名 rd,可在应用所在容器查看dns配置
  
  ip: ‘rd‘,
  
  port: 6379,
  
  prefix: ‘‘,
  
  db: 1,
  
  password: null
  
  });
  
  function createRedisClient({port, ip, prefix, db}) {
  
  let client = redis www.mcyulegw.com.createClient(port, ip, {
  
  prefix,
  
  db,
  
  no_ready_check: true
  
  });
  
  client.on(‘reconnecting‘, (err)=>{
  
  console.warn(`redis client reconnecting, delay ${err.delay}ms and attempt ${err.attempt}`);
  
  });
  
  client.on(‘error‘, function (err) {
  
  console.error(‘Redis error!‘,err);
  
  });
  
  client.on(‘ready‘, function() {
  
  console.info(`redis初始化完成,就绪: ${ip}:${port}/${db}`);
  
  });
  
  return client;
  
  }
  
  function execReturnPromise(cmd, args) {
  
  return new Promise((res,rej)=>{
  
  redisClient.send_www.tiaotiaoylzc.com command(cmd, args, (e,reply)=>{
  
  if(e){
  
  rej(e);
  
  }else{
  
  res(reply);
  
  function batchReturnPromise() {
  
  return new Promise((res,rej)=>{
  
  let b = redisClient.batch();
  
  b.exec = promisify(b.exec);
  
  res(b);
 
  router.get(‘/‘, async (ctx,www.yongshi123.cn next) => {
  
  await execReturnPromise(‘set‘,[‘testkey‘,‘helloworld‘]);
  
  let ret = await www.michenggw.com execReturnPromise(‘get‘,[‘testkey‘]);
  
  ctx.body = {
  
  status: ‘ok‘,
  
  result: ret,
 
  router.get(‘/batch‘, async (ctx, next) => {
  
  await execReturnPromise(‘set‘,[‘testkey‘,‘helloworld, batch!‘]);
  
  let batch = await batchReturnPromise(www.zhongyiyuL.cn);
  
  for(let i=0;i < 10;i++){
  
  batch.get(‘testkey‘);
  
  }
  
  let ret = await batch.exec();
  
  ctx.body = {
  
  status: ‘ok‘,
  
  result: ret,
 
  .use(router.routes(www.pingguoyul.cn))
  
  .use(router.allowedMethods())
  
  .listen(8090);
  
  以上就是4种应对跨库Join的思路,实战中,一定是将这4类方案进行组合使用的,同时,需要注意的是,相比这些解决思路,更重要的是表结构的合理设计。否则要彻底解决跨库是很困难的。
  
  分布式事务的处理方式
  
  除此之外,分库后,还有一个难题,就是分布式事务的处理。具体的事例,可以参见我之前的这两篇文章1和 文章2。里面会提到在微服务下,服务间事务回滚的几个思路,希望对大家有用

原文地址:https://www.cnblogs.com/qwangxiao/p/10451142.html

时间: 2024-07-30 07:44:56

微服务改造中解决跨库问题的思路的相关文章

使用 Dubbo 对遗留单体系统进行微服务改造

摘要: 在 2016 年 11 月份的<技术雷达>中,ThoughtWorks 给予了微服务很高的评价.同时,也有越来越多的组织将实施微服务作为架构演进的一个必选方向.只不过在拥有众多遗留系统的组织内,将曾经的单体系统拆分为微服务并不是一件容易的事情. Credit: Justin Kenneth Rowley. You can find the original photo at flickr. The microservices style of architecture highligh

微服务系统中的认证策略

软件安全本身就是个很复杂的问题,由于微服务系统中的每个服务都要处理安全问题,所以在微服务场景下会更复杂.David Borsos在最近的伦敦微服务大会上作了相关内容的演讲,并评估了四种面向微服务系统的身份验证方案. 在传统的单体架构中,单个服务保存所有的用户数据,可以校验用户,并在认证成功后创建HTTP会话.在微服务架构中,用户是在和服务集合交互,每个服务都有可能需要知道请求的用户是谁.一种朴素的解决方案是在微服务系统中应用与单体系统中相同的模式,但是问题就在于如何让所有的服务访问用户的数据.解

单体式应用微服务改造经验谈【上】

昨日好评博文:<如何设计出优美的Web API?> 截止目前阅读量近 2000,获得好评无数,小伙伴们不要错过哦! 微服务是当下最流行的应用架构技术了,它跟容器服务.DevOps合称云时代的三剑客,可以帮我们化解业务发展过快导致的产品迭代压力,让我们可以自由选择最适合团队的技术栈,让系统能够承载互联网海量用户的访问,让我们可以更加轻松地运维大型的互联网系统.近些年在厂商.社区和用户等各方努力推动下,微服务相关的理论和产品都日趋成熟,不同语言的微服务开发及治理套件(例如:Spring Cloud

微服务开发中的数据架构设计

本文来自作者 陈伟荣 在 GitChat 分享的文章[微服务开发中的数据架构设计] 前言 微服务是当前非常流行的技术框架,通过服务的小型化.原子化以及分布式架构的弹性伸缩和高可用性,可以实现业务之间的松耦合.业务的灵活调整组合以及系统的高可用性.为业务创新和业务持续提供了一个良好的基础平台.本文分享在这种技术架构下的数据架构的设计思想以及设计要点,本文包括下面若干内容. 微服务技术框架中的多层数据架构设计 数据架构设计中的要点 要点1:数据易用性 要点2:主.副数据及数据解耦 要点3:分库分表

微服务架构中APIGateway原理

背景 我们知道在微服务架构风格中,一个大应用被拆分成为了多个小的服务系统提供出来,这些小的系统他们可以自成体系,也就是说这些小系统可以拥有自己的数据库,框架甚至语言等,这些小系统通常以提供 Rest Api 风格的接口来被 H5, Android, IOS 以及第三方应用程序调用. 但是在UI上进行展示的时候,我们通常需要在一个界面上展示很多数据,这些数据可能来自于不同的微服务中,举个例子. 在一个电商系统中,查看一个商品详情页,这个商品详情页包含商品的标题,价格,库存,评论等,这些数据对于后端

SQL Server 中的跨库视图

SQL Server 中的跨库视图 在一个SQL中,有多个数据库,A.B.C,在使用C为连接库中,现在要查询A中的表T1. 那么,在C中建创视图(A_T1). SELECT *FROM A.dbo.T1 这样就当本地表使用了.

Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析

Java生鲜电商平台-SpringCloud微服务架构中网络请求性能优化与源码解析 说明:Java生鲜电商平台中,由于服务进行了拆分,很多的业务服务导致了请求的网络延迟与性能消耗,对应的这些问题,我们应该如何进行网络请求的优化与处理呢? 到底有没有一些好的建议与方案呢? 下面这个文章将揭晓上面的问题,让你对SpringCloud微服务网络请求性能有一个全新的认识. 目录简介 01.网络请求异常分类 02.开发中注意问题 03.原始的处理方式 04.如何减少代码耦合性 05.异常统一处理步骤 06

微服务架构中整合网关、权限服务

前言:之前的文章有讲过微服务的权限系列和网关实现,都是孤立存在,本文将整合后端服务与网关.权限系统.安全权限部分的实现还讲解了基于前置验证的方式实现,但是由于与业务联系比较紧密,没有具体的示例.业务权限与业务联系非常密切,本次的整合项目将会把这部分的操作权限校验实现基于具体的业务服务. 1. 前文回顾与整合设计 在认证鉴权与API权限控制在微服务架构中的设计与实现系列文章中,讲解了在微服务架构中Auth系统的授权认证和鉴权.在微服务网关中,讲解了基于netflix-zuul组件实现的微服务网关.

罗辑思维首席架构师:Go微服务改造实践

转自:http://www.infoq.com/cn/news/2018/05/luojisiwei 方圆 曾先后在 Cisco,新浪微博从事基础架构研发工作.十多年一直专注于后端技术的研发,在消息通信,分布式存储等方向有着丰富的经验.个人技术兴趣广泛,主要专注 Go/Java/Python 等编程语言的发展,尤其是在云计算等前沿领域的应用. 一.改造的背景 得到最早的APP就是一个单体的PHP的应用,就是图中最大的黄色块,中间蓝色块代表不同模块.下面的黄色部分代表passport 和支付系统,