每日新闻

每日新闻

GoCN每日新闻资讯
有问必答

有问必答

Go相关的问题,技术相关的问题
文章分享

文章分享

技术文章分享,让知识传播给更多的人
招聘应聘

招聘应聘

为Gopher服务的招聘应聘平台

10.11 每日早报

文章分享astaxie 发表了文章 • 0 个评论 • 1593 次浏览 • 2016-10-11 09:52 • 来自相关话题

10.11 每日早报 新闻: 1.哔哩哔哩正式上线VIP会员制度“大会员”,单月价格25元 2.Mozilla为Firefox Sync引入设备管理功能,可远程取消设备同步 ...查看全部
10.11 每日早报

新闻:

1.哔哩哔哩正式上线VIP会员制度“大会员”,单月价格25元

2.Mozilla为Firefox Sync引入设备管理功能,可远程取消设备同步

3.京东发起公益活动,在北京和天津推出快递小哥上门收旧衣服活动

4.花椒直播获3亿元A轮融资,360投资6000万元

5.福田汽车牵手百度,聚焦无人驾驶超级卡车和车联网

6.ofo共享单车完成1.3亿美元C轮融资,宣布向非校园的城市用户开放

7.电子合同签署云平台契约锁获得900万元天使轮融资,上海泛微网络领投

资源:

2016上半年度中国快递市场研究报告
http://www.bigdata-research.cn/content/201610/354.html

注:上述内容来源于互联网,由EGO整理

一个支持负载均衡,健康检查的 TcpProxy

开源程序astaxie 发表了文章 • 1 个评论 • 1823 次浏览 • 2016-10-11 07:31 • 来自相关话题

## goTcpProxy GitHub:https://github.com/zheng-ji/goTcpProxy [![Go Report Card](https://goreportcard.com ...查看全部
## goTcpProxy

GitHub:https://github.com/zheng-ji/goTcpProxy

