go语言能做什么?
很多朋友可能知道Go语言的优势在哪,却不知道Go语言适合用于哪些地方。
1、 Go语言作为服务器编程语言,很适合处理日志、数据打包、虚拟机处理、文件系统、分布式系统、数据库代理等;网络编程方面。Go语言广泛应用于Web应用、API应用、下载应用等;除此之外,Go语言还可用于内存数据库和云平台领域,目前国外很多云平台都是采用Go开发。
2、 其实Go语言主要用作服务器端开发。其定位是用来开发"大型软件"的,适合于很多程序员一起开发大型软件,并且开发周期长,支持云计算的网络服务。Go语言能够让程序员快速开发,并且在软件不断的增长过程中,它能让程序员更容易地进行维护和修改。它融合了传统编译型语言的高效性和脚本语言的易用性和富于表达性。
3、 Go语言成功案例。Nsq:Nsq是由Go语言开发的高性能、高可用消息队列系统,性能非常高,每天能处理数十亿条的消息;
4、 Docker:基于lxc的一个虚拟打包工具,能够实现PAAS平台的组建。
5、 Packer:用来生成不同平台的镜像文件,例如VM、vbox、AWS等,作者是vagrant的作者
6、 Skynet:分布式调度框架。
7、 Doozer:分布式同步工具,类似ZooKeeper。
8、 Heka:mazila开源的日志处理系统。
9、 Cbfs:couchbase开源的分布式文件系统。
10、 Tsuru:开源的PAAS平台,和SAE实现的功能一模一样。
11、 Groupcache:memcahe作者写的用于Google下载系统的缓存系统。
12、 God:类似redis的缓存系统,但是支持分布式和扩展性。
13、 Gor:网络流量抓包和重放工具。
以上的就是关于go语言能做什么的内容介绍了。
golang实现本地延迟队列
有个服务会大量使用延迟消息,进行事件处理。随着业务量不断上涨。在晚间、节假日等流量高峰期消息延迟消息队列限流会导致事件丢失,影响业务。与下游沟通后给上调到了最大限流值,问题依然存在,于是决定自己搞一套降级方案。
下游服务触发限流时,能降级部分流量到本地延迟队列,把业务损失降到最低。
本地延迟队列承接部分mq流量
流程如下:
1. 使用zset 存储延迟消息,其中:score为执行时间,value为消息体
2. 启动协程轮询zset,获取score最小的10条数据,协程执行间隔时间xs
如果最小分值小于等于当前时间戳,则发送消息
若最小分值大于当前时间戳,sleep等待执行
需要对key进行hash,打散到多个分片中,避免大key和热key问题,官方大key定义
因此,需保证每个key中value数量n5000,单个value大小不超过 10240/n kb
假设承接10w qps,如何处理?
10w qps延迟120s时,最开始消息队列会积累100000*120=12000000条消息
假如每条消息大小500b,需占用存储6000000kb = 6000Mb = 6GB
为避免大key问题,每个zset存放4000个元素,需要哈希到3000(3000是key的数量,可配置)个zset中。
整个集群假设500台实例,每个处理qps平均在200左右。
单实例消费能力计算:
遍历每个zset,针对每个zset起goroutine处理,此示例中需要 起3000个
但是每秒能处理成功的只有200个,其他都在空跑
综上:
将redis key分片数n和每次处理的消息数m进行动态配置,便于调整
当流量上涨时,调大分片数n和单实例单分片并发数m即可,假如消费间隔200ms,集群处理能力为n*m*5 qps
n = (qps * 120) / 4000
若qps=q,则计算公式如下
zadd = q
zRange = 500 * 5 * n / 500
zRemove = q
setNx = 500 * 5 * n
若10w qps,则
读qps = 15000 + 500*3000*5 =7515000,写 20w
pros
redis 读写性能好,可支持较大并发量,zrange可直接取出到达执行时间的消息
cons
redis 大key问题导致对数据量有一定的限制
分片数量扩缩容会漏消费,会导致事件丢失,业务有损
key分片数量过多时,redis读写压力较大
机器资源浪费,3000个协程,单实例同一秒只有200个针对处理,其他都在空跑
流程如下:
使用带缓冲的channel来实现延迟队列,channel中存放的数据为消息体(包括执行时间),channel能保证先进先出
从channel中取出数据后,判断是否到达执行时间
到达,同步发送mq
未到达,sleep 剩余执行时间,然后再次执行
从channel读出的数据如果未到达执行时间,无法再次放入channel中,需要协程sleep(执行时间-当前时间)
10w qps延迟120s时,最开始消息队列会积累100000*120=12000000条消息,假设每条消息大小500b,需要6G存储空间
channel 大小 = (qps*120)/ c , c=集群实例数,c=500 = channel大小为24000,占用12M内存
要处理10w qps,分摊到每个机器的处理速度为 100000/500 = 200,假设单协程处理10qps,开20个即可。
pros:
本地存储,相比redis,读写速度更快;协程数量少,开销低;资源利用率较方案一高
cons:
稳定性不如redis,实例故障可能导致数据丢失;worker池和channel扩缩容依赖服务重启,成本高速度慢
综上,我们以10w qps为例,对比两种方案在以下指标差异,选择方案二。
附上demo
nsq介绍和使用
最近一直在寻找一个高性能,高可用的消息队列做内部服务之间的通讯。一开始想到用zeromq,但在查找资料的过程中,意外的发现了Nsq这个由golang开发的消息队列,毕竟是golang原汁原味的东西,功能齐全,关键是性能还不错。其中支持动态拓展,消除单点故障等特性, 都可以很好的满足我的需求
下面上一张Nsq与其他mq的对比图,看上去的确强大。下面简单记录一下Nsq的使用方法
图片来自golang2017开发者大会
在使用Nsq服务之前,还是有必要了解一下Nsq的几个核心组件
整个Nsq服务包含三个主要部分
先看看官方的原话是怎么说:
nsqlookupd是守护进程负责管理拓扑信息。客户端通过查询 nsqlookupd 来发现指定话题(topic)的生产者,并且 nsqd 节点广播话题(topic)和通道(channel)信息
简单的说nsqlookupd就是中心管理服务,它使用tcp(默认端口4160)管理nsqd服务,使用http(默认端口4161)管理nsqadmin服务。同时为客户端提供查询功能
总的来说,nsqlookupd具有以下功能或特性
官方原话:是一套 WEB UI,用来汇集集群的实时统计,并执行不同的管理任务
总的来说,nsqadmin具有以下功能或特性
nsqadmin默认的访问地址是
官方原话:nsqd 是一个守护进程,负责接收,排队,投递消息给客户端
简单的说,真正干活的就是这个服务,它主要负责message的收发,队列的维护。nsqd会默认监听一个tcp端口(4150)和一个http端口(4151)以及一个可选的https端口
总的来说,nsqd 具有以下功能或特性
这是官方的图,第一个channel(meteics)因为有多个消费者,所以触发了负载均衡机制。后面两个channel由于没有消费者,所有的message均会被缓存在相应的队列里,直到消费者出现
这里想到一个问题是,如果一个channel只有生产者不停的在投递message,会不会导致服务器资源被耗尽?也许nsqd内部做了相应处理,但还是要避免这种情况的出现
了解nsqlookupd,nsqd与客户端中消费者和生产者的关系
消费者有两种方式与nsqd建立连接
生产者必须直连nsqd去投递message(网上说,可以连接到nsqlookupd,让nsqlookupd自动选择一个nsqd去完成投递,但是我用Producer的tcp是连不上nsqlookupd的,不知道http可不可以…),
这里有一个问题就是如果生产者所连接的nsqd炸了,那么message就会投递失败,所以在客户端必须自己实现相应的备用方案
执行完后检查godep是否已经安装在bin目录下,一般都会自动安装,如果没有,用go install手动安装下
如果安装成功,bin目录里就会出现一大堆nsq_…开头的可执行文件
nsqd是一个独立的服务,启动一个nsqd就可以完成message的收发,启动一个单机的nsqd,很简单
客户端可以使用http,也可以使用tcp,这里我使用是官方的go-nsq包做客户端,使用tcp进行message的收发
//Nsq发送测试
//Nsq接收测试
Go语言使用NSQ消息队列
重点提示:
这样我们就启动了一个 nsqd 的实例
编写一个消息生产者
nsq_single_product.go
编写一个消息消费者
nsq_single_consumer.go
添加第一个实例
添加第二个实例
消息生产者
nsq_cluster_product.go
消息消费者
nsq_cluster_consumer.go