golang并发工具MapReduce降低服务响应时间
来源:脚本之家
时间:2022-12-29 11:12:52 234浏览 收藏
亲爱的编程学习爱好者,如果你点开了这篇文章,说明你对《golang并发工具MapReduce降低服务响应时间》很感兴趣。本篇文章就来给大家详细解析一下,主要介绍一下并发、MapReduce、服务响应,希望所有认真读完的童鞋们,都有实质性的提高。
那么通过什么手段来优化呢?我们首先想到的是通过并发来的方式来处理依赖,这样就能降低整个依赖的耗时,Go基础库中为我们提供了 WaitGroup 工具用来进行并发控制,但实际业务场景中多个依赖如果有一个出错我们期望能立即返回而不是等所有依赖都执行完再返回结果,而且WaitGroup中对变量的赋值往往需要加锁,每个依赖函数都需要添加Add和Done对于新手来说比较容易出错
基于以上的背景,go-zero框架中为我们提供了并发处理工具MapReduce,该工具开箱即用,不需要做什么初始化,我们通过下图看下使用MapReduce和没使用的耗时对比:
相同的依赖,串行处理的话需要200ms,使用MapReduce后的耗时等于所有依赖中最大的耗时为100ms,可见MapReduce可以大大降低服务耗时,而且随着依赖的增加效果就会越明显,减少处理耗时的同时并不会增加服务器压力
并发处理工具MapReduce
MapReduce是Google提出的一个软件架构,用于大规模数据集的并行运算,go-zero中的MapReduce工具正是借鉴了这种架构思想
go-zero框架中的MapReduce工具主要用来对批量数据进行并发的处理,以此来提升服务的性能
MapReduce的用法演示
MapReduce主要有三个参数,第一个参数为generate用以生产数据,第二个参数为mapper用以对数据进行处理,第三个参数为reducer用以对mapper后的数据做聚合返回,还可以通过opts选项设置并发处理的线程数量
场景一:
某些功能的结果往往需要依赖多个服务,比如商品详情的结果往往会依赖用户服务、库存服务、订单服务等等,一般被依赖的服务都是以rpc的形式对外提供,为了降低依赖的耗时我们往往需要对依赖做并行处理
func productDetail(uid, pid int64) (*ProductDetail, error) { var pd ProductDetail err := mr.Finish(func() (err error) { pd.User, err = userRpc.User(uid) return }, func() (err error) { pd.Store, err = storeRpc.Store(pid) return }, func() (err error) { pd.Order, err = orderRpc.Order(pid) return }) if err != nil { log.Printf("product detail error: %v", err) return nil, err } return &pd, nil }
该示例中返回商品详情依赖了多个服务获取数据,因此做并发的依赖处理,对接口的性能有很大的提升
场景二:
很多时候我们需要对一批数据进行处理,比如对一批用户id,效验每个用户的合法性并且效验过程中有一个出错就认为效验失败,返回的结果为效验合法的用户id
func checkLegal(uids []int64) ([]int64, error) { r, err := mr.MapReduce(func(source chan该示例中,如果check过程出现错误则通过cancel方法结束效验过程,并返回error整个效验过程结束,如果某个uid效验结果为false则最终结果不返回该uid
MapReduce使用注意事项
mapper和reducer中都可以调用cancel,参数为error,调用后立即返回,返回结果为nil, error
mapper中如果不调用writer.Write则item最终不会被reducer聚合
reducer中如果不调用writer.Wirte则返回结果为nil, ErrReduceNoOutput
reducer为单线程,所有mapper出来的结果在这里串行聚合
实现原理分析:
MapReduce中首先通过buildSource方法通过执行generate(参数为无缓冲channel)产生数据,并返回无缓冲的channel,mapper会从该channel中读取数据
func buildSource(generate GenerateFunc) chan interface{} { source := make(chan interface{}) go func() { defer close(source) generate(source) }() return source }在MapReduceWithSource方法中定义了cancel方法,mapper和reducer中都可以调用该方法,调用后主线程收到close信号会立马返回
cancel := once(func(err error) { if err != nil { retErr.Set(err) } else { // 默认的error retErr.Set(ErrCancelWithNil) } drain(source) // 调用close(ouput)主线程收到Done信号,立马返回 finish() })在mapperDispatcher方法中调用了executeMappers,executeMappers消费buildSource产生的数据,每一个item都会起一个goroutine单独处理,默认最大并发数为16,可以通过WithWorkers进行设置
var wg sync.WaitGroup defer func() { wg.Wait() // 保证所有的item都处理完成 close(collector) }() pool := make(chan lang.PlaceholderType, workers) writer := newGuardedWriter(collector, done) // 将mapper处理完的数据写入collector for { select { case <-done: // 当调用了cancel会触发立即返回 return case pool <- lang.Placeholder: // 控制最大并发数 item, ok := <-input if !ok { <-pool return } wg.Add(1) go func() { defer func() { wg.Done() <-pool }() mapper(item, writer) // 对item进行处理,处理完调用writer.Write把结果写入collector对应的channel中 }() } }reducer单goroutine对数mapper写入collector的数据进行处理,如果reducer中没有手动调用writer.Write则最终会执行finish方法对output进行close避免死锁
go func() { defer func() { if r := recover(); r != nil { cancel(fmt.Errorf("%v", r)) } else { finish() } }() reducer(collector, writer, cancel) }()在该工具包中还提供了许多针对不同业务场景的方法,实现原理与MapReduce大同小异,感兴趣的同学可以查看源码学习
MapReduceVoid
功能和MapReduce类似但没有结果返回只返回error
Finish
处理固定数量的依赖,返回error,有一个error立即返回
FinishVoid
和Finish方法功能类似,没有返回值
Map
只做generate和mapper处理,返回channel
MapVoid
和Map功能类似,无返回文末
项目地址 https://github.com/zeromicro/go-zero
本文主要介绍了go-zero框架中的MapReduce工具,在实际的项目中非常实用。用好工具对于提升服务性能和开发效率都有很大的帮助,希望本篇文章能给大家带来一些收获,更多关于golang并发MapReduce服务响应的资料请关注golang学习网其它相关文章!
今天关于《golang并发工具MapReduce降低服务响应时间》的内容介绍就到此结束,如果有什么疑问或者建议,可以在golang学习网公众号下多多回复交流;文中若有不正之处,也希望回复留言以告知!
-
417 收藏
-
328 收藏
-
367 收藏
-
221 收藏
-
109 收藏
-
266 收藏
-
188 收藏
-
317 收藏
-
430 收藏
-
451 收藏
-
311 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习
-
- 贤惠的帽子
- 太给力了,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢老哥分享博文!
- 2023-06-18 19:33:29
-
- 优秀的发箍
- 这篇文章内容太及时了,太详细了,很有用,收藏了,关注up主了!希望up主能多写Golang相关的文章。
- 2023-05-09 12:45:39
-
- 多情的狗
- 这篇技术贴出现的刚刚好,很详细,受益颇多,已收藏,关注作者了!希望作者能多写Golang相关的文章。
- 2023-02-27 07:37:34
-
- 雪白的雪糕
- 感谢大佬分享,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,看完之后很有帮助,总算是懂了,感谢楼主分享文章内容!
- 2023-02-07 20:14:59
-
- 安详的西牛
- 写的不错,一直没懂这个问题,但其实工作中常常有遇到...不过今天到这,帮助很大,总算是懂了,感谢老哥分享技术文章!
- 2023-01-25 02:30:32
-
- 直率的夕阳
- 这篇技术文章出现的刚刚好,很详细,写的不错,码起来,关注博主了!希望博主能多写Golang相关的文章。
- 2023-01-05 11:07:48
-
- 义气的眼神
- 太全面了,码起来,感谢楼主的这篇博文,我会继续支持!
- 2023-01-01 04:26:17