Quantcast
Channel: IT社区推荐资讯 - ITIndex.net
Viewing all 15891 articles
Browse latest View live

ARM架构是什么?为什么高通三星都依赖他?

$
0
0

近十年的移动互联网发展,让智能手机大规模普及,也带火了一个曾经并不为人广泛知道的公司——ARM。这家成立于英国剑桥的芯片设计公司在 1985 年研发出了精简指令集架构处理器,名为 Acorn RISC Machine,而简称就是著名的 ARM。作为一家处理器设计公司,其研发的 ARM 架构最初面向的是低功耗、低成本、高性能处理器。

ARM 架构是一种采用独特的 ARM 指令集系统、并且根据不同适用范围开发的处理器体系结构。经过 30 多年的发展,目前 ARM 架构有针对不同类型计算设计的体系结构。简单来说有这几种。

Cortex-A:针对高性能计算。如我们目前手机 SoC 中常出现的 Cortex-A76 等。

Cortex-R:针对实时操作处理。主要是面向嵌入式实时处理器。在汽车的电子制动系统,工业控制领域等领域比较常见。

Cortex-M:专为低功耗、低成本系统设计。目前火热的 IoT 领域常常见到采用 Cortex-M 架构的处理器。

ARM 架构,更主要的是 ARM 指令集系统。不同于 x86 架构的复杂指令集(CISC)架构,是一种精简指令集(RISC)架构。相对于 CISC 架构处理器,采用精简指令集设计的 ARM 架构设计目标是能在尽量高的时钟频率下通过很少周期执行的指令集。大幅减少不常用的指令,降低芯片复杂度。采用 Load/Store 指令体系结构,处理器通过 load、store 指令存取内存中的数据,针对逻辑、算术等运算,CPU 只处理寄存器中的数据。同时由于这个原因,包括 ARM 在内的很多 RISC 架构处理器都有很多寄存器来存放指令及数据。为了方便指令的解码,虽然 ARM 处理器不是单周期指令,但是其绝大多数指令是定长的,加快了常用操作的速度。

同时 ARM 也没有完全局限于此,ARM 架构还有像 Thumb 指令集、条件执行等技术,进一步提高处理器效率。

所以总结来说,ARM 架构就是采用精简指令集计算机结构、但有自己特色,根据不同用途有不同型号的处理器架构。

那么为什么高通、三星都以来 ARM 架构呢?

有以下几点原因可供参考。

首先是授权。众所周知,x86 架构由于授权问题只有几家可以生产,包括现在的 Intel、AMD,曾经的威盛。而全美达也只是生产出了基于纯软件模拟 x86 处理器的 CPU。国内的兆芯及海光也有一定的授权限制。

除了 x86 外,另一套著名的指令集系统 MIPS 是可以授权生产的,虽然授权费用比较贵,但是其灵活性极高,所以出现了比较严重的“碎片化”。有能力设计的都在自主设计微架构、添加指令等。如国内的龙芯、索尼的 PSP 游戏机等。

而 ARM 的授权方式有多种。首先是处理器授权,这种授权方式只授权已经设计好的内核,工厂等买到后自己发挥的余地不多。如海思部分麒麟处理器就是采用这种方式。还有一种是架构/指令集授权,这种方式在微结构设计上有更多的灵活性,如苹果的 vortex,三星的 M3、M4、高通的 Krait 等。同时即使厂商在定制自己的微架构,但是在指令集上有限制,这样即使厂商修改软件层面如编译器等工具,也不需要大更改。所以出现了现在 Android 手机处理器多家争鸣的情况。既保证了兼容性,厂商又能充分发挥。所以高通、三星等厂商选择 ARM 处理器也是最好的选择。

虽然现在 MIPS 及 IBM 的 Power 架构也已开源,而且现在也有 RISC-V 这样一开始就开源且已初具规模的开源指令集及架构,但是独特的授权策略让 ARM 拥有了一批忠实拥趸。

其次是适用范围。虽然 ARM 架构在强调低功耗高性能,但是其在近几年前适用范围还是相对较窄的,一直活跃在嵌入式、手持设备等低功耗领域。合作伙伴也是多生产低功耗处理器。甚至 Intel 也曾经出品过基于 ARM 指令集的 XScale 处理器,Dell 曾经生产过基于这个处理器的 PDA(恍如隔世,很老的概念了)。而本世纪头十年最火的手机品牌诺基亚的塞班智能手机中也使用过 ARM11 架构的处理器。而现在高通、三星是重要的手机 SoC 设计生产商,所以他们选择 ARM 架构不仅可以迅速切入低功耗处理器市场,而且也可以借助 ARM 的丰富经验快速设计出强大的处理器。

最后就是乘上了移动互联网的东风,在智能手机最需要计算性能的时候提供了足够的性能,为处理器设计生产厂商提供了足够的经验。ARM 公司早在 2002 年(距 2019 年已经 17 年了)就开发出了 ARM11 架构及处理器。而到了 8 年之后的 2010 年,依旧有手机使用 ARM11 架构处理器的手机,如曾经小编使用过的摩托罗拉 ME600 后空翻使用的是高通 MSM7201A SoC,其 CPU 部分就是 ARM11 架构。而随后 Cortex-A8 早在 2005 年就研发完成了。所以等 Android 手机开始兴起时,ARM 公司及其合作伙伴就已经拥有足够的经验了,而性能也符合当时 Android 手机的需求。现在高通的骁龙处理器及三星的 Exynos 处理器在 Android 手机界是重要的组成部分,所生产的 SoC CPU 部分都是采用 ARM 设计的内核或指令集的。

高通,三星等公司就是因为与 ARM 公司紧密的合作让我们拥有了现在这么强大的智能手机,所以他们算是休戚与共了。同时高通、三星在依赖 ARM 提供的处理器架构、指令集的同时,ARM 也需要像三星、台积电等公司的支持,将还是代码的处理器内核编程实际的硅芯片。所以这并不是一个谁依赖谁的问题,而是各方通力合作的结果。

本文链接


mXtract:一款功能强大的内存数据提取&分析工具

$
0
0

mXtract

mXtract是一款开源的Linux安全工具,该工具可从目标系统的内存中提取并分析数据。从本质上来说,mXtract是一款防御端渗透测试工具,它的主要功能是扫描目标系统内存并尝试通过正则表达式来从中提取出私钥、IP和用户密码等敏感数据。请记住,扫描结果跟正则表达式的质量息息相关…

工具截图

mXtract

Verbose模式扫描单个IP正则式,扫描单个数据段,显示整个扫描进程信息以及扫描的环境文件。

mXtract

Verbose模式扫描单个IP正则式,扫描范围仅限堆栈空间,显示扫描进程信息,扫描环境文件。

mXtract

简单扫描,单个IP正则式,显示扫描进程信息,扫描环境文件。

为什么直接从内存中导出数据?

在大多数Linux环境中,用户可以直接访问进程的内存信息,这将允许攻击者收集用户凭证、私钥或其他敏感信息。

功能介绍

1、 可输入正则表达式列表;

2、 清晰可读的显示数据;

3、 使用当前权限检测内存范围是否可写;

4、 以XML和HTML格式输出数据;

5、 大规模扫描每一个进程或特定的PID;

6、 选择特定的内存区域进行扫描;

7、 显示详细的进程信息;

8、 扫描进程环境文件;

9、 内存数据自动导出,并移除Unicode字符

工具下载

git clone https://github.com/rek7/mXtract

工具编译

cd mXtract && sh compile.sh

命令运行完成之后,将创建/bin/目录,并将代码编译为mxtract。

命令

mXtract

工具使用样例

$./mxtract -wm -wr -e -i -d=/tmp/output/ -r=example_regexes.db

项目地址

mXtract:【 GitHub传送门

* 参考来源: mXtract,FB小编Alpha_h4ck编译,转载请注明来自FreeBuf.COM

通过 Flask, Docker, Jenkins 和 Kubernets 部署机器学习模型

$
0
0

本文主要介绍部署机器学习模型的一种自动化方式,如题所示,通过 FlaskDocker, JenkinsKubernets实现。基本原理就是通过 Fflask 提供暴露出 RESTful API接收客户端的 predict 请求,然后将这个服务打包成一个 docker image 便于部署和迁移,当代码或模型更新时通过 Jenkins 触发自动构建新的 docker image,而通过 kubernets 管理容器则让整个服务具备伸缩性和可靠性。本文主要参考了 Deploy a machine learning model in 10 minutes with Flask, Docker, and Jenkins,并在其基础上进行了完善和拓展,如通过一个简单的 shell script 实现 jenkins 的触发功能,并添加了 kubernets 部分的介绍等。本文的对应的所有代码可从 DeployMachineLearningModel获取。

下文基本可以依样画葫芦走一遍,为了避免不必要的麻烦,尽量不要在 windows 下配置,虽然上述这些工具也提供了 windows 的版本,但是使用起来总是出现各种问题;也不要在win10 的 wsl 中配置,因为 docker 涉及到了 linux 底层的 cgroup,在 wsl 中并不能直接安装 docker。本文的实验时最开始为了方便在上面提到的两个环境中进行了实验,结果是折腾了好久,最后通过在 virtual box 中的 ubuntu 16.04 进行以下的实验。

下图摘自文章前面提到的 Deploy a machine learning model in 10 minutes with Flask, Docker, and Jenkins,从中可以看到清晰看到整个部署和访问的流程

deploy model

Flask 提供 RESTful api

Flask 的作用主要是提供 RESTful api 供客户端进行 predict,像 Google、Microsoft、Face++ 这些公司提供的 AI 服务(即人脸识别,表情识别等),基本都是通过 RESTful api 提供的,其基本原理是客户端将通过 POST 请求将需要预测的样本发送到服务器,然后服务器提取样本进行预测并返回结果;且通常还需要附带 id 判别身份,从而进行相应的扣费,这里为了简单起见不会去考虑这些问题。

通过 Flask 能够非常简单地在搭建一个 HTTP Server 并在指定端口监听,如果接收到 POST 请求便调用模型进行预测并返回,因此首先需要训练模型并将训练好的模型 load 进内存,为了简单起见,这里的任务是 sklearn 内置的 iris 分类。

训练并保存模型

训练并持久化模型的代码如下所示,对应 train_model.py文件

1     
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# coding: utf-8     
import pickle
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn import tree

# simple demo for traing and saving model
iris=datasets.load_iris()
x=iris.data
y=iris.target

#labels for iris dataset
labels ={
0: "setosa",
1: "versicolor",
2: "virginica"
}

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=.25)
classifier=tree.DecisionTreeClassifier()
classifier.fit(x_train,y_train)
predictions=classifier.predict(x_test)

#export the model
model_name = 'model.pkl'
print("finished training and dump the model as {0}".format(model_name))
pickle.dump(classifier, open(model_name,'wb'))

加载模型并提供调用 api

通过 Flask 能够快速启动一个 http server 并在不同的访问路径设置不同的处理函数,详细语法可参考 官网教程

本文的例子很简单,如下代码所示(对应源文件 server.py),首先把模型 load 进内存,然后设置了访问路径为 /api时调用模型进行 predict,为了简单起见这里没做输入数据的检查和异常处理;最后 app.run启动了一个 server 并默认监听在 5000 端口。

1     
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# coding: utf-8     
import pickle

from flask import Flask, request, jsonify

app = Flask(__name__)

# Load the model
model = pickle.load(open('model.pkl', 'rb'))
labels = {
0: "versicolor",
1: "setosa",
2: "virginica"
}

@app.route('/api', methods=['POST'])
def predict():
# Get the data from the POST request.
data = request.get_json(force = True)
predict = model.predict(data['feature'])
return jsonify(predict[0].tolist())

if __name__ == '__main__':
app.run(debug = True, host = '0.0.0.0')

利用以上两个文件,通过命令 python train_model.py && python server.py便可训练出一个模型并通过 http server 提供访问 api。

客户端要进行预测时可通过如下代码(见源文件 client.py), 这里的 192.168.31.78是我的实验环境里面启动 httpserver 的机器ip( client.py里面使用的是 8000 端口,因为利用了 docker 进行了端口映射,后文会对这一点进行讲解)

1     
2
3
4
5
6
7
8
9
10
11
12
13
# coding: utf-8     
import requests
# Change the value of experience that you want to test
url = 'http://192.168.31.78:5000/api'
feature = [[5.8, 4.0, 1.2, 0.2]]
labels ={
0: "setosa",
1: "versicolor",
2: "virginica"
}

r = requests.post(url,json={'feature': feature})
print(labels[r.json()])

在同一局域网的机器运行上面的代码便能输出 setosa这个预测结果

Docker 打包和运行程序

Docker 的安装参考 Get Docker CE for Ubuntu, 这里不再赘述

打包

利用 Docker 可以将上述部署的环境打包成一个 image,便于部署、迁移和弹性扩展(配合 Kubernets 使用),因此下文主要描述如何通过 Dockerfile 构建 image,关于 Dockerfile 的详细语法可参考 文档,这里只列出本文用到的一些语法。

类似 shell 脚本,Dockerfile 里面是一系列的指令,作用是让 Docker 通过 Dockerfile 和 docker build命令自动构建出目标 image。

在执行 docker build 命令时通过 -t 指定生成的 image 的 tag,能够保存生成的 image,如 docker build -t shykes/myapp .,最后的 .表示 Dockerfile 的目录,即这条命令是在 Dockerfile 所在目录下执行

Dockerfile 的基本原理是首先通过 FROM命令获取一个基本的 image,然后在这个 image 基础上通过各种命令配置好我们运行程序需要的环境,接着把我们的源文件复制到 image 里,进行构建和运行。

Dockerfile 中值得注意事项如下,为了保持原意这里不进行翻译

  • each instruction is run independently, so RUN cd /tmp will not have any effect on the next instructions
  • basic syntax is INSTRUCTION arguments, the instruction is not case-sensitive. However, convention is for them to be UPPERCASE to distinguish them from arguments more easily.
  • A Dockerfile must start with a FROM instruction. The FROM instruction specifies the Base Image from which you are building
  • FROM can appear multiple times within a single Dockerfile to create multiple images or use one build stage as a dependency for another
  • Docker treats lines that begin with # as a comment
  • RUN <command> (the command is run in a shell, which by default is /bin/sh -c on Linux or cmd /S /C on Windows
  • There can only be one CMD instruction in a Dockerfile. If you list more than one CMD then only the last CMD will take effect.
  • RUN v.s CMD. RUN actually runs a command and commits the result; CMD does not execute anything at build time, but specifies the intended command for the image.
  • The WORKDIR instruction sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile. If the WORKDIR doesn’t exist, it will be created even if it’s not used in any subsequent Dockerfile instruction
  • COPY <src>... <dest>; The COPY instruction copies new files or directories from <src> and adds them to the filesystem of the container at the path <dest>;The <dest> is an absolute path, or a path relative to WORKDIR, If <dest> doesn’t exist, it is created along with all missing directories in its path.
  • ADD <src> <dest>; The ADD instruction copies new files, directories or remote file URLs from <src> and adds them to the filesystem of the image at the path <dest>
  • COPY v.s ADD. COPY only lets you copy in a local file or directory from your host (the machine building the Docker image) into the Docker image itself. ADD lets you do that too, but it also supports 2 other sources. First, with ADD you can use a remote URL instead of a local file / directory . Secondly, you can extract a tar file** from the source directly into the destination.
  • Environment variables (declared with the ENV statement) can also be used in certain instructions as variables to be interpreted by the Dockerfile; Environment variables are notated in the Dockerfile either with $variable_name or ${variable_name}

因此,构建上述的环境的 Dockerfile 如下所示, 参考链接中的 Dockerfile 中有两个 FROM 语句,分别表示 ubuntu 环境和 python 环境,且需要安装 pip 等工具,这里直接通过 nitincypher/docker-ubuntu-python-pip提供这些功能

1     
2
3
4
5
6
7
8
9
10
11
12
# train and run the model with RESTful api     
FROM nitincypher/docker-ubuntu-python-pip

COPY ./requirements.txt /app/requirements.txt

WORKDIR /app

RUN pip install -r requirements.txt

COPY . /app

CMD python /app/train_model.py && python /app/server.py

实验的项目路径为 /opt/src/DeployMachineLearningModel, 则构建 image 的命令为 docker build -t deploy_ml_model ., 其过程如下所示,可以看到

1)构建前系统的 docker images 情况,由于之前已经运行过这条命令,因此依赖的 nitincypher/docker-ubuntu-python-pip也已经 pull 到本地了。如果是第一次运行,则下载 nitincypher/docker-ubuntu-python-pip需要一定的时间
2) Dockerfile 中每条命令都是运行时的一个 step,在构建时不会运行 CMD的命令,而是通过 docker run时才执行

build

构建完成后可以看到系统中的多了 deploy_ml_model这个 image

after build

运行

接着需要运行这个 image,运行的 container 内部 Flask 在监听 5000 端口,因此需要通过端口映射为外部机器可见的端口,通过命令 docker run -p 8000:5000 deploy_ml_model可通过运行 docker 的机器的 8000 端口访问 container 内部提供的 api,如下所示

run container

将上面的客户端的代码的端口改成 8000 便是 client.py源文件了,运行 client.py结果如下所示,

response

此时的 server 接收到一个 POST 请求,输出的日志如下

server log

如果需要停止运行的 container,通过 docker stop并指定 container 的 id 即可, container id 并不需要全输入,只需要输入能系统能区分不同 container 的程度即可。该过程如下所示

stop container

Jenkins或自定义脚本触发自动构建

上面的构建流程中,只要每次代码或模型有更新便需要重新手动执行 docker builddocker run, 而通过 jenkins 或自定义的脚本便能让这个流程自动化,这个过程需要结合 Github 实现,即当代码仓库有更新时,便自动构建新的 image。

其基本原理是 Github 在 repository 发生变化时,会向指定的 url 发送一个 POST 请求告知 repository 有更新,只要我们监听这个 url 并在收到这个 POST 请求时进行更新即可,这个机制在 Github 中被称为 WebHooks。Github 提供的 WebHooks 中涵盖了多种更新情况,不同的更新对应于不同的 event,可以在 Github 中自定义需要触发的事件,默认触发的是 PUSH 事件(如commit、PR 等)。

Jenkins 自动构建

Jenkins 在 Ubuntu 下的安装参考 Installing Jenkins,这里不再赘述

Jenkins 是一个功能齐全的自动化构建工具,类似 Docker 通过 Dockerfile 定义 image 的构建过程,jenkins 也能通过 Jenkinsfile 定义工程的构建过程。

但是本文只用到其接收到 Github 发送的 POST 请求并触发其重新构建的功能,其配置流程如下,首先新建一个自由风格的项目,并配置其为 Github 项目,管理源码的方式为 git,如下所示

configure

然后配置触发方式和构建的命令如下图所示

configure

配置并保存后便可直接 “立即构建” 进行项目的构建,jenkins 会自动下载仓库并进行构建,通过控制台输出可以看到构建过程,该过程如下所示

build

点击控制台输出后显示的日志

log

上面提到了触发 jenkins 自动构建的原理,即当代码仓库有更新时,github 会发送 POST 请求给 jenkins,然后 jenkins 会进行自动构建,这种情况下 jenkins 首先需要有一个能够接受 github 的 POST 请求的 url,但是 jenkins 当前是部署在局域网内部的,这时便需要借助 ngrok这个工具来生成一个 github 能够访问的 url 了

ngrok 的作用就是为局域网内部的机器生成一个 public url,从而使得内部的服务能够被其他机器访问,其基本原理就是 ngrok 在这个访问过程中提供了中转。ngrok 的下载和安装都很简单,可参考上面上面的 ngrok 的官网,这里不再赘述。

由于 jenkins 在本地的端口是8080,因此通过 ngrok 为 jenkins 生成 public url 如下所示,可以看到生成了 http 和 https 两个类型的地址;最下面显示的是最近的请求情况,可以看到 github 发送了3个更新的 POST 请求

