0%

当我们在做数据库分库分表或者是分布式缓存时,不可避免的都会遇到一个问题:

如何将数据均匀的分散到各个节点中,并且尽量的在加减节点时能使受影响的数据最少。

Hash 取模

随机放置就不说了,会带来很多问题。通常最容易想到的方案就是 hash 取模了。

可以将传入的 Key 按照 index = hash(key) % N 这样来计算出需要存放的节点。其中 hash 函数是一个将字符串转换为正整数的哈希映射方法,N 就是节点的数量。

这样可以满足数据的均匀分配,但是这个算法的容错性和扩展性都较差。

比如增加或删除了一个节点时,所有的 Key 都需要重新计算,显然这样成本较高,为此需要一个算法满足分布均匀同时也要有良好的容错性和拓展性。

Read more »

前言

看过之前SBC系列的小伙伴应该都可以搭建一个高可用、分布式的微服务了。 目前的结构图应该如下所示:

各个微服务之间都不存在单点,并且都注册于 Eureka ,基于此进行服务的注册于发现,再通过 Ribbon 进行服务调用,并具有客户端负载功能。

一切看起来都比较美好,但这里却忘了一个重要的细节:

当我们需要对外提供服务时怎么处理?

这当然也能实现,无非就是将我们具体的微服务地址加端口暴露出去即可。

那又如何来实现负载呢?

简单!可以通过 Nginx F5 之类的工具进行负载。

但是如果系统庞大,服务拆分的足够多那又有谁来维护这些路由关系呢?

当然这是运维的活,不过这时候运维可能就要发飙了!

并且还有一系列的问题:

  • 服务调用之间的一些鉴权、签名校验怎么做?
  • 由于服务端地址较多,客户端请求难以维护。

针对于这一些问题 SpringCloud 全家桶自然也有对应的解决方案: Zuul
当我们系统整合 Zuul 网关之后架构图应该如下所示:

Read more »

原文链接

1 在 GitHub.com 编辑代码

我将从我认为大家都知道的一件事情开始(尽管我是直到一周前才知道)。

当你在 GitHub 查看文件时(任何文本文件,任何仓库中),右上角会有一个小铅笔图标,点击它就可以编辑文件了。完成之后点击 Propose file change 按钮 GitHub 将会自动帮你 fork 该项目并且创建一个 pull request

很厉害吧!他自动帮你 fork 了该 repo。

不再需要 fork , pull ,本地编辑再 push 以及创建一个 PR 这样的流程了。

这非常适合修复编写代码中出现的拼写错误和修正一个不太理想的想法。

2 粘贴图片

你不仅仅受限于输入文本和描述问题,你知道你可以直接从粘贴板中粘贴图片吗?当你粘贴时,你会看到图片已经被上传了(毫无疑问被上传到云端)之后会变成 Markdown 语法来显示图片。

3 格式化代码

如果你想写一段代码,你可以三个反引号开始 —— 就像你在研究MarkDown时所学到的 —— 之后 GitHub 会试着猜测你写的语言。

但如果你写了一些类似于 Vue, Typescript, JSX 这样的语言,你可以明确指定得到正确的高亮。

注意第一行中的

