回顾:

  以前一直是C++开发(客户端),最近听同事讲go语言不错,随后便决定先从go语法开始投向go的怀抱。由于历史原因学习go语法时,用了半天的时间看完了菜鸟教程上相关资料,后来又看了易百教程上的一些实例代码,感觉都比较简单,毕竟还是有C++基础存在的。。。但是找工作大多都是需要工作经验的,那么怎么办才好呢!后来在知乎上看到有一位大神推荐看NSQ和skynet开源框架,权衡之下我决定从NSQ开始学习,进入我的go学习之路。

  要学习NSQ,首先就是上www查找相关NSQ的资料,没想到百度一下相关资料还是挺多,有好几个网友的博客都写的不错,思路比较清晰,但是基本都没有完全的把NSQ分析下来,只能后边继续等待了。文章末尾我会把自己觉着可以帮助理解的文章链接贴上。

  本篇文章我不打算直接开始分析NSQ框架代码,而是想从一些零散的地方着手,针对性的讲NSQ,这样有利于后期我们逐模块分析NSQ源码。

  下边就开始我们文本的中心内容,文章结构是按点划分,会比较零散但都是个人在看NSQ源码时的心得,也可以说是个人觉得比较难理解的地方吧,看NSQ之前,只学习了go语法2天时间,因此文中可能会涉及到一些基础性错误,欢迎大家指正。

一、NSQ部署

  我个人电脑是win10 64位,因此在这儿我就给出一个网友写好的Windows下NSQ部署文章NSQ如何在windows上安装,安装网友的文章说明我的测试结果图1所示,当启动nsqd连接nsqlookupd时,会有相应的提示,启动nsq_to_file进程时,会往nsqd写入消息都有相应提示,如图1中用红色矩形框选中的是对于的关键提示信息。

图1 NSQ部署测试

  打开浏览器直接输入http://127.0.0.1:4171/就可以查看NSQ运行情况

二、NSQ拓扑图

  通过第一小节,我们简单的把NSQ部署起来,并看到了NSQ的运行情况,还记得我们启动各个进程的步骤吗,不记得没关系,看图2所示,该图是出自nsq源码分析之概述,个人觉着这幅图对NSQ总结的非常好,从图中我们可以了解到下面几个点

  • nsqlookupd进程同时开启tcp和http两个监听服务,TCP监听是用于NSQD进程连接,http监听是用于提供给nsqadmin获取集群信息
  • nsqadmin进程只开启http服务,其实就是一个web服务,提供给客户端查询集群信息
  • nsqd进程同时开启tcp和http服务,TPC监听和http监听都提供给生产者和消费者连接,http服务还提供给nsqadmin获取该nsqd本地信息
  • nsqd连接到nsqlookupd的tcp监听上,通过心跳告诉nsqlookupd自己在线
  • writer是生产者,直接连接nsqd
  • reader是消费者,直接连接nsqd

图2 NSQ拓扑图

  了解了nsq的整体结构后,我们就可以开始按模块分析nsq的源码

三、NSQ启动与退出

  nsq优雅的启动与退出使用了SVC包,推荐阅读Nsq源码阅读(1) 启动和优雅退出,这篇文章讲解的非常详细。

四、全局唯一messageid

  Nsq源码阅读(6) 全局唯一messageid

五、NSQ同步

  NSQ中简单包装了sync.WaitGroup,包装后的待执行函数都会在轻量级的线程中执行,代码如下所示。主线程中启动了多个子线程后,只有等启动的多个子线程结束后主线程才能结束,方法Wrap中的Add和Done调用分别会维护一个引用计数,只有当该引用计数为0时,主线程才会结束等待

 //如果结构体S,包含一个匿名字段T,那么这个结构体S 就有了T的方法。
type WaitGroupWrapper struct {
sync.WaitGroup
} func (w *WaitGroupWrapper) Wrap(cb func()) {
w.Add() //sync.WaitGroup结构中方法
go func() {
cb()
w.Done() //sync.WaitGroup结构中方法
}()
}

六、Go接口

  Go语言式的接口,就是不用显示声明类型T实现了接口I,只要类型T的公开方法完全满足接口I的要求,就可以把类型T的对象用在需要接口I的地方。比如nsqlookupd.go文件中Main函数最后启动http监听服务时代码

 l.Lock()
l.httpListener = httpListener //把Listener存在NSQLookupd的struct里
l.Unlock()
//创建httpServer的实例,httpServer在nsqlookupd\http.go文件中定义
httpServer := newHTTPServer(ctx)
//调用http_api.Serve方法(在http_api\http_server.go中定义)开始在指定的httpListener上接收http连接。
l.waitGroup.Wrap(func() {
//因为httpServer结构重写了http.Handler接口类的ServeHTTP方法,因此可以当http.Handler使用
http_api.Serve(httpListener, httpServer, "HTTP", l.opts.Logger)
})

  代码第9行调用中的第二个参数httpServer,是一个自定义的struct,而http_apit.Serve需要的参数类型为http.Handler,因为httpServer实现了http.Handler接口类中的接口,因此可以在这个地方使用,对每一个类型实现接口方法如下

 func (s *httpServer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
s.router.ServeHTTP(w, req)
}

