const kafka = require('kafka-node');
let conn = {'kafkaHost':'10.10.0.21:9092'}; //ip和端口
let consumers = [
{
'type': 'consumer',
'options': {'autoCommit': true},
'name':'common',
'topic':[
//修改topic
{'topic': 'data_output', 'partition': 0}
]
}
];
let MQ = function(){
}
MQ.prototype.AddConsumer = function (conn, topics, options, handler){
let client = new kafka.KafkaClient(conn);
let consumer = new kafka.Consumer(client, topics, options);
if(!!handler){
consumer.on('message', handler);
}
consumer.on('error', function(err){
console.error('consumer error ',err.stack);
});
}
var mq = new MQ();
mq.AddConsumer(conn, consumers[0].topic, consumers[0].options, function (message){
console.log(message.value);
});
docker网段的更改方法
在一些云主机上运行docker的时候,会发现docker占用的网段与其他云主机网段(比如VPS代理等)冲突,这个时候就需要对docker占用的网段进行更改。以腾讯云CVM Tencent tlinux release 2.2 (tkernel3)为例,主要步骤如下:
1.docker network ls 查看docker网络
2.docker network rm [NETOWRK ID]删除发生冲突的网络,全部删除也可以。部分网络会提示报错删除不了,没关系,忽略;
3.vi /etc/docker/daemon.json,新增如下内容
{
"bip":"192.168.100.1/24"
}
4. service docker restart 重启docker daemon。
5.docker run重新运行容器,会发现容器IP已经为192.168.100网段。变更完成。
js获取鼠标位置的HMTL元素
在图形化的网络爬虫软件中,都会集成一个chrome内容的浏览器,用于配置爬虫流程和需要采集的数据。它通过使用代理或者chrome插件的方式,向chrome获取的html代码中注入javascript代码,javascript代码中,阻止正常的鼠标点击和键盘事件,根据鼠标位置获取HTML元素并与windows软件交互。在这个过程中需要解决三个问题:javascript如何注入?如何写js阻止鼠标键盘事件?如何根据鼠标位置获取html元素并且与Windows软件通信?
- javascript的注入
1.1 通过代理注入
这里的代理,不严谨的说,就是请求和应答的中转方,它先获得真实web服务器的应答,修改后再发给真实的web客户端。因为代理有修改应答的机会,所以它可以随意修改html代码,往其中注入任意代码,自然也可以注入javascript。
1.2 通过chrome插件注入
chrome扩展运行在chrome浏览器中,用于扩展chrome功能,也可以做到任意更改html代码,常用的adblock等插件,都是通过对页面html代码的删改实现的。通过插件往html注入代码最简单的实现如下:const theScript = document.createElement('script');
theScript.innerHTML = '"your code here"';//注入的javascript代码
document.body.appendChild(theScript);
这样之后,注入的javascript代码就成为html的一部分。
1.3 通过iframe注入
将需要爬取的页面设置为一个iframe的src属性值,这样就可以将目标页面嵌入到一个网页中,然后就可以在网页的javascript代码中往目标页面嵌入javascript代码,样例如下:var original_html=”hello,world”
var inject_script=’’
var html_src=’data:text/html;charset=utf-8’+encodeURI(html+inject_script)
iframe.src=html_src - javascript阻止鼠标和键盘事件
修改window对象的事件响应函数,可以打一些简单的日志,然后全部停止掉事件的继续流转。function ec_click (event){
var elementMouseIsOver = get_current_element(event)
console.log('当前鼠标指向的元素是:', elementMouseIsOver)
event.stopPropagation
} window.onmousemove = ec_click - javascript与windows软件或者其他javascript通信
可以使用WebSocket完成通信,WebSocket相对于HTTP的优势时双向通信,服务器端可以主动给客户端推送消息,消息将被客户端注册的事件处理函数处理。使用websocket可以在javascript与windows软件或其他javascript之间通信,只需要找个linux主机做一个websocket服务器,中转一下消息即可。