ngrok

得到 public url 后,需要将其配置到 github 项目的 webhook 中,打开 github 项目的地址,点击 setting 进行设置,设置如下所示,Payload URL 为通过 ngrok 得到的 public url 加上 /github-webhook/路径,注意不能省略最后的斜杆,否则会出现 403 No valid crumb was included in the request的错误

webhook

点击 update webhook 后(第一次是 save)后,github 便会向 payload url 发送一个 POST 请求,就是在上上一张图最下方显示的 POST 请求。

这样当 github 的仓库有更新时就会自动触发 jenkins 进行自动构建,但是由于前一个构建任务会一直运行 http server 接受,因此会出现如下图的 already in progress 的问题,新的 build 会被挂起,直到前一个build 被终止(通过 docker stop) 关掉服务

trigger build

针对这个问题,这个 issue Pushing new commit to existing PR does not stop previous build给出了通过配置 jenkins 的解决方法,但是我在我配置的环境中找不到这个设置选项,试了几遍后却依然找不到这个配置选项,所以就有了下面的自定义脚本进行自动构建。

而针对这个问题,令一种解决方法是在构建命令时只写 docker build, 每次都只是生成最新的 image;而 docker run留给人工去启动,但是这样可能就显得不那么自动化了。

自定义脚本进行自动构建

细想一下上面的触发构建过程,本地需要做的是 jenkins 接受 github 发过来的 POST 请求然后启动 docker builddocker run, 然后由于已经有 container 在跑了,因此无法决定启动新的构建过程。

那其实我们也可以 自己建立一个 http server 接受 github 的 POST 请求,在接受到请求后通过 docker stop停掉当前正在运行的 container 并开始新的构建过程,而借助前文描述的 Flask,我们可以很容易建立一个接受 POST 请求的 http server,代码如下所示(见源文件 hook_server.py)

1     
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# -*- coding: utf-8 -*-     
from flask import Flask, jsonify
import subprocess

app = Flask(__name__)

@app.route('/github_webhook', methods=['POST'])
def rebuild():
print('new commits to github repository')
## subprocess.run can just deal with the first change
## since it stuck in it, use popen instead
# subprocess.run(['sh', 'build_and_run.sh'])
subprocess.Popen(['sh', 'build_and_run.sh'])
return jsonify('got it')

if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=8081)

为了保持一致性,这里的路径也选择为 /github_webhook, 为了简单起见,处理的函数只是接受请求,没有对 POST 请求做进一步的解析,接收到命令后通过 subprocess 新创建一个进程执行重新构建并运行 docker image 的脚本 build_and_run.sh, 注意这里要 使用 subprocess.Popen而不是 subprocess.run, 因为 subprocess.run要等命令执行返回才能继续往下执行,而我们启动的服务也是一个 http server。如果使用 subprocess.run只能在第一次的更新时触发自动构建,之后会一直保持在新创建的进程中而无法处理 github 发过来的新的请求,因此要使用 subprocess.Popen避免这个问题,两者更详细的区别可参考 What is the difference between subprocess.popen and subprocess.run

上面执行的脚本 build_and_run.sh的具体内容如下, 首先通过 git pull 更新代码,这里项目的代码的本地路径为 “/opt/src/DeployMachineLearningModel/“,然后判断当前是否有正在运行的 container,如果有则先 stop,然后再执行构建过程,在构建和运行之间通过 docker image rm(等价于 docker rmi)删除 docker 的 <none>:<none> images, 这些 images 也被称为 dangling images, 是被覆盖的原来的 image,会占用额外的磁盘空间,详细信息可参考 What are Docker : images?

1     
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash     
# update code
project_dir="/opt/src/DeployMachineLearningModel/"
cd $project_dir && git pull

# build and run with new code
running_container=$(docker ps | grep deploy_ml_model | awk -F ' ' '{print $1}')
if [ -n "$running_container" ]; then
echo "container id not empty, stop it firstly"
docker stop $running_container
else
echo "empty container id"
fi
docker build -t deploy_ml_model .
docker image rm -f $(docker images -f "dangling=true" -q)
docker run -p 8000:5000 deploy_ml_model

同样需要通过 ngrok 映射本地的 http server 到一个 public url 并将 public url 添加到 github 项目的 webhook 中,如下图所示

ngrok script

script github webhook

通过 python hook_server.py运行脚本监听指定的 repository 是否有新的 commit,如果有,则触发运行 build_and_run.sh脚本,其过程如下所示

script trigger run

Kubernets

通过上面的三个步骤,已经基本能够形成一个自动化的部署方案了,个人的自娱自乐基本也够了,但是上面还只是单点的服务,缺乏高可用性和伸缩性。

针对这一点,Docker 会经常与 Kubernets 配合使用,Kubernets 是专门为容器化应用的自动部署、拓展和管理的一个分布式系统。Kubernets 的前身是 Google 内部的系统 Brog,而 google 也参与了 Kubernets 的设计,Kubernets + 容器的部署方式应该会是未来的发展趋势,这里主要根据 Learn Kubernetes Basics总结 Kubernets 的一些经典的使用方式。包括应用的部署,拓展,滚动更新等。

由于实验环境需要多台机器,虽然 Minikube能够在单机上实现 Kubernets sigle-node 集群,但是根据 Install Minikube,virtual box 中的虚拟机似乎不支持 VT-x or AMD-v virtualization,因此,这里直接使用 Learn Kubernetes Basics提供的 shell 环境。

基本架构

Kubernets cluster 是经典主从架构(master-nodes),主(master)负责管理集群,如调度、拓展、更新等,从(nodes)则负责计算或提供服务,每个 node 通过 Kubelet这个 agent 与 master 通信,除此之外,node 中还要有容器运行环境如 Docker 或 rkt。基本架构如下图所示

basic structure

Kubernets 提供的命令行程序 Kubectl(注意与node的 Kubelet 区分)能够获取与集群通信,获取集群信息,部署应用等,如下图是通过 kubectl 获取通过 Minikube 启动的 Kubernets 集群的一些信息

  • kubectl cluster-info:提供 web 界面查看应用的具体信息
  • kubectl nodes:显示所有的 nodes 的信息

basic info

部署(deployment)

部署应用到 Kubernets 集群时,需要构建好要运行的 docker image 的路径,部署使用的也是命令行程序 kubectl,命令是 kubectl run NAME --image=image_url, NAME 是指定的应用的名称,–image 则是指定的 image 的 url,通过 kubectl get deployments可以看到当前部署的应用,如下图所示

deploy with run

在 Kubernets cluser 中启动了应用后,外部网络是无法直接访问这个应用的,这点跟 Docker 有点相似,需要做映射,但是为了调试的便利性,kubectl 提供了 kubectl proxy这个命令,相当于把Cluster内部的地址映射到本地机器,启动之后可通过本机访问 Kubernets cluser 内部 的应用。如下图所示是访问上面启动的应用

kubectl proxy

Pods

上面通过 kubectl 进行部署后,Kubernets 会在 node 中创建了 Pod 来容纳 container,一个 node 中可能有多个 pod,Kubernetes 的 master 会根据 node 的资源情况在不同 node 中分配 pod;pod 是 container 和 其所包含的资源的机器,其定义如下,

A Pod is a Kubernetes abstraction that represents a group of one or more application containers (such as Docker or rkt), and some shared resources for those containers. Those resources include:

  • Shared storage, as Volumes
  • Networking, as a unique cluster IP address
  • Information about how to run each container, such as the container image version or specific ports to use

Pod 相当于应用的“逻辑主机”,而 a group of containers 值得是一个应用中有若干个联系紧密的 container 协作,这些 containers 具有相同的IP。

pod

除了 kubectl run, kubectl 常用的命令一下这些

  • kubectl get:列出当前系统的资源(pods、nodes等),后面跟着
  • kubectl describe:列出资源的详细信息

如下是通过这两条命令获取前面部署的应用的 pod 信息

pod info

下面的命令则是查看 pod 的日志信息在 pod 中的 container 执行命令,通过命令 export POD_NAME=$(kubectl get pods -o go-template --template '{ {range .items} }{ {.metadata.name}}{ {"\n"}}{ {end}}')能够获取当前的 pod name

  • kubectl logs $POD_NAME:打印 pod 中的 container 的日志信息
  • kubectl exec $POD_NAME: 在 pod 中的 container 执行命令

下面首先通过命令获取了 pod 的名称,然后通过 pod 的名称查看其日志并执行命令,执行效果如下所示

log exec

Service

Service 可以说是比 Pod 更高一级的概念,假设部署某个应用时指定其 replicas 的数量是 3,那么就会有 3 个相互独立的 pods,每个 pod 都有自己的 ip,,而 service 就是这些 pods 的集合。Service 管理着这些 pod 的失败重启等,从而向上提供 Pod 的抽象;service 的概念如下图所示

service

关于 service 的定义如下

A Service in Kubernetes is an abstraction which defines a logical set of Pods and a policy by which to access them

除了 pods,service 中还有一项是 policy,指的是让 cluster 内部的 pod 供外界进行访问的方式,service 可设置的访问方式有下面四种

  1. ClusterIP (default) - Exposes the Service on an internal IP in the cluster. This type makes the Service only reachable from within the cluster.
  2. NodePort - Exposes the Service on the same port of each selected Node in the cluster using NAT. Makes a Service accessible from outside the cluster using <NodeIP>:<NodePort>. Superset of ClusterIP.
  3. LoadBalancer - Creates an external load balancer in the current cloud (if supported) and assigns a fixed, external IP to the Service. Superset of NodePort.
  4. ExternalName - Exposes the Service using an arbitrary name (specified by externalName in the spec) by returning a CNAME record with the name. No proxy is used. This type requires v1.7 or higher of kube-dns.

通过 kubectl expose能够让集群内部的 service 供外界访问,如下指定的访问方式是 NodePort, kubernets 默认会启动一个 keubernets 服务,就是第一条 kubectl get services所显示的内容, 而经过 kubectl expose的服务也会出现在其中,内部端口 8080 被映射为了外部的 32066 端口,通过外部ip(命令中的 minikube ip) 和 32066 端口便能访问内部的服务。

expose

Service 通过 Labels 和 Selectors来区分同一个 service 中的不同 pod,label 就是一系列的 key-value 对, label 可结合具体的应用场景进行使用,如区分开发、测试和生产环境的 pod;区分同一个 pod 的不同版本等。

部署时每个 pod 会被自动分配一个 label;通过 kubectl describe deployment查看其对应的 label,也可以在 kubectl get查看 pod 或 services 的信息时通过 -l参数指定具体的 pod 或 service,如下图所示

see label

通过 kubectl label可更改 pod 的 label,如下图所示

change label

可以根据 label 删除 service,此时虽然外部无法访问 pod,但是集群内部的 pod 仍然在运行,如下图所示

delete service

伸缩性(scaling)

伸缩性就是改变运行同一个 image 的 pods 的数量,如下图所示

pod

可以通过 kubectl scale命令指定 replica 的数量,也可以 自动伸缩,如下图所示是将原来只有一个 pod 的 deployment 拓展到 4 个 pod, 从 kubectl get deployments可以看到当前 deployment 可用的 pod 的数量

scale pod

而有了多个 pod, service 就要决定如何分配访问这些 pods 的流量,上面提到的 service 设置的访问方式 LoadBalancer 就是在这里使用(需要注意的是 NodePort 和 LoadBalancer 是可以共存),通过下面访问多次的结果,可以看到每次访问的 pod 都不一样,从而实现了负载均衡

load balance

滚动更新(Rolling updates)

有了多个 pods,在更新 images 时便可以进行 rolling update,其实就是我们常说的滚动更新,不是一次性地 stop 所有 pods 然后同时进行更新,而是先停掉部分的 pods,然后进行更新,并根据这个方法更新所有的 pods。如下图所示

rolling update

这样的好处是在更新时不会让服务停止,如下图所示是更新前 pod 的一些信息,可以看到此时 image 的版本均为 v1

before update

下面通过 kubectl set更新上图所示的 deployment,使用了 v2 版本的 image,在 kubectl set后,可以看到原来的 pod 处于 terminating 的状态,且多了四个新的 pod(可通过 AGE 区分),随着 update 完成,只有新的 pods 在运行,image 版本均变为了 v2,通过 kubectl rollout status可以查看更新的情况。

after update

除此之外, Kubernets中的每次更新都有版本记录,可进行回滚,如下图更新了一个不存在的 image,从 kubectl get pods可以看到新的 pod 的状态是 ErrImagePull,通过 kubectl rollout undo即可进行版本的回滚,最后所有 pods 的状态均恢复正常,image 版本均为 v2,如果再进行一次 kubectl rollout undo,那么 image 版本就变为 v1 了。

rollback

总结

本文主要介绍了部署机器学习模型的一种方式,通过 Flask,Docker,Jenkins 和 Kubernets 共同构建。Flask 负责加载模型并提供 RESTful api,Docker 负责把程序及其依赖的环境打包成镜像,Jenkins 则可以在代码仓库有更新时触发自动构建,生成最新的 image,本文也通过自定义脚本的方式来实现了这一简单功能,但是 Jenkins 是一个功能非常丰富的工具,在项目更大更复杂时,采用 Jenkins 也许会更加方便。

通过 Flask,Docker 和 Jenkins 可以实现基本的自动化部署,但是此时的服务是单点的,不具备容灾性和伸缩性,通过 Kubernets 则可以较好地解决这个问题,只需要提供打包好的镜像,Kubernets 便能够提供伸缩性服务,滚动更新,回滚等操作。

拉姆·查兰:高效能领导者的7条基本行为

$
0
0


题图:全球著名的管理大师拉姆·查兰


“领导者只需要进行战略性的思考,具体的工作交给手下的经理们”,这种想法可能给你带来难以估量的危害。 

拉姆·查兰认为,一个组织要想建立一种执行文化,其领导者必须全身心地投入到公司的日常运营当中。

那么领导者如何带领企业建立起执行文化?如何避免过于陷入企业日常管理的细节当中?


文 / 摘自 《执行:如何完成任务的学问》



高效能领导者的七条基本行为


1. 了解你的企业和你的员工

2. 坚持以事实为基础

3. 确立明确的目标和实现目标的先后顺序

4. 跟进

5. 对执行者进行奖励

6. 提高员工的能力和素质

7. 了解你自己


很多企业的最高领导者都认为自己不应该屈尊去从事那些具体的工作。这样当领导当然很舒服了:你只需要站在一旁,进行一些战略性的思考,用你的远景目标来激励自己的员工,而把那些无聊的具体工作交给手下的经理们。自然,这种领导工作是每个人都向往的。如果有一份工作,既不让你亲自动手,又可以让你享有所有的乐趣与荣耀的话,谁不想干呢?


相反,谁会在一个鸡尾酒会上告诉自己的朋友:“我的目标是成为一名经理”呢?毕竟,在这个时代,经理似乎已经成了一个贬义词。我在这里要提出的是,这种思考问题的方法是错误的,它很可能给你带来难以估量的危害。


对于一个组织来说,要想建立一种执行文化,其领导者必须全身心地投入到该公司的日常运营当中。领导并不是一项只注重高瞻远瞩的工作,也不能只是一味地与投资者和立法者们闲谈——虽然这也是他们工作的一部分。领导者必须切身融入到企业运营当中。


要学会执行,领导者们必须对一个企业、所属员工和生存环境有着全面综合的了解,而且这种了解是不能为任何人所代劳的,因为,毕竟只有领导者才能够带领一个企业真正地建立起一种执行文化。


那么,负责执行的领导者究竟应该做些什么?如何避免成为一名微观管理者,如何避免过于陷入企业日常管理的细节当中?我们在下面列出了领导者的七条基本行为。



1

了解你的企业和你的员工


领导者必须学会全心全力地体验自己的企业。


在那些没有建立执行文化的企业里,领导者们通常都不了解自己的企业每天在干些什么。他们只是通过下属的汇报来获得一些间接性的信息,但这些信息都是经过过滤的——在很大程度上受到信息收集人员的个人因素、领导者自身的日程安排、个人喜好等因素的影响。领导者并没有参与到战略计划的实施当中,所以他们也无法从整体上对自己的企业产生全面综合的了解,而企业的员工们对这些领导者也并不真正了解。


作为一名领导者,你必须亲自参与到实际的企业运营当中去,而绝对不能以一种若即若离的态度来经营自己的企业。


当你亲自参与一个项目的时候,员工们可能认为你有点过于干涉他们的工作,但他们会说:“至少老板对我们的工作表示出了足够的关注。他已经在这里呆了四个小时,提出了一连串我们没有考虑到的问题。”


优秀的员工总是很喜欢这样的老板。这会让他们感到自己受到了重视,从而产生一种尊重感,而且这也是领导者对员工工作表示欣赏的一种方式,同时也是对他们辛苦工作的一种回报。


领导者的个人参与、理解和承诺还是克服员工消极(在很多情况下甚至是积极的)抵触情绪的必要条件。因为启动一个项目之前,领导者对项目的美妙前景大肆渲染,能清楚地定义项目对组织的重要意义,并清楚地知道该项目可能带来的收益时,才会做出这种表现。


此后,他会对整个项目的进展情况进行跟进,确保每个人都采取了积极的态度——当然,前提是他对实施过程中可能出现的问题已经有了清醒的认识。在跟进的过程中,他需要和从事实际工作的人们进行交流,并一次又一次地申明自己对该项目的信心和态度。


2

坚持以事实为基础


实事求是是执行文化的核心。但对于大多数组织来说,里面的员工都是在尽量避免或掩盖现实,为什么呢?因为实事求是的态度有时会使生活变得非常残酷。


没有人喜欢打开潘多拉的盒子,他们总是希望能够掩盖错误,或者拖延时间来寻找新的解决方案,而不愿意承认自己此刻并没有找到任何答案。他们希望能够避免对抗,大家都希望汇报好消息,没有人愿意成为制造麻烦、对抗上级的倒霉蛋。


企业的领导者也是如此。当我们要求领导者们描述自己企业的强处与弱处的时候,对方总是对自己的强处夸夸其谈,而对于自己的弱处,却总是讳莫如深。当我们问对方准备采取什么措施来改进自己弱处的时候,答案总是含糊其辞。他们会说:“我们必须实现目标。”当然,你应该尽量达到自己制定的目标,但问题是你准备采取什么具体的措施。


当AT&T兼并一些自己根本无法经营的光纤企业的时候,所采取的是一种实事求是的态度吗?显然不是。理查德·托曼在没有足够人力的情况下在施乐公司同时发起两个大规模改造的时候,他采取的是一种实事求是的态度吗?也不是。


如何使自己在做出任何决策的时候,始终把实事求是的态度放在首位呢? 首先,你自己必须坚持实事求是;其次,要确保组织中在进行任何谈话的时候,都把实事求是作为基准。


3

确立明确的目标和实现目标的先后顺序


执行型的领导者们通常更为关注一些每个人都能把握清晰的目标,为什么只有“一些”呢?



首先,所有懂得商业逻辑的人都明白这样一个道理: 把精力集中在三到四个目标上面是最有效的资源利用方式。其次,当代组织中的人们也需要一些明确的目标,因为这正是一个组织得以正常运行的关键。


在传统的等级分明的公司里,这并不是一个问题——这些公司的人们一般都知道自己的任务,因为各种命令会通过一条清晰的链条直接传达到每个人身上。而当决策过程被分散的时候,比如说在矩阵型组织当中,各级相关人员就要进行一定的取舍和选择。因为在这种情况下,部门之间将存在着对资源的竞争,同时决策权和工作关系不清晰的问题也在很大程度上增加了人们选择的难度。在这种组织当中,如果没有事先设定清晰的目标顺序,各级部门之间在进行决策时很可能就会陷入无休止的争论之中。