七、NSQD心跳

  NSQD作为消息接收、转发者,他也是nsqlookupd的客户端,当nsqd启动时,除过自己启动tcp和http服务等待生产者和消费者连接外,还需要作为client连接到nsqlookupd。在nsqd.go文件的Main函数最后,通过waitGroup启动了3个线程,如下代码所示,第2行代码启动了一个lookupLoop循环,该循环是一个死循环,其中有一项功能就是发送心跳值,告诉所有的nsqlookupd,自己还活着。

 n.waitGroup.Wrap(func() { n.queueScanLoop() }) //循环处理消息的分发
n.waitGroup.Wrap(func() { n.lookupLoop() }) //同步nsqd状态到nsqlookup比如:在线、Topic变化、Channel变化等
if n.getOpts().StatsdAddress != "" {
n.waitGroup.Wrap(func() { n.statsdLoop() })
}

  心跳发送代码在lookup.go文件中,处理方式如下

 case <-ticker: //发送心跳  告诉nsqlookup自己在线
// send a heartbeat and read a response (read detects closed conns)
for _, lookupPeer := range lookupPeers {
n.logf("LOOKUPD(%s): sending heartbeat", lookupPeer)
cmd := nsq.Ping()
_, err := lookupPeer.Command(cmd)
if err != nil {
n.logf("LOOKUPD(%s): ERROR %s - %s", lookupPeer, cmd, err)
}
}

  nsqlookupd作为服务器端,启动时就开启了tcp监听,每接受一个nsqd连接,就使用go开启一个handle处理函数,最终和客户端(nsqd)交互功能代码在LookupProtocolV1文件中完成。

  此时我们在看图2的NSQ拓扑图,说过了nsqd作为client链接nsqlookupd服务器端后,我们在顺道说下nsqd开启tcp监控作为服务器时有哪些是客户端,此时的client包括:生产者和消费者,即图中的writer和reader。

八、Decorator装饰器

  先看下NSQ源码中对Decorator定义,其实就是一个函数的嵌套定义,源码位置在internal/http_api/api_response.go文件中,代码如下:

 type Decorator func(APIHandler) APIHandler

 type APIHandler func(http.ResponseWriter, *http.Request, httprouter.Params) (interface{}, error)

  下边我们来看两个关于Decorate的使用

 func Decorate(f APIHandler, ds ...Decorator) httprouter.Handle {
decorated := f
for _, decorate := range ds {
decorated = decorate(decorated)
}
return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
decorated(w, req, ps)
}
} func Log(l app.Logger) Decorator { //Logger是go对应的log4版本
return func(f APIHandler) APIHandler {
return func(w http.ResponseWriter, req *http.Request, ps httprouter.Params) (interface{}, error) {
start := time.Now() //当前时间
response, err := f(w, req, ps) //执行http请求 err错误状态 response处理结果
elapsed := time.Since(start) //f(APIHandler)调用时长
status :=
if e, ok := err.(Err); ok {
status = e.Code //重置错误码
}
l.Output(, fmt.Sprintf("%d %s %s (%s) %s",
status, req.Method, req.URL.RequestURI(), req.RemoteAddr, elapsed)) //输出http处理日志信息
return response, err //返回一个接口 和错误状态
}
}
}

  首先先来看下代码第一行定义的Decorate函数,这个函数其实就是一个装饰函数,第一个参数为需要被装饰的视图函数,从第二参数开始,都是装饰函数,最后返回装饰好的视图函数。

  第11行代码定义了一个Log函数,返回值为Decorator类型,也就是代码第12行return后边的表达式,该表达式也是一个函数定义,其返回值为APIHandler,第13行代码return后边的表达式为其返回值。

相关资料

  NSQ如何在windows上安装

  nsq源码阅读笔记之nsqd:hurray123CSDN

  go语言nsq源码解读-基本介绍:熊窝窝

  Nsq源码阅读:胖梁的技术笔记

  nsq源码分析之概述:罗道文的私房菜

如果您觉得文章不错,不妨给个打赏,写作不易,感谢各位的支持。您的支持是我最大的动力,谢谢!!! 

 

很重要--转载声明

  1. 本站文章无特别说明,皆为原创,版权所有,转载时请用链接的方式,给出原文出处。同时写上原作者:朝十晚八 or Twowords
  2. 如要转载,请原文转载,如在转载时修改本文,请事先告知,谢绝在转载时通过修改本文达到有利于转载者的目的。

