通过企业微信构建消息推送服务

之前用server酱的微信消息推送服务,但是最近老抽风,准备换别的推送服务。 目前发现企业微信的应用消息很合适优点不少。个人也可注册使用。 图文消息 mpnews 内容最大支持666K字节 一次可最多发送八条消息,虽然基本都是发单条 可以显示摘要 可以消息免打扰 虽然是企业微信的应用消息,但是通过关注微信插件可以直接在微信app内查看消息。 简单使用 Golang 编写了一个腾讯 Serverless 云函数,实现了类似于server酱的消息推送,GET、POST方式调用均可。 腾讯云函数目前每月都有免费额度个人完全够用了,API网关新开会送一年资源包也是够用完全白嫖。可以绑定自有域名,选择香港区域,不用备案。 一年到期之后,可以转战阿里云。代码很简单,改改也可以直接docker部署。 详见GitHub wx-msg-push-tencent

March 15, 2021 · 1 min · 18 words · Nick

nps 内网穿透

nps 是一款轻量级、高性能、功能强大的内网穿透代理服务器。目前支持 tcp、udp 流量转发,可支持任何 tcp、udp 上层协议(访问内网网站、本地支付接口调试、ssh 访问、远程桌面,内网 dns 解析等等……),此外还支持内网 http 代理、内网 socks5 代理、p2p 等,并带有功能强大的 web 管理端。 实现结构图 +---------------+ +---------------------------------------+ +--------------------------------------------+ | | | | | | | traffic | | Server x.x.x.x | | | | | | | | | | | | nps web | | | | | | +---------+ +--------------+ | | intranet | | nps.test.com -----> | Traefik | +--> |127.0.0.1:8081| | | | | | | +---------+ +--------------+ | | | | | | | | | | | | | | nps Client | | | | +---------+ x.x.x.x:8024 | +-------------+ :5900 +-------------+ | | x.x.x.x:8001 -----> | nps | <------------------------------> | 10.1.50.100 | +-----> | 10.1.50.101 | | | | | +---------+ | | +-------------+ +-------------+ | | | | | | | +---------------+ +---------------------------------------+ +--------------------------------------------+ 服务端:CentOS 7.9 客户端:MacOS 10.15 ...

January 7, 2021 · 2 min · 357 words · Nick

Swoole slowlog 乱码修复

先说结果:fork 了 swoole 的源码,修复之后打了个 v1.10.7 的版本。 发现问题 由于各种原因项目在使用 swoole 的 v1.x 远古版本跑 TCP 服务,基础环境如下。 CentOS 6.9 PHP 5.5.38 然后遇到了程序偶发性超时情况严重。怀疑是版本bug,首先将 swoole 升级到了当前环境可用的最高版本 v1.10.6,问题依然没有解决。但是这个版本已经有了慢日志功能,将慢日志功能开起来,模拟程序阻塞超时,试试看功能可用否。 tcp_server.php <?php class tcpTest { static public function aa() { self::bb(); } static public function bb() { sleep(3); } } class Server { static private $serv = null; private function __construct() { $serv = new \swoole_server("0.0.0.0", 9577); $serv->set([ 'reactor_num' => 2, 'worker_num' => 8, 'task_worker_num' => 0, 'dispatch_mode' => 2, 'daemonize' => false, 'tcp_fastopen' => true, 'request_slowlog_timeout' => 2, 'request_slowlog_file' => '/tmp/swoole_slow.log', 'trace_event_worker' => true, ]); $serv->on('Start', array($this, 'onStart')); $serv->on('Connect', array($this, 'onConnect')); $serv->on('Receive', array($this, 'onReceive')); $serv->on('Close', array($this, 'onClose')); $serv->start(); } public function onStart($serv) { echo __METHOD__ . PHP_EOL; } public function onConnect($serv, $fd, $from_id) { echo __METHOD__ . " worker_id:{$serv->worker_id} work_pid:{$serv->worker_pid} fd:{$fd} from_id:{$from_id}" . PHP_EOL; } public function onReceive($serv, $fd, $from_id, $data) { $fdinfo = $serv->connection_info($fd,$from_id,true); echo __METHOD__ . " ip:{$fdinfo['remote_ip']} worker_id:{$serv->worker_id} work_pid:{$serv->worker_pid} fd:{$fd} from_id:{$from_id} data:{$data}" . PHP_EOL; \tcpTest::aa(); $res_data = ['time' => date('Y-m-d H:i:s')]; $serv->send($fd, json_encode($res_data)); } public function onClose($serv, $fd, $from_id) { echo __METHOD__ . " worker_id:{$serv->worker_id} work_pid:{$serv->worker_pid} fd:{$fd} from_id:{$from_id}" . PHP_EOL . PHP_EOL; } static public function inst() { if (!(self::$serv instanceof self)) { self::$serv = new self; } return self::$serv; } } $res = \Server::inst(); tcp_client.php ...