利用正则表达式解析zookeeper四字命令输出
zookeeper支持四字命令获取节点的内部状态,所谓的四字命令,就是往zookeeper配置的ip和服务端口发送srvr/ruok之类的字符串,zookeeper返回内部状态的命令。具体的有:
conf:输出相关服务配置的详细信息。比如端口、zk数据及日志配置路径、最大连接数,session超时时间、serverId等。
cons:列出所有连接到这台服务器的客户端连接/会话的详细信息。包括“接受/发送”的包数量、session id 、操作延迟、最后的操作执行等信息
crst:重置当前这台服务器所有连接/会话的统计信息
dump:列出未经处理的会话和临时节点(只在leader上有效)
envi:输出关于服务器的环境详细信息(不同于conf命令),比如host.name、java.version、java.home、user.dir=/data/zookeeper-3.4.6/bin之类信息
ruok:测试服务是否处于正确运行状态。如果正常返回”imok”,否则返回空
srst:重置服务器的统计信息
srvr:输出服务器的详细信息。zk版本、接收/发送包数量、连接数、模式(leader/follower)、节点总数
stat:输出服务器的详细信息:接收/发送包数量、连接数、模式(leader/follower)、节点总数、延迟。 所有客户端的列表
wchs:列出服务器watches的简洁信息:连接总数、watching节点总数和watches总数
wchc:通过session分组,列出watch的所有节点,它的输出是一个与 watch 相关的会话的节点列表。如果watches数量很大的话,将会产生很大的开销,会影响性能,小心使用
wchp:通过路径分组,列出所有的 watch 的session id信息。它输出一个与 session 相关的路径。如果watches数量很大的话,将会产生很大的开销,会影响性能,小心使用
mntr:列出集群的健康状态。包括“接受/发送”的包数量、操作延迟、当前服务模式(leader/follower)、节点总数、watch总数、临时节点总数
现在如果需要在go代码中,通过四字命令获取服务器状态,请求应答的过程比较简单,提取具体数字的过程考验对正则表达式的理解。
[root@VM_15_146_centos ~]# echo srvr | nc 127.0.0.1 2283 Zookeeper version: 3.4.14-4c25d480e66aadd371de8bd2fd8da255ac140bcf, built on 03/06/2019 16:18 GMT Latency min/avg/max: 0/0/56 Received: 7274380 Sent: 7274376 Connections: 4 Outstanding: 0 Zxid: 0x1000002a19 Mode: follower Node count: 23228
上面是执行一次srvr命令得到的输出,我们要从这个字符串(tcp连接读出的[]byte)中解析出版本、构建时间和其他所有指标。
const ( zrVer = `^Zookeeper version: ([A-Za-z0-9\.\-]+), built on (\d\d/\d\d/\d\d\d\d \d\d:\d\d [A-Za-z0-9:\+\-]+)` zrLat = `^Latency min/avg/max: (\d+)/(\d+)/(\d+)` zrNet = `^Received: (\d+).*\n^Sent: (\d+).*\n^Connections: (\d+).*\n^Outstanding: (\d+)` zrState = `^Zxid: (0x[A-Za-z0-9]+).*\n^Mode: (\w+).*\n^Node count: (\d+)` ) re, err := regexp.Compile(fmt.Sprintf(`(?m:\A%v.*\n%v.*\n%v.*\n%v)`, zrVer, zrLat, zrNet, zrState)) matches := re.FindAllStringSubmatch(string(response), -1)
在这些正则表达式中,()扩起的部分,在FindAllStringSubmatch调用中,将会按照二维数组方式返回,自己数是第几个,取到对应的字段。
这个字符串确定只会匹配上一次,因此可以直接使用matches[0]赋值将匹配结果降为一维数组,数组元素就是各个字段的值。
在上面,match[0]是版本号,match[1]是构建时间,以此类推下去。
Fisher–Yates shuffle 洗牌算法 和go-zookeeper库中的代码缺陷
项目中使用到一个golang的zookeeper库,使用过程中遇到一些问题待解决,看看源代码解决。记录下看源代码过程看到的一些内容。这里讲一下看到的第一个内容,该sdk里用到的洗牌算法。
该库的地址为:https://github.com/go-zookeeper/zk
这个算法在这个sdk,主要是避免所有的zookeeper客户端在使用相同的配置文件时,拿到的ip+端口列表都是同样的顺序,大家集中的去访问一个zookeeper节点,zookeeper集群内各个节点负载很不均衡。
看看源代码
// stringShuffle performs a Fisher-Yates shuffle on a slice of strings
func stringShuffle(s []string) {
for i := len(s) - 1; i > 0; i-- {
j := rand.Intn(i + 1)
s[i], s[j] = s[j], s[i]
}
}
很简单的,说人话就是,从最后一个往前,每次都在这个之前及自身随机生成一个下标确定一个元素,交换这两个数。这里注意一点:可能出现自己与自己交换的情况,这也是保证随机性的一个重要原因,否则,就会出现一个很验证的问题,就是某个元素在随机洗牌之后,肯定不会出现在自己原来的位置,这样的话就排除了一大批可能的排列,而不是真正的随机。
在该库的使用过程中,zookeeper集群配置有三个zookeeper节点,我感觉所有客户端仍然会集中的去访问相同的zookeeper节点。
分析原因:
该库的随机算法在调用rand.Intn()函数之前,没有使用任何随机因素进行初始化,可以写代码验证,未初始化的rand.Intn()每次启动,生成的都是相同的随机数。
//测试代码
package main
import (
"fmt"
"math/rand"
)
func main() {
fmt.Println(rand.Intn(30))
}
#!/bin/bash
#测试运行脚本
for i in $(seq 1 10)
do
./rand
sleep 1
done
可以看到所有的输出都是相同的11。所以这个库在这里是有代码缺陷的,或者我看的版本有问题。所有的客户端仍然会集中去访问相同的节点。