[![Go Report Card](https://goreportcard.com/badge/github.com/zheng-ji/goTcpProxy)](https://goreportcard.com/report/github.com/zheng-ji/goTcpProxy)

一个支持负载均衡,健康检查的 TcpProxy

![smailltcp](https://cloud.githubusercontent.com/assets/1414745/19109474/2eea5e56-8b28-11e6-80ba-be5ed9117f9e.jpg)

### Description

#### English
* A tcp proxy service
* Supprot multi backend severs
* Consistent Hash Load Balance
* Auto detect down server, and remove it.
* Monitor backend health status

#### 中文

* TCP 代理服务
* 后端支持多个服务器
* 支持一致性哈希的负载均衡
* 自动检测失败的后端服务器,并移除
* 后端服务的健康检查接口

### How To Compile

```
cd $GOPATH;
git clone http://github.com/zheng-ji/goTcpProxy;
make
```

### How To Use

配置文件详解

```
bind: 0.0.0.0:9999 // 代理服务监听端口
wait_queue_len: 100 // 等待队列长度
max_conn: 10000 // 并发最大连接
timeout: 5 // 请求超时时间
failover: 3 // 后端服务允许失败次数
stats: 0.0.0.0:19999 // 健康检查接口
backend: // 后端服务列表
- 127.0.0.1:80
- 127.0.0.1:81
log:
level: "info"
path: "/Users/zj/proxy.log"
```

```
// 运行服务
./goTcpProxy -c=etc/conf.yaml
```

![gotcp](https://cloud.githubusercontent.com/assets/1414745/19108922/68eeab00-8b25-11e6-903a-864a19e2d9c5.png)

License
-------

Copyright (c) 2015 released under a MIT style license.

三十分钟 Docker 新手入门

文章分享astaxie 发表了文章 • 0 个评论 • 1651 次浏览 • 2016-10-10 23:35 • 来自相关话题

# 简介 如果您是 Docker 新手请您花大约三十分钟的时间来了解 Docker 相关的知识和内容。 Docker 与 Linux 息息相关,因此在阅读本文档之前请您确保以下条件: 1. 对 Linux 的 ...查看全部
# 简介

如果您是 Docker 新手请您花大约三十分钟的时间来了解 Docker 相关的知识和内容。 Docker 与 Linux 息息相关,因此在阅读本文档之前请您确保以下条件:

1. 对 Linux 的命令行操作有一定了解,并且懂得一些基础命令。
2. 对 Linux 服务管理有一定的了解。
3. 当阅读完本文之后您可以了解什么是 Docker、使用它有什么好处、以及 Docker 具体的使用方法。

# 为什么选择 Docker?

1. 相对于虚拟机来说 Docker 有镜像管理。
2. 相对于虚拟机来说更强大的迁移能力。
3. 云计算的未来,再也不用受到环境 API 的限制。

# 安装 Docker

Docker 的安装十分简单方便,如果您有 Linux 虚拟机 VPS 可以直接参考 [Docker 极速下载](http://get.daocloud.io/) 运行如下脚本来安装 Docker:

```shell
user$ curl -sSL https://get.daocloud.io/docker | sh
```

在 Docker 安装完成以后,国内的特殊网络环境会导致在构建 Docker 镜像或者是抓取(pull)来自 Docker Hub 上的镜像时会遇到连接问题,这时我们就需要使用 [DaoCloud 加速器服务](https://dashboard.daocloud.io/mirror)。

1. 注册 DaoCloud 账号,打开控制台进入加速服务。
2. 在网页的最下方有详细的使用步骤请参考。

如果您使用的是 Windows 或 Mac 请您下载安装 Boot2Docker。

这里我推荐使用 Ubuntu Server 操作系统,无论是在裸机上还是虚拟机上。

# Hello World

这部分的代码来自 Docker 用户指南,但是与用户指南不同的是我们会描述更多的执行过程。

## 案例 1 启动一个容器

```shell
root# docker run ubuntu:14.04 /bin/echo 'Hello world'
Hello world
```
1. 注意操作 Docker 是需要权限的,这里使用 root 用户操作,当然您也可以把 docker 加入自己的用户。
2. `run` 作为 Docker 的子命令来控制新建容器并且运行。Docker 命令虽然比较多,但是命令是分级来执行的,多参照 help 就会习惯。
3. `ubuntu:14.04` 代表镜像的名字和版本号,托管在 Docker Hub 上,如果本地没有抓取过那么执行命令的时候会自动从 Docker Hub 抓取。
4. `/bin/echo` 为在容器内执行的程序(应用)。
5. `'Hello world'` 为程序执行的参数。

> 提示:Docker 在命令执行完毕后不会销毁容器,但是状态为变为 Exited。

从这句命令中我们可以看到 Docker 可以根据情况判断镜像存在的情况,在后文中会介绍镜像的管理。同时 ubuntu:14.04 将会被载入到缓存中,如果后面的镜像构建依赖于它并不会花费额外的网络带宽抓取,十分方便。

## 案例 2-1 以交互模式启动一个容器

```shell
root# docker run -t -i ubuntu:14.04 /bin/bash
root@af8bae53bdd3:/#
```
与上面的案例不同的是这条命令带有 -t 和 -i 选项,这两个选项在这指的是:

```shell
-i, --interactive=false Keep STDIN open even if not attached
-t, --tty=false Allocate a pseudo-TTY
```

上面来自 `docker help run` 的输出,help 命令是获取文档帮助信息最简短而高效的途径。本次启动的进程是 bash,运行 bash 之后,容器会在交互的模式下启动。当 bash 退出后就会停止运行。这就是 Docker 运行程序的最简单方式。

> 提示:此程序运行完成之后,容器不会被销毁,但是状态为 Exited。此外对于以交互模式启动的容器可以先按下 Ctrl+P 然后按下 Ctrl+Q 这样的按键顺序脱离(detach)一个容器,脱离后的容器状态仍为 Up 并且程序会继续在后台运行,这时可以使用 attach 命令重新附到一个已经脱离的程序。
## 案例 2-2 查看容器内的文件以及容器本身

在上一个例子中如果容器没有关闭通过如下命令可以看出:

```shell
root@33d90ffaf1ac:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@33d90ffaf1ac:/# pwd
/
root@33d90ffaf1ac:/#
```
Docker 中整个容器是一个 Linux 环境,ubuntu 镜像的默认用户为 root,默认工作目录为根目录。

```shell
root@33d90ffaf1ac:/# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 18172 3104 ? Ss 08:50 0:00 /bin/bash
root 16 0.0 0.0 15572 2200 ? R+ 09:04 0:00 ps aux
```
容器中的进程相当简洁,只有正在运行的两个程序没有其他任何进程。

并且 PID 号码是独立存在的,与宿主机完全没有关系。

## 案例 3 查看后台运行容器的日志信息

```shell
root# sudo docker run -t -i -d ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
8b8aad0aa7670441f99ce88fbac021bfb9cb124e7de4417a00ed3c0ccc6cb203
```
在这个案例中加入了新的选项 `-d`,这个选项中可以让 Docker 后台运行程序。

如果我们查看运行的结果:

```shell
root# docker logs 8b8aad0aa767
hello world
hello world
hello world
```
从上面的命令来看,使用 logs 能看到程序的输出 log 过程,这样对服务的调试是非常有帮助的。如果容器没有自己设定的名字很难快速准确的调度容器。

## 案例 4 快速准确的调度容器--给容器起名字

```shell
root# docker run -t -i -d --name helloubuntu ubuntu:14.04 /bin/sh -c "while true; do echo hello world; sleep 1; done"
8b8aad0aa7670441f99ce88fbac021bfb9cb124e7de4417a00ed3c0ccc6cb203
```
上面的命令跟之前案例中的命令对比多了一个 `--name` 选项给调度容器带来了很多方便,用户可以自己设定容器的名字,当然如果未指定名字系统会自动起一个随机的名字给容器。那么我们查看 logs 的时候就可以通过命令 `docker logs helloubuntu` 来查看日志信息了。

注意:容器名必须以英文字母和数字开头,并且只能包含英文数字、下划线 _、小数点 .、和减号 -。
## 案例 5 列出所有正在运行的容器和它们的基本信息

```shell
root# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
53d90769be11 ubuntu:14.04 [...] 2 min ago Up 2 min helloubuntu
8b8aad0aa767 ubuntu:14.04 [...] 14 min ago Up 14 min dreamy_fermat
deaaa8e60c9f ubuntu:14.04 [...] 14 min ago Up 1 sec distracted_darwin
33d90ffaf1ac ubuntu:14.04 [...] 26 min ago Exited (0) tender_franklin
```
> 注意:由于文档宽度关系,样例中有些内容被缩写以方便展示。

在 `# docker ps -a` 这个命令中我们可以看到容器的 ID、使用的镜像、启动的命令、创建的时间、当前状态、端口映射状态和名字。

## 案例 6 容器管理

以下管理命令都可以通过传入容器的 ID 或者名字来管理指定的容器:

- stop 停止一个正在运行的容器。
- start 运行一个正在停止的容器。
- restart 重启一个容器。
- rm 删除一个容器。

传入多个 ID 或者名字可以操作多个容器。例如:`docker rm name1 name2` 可以同时删除两个容器。

> 提示:如果要删除所有容器 docker rm $(docker ps -q -a)。

## 阶段总结

当您看到这里的时候可以说对 Docker 已经有了初步的操作能力,包括运行容器中的程序、查看容器内容、运行容器、停止容器、查看容器、重启容器和删除容器。但是距离在 Docker 上运行自己的业务或者组织开发还是有一定距离的。接下来我们开始进阶学习,重点研究一下 Docker 操作的组成要素。

# Docker 组成要素

如果将轮船拉着集装箱运行在大海上,与 Docker 运行容器里面的程序类比:

- Linux 相当于大海,有不同的海洋气候各有不同。
- Docker 相当于能行驶在各种大海上的轮船,容器相当于各种规格的集装箱。
- Docker 内的系统相当于货物的包装。
- 目标程序则相当于货物。

当您看完上面的描述之后可以了解到每一种角色不同的作用以及所处的位置有所了解。

当然理论上的 Docker 只是一个轮船图纸,必须得有一个守护进程才能运行。

镜像也是一样,它只是集装箱的图纸,需要在 Docker 中运行容器。

# 通过 Docker 运行您的 Web 应用,Step By Step

代码文件请参考: [DaoCloud 搭建静态博客](https://github.com/lijianying10/DaoCloudStaticBlog) 以及 [整个研究过程参考](http://open.daocloud.io/build-and-deploy-the-thinnest-docker-image/)。

Step 1:准备自己的互联网应用 - 参考文件中的 static 这个文件为编译好的 golang 应用程序。

Step 2:准备 Linux RootFS - 参考文件中的 root.fs 为打包好的 BusyBox。

Step 3:准备 Dockerfile:

```shell
# 从一个空镜像中开始创建,没有任何依赖。
FROM scratch
MAINTAINER DaoCloud

# 给 Docker 文件系统中添加根目录,也是 Linux 的一些基础目录。
ADD ./rootfs.tar /

# 给镜像添加工作目录 /app
RUN mkdir -p /app

# 设定默认工作路径
WORKDIR /app

# 复制应用进入到镜像中
COPY ./static /app

# 复制应用依赖的静态文件目录
COPY ./public /public

# 对外开放的服务接口为 8080
EXPOSE 8080

# 容器运行时默认调用的启动命令
CMD ["/app/static"]
```
Step4:构建镜像 - sudo docker build -t [标签] . 注意:最后有一个点 . 表示构建时的当前目录。

Step5:运行镜像 - 这一步就不赘述了,请参阅最开始的一个章节。

这里重点讲解一下第三步中 Dockerfile 的格式。参照 Dockerfile 中的注释。

关于 Dockerfile 内部的指令的教程网上虽然很多,但是坑也不少。首先要注意,构建用的依赖文件都要放到同一个目录中,为了安全和可移植性尽量不要用到目录之外的文件。

COPY 或者 ADD 的目的地址比如说上面的 /app/ 与 /public 意义不同,第一个是复制文件到 app 下,第二个是复制目录到根名字叫 public。

为了更详细的介绍 Dockerfile 添加一个额外的案例:

```shell
FROM node:slim

MAINTAINER DaoCloud

RUN apt-get update \
&& apt-get install -y git ssh-client ca-certificates --no-install-recommends \
&& rm -r /var/lib/apt/lists/*

RUN echo "Asia/Shanghai" > /etc/timezone \
&& dpkg-reconfigure -f noninteractive tzdata

RUN npm install hexo@3.0.0 -g

RUN mkdir /hexo
WORKDIR /hexo

EXPOSE 4000

CMD ["/bin/bash"]
```
在这个 Dockerfile 中:

FROM node:slim 表示构建的时候依赖于 Node.js 系统,并标明了标签为 slim,但是没标明也不需要标明的是 node 依赖于 Debian,这是用户自己需要了解的,下一步就开始运行,当开始构建时是可以运行 Dockerfile 中的脚本的。

第一个 RUN:后面标记的是需要让 Debian 更新源并且安装一系列的软件,最后清空无用缓存。

第二个 RUN:设定时区。

第三个 RUN:安装 Hexo 博客系统。

最后新建目录设定工作目录开放 4000 端口上文中已经提过。

在补充的这个例子中我们可以清楚的看到构建自己的镜像可以依赖于其他镜像构建环境基本上都已经准备好了,非常方便。第二个例子是构建 Hexo 博客环境的做法。

# 管理 Docker 镜像

## 拿来主义:pull(抓取)

第一种是直接抓取比如说下载一个 docker 管理用的 dockerui 工具,我们可以直接告诉 docker pull 回来:

```shell
root# docker pull dockerui/dockerui

```
也可以通过运行的方式来抓回镜像:

```shell
root# docker run -d -p 9000:9000 --privileged \
-v /var/run/docker.sock:/var/run/docker.sock dockerui/dockerui
```
这样用直接访问 http://localhost:9000/ 的方法来管理 docker 了。

## 查看自己所有的镜像

```shell
root# docker images
REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
hexo3 latest 66f7fc371b44 9 days ago 261.5 MB
node slim 84326d4c0101 11 days ago 164.5 MB
dockerui/dockerui latest 9ac79962b9b0 2 weeks ago 5.422 MB
busybox latest 8c2e06607696 7 weeks ago 2.433 MB
garland/butterfly latest 114f9c134231 3 months ago 394.5 MB
progrium/busybox latest 8cee90767cfe 4 months ago 4.789 MB
```
## 搜索需要的镜像

推荐到 [Docker Hub Registry](https://registry.hub.docker.com/) 上搜索。

但是也可以通过命令 `docker search 关键词` 进行搜索。

## 清空所有当前镜像

使用命令:`docker rmi $(docker images -q)`。

如果当前已经没有镜像了命令会报错找不到镜像。

> 警告:请谨慎清空所有镜像。

## 构建镜像的缓存

在构建镜像时 Dockerfile 中的指令会进入缓存,如果构建时可以使用缓存,docker 可以做到快速完成构建。

Docker 数据卷的挂载与外部服务访问

首先要注意的一点:容器被删除后里面的数据会被删除,因此要注意挂载数据卷使数据持久化。

因此这里介绍一下挂载宿主机中的目录作为数据卷到 Docker 中的方法:

`root# docker run -it -d -p 4000:4000 -v /root/blog/:/hexo --name hexo hexo3`
这是上一个案例中运行 Hexo 博客的方法,注意挂载描述在 -v 之后,容器中就可以访问到宿主机中的持久化位置了。

> 注意,在数据库应用中最需要根据配置文件将数据库持久化的位置放到宿主机中。

对于开发更加详细的意见可以产考 [使用 Docker 做开发的建议团队工作流](http://www.philo.top/2015/06/04/DockerWorkflow/)。

为了使 Hexo 博客可以被宿主机以外的设备访问,这里使用 -p 参数来发布 Docker 的端口到宿主机中。

# Docker 学习建议:

1. 在详细实践完成本文之后如果您有精力,并且英文阅读能力还不错请您移步到 Docker官方文档 继续更深入的学习。
2. Docker 只是一种非常实用的工具,不要以 Docker 为目的去学习 Docker,重要的不是 Docker 而是您用 Docker 做什么。

# 总结

由于篇幅有限新手教程就到这里,希望您在这半个小时到一个小时中能有一次非常完美的 Docker 学习体验,在接下来的学习中您还可以继续从 Docker 官方的文档中了解更多的 Docker 相关的信息,尤其是 Docker 容器与容器之间的问题解决,以及更多更加丰富的命令参数使用,比如环境变量的控制。

相信做完这部分实践之后您已经了解了 Docker 能够做什么,如何进行基础方面的使用。在下一篇中我们会 根据您现有的基础介绍如何使用 DaoCloud 各项服务。

在接下来的学习中,如果需要请您学习使用版本控制工具 Git,及其相关基础知识。

请教各位大神 golang 有根据设备mac 等信息 生产唯一标示的库吗

回复

有问必答astaxie 回复了问题 • 1 人关注 • 1 个回复 • 2560 次浏览 • 2016-10-10 23:20 • 来自相关话题

百度如何使用Go语言重构日请求量千亿级别的系统?

Golangastaxie 发表了文章 • 1 个评论 • 1866 次浏览 • 2016-10-10 22:09 • 来自相关话题

百度日请求量在 700 亿以上,占比约 50%,面对如此庞大的前端页面访问量,百度如何处理数据拥堵现象?本次分享以 Baidu-FrontEnd 的重构历程为主线索,展示在设计海量接入前端中的权衡以及对语言的考虑。首先要解决的就是 GO 语言难以克服的“先天不 ...查看全部
百度日请求量在 700 亿以上,占比约 50%,面对如此庞大的前端页面访问量,百度如何处理数据拥堵现象?本次分享以 Baidu-FrontEnd 的重构历程为主线索,展示在设计海量接入前端中的权衡以及对语言的考虑。首先要解决的就是 GO 语言难以克服的“先天不足”缺陷,GC(Gabage Collection)延迟造成的关键问题。其次就是如何合理的设计软件架构,来协调稳定性与可扩展性之间的矛盾。最后,采用 GO 语言 HTTP 类库所面临的协议一致性问题。

# 嘉宾介绍
陶春华,百度资深运维工程师,天津大学计算机专业博士。2013 年加入百度,目前是百度 Golang 委员会成员 & Code Master,工作中主要方向在百度接入的 Go 项目,曾负责应用层防火墙 WAF、7 层流量代理的 Go 语言改造等前端接入工作。

#演讲稿

http://q.infoqstatic.com/ppt/2-6-Golang-baidu.pdf

beego 1.7.1 新版本发布

开源程序astaxie 发表了文章 • 1 个评论 • 2175 次浏览 • 2016-10-10 16:47 • 来自相关话题

# beego 1.7.1 新增功能: 1. access log增加IP [#2156](https://github.com/astaxie/beego/pull/2156) 2. orm增加新接口ReadForUpda ...查看全部
# beego 1.7.1
新增功能:
1. access log增加IP [#2156](https://github.com/astaxie/beego/pull/2156)
2. orm增加新接口ReadForUpdate [#2158](https://github.com/astaxie/beego/pull/2158)
3. 参数bind支持数组form,columns[0].Data=foo&columns[1].Data=bar&columns[2].Data=baz [#2111](https://github.com/astaxie/beego/pull/2111)
4. 自定义recover函数,增加配置`beego.BConfig.RecoverFunc`,默认和原来保持一致,但是用户可以自己定义 [#2004](https://github.com/astaxie/beego/issues/2004)
5. memcache cache 同时支持byte和string的存储,这样就可以通过gob保存struct [#1521](https://github.com/astaxie/beego/issues/1521)
6. ORM delete支持按照指定条件删除 (#1802)[https://github.com/astaxie/beego/issues/1802]
7. swagger的支持输出yaml (#2162)[https://github.com/astaxie/beego/pull/2162]
8. 增加RunController 和 RunMethod,让用户自定义路由规则 (#2017)[https://github.com/astaxie/beego/issues/2017]

修复bug:
1. 静态目录如果已经存在index.html,当访问目录的时候不会自动添加/, 例如访问/swagger不会跳转到/swagger/,这样会导致相对的css和js访问不存在 [#2142](https://github.com/astaxie/beego/issues/2142)
2. beego admin ui里面访问时间排序没有安装us,ms排序,而是安装字符排序 [#1877](https://github.com/astaxie/beego/issues/1877)
3. captcha生产图片的时候,自定义height和width crash [#2161](https://github.com/astaxie/beego/issues/2161)
4. DELETE请求下开启了CopyBody情况下,如果body为空panic [#1656](https://github.com/astaxie/beego/issues/1656)


# beego 1.7.0
新增改进功能:
1. Filter访问速度提升7.5倍以上 [#1799](https://github.com/astaxie/beego/pull/1799)
2. Gzip压缩的时候支持不同的level [#1808](https://github.com/astaxie/beego/pull/1808)
3. ORM PK支持负数 [#1810](https://github.com/astaxie/beego/pull/1810)
4. ORM 支持自定义自增ID的值 [#1826](https://github.com/astaxie/beego/pull/1826)
5. Context 下载文件函数改进:下载文件之前先检查是否存在 [#1827](https://github.com/astaxie/beego/pull/1827)
6. log增加 `GetLogger`函数,可以增加相应的前缀 [#1832](https://github.com/astaxie/beego/pull/1832)

关于Go tools的比较有用的flags

Golangitfanr 发表了文章 • 0 个评论 • 6829 次浏览 • 2016-10-10 16:45 • 来自相关话题

你刚接触Go tools吗?或者你想扩展下你的知识面?这篇文章是关于Go tools的flags,这些flags每个人都应该知道。 免责声明:这篇文件可能有一些偏见。这是我个人常用的flags集合。我周边的人很难找到这些falgs的参 ...查看全部

你刚接触Go tools吗?或者你想扩展下你的知识面?这篇文章是关于Go tools的flags,这些flags每个人都应该知道。

免责声明:这篇文件可能有一些偏见。这是我个人常用的flags集合。我周边的人很难找到这些falgs的参考文档。如果你有更好的主意,可以在[Twitter][1]上私信我。

# $ go build -x


`-x`列出了go build触发的所有命令。

如果你对Go的工具链、使用跨平台编译器比较好奇,或者对传入外部编译器的flags不清楚,或者怀疑链接器有bug,那么使用`-x`来查看所有的触发。

# $ go build -x


```
WORK=/var/folders/00/1b8h8000h01000cxqpysvccm005d21/T/go-build600909754
mkdir -p $WORK/hello/perf/_obj/
mkdir -p $WORK/hello/perf/_obj/exe/
cd /Users/jbd/src/hello/perf
/Users/jbd/go/pkg/tool/darwin_amd64/compile -o $WORK/hello/perf.a -trimpath $WORK -p main -complete -buildid bbf8e880e7dd4114f42a7f57717f9ea5cc1dd18d -D _/Users/jbd/src/hello/perf -I $WORK -pack ./perf.go
cd .
/Users/jbd/go/pkg/tool/darwin_amd64/link -o $WORK/hello/perf/_obj/exe/a.out -L $WORK -extld=clang -buildmode=exe -buildid=bbf8e880e7dd4114f42a7f57717f9ea5cc1dd18d $WORK/hello/perf.a
mv $WORK/hello/perf/_obj/exe/a.out perf
```


# $go build -gcflags

用来给Go编译器传入参数。`go tool compile -help`列出了可以被传入编译器的所有的参数列表。

比如,为了禁止编译器优化和内联,你可以使用下面的gcfalgs:

```
$ go build -gcflags="-N -l"
```


# $go test -v


它提供了非正式的测试输出,打印了测试的名字、状态(通过或者失败)、耗时、测试用例的日志等。

不带有`-v`flag的go test命令非常安静,我经常把`-v`开关打开。比如输出如下:

```
$ go test -v context
=== RUN TestBackground
--- PASS: TestBackground (0.00s)
=== RUN TestTODO
--- PASS: TestTODO (0.00s)
=== RUN TestWithCancel
--- PASS: TestWithCancel (0.10s)
=== RUN TestParentFinishesChild
--- PASS: TestParentFinishesChild (0.00s)
=== RUN TestChildFinishesFirst
--- PASS: TestChildFinishesFirst (0.00s)
=== RUN TestDeadline
--- PASS: TestDeadline (0.16s)
=== RUN TestTimeout
--- PASS: TestTimeout (0.16s)
=== RUN TestCanceledTimeout
--- PASS: TestCanceledTimeout (0.10s)
...
PASS
ok context 2.426s
```

# $go test -race

[Go竞争检测工具][2]可以通过`--race`使用。go test也支持这个flag并且报告竞争。在开发阶段使用这个flag可以检测竞争。


# $go test -run

使用`-run`flag,你可以通过正则过滤测试用例。下面的命令会只测试[test examples][3]:

```
$ go test -run=Example
```

# $go test -coverprofile

你可以输出一个覆盖信息,如果你在测试一个包,然后使用go tool来在浏览器上实现可视化:


```
$ go test -coverprofile=c.out && go tool cover -html=c.out
```
上面的命令会创建一个覆盖信息,然后在浏览器上打开结果页面。可视化后的结果会类似下面的页面:

![此处输入图片的描述][4]


# $go test -exec

这是一个鲜为人知的特性,使用`-exec`这个flag,你可以用另外的程序和tools交互。这个flag允许你使用Go tool把一些工作代理到另外的程序。

使用这个flag常用的需求场景是:当你需要做更多的事情,而不是仅仅执行宿主机的程序。Go的[Android build][5],使用了`-exec`来推送测试二进制文件到Android设备(通过使用`adb`),并收集测试结果。可以作为一个参考。

# $go get -u

如果你执行go-test命令来获取一个已经在GOPATH中的包,那么go-get不好更新包到最新版本,而`-u`会强制tool同步这个仓库的最新的版本。

如果你是一个library的作者,那么你可能喜欢写你的安装说明通过`-u`flag,比如,[golin][6]t这样的方式:

```
$ go get -u github.com/golang/lint/golint
```

# $go get -d

如果你只想clone一个repo到GOPATH,跳过编译和安装过程,那么使用`-d`。它会下载包,然后在尝试编译和安装之前停止。

我经常使用它,作为git clone的替代命令,使用虚假的URLs,因为它会克隆这个repo到它合适的GOPATH。比如:

```
$ go get -d golang.org/x/oauth2/...
```

会克隆包到`$GOPATH/src/golang.org/x/ouath2`。给出的`golang.org/x/oauth2`是一个虚假的URL,go-get这个仓库是很有用的,而不是尝试知道知己的repo是什么(go.googlesource.com/oauth2)。

# $go get -t

如果你的包需要额外的包来测试,`-t`会允许你在go-get过程中下载它们。如果你不传入`-t`参数,go get会只下载非测试代码的依赖。

# $ go list -f

允许你下载Go包以一种自定义的格式。对写bash脚本非常有用。下面的命令会输出runtime包的依赖:

```
$ go list -f '{{.Deps}}' runtime
[runtime/internal/atomic runtime/internal/sys unsafe]
```

更多的格式化信息可以在[Dave Cheney的文章][7]的go list章节得到。

[英文原文][8]

[1]: https://twitter.com/rakyll
[2]: https://blog.golang.org/race-detector
[3]: https://blog.golang.org/examples
[4]: https://raw.githubusercontent.com/itfanr/articles-about-golang/master/2016-09/2016-09-27-1-1.png
[5]: https://github.com/golang/go/blob/master/misc/android/go_android_exec.go
[6]: https://github.com/golang/lint#installation
[7]: http://dave.cheney.net/2014/09/14/go-list-your-swiss-army-knife
[8]: http://golang.rakyll.org/go-tool-flags/

使用Go语言每分钟处理1百万请求

技术讨论astaxie 发表了文章 • 5 个评论 • 5444 次浏览 • 2016-10-10 16:25 • 来自相关话题

# 使用Go语言每分钟处理1百万请求(译) --- 在[Malwarebytes ][1]我们经历了显著的增长,自从我一年前加入了硅谷的公司,一个主要的职责成了设计架构和开发一些系统来支持一个快速增长的信息 ...查看全部
# 使用Go语言每分钟处理1百万请求(译)

---

在[Malwarebytes ][1]我们经历了显著的增长,自从我一年前加入了硅谷的公司,一个主要的职责成了设计架构和开发一些系统来支持一个快速增长的信息安全公司和所有需要的设施来支持一个每天百万用户使用的产品。我在反病毒和反恶意软件行业的不同公司工作了12年,从而我知道由于我们每天处理大量的数据,这些系统是多么复杂。

有趣的是,在过去的大约9年间,我参与的所有的web后端的开发通常是通过Ruby on Rails技术实现的。不要错怪我。我喜欢Ruby on Rails,并且我相信它是个令人惊讶的环境。但是一段时间后,你会开始以ruby的方式开始思考和设计系统,你会忘记,如果你可以利用多线程、并行、快速执行和小内存开销,软件架构本来应该是多么高效和简单。很多年期间,我是一个c/c++、Delphi和c#开发者,我刚开始意识到使用正确的工具可以把复杂的事情变得简单些。

作为首席架构师,我不会很关心在互联网上的语言和框架战争。我相信效率、生产力。代码可维护性主要依赖于你如何把解决方案设计得很简单。

# 问题

当工作在我们的匿名遥测和分析系统中,我们的目标是可以处理来自于百万级别的终端的大量的POST请求。web处理服务可以接收包含了很多payload的集合的JSON数据,这些数据需要写入Amazon S3中。接下来,map-reduce系统可以操作这些数据。

按照习惯,我们会调研服务层级架构,涉及的软件如下:

- Sidekiq
- Resque
- DelayedJob
- Elasticbeanstalk Worker Tier
- RabbitMQ
- and so on…

搭建了2个不同的集群,一个提供web前端,另外一个提供后端处理,这样我们可以横向扩展后端服务的数量。

但是,从刚开始,在 讨论阶段我们的团队就知道我们应该使用Go,因为我们看到这会潜在性地成为一个非常庞大( large traffic)的系统。我已经使用了Go语言大约2年时间,我们开发了几个系统,但是很少会达到这样的负载(amount of load)。

我们开始创建一些结构,定义从POST调用得到的web请求负载,还有一个上传到S3 budket的函数。

```
type PayloadCollection struct {
WindowsVersion string `json:"version"`
Token string `json:"token"`
Payloads []Payload `json:"data"`
}

type Payload struct {
// [redacted]
}

func (p *Payload) UploadToS3() error {
// the storageFolder method ensures that there are no name collision in
// case we get same timestamp in the key name
storage_path := fmt.Sprintf("%v/%v", p.storageFolder, time.Now().UnixNano())

bucket := S3Bucket

b := new(bytes.Buffer)
encodeErr := json.NewEncoder(b).Encode(payload)
if encodeErr != nil {
return encodeErr
}

// Everything we post to the S3 bucket should be marked 'private'
var acl = s3.Private
var contentType = "application/octet-stream"

return bucket.PutReader(storage_path, b, int64(b.Len()), contentType, acl, s3.Options{})
}
```

# 本地Go routines方法

刚开始,我们采用了一个非常本地化的POST处理实现,仅仅尝试把发到简单go routine的job并行化:

```
func payloadHandler(w http.ResponseWriter, r *http.Request) {

if r.Method != "POST" {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}

// Read the body into a string for json decoding
var content = &PayloadCollection{}
err := json.NewDecoder(io.LimitReader(r.Body, MaxLength)).Decode(&content)
if err != nil {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusBadRequest)
return
}

// Go through each payload and queue items individually to be posted to S3
for _, payload := range content.Payloads {
go payload.UploadToS3() // <----- DON'T DO THIS
}

w.WriteHeader(http.StatusOK)
}
```

对于中小负载,这会对大多数的人适用,但是大规模下,这个方案会很快被证明不是很好用。我们期望的请求数,不在我们刚开始计划的数量级,当我们把第一个版本部署到生产环境上。我们完全低估了流量。

上面的方案在很多地方很不好。没有办法控制我们产生的go routine的数量。由于我们收到了每分钟1百万的POST请求,这段代码很快就崩溃了。

# 再次尝试

我们需要找一个不同的方式。自开始我们就讨论过, 我们需要保持请求处理程序的生命周期很短,并且进程在后台产生。当然,这是你在Ruby on Rails的世界里必须要做的事情,否则你会阻塞在所有可用的工作 web处理器上,不管你是使用puma、unicore还是passenger(我们不要讨论JRuby这个话题)。然后我们需要利用常用的处理方案来做这些,比如Resque、 Sidekiq、 SQS等。这个列表会继续保留,因为有很多的方案可以实现这些。

所以,第二次迭代,我们创建了一个缓冲channel,我们可以把job排队,然后把它们上传到S3。因为我们可以控制我们队列中的item最大值,我们有大量的内存来排列job,我们认为只要把job在channel里面缓冲就可以了。

```
var Queue chan Payload

func init() {
Queue = make(chan Payload, MAX_QUEUE)
}

func payloadHandler(w http.ResponseWriter, r *http.Request) {
...
// Go through each payload and queue items individually to be posted to S3
for _, payload := range content.Payloads {
Queue <- payload
}
...
}
```

接下来,我们再从队列中取job,然后处理它们。我们使用类似于下面的代码:

```
func StartProcessor() {
for {
select {
case job := <-Queue:
job.payload.UploadToS3() // <-- STILL NOT GOOD
}
}
}
```

说实话,我不知道我们在想什么。这肯定是一个满是Red-Bulls的夜晚。这个方法不会带来什么改善,我们用了一个 有缺陷的缓冲队列并发,仅仅是把问题推迟了。我们的同步处理器同时仅仅会上传一个数据到S3,因为来到的请求远远大于单核处理器上传到S3的能力,我们的带缓冲channel很快达到了它的极限,然后阻塞了请求处理逻辑的queue更多item的能力。

我们仅仅避免了问题,同时开始了我们的系统挂掉的倒计时。当部署了这个有缺陷的版本后,我们的延时保持在每分钟以常量增长。

![此处输入图片的描述][2]

# 最好的解决方案

我们讨论过在使用用Go channel时利用一种常用的模式,来创建一个二级channel系统,一个来queue job,另外一个来控制使用多少个worker来并发操作JobQueue。

想法是,以一个恒定速率并行上传到S3,既不会导致机器崩溃也不好产生S3的连接错误。这样我们选择了创建一个Job/Worker模式。对于那些熟悉Java、C#等语言的开发者,可以把这种模式想象成利用channel以golang的方式来实现了一个worker线程池,作为一种替代。

```
var (
MaxWorker = os.Getenv("MAX_WORKERS")
MaxQueue = os.Getenv("MAX_QUEUE")
)

// Job represents the job to be run
type Job struct {
Payload Payload
}

// A buffered channel that we can send work requests on.
var JobQueue chan Job

// Worker represents the worker that executes the job
type Worker struct {
WorkerPool chan chan Job
JobChannel chan Job
quit chan bool
}

func NewWorker(workerPool chan chan Job) Worker {
return Worker{
WorkerPool: workerPool,
JobChannel: make(chan Job),
quit: make(chan bool)}
}

// Start method starts the run loop for the worker, listening for a quit channel in
// case we need to stop it
func (w Worker) Start() {
go func() {
for {
// register the current worker into the worker queue.
w.WorkerPool <- w.JobChannel

select {
case job := <-w.JobChannel:
// we have received a work request.
if err := job.Payload.UploadToS3(); err != nil {
log.Errorf("Error uploading to S3: %s", err.Error())
}

case <-w.quit:
// we have received a signal to stop
return
}
}
}()
}

// Stop signals the worker to stop listening for work requests.
func (w Worker) Stop() {
go func() {
w.quit <- true
}()
}
```

我们已经修改了我们的web请求handler,用payload创建一个Job实例,然后发到JobQueue channel,以便于worker来获取。

```
func payloadHandler(w http.ResponseWriter, r *http.Request) {

if r.Method != "POST" {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}

// Read the body into a string for json decoding
var content = &PayloadCollection{}
err := json.NewDecoder(io.LimitReader(r.Body, MaxLength)).Decode(&content)
if err != nil {
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
w.WriteHeader(http.StatusBadRequest)
return
}

// Go through each payload and queue items individually to be posted to S3
for _, payload := range content.Payloads {

// let's create a job with the payload
work := Job{Payload: payload}

// Push the work onto the queue.
JobQueue <- work
}

w.WriteHeader(http.StatusOK)
}
```

在web server初始化时,我们创建一个Dispatcher,然后调用Run()函数创建一个worker池子,然后开始监听JobQueue中的job。

```
dispatcher := NewDispatcher(MaxWorker)
dispatcher.Run()
```

下面是dispatcher的实现代码:

```
type Dispatcher struct {
// A pool of workers channels that are registered with the dispatcher
WorkerPool chan chan Job
}

func NewDispatcher(maxWorkers int) *Dispatcher {
pool := make(chan chan Job, maxWorkers)
return &Dispatcher{WorkerPool: pool}
}

func (d *Dispatcher) Run() {
// starting n number of workers
for i := 0; i < d.maxWorkers; i++ {
worker := NewWorker(d.pool)
worker.Start()
}

go d.dispatch()
}

func (d *Dispatcher) dispatch() {
for {
select {
case job := <-JobQueue:
// a job request has been received
go func(job Job) {
// try to obtain a worker job channel that is available.
// this will block until a worker is idle
jobChannel := <-d.WorkerPool

// dispatch the job to the worker job channel
jobChannel <- job
}(job)
}
}
}
```

注意到,我们提供了初始化并加入到池子的worker的最大数量。因为这个工程我们利用了Amazon Elasticbeanstalk带有的docker化的Go环境,所以我们常常会遵守[12-factor][3]方法论来配置我们的生成环境中的系统,我们从环境变了读取这些值。这种方式,我们控制worker的数量和JobQueue的大小,所以我们可以很快的改变这些值,而不需要重新部署集群。

```
var (
MaxWorker = os.Getenv("MAX_WORKERS")
MaxQueue = os.Getenv("MAX_QUEUE")
)
```

# 直接结果

我们部署了之后,立马看到了延时降到微乎其微的数值,并未我们处理请求的能力提升很大。

![此处输入图片的描述][4]

Elastic Load Balancers完全启动后,我们看到ElasticBeanstalk 应用服务于每分钟1百万请求。通常情况下在上午时间有几个小时,流量峰值超过每分钟一百万次。

我们一旦部署了新的代码,服务器的数量从100台大幅 下降到大约20台。

![此处输入图片的描述][5]

我们合理配置了我们的集群和自动均衡配置之后,我们可以把服务器的数量降至4x EC2 c4.Large实例,并且Elastic Auto-Scaling设置为如果CPU达到5分钟的90%利用率,我们就会产生新的实例。

![此处输入图片的描述][6]


# 总结

在我的书中,简单总是获胜。我们可以使用多队列、后台worker、复杂的部署设计一个复杂的系统,但是我们决定利用Elasticbeanstalk 的auto-scaling的能力和Go语言开箱即用的特性简化并发。

我们仅仅用了4台机器,这并不是什么新鲜事了。可能它们还不如我的MacBook能力强大,但是却处理了每分钟1百万的写入到S3的请求。

处理问题有正确的工具。当你的 Ruby on Rails 系统需要更强大的web handler时,可以考虑下ruby生态系统之外的技术,或许可以得到更简单但更强大的替代方案。

[文章原文][7]


[1]: http://www.malwarebytes.org/
[2]: https://raw.githubusercontent.com/itfanr/articles-about-golang/master/2016-10/1-1.png
[3]: http://12factor.net/
[4]: https://raw.githubusercontent.com/itfanr/articles-about-golang/master/2016-10/1-2.png
[5]: https://raw.githubusercontent.com/itfanr/articles-about-golang/master/2016-10/1-3.png
[6]: https://raw.githubusercontent.com/itfanr/articles-about-golang/master/2016-10/1-4.png
[7]: http://marcio.io/2015/07/handling-1-million-requests-per-minute-with-golang/

谁知道有用go写的开源项目,用来扫描IP和端口的?

回复

有问必答astaxie 回复了问题 • 2 人关注 • 1 个回复 • 3219 次浏览 • 2016-10-14 10:44 • 来自相关话题

10.10 每日早报

技术讨论astaxie 发表了文章 • 0 个评论 • 1421 次浏览 • 2016-10-10 09:12 • 来自相关话题

新闻: 1.华为发布国内首份Android 7.0应用兼容报告,数千款经典应用中83%兼容 2.万达旅业整体并入同程,同程管理团队增资10亿保持投票权第一 3.Fill耳机音乐平台碎 ...查看全部
新闻:

1.华为发布国内首份Android 7.0应用兼容报告,数千款经典应用中83%兼容

2.万达旅业整体并入同程,同程管理团队增资10亿保持投票权第一

3.Fill耳机音乐平台碎乐App上线,集合部分分答与弹幕视频App功能

4.IT人才培训平台51CTO完成过亿元人民币B轮融资,华开投资领投
5.三星Gear VR中国区应用商店上线,Gear VR入华长路漫漫

6.爱回收正式开启品牌升级战略,推出估价、隐私和环保等三大体系

7.苹果欧洲首家iOS开发者学院开学,首批100名学生开始接受免费培训

8.食品一站式平台格格家完成1亿元A+轮融资,广发信德领投

资源:

2016年全球快速消费品电商研究报告 http://www.kantarworldpanel.com/dwl.php?sn=news_downloads&amp;id=1197  
2016年美国五大产业风险投资报告 http://martinprosperity.org/media/Startup-US-2016_Industrial-Clusters.pdf

注:上述内容来源于互联网,由EGO整理

第二届 Gopher China 大会

Golang傅小黑 发表了文章 • 0 个评论 • 1823 次浏览 • 2016-10-09 21:44 • 来自相关话题

又一次,和同事去参加 GopherChina 2016 大会,了解 Go 语言相关的最新动态。和一年前不同,Go 语言已经受到许多企业青睐。一些知名企业开始使用 Go 语言开发。因而,本届大会更多的内容注重在 Go 实现的业务场景和架构上。 ...查看全部
又一次,和同事去参加 GopherChina 2016 大会,了解 Go 语言相关的最新动态。和一年前不同,Go 语言已经受到许多企业青睐。一些知名企业开始使用 Go 语言开发。因而,本届大会更多的内容注重在 Go 实现的业务场景和架构上。

Go 与 高并发服务

Go 语言的 goroutine 特性,非常适合开发高并发网络服务。大会有几个题目聊起相关的内容。

百度前端接入团队分享了《Go在百度BFE的应用》。相关的内容其实在InfoQ有过分享。百度的服务体量太过巨大(日均千亿),代码优化手段 + Go的版本更新 对服务整体的提升作用不大,只能用特殊的措施 ———— 车轮大战。关闭 runtime 的GC,由代码根据目前程序的运行情况判断是否手动 runtime.GC()。以 master-worker的模式轮换正在服务和正在GC的程序。这种架构估计只有百度这种规模才用得上吧。但是私下的交流来说,小伙伴还是觉得 nginx + C 模块更适合。况且BFE之前那套也就是C写的,有足够的技术实力。

对比的来看是,吴小伟(skoo)的《Go在阿里云CDN系统的应用》。阿里 CDN 的网络接入系统还是 C 语言写的。CDN 的日志系统、调度系统和刷新系统是 Go 写的。这些业务对 Go 语言的 GC 不敏感,加上 Go 比 C 更简洁的语法特性,更快的开发效率,开发周围系统是很适合的。这里可以看到,同样是大流量系统,思考的角度也有不同。顺便说一下,skoo 是比较早研究 Go 语言的技术大神之一,博客有一些关于 Go 核心原理的文章。

Go 与 分布式服务

大会里的几个 Go 开发的分布式服务涉及数据库,存储,搜索。

刘奇的《Go在分布式数据库中的应用》主要是分享他主导开发的 TiDB 分布式数据库。TiDB 是基于 kv 存储的 SQL 分布式数据库。想一下,必然有 KV 存储层,KV 到 SQL 的转换,SQL 连接协议,以及分布式相关的模块。首先,使用 rust 开发了 TiKV 分布式 kv 存储系统,类似 HBase。然后使用 Go 开发兼容各种 kv 存储的 API 层,SQL 处理层, MySQL 协议层 和 分布式管理。TiDB 最核心的部分是 Placement Driver 分布式管理模块,负责路由数据存储的region,存储region的schema和region扩容复制及删除。关于数据库开发我没有什么经验,只能听听参考思路。

毛剑的《Go在数据存储上面的应用》参考 Facebook 的 Haystack paper 实现自己的小文件存储系统 bfs。存储系统一般的结构包括目录路由和存储节点。目录路由负责定位资源实际的存储位置。存储节点负责实际数据存储过程处理,比如合并。bfs 再加上了对外统一的 API 层 ———— 暴露简单的操作接口屏蔽细节, pitchfork 心跳监控层 ———— 保证节点可用性。毛大很细节的讲了各个模块的实现,及存储数据的流动过程、副本复制和节点灾备的问题。内容充足有条理,听的比较好而且可以参考学习的细节较多。

陈辉聊了一下《Go 与人工智能》。题目很大,主要的内容是分词算法、搜索引擎、抓取工具和机器学习。算是一般大数据研究需要的基础智能技术。wukong 搜索 和 sego 分词已经很早以前放出了。wukong 搜索是一个搜索引擎架子,有很好的定制化能力。除了基本的分词、索引和排序,还可以自己添加算法进行筛选。wukong搜索目前是全数据都加载到内存的。希望以后可以更方便的支持实时数据落地和读取,减小内存占用。

Go 与 容器

Docker 是 Go 的明星产品,但是已经形成自己的生态。单纯聊 Docker,就有很大一系列内容。大会的两个题目主要聊的内容是 Go 在 Docker 集群中的作为外在工具的角色。

小米高步双《Go在小米商城运维平台的应用与实践》很大的篇幅在说使用 Docker 搭建了 MAE(Mall App Engine) 集群满足小米商城的业务需求。Go 语言开发了 Docker 中的模块,集群 Router 和 Monitor。Docker 的 API 对 Go 友善。使用 Go 开发管理工具更方便控制 Docker 集群。演讲中提到了 fasthttp,比 net/http 性能更高。我以前有篇 文章 分析 fasthttp,它并不适合做 HTTP 长连接服务。另外还提及了一下 TCP 的 Multiplex Connection,令我想起了 HTTP2。

Daocloud 的孙宏亮对 Docker 有深刻的研究。更多的说 Daocloud 关于公共 Docker 集群的架构,关于 Go 的内容聊的比较少。孙老师对于 Go 操作进程和系统命令的能力很满意,使用 Go 开发了 Daocloud 很多的辅助功能工具,但是可惜没有深入介绍。

另一个容器化的明星是 CoreOS。大会上邓洪超的《Go在CoreOS分布式系统的性能调试和优化》很热情的介绍基于 CoreOS 的容器隔离体系。我并不熟悉 CoreOS 体系,这次的内容权当是科普。容器化的世界不仅仅是 Docker 的世界。去看看更多的技术开眼界也是极好的。

Go 与 Web

Go 的 HTTP 包已经足够实现 Web API 服务。但是 html/template 包的诡异语法对实现繁多复杂页面的 Web 站点并不是很好的选择。米嘉的演讲《Go build web》利用代码生成来满足对应的需求。路由部分继承 Gin 和 Goji 的中间件思路,数据库操作部分使用go generate命令自动生成结构体操作的代码,再开发了一个工具做start-kit的boilerplate做前端资源、热更新等的支持,这几个部分组成了完善的 Go Web 技术栈工具。其实目前很多新手是从 Web 方面开始学习 Go 语言。熟练使用或者自己参照实现类似的技术工具,还是很不靠谱的。如果真要学习,还可以去看看 goa 这个利用 Go 做 DSL 的代码生成工具。

Go 与 移动开发

沈晟沈老板为我们带来了《Golang在移动客户端开发中的应用》。沈老板在比较多的是说团队对 [gomobile] 的探索和尝试。目前 Go 参与 mobile 开发的方式是将一些算法库或者逻辑库编译成 c-archive 或者 .so 嵌入到 app 中,并不是代替 Obj-C 或者 Java 作为主力开发的角色。介绍的内容还都是概念性的演示,还没有实际案例。GopherCon India 有几个关于 mobile 演讲比这次更加激进一些,有兴趣的同学可以去 看看。

Go 的细节

Go 开发组的两位外国友人在更加细致的尺度上描述了 Go 语言的一些功能和特性。

Marcel van Lohuizen 主要介绍了 《I18n and L13n for Go using x/text》,golang.org/x/text 库的功能和计划。我并不熟悉文本编码方面的知识,但是看作者在各种字符集之间操作正确处理本地化差异的时候,所做的工作,感到由衷的敬佩。针对某个库某一些功能做了细致入微的研究,是国外技术人员很优秀的品质。而且演讲的内容丰富,很多细节很有意思,我觉得很有趣很好玩,从来没想过本地化和国际化还有这么多门道。

Dave Cheney 是 GB 版本管理工具的作者,Go 语言的 linker 的主要维护者,对 Go 语言细节有很深的认识。这次《Writing High Performance Go》从代码书写、调试、测试的层面帮助使用者提升技巧。比如如何避免 string 和 []byte 转换时的内存拷贝的影响,预想创建适当长度的 slice 避免扩容浪费,多使用 bufio 来操作字节流,思考和明确代码中 goroutine 的生命周期,使用队列池等方式控制 goroutine 的数量等。Slide 中列举了很多需要考虑的细节和使用注意,非常的赞。而且 slide 是使用 Go 的 present 工具生成的,一边展示一边直接操作代码,非常的直观。而且为了介绍 net/http/pprof 竟然在 present 工具开启了 pprof 为我们展示,表现力超赞。

这里可以发现很多时候我们不仅仅是需要面对各种复杂业务的规划和架构能力,还需要对使用的工具细致入微的操控能力。

Go 的持续集成

Grab 的 赵畅 的 《Golang项目的测试,持续集成以及部署策略》也是我觉得非常赞的一组内容。不仅描述 Go 的开发,测试,持续集成和部署,而且介绍创业公司对各种不同领域的云服务的应用。使用 gometalinter 检查代码规范和代码质量,使用 testify 简化测试逻辑,从 Travis CI 到自己搭建 Jenkins 的集成服务演进之路,还有 Scalyr 日志分析,Slack 团队项目管理。国外的团队对各种第三方的辅助工具有非常充分的利用,而国内创业企业还不愿意去尝试这些方式。

技术沙龙

第一天的大会后晚上举行了技术沙龙,有 Go vs Rust 和 Docker vs VM 的两场大战。

Go 和 Rust 的战斗集中在代码风格和社区文化上。Go 和 Rust 虽然都是近些年发展的语言,但是很多的思考看得出现在的语言的发展。 Go 秉承降低心智负担的基本原则,以最简单直接以至于简陋的方式来实现,比如 if err != nil 到处都是。这样逼迫使用者仔细思考每一步的问题,把error认为正常逻辑里的一环去深入考虑。而 Rust 使用 try(fn()) 和 fn()? 更优雅的处理错误也是大多数程序员希望的事情。谁也不愿意反复的写if err的语句。而且 try 这种方式也是借鉴其他语言的成功经验的。可以认为大多数不是心智太低,不需要像 Go 强制让你仔仔细细思考清楚的,还是更愿意接受稍微复杂了一点的 try 方式。Go 的 error 是 value 不是错误,这个哲学使它将 error 和其他正常值等价考虑,才有这样繁琐了一些的操作。try 的使用意味着这里在操作一个特殊的值 error,让大家注意。到底该如何对待 error,估计还是会有持久的论战。

Docker 容器化是新兴的分布式系统部署方案,VM 部署已经是成熟的解决方案。使用新兴的方案未必会带来足够好的效益,也是大家考虑担忧的一点。我觉得 Docker 适应微服务架构,重点除了更清晰的架构划分,更细粒度的资源控制外,还有就是可描述的架构模型。Docker 容器体系的编排和调度工具,就是对大规模应用有了一种可以描述的方式,就是编排和调度配置。这对于以后如何控制大规模的集群有重要意义。

很多大神们

BetaGo 和 毛剑 之前就认识,只是他俩坐下来就是在聊妹子,我呵呵呵呵呵。Asta谢作为主办者,还是一直忙前忙后没有停歇。刘奇 大神光亮的头顶非常的好辨认,郝林比我看到的照片里感觉更胖了哈哈。

我只是个普通的程序员,并不是大神。参加大会还是了解和学习,帮助自己做好工作,我就满足了。

Go编码规范指南

技术讨论astaxie 发表了文章 • 1 个评论 • 12343 次浏览 • 2016-10-09 21:09 • 来自相关话题

# Go编码规范指南 ## 序言 看过很多方面的编码规范,可能每一家公司都有不同的规范,这份编码规范是写给我自己的,同时希望我们公司内部同事也能遵循这个规范来写Go代码。 如果你的代 ...查看全部
# Go编码规范指南

## 序言

看过很多方面的编码规范,可能每一家公司都有不同的规范,这份编码规范是写给我自己的,同时希望我们公司内部同事也能遵循这个规范来写Go代码。

如果你的代码没有办法找到下面的规范,那么就遵循标准库的规范,多阅读标准库的源码,标准库的代码可以说是我们写代码参考的标杆。

## 格式化规范

go默认已经有了gofmt工具,但是我们强烈建议使用goimport工具,这个在gofmt的基础上增加了自动删除和引入包.

```
go get golang.org/x/tools/cmd/goimports

```

不同的编辑器有不同的配置, sublime的配置教程:[http://michaelwhatcott.com/gosublime-goimports/](http://michaelwhatcott.com/gosublime-goimports/)

LiteIDE默认已经支持了goimports,如果你的不支持请点击属性配置->golangfmt->勾选goimports

保存之前自动fmt你的代码。

## 行长约定

一行最长不超过80个字符,超过的请使用换行展示,尽量保持格式优雅。

## go vet

vet工具可以帮我们静态分析我们的源码存在的各种问题,例如多余的代码,提前return的逻辑,struct的tag是否符合标准等。

```
go get golang.org/x/tools/cmd/vet

```

使用如下:

```
go vet .

```

## package名字

保持package的名字和目录保持一致,尽量采取有意义的包名,简短,有意义,尽量和标准库不要冲突。

## import 规范

import在多行的情况下,goimports会自动帮你格式化,但是我们这里还是规范一下import的一些规范,如果你在一个文件里面引入了一个package,还是建议采用如下格式:

```
import (
"fmt"
)

```

如果你的包引入了三种类型的包,标准库包,程序内部包,第三方包,建议采用如下方式进行组织你的包:

```
import (
"encoding/json"
"strings"

"myproject/models"
"myproject/controller"
"myproject/utils"

"github.com/astaxie/beego"
"github.com/go-sql-driver/mysql"
)

```

有顺序的引入包,不同的类型采用空格分离,第一种实标准库,第二是项目包,第三是第三方包。

在项目中不要使用相对路径引入包:

```
// 这是不好的导入
import “../net”

// 这是正确的做法
import “github.com/repo/proj/src/net”

```

## 变量申明

变量名采用驼峰标准,不要使用`_`来命名变量名,多个变量申明放在一起

```
var (
Found bool
count int
)

```

在函数外部申明必须使用var,不要采用`:=`,容易踩到变量的作用域的问题。

## 自定义类型的string循环问题

如果自定义的类型定义了String方法,那么在打印的时候会产生隐藏的一些bug

```
type MyInt int
func (m MyInt) String() string {
return fmt.Sprint(m) //BUG:死循环
}

func(m MyInt) String() string {
return fmt.Sprint(int(m)) //这是安全的,因为我们内部进行了类型转换
}

```

## 避免返回命名的参数

如果你的函数很短小,少于10行代码,那么可以使用,不然请直接使用类型,因为如果使用命名变量很
容易引起隐藏的bug

```
func Foo(a int, b int) (string, ok){

}

```

当然如果是有多个相同类型的参数返回,那么命名参数可能更清晰:

```
func (f *Foo) Location() (float64, float64, error)

```

下面的代码就更清晰了:

```
// Location returns f's latitude and longitude.
// Negative values mean south and west, respectively.
func (f *Foo) Location() (lat, long float64, err error)

```

## 错误处理

错误处理的原则就是不能丢弃任何有返回err的调用,不要采用`_`丢弃,必须全部处理。接收到错误,要么返回err,要么实在不行就panic,或者使用log记录下来

### error 信息

error的信息不要采用大写字母,尽量保持你的错误简短,但是要足够表达你的错误的意思。

## 长句子打印或者调用,使用参数进行格式化分行

我们在调用`fmt.Sprint`或者`log.Sprint`之类的函数时,有时候会遇到很长的句子,我们需要在参数调用处进行多行分割:

下面是错误的方式:

```
log.Printf(“A long format string: %s %d %d %s”, myStringParameter, len(a),
expected.Size, defrobnicate(“Anotherlongstringparameter”,
expected.Growth.Nanoseconds() /1e6))

```

应该是如下的方式:

```
log.Printf(
“A long format string: %s %d %d %s”,
myStringParameter,
len(a),
expected.Size,
defrobnicate(
“Anotherlongstringparameter”,
expected.Growth.Nanoseconds()/1e6,
),


```

## 注意闭包的调用

在循环中调用函数或者goroutine方法,一定要采用显示的变量调用,不要再闭包函数里面调用循环的参数

```
fori:=0;i go func(){ DoSomething(i) }() //错误的做法
go func(i int){ DoSomething(i) }(i)//正确的做法
}

```

[http://golang.org/doc/articles/race_detector.html#Race_on_loop_counter](http://golang.org/doc/articles/race_detector.html#Race_on_loop_counter)

## 在逻辑处理中禁用panic

在main包中只有当实在不可运行的情况采用panic,例如文件无法打开,数据库无法连接导致程序无法
正常运行,但是对于其他的package对外的接口不能有panic,只能在包内采用。

强烈建议在main包中使用log.Fatal来记录错误,这样就可以由log来结束程序。

## 注释规范

注释可以帮我们很好的完成文档的工作,写得好的注释可以方便我们以后的维护。详细的如何写注释可以
参考:[http://golang.org/doc/effective_go.html#commentary](http://golang.org/doc/effective_go.html#commentary)

### bug注释

针对代码中出现的bug,可以采用如下教程使用特殊的注释,在godocs可以做到注释高亮:

```
// BUG(astaxie):This divides by zero.
var i float = 1/0

```

[http://blog.golang.org/2011/03/godoc­documenting­go­code.html](http://blog.golang.org/2011/03/godoc%C2%ADdocumenting%C2%ADgo%C2%ADcode.html)

## struct规范

### struct申明和初始化格式采用多行:

定义如下:

```
type User struct{
Username string
Email string
}

```

初始化如下:

```
u := User{
Username: "astaxie",
Email: "astaxie@gmail.com",
}

```

### recieved是值类型还是指针类型

到底是采用值类型还是指针类型主要参考如下原则:

```
func(w Win) Tally(playerPlayer)int //w不会有任何改变
func(w *Win) Tally(playerPlayer)int //w会改变数据

```

更多的请参考:[https://code.google.com/p/go-wiki/wiki/CodeReviewComments#Receiver_Type](https://code.google.com/p/go-wiki/wiki/CodeReviewComments#Receiver_Type)

### 带mutex的struct必须是指针receivers

如果你定义的struct中带有mutex,那么你的receivers必须是指针

## 参考资料

1. [https://code.google.com/p/go-wiki/wiki/CodeReviewComments](https://code.google.com/p/go-wiki/wiki/CodeReviewComments)

2. [http://golang.org/doc/effective_go.html](http://golang.org/doc/effective_go.html)

golang的goroutine是如何实现的?

回复

技术讨论astaxie 回复了问题 • 5 人关注 • 1 个回复 • 5535 次浏览 • 2016-10-09 20:26 • 来自相关话题

golang在处理网络高并发方面有哪些优势?

有问必答astaxie 回复了问题 • 2 人关注 • 1 个回复 • 2714 次浏览 • 2016-10-09 20:06 • 来自相关话题