May 11, 2020 · 3 min · 433 words · Nick

用 Consul 和 Traefik 实现 Docker 容器的服务注册与发现

docker 实现应用的容器化 consul 集群实现服务的注册、发现 traefik 处理外部流量的负载均衡与路由 启动 consul 集群与 docker 通过 vagrant 起三台虚拟机实现基本的 consul 集群环境(为了节约资源把 docker 也运行在这上面了)。 consul 的 vagrant 配置文件如下: # -*- mode: ruby -*- # vi: set ft=ruby : # All Vagrant configuration is done below. The "2" in Vagrant.configure # configures the configuration version (we support older styles for # backwards compatibility). Please don't change it unless you know what # you're doing. Vagrant.configure("2") do |config| $script = <<SCRIPT echo "Installing" yum install -y wget wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo yum clean all yum makecache yum install -y jq unzip vim wget net-tools bind-utils dnsmasq sudo cp /vagrant/consul /usr/bin/consul echo "Installing docker.." sudo yum install -y yum-utils device-mapper-persistent-data lvm2 sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo sudo yum install -y docker-ce docker-ce-cli containerd.io sudo systemctl start docker echo "success" SCRIPT # The most common configuration options are documented and commented below. # For a complete reference, please see the online documentation at # https://docs.vagrantup.com. # Every Vagrant development environment requires a box. You can search for # boxes at https://vagrantcloud.com/search. config.vm.box = "centos/7" config.vm.provision "shell", inline: $script config.vm.define "node1" do |node1| node1.vm.hostname = "node1" node1.vm.network "private_network", ip: "172.17.17.11" end config.vm.define "node2" do |node2| node2.vm.hostname = "node2" node2.vm.network "private_network", ip: "172.17.17.12" end config.vm.define "node3" do |node3| node3.vm.hostname = "node3" node3.vm.network "private_network", ip: "172.17.17.13" end # Disable automatic box update checking. If you disable this, then # boxes will only be checked for updates when the user runs # `vagrant box outdated`. This is not recommended. config.vm.box_check_update = false # Create a forwarded port mapping which allows access to a specific port # within the machine from a port on the host machine. In the example below, # accessing "localhost:8080" will access port 80 on the guest machine. # NOTE: This will enable public access to the opened port # config.vm.network "forwarded_port", guest: 80, host: 8080 # Create a forwarded port mapping which allows access to a specific port # within the machine from a port on the host machine and only allow access # via 127.0.0.1 to disable public access # config.vm.network "forwarded_port", guest: 80, host: 8080, host_ip: "127.0.0.1" # Create a private network, which allows host-only access to the machine # using a specific IP. # config.vm.network "private_network", ip: "192.168.33.10" # Create a public network, which generally matched to bridged network. # Bridged networks make the machine appear as another physical device on # your network. # config.vm.network "public_network" # Share an additional folder to the guest VM. The first argument is # the path on the host to the actual folder. The second argument is # the path on the guest to mount the folder. And the optional third # argument is a set of non-required options. # config.vm.synced_folder "../data", "/vagrant_data" # Provider-specific configuration so you can fine-tune various # backing providers for Vagrant. These expose provider-specific options. # Example for VirtualBox: # config.vm.provider "virtualbox" do |vb| # # Display the VirtualBox GUI when booting the machine # vb.gui = true # # # Customize the amount of memory on the VM: vb.memory = "1024" end # # View the documentation for the provider you are using for more # information on available options. # Enable provisioning with a shell script. Additional provisioners such as # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the # documentation for more information about their specific syntax and use. # config.vm.provision "shell", inline: <<-SHELL # apt-get update # apt-get install -y apache2 # SHELL end 为了节省时间我直接下载好了 consul 的可执行文件放到了 vagrant 配置文件同目录下,vagrant 会把当前目录下的文件都复制进虚拟机的 /vagrant 目录下,还有三个节点的 consul 配置文件。 ...

February 6, 2020 · 9 min · 1788 words · Nick

年前线上问题总结