确立清晰的目标之后,你的下一个任务就是简化。那些执行型领导者们的讲话总是非常简单而直接。他们能够简洁地阐述自己正在思考的问题和建议,而且他们知道如何对自己的想法进行简化,从而达到使每个人都能很好地理解、评估和执行,并最终使这些想法成为组织内部的共识。


4

跟进


如果没有得到严肃对待的话,清晰而简洁的目标并没有太大意义。很多公司都是由于没有及时跟进而白白浪费了很多很好的机会,同时这也是执行不力的一个主要原因。


想一下,你每年要参加多少没有结果的会议——人们花了很多时间进行讨论,但在会议结束的时候却根本没有做出任何决策,更没有得出任何确定的结果。每个人都对你的提议表示同意,但由于没人愿意承担执行的任务,你的提议最终还是没有产生任何实际的结果。


出现这种情况的原因有很多:可能公司遇到了其他更重要的事情;也可能大家认为你的提议并不好,甚至可能他们在会议当时就这么认为,只是没有说出来罢了。


5

对执行者进行奖励


如果你希望自己的员工能够完成具体的任务,你就要对他们进行相应的奖励。



这似乎是毫无疑问的,但许多公司却没有意识到这一点。 经过长期观察,我发现那些不具备执行型文化的公司根本没有采取任何措施来衡量、奖励和提拔那些真正有能力的员工。就薪酬增幅而言,那些表现优异的员工和表现不佳的员工之间并没有太大差别。在这些公司当中,领导者们甚至都无法向那些表现优异的员工解释为什么他们的薪酬没有达到自己的预期水平。


一位优秀的领导者应该能够做到奖罚分明,并把这一精神传达到整个公司当中,否则人们就没有动力来为公司做出更大的贡献,而这样的公司是无法真正建立起一种执行型文化的。你必须确保每个人都清楚地理解这一点: 每个人得到的奖励和尊敬都是建立在他们的工作业绩上的。


6

提高员工的能力和素质


作为一名领导者,你的成长过程实际上就是一个不断吸取知识和经验乃至智慧的过程,所以你工作的一个重要组成部分就应当是把这些知识和经验传递给下一代领导者,而且你也正是通过这种方式来不断提高组织当中个人和集体的能力。对他人进行指导是提高其能力的一个重要组成部分,优秀的领导者总是把自己与下属的每一次会面看成是一次指导的好机会。


最有效的指导方式就是: 首先仔细观察一个人的行为,然后向其提供具体而有用的反馈。在进行指导的时候,你首先需要指出对方行为当中的不足,这时你需要给出具体的例子,告诉对方哪些表现是正确的,哪些是需要改进的。


在对公司业务和组织问题进行小组讨论的时候,每个人都面临着一次学习的机会。通过共同分析问题,探求每一种解决方案的利与弊,并最终做出能够让大家都接受的决策,这本身就是一个很好的学习方式。


领导者一定需要掌握提问的艺术,通过提出一些一针见血的问题,你可以迫使人们进行更为深入的思考和探索。这个原则也适用于私下的个人指导,无论你的个人风格是温和还是直爽,你的目标都是要提出一些针对现实的问题,并在适当的时候给予人们一些必要的帮助以解决其所面对的问题。


7

了解你自己


每个人都至少在口头上认为一个组织的领导者必须具有强韧的性格,作为一名执行型领导者尤其如此。


如果没有我们所谓的情感强度的话,你根本就不可能诚实地面对自己,也无法诚实地面对自己的业务和组织现实,或者对人们做出正确的评价。 你将无法容忍与自己相左的观点,而这一点对于一个组织的健康发展其实是非常必要的。


情感强度来自于自我发现和自我超越,这也是各种人力资源管理技巧的基础。优秀的领导者总是能够清楚地了解自己下属的优势与弱项,并能够最大限度地帮助其发挥自己的长处,改正自己的缺点。


一个能够长期成为领导者的人一般都有一套自己的伦理标准,这正是他们拥有足够的力量来完成艰难任务的源泉所在。这样的人绝对不会放弃自己的信念,这种性格已经远远超越了我们通常所说的以诚待人的道德范畴,已经升华成为一种商业领导者所共有的伦理规范。


当今组织中的领导者们或许能够暂时地克服自己情感上的弱点,但这绝对不意味着他们已经解决了情感强度的问题,因为他们终究无法长时间地掩盖自己固有的缺点——而这些人又不得不时刻面对情感方面的挑战,所以问题最终还是无法避免的。无法战胜这些挑战就意味着他们将无法达到自己预期的目标。因为落实任务需要执行者具有一系列行为方面的特点,而如果一个人缺乏情感方面的强度,他将很难形成这些行为习惯。


无论是对自己还是对别人而言,如果大家都不能实事求是地面对组织中存在的问题,你的组织怎么可能会制定出符合实际情况的战略计划呢?如果领导者们没有勇气和自信解决组织中的冲突,或者是提出善意的批评,整个组织怎么可能建立一种实事求是的文化呢?如果一个小组的成员都不能坦率地承认自己对很多问题都没有答案,这个小组就根本无法改正自己的错误,更谈不上进行任何改进了。



要做到量才适用,领导者必须具有一定的情感强度。对表现不佳者姑息纵容几乎是所有公司的通病,而这在大多数情况下都是领导者缺乏情感强度的结果。而且,如果没有一定的情感强度的话,你将很难聘请到真正优秀的人。


通常情况下,一位缺乏情感强度的经理, 为了保护自己脆弱的权威性,会请一些他自认为会比较忠诚的人,而排斥那些敢于提出新创意,对其形成挑战的人。但实际上,这种情感上的脆弱最终将使得这位领导者的前途和整个组织的命运毁于一旦。


海康威视年报出炉:摊开498亿看懂中国安防生意经

$
0
0

人工智能技术大举进军安防行业,长居行业龙头位置的海康绝对是不容忽视的风向标。摊开海康威视的2018年财报全文,从财务基本面表现、业务架构调整信号、AI技术引发产品革新、行业变量与格局等四个方面复盘2018、展望2019年安防行业的发展趋势。

撰文 | 四月

昨日晚间,海康威视发布 2018 年年报全文,公司 2018 年 1-12 月实现营业收入 498.37 亿元,同比增长 18.93%;净利润 113.53 亿元,同比增长 20.64%;每股收益 1.24 元。

电子制造行业已披露年报个股的平均营业收入增长率为 18.66%,年报个股的平均净利润增长率为 6.28%。海康营收增长与电子制造行业个股水平持平,净利润增长明显高于行业平均水平。

对比国内安防排名第二的大华,浙江大华在 2018 年实现营业总收入 236.66 亿元,同比增长 25.58%;净利润 25.32 亿元,同比增长 6.42%。海康的营收增长低于大华,但净利润增长高出大华 14 个百分点;从净利润推算的利润率上看,海康的利润率是大华的一倍。

股东分红方面,海康拟每 10 股派发红利 6.00 元(含税)。

同时,海康威视发布 2019 年一季度业绩报告,公司 2019 年一季度实现营业收入 99.42 亿元,同比增长 6.17%;净利润 15.36 亿元,同比下降 15.41%;每股收益 0.17 元。

根据 2019 年半年度业绩预告,预计 2019-01-01 到 2019-06-30 业绩:净利润 37.33 亿元至 45.62 亿元,增长幅度为-10% 至 10%,上年同期业绩净利润为 41.47 亿元。

截至昨日收盘,海康威视涨 1.87%,报 34.90 元。

海康威视,以视频为核心的智能物联网解决方案和大数据服务提供商。根据 IHS 报告,海康威视连续 7 年蝉联视频监控行业全球第一,拥有全球视频监控市场份额的 22.6%。在 A&S《安全自动化》公布的「全球安防 50 强」榜单中,海康威视连续 3 年蝉联全球第一位。

一、基本面稳定向好,不稳定因素持续

2018 年,海康威视实现销售收入 498.37 亿元,增长 18.93%;实现归属于上市公司股东的净利润 113.53 亿元,增长 20.64%;整体毛利率为 44.85%,与上年同期相比提高 0.85%。各项核心指标均保持稳定上涨。

近六年来看,海康威视的营收一直处于增长中,平均增速在40%左右。增速最快为2014年,达到60.37%,但2014年后,营收增速明显放缓,2018年增速相比2017年缩水近一半。

净利润增速呈现类似趋势走向,但净利润增速下降坡度稍缓于营收增速。增速放缓的部分原因受限于行业整体存量,以及国内外局势影响。

财报中已经明确提出两大风险因素:「国内经济波动风险」和「发达国家贸易保护风险」。在此前 2018 年 Q3 的财报会议上,海康也曾作出回应,表示主要受到三类因素影响:

第一在去杠杆的大形势下,整个实体经济整体下行,投资信心不足,政府与企业的投资行为都有所放缓,其中尤其是政府行业的收入增速受到的影响较为明显,包括公安交通行业。

第二面对资金链紧张的大环境,公司加强应收风险的控制,我们选择了更为谨慎的业务策略,为此我们宁愿放弃一些收入的增速,其中较为突出的是经销渠道的策略调整。

第三,八、九月份中美两国贸易摩擦的大环境,公司在美国市场的业务承受了比较大的压力,公司也相应地调整了市场策略,开拓节奏有所放缓。

显然,上述三类宏观层面的不稳定因素影响范围远不止于海康,更是整个行业层面的。

2018 年中国安防行业整体市场规模增速有所放缓。有人士分析,单纯就安防供应端市场,增长率从 9% 的预期调整到 7%-7.5%,规模约为 5100 亿-5200 亿元。

不过,针对 2019 年下半年,从众多分析看,大环境将会回暖上行。

作为技术密集型企业,海康威视将研发投入作为发展的重要驱动力,研发投入一直保持上升趋势,平均增速保持在40%以上,从2012年的6亿元上升到2018年45亿元,年增长率为600%。

从研发费用占净利润比例来看,从 2012 年至 2018 年六年间,基本保持在 30% 上下,2018 年上占比上升到 39.55%,高于行业平均水平,研发投入的绝对数值在行业内也属于领先地位。

目前,公司研发技术人员高达 16000 人,继续保持业内最大的研发投入规模。随着海康的销售额基数的增长,其研发投入绝对数额大幅提升。

在资产负债表方面,赚钱的速度却跟不上放账和投资的速度依然是toB安防行业的特色,面向政企用户应收账款交付周期长。

此外,虽然近四年里海康高管大笔减持的消息时有传出,扰动人心,但从2018年的前十名股东持股数量可以看出,海康前十大股东的持股比列总额仍然高达77%,股比高度集中,散户可不必多虑。

二、牌面整合:三类策略应对碎片化

安防难啃在于市场碎片化,强势客户集中。

AI 时代,泛在智能,涌现出很多 AI 感知智能需求的机会,但也同时应该为 AI 感知智能应用碎片化需求落地的困难做好准备。胡扬忠曾谈道,「人工智能应用正在以碎片化的方式涌现,所有场景化的技术即意味着碎片化,将导致公司在市场竞争中很难集中发力。」

从 2009 年海康成立,中国安防行业在近年十年的发展里,或者说中国「摄像头行业」已经洋洋洒洒覆盖了公安、交通、司法、金融、文教卫、能源和楼宇七大行业,以及 40 余个子行业的纵向垂直领域。

在 2018 年,海康启动业务架构的变革重组,近 3 万人的组织悄然无声地完成了大挪移,原有七大业务板块调整为三大业务群,分别包括 公共服务事业群 PBG、企事业事业群 EBG、中小企业事业群 SMBG。

针对不同事业群,采取不同业务策略,更有效的协同内部资源,提供不同的产品和系统解决方案。在架构逻辑与命名上,向互联网公司 BAT 看齐。

PBG(Public Business Group,公共服务事业群),以传统公安、交通、司法三个事业部为基础组建业务团队,以城市治理和城市服务为主,适应行政区域的块状模式,顺应城市治理和城市服务的整体运营需求。

EBG(Enterprise Business Group,企事 业事业群),以传统金融、能源、楼宇、文教卫四个事业部为基础,组建业务团队,以传统大型企业市场服务为主,适应集团企业的条状模式,顺应集团企业的垂直化 运营管理需求。

SMBG(Small & Medium Business Group,中小企业事业群),以传统渠道经销管理团队为基础组建业务团队,以中小型企业市场服务为主,努力打造产品分销、安装和运维服务、SaaS 共享为一体的产业生态和平台。

值得注意的是,无论安防的内核与外延如何变化。在安防业务的排序中,仍然以面向公安、交通、司法等政府类的传统安防订单「油水最足」,市场竞争最为激烈,无论是传统巨头还是 CV 独角兽均是同理可循。

可以预见的是,这类城市级市场也将是阿里、华为的未来战场。

综合过往财报数据来看,海康的安防产品在各类行业应用中的比列基本为:

民用市场占 6%,能源市场占 9%,教育市场占 8%,银行、电信、石油、文教卫等大企业市场占比 40%,交通、司法、平安城市等政府市场占比 30%,客户集中为强势群体。

关于海康在 2018 年进行业务架构调整更为本质的原因,在 2018Q3 财报会议上曾谈道:

「以前公司在业绩增长得比较好的时候,粗放一些,现在管理上更精细一些。」

这套逻辑对于其他安防公司同样适用。据机器之心了解,商汤在 2018 年春节后同样进行了业务架构梳理与调整,此前曾铺设多达十余条的业务线在今年收拢为六大事业群。旷视在进行业务核算时,主要依照技术方案来进行划分。

冗余业务线的架构合并趋势,体现了从业者对于安防市场的碎片化和业务逻辑的进一步理解和深化。

三、历经数次变革,AI 步伐更显急速

从高清化、网络化、集成化,在安防产业的历届技术变革中,海康从未缺席,且一直处于引领位置。

但在当下,第三次人工智能浪潮的变革显得更为急促,人工智能大数据云计算边缘计算等多项前沿技术的融合,导致技术扩散速度加快。

这一次,海康不仅要稳,还要快。

海康切入 AI,最早在 2016 年,首先推出基于深度学习算法的全系列深度智能产品家族。

2017 年,海康提出 AI Cloud 边缘节点、边缘域、云中心的三级架构,推进人工智能更广泛的物联网领域应用。而「云、边、端」的三级架构模式也逐步受到行业内诸多安防类 AI 公司的跟进。

2018 年,海康在 AI Cloud 的架构基础之上,进一步整合「两池一库四平台」产品线,提出了 AI Cloud 物信融合的数据架构。

在业务落地上,海康依托于 AI Cloud 开放平台建立合作伙伴生态圈,打开市场边界,不再局限于安防,着重解决人工智能应用场景化、碎片化,用户需求落地困难的问题,对内统一软件架构,对外推行开放融合的策略。

借助于技术的变革,也为海康打开了通向中后端市场的机会。从 2017 年起,海康开始发力中端及数据中心控制类产品。

在 2018 年财报中,中端数据中心控制类产品取得抢眼成绩,达到 44%的增长率,毛利率 53.84%,主要包括传输控制与显示、集中存储、应用软件、数据中心的结构化服务器等。

目前,中心智能解析产品主要面向平安城市、智慧交通等行业市场,海康提出视频智能全分析、计算资源全兼容、引擎和数据全开放的理念,形成丰富、开放的中心智能产品系列和生态体系,取得了良好的市场业绩。

在种类庞杂的安防及泛安防产品矩阵中,海康目前的主要收入仍来自于产品销售。从 2018 年全年收入结构来看,硬件仍是「重头」,是营收及利润的核心,高贡献,高利润。

监控摄像头等前端产品,以及基于 AI、大数据进行存储分析的视频控制系统的中、后端产品的收入占比为 76.61%,工程比例仅为 4.59%。

值得一提的是,「其他」产品规模达到 66 亿,虽然尚未见海康对「其他」做出说明,按海康的年报条目「视频产品及服务」进行总归类,「其他」应该属于「门禁、防盗、停车场、对讲等」非主流但是大安防领域营收。

在创新业务的市场,海康的身份变得丰富起来,有聚焦于 C 端的智能家居业务萤石网络、面向工业制造行业的海康机器人、海康汽车电子等,还有海康智慧存储、海康微影、海康慧影等新业务。

在 26 亿规模、增速 62.96% 的创新产品中,萤石是绝对主力。经过六年发展,萤石云平台已经拥有 4000 万量级的设备接入、3000 万量级用户,对接活跃应用超过 5000 个,初步建立起开放、共享的家庭视频云生态体系。

四、三分天下谁主沉浮?

在过去十余年的发展历程中,安防产业的格局向来封闭而稳固,直到智能化浪潮将安防行业的更多变量因子释放出来。

如今谈到安防,谈到海康,话题总是离不开商汤、旷视等 CV 独角兽的新攻势,以及华为、阿里等重量级选手入场后的威胁。

根据 2018 年的牌面,如何判断接下来的走势?

二级市场的数据指标或许可以管中窥豹。目前,海康总市值为 3262 亿元,用这个数值除以 2018 年全年扣非净利润 113.36 亿元,得到市盈率为 28 倍;除以 2018 年全年营收总额 498.1 亿元,得到市销率为 6.54 倍。

相比去年,市盈率在 35 上下波动,海康市盈率有所回落正常。在安防市场、人工智能 toB 产业化进程中,市销率 6.54、市盈率 28,应该算得上可参考的、比较健康的经济指标。

所谓「健康」,即对比而言。看语音领域的 AI 领投概念股科大讯飞,其股价在 2019 年以来上升超过 40%,目前市值 637 亿元,208 年全年营收 79.17 亿元,净利润 5.42 亿元,市销率约 8 倍,市盈率高达 117 倍。

数值基本可以和媲美还在一级市场徘徊的 AI 独角兽们。

以商汤、旷视、依图等为代表的 AI 视觉公司,从 2017 年以来就多次刷新估值记录。员工超过 2000 人的商汤,其去年中期公布的估值已达 45 亿美元,投资方包括阿里巴巴、新加坡淡马锡、高通等。此后业内传出的新报价高至 80 亿美元,甚至近百亿美元。

假设在 2018 年,排头兵商汤、旷视以 3 亿美元的年销售额计算,市销率,采用估值/销售额能到 20 倍上下。

即便公司已摆脱亏损,市盈率,采用估值/净利润,过百倍毫无悬念。

对比之下,面对 AI 四小龙的「虚势」,海康足够做到兵来将挡,但对于华为的野心却不可以不郑重其事,超 7000 亿的营收规模对于绝大部分公司而言都是庞然大物。

「暂定个小目标,在智慧视频领域,我们会用两到三年的时间做到全球第三」。

去年 5 月,华为 EBG 中国区企业云通信解决方案销售部部长彭晓东接受媒体采访时说道。全球安防监控前三依次为海康威视、博世、大华股份。

既然华为定了目标,三年安防杀到全球第三,在市场不是飞速增长的情况下,华为吃的便将是老大和老二的份额。

五、结语

「2018 年的经营挑战,超过以往的任何一年。公司在销售上比以往任何一年都谨慎保守,更加注重短期风险管理。」

这是海康为 2018 年安防行业写下的注脚。展望 2019「外部环境依然存在一定的不确定性」,而面对诸多的不确定性,唯有四条心法谨记于心。

重研发。无论外部环境如何变化,坚持在研发上投入,保证产品和系统解决方案持续竞争力。

外部,提升客户服务满意度。坚持在客户服务上增加投入,提高客户的满意度。

内部,运营管理效率提升。继续优化内部运营管理,提升运营效率。

坚持国际化道路,提升业务增长驱动力。依然坚持国际化道路,继续加大国际市场上的投入力度。

(注:本文统计图表为原创,未经允许请勿转载)


网宿 :2018中国互联网发展报告

$
0
0

《报告》显示,2018年,全国互联网普及率达57.7%,相比2017年增长4个百分点,其中,八成以上的省份互联网普及率超过50%。与此同时,截至2018年12月,全国互联网独立IP数超过2.6亿,同比增长8%。

全国互联网普及率差距缩小移动端渗透率普遍超80%

