ZeroMQ的安装和使用

2 篇文章 0 订阅

安装

简单的通过brew 安装:
 通过brew install zeromq 直接安装
使用之前先get : go get github.com/alecthomas/gozmq
安装或者启动的时候遇到的一个问题:

  1. pkg-config: exec: “pkg-config”: executable file not found in $PATH
     解决方法:brew install pkg-config

使用之前先比较下各个MQ:Kafka暂不考虑


TPS:
  ZeroMQ 性能最好,RabbitMQ次之,而ActiveMQ最差
持久化
 ZeroMQ不支持持久化,RabbitMQ,ActiveMQ都支持
技术性
  RabbitMQ功能更全,ActiveMQ次之,ZeroMQ最差RabbitMQ都功能完善,只需会调用即可,ActiveMQ Performance 差,而ZeroMQ可以实现RabbitMQ,但是都得需要我们自己编写,代码量大
并发性
 毫无疑问,作为一个用了算长的一段时间的RabbitMQ,非它莫属,天生为高并发而生的ErLang语言

ZeroMQ基于socket的字节流,消息完整性不需要我们保证,RabbitMQ则需要我们自己控制
使用时间:RabbitMQ>ActiveMQ 而ZeroMQ未学,因而从头学:
  照着offical doc 来吧

Hello World

server 端:	服务器既可以接收消息,也可以回复消息
func main() {
	context, _ := zmq2.NewContext(5)
	soc, _ := context.NewSocket(zmq2.REP)
	defer soc.Close()
	soc.Bind("tcp://*:5555")
	//waitting for msg
	for{
		msg, _ := soc.Recv(0)
		fmt.Println("receive msg:",msg)
		// logic code
		time.Sleep(time.Second)
		//send new msg back to client
		sprintf := fmt.Sprintf("world")
		soc.Send(sprintf,0)
	}
}
client端:
func main() {
	context, _ := zmq4.NewContext()
	socket, _ := context.NewSocket(zmq4.REQ)
	defer socket.Close()
	fmt.Println("connecting to hello world server ...")
	socket.Connect("tcp://localhost:5555")
	for i := 0; i < 10; i++ {
		//send hello
		msg := fmt.Sprintf("hello")
		socket.Send(msg, 0)
		fmt.Println("send msg :", msg)
		//waiting for reply
		reply, _ := socket.Recv(0)
		fmt.Println("[client] receive msg:", reply)
	}
}

结果:
在这里插入图片描述
整个过程是很顺序化的,发送一次会接收一次,很固定的模式
当我们试图发送多次的时候:

	i2, _ := socket.Send(msg, 0)
		fmt.Println(i2)
		send, e := socket.Send(msg+"-test", 0)
		if nil!=e{
			logrus.Errorf("error:%v",e)
			fmt.Println(send)
		}

结果:
在这里插入图片描述
报错了
部分总结:这是请求-响应模式,一次请求对应一次响应,一个循环期间,这对不可以再发送消息,并且因为ZMQ默认不支持持久化,所以当服务器宕机之后,如果想持久化需要手动编写code,依据:

If you kill the server (Ctrl-C) and restart it,
 the client won't recover properly. 
 Recovering from crashing processes isn't quite that easy. 
 Making a reliable request-reply flow is complex enough,既不支持持久化,若想需要build manually```

The REQ-REP socket pair is in lockstep. T
he client issues zmq_send() and then zmq_recv(), 
in a loop (or once if that's all it needs).
 Doing any other sequence (e.g., sending two messages in a row) will result in a return code of -1 from the send or recv call. Similarly, 
 the service issues zmq_recv() and then zmq_send() in that order, as often as it needs to.
当试图发送2条信息的时候回返回-1错误码,这点类似于Java中的SynchronousQueue ,take()和put()是绑定一起的,但是tpc这个性能是最高的,how? 

Now this looks too simple to be realistic,
but ZeroMQ sockets have, as we already learned, superpowers.
You could throw thousands of clients at this server, all at once,
and it would continue to work happily and quickly.
ZeroMQ允许你开放成千上万个server-client pair对

几个特殊的参数:

  Send函数总是能见到一个flag的参数名称,关于这个参数的定义:
  1.ZMQ_DONTWAIT(0) 既以非阻塞的形式发送消息 2.ZMQ_SNDMORE(1)既当一个数据过大的时候,允许数据分成多个message来发送,但是逻辑上应该知道这些message应该合为一个来处理

数据传输类型

ZMQ没有约定数据格式,所以数据格式都需要自个儿控制,与protobuf类似
官方提示关于String 数据,不同语言String 可能结构不同,c 以null字节结尾,而当Python 发送数据的时候zmq可能不会接收到null ----既Py发送string 给C客户端(string不是以null结尾),C客户端不支持这种格式的string,则会发生错误(因此数据通信格式的定义很关键)

模式:

  1. REQ-RESP模式,上面已经写了,既一次请求对应一次响应,中途不可以重复某次操作
  2. PUB-SUB 模式: 发布订阅模式,服务端将数据推送到旗下的客户端set集合,这种模式是单向的,服务端不考虑客户端是否连接,服务端只管发送数据
  3. PUSH-PULL模式:在这种模式下,服务端既可以是服务端也可以是客户端,当bind之后则是push的服务端,而connect之后又可以成为client端
    演示例子:
func main() {
	context, _ := zmq4.NewContext()	//创建包含io的上下文
	socket, _ := context.NewSocket(zmq4.PUB)	//建立一个socket连接,并且指定为publishe
	defer  socket.Close()
	socket.Bind("tcp://*:5556")//绑定端口和ip地址
	socket.Bind("ipc://weather.ipc")
	rand.Seed(time.Now().UnixNano())	//时间种子,与Java中的Random randm=new Random(47)相同
	for{
		//  make values that will fool the boss
		zipCode := rand.Intn(100000)	//可以理解为RabbitMQ中的channel,通过这个channel发送到queue中,,而client只需要订阅这个channel即可
		temperature := rand.Intn(215) - 80
		relhumidity := rand.Intn(50) + 10
		msg := fmt.Sprintf("%d %d %d", zipCode, temperature, relhumidity)
		socket.Send(msg, 0)	//发送消息,官网定义这个消息会入队的形式发送,内部真正调用的是C中的func
		//C.zmq_send(soc.soc, unsafe.Pointer(&d[0]), C.size_t(len(data)), C.int(flags))
	}
}
Client端:
func main() {
	context, _ := zmq4.NewContext()
	socket, _ := context.NewSocket(zmq4.SUB)
	defer socket.Close()
	var temps []string
	var err error
	var temp int64
	total_temp := 0
	filter := "59937"
	// find zipcode
	if len(os.Args) > 1 { // ./wuclient 85678
		filter = string(os.Args[1])
	}
	  Subscribe to just one zipcode (whitefish MT 59937) //
	fmt.Printf("Collecting updates from weather server for %s…\n", filter)
	socket.SetSubscribe(filter)	//可以与RabbitMQ这么理解:通过订阅某个channel,从而与其上的queue绑定了
	socket.Connect("tcp://localhost:5556")
	for i := 0; i < 101; i++ {
		datapt, _ := socket.Recv(0)
		temps = strings.Split(string(datapt), " ")
		temp, err = strconv.ParseInt(temps[1], 10, 64)
		if err == nil {
			total_temp += int(temp)
		}
	}
	fmt.Printf("Average temperature for zipcode %s was %dF \n\n", filter, total_temp/100)
}
	1. 部分总结:**发布订阅模式,订阅的key,我们发现是消息的首个主体,如 a asdddd,通过空格分隔,则订阅的key就是a,具体源码无法看到,因为是native方法,只能猜测并大致验证是这样的**
	2. 提示:**client必须订阅某个主体,这个就跟RabbitMQ中的consumer必须绑定某个queue和routingKey一样,client才能收到消息,并且这种模式下,server只能发不可收,client只能收不可发,并且client可以sub多个server,并且client端启动的时候总是会忽略收到的第一个消息,同时client与server不具有先后顺序,既都能单独存在**
	3. 一个subscriber可以订阅多个publisher,每次调用只会占用1个连接,若收到消息,会以公平的方式交错的接收数据从而自个儿处理
	4. 当一个Publisher无任何Subscriber的时候,消息则会直接丢弃
	5. 从3.x开始,filter分发过滤逻辑交由server端(若使用的是tcp或icp协议)
  1. Channel 模式: 管道模式,在这个模式下每个socket即使服务端也是客户端,用于任务分发和结果收集,由一个server分配任务,clients 消费任务并返回消息,然后server端接收结果
    整体流程比较好理解,Worker连接到任务发生器上,等待任务的产生,完成后将结果发送至结果收集器。如果要以客户端服务端的概念来区分,这里的任务发生器与结果收集器是服务端,而worker是客户端。
    前面说到了这里任务的派发是“公平的”,因为内部采用了LRU的算法来找到最近最久未工作的闲置worker。但是公平在这里是相对的,当任务发生器启动后,第一个连接到它的worker会在一瞬间承受整个任务发生器产生的tasks。

官方的几点建议:

  1. context上下文记得要释放,Java中放在Finally块中,而Go则放在defer中
  2. 不要开启太多的socket连接,因为这些连接通常都在contxt销毁之后才销毁,若创建了太多连接,review code
  3. 如果编写的是多线程相关的,则不要公用同一个socket连接,需要自己手动释放(close),并且在destroy context的时候,send,recv等都会返回error,context的close是个blocking func,会等待所有的socket safelly close之后再close
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ZeroMQ是一个高性能、异步消息传递库,可以在不同的应用程序之间进行快速、可靠的通信。在Linux上安装ZeroMQ可以按照以下步骤进行操作: 1. 下载ZeroMQ的源代码包,可以从官方网站或者GitHub上获取。 2. 解压源代码包,并进入解压后的目录。 3. 执行以下命令安装依赖项: ``` sudo apt-get install libtool pkg-config build-essential autoconf automake ``` 4. 执行以下命令编译和安装ZeroMQ: ``` ./autogen.sh ./configure make sudo make install ``` 5. 安装完成后,可以使用以下命令验证ZeroMQ是否成功安装: ``` ldconfig -p | grep zmq ``` 如果输出中包含类似于`libzmq.so`的信息,则表示安装成功。 引用[1]中的内容是关于在运行ZeroMQ的Java示例代码时,可能需要添加`java.library.path`参数的说明。这个参数用于指定Java虚拟机加载本地库文件的路径。在运行ZeroMQ的Java示例代码时,如果出现`no XXX in java.library.path`的错误,可以按照引用[1]中的说明修改运行脚本,添加`-Djava.library.path`参数,并指定ZeroMQ库文件的路径。 引用[2]中的内容是关于在Linux上配置环境变量的说明。可以通过修改`~/.bashrc`文件来添加环境变量。在这个例子中,通过执行`echo CLASSPATH=/usr/local/share/java/zmq.jar:. >> ~/.bashrc`命令,将`CLASSPATH`环境变量设置为`/usr/local/share/java/zmq.jar:.`,其中`/usr/local/share/java/zmq.jar`是ZeroMQ的Java库文件的路径。 综上所述,要在Linux上安装ZeroMQ,可以按照上述步骤进行操作,并根据需要修改运行脚本和配置环境变量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值