Intro 在家中除了带娃、看书也无事可做。把节前值班遇到的问题总结下。 除夕那天我们公司依然正常上班,很多同事都已经提前回家了,在的人也不多,中午吃完饭没什么事就都走了。突然领导发来贺电以为什么好事,居然线上出问题了。前端同事反馈后端无响应,这个反馈也是没谁了,问了下具体调用的后端url,某个同事的 php 项目,没辙硬上吧。找运维查了下对应的机器有四台,先上 kibana 看下 nginx access 日志有大量请求404,error 日志没问题。再看 php error 日志有响应很慢的请求,应该是进来了,再看下 php 慢日志看调用栈应该是走到了一个 redis 类。这时候运维还在先让运维看下 redis 有问题没。我接着追代码,看代码发现这老哥没用框架定义的 redis 实例化类,自己整了个,真难受啊,一行行看 redis 配置从哪取的八成是这 redis 的问题。这时候运维反馈线上 redis 没问题。我接着撸代码,终于看到调的配置名了,去项目下 grep 下。这一搜发现这个配置有测试环境的,有预发环境的,还有个默认的配置,线上配置文件没有,不用说线上环境肯定用的默认的配置,默认的配的是测试环境的 redis。然而测试环境因为春节放假都关机了。 问题查清楚了,加上了线上环境的 redis 配置。 但是这个 bug 太tm智障了,全是问题。 生产环境 调 测试环境 生产环境和测试环境要实现网络隔离,配置文件方式还是有点老,整个配置中心。 自行实现 redis 类 框架已经提供了 redis 类,还要自行实现,直接影响排查效率。屏蔽了 redis 链接不上,然后给前端扔了个 404。没有规矩不成方圆要多 code review 啊。 另 最近新型冠状病毒肆虐异常,各地陆续启动公共卫生事件一级响应,春节假期国家也延长到了正月初十。北京这边有的村不让从外回京的人进村,要外隔离,也是没谁了。

January 30, 2020 · 1 min · 55 words · Nick

Golang 与 PHP 的 json 序列化问题

Intro 最近在做 Golang 与 PHP 的 RPC 实现。因 PHP 业务端已上线稳定,Golang 方面则需要完全兼容。其中使用了 json 序列化,发现区别还是很大的,见下面代码。 $ php -a php > echo json_encode("<test我爱中国>"); "<test\u6211\u7231\u4e2d\u56fd>" package main import ( "encoding/json" "fmt" ) func main() { st := "<test我爱中国>" res, err := json.Marshal(st) if err != nil { fmt.Println("json err:", err.Error()) } fmt.Printf("json is: %s", string(res)) // json is: "\u003ctest我爱中国\u003e" } PHP 默认的 json_encode() 函数会把多字节字符转成 \uXXXX 当然通过设置 JSON_UNESCAPED_UNICODE 可以解决这个问题。这里不动 PHP 代码。 Golang 这里用 json 包的 Marshal 方法实现序列化,对多字节字符是不进行处理的。但是这个方法出于安全考虑会将"<", “>”, “&“这三个字符转成 \uXXXX 形式。这还不是最魔幻的,这个方法没有可选参数进行设置。 ...

December 23, 2019 · 3 min · 467 words · Nick

Golang 生成 O'Reilly 在线学习平台的电子书

O’Reilly 是有名的动物书出版公司,当然他们也不仅仅出电子书还有很多别的业务。O’Reilly 在线学习平台上有他们所有出版过的图书都是原版的,但是仅提供在线阅读,虽然也有 App,但是想在 kindle 上看提高阅读体验。 于是抽时间练习练习 Golang 写了个程序,生成 mobi 格式的电子书。Github 地址 oreilly_kindle_book 。 使用说明 目前仅支持 macOS、linux, windows 改改应该也可以,但是我手头没有 windows 测不了,或者编个 Docker image 也 ok。 需要 O’Reilly 在线学习平台的账号,这是必须的。 安装 kindlegen,mobi 的生成就靠它。 oreilly_kindle_book 编译 基于 golang 1.13 开发,目前没有上传二进制包,自行编译吧。 推荐 clone 之后直接 make && make install。 $ git clone https://github.com/zyh94946/oreilly_kindle_book.git $ cd oreilly_kindle_book $ make && make install Building oreilly_kindle_book... Building success... Installing oreilly_kindle_book... Install success to /usr/local/bin/oreilly_kindle_book. Usage of oreilly_kindle_book: -email string you login email of https://www.oreilly.com/member/ -help help -n string the num of https://learning.oreilly.com/library/view/BOOK-NAME/*** -p string you login password of https://www.oreilly.com/member/ -version print version and exit 当然 go get 也可以 ...

October 31, 2019 · 1 min · 155 words · Nick