《报告》显示,2018年,中国互联网普及率前六名的省市为北京(75%)、上海(74%)、广东(69%)、福建(67%)、天津(65%)、浙江(63%),中东西部互联网普及率差距逐渐缩小。与2017年相比,普及率最高的北京与普及率最低的云南之间差距缩小了5个百分点。从网民数来看,华东地区占总网民数的30.71%,远高于其他地区。

其中,移动端在用户渗透领域已进入成熟期。2018年,全国各地的移动端使用率普遍远远高于PC端,所有省份的移动端普及率都超过了80%,其中18个省份普及率超90%,且仍呈现上升趋势。与此相对的是,PC端渗透率出现小幅下降。

夜间访问增长8% 行业活跃度的地区差异明显

《报告》对网民行为分析和行业发展状况进行了统计和解读。纵观2018年中国网民的访问时间轨迹,可以发现,全国网民的访问高峰出现在20:00-21:00间。具体到行业来看,社交网民白天访问较平稳,于夜间22:00呈现晚高峰;生活服务及游戏类的访问高峰在11:00至13:00及20:00至22:00;金融类的访问则集中在工作日的09:00至16:00,贴合金融行业的工作时间。

值得注意的是,与2017年相比,2018年整体网民夜间0:00至8:00的访问活跃度有明显提升,平均访问量涨幅达8%。可以看出,互联网开始争夺用户“睡眠时间”。同时,昼夜访问量差距也在逐渐缩小。

对此,业内人士表示,昼夜访问差异缩小不仅源于互联网普及率的不断提升,有大量日间空闲时间的中老年用户比例逐渐增多,同时,由于短视频等碎片化渗透类应用的不断普及,导致互联网访问量趋于分散。

从行业活跃度来看,《报告》显示,2018年度,网民活跃度行业排名TOP3分别为社交、视听影音和资讯,社交应用服务继续盘踞最受网民青睐应用榜首。同时,电商类应用经历了2017年的相对低迷,在2018年表现较为抢眼,用户活跃度显著提升了11个百分点。

但是行业活跃度的地区差异依旧明显。《报告》显示,上海、浙江、天津等高线省市的社交活跃度更高,而视听影音活跃度则明显偏低于低线省市。而在游戏领域,西部地区的访问活跃度则明显高于其他地区,并且游戏与电商的网民活跃度有着较高的一致性。

生活服务向细分领域过渡明显社交、视听影音及资讯用户重合度超80%

《报告》显示,在生活服务网民分布中,生活分类信息网的访问量由2017年的41.2%下降到了2018年的22.4%,而与之相对应的是,商旅、教育咨询、医疗医药等专业细分领域的应用访问量均有不同幅度的提升。

对此,有专家表示,源于网民消费水平的提升和消费习惯的变化,对在线教育、商旅等专业细分服务的需求显著增加,迎来了更深入的发展。同时,随着互联网的纵深发展,单纯的信息分类检索及导航已经无法满足用户,甚至于某些需求相对较低的服务被集成到了大的平台,让生活分类信息的访问需求出现明显滑坡。

同时,《报告》传达了一个重要趋势即各个行业的用户重合度在不断提高,尤其在社交、视听影音和资讯三大领域,彼此间用户重合率均超过80%。电商与资讯、视听影音、社交及游戏的用户重合率也都超过了60%,生活服务与其他行业也均有50%左右的重合率。

PDF版本将分享到199IT交流群,支持我们发展可加入!

更多阅读:

猎聘网:2019年Q1中高端人才报告 平均年薪为26.38万元

$
0
0

猎聘网近日发布2019年第一季度中高端人才报告。报告显示,互联网行业每个月的中高端人才紧缺程度都明显高于全行业水平,这表明互联网行业依然是最有活力的行业之一。报告还显示,在5G这个新兴领域中,2019年第一季度的职位需求同比增长32.12%,而平均年薪为26.38万元。

互联网春天仍在 平均年薪23.42万元

猎聘大数据显示,从2018年1月到2019年3月,国内中高端人才紧缺程度总体放缓,全行业人才紧缺指数TSI(TSI 即 Talent Shortage Index 的缩写。TSI>1,表示人才供不应求; TSI<1,表示人才供大于求。如果 TSI 呈上升趋势,表示人才越来越抢手,找工作相对容易) 总体呈下降趋势,从2018年1月的最高点1.25降到2019年3月的最低点0.74,人才从供不应求到供大于求。2018年10月是一个转折点,当月开始TSI跌破1。

这与全国整体的经济形势密切相关。2018年下半年,国内经济面临较大的下行压力,用人单位招人整体趋于保守,招聘需求有所放缓,而求职者对换工作也较为谨慎,整体人才紧缺程度随之降低;同时一季度的1、2月处于招聘淡季,又受春节假期因素影响,因而受到了一定程度的冲击。

对比互联网行业与全行业过去15个月的TSI走势,互联网行业每个月的中高端人才紧缺程度都明显高于全行业水平,这表明互联网行业依然是最有活力的行业之一。

由于互联网在前几年的发展过程中存在一些求快、过猛的现象,在经济形势的考验下,在人才需求上逐渐回归理性,为了更好的发展,一些互联网公司积极地进行组织架构和人才结构的调整,以完成组织升级和人才升级,更好地适应当下的经济形势。

根据猎聘统计,国内2019年一季度有融资和上市行为的公司多达1200多家,其中互联网公司近500家,后者人才需求同比2018年一季度增长57.43%;在不同司龄的互联网公司中,猎聘发现新兴互联网公司招聘需求同比2018年一季度增长32.83%。具有10年以上历史的互联网公司的招聘需求同比增长39.30%。

从全国中高端人才平均年薪来看,其中,金融行业的平均年薪依旧遥遥领先其他行业,为24.95万元;其次是互联网行业,平均年薪为23.42万元。

一线城市吸引力强劲 北京平均年薪27.44万元

从2019年一季度中高端人才的城市分布来看,一线城市集中度较高,为43%。由于一线城市资源更丰富,行业发展更成熟,为各类人才提供了更多发展机会,工资待遇较为优厚,因此吸引力非常强劲。

从排名来看,一线城市依然稳居前四,杭州的中高端人才占比仅次于一线城市。由于杭州发展速度较快,提供了大量的就业机会,此外杭州地理环境优越、气候温宜,因此吸引大量中高端人才加入。另外,近些年各城市陆续出台各类引才新政,且二线城市引才力度相对较大,因此对中高端人才具有极强的吸引力。

在薪酬方面,北京平均年薪27.44万元,排名第一;其次是上海、深圳和广州,其平均年薪集中在23~26万元之间;值得注意的是,二线城市与新一线城市的薪酬仍存在明显的差距,普遍在20万元以下。虽然二线城市就业政策相对较好,但是生活成本相对较低,在一定程度上也影响了当地的薪资水平。

电竞平均年薪超30万 5G职位需求同比增长32.12%

猎聘还通过大数据分析了18个新兴领域,涵盖5G、AI、AR、VR、区块链、电竞、大数据、新能源汽车、平台经济、共享经济、跨境电商、互联网+教育、工业互联网、新一代信息技术、高端装备、生物医药、新材料、物联网,专门分析了其中职位增长和薪资位居前十的领域,一探其人才需求和收入的详细情况。

在职位增长方面,在2019年一季度,在这些新兴领域职位同比增长最快的十大领域中,增长幅度高度不同,但均为正向增长,增长区间为14.33%-91.42%。

其中,互联网+教育职位需求同比增长排名第一,为91.42%;电竞位居第二,同比增长为89.50%;AI排名第三,职位同比增长为44.30%。今年因为国产5G手机扎堆发布被备受关注的5G领域,比2018年一季度同比增长32.12%。

在这些领域中,5G也是一大热点。2019年被称为“5G发展元年”,随着国内手机大厂在今年2月的2019世界移动通信大会上扎堆发布了各家的5G手机后,5G成为了全民关注的高科技热点,必将拉动该领域对中高端人才的需求。

在薪资排名方面,薪资排名前十的新兴领域中整体水平较高,平均年薪均超23万元,其中平均年薪最高的是电竞,为31.43万元;平均年薪位居第二和第三的新兴领域为区块链和AI,分别为27.10万元、26.38万元;5G领域位居第四,平均年薪26.38万元。

自 新浪科技

更多阅读:

转载:一文读懂深圳最新统计公报:深圳已成负债之城,杠杆率远超上海,人均负

$
0
0

一文读懂深圳最新统计公报:深圳已成负债之城,杠杆率远超上海,人均负债15万!

城管队长 买房之前 今天

来源:城管队长

4月20日,著名经济学家张五常发表了一篇刷屏文章,放言:深圳将成整个世界的经济中心;深圳将超过上海;十年后深圳一定会超过硅谷;深圳是个现象……

此前一天,深圳市统计局发布《深圳市2018年国民经济和社会发展统计公报》。过了一个多季度才发布数据,这“深圳速度”比广州、北京、上海慢了一个月。虽然来的晚,但这些枯燥数据与张五常的激越的观点互为比较,相信能看到一个更真实的深圳。

1

对《深圳市2018年国民经济和社会发展统计公报》,城管队长解读如下:

1、深圳GDP总量与上海相比,还差一个东莞。2018年深圳GDP总量24221.98亿元,增幅7.6%。总量超过了香港、广州,比上海少8460亿,相当于少了个东莞(8278亿元)。但这一辉煌成绩,却是5年来增幅最低的。2016年深圳GDP增幅最高,达9.1%。2019可能继续探底。

深圳2014-2018年生产总值及增速

2、南山区没你想得那么厉害。去年,无论是高科技发展、城市面貌,南山被点赞最多。可是数据表明,南山区GDP虽然突破5000亿位居深圳之首,但增幅仅4.5%。增幅最高的龙岗、龙华、坪山增幅均超过10%,福田区也达到7.4%。看来南山的成绩主要表现在房价上。

3、深圳人口:没户口的依然占大头,人口增加49.83万人,全国各城市增量第一。深圳常住人口1302.66万人,其中户籍人口454.70万人,增长4.6%,占常住人口比重34.9%(原因是落户条件低到大专生都可以);非户籍人口847.97万人,增长3.6%,占比重65.1%。宝安区人最多,325万人。福田区户籍人口最多,是唯一超过100万的区。同时,去年福田区无户籍人口增幅各区最高,达13%。

大家都说深圳实际人口已经超过2000万人,这多出来的七八百万人,统计局既不反对又不解释,让人着急。

4、深圳养了5.91万头猪。这让人意外,土地如此稀缺的深圳,还能有地方养5.9万头猪!但比上一年减少了15.7%。

2018年主要畜产品产量

5、深圳存款余额7.255万亿(比广州多近2万亿)!其中住户存款1.381万亿。按照数据,深圳金融机构本外币存款余额比上一年增4.1%;金融机构本外币贷款余额52539.79亿元,增长13.4%,贷款增速高于存款增速,说明经济刺激显著,但估计不少是房贷。

6、深圳人太能借钱了!住户贷款近2万亿,人均负债15万!深圳住户贷款达到住户存款(13810.06亿元)的144.4%。按照1302万人口计算,人均负债15万元,大头是房贷。如果考虑到存款因素,深圳人均净负债4.4万元。与上海相比,这一数据让人冒汗,上海与深圳相反,住户存款多于贷款,借钱多的原因,预计一是房贷、二是创业(详见文后分析)。

2018年末金融机构(含外资)本外币存贷款

7、深圳政府收入比广州竟然多一倍以上,但花钱谨慎了。深圳全年完成一般公共预算收入3538.41亿元,比上年增长6.2%。广州一般公共预算收入只有1632亿元,深圳比广州富一倍!其中,深圳的税收收入2899.60亿元,增长9.2%。一般公共预算支出4282.54亿元,下降6.8%。

8、深圳工业强大,国有企业工业增加值下降!增加值9254.00亿元,比上年增长9.0%,这一数据高于北上广。其中,国有企业降21.4%;股份制企业增长12.8%;外商及港澳台商投资企业增长3.8%。深圳最大的工业行业是计算机、通信和其他电子设备制造业,增加值比上年增长14.0%。国有企业降,民营和外资企业增,说明深圳特色继续保持和发展。

9、深圳工厂生意难做利润下降,但劳动生产率大增!实体经济确实不好做,利润总额下降,但劳动生产率大增,说明生意不好,但工人们干劲足,一定是996工作制!数据表明:深圳全年规模以上工业企业主营业务收入33174.49亿元,比上年增长9.5%;实现利润总额2022.14亿元,下降4.0%;工业全员劳动生产率31.11万元/人,增长19.1%。

从各区看,龙岗、龙华两区工业增加值增幅均达到18%,为深圳两大工业龙头。另一工业强区宝安仅增7.5%。南山表现最差,降幅3.2%;福田增幅10.5%。是因为南山工改工房地产搞得太多了,耽误了正业?

10、深圳制造了3亿台手机,2万个机器人,增幅最多的是新能源车!这主要靠比亚迪吧。手机产量最大,但减少的也最多(降幅15.3%),也难怪,华为手机跑了,金立倒了。注意,移动通信基站、机器人、服务器这些高科技产品增幅较多。

2018年深圳主要工业品产量

11、深圳人更舍得为吃花钱了。固定资产投资方面,住宿和餐饮业增幅高达312%,居各行业之首。投资下降最厉害的是“居民服务、修理和其他服务业”,估计居民都用网络连接服务了,不需要再投资服务、修理这些店面了。下降第二多的是批发、零售方面的投资,同样是互联网电商冲击。文化、体育和娱乐业投资增幅第二。

数据还表明,深圳人更舍得为吃花钱!深圳全年社会消费品零售总额6168.87亿元,比上年增长7.6%。其中,商品零售额5424.38亿元,增长7.4%;餐饮收入额744.49亿元,增长8.4%。为“吃”和“玩”投资最多的城市,是不是很可爱?!

2018年深圳固定资产投资主要行业情况

从物价涨幅看,医疗保健涨4.3%,居住涨3.4%。物价上涨最低的是衣服,仅0.4%。看来,在深圳看病不划算,买衣服最划算。

按区来看,购物首选仍然是福田,比南山多了一倍多。就商品而言,购买家电、珠宝的下降了,买车的增幅最大,达到25.9%!去年全国汽车销量大幅下降,而深圳反而大增。买酒、买书、买文具的增加较多,说明深圳进入中产阶段。

12、深圳人消费力被房贷压制!通过5年来深圳消费品零售总额增幅情况看,2015年房价涨幅较大的时候,零售总额增幅明显下降,说明销售受房贷挤压严重。深圳GDP与广州相当,但零售总额6168亿,与广州9256多亿零售总额相比,差距明显,一方面在于广州批发业强大,另一方面也说明深圳人购物力量薄弱。

2014-2018年社会消费品零售总额及增速

13、深圳房地产投资增幅大,但住宅竣工面积下降三成!全年建筑业增加值724.46亿元,比上年增长13.9%。这是5年来增幅最高的。同时,在固定资产投资上,房地产开发投资增长23.6%(高于全市固定资产投资增幅)。这两个数据说明,深圳经济还是依赖于建筑和房地产的。从直观感受上也可印证,高楼大厦越来越多、越来越密。

房地产投资增长最多的是光明区和宝安区,今后绝对是房地产主战场。非房地产投资增长福田区高达达47%,这个区有前途!

2018年深圳商品房中住宅施工面积增幅15.2%,但竣工面积下降32%!销售面积增加7.6%。这说明,楼市调控政策太严厉,很多房子放缓工期。未来住房供应量减少将对房价产生影响。

2018年房地产开发和销售指标完成情况

14、进口大增,出口下降!深圳进口大幅增加19.4%至1.37万亿,出口下降1.6%,至1.63万亿。可能是中美贸易谈判后的常态。出口中,国有企业下降最多。另外,出口到美国的东西减少了,到台湾的大幅增加。从东盟、台湾、韩国进口的东西最多。

15、航空运输领跑,港口吞吐量增幅下降。货物运输中,航空运输大增至108万吨,比上年增加近10%;水路和铁路运输下降,铁路运输量仅有69万吨(下降1.5%),看来高铁都去拉人了。


在住户贷款项目中,上海公布了住房贷款1.33万亿,也就是说房贷占贷款的60%。深圳没有公布住房贷款数据。但可以推测,深圳住户贷款额奇高无比,一是买房贷款多,二是小企业经营个人贷款多。个人贷款渠道有限,因此很多人抵押房产贷款。

这说明:深圳杠杆率高,深圳人比上海人打拼更艰苦;深圳恩格尔系数29.2%,跟全国平均水平差不多,也说明了这一点。张五常把深圳吹到天上,但脚踩大地的深圳人的生活其实是满拮据的。不过,深圳人敢于借钱,说明对未来更有盼头。这也与深圳人年轻,能够贷更多款有关。

统计局数据里的深圳,跟你感受到的深圳是一个吗?

 

Spring Cloud Alibaba基础教程:Sentinel使用Apollo存储规则

$
0
0

上一篇我们介绍了如何通过Nacos的配置功能来存储限流规则。Apollo是国内用户非常多的配置中心,所以,今天我们继续说说Spring Cloud Alibaba Sentinel中如何将流控规则存储在Apollo中。

使用Apollo存储限流规则

Sentinel自身就支持了多种不同的数据源来持久化规则配置,目前包括以下几种方式:

本文我们就来一起动手尝试一下,如何使用Apollo来存储限流规则。

准备工作

下面我们将同时使用到 ApolloSentinel Dashboard,所以可以先把 ApolloSentinel Dashboard启动起来。

如果还没入门 Sentinel Dashboard可以通过文末的系列目录先学习之前的内容。Apollo的话相对复杂一些,这里不做详细介绍了,如果还没有接触过Apollo的读者可以查看其 官方文档进一步学习。

应用配置

第一步:在Spring Cloud应用的 pom.xml中引入Spring Cloud Alibaba的Sentinel模块和Apollo存储扩展:

<dependencies>     
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-apollo</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>

第二步:在Spring Cloud应用中配置的服务信息,在 resource目录下,创建 apollo-env.properties文件,内容样例:

local.meta=http://192.168.0.201:8080     
dev.meta=http://192.168.0.202:8080

这里需要了解Apollo对多环境的配置,这里设置的是每个环境不同的配置服务地址,读者需要根据自己的实际情况修改。

第三步:在Spring Cloud应用中添加配置信息:

spring.application.name=sentinel-datasource-apollo     
server.port=8002

# apollo config
app.id=${spring.application.name}

# sentinel dashboard
spring.cloud.sentinel.transport.dashboard=localhost:8080

# sentinel datasource apollo
spring.cloud.sentinel.datasource.ds.apollo.namespaceName=application
spring.cloud.sentinel.datasource.ds.apollo.flowRulesKey=sentinel.flowRules
  • app.id:Apollo中的创建的项目名称,这里采用 spring.application.name参数的引用,从而达到服务名与配置项目名一致的效果
  • spring.cloud.sentinel.transport.dashboard:sentinel dashboard的访问地址,根据上面准备工作中启动的实例配置
  • spring.cloud.sentinel.datasource.ds.apollo.namespaceName:Apollo的空间名
  • spring.cloud.sentinel.datasource.ds.apollo.flowRulesKey:配置规则的key名称

关于Apollo相关配置的对应关系可见下图所示:

upload successful

第四步:创建应用主类,并提供一个rest接口,比如:

@EnableApolloConfig     
@SpringBootApplication
public class TestApplication {

public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}

@Slf4j
@RestController
static class TestController {

@GetMapping("/hello")
public String hello() {
return "didispace.com";
}

}

}

其中 @EnableApolloConfig注解是开启Apollo的配置加载功能。

第五步:Apollo中配置限流规则,具体可见第三步的截图中的样子。其中,key值的内容是下面的json

[     
{
"resource": "/hello",
"limitApp": "default",
"grade": 1,
"count": 5,
"strategy": 0,
"controlBehavior": 0,
"clusterMode": false
}
]

