Go 语言分布式任务处理器 Machinery -- 架构,源码详解篇
Go 语言分布式任务处理器 Machinery – 架构,源码详解篇
你是否因为一个复杂的分布式并发场景且需要进行任务编排而写了一个逻辑复杂,各种耦合,又臭又长的代码?代码跑起来各种bug 浪费时间精力,其他人也看不懂没法接手?
其实 Go 语言有现成的轮子来辅助你实现复杂的逻辑,让你的代码优美,低耦合,鲁棒性强,少bug。这个就是分布式队列Machinery
本文深度结合源码讲解Machinery的使用方法和需要注意的坑位,让你从根上掌握Machinery的使用方法。
优势我们为什么要使用任务处理器?其实引入一个轮子之前想清楚他的优势是十分必要的,如果不充分了解他的优势那么很可能就为了用而用,很多场景可能使用它反而浪费了系统性能。我们就先来看下Machinery 的优势:
Machinery 支持定义串行,并行 ,延迟,重试,定时等各种任务执行方式,并且你可以在定义好任务执行方式后对多个任务进行编排,调任务整先后完成顺序,他还对数据处理结果进行缓存,处理结果出错可以再次处理,增加程序的鲁棒性。访问结果可以直接查询缓存,提高响应速度:
简化代码:其实简化代码是引入 Machin ...
使用 Maxwell 订阅 MySQL binlog 同步至 Kafka
使用 Maxwell 订阅 MySQL binlog 同步至 Kafka
Maxwell 是一款开源的 MySQL binlog 数据同步工具,它可以实时解析 MySQL binlog,将数据变更事件转换为 JSON 格式,然后推送至 Kafka 等消息队列中。
它是由美国 Zendesk 开源,用 Java 编写的 MySQL 实时抓取软件。实时读取MySQL 二进制日志 Binlog,并生成 JSON 格式的消息,作为生产者发送给 Kafka,Kinesis、RabbitMQ、Redis、Google Cloud Pub/Sub、文件或其它平台的应用程序。
这篇文章尽量简单的描述关键步骤,具体的实践小例子我通过代码来给大家呈现了,我的代码用golang编写包括简单数据插入mysql到触发Maxwell生产信息并通过Kafka消费解析binlog数据代码中都有详细的说明哦
我的代码在这里
Mysql主从复制过程
Master 主库将改变记录,写到二进制日志(binary log)中
Slave 从库向 mysql master 发送 dump 协议,将 master 主库的 bin ...
用 ETCD + NSQ 实现分布式数据分片处理(Golang)
用 ETCD + NSQ 实现分布式数据分片处理(Golang)
数据分片处理是提高服务数据处理速度的重要手段,而多服务分布式数据分片处理则在现代的云服务时代优势性更大,你不但可以通过这样的处理减少单体服务压力,提高数据处理速度,还可以进行服务的 动态横向拓展,在你的服务处理数据有压力时再不进行暂停当前服务的同时对服务进行动态扩展,从而提高处理性能,避免出现数据积压服务处理不及时的重大问题。
为什么要做分布式数据分片处理主要是因为可以动态扩容,试想一个大数据量高并发而且数据量会动态变化的项目你设计的服务不支持横向扩容会出现什么样可怕的问题,数据积压,丢失数据,你这个时候要进行纵向扩容将会导致一段时间数据缺失,用户无法访问,这个是不可容忍的,如果你的服务可以动态扩容,那么你发现数据量过大服务器压力过大时你只要增加一个Pod是不是很开心。
为什么使用ETCD + NSQETCD 本身是一个高可用的集群,保证数据的高可用和一致性。本身提供watch方法快速发现k v 变动从而及时响应且本身效率高广泛使用于服务注册发现等场景。下面是etcd的优势:
完全复制:集群中的每个节点都可以使用完整 ...
高性能 Golang 并发包 -- ant
高性能 Golang 并发包 – ant
接触了很多比较热的并发包和小工具,比如之前我写到的Tunny,Machinery等等,我觉得设计的最好的还是 ant,当然Tunny更轻便,Machinery主打分布式并发处理各自有自身优势,但如果你要选一个单服务进行的生产消费的并发处理包,那一定是 ant。
ant 把很多性能优化都做到了很好,在高并发种容易出现的内存泄露,GC压力等问题都在设计上进行了很好的规避,让性能做到起飞。
下面我通过源码来和大家一起学习下它的一些精彩设计。
程序流程:ant 的主体是pool结构 ,pool结构管理着worker队列,worker是执行任务的最小单位。
生产者不断提交任务给pool,pool 进行任务的调度处理。
下面是整个包工作的流程图:
主体架构整个包设计的主体分为三层最上层是pool 接够,中层是queue结构,底层是worker结构。
处理任务的最小单位是worker 结构,queue其实就一个worker的队列,负责worker的调度和清理等工作,pool是最上层的结构也就是我们接触到的使用结构,pool主要负责并发数量控制,task发 ...
Go 语言分布式缓存 Groupcache -- 用法,源码深度解读
Go 语言分布式缓存 Groupcache – 用法,源码深度解读
groupcache是memcached作者Brad Fitzpatrick的另一kv cache项目,由于作者转 go 并对go语言情有独钟,所以作者本着‘intended as a replacement for memcached in many cases’ 的设计初衷设计了groupcache 。Redis等其他常用cache实现不同,groupcache并不运行在单独的server上,而是作为library和app运行在同一进程中。所以groupcache既是server也是client。
为什用,怎么用?还是老样子,我们先搞清楚为什么要用Groupcache,
Groupcache是一个轻量级的分布式缓存库,他的逻辑非常简单所以保证了他的轻量,但它却可以满足各种缓存中间件的功能,如防击穿,防穿透,防雪崩。我们之后会通过源码来解释他是如何做到这些的。同时因为其简单的逻辑保证其在消耗极少资源的情况下保持高性能。
有利一定会有弊,他在应用上会受一些限制,接下来我们讨论怎么用比较好。
要搞清楚这一点我们需要看下 ...
GMP调度模型
Golang GMP调度模型
Go 语言的Goroutine其实概念和协程是一致的,我们可以称之为有go特色的协程
为了解决多线程调度器的问题,Go 开发者 Dmitry Vyokov 在已有 G、M 的基础上,引入了 P 处理器,由此产生了当前 Go 中经典的 GMP 调度模型。
P:Processor的缩写,代表一个虚拟的处理器,它维护一个局部的可运行的 G 队列,可以通过 CAS 的方式无锁访问,工作线程 M 优先使用自己的局部运行队列中的 G,只有必要时才会去访问全局运行队列,这大大减少了锁冲突,提高了大量 G 的并发性。每个 G 要想真正运行起来,首先需要被分配一个 P。
如图 1.5 所示,是当前 Go 采用的 GMP 调度模型。可运行的 G 是通过处理器 P 和线程 M 绑定起来的,M 的执行是由操作系统调度器将 M 分配到 CPU 上实现的,Go 运行时调度器负责调度 G 到 M 上执行,主要在用户态运行,跟操作系统调度器在内核态运行相对应。
M 是最重要的结构是一个线程的概念系统会为其分配Cpu资源,用来串联内核态和用户态,Goroutinue的具体代码与M绑定 ...
想要写好Go并发不得不掌握的数据结构(4)
想要写好Go并发不得不掌握的数据结构(4)Context如果我们遇到了下面的一些场景,也可以考虑使用 Context:
上下文信息传递 (request-scoped),比如处理 http 请求、在请求处理链路上传递信息;
控制子 goroutine 的运行;
超时控制的方法调用;
可以取消的方法调用。
所以,我们需要掌握 Context 的具体用法,这样才能在不影响主要业务流程实现的时候,实现一些通用的信息传递,或者是能够和其它 goroutine 协同工作,提供 timeout、cancel 等机制。
Context 基本使用方法包 context 定义了 Context 接口,Context 的具体实现包括 4 个方法,分别是 Deadline、Done、Err 和 Value,如下所示:
123456type Context interface { Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key ...
想要写好Go并发不得不掌握的数据结构(3)
想要写好Go并发不得不掌握的数据结构(3)SingleFlightSingleFlight 是 Go 开发组提供的一个扩展并发原语。它的作用是,在处理多个 goroutine 同时调用同一个函数的时候,只让一个 goroutine 去调用这个函数,等到这个 goroutine 返回结果的时候,再把结果返回给这几个同时调用的 goroutine,这样可以减少并发调用的数量。
其实,sync.Once 不是只在并发的时候保证只有一个 goroutine 执行函数 f,而是会保证永远只执行一次,而 SingleFlight 是每次调用都重新执行,并且在多个请求同时调用的时候只有一个执行。它们两个面对的场景是不同的,sync.Once 主要是用在单次初始化场景中,而 SingleFlight 主要用在合并并发请求的场景中,尤其是缓存场景
如果你学会了 SingleFlight,在面对秒杀等大并发请求的场景,而且这些请求都是读请求时,你就可以把这些请求合并为一个请求,这样,你就可以将后端服务的压力从 n 降到 1。尤其是在面对后端是数据库这样的服务的时候,采用 SingleFlight 可以极大 ...
想要写好Go并发不得不掌握的数据结构(2)
想要写好Go并发不得不掌握的数据结构(2)Channel要想了解 Channel 这种 Go 编程语言中的特有的数据结构,我们要追溯到 CSP 模型,学习一下它的历史,以及它对 Go 创始人设计 Channel 类型的影响。CSP 是 Communicating Sequential Process 的简称,中文直译为通信顺序进程,或者叫做交换信息的循序进程,是用来描述并发系统中进行交互的一种模式。CSP 最早出现于计算机科学家 Tony Hoare 在 1978 年发表的论文中(你可能不熟悉 Tony Hoare 这个名字,但是你一定很熟悉排序算法中的 Quicksort 算法,他就是 Quicksort 算法的作者,图灵奖的获得者)。最初,论文中提出的 CSP 版本在本质上不是一种进程演算,而是一种并发编程语言,但之后又经过了一系列的改进,最终发展并精炼出 CSP 的理论。CSP 允许使用进程组件来描述系统,它们独立运行,并且只通过消息传递的方式通信。
Channel 的应用场景Don’t communicate by sharing memory, share memory by ...
想要写好Go并发不得不掌握的数据结构
想要写好Go并发不得不掌握的数据结构Map哈希表(Hash Table)这个数据结构,我们已经非常熟悉了。它实现的就是 key-value 之间的映射关系,主要提供的方法包括 Add、Lookup、Delete 等。因为这种数据结构是一个基础的数据结构,每个 key 都会有一个唯一的索引值,通过索引可以很快地找到对应的值,所以使用哈希表进行数据的插入和读取都是很快的。Go 语言本身就内建了这样一个数据结构,也就是 map 数据类型。
map 的基本使用方法
1map[K]V
其中,key 类型的 K 必须是可比较的(comparable),也就是可以通过 == 和 != 操作符进行比较;value 的值和类型无所谓,可以是任意的类型,或者为 nil。
在 Go 语言中,bool、整数、浮点数、复数、字符串、指针、Channel、接口都是可比较的,包含可比较元素的 struct 和数组,这俩也是可比较的,而 slice、map、函数值都是不可比较的。
那么,上面这些可比较的数据类型都可以作为 map 的 key 吗?显然不是。通常情况下,我们会选择内建的基本类型,比如整数、字符串做 k ...