1
```jsx

Read more »

前言

写这篇文章的起因是由于之前的一篇关于Kafka异常消费,当时为了解决问题不得不使用临时的方案。

总结起来归根结底还是对Kafka不熟悉导致的,加上平时工作的需要,之后就花些时间看了Kafka相关的资料。

何时使用MQ

谈到Kafka就不得不提到MQ,是属于消息队列的一种。作为一种基础中间件在互联网项目中有着大量的使用。

一种技术的产生自然是为了解决某种需求,通常来说是以下场景:

  • 需要跨进程通信:B系统需要A系统的输出作为输入参数。
  • 当A系统的输出能力远远大于B系统的处理能力。

针对于第一种情况有两种方案:

  • 使用RPC远程调用,A直接调用B。
  • 使用MQ,A发布消息到MQ,B订阅该消息。

当我们的需求是:A调用B实时响应,并且实时关心响应结果则使用RPC,这种情况就得使用同步调用。

Read more »

1

前言

看过 应用限流的朋友应该知道,限流的根本目的就是为了保障服务的高可用。

本次再借助SpringCloud中的集成的Hystrix组件来谈谈服务容错。

其实产生某项需求的原因都是为了解决某个需求。当我们将应用进行分布式模块部署之后,各个模块之间通过远程调用的方式进行交互(RPC)。拿我们平时最常见的下单买商品来说,点击下单按钮的一瞬间可能会向发送的请求包含:

  • 请求订单系统创建订单。
  • 请求库存系统扣除库存。
  • 请求用户系统更新用户交易记录。

这其中的每一步都有可能因为网络、资源、服务器等原因造成延迟响应甚至是调用失败。当后面的请求源源不断的过来时延迟的资源也没有的到释放,这样的堆积很有可能把其中一个模块拖垮,其中的依赖关系又有可能把整个调用链中的应用Over最后导致整个系统不可能。这样就会产生一种现象:雪崩效应

之前讲到的限流也能起到一定的保护作用,但还远远不够。我们需要从各个方面来保障服务的高可用。

比如:

  • 超时重试。
  • 断路器模式。
  • 服务降级。
    等各个方面来保障。
Read more »

封面

前言

最近线上遇到一个问题:在消费kafka消息的时候如果长时间(大概半天到一天的时间)队列里没有消息就可能再也消费不了。针对这个问题我们反复调试多次。线下模拟,调整代码,但貌似还是没有找到原因。但是只要重启消费进程就又可以继续消费。

解决方案

由于线上业务非常依赖kafka的消费,但一时半会也没有找到原因,所以最后只能想一个临时的替换方案:

基于重启就可以消费这个特点,我们在每次消费的时候都记下当前的时间点,当这个时间点在十分钟之内都没有更新我们就认为当前队列中没有消息了,就需要重启下消费进程。

既然是需要重启,由于目前还没有上分布式调度中心所以需要crontab来配合调度:每隔一分钟会调用一个shell脚本,该脚本会判断当前进程是否存在,如果存在则什么都不作,不存在则启动消费进程。

Read more »

pexels-photo-306198.jpeg

前言

在一个高并发系统中对流量的把控是非常重要的,当巨大的流量直接请求到我们的服务器上没多久就可能造成接口不可用,不处理的话甚至会造成整个应用不可用。

比如最近就有个这样的需求,我作为客户端要向kafka生产数据,而kafka的消费者则再源源不断的消费数据,并将消费的数据全部请求到web服务器,虽说做了负载(有4台web服务器)但业务数据的量也是巨大的,每秒钟可能有上万条数据产生。如果生产者直接生产数据的话极有可能把web服务器拖垮。

对此就必须要做限流处理,每秒钟生产一定限额的数据到kafka,这样就能极大程度的保证web的正常运转。

其实不管处理何种场景,本质都是降低流量保证应用的高可用。

常见算法

对于限流常见有两种算法:

  • 漏桶算法
  • 令牌桶算法

漏桶算法比较简单,就是将流量放入桶中,漏桶同时也按照一定的速率流出,如果流量过快的话就会溢出(漏桶并不会提高流出速率)。溢出的流量则直接丢弃。

如下图所示:

漏桶算法,来自网络.png

Read more »

pexels-photo-9046.jpg

前言

之前看过SSM(十四) 基于annotation的http防重插件的朋友应该记得我后文说过之后要用SpringBoot来进行重构。

这次采用自定义的starter的方式来进行重构。

关于starter(起步依赖)其实在第一次使用SpringBoot的时候就已经用到了,比如其中的:

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

我们只需要引入这一个依赖SpringBoot就会把相关的依赖都加入进来,自己也不需要再去担心各个版本之间的兼容问题(具体使用哪个版本由使用的spring-boot-starter-parent版本决定),这些SpringBoot都已经帮我们做好了。

01.jpg


Read more »

pexels-photo-516961.jpeg

前言

上一篇简单入门了SpringBoot+SpringCloud 构建微服务。但只能算是一个demo级别的应用。
这次会按照实际生产要求来搭建这套服务。

Swagger应用

上次提到我们调用自己的http接口的时候采用的是PostMan来模拟请求,这个在平时调试时自然没有什么问题,但当我们需要和前端联调开发的时候效率就比较低了。

通常来说现在前后端分离的项目一般都是后端接口先行。

后端大大们先把接口定义好(入参和出参),前端大大们来确定是否满足要求,可以了之后后端才开始着手写实现,这样整体效率要高上许多。

但也会带来一个问题:在接口定义阶段频繁变更接口定义而没有一个文档或类似的东西来记录,那么双方的沟通加上前端的调试都是比较困难的。

基于这个需求网上有各种解决方案,比如阿里的rap就是一个不错的例子。

但是springCould为我们在提供了一种在开发springCloud项目下更方便的工具swagger

实际效果如下:

01.png

Read more »

00.jpeg

前言

随着互联网的兴起,现在三高(高可用、高性能、高并发)项目是越来越流行。

本次来谈谈高并发。首先假设一个业务场景:数据库中有一条数据,需要获取到当前的值,在当前值的基础上+10,然后再更新回去。
如果此时有两个线程同时并发处理,第一个线程拿到数据是10,+10=20更新回去。第二个线程原本是要在第一个线程的基础上再+20=40,结果由于并发访问取到更新前的数据为10,+20=30

这就是典型的存在中间状态,导致数据不正确。来看以下的例子:

并发所带来的问题

和上文提到的类似,这里有一张price表,表结构如下:

1
2
3
4
5
6
7
CREATE TABLE `price` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',
`total` decimal(12,2) DEFAULT '0.00' COMMENT '总值',
`front` decimal(12,2) DEFAULT '0.00' COMMENT '消费前',
`end` decimal(12,2) DEFAULT '0.00' COMMENT '消费后',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1268 DEFAULT CHARSET=utf8
Read more »