可以看到上面配置规则是一个数组类型,数组中的每个对象是针对每一个保护资源的配置对象,每个对象中的属性解释如下:

  • resource:资源名,即限流规则的作用对象
  • limitApp:流控针对的调用来源,若为 default 则不区分调用来源
  • grade:限流阈值类型(QPS 或并发线程数); 0代表根据并发数量来限流, 1代表根据QPS来进行流量控制
  • count:限流阈值
  • strategy:调用关系限流策略
  • controlBehavior:流量控制效果(直接拒绝、Warm Up、匀速排队)
  • clusterMode:是否为集群模式

这里我们只做简单的配置解释,以便于理解这里的配置作用。实际上这里还有非常多可配置选项和规则,更复杂的配置后面我们单独开一篇来深入学习。

第六步:启动应用。如果一些顺利,可以看到类似下面的日志,代表已经成功从Nacos加载了一条限流规则:

2019-04-18 23:56:11.278  INFO 29149 --- [           main] o.s.c.a.s.c.SentinelDataSourceHandler    : [Sentinel Starter] DataSource ds-sentinel-apollo-datasource start to loadConfig     
2019-04-18 23:56:11.279 INFO 29149 --- [ main] o.s.c.a.s.c.SentinelDataSourceHandler : [Sentinel Starter] DataSource ds-sentinel-apollo-datasource load 1 FlowRule

通过postman或者curl访问几下 localhost:8002/hello接口:

$ curl localhost:8002/hello     
didispace.com

此时,在Sentinel Dashboard中就可以看到当前我们启动的 sentinel-datasource-apollo服务。点击左侧菜单中的流控规则,可以看到已经存在一条记录了,这条记录就是上面我们在Apollo中配置的限流规则。

深入思考

在使用Apollo存储规则配置的时候与Nacos存储一样,对于Sentinel控制台这些数据是只读的,也就是说:

  • Sentinel控制台中修改规则:仅存在于服务的内存中,不会修改Apollo中的配置值,重启后恢复原来的值。
  • Nacos控制台中修改规则:服务的内存中规则会更新,Apollo中持久化规则也会更新,重启后依然保持。

代码示例

本文介绍内容的客户端代码,示例读者可以通过查看下面仓库中的 alibaba-sentinel-datasource-apollo项目:

如果您对这些感兴趣,欢迎star、follow、收藏、转发给予支持!

参考资料

下面是Sentinel的仓库地址与官方文档,读者也可以自己查阅文档学习:

系列回顾

专题推荐

Nimbus: Hulu的深度学习平台

$
0
0

背景

Hulu是美国领先的互联网专业视频服务平台,目前在美国拥有超过2500万付费用户。Hulu的目标是帮助用户在任意时刻、任何地点、以任何方式查找并欣赏到高质量的电视剧、电影和电视直播。实现这一目标离不开各个团队的努力,而AI在其中扮演者越来越重要的角色。在Hulu, 我们拥有诸多的researcher团队,如广告团队,推荐团队,视频理解团队等ji等。早期的时候,大家还是各自为战,以“小作坊”的形式构建机器学习相关环境。这种非集中式的生产模式存在着许多弊端。概括来说就是无法共享资源(计算资源,数据资源,尤其是昂贵的GPU资源),无法共享经验(模型或者框架优化)以及存在很高的额外的环境搭建和运维成本(严重影响了researcher的工作效率)。基于此,我们构建了AI Platform这个跨Team的组织。

整个AI Platform可以分为三层,从上到下依次是AI服务层,ML数据层,基础架构层。AI服务层主要是用于线上模型管理和部署,涉及到CICD, 监控,负载均衡等服务相关内容。ML数据层则包含了机器学习所用到的数据源,包含经过多个ETL pipeline清洗后生成的用于存放特征的数据仓库。最底层则是基础架构层,包括分布式存储,计算和调度等等,这也是我们基础架构团队主要负责的一块。

一个机器学习作业的生命周期大致可以分为数据准备阶段,模型训练阶段和模型服务阶段。在Hulu, 其对应的基础设施如下图所示。

从图中可以看出,Hulu已经拥有大部分ML所需的基础设施,包括线上服务部分以及离线计算所能用到的Hadoop相关的基础设施等。这已经能满足一定程度的机器学习需求,但是Spark / Flink MLlib主要面向传统的机器学习算法,我们缺少了一套专门的机器学习平台,从而可以支持对环境要求更加复杂的机器学习框架尤其是深度学习框架。于是,我们研发了Nimbus。

技术选型

Docker

Docker是我们技术选型中最先确定的方向。机器学习平台一个很重要的需求就是对TensorFlow, Caffe, Pytorch,XGBoost等多种机器学习框架的支持,每种机器学习框架还有多种不同的版本,即使是统一版本也有不同的环境依赖,比如CUDA版本,Python版本等等。而Docker作为一个当下盛行的开源容器引擎,可以为任何模型训练创建一个轻量级的、可移植的、可隔离的容器环境,从而可以轻松应对这些需求。

Mesos

选定Docker作为底层引擎之后,下一个需要抉择的便是资源管理和编排框架。当时主要考虑的Yarn,Mesos以及Kubernetes。 在选型中,一个很重要的考量是对gpu的支持上。Yarn基本上从yarn 3.1真正开始支持将gpu作为底层可分配资源,而hulu大规模使用的都是基于cdh5.7.3的2.6版本,虽然可以通过打一些补丁进行支持,但是涉及的集群规模很大、服务众多,存在较大的风险。于此同时,yarn与docker的结合也并不是很完美。剩下的Mesos和Kubernetes都可以满足我们的需求,但是基于当时的软件成熟度、运维复杂度以及经验积累等方面的考量,我们最终选择了Mesos。

Framework

Framework是Mesos上存在的一种概念。Mesos实现了两级调度架构。第一级调度位于Mesos Master的守护进程,负责管理Mesos集群中所有节点上运行的Slave守护进程。Mesos slave将它的可用资源汇报给master,master再将资源分配给对应的Framework,由Framework选择接受整个、部分或者拒绝这个资源。所有接受的资源之后将由Framework负责调度。Mesos上开源的Framework并不是特别的多,起初我们选择Marathon,  并基于此完成了第一个版本,可以实现分布式TensorFlow, XGBoost的训练。很快,我们发现了其存在的一些局限性。其中最主要的原因在于Marathon更适合于长服务类型的作业,在短作业的生命周期管理上不够灵活。另外一点在于采用Marathon-LB作为服务发现引擎时,在分布式训练中,所有流量都需要经过Marathon-LB,从而带来严重的网络性能问题。之后,我们便采用了Hulu自研的针对短作业的高吞吐的调度引擎CapOS作为Mesos之上的调度框架。

架构设计

整体架构主要分为三块,Nimbus管理层,计算层和存储层。

存储层主要包含了三块。(1)用于存储模型代码的Github以及基于Http的文件服务器。(2)Hulu内部用于存放镜像的镜像仓库Cubox。(3)用于存放海量的训练数据的多种分布式存储,如HDFS, S3, Ceph以及Hulu内部专门用作小文件存储的Framehouse等。

计算层主要采用了Mesos+Docker的解决方案,上层采用Capos作为调度平台,最终运行在IaaS层提供的物理机或者虚拟机之上。

Nimbus管理层上,通过封装和抽象,Nimbus对外提供了包括客户端、网页以及Restful API的访问接口,在这可以对机器学习任务进行一站式管理。Nimbus Server中包含了一些列AI作业管理的逻辑。

对于一个AI作业,Nimbus会根据框架类型和运行模式执行不同的处理逻辑。就运行模式而言,无非是分为单机模式和分布式模式。单机模式比较简单,一般直接对应一个容器。分布式模式则会相对复杂。目前主流的分布式训练主要包含一下几种方式。

其中模型并行和流水线并行需要依赖于特定模型结构支持,因此并不具有通用型。作为平台方,我们主要考虑支持的是数据并行。数据并行一个主流的方案的是采用Parameter Server架构,这也是TensorFlow默认的方案。


我们利用CapOS提供的Programing API接口,实现了针对TensorFlow PS架构的Application Master,包含资源申请, 拓扑管理,组件间服务发现等环节。相较于之前同于LB的方式进行服务发现,这里采用了端到端直连的方式进行通信,可以尽量分摊网络开销,优化整体网络性能。


相对PS模式之外另一种数据并行方案采用的Allreduce模式,根据实现方式不同又可以细分为Ring Allreduce、Tree Allreduce等等。XGBoost的分布式实现就是基于Allreduce模式。同样的,我们也需要实现其对应的Application Master逻辑。

优化和改进

作为平台提供方,我们也一直致力于在功能性、易用性、性能等方面进行改进。下面将罗列一些比较重要的点。

框架支持

随着AI的火热发展,各种机器学习框架层出不穷。由于人力有限,我们也不可能面面俱到,对所有框架进行集成。根据目前Hulu的使用情况,我们已经完成了对TensorFlow, Pytorch, Caffe2,XGBoost, Gensim, LightGBM的支持。在框架集成上,除了完成一系列和我们底层存储对接外,很重要的一步在于镜像构建。在这里我们也做很多工作,包括

(1)一些源码的改造,使XGBoost分布式模式可以运行在容器之中,Caffe2的编译脚本的改造使得可以自动build出各种CUDA、OpenCV组合下的镜像。

(2)一系列的构建脚本,可以快速的完成对已支持框架的新版本的测试和集成。

(3)利用一些镜像优化手段如多阶段构建、基础层共享以及基础镜像提前分发等手段减少镜像下载时间,从而降低启动延迟。

(4)此外,Nimbus也支持自定义镜像,方便用户使用一些独特的计算环境或者框架。我们提供了一些模板镜像,方便用户进行镜像制作。

调试工具

调试是模型开发阶段必不可少的环境。一般而言,本地运行都会比远端执行更容易调试。为了较少这部分影响,我们提供了一些列工具。除了常规的作业日志和监控系统外,我们也集成了Terminal,可以远程登陆到机器内部进行调试。集成了Jupyter notebook, 并且提供debug模式,内置了nimbus-run和nimbus-tensorboard等命令,可以很方便的在容器内进行边修改,边调试运行,边看结果,尽可能实现和本地调试一样的体验。由于debug模式同实际运行使用了同样的资源,为了避免资源浪费,我们会有时间限制,到期后除非续约,否则将自动回收资源。/在这种模式下,Jupyter主要用作debug场景,我们也在计划构建真正意义的Jupyter as a Service,可以取代reacher的工作站,完成云端编码、测试、训练等一条龙服务。

调度策略优化

CapOS默认的调度策略针对高吞吐做了大量优化,缺乏针对机器学习任务特别是分布式机器学习任务的优化。得益于其提供的灵活的Programming API,在默认策略之上我们封装了一层的针对AI作业的调度策略。

(1)数据中心自动选择。Hulu目前同时使用了多套数据中心,包括自己本地构建的两个数据中心以及云上的多个数据中心。Nimbus提供了对多个数据中心进行调度的能力。用户可以自己选择数据中心也可以由系统进行设置。数据中心一旦配置错误,将带来大量的跨数据中心的访问,极大的影响模型训练的速度。为此,我们加入了对数据源的位置感知能力,系统根据AI作业的输入和输出信息,以及各个数据中心的资源使用情况,可以自动选择最为合适的数据中心。

(2)GPU 优先的调度策略。GPU对于机器学习尤其是深度学习来说是一种极为重要的资源。在当前Nimbus集群中,同时存在了GPU作业和一般的CPU作业。在之前调度逻辑中,CPU作业可能会占据GPU机器上的CPU和内存资源,导致GPU任务因为CPU或者内存不足而没法调度出去,从而可能引发GPU资源闲置。在之后,我们对GPU机器做了额外的保护,尽量避免CPU作业抢占GPU的资源,只有当GPU机器出现闲置并且CPU机器不足以满足的情况下才会进行调度。

(3)分布式任务拓扑感知。分布式训练主要瓶颈在于多机之间的通信开销。因此我们需要分布式训练的各个节点尽可能位于同一机房,同一机架甚至同一机器上。在PS架构下,PS 节点作为中心节点,网络流量往往非常大,很容易把带宽跑满,在这种场景下需要尽可能把PS节点打散到不同的宿主机上,从而分摊网络流量。我们当前的版本还是基于一个比较粗的力度,这一点不如K8S,其可以利用Pod Affinity很容易实现更细粒度的优化。

统一的IO层

虽然用户的模型代码几乎可以不用修改就可以直接运行在Nimbus之上,然而在大规模机器学习训练过程中,势必需要引入分布式存储。从本地存储转到分布式存储,这将带来很大的使用习惯的改变。尽管主流分布式存储也都支持POSIX标准,然而这会降低IO性能,影响训练效率。为了减少这层gap,我们引入了一个统一的IO层,提供常用的文件Open,List, Delete接口,对外屏蔽底层文件系统的差异。所有的IO请求都将根据schema不同自动路由到不同文件系统之中。

开源社区合作

Nimbus相关生态系统中有大量的来源于开源社区的组件。作为平台方,我们也一直紧密关注着开源社区尤其是机器学习框架的动态。汲取社区力量更好的服务Hulu内部用户,也把Hulu的需求和优化回馈给社区。我们向XGBoost社区反馈了分布式模式下的文件处理的bug并解决后贡献给开源社区(dmlc-core/pull/452)。后续我们也会和社区保持紧密的联系,共同推动社区的良性发展。

作者简介:苏经纬,Hulu AI基础架构研发工程师,专注于AI、容器、容器编排等技术。


原创文章,转载请注明:转载自 董的博客

本文链接地址:Nimbus: Hulu的深度学习平台

微信公众号:hadoop-123,专注于大数据技术分享,欢迎加入!

GitHub - smartnews/jpa-entity-generator: Lombok-wired JPA entity source code generator, Gradle and Maven supported.

$
0
0

jpa-entity-generator

Build StatusMaven Central

This is a Java library which generates Lombok-wired JPA entity source code. The project provides Gradle plugin and Maven plugin.

Getting Started

build.gradle

applyplugin:'java'buildscript {
  dependencies {
    classpath'com.h2database:h2:1.4.197'classpath'com.smartnews:jpa-entity-generator:0.99.6'}
}

configurations { providedCompile }
sourceSets.main.compileClasspath+=configurations.providedCompile
sourceSets.test.compileClasspath+=configurations.providedCompile
sourceSets.test.runtimeClasspath+=configurations.providedCompile

repositories {
  mavenCentral()
}
dependencies {
  providedCompile'org.projectlombok:lombok::1.18.2'providedCompile'org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final'}

applyplugin:'entitygen'entityGen {
    configPath='src/main/resources/entityGenConfig.yml'}
For Maven users

Maven plugin to run the code generator is also available.

<plugin><groupId>com.smartnews</groupId><artifactId>maven-jpa-entity-generator-plugin</artifactId><version>0.99.6</version><dependencies><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.46</version></dependency></dependencies></plugin>

Put src/main/resources/entityGenConfig.yml, and then run the following command:

mvn jpa-entity-generator:generateAll

src/main/resources/entityGenConfig.yml

jdbcSettings:url:"jdbc:h2:file:./db/blog;MODE=MySQL"username:"user"password:"pass"driverClassName:"org.h2.Driver"packageName:"com.example.entity"

If you need more examples, check the sample entityGenConfig.ymlin this repository.

entityGen task

./gradlew entityGen compileJava

entityGentask generates entity classes for all the existing tables in the database.

packagecom.example.entity;importjava.sql.*;importjavax.persistence.*;importlombok.Data;@Data@Entity(name="com.example.entity.Blog")@Table(name="blog")publicclassBlog{@Id@GeneratedValue(strategy=GenerationType.IDENTITY)@Column(name="\"id\"")privateIntegerid;@Column(name="\"name\"")privateStringname;@Column(name="\"active\"")privateByteactive;@Column(name="\"created_at\"")privateTimestampcreatedAt;
}

How to test on your local machine

To run the unit tests, simply run the following script as the TravisCI build does.

./test.sh

If you need to make sure if your latest code works with sample project or your existing projects, run the following command to publish the latest build to the local Maven repository.

./gradlew uploadArchives -Plocal

How to release new version

./gradlew clean uploadArchives
mvn deploy -Dmaven.test.skip=true

FFM:功能强大的开源渗透测试工具,帮你开启自由攻击模式的“新大陆“

$
0
0

bbbbbbbbbb.jpg

Freedom Fighting Mode (FFM)

FFM是一款采用Python开发的开源渗透测试工具,广大研究人员可以将FFM用于红队任务的后渗透测试阶段。

研究人员在 SSTIC 2018大会上正式公布了这款工具,感兴趣的用户可以点击【 这里】查看当时的工具介绍文稿。

工具安装

git clone git://github.com/JusticeRage/FFM.git

工具使用

该工具的主要目的是为了帮助研究人员自动化实现后渗透利用阶段的常规任务,并通过检测目标环境的安全配置来帮助目标用户增强安全保护等级。

运行“./ffm.py“即可激活FFM,接下来我们就可以开始测试任务了。最常用的两个操作命令如下:

1、 输入“!list“命令可查看该工具提供的所有操作命令;

2、 输入“SHIFT+TAB“命令可在远程主机上实现命令补全;

命令列表