NSQ之粗读浅谈的更多相关文章

  1. [UWP]浅谈按钮设计

    一时兴起想谈谈UWP按钮的设计. 按钮是UI中最重要的元素之一,可能也是用得最多的交互元素.好的按钮设计可以有效提高用户体验,构造让人眼前一亮的UI.而且按钮通常不会影响布局,小小的按钮无论怎么改也不 ...

  2. 浅谈CDN、SEO、XSS、CSRF

    CDN 什么是CDN 初学Web开发的时候,多多少少都会听过这个名词->CDN. CDN在我没接触之前,它给我的印象是用来优化网络请求的,我第一次用到CDN的时候是在找JS文件时.当时找不到相对 ...

  3. 【微信小程序项目实践总结】30分钟从陌生到熟悉 web app 、native app、hybrid app比较 30分钟ES6从陌生到熟悉 【原创】浅谈内存泄露 HTML5 五子棋 - JS/Canvas 游戏 meta 详解,html5 meta 标签日常设置 C#中回滚TransactionScope的使用方法和原理

    [微信小程序项目实践总结]30分钟从陌生到熟悉 前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05- ...

  4. 浅谈Hybrid技术的设计与实现第三弹——落地篇

    前言 接上文:(阅读本文前,建议阅读前两篇文章先) 浅谈Hybrid技术的设计与实现 浅谈Hybrid技术的设计与实现第二弹 根据之前的介绍,大家对前端与Native的交互应该有一些简单的认识了,很多 ...

  5. 浅谈Android应用保护(一):Android应用逆向的基本方法

    对于未进行保护的Android应用,有很多方法和思路对其进行逆向分析和攻击.使用一些基本的方法,就可以打破对应用安全非常重要的机密性和完整性,实现获取其内部代码.数据,修改其代码逻辑和机制等操作.这篇 ...

  6. Android应用安全开发之浅谈加密算法的坑

      <Android应用安全开发之浅谈加密算法的坑> 作者:阿里移动安全@伊樵,@舟海 阿里聚安全,一站式解决应用开发安全问题     Android开发中,难免会遇到需要加解密一些数据内 ...

  7. 浅谈Linux中的信号处理机制(二)

    首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...

  8. 浅谈Oracle事务【转载竹沥半夏】

    浅谈Oracle事务[转载竹沥半夏] 所谓事务,他是一个操作序列,这些操作要么都执行,要么都不执行,是一个不可分割的工作单元.通俗解释就是事务是把很多事情当成一件事情来完成,也就是大家都在一条船上,要 ...

  9. 浅谈大型web系统架构

    动态应用,是相对于网站静态内容而言,是指以c/c++.php.Java.perl..net等服务器端语言开发的网络应用软件,比如论坛.网络相册.交友.BLOG等常见应用.动态应用系统通常与数据库系统. ...

随机推荐

  1. SpringCloud学习笔记(3)——Hystrix

    参考Spring Cloud官方文档第13.14.15章 13. Circuit Breaker: Hystrix Clients Netflix提供了一个叫Hystrix的类库,它实现了断路器模式. ...

  2. Caddy服务器搭建和实现文件共享

    1:Caddy介绍 作为新兴 Web 服务器,Caddy 提供了很多简单易用的功能而没有历史的包袱,其默认支持并且能帮你自动配置 HTTP/2.HTTPS,对于 IPV6.WebSockets 都有很 ...

  3. var a=function(){...}与function a(){...}的区别

    var a = function(){...}在js预加载时按变量处理,即预加载定义,不加载赋值. function a(){...}即加载定义,而且赋值. 例如:a(); //正常执行a()函数; ...

  4. ConcurrentHashMap\HashMap put操作时key为什么要rehash

    参考java并发编程的艺术一书中,对ConcurrentHashMap的讲解 ConcurrentHashMap使用的是分段锁Segment来保证不同的Segment区域互相不干扰,不存在锁竞争关系, ...

  5. java 之 命令模式(大话设计模式)

    命令模式,笔者一直以为当我们开发的过程中基本上很难用到,直到维护阶段或者重构阶段,我们会发现有些撤销命令和追加命令比较频繁时,自然而然就用到命令模式. 先看下类图 大话设计模式-类图 简单说下类图,最 ...

  6. Sagit.Framework For IOS 开发框架入门教程3:Start引导页及框架布局和隐藏事件的内幕

    前言: 框架依旧在快速更新着:在重构.简化代码,统一标准的过程中. 中间也遇到各种坑,不过好在一步一脚印的解决了. 虽然还有些功能还在思考,不过教程,还是得补上: 上篇文章:Sagit.Framewo ...

  7. day8、 显示Linux路由表、各列信息

    要用到的命令是 route route 命令    显示和设置Linux路由表 -A:设置地址类型: -C:打印将Linux核心的路由缓存: -v:详细信息模式: -n:不执行DNS反向查找,直接显示 ...

  8. 移动端 cursor:pointer问题

    之前一直没有注意过,为元素设置上cursor:pointer属性后,会导致元素点击时出现一个蓝色的背景. 为元素设置-webkit-tap-highlight-color: transparent;可 ...

  9. [Maven实战](7)坐标

    1. 简单介绍 maven的世界中拥有数量很巨大的构件,也就是平时用的一些jar,war等文件. 在maven为这些构件引入坐标概念之前,我们无法使用不论什么一种方式来唯一标识全部这些构件. 因此,当 ...

  10. 简单了解Markdown

    在Github的readme.md文件的编辑中,開始渐渐的接触Markdown.如今简单系统叙述一下Markdown的语法. Markdown是一种能够使用普通文本编辑器编写的标记语言.通过类似HTM ...