1、“!os“:这个命令非常简单,它会执行“cat /etc/*release*”来查看当前设备运行的操作系统版本,以便研究人员了解目标设备的测试环境。通过SSH连接目标设备后,“!os”命令即可使用,插件位于“commands/replacement_commands.py”。

2、“!download [remotefile] [local path]”:可以从远程主机中获取文件,并将其通过命令行工具拷贝到本地。这个命令有些复杂,因为它有更严格的错误检查,插件位于“commands/download_file.py”。需要注意的是,远程主机需要xxd或od来保证功能的正常运行。

3、“!upload [local file][remote path]”:这个命令的功能跟上面的那个差不多,只不过它负责的是将本地文件发送到远程主机中。

4、“!pty”:该命令会生成一个TTY,不过大多数情况下不建议使用,因为它会在目标主机上留下“痕迹“。当然,某些命令(例如sudo)还是需要TTY的。

5、“!py [local script]“:该命令可以在远程主机上执行本地Python脚本,而且全部在内存中运行。

研究人员可以通过编辑ffm.conf来对插件进行自定义配置。

处理器

上述指令可以生成一些bash命令并将其转发至shell,然后根据shell的输出来生成额外指令并进行更加复杂的操作。其中,当用户输入完数据并按下回车键后,输入处理器便会开始执行;当shell返回处理数据后,输出处理器便会运行。

许可证协议

该项目遵循 GPL v3开源许可证协议。

工具地址

FFM:【 GitHub传送门

*参考来源: JusticeRage,FB小编Alpha_h4ck编译,转载请注明来自FreeBuf.COM

快讯:华为即将支持统一推送标准

$
0
0

快讯:华为即将支持统一推送标准

IT之家4月18日消息据统一推送联盟消息,4月18日下午,由华为开发者联盟主办的HUAWEI Developer Day系列活动在西安成功举办。本次大会上,华为介绍了统一推送开发工作进展及时间表,并宣布将在今年10月份正式发布支持统一推送标准的华为推送服务。

由于长期以来存在的安卓“碎片化”的问题,我国大量的App必须在后台“保活”来确保推送消息的正常触达。为此,安卓生态滋生了大量如应用交叉唤醒、链式启动等应用擅自后台启动的问题。这种行为消耗了系统的大量系统资源,并进一步导致手机出现耗电、卡顿等问题。

统一推送联盟自成立以来,一直致力于解决上述问题。2018年8月1日,经过多方调研,反复讨论,多次修改,联盟面向社会发布了《统一推送通道层接口规范》,随后联盟明确了国内统一推送时间表。

联盟已发布统一推送时间表,在2019年底前将推动更多现有推送通道支持统一推送相关标准。

华为,统一联盟推送,IT资讯,业界,快讯:华为即将支持统一推送标准

基于socket.io快速实现一个实时通讯应用

$
0
0

随着web技术的发展,使用场景和需求也越来越复杂,客户端不再满足于简单的请求得到状态的需求。实时通讯越来越多应用于各个领域。

HTTP是最常用的客户端与服务端的通信技术,但是HTTP通信只能由客户端发起,无法及时获取服务端的数据改变。只能依靠定期轮询来获取最新的状态。时效性无法保证,同时更多的请求也会增加服务器的负担。

WebSocket技术应运而生。

WebSocket概念

不同于HTTP半双工协议,WebSocket是基于TCP 连接的全双工协议,支持客户端服务端双向通信。

WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

WebSocket API中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

HTTP与websocket对比

实现

原生实现

WebSocket对象一共支持四个消息 onopen, onmessage, onclose和onerror。

建立连接

通过javascript可以快速的建立一个WebSocket连接:

    var Socket = new WebSocket(url, [protocol] );

以上代码中的第一个参数 url, 指定连接的URL。第二个参数 protocol是可选的,指定了可接受的子协议。

同http协议使用 http://开头一样,WebSocket协议的URL使用 ws://开头,另外安全的WebSocket协议使用 wss://开头。

  1. 当Browser和WebSocketServer连接成功后,会触发onopen消息。
    Socket.onopen = function(evt) {};
  1. 如果连接失败,发送、接收数据失败或者处理数据出现错误,browser会触发onerror消息。
    Socket.onerror = function(evt) { };
  1. 当Browser接收到WebSocketServer端发送的关闭连接请求时,就会触发onclose消息。
    Socket.onclose = function(evt) { };

收发消息

  1. 当Browser接收到WebSocketServer发送过来的数据时,就会触发onmessage消息,参数evt中包含server传输过来的数据。
    Socket.onmessage = function(evt) { };
  1. send用于向服务端发送消息。
    Socket.send();

socket

WebSocket是跟随HTML5一同提出的,所以在兼容性上存在问题,这时一个非常好用的库就登场了—— Socket.io

socket.io封装了websocket,同时包含了其它的连接方式,你在任何浏览器里都可以使用socket.io来建立异步的连接。socket.io包含了服务端和客户端的库,如果在浏览器中使用了socket.io的js,服务端也必须同样适用。

socket.io是基于 Websocket 的Client-Server 实时通信库。

socket.io底层是基于engine.io这个库。engine.io为 socket.io 提供跨浏览器/跨设备的双向通信的底层库。engine.io使用了 Websocket 和 XHR 方式封装了一套 socket 协议。在低版本的浏览器中,不支持Websocket,为了兼容使用长轮询(polling)替代。

engine.io

API文档

Socket.io允许你触发或响应自定义的事件,除了connect,message,disconnect这些事件的名字不能使用之外,你可以触发任何自定义的事件名称。

建立连接

    const socket = io("ws://0.0.0.0:port"); // port为自己定义的端口号
    let io = require("socket.io")(http);
    io.on("connection", function(socket) {})

消息收发

一、发送数据

    socket.emit(自定义发送的字段, data);

二、接收数据

    socket.on(自定义发送的字段, function(data) {
        console.log(data);
    })

断开连接

一、全部断开连接

    let io = require("socket.io")(http);
    io.close();

二、某个客户端断开与服务端的链接

    // 客户端
    socket.emit("close", {});
    // 服务端
    socket.on("close", data => {
        socket.disconnect(true);
    });

room和namespace

有时候websocket有如下的使用场景:1.服务端发送的消息有分类,不同的客户端需要接收的分类不同;2.服务端并不需要对所有的客户端都发送消息,只需要针对某个特定群体发送消息;

针对这种使用场景,socket中非常实用的namespace和room就上场了。

先来一张图看看namespace与room之间的关系:

namespace与room的关系

namespace

服务端

    io.of("/post").on("connection", function(socket) {
        socket.emit("new message", { mess: `这是post的命名空间` });
    });
    
    io.of("/get").on("connection", function(socket) {
        socket.emit("new message", { mess: `这是get的命名空间` });
    });

客户端

    // index.js
    const socket = io("ws://0.0.0.0:****/post");
    socket.on("new message", function(data) {
        console.log('index',data);
    }
    //message.js
    const socket = io("ws://0.0.0.0:****/get");
    socket.on("new message", function(data) {
        console.log('message',data);
    }

room

客户端

    //可用于客户端进入房间;
    socket.join('room one');
    //用于离开房间;
    socket.leave('room one');

服务端

    io.sockets.on('connection',function(socket){
        //提交者会被排除在外(即不会收到消息)
        socket.broadcast.to('room one').emit('new messages', data);
        // 向所有用户发送消息
        io.sockets.to(data).emit("recive message", "hello,房间中的用户");      
    }

用socket.io实现一个实时接收信息的例子

终于来到应用的阶段啦,服务端用 node.js模拟了服务端接口。以下的例子都在本地服务器中实现。

服务端

先来看看服务端,先来开启一个服务,安装 expresssocket.io

安装依赖

    npm install --Dev express
    npm install --Dev socket.io

构建node服务器

    let app = require("express")();
    let http = require("http").createServer(handler);
    let io = require("socket.io")(http);
    let fs = require("fs");
    http.listen(port); //port:输入需要的端口号
    
    function handler(req, res) {
      fs.readFile(__dirname + "/index.html", function(err, data) {
        if (err) {
          res.writeHead(500);
          return res.end("Error loading index.html");
        }
        res.writeHead(200);
        res.end(data);
      });
    }
    io.on("connection", function(socket) {
        console.log('连接成功');
        //连接成功之后发送消息
        socket.emit("new message", { mess: `初始消息` });
        
    });

客户端

核心代码——index.html(向服务端发送数据)

<div>发送信息</div><input placeholder="请输入要发送的信息" /><button onclick="postMessage()">发送</button>
    // 接收到服务端传来的name匹配的消息
    socket.on("new message", function(data) {
      console.log(data);
    });
    function postMessage() {
      socket.emit("recive message", {
        message: content,
        time: new Date()
      });
      messList.push({
        message: content,
        time: new Date()
      });
    }

核心代码——message.html(从服务端接收数据)

    socket.on("new message", function(data) {
      console.log(data);
    });

效果

实时通讯效果
实时通讯效果

客户端全部断开连接
全部断开

某客户端断开连接
某客户端断开连接

namespace应用
namespace

加入房间
加入房间

离开房间
离开房间

框架中的应用

npm install socket.io-client

    const socket = require('socket.io-client')('http://localhost:port');

    componentDidMount() {
        socket.on('login', (data) => {
            console.log(data)
        });
        socket.on('add user', (data) => {
            console.log(data)
        });
        socket.on('new message', (data) => {
            console.log(data)
        });
    }

分析webSocket协议

Headers

Headers

请求包

    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
    Cache-Control: no-cache
    Connection: Upgrade
    Cookie: MEIQIA_VISIT_ID=1IcBRlE1mZhdVi1dEFNtGNAfjyG; token=0b81ffd758ea4a33e7724d9c67efbb26; io=ouI5Vqe7_WnIHlKnAAAG
    Host: 0.0.0.0:2699
    Origin: http://127.0.0.1:5500
    Pragma: no-cache
    Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
    Sec-WebSocket-Key: PJS0iPLxrL0ueNPoAFUSiA==
    Sec-WebSocket-Version: 13
    Upgrade: websocket
    User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1

请求包说明:

  • 必须是有效的http request 格式;
  • HTTP request method 必须是GET,协议应不小于1.1 如: Get / HTTP/1.1;
  • 必须包括Upgrade头域,并且其值为“websocket”,用于告诉服务器此连接需要升级到websocket;
  • 必须包括”Connection” 头域,并且其值为“Upgrade”;
  • 必须包括”Sec-WebSocket-Key”头域,其值采用base64编码的随机16字节长的字符序列;
  • 如果请求来自浏览器客户端,还必须包括Origin头域 。 该头域用于防止未授权的跨域脚本攻击,服务器可以从Origin决定是否接受该WebSocket连接;
  • 必须包括“Sec-webSocket-Version”头域,是当前使用协议的版本号,当前值必须是13;
  • 可能包括“Sec-WebSocket-Protocol”,表示client(应用程序)支持的协议列表,server选择一个或者没有可接受的协议响应之;
  • 可能包括“Sec-WebSocket-Extensions”, 协议扩展, 某类协议可能支持多个扩展,通过它可以实现协议增强;
  • 可能包括任意其他域,如cookie.

应答包

应答包说明:

    Connection: Upgrade
    Sec-WebSocket-Accept: I4jyFwm0r1J8lrnD3yN+EvxTABQ=
    Sec-WebSocket-Extensions: permessage-deflate
    Upgrade: websocket
  • 必须包括Upgrade头域,并且其值为“websocket”;
  • 必须包括Connection头域,并且其值为“Upgrade”;
  • 必须包括Sec-WebSocket-Accept头域,其值是将请求包“Sec-WebSocket-Key”的值,与”258EAFA5-E914-47DA-95CA-C5AB0DC85B11″这个字符串进行拼接,然后对拼接后的字符串进行sha-1运算,再进行base64编码,就是“Sec-WebSocket-Accept”的值;
  • 应答包中冒号后面有一个空格;
  • 最后需要两个空行作为应答包结束。

请求数据

    EIO: 3
    transport: websocket
    sid: 8Uehk2UumXoHVJRzAAAA
  • EIO:3 表示使用的是engine.io协议版本3
  • transport 表示传输采用的类型
  • sid: session id (String)

Frames

WebSocket协议使用帧(Frame)收发数据,在控制台->Frames中可以查看发送的帧数据。

其中帧数据前的数字代表什么意思呢?

这是 Engine.io协议,其中的数字是数据包编码:

<Packet type id> [<data>]

  • 0 open——在打开新传输时从服务器发送(重新检查)
  • 1 close——请求关闭此传输,但不关闭连接本身。
  • 2 ping——由客户端发送。服务器应该用包含相同数据的乓包应答

    客户端发送:2probe探测帧
  • 3 pong——由服务器发送以响应ping数据包。

    服务器发送:3probe,响应客户端
  • 4 message——实际消息,客户端和服务器应该使用数据调用它们的回调。
  • 5 upgrade——在engine.io切换传输之前,它测试,如果服务器和客户端可以通过这个传输进行通信。如果此测试成功,客户端发送升级数据包,请求服务器刷新其在旧传输上的缓存并切换到新传输。
  • 6 noop——noop数据包。主要用于在接收到传入WebSocket连接时强制轮询周期。

实例

发送数据

接收数据

以上的截图是上述例子中数据传输的实例,分析一下大概过程就是:

  1. connect握手成功
  2. 客户端会发送2 probe探测帧
  3. 服务端发送响应帧3probe
  4. 客户端会发送内容为5的Upgrade帧
  5. 服务端回应内容为6的noop帧
  6. 探测帧检查通过后,客户端停止轮询请求,将传输通道转到websocket连接,转到websocket后,接下来就开始定期(默认是25秒)的 ping/pong
  7. 客户端、服务端收发数据,4表示的是engine.io的message消息,后面跟随收发的消息内容

为了知道Client和Server链接是否正常,项目中使用的ClientSocket和ServerSocket都有一个心跳的线程,这个线程主要是为了检测Client和Server是否正常链接,Client和Server是否正常链接主要是用ping pong流程来保证的。

该心跳定期发送的间隔是socket.io默认设定的25m,在上图中也可观察发现。该间隔可通过 配置修改。

socket通信流程

参考 engine.io-protocol

参考文章

Web 实时推送技术的总结
engine.io 原理详解

广而告之

本文发布于 薄荷前端周刊,欢迎Watch & Star ★,转载请注明出处。

欢迎讨论,点个赞再走吧 。◕‿◕。 ~

互联网人才的成长之路:写在创业 7 周年

$
0
0

前言

在互联网行业工作快十年了,自己在猿辅导参与创业也马上 7 年了。自己始终想总结出互联网人才在成长上大的阶段,于是有了最近的这个心得。其实不一定对,但是也算是思考了很久,所以写出来供大家讨论交流。

不管是做产品、技术,还是做运营,市场,我把一个互联网人才的成长分为四级,每一级对应一类能力。

第一级:执行能力

我对执行能力的解释是:对于比较明确的工作目标和内容,通过对目标进行分析,对步骤进行拆解,以及投入自己的热情和努力,加上一定的沟通和协作,最终可以保质保量的完成工作目标。

刚毕业的同学,不管是做产品,还是做技术,还是做运营,都是做偏执行的事情。这个时候,工作其实是非常具体的,不会需要你花很大的精力来做规化。因为有偏资深的人把关,这个时候其实也相对容易完成目标。

但是,我个人觉得至少有 80% 的人,在这一级能力上都是不太优秀的。为什么呢?因为做好一件事情真的非常难。它需要一个人具备:

  • 对工作的努力和热情。
  • 对工作的一些基础能力的积累。
  • 自我情绪和行为控制,包括转移注意力、自我激励、延迟满足等。
  • 沟通协调能力,包括认知他人情绪和处理相互关系。

以上四点都不容易:

  • 有多少人真正的把工作当作自己的事情,并且投入足够的热情?
  • 有多少人在专业能力上做到的足够的积累?拿研发来说,学校学的数据结构、计算机网络、算法、设计模式这些课程,有多少人是真的是很扎实的?
  • 人很容易懈怠的,自我的激励并不容易。有多少人不需要领导盯着,自己天天抢着多做一些,多学一些?拿研发来说,下班之后有多少人自觉充电学习的?
  • 研发和产品,研发和研发,都是需要沟通配合的,很多研发在这一点上都偏弱。

所以,第一级能力,就挡住了 80% 的同学。

如果你做好了执行,恭喜你,你就是公司应届生里面那前 20% 绩效拿 A 的同学。你们可以获得超额的回报,并且可能获得晋升的机会。

但是,这仅仅是刚刚开始,让我们看看后面还有哪些能力需要积累。

第二级:迭代的能力

我对迭代的理解是:它包括自我迭代和工作迭代,方法上都是通过:主动学习、主动复盘、关注数据和分析数据。通过这些方法,整理出工作或者生活的一些概括的规则、模型或方法论。

执行力虽然很重要,但是更重要的是背后的思考和总结,否则就是使用蛮力。任何事情,按理说你做久了,都应该通过总结,形成一些做事情的经验。最终这些沉淀下来的经验,才是你和别人竞争的优势。

迭代的能力听起来很容易啊,为什么我把它单独作为一级呢?

因为这是一个听起来容易,执行起来很难的能力。

迭代能力做得好,首先应该例行化,一个人应该定期地做总结和反思。这就类似于 Scrum 将回顾会议(Retrospective Meeting)作为例行会议一样,让组织定期迭代。但是能够坚持按周、按月、按年总结反思的人还是偏少。最近一个朋友推荐《曾国藩传》,他说书里写道曾国藩按天为单位做自我反思总结,还把这些内容分享给周围的人,这就是人家牛逼的地方。

迭代能力做得好,也需要文档化。你应该用任何书面的方式把它记录下来,可以是纸质的,也可以是电子的(比如 Evernote 等)。《原则》、《卓有成效的管理者》等书里面都推荐了这个方法。因为文档化的内容,更方便做复盘和总结。文档化这件事情也很难坚持,因为相对来说比较枯燥。

举个例子:我现在觉得某支股票很厉害,买了一些它的股票。我如果把这些买下它的理由写下来。然后过了半年,假如这个股票跌了,那我就得看我当时的决策为什么不对。这相当于一条一条打自己的脸。如果没有文档化,这个事情就容易被糊弄过去,那我得到的总结就不够深刻了。

迭代能力之所以重要,是因为个人成长之路很多时候无法依赖于老师教,只能通过自我学习,而迭代总结就是最好的个体学习方式。

第三级:开放和组织能力

开放能力是指:自我客观评价,并且愿意倾听的能力。组织能力是指:能够把一群人推动做好一件事情。

拥有前面两级的能力,已经是一个很优秀的职场人士了。但是这个时候就特别容易骄傲,比如:

  • 总觉得自己特别牛逼。希望用自己的一些点子一下子带来竞争优势。
  • 总觉得与自己合作的同事水平一般。比如产品觉得技术拖后腿开发慢,还老出线上事故。技术觉得产品老改需求,而且功能上线后并没有见到什么效果。产品技术觉得运营老是搞特别复杂的活动,不会做减法。运营老觉得技术支持不到位,总是说没资源排期。
  • 总觉得竞争对手的策略都是失败的,同时认为自己的策略都很厉害。

自我客观评价,需要个体首先要对自己有一个清晰的判断,认知到自己的优点和短板。一个人战略能力强,关注细节的能力就差;一个人专业能力强,统筹业务的能力就差。不可能一个人各方面都是全才。因为很多事情,还是靠时间投入积累出来的,没有足够的时间积累,很难说自己就是这方面的专家。

自我能够客观评价之后,就会做取舍,放弃一部分东西,同时获得一部分东西。放弃这件事情其实很难,是反人性的。但是好多时候做企业定战略的时候,也是取舍,很多时候战略企业是结合自己的团队、现状等各种具体的情况做出来的取舍。

自我客观评价之后,也容易对他人进行客观评价了,既然看自己都知道看长处,那看别人也应该看优点。组织分工的时候,利用大家各自的长处,就容易形成合力。评价员工的时候,也应该看人家的长处,除非他的短处限制了他的工作产出,否则并不需要按短处来打分。比如:一个牛逼的程序员,但是很内向,只要这个不影响必要的沟通,否则他内向点就内向点呗,只要他的代码厉害,沟通上的短板影响不大。

自我客观评价的能力难点在于人都会高估自己,低估别人,所以需要多做自我提醒。一件事情如果别人思考得更久,但是结论和自己的不一样,就应该多思考一下再做判断。

能够做到自我客观评价之后,通常也就会注意倾听了。因为当前这种社会组织形式下,决策者在信息量上并不占优,所以只有足够倾听,获得足够的信息量,才可以获得高质量的决策。

说完开放能力,再说说组织能力。

组织能力,是一种招聘和培养核心班子的能力。在之前的能力级别,都依赖于自己更多,而在这个级别,依赖于别人更多。不管是做决策还是做执行,本质上你离不开别人了。如果最大化你的价值和组织的价格,是需要学习的。优秀的人可以通过培养,招聘,授权,聚焦,管理非常多的人和事情。

第四级:战略能力。

战略能力是指:能够通过思考,产出高质量竞争策略的能力。所谓的高质量,就是从结果看能够产生商业竞争上的优势。

战略能力看起来简单,但实操无比困难。你得抵挡诱惑,决定做什么不做什么;你得构建有效的竞争手段;你得最终形成互城河。你的对手一点都不笨,你想得到的别人也想得到,你要假设面对的是一个完美对手。用最坏情况下,打明牌也能成功的方式来获胜。

也因为战略太重要了,所以初创公司的 CEO 值得拿超过 50% 的决策权和相关股份。当然,他也承担了企业最大的成败因素。因为战略错了,什么都错了。

我个人对战略能力的亲身实践非常少,但是我所在的猿辅导公司,从最初的从成人教育转到 K12 领域,到之后的专注在线直播课业务,都给我很强的感受:原来战略定得好可以这么厉害。我也希望在这方面能够持续学习提高。

小结

  • 第一级:执行能力。
  • 第二级:迭代能力。
  • 第三级:开放和组织能力。
  • 第四级:战略能力。

腾讯宣布测试年满 16 周岁才能玩游戏

$
0
0
腾讯是中国乃至世界最大的游戏公司,但过去一年它的游戏遭到了官媒党媒的批评,被指忽视了社会责任,让儿童沉迷于游戏,这一批评促使腾讯推出了所谓的健康系统——即实名制系统。凡是启用健康系统的游戏,其用户账号都会接受强制的公安实名校验,以确认相关身份信息的真实有效。校验通过后,确认为未成年人的帐号将纳入健康系统进行防沉迷,12 周岁以下(含 12 周岁)每天限玩 1 小时(同时每日 21:00 - 次日 8:00 之间禁玩),12 周岁以上未成年人每天限玩 2 小时。校验未通过的账号将禁止登录。现在,腾讯宣布 将启动 16+ 试点,即年满 16 周岁的用户才可以获得系统授权,直接登录游戏体验;16 周岁及以上的未成年用户仍会受到健康系统防沉迷规则的管理,每天限玩 2 小时。

四大模块,带你了解阿里大数据产品技术架构

$
0
0

本文笔者将从数据采集层、数据计算层、数据服务层、数据应用层四大层次来带大家了解阿里大数据的产品技术架构。

2014年,马云提出:“人类正从IT时代走向DT时代”。

如果说在IT时代是以自我控制、自我管理为主,那么到了DT (Data Technology)时代,则是以服务大众、激发生产力为主。以互联网(或者物联网)、云计算、大数据和人工智能为代表的新技术革命正在渗透至各行各业,悄悄地改变着我们的生活。

在DT时代,人们比以往任何时候更能收集到更丰富的数据。

IDC的报告显示:预计到2020年,全球数据总量将超过40ZB (相当于40万亿GB),这一数据量是2011年的22倍!正在呈“爆炸式”增长的数据,其潜在的巨大价值有待发掘。数据作为一种新的能源,正在发生聚变,变革着我们的生产和生活,催生了当下大数据行业发展热火朝天的盛景。

但是,如果不能对这些数据进行有序,有结构地分类组织和存储。如果不能有效利用并发掘它,继而产生价值,那么它同时也成为一场“灾难”。无序、无结构的数据犹如堆积如山的垃圾,给企业带来的是令人昨舌的高额成本。

在阿里巴巴集团内,我们面临的现实情况是:集团数据存储达到EB级别,部分单张表每天的数据记录数高达几千亿条,在2016年“双”购物狂欢节”的24小时中,支付金额达到了1207 亿元人民币,支付峰值高达12万笔/秒,下单峰值达17.5万笔/秒,媒体直播大屏处理的总数据量高达百亿且所有数据都需要做到实时、准确地对外披露……

这些给数据采集、存储和计算都带来了极大的挑战。

在阿里内部,数据工程师每天要面对百万级规模的离线数据处理工作。阿里大数据井喷式的爆发,加大了数据模型、数据研发、数据质量和运维保障工作的难度。

同时,日益丰富的业态,也带来了各种各样、纷繁复杂的数据需求。如何有效地满足来自员工、商家、合作伙伴等多样化的需求?提高他们对数据使用的满意度,是数据服务和数据产品需要面对的挑战。

如何建设高效的数据模型和体系,使数据易用,避免重复建设和数据不一致性,保证数据的规范性?如何提供高效易用的数据开发工具?如何做好数据质量保障:如何有效管理和控制日益增长的存储和计算消耗?如何保证数据服务的稳定,保证其性能?如何设计有效的数据产品高效赋能于外部客户和内部员…..这些都给大数据系统的建设提出了更多复杂的要求。

本文介绍的阿里巴巴大数据系统架构,就是为了满足不断变化的业务需求,同时实现系统的高度扩展性、灵活性以及数据展现的高性能而设计的。

如图1.1所示是阿里巴巴大数据系统体系架构图,从图中可以清晰地看到数据体系主要分为数据采集、数据计算、数据服务和数据应用四大层次。

干货|3分钟带你了解阿里大数据产品技术架构

一、数据采集层

阿里巴巴是一家多业态的互联网公司,几亿规模的用户(如商家、消费者、商业组织等)在平台上从事商业、消费、娱乐等活动,每时每刻都在产生海量的数据。

数据采集作为阿里大数据系统体系的第一环尤为重要。因此,阿里巴巴建立了一套标准的数据采集体系方案,致力全面、高性能、规范地完成海量数据的采集,并将其传输到大数据平台。

阿里巴巴的日志采集体系方案包括两大体系: Aplus.JS 是Web端日志采集技术方案; UserTrack 是APP端日志采集技术方案。

在采集技术基础之上,阿里巴巴用面向各个场景的埋点规范,来满足通用浏览、点击、特殊交互、APP事件、H5及APP里的HS和Native日志数据打通等多种业务场景。

同时,还建立了一套高性能、高可靠性的数据传输体系,完成数据从生产业务端到大数据系统的传输。在传输方面,采用TimeTunnel (TT), 它既包括数据库的增量数据传输,也包括日志数据的传输。

TT作为数据传输服务的基础架构,既支持实时流式计算,也支持各种时间窗口的批量计算。另外,也通过数据同步工具(DataX和同步中心,其中同步中心是基于DataX易用性封装的)直连异构数据库(备库)来抽取各种时间窗口的数据。

二、数据计算层

数据只有被整合和计算,才能被用于洞察商业规律,挖掘潜在信息,从而实现大数据价值,达到赋能于商业和创造价值的目的。

从采集系统中收集到的大量原始数据,将进人数据计算层中被进一步整合与计算。

面对海量的数据和复杂的计算,阿里巴巴的数据计算层包括两大体系:数据存储及计算云平台(离线计算平台MaxCompute和实时计算平台StreamCompute)和数据整合及管理体系(内部称之为“OneData”)。

其中,MaxCompute 是阿里巴巴自主研发的离线大数据平台,其丰富的功能和强大的存储及计算能力使得阿里巴巴的大数据有了强大的存储和计算引擎: StreamCompute 是阿里巴巴自主研发的流式大数据平台,OneData是数据整合及管理的方法体系及工具。

阿里巴巴的大数据工程师在这一体系下,构建统一、规范、可共享的全域数据体系,避免数据的冗余和重复建设,规避数据烟囱和不一致性,充分发挥阿里巴巴在大数据海量、多样性方面的独特优势。

借助这一统一化数据整合及管理的方法体系,我们构建了阿里巴巴的数据公共层,并可以帮助相似大数据项目快速落地实现。

从数据计算频率角度来看:阿里数据仓库可以分为离线数据仓库和实时数据仓库。

离线数据仓库主要是指:传统的数据仓库概念,数据计算频率主要以天(包含小时、周和月)为单位——如T-1,则每天凌晨处理上一天的数据。

但是,随着业务的发展特别是交易过程的缩短,用户对数据产出的实时性要求逐渐提高,所以阿里的实时数据仓库应运而生。“双11”实时数据直播大屏,就是实时数据仓库的种典型应用。

阿里数据仓库的数据加工链路也是遵循业界的分层理念,包括:操作数据层(Operational Data Store, ODS)、 明细数据层(Data WarehouseDetail, DWD)、汇总数据层(Data Warehouse Summary, DWS)和应用数据层(Application Data Store, ADS)。通过数据仓库不同层次之间的加工过程实现从数据资产向信息资产的转化,并且对整个过程进行有效的元数据管理及数据质量处理。

在阿里大数据系统中,元数据模型整合及应用是一个重要的组成部分,主要包含:数据源元数据、数据仓库元数据、数据链路元数据、工具类元数据、数据质量类元数据等。

元数据应用主要面向数据发现、数据管理等,如用于存储、计算和成本管理等。

三、数据服务层

当数据已被整合和计算好之后,需要提供给产品和应用进行数据消费。

为了有更好的性能和体验,阿里巴巴构建了自己的数据服务层,通过接口服务化方式对外提供数据服务。针对不同的需求,数据服务层的数据源架构在多种数据库之上,如:MySQL和HBase等。后续将逐渐迁移至阿里云2数据库ApsaraDB for RDS(简称”RDS )和表格仔储(Table Store)等。

开放给集团内部各应用使用:现在,数据服务每天拥有几十亿的数据调用量,如何在性能、稳定性、扩展性等方面更好地服务于用户?如何满足应用各种复杂的数据服务需求?如何保证“双11” 媒体大屏数据服务接口的高可用……

随着业务的发展,需求越来越复杂,因此数据服务也在不断地前进。

数据服务可以使应用对底层数据存储透明,将海量数据方便高效的开放给集团内部各应用使用。现在,数据服务每天拥有几十亿的数据调用量,如何在性能、稳定性、扩展性等方面更好地服务于用户?如何满足应用各种复杂的数据服务需求?如何保证“双11”媒体大屏数据服务接口的高可用……随着业务的发展,需求越来越复杂,因此数据服务也在不断地前进。

数据服务层对外提供数据服务主要是通过统一的数据服务平台 (为方便阅读,简称为“OneService”)。

OneService 以数据仓库整合计算好的数据作为数据源,对外通过接口的方式提供数据服务,主要提供简单数据查询服务、复杂数据查询服务(承接集团用户识别、用户画像等复杂数据查询服务)和实时数据推送服务三大特色数据服务。

四、数据应用层

数据已经准备好,需要通过合适的应用提供给用户,让数据最大化地发挥价值。

阿里对数据的应用表现在各个方面,如:搜索、推荐、广告、金融、信用、保险、文娱、物流等。商家,阿里内部的搜索、推荐、广告、金融等平台,阿里内部的运营和管理人员等,都是数据应用方:ISV、研究机构和社会组织等也可以利用阿里开放的数据能力和技术。

我们相信:数据作为新能源,为产业注人的变革是显而易见的。我们对数据新能源的探索也不仅仅停留在狭义的技术、服务和应用上。我们正在挖掘大数据更深层次的价值,为社会经济和民生基础建设等提供创新方法。

 

作者:Wilton(董超华),曾任职科大讯飞,现任富力环球商品贸易港大数据产品经理。公众号名称:改变世界的产品经理。

本文由@华仔 原创发布于人人都是产品经理,未经许可,禁止转载。

题图来自Unsplash, 基于CC0协议。

基于PaddlePaddle的词向量实战 | 深度学习基础任务教程系列(二)

$
0
0

词向量是自然语言处理中常见的一个操作,是搜索引擎、广告系统、推荐系统等互联网服务背后常见的基础技术。

在这些互联网服务里,我们经常要比较两个词或者两段文本之间的相关性。为了做这样的比较,我们往往把词表示成计算机适合处理的方式。最自然的方式莫过于向量空间模型(vector space model)。在这种方式里,每个词被表示成一个实数向量(one-hot vector),其长度为字典大小,每个维度对应一个字典里的每个词,除了这个词对应维度上的值是1,其他元素都是0。One-hot vector虽然自然,但是用处有限。比如,在互联网广告系统里,如果用户输入的query是“母亲节”,而有一个广告的关键词是“康乃馨”。

按照常理,我们知道这两个词之间是有联系的——母亲节通常应该送给母亲一束康乃馨;但是这两个词对应的one-hot vectors之间的距离度量,无论是欧氏距离还是余弦相似度(cosine similarity),由于其向量正交,都认为这两个词毫无相关性。得出这种与我们相悖的结论的根本原因是:每个词本身的信息量都太小。所以,仅仅给定两个词,不足以让我们准确判别它们是否相关。要想精确计算相关性,我们还需要更多的信息——从大量数据里通过机器学习方法归纳出来的知识。

在机器学习领域,通过词向量模型(word embedding model)可将一个one-hot vector映射到一个维度更低的实数向量(embedding vector),如:

embedding(母亲节)=[0.3,4.2,−1.5,...];
embedding(康乃馨)=[0.2,5.6,−2.3,...];

在这个映射到的实数向量表示中,两个语义(或用法)上相似的词对应的词向量“更像”,这样如“母亲节”和“康乃馨”的对应词向量的余弦相似度就不再为零了。

词向量模型可以是概率模型、共生矩阵(co-occurrence matrix)模型或神经元网络模型。在用神经网络模型求词向量之前,传统的做法是统计一个词语的共生矩阵X,在对X做矩阵分解,得到了所有词的词向量。

但是传统的方法有三大问题:1)由于很多词没有出现,导致矩阵极其稀疏;2)矩阵非常大,维度太高;3)需要手动去掉停用词(如although, a,...),不然这些频繁出现的词也会影响矩阵分解的效果。

而基于神经网络的模型不需要计算和存储一个在全语料上统计产生的大表,是通过学习语义信息得到词向量,因此能很好地解决以上问题。本教程旨在展示神经网络训练词向量的细节,以及如何用PaddlePaddle训练一个词向量模型。

项目地址:

http://paddlepaddle.org/documentation/docs/zh/1.3/beginners_guide/basics/word2vec/index.html

基于PaddlePaddle训练一个词向量模型操作详情请参照Github:

https://github.com/PaddlePaddle/book/blob/develop/04.word2vec/README.cn.md

效果展示

当词向量训练好后,我们可以用数据可视化算法t-SNE[4]画出词语特征在二维上的投影(如下图所示)。从图中可以看出,语义相关的词语(如a, the, these; big, huge)在投影上距离很近,语意无关的词(如say, business; decision, japan)在投影上的距离很远

另一方面,我们知道两个向量的余弦值在[−1,1][−1,1]的区间内:两个完全相同的向量余弦值为1, 两个相互垂直的向量之间余弦值为0,两个方向完全相反的向量余弦值为-1,即相关性和余弦值大小成正比。因此我们还可以计算两个词向量的余弦相似度:

please input two words: big huge
similarity: 0.899180685161
please input two words: from company
similarity: -0.0997506977351

以上结果可以通过运行calculate_dis.py加载字典里的单词和对应训练特征结果得到,我们将在模型应用中详细描述用法。

模型概览

在这里我们介绍三个训练词向量的模型:N-gram模型,CBOW模型和Skip-gram模型,它们的中心思想都是通过上下文得到一个词出现的概率。对于N-gram模型,我们会先介绍语言模型的概念,并在之后的训练模型中,带大家用PaddlePaddle实现它。而后两个模型,是近年来最有名的神经元词向量模型,由Tomas Mikolov 在Google 研发[3],虽然它们很浅很简单,但训练效果很好。

N-gram neural model

在计算语言学中,N-gram是一种重要的文本表示方法,表示一个文本中连续的n个项。基于具体的应用场景,每一项可以是一个字母、单词或者音节。N-gram模型也是统计语言模型中的一种重要方法,用N-gram训练语言模型时,一般用每个N-gram的历史n-1个词语组成的内容来预测第n个词。

Yoshua Bengio等科学家就于2003年在著名论文Neural Probabilistic Language Models [1]中介绍如何学习一个神经元网络表示的词向量模型。文中的神经概率语言模型(Neural Network Language Model,NNLM)通过一个线性映射和一个非线性隐层连接,同时学习了语言模型和词向量,即通过学习大量语料得到词语的向量表达,通过这些向量得到整个句子的概率。

因所有的词语都用一个低维向量来表示,用这种方法学习语言模型可以克服维度灾难(curse of dimensionality)。一句话中第t个词的概率和该句话的前t−1个词相关。可实际上越远的词语其实对该词的影响越小,那么如果考虑一个n-gram, 每个词都只受其前面n-1个词的影响,则有:

语料中都是有意义的句子,N-gram模型的优化目标则是最大化目标函数:

其中f(Wt,Wt-1,...,Wt-n+1)表示根据历史n-1个词得到当前词Wt的条件概率,R(θ)表示参数正则项。

图2. N-gram神经网络模型

图2展示了N-gram神经网络模型,从下往上看,该模型分为以下几个部分:-对于每个样本,模型输入Wt-n+1,...,Wt-1,输出句子第t个词在字典中|V|个词上的概率分布。每个输入词Wt-n+1,...,Wt-1首先通过映射矩阵映射到词C(Wt-n-1),...,C(Wt-1)。然后所有词语的词向量拼接成一个大向量,并经过一个非线性映射得到历史词语的隐层表示

其中,x为所有词语的词向量拼接成的大向量,表示文本历史特征;θ、U、b1、b2和W分别为词向量层到隐层连接的参数。g表示未经归一化的所有输出单词概率,gi表示未经归一化的字典中第i个单词的输出概率。

根据softmax的定义,通过归一化gi,生成目标词Wt的概率为

整个网络的损失值(cost)为多类分类交叉熵,用公式表示为

其中yik表示第i个样本第k类的真实标签(0或1),softmax(gik)表示第ii个样本第k类softmax输出的概率。

Continuous Bag-of-Words model(CBOW)

CBOW模型通过一个词的上下文(各N个词)预测当前词。当N=2时,模型如下图所示:

图3. CBOW模型

具体来说,不考虑上下文的词语输入顺序,CBOW是用上下文词语的词向量的均值来预测当前词。即:

其中Xt为第t个词的词向量,分类分数(score)向量z=U*context,最终的分类y采用softmax,损失函数采用多类分类交叉熵。

Skip-gram model

CBOW的好处是对上下文词语的分布在词向量上进行了平滑,去掉了噪声,因此在小数据集上很有效。而Skip-gram的方法中,用一个词预测其上下文,得到了当前词上下文的很多样本,因此可用于更大的数据集。

图4. Skip-gram模型

如上图所示,Skip-gram模型的具体做法是,将一个词的词向量映射到2n个词的词向量(2n表示当前输入词的前后各n个词),然后分别通过softmax得到这2n个词的分类损失值之和。

数据准备

1、数据介绍

本教程使用Penn Treebank (PTB)(经Tomas Mikolov预处理过的版本)数据集。PTB数据集较小,训练速度快,应用于Mikolov的公开语言模型训练工具[2]中。其统计情况如下:

训练数据

验证数据

测试数据

ptb.train.txt

ptb.valid.txt

ptb.test.txt

42068句

3370句

3761句

2、数据预处理

本教程训练的是5-gram模型,表示在PaddlePaddle训练时,每条数据的前4个词用来预测第5个词。PaddlePaddle提供了对应PTB数据集的python包paddle.dataset.imikolov,自动完成数据的下载与预处理,方便大家使用。

预处理会把数据集中的每一句话前后加上开始符号<s>以及结束符号<e>。然后依据窗口大小(本教程中为5),从头到尾每次向右滑动窗口并生成一条数据。

如"I have a dream that one day" 一句提供了5条数据:

<s> I have a dream
I have a dream that
have a dream that one
a dream that one day
dream that one day <e>

最后,每个输入会按其单词次在字典里的位置,转化成整数的索引序列,作为PaddlePaddle的输入。

模型结构

本配置的模型结构如下图所示:

图5. 模型配置中的N-gram神经网络模型

首先我们先加载所需的包

from__future__importprint_functionimportpaddleaspaddleimportpaddle.fluidasfluidimportsiximportnumpyimport sysimportmath

然后,定义参数

EMBED_SIZE = 32      # embedding维度
HIDDEN_SIZE = 256    # 隐层大小
N = 5                # ngram大小,这里固定取5
BATCH_SIZE = 100     # batch大小
PASS_NUM = 100       # 训练轮数
 use_cuda = False  # 如果用GPU训练,则设置为True
word_dict = paddle.dataset.imikolov.build_dict()
dict_size = len(word_dict)

更大的BATCH_SIZE将使得训练更快收敛,但也会消耗更多内存。由于词向量计算规模较大,如果环境允许,请开启使用GPU进行训练,能更快得到结果。在新的Fluid版本里,我们不必再手动计算词向量。PaddlePaddle提供了一个内置的方法fluid.layers.embedding,我们就可以直接用它来构造N-gram 神经网络。

现在,我们来定义我们的N-gram 神经网络结构。这个结构在训练和预测中都会使用到。因为词向量比较稀疏,我们传入参数 is_sparse == True, 可以加速稀疏矩阵的更新。      

definference_program(words,is_sparse): 
    embed_first=fluid.layers.embedding(
        input=words[0],
        size=[dict_size,EMBED_SIZE],
        dtype='float32',
        is_sparse=is_sparse,
        param_attr='shared_w')
    embed_second=fluid.layers.embedding(
        input=words[1],
        size=[dict_size,EMBED_SIZE],
        dtype='float32',
        is_sparse=is_sparse,
        param_attr='shared_w')
    embed_third=fluid.layers.embedding(
        input=words[2],
        size=[dict_size,EMBED_SIZE],
        dtype='float32',
        is_sparse=is_sparse,
        param_attr='shared_w')
    embed_fourth=fluid.layers.embedding(
        input=words[3],
        size=[dict_size,EMBED_SIZE],
        dtype='float32',
        is_sparse=is_sparse,
        param_attr='shared_w')
 
    concat_embed=fluid.layers.concat(
        input=[embed_first,embed_second,embed_third,embed_fourth],axis=1)
    hidden1=fluid.layers.fc(input=concat_embed,
                              size=HIDDEN_SIZE,
                              act='sigmoid')
    predict_word=fluid.layers.fc(input=hidden1,size=dict_size,act='softmax')
    returnpredict_word


基于以上的神经网络结构,我们可以如下定义我们的训练方法
deftrain_program(predict_word):
    # 'next_word'的定义必须要在inference_program的声明之后,
    否则train program输入数据的顺序就变成了[next_word, firstw, secondw,
    # thirdw, fourthw], 这是不正确的.
    next_word=fluid.layers.data(name='nextw',shape=[1],dtype='int64')
    cost=fluid.layers.cross_entropy(input=predict_word,label=next_word)
    avg_cost=fluid.layers.mean(cost)
    returnavg_cost
 
defoptimizer_func():
    returnfluid.optimizer.AdagradOptimizer(
        learning_rate=3e-3,
        regularization=fluid.regularizer.L2DecayRegularizer(8e-4))


现在我们可以开始训练啦。我们有现成的训练和测试集:paddle.dataset.imikolov.train()和paddle.dataset.imikolov.test()。两者都会返回一个读取器。paddle.batch 会读入一个读取器,然后输出一个批次化了的读取器。我们还可以在训练过程中输出每个步骤,批次的训练情况。

deftrain(if_use_cuda,params_dirname,is_sparse=True):
    place=fluid.CUDAPlace(0)ifif_use_cudaelsefluid.CPUPlace()
 
    train_reader=paddle.batch(
        paddle.dataset.imikolov.train(word_dict,N),BATCH_SIZE)
    test_reader=paddle.batch(
        paddle.dataset.imikolov.test(word_dict,N),BATCH_SIZE)
 
    first_word=fluid.layers.data(name='firstw',shape=[1],dtype='int64')
    second_word=fluid.layers.data(name='secondw',shape=[1],dtype='int64')
    third_word=fluid.layers.data(name='thirdw',shape=[1],dtype='int64')
    forth_word=fluid.layers.data(name='fourthw',shape=[1],dtype='int64')
    next_word=fluid.layers.data(name='nextw',shape=[1],dtype='int64')
 
    word_list=[first_word,second_word,third_word,forth_word,next_word]
    feed_order=['firstw','secondw','thirdw','fourthw','nextw']
 
    main_program=fluid.default_main_program()
    star_program=fluid.default_startup_program()
 
    predict_word=inference_program(word_list,is_sparse)
    avg_cost=train_program(predict_word)
    test_program=main_program.clone(for_test=True)
 
    sgd_optimizer=optimizer_func()
    sgd_optimizer.minimize(avg_cost)
 
    exe=fluid.Executor(place)
 
    deftrain_test(program,reader):
        count=0
        feed_var_list=[
            program.global_block().var(var_name)forvar_nameinfeed_order
]
        feeder_test=fluid.DataFeeder(feed_list=feed_var_list,place=place)
        test_exe=fluid.Executor(place)
        accumulated=len([avg_cost])*[0]
        fortest_datainreader():
            avg_cost_np=test_exe.run(
                program=program,
                feed=feeder_test.feed(test_data),
                fetch_list=[avg_cost])
            accumulated=[
                x[0]+x[1][0]forxinzip(accumulated,avg_cost_np)
]
            count+=1
        return[x/countforxinaccumulated]
 
    deftrain_loop():
        step=0
        feed_var_list_loop=[
            main_program.global_block().var(var_name)forvar_nameinfeed_order
]
        feeder=fluid.DataFeeder(feed_list=feed_var_list_loop,place=place)
        exe.run(star_program)
        forpass_idinrange(PASS_NUM):
            fordataintrain_reader():
                avg_cost_np=exe.run(
                    main_program,feed=feeder.feed(data),fetch_list=[avg_cost])
                ifstep%10==0:
                    outs=train_test(test_program,test_reader)
                    print("Step %d: Average Cost %f"%(step,outs[0]))
                    整个训练过程要花费几个小时,如果平均损失低于5.8
                    我们就认为模型已经达到很好的效果可以停止训练了。
                    注意5.8是一个相对较高的值,为了获取更好的模型,可以将
                    这里的阈值设为3.5,但训练时间也会更长。
                    ifouts[0]<5.8:
                        ifparams_dirnameisnotNone:
                            fluid.io.save_inference_model(params_dirname,[
                                'firstw','secondw','thirdw','fourthw'
                            ], [predict_word],exe)
                        return
                step+=1
                ifmath.isnan(float(avg_cost_np[0])):
                    sys.exit("got NaN loss, training failed.")
        raiseAssertionError("Cost is too large {0:2.2}".format(avg_cost_np[0]))
    tain_loop()

  train_loop将会开始训练。期间打印训练过程的日志如下:

Step 0: Average Cost 7.337213
Step 10: Average Cost 6.136128
Step 20: Average Cost 5.766995
...

预测下一个词的配置

我们可以用我们训练过的模型,在得知之前的N-gram 后,预测下一个词。

definfer(use_cuda,params_dirname=None):
    place=fluid.CUDAPlace(0)ifuse_cudaelsefluid.CPUPlace()
 
    exe=fluid.Executor(place)
 
    inference_scope=fluid.core.Scope()
    withfluid.scope_guard(inference_scope):
        使用fluid.io.load_inference_model获取inference program
        # feed变量的名称feed_target_names和从scopefetch的对象fetch_targets
[inferencer,feed_target_names,
         fetch_targets]=fluid.io.load_inference_model(params_dirname,exe)
 
        设置输入,用四个LoDTensor来表示4个词语。这里每个词都是一个id
        用来查询embedding表获取对应的词向量,因此其形状大小是[1]
        # recursive_sequence_lengths设置的是基于长度的LoD,因此都应该设为[[1]]
        注意recursive_sequence_lengths是列表的列表
        data1=[[211]]  # 'among'
        data2=[[6]]  # 'a'
        data3=[[96]]  # 'group'
        data4=[[4]]  # 'of'
        lod=[[1]]
 
        first_word=fluid.create_lod_tensor(data1,lod,place)
        second_word=fluid.create_lod_tensor(data2,lod,place)
        third_word=fluid.create_lod_tensor(data3,lod,place)
        fourth_word=fluid.create_lod_tensor(data4,lod,place)
 
        assertfeed_target_names[0]=='firstw'
        assertfeed_target_names[1]=='secondw'
        assertfeed_target_names[2]=='thirdw'
        assertfeed_target_names[3]=='fourthw'
 
        构造feed词典 {feed_target_name: feed_target_data}
        预测结果包含在results之中
        results=exe.run(
            inferencer,
            feed={
                feed_target_names[0]:first_word,
                feed_target_names[1]:second_word,
                feed_target_names[2]:third_word,
                feed_target_names[3]:fourth_word
},
            fetch_list=fetch_targets,
            return_numpy=False)
        print(numpy.array(results[0]))
        most_possible_word_index=numpy.argmax(results[0])
        print(most_possible_word_index)
        print([
            keyforkey,valueinsix.iteritems(word_dict)
            ifvalue==most_possible_word_index
][0])

由于词向量矩阵本身比较稀疏,训练的过程如果要达到一定的精度耗时会比较长。为了能简单看到效果,教程只设置了经过很少的训练就结束并得到如下的预测。我们的模型预测 among a group of 的下一个词是the。这比较符合文法规律。如果我们训练时间更长,比如几个小时,那么我们会得到的下一个预测是 workers。预测输出的格式如下所示:

[[0.03768077 0.03463154 0.00018074 ... 0.00022283 0.00029888 0.02967956]]0the

其中第一行表示预测词在词典上的概率分布,第二行表示概率最大的词对应的id,第三行表示概率最大的词。

整个程序的入口很简单:

defmain(use_cuda,is_sparse):
    ifuse_cudaandnotfluid.core.is_compiled_with_cuda():
        return


    params_dirname="word2vec.inference.model" 
    train(
        if_use_cuda=use_cuda,
        params_dirname=params_dirname,
        is_sparse=is_sparse)
infer(use_cuda=use_cuda,params_dirname=params_dirname)
main(use_cuda=use_cuda,is_sparse=True)

总结

在本教程中,我们最开始先介绍了词向量、语言模型和词向量的关系、以及如何通过训练神经网络模型获得词向量。在信息检索中,我们可以根据向量间的余弦夹角,来判断query和文档关键词这二者间的相关性。在句法分析和语义分析中,训练好的词向量可以用来初始化模型,以得到更好的效果。在文档分类中,有了词向量之后,可以用聚类的方法将文档中同义词进行分组,也可以用N-gram 来预测下一个词。希望大家在阅读完本教程能够自行运用词向量进行相关领域的研究。

参考文献

[1]Bengio Y, Ducharme R, Vincent P, et al. A neural probabilistic language model[J]. journal of machine learning research, 2003, 3(Feb): 1137-1155.
[2]Mikolov T, Kombrink S, Deoras A, et al. Rnnlm-recurrent neural network language modeling toolkit[C]//Proc. of the 2011 ASRU Workshop. 2011: 196-201.
[3]Mikolov T, Chen K, Corrado G, et al. Efficient estimation of word representations in vector space[J]. arXiv preprint arXiv:1301.3781, 2013.
[4]Maaten L, Hinton G. Visualizing data using t-SNE[J]. Journal of Machine Learning Research, 2008, 9(Nov): 2579-2605.

[译] 使用 Node.js 提供百万的活跃 WebSocket 连接 - 掘金

$
0
0

仅使用消费级笔记本和一些 Wifi 资源便可提供大量的 WebSocket 服务

通过最新发布的 TypeScript web 服务工程 uWebSockets.js,我们看到它带来的不仅有提升的性能,还有提升的内存利用率。对 Node.js 使用者尤其如此,所以为了演示我想在实际使用环境中开展大规模的测试。

我们计划使用我那购买了 6 年的笔记本电脑,它具有 8GB 运行内存和 72Mbit 速率的 Wifi 网络适配器(这是网络链接速度)的笔记本电脑。它还有一个 1Gbit 速率的以太网适配器,我们可以稍后使用。所有配置都是消费级的,在 2013 年购买后没有任何硬件升级。这个笔记本将运行安装了 uWebSockets.js v15.1.0 的 Node.js。

服务器硬件

我们首先需要做一些 Linux 系统的配置工作 —— 主要是需要通过修改文件 /etc/security/limits.conf(在你的系统上文件路径可能不同,我这里用的是 Ubuntu 18.04 版本)来提升最大打开文件数量的限制。添加如下几行:

* soft nofile 1024000
* hard nofile 1024000复制代码

然后我们需要设置一些其他变量(同样的,你的路径可能不同):

sudo sysctl net.ipv4.tcp_tw_reuse=1
sudo sysctl fs.file-max=1024000复制代码

然后你需要需要配置某一网段内的大约 50 个 IP 地址。对于我的 Wifi 适配器,我添加了这行配置:

foriin{135..185};dosudo ip addr add 192.168.0.$i/24 dev wlp3s0;done复制代码

理论上,每个 IP 地址有 65k 个连接限制,但是实际上限值经常大约在 20k 左右,所以我们使用多个地址且使每个地址支撑 20k 个连接数(50 * 20 千 = 1 百万)。

然后我使用命令 sudo -i将 web 服务以 root 身份运行,这之后执行 ulimit -n 1024000命令,接着对 node examples/WebSocket.js(在 uWebSockets.js 文件夹中)也这么做。

真得就是这样的。客户端侧做了类似的配置,但是显然不需要设置多个 IP 地址。客户端电脑运行一个由 uSockets编写的单线程 C 客户端。这个测试的源代码都是开源的,同时客户端的代码是位于 uWebSockets/benchmarks 文件夹的『scale_test.c』。你可能需要为你自己的运行做一些小改动。

WebSocket 连接数量需要花几分钟才能达到 100 万个,如果我们想做的改进的话可以增加每批次的连接数和使用多个线程的客户端(诸如此类),但是这与我们对服务端感兴趣的点无关。服务端运行在单个线程上并且在连接阶段或之后 CPU 占用率都很低。

首先,让我们讨论一下 5k 个关闭的连接。uWebSockets.js 被配置为丢弃和杀死所有闲置已超过 60s 的 WebSocket 连接。『idleTimeout』就被用到了,这意味着我们需要在每 60s 就要与每 100 万个 WebSocket 连接主动发送和接收一条 WebSocket 消息。

你可以在这上面这张网络图中看到与 ping 消息相关的流量峰值。每秒最少有 16.7k 条 WebSocket 消息需要到达服务器 —— 都变少了之后我们开始关闭连接。

显然我们通过 Wifi 网络没有很好地满足这个标准。我们是丢失了一些连接,但在一个没有花哨配置的 WiFi 网络环境下仍存活 995k 个 WebSocket 连接却是很酷的事情!

服务端的 CPU 使用率保持在 0–2% 范围,用户控空间内存使用大约为 500MB 而整体系统范围的内存使用大约为 4.7GB。CPU 使用率或者内存使用一直都没有出现服务端激增走势,它始终处于完全稳定状态。

好吧!那么让我们拿出大杀器吧 —— Ethernet。我们将服务器和客户端连接到 1Gbit 消费级路由器并重新运行测试:

结果是服务运行状况稳定,而且没有连接丢失,WiFi 网络稳定性不足但是 Ethernet 却表现很好。为了保证每项都是稳定的,我让客户端和服务器持续运行了一个小时,这样没有一个连接丢失,然后有约 1.2 亿条 WebSocket 消息(16.7k * 60 * 60 * 2):

每项都是稳定良好运行。事实上,我在运行服务的笔记本上写着本文,并且被关闭的 socket 连接数量始终为 0,同时系统也是响应及时的。甚至我开启一个简单的游戏的情况下服务还能让连接继续。

此时我们已经实现了一个非常酷的概念验证场景。有一部分归因于稳定的 Ethernet 连接,但当然很大程度上也依赖服务端软件。任何其他的 Node.js 软件栈都无法实现这一壮举 —— 它们都不具备像这样足以在笔记本上维持这么多 WebSocket 连接的轻量级和高性能特点。你可以在系统变得无响应时停止 swap 分区交换,并且下面看到的这样来停止获取 ping 结果:

如果我们使用另一个服务软件栈可能运行不太好,这里『websockets/ws』 发生彻底崩溃并触发了重试

使用 uWebSockets.js,我们可以在这台笔记本上运行几十万个 WebSocket 连接,但是超过 100 万的常规连接则需要重新编译具备不同限制的 Linux 内核,这也是我们把它作为边界值的原因。

这里我们不打算去研究底层的嵌入式 C 开发,并且我认为这是明智的选择。只需启动一个新应用实例,一台新笔记本,通过这种方式继续扩展你的问题。

如果你对这个软件栈感兴趣,有 I/O 扩展性问题,或者想要避免陷入许多常见陷阱,一定要联系我们,我们可以通过公司对公司的形式来研讨问题。

感谢你的阅读!

如果发现译文存在错误或其他需要改进的地方,欢迎到 掘金翻译计划对译文进行修改并 PR,也可获得相应奖励积分。文章开头的 本文永久链接即为本文在 GitHub 上的 MarkDown 链接。


这些知识决定了程序员的上限

$
0
0

讲述决定程序员上限的一些知识技能点,包括如何学习、如何阅读源码、计算机科学基础知识体系等。

什么是程序员?

  • 码农、程序猿、程序媛
  • 使用 程序实现价值
  • 程序=数据+算法
  • 软件=程序+软件工程
  • 程序员=工程师?

程序员金字塔

程序员知识结构

  • 面试造火箭,工作打蚊子
  • 会什么是你的下限,能够会什么是你的上限
  • 越底层的东西越决定上限

学习欲望

杜绝 1年工作经验重复 N

  • 如果自己遇到这种问题会怎么解决,与资料中的解决方案相比优劣如何?
  • 别人为什么会想到这种解决方案?
  • 自己是由于经验欠缺还是技能点欠缺才导致没有想到好的解决方案?
  • 解决这类问题的根本思路是什么样的?

学习能力

不是懂得多,而是学得快

  • 知其然更要知其所以然:技术以深度优先
  • 类比现实:对现实世界的模拟
  • 更好地接受信息:建立自己的知识体系;阅读并记笔记,纳入知识体系
  • 深度思考:阅读书籍
  • 动手实践、频繁练习:项目驱动型学习;主动思考
  • 自我总结:完善知识体系;笔记、博客、分享
  • 持续学习:逃离舒适区;学到老,活到老

如何学习新技术

如何阅读源码

  1. 阅读该技术的架构文档,了解其总体架构和组成
  2. 根据总体架构,将源码文件以模块或者上下层级进行分类。
  3. 从未阅读过的模块中选择最独立(依赖性最小)的模块代码读起。
  4. 阅读此模块的功能介绍文档。
  5. 阅读此模块的源代码: 运行程序,断点调试
  6. 一边阅读一边整理调用关系图。
  7. 转到第三步。

参考 官方文档或者经典书籍

计算机思维

  • 冯.诺依曼体系:程序存储,顺序执行。
  • 二进制存储:用比特解决问题
  • 位运算:位运算的高效
  • 逻辑分支:条件判断、循环、迭代、递归

个人规划

  • 长期规划:职业规划;高瞻远瞩
  • 短期规划:具体技能、晋升、学习方面的规划;优先级排序

基础学科

  • 物理:电路原理;量子计算机
  • 数学:工程优化;线性代数;微积分
  • 英语!!:阅读英文文献;计算机术语

计算机组成原理

计算机的硬件组成和运行原理

  • 冯诺依曼体系摩尔定律阿曼达定律
  • 数据的机器表示:原码、补码、反码、浮点数/定点数
  • 指令系统:复杂指令集、简单指令集
  • 存储器:分类、缓存
  • CPU: 流水线、伪共享、缓存
  • IO设备:IO总线、DMA、中断

计算机操作系统

屏蔽计算机硬件的中间层

  • 作业调度: 调度策略、优先级
  • 进程管理:进程和线程、进程间通信
  • 存储管理:内存、虚拟内存、文件系统、页、页缓存
  • IO管理:IO设备读写操作
  • Linux操作系统

计算机网络

单个计算机之间的互连

  • TCP/IP协议栈:四层/七层
  • TCP连接状态
  • TCP与UDP的区别
  • HTTP协议、RESTful规范
  • 网络安全
  • 下一代互联网:IPv6、物联网、5G

编译原理

将代码转换成机器可理解的二进制,有助于实现DSL

  • 词法分析、语法分析
  • 类型检查
  • 运行时环境、中间代码
  • 代码生成、代码优化

数据结构和算法

程序=数据+算法

  • 基本数据结构:数组、链表、栈、队列、哈希表
  • 最大堆、最小堆:TopN问题
  • :平衡二叉树、B树、B+树、红黑树
  • 跳跃表: 简单可实现
  • 经典排序算法:快速排序、归并排序、插入排序、冒泡排序
  • 经典查找算法:顺序查找、二分查找
  • 高级算法:贪心、分治、回溯、动态规划
  • 大数据处理:Bitmap、Bloomfilter、Hyperloglog、MapReduce、MPP

设计模式

软件可复用、可扩展、可维护。善用而不滥用。

  • 面向对象SOLID设计原则:单一职责、开闭原则、里氏代换、接口隔离、依赖倒转
  • 常用设计模式:单例模式、工厂模式、代理模式、适配器模式、观察者模式
  • 常用框架中的设计模式:Spring
Viewing all 15891 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>