如何用go创建一个webservice

Python010

如何用go创建一个webservice,第1张

http包建立Web服务器

package main

import (

"fmt"

"net/http"

"strings"

"log"

)

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

r.ParseForm() //解析参数,默认是不会解析的

fmt.Println(r.Form) //这些信息是输出到服务器端的打印信息

fmt.Println("path", r.URL.Path)

fmt.Println("scheme", r.URL.Scheme)

fmt.Println(r.Form["url_long"])

for k, v := range r.Form {

fmt.Println("key:", k)

fmt.Println("val:", strings.Join(v, ""))

}

fmt.Fprintf(w, "Hello astaxie!") //这个写入到w的是输出到客户端的

}

func main() {

http.HandleFunc("/", sayhelloName) //设置访问的路由

err := http.ListenAndServe(":9090", nil) //设置监听的端口

if err != nil {

log.Fatal("ListenAndServe: ", err)

}

}

上面这个代码,我们build之后,然后执行web.exe,这个时候其实已经在9090端口监听http链接请求了。

在浏览器输入

可以看到浏览器页面输出了Hello astaxie!

可以换一个地址试试:

看看浏览器输出的是什么,服务器输出的是什么?

在服务器端输出的信息如下:

图3.8 用户访问Web之后服务器端打印的信息

我们看到上面的代码,要编写一个Web服务器很简单,只要调用http包的两个函数就可以了。

如果你以前是PHP程序员,那你也许就会问,我们的nginx、apache服务器不需要吗?go就是不需要这些,因为他直接就监听tcp端口了,做了nginx做的事情,然后sayhelloName这个其实就是我们写的逻辑函数了,跟php里面的控制层(controller)函数类似。

如果你以前是Python程序员,那么你一定听说过tornado,这个代码和他是不是很像,对,没错,Go就是拥有类似python这样动态语言的特性,写Web应用很方便。

如果你以前是Ruby程序员,会发现和ROR的/script/server启动有点类似。

Prometheus有4大指标类型(Metrics Type),分别是Counter(计数器)、Gauge(仪表盘)、Histogram(直方图)和Summary(摘要)。

这是在Prometheus客户端(目前主要有Go、Java、Python、Ruby等语言版本)中提供的4种核心指标类型,但是Prometheus的服务端并不区分指标类型,而是简单地把这些指标统一视为无类型的时间序列。

注意:

<font color=red>上面这句话应该这么理解,四个指标类型,实际上就是客户端采集数据的四个维度,采集这四个维度的指标数据,但是最终汇总到服务端那里,则是对这四个维度无感的,只是简单的作为时间序列存储起来。</font>

 计数器表示一种单调递增的指标,除非发生重置的情况下下只增不减,其样本值应该是不断增大的。例如,可以使用Counter类型的指标来表示服务的请求数、已完成的任务数、错误发生的次数等。

 但是,计数器计算的总数对用户来说大多没有什么用,大家千万不要将计数器类型应用于样本数据非单调递增的指标上,比如当前运行的进程数量、当前登录的用户数量等应该使用仪表盘类型。

为了能够更直观地表示样本数据的变化情况,往往需要计算样本的增长速率,这时候通常使用PromQL的rate、topk、increase和irate等函数,如下所示:

如上所示,速率的输出rate(v range-vector)也应该用仪表盘来承接结果。

在上面的案例中,如果有一个标签是Device,那么在统计每台机器每秒接受的HTTP请求数时,可以用如下的例子进行操作。

补充

 这背后与rate()的实现方式有关,rate()在设计上假定对应的指标是一个计数器,也就是只有<font color=red>incr(增加)和reset(归零)</font>两种行为。而执行了sum()或其他聚合操作之后,得到的就不再是一个计数器了。举个例子,比如sum()的计算对象中有一个归零了,那整体的和会下降,而不是归零,这会影响rate()中判断reset(归零)的逻辑,从而导致错误的结果。

 increase(v range-vector)函数传递的参数是一个区间向量,increase函数获取区间向量中的第一个和最后一个样本并返回其增长量。下面的例子可以查询Counter类型指标的增长速率,可以获取http_requests_total在最近5分钟内的平均样本,其中300代表300秒。

 rate和increase函数计算的增长速率容易陷入<font color=red>长尾效应中</font>。比如在 某一个由于访问量或者其他问题导致CPU占用100%的情况中,通过计算在时间窗口内的平均增长速率是无法反映出该问题的

 为什么监控和性能测试中,我们更关注p95/p99位?就是因为长尾效应。由于个别请求的响应时间需要1秒或者更久,<font color=red>传统的响应时间的平均值就体现不出响应时间中的尖刺了</font>,去尖刺也是数据采集中一个很重要的工序,这就是所谓的长尾效应。p95/p99就是长尾效应的分割线,如表示99%的请求在XXX范围内,或者是1%的请求在XXX范围之外。99%是一个范围,意思是99%的请求在某一延迟内,剩下的1%就在延迟之外了。只是正推与逆推而已,是一种概念的两种不同描述。

 irate(v range-vector)是PromQL针对长尾效应专门提供的灵敏度更高的函数。irate同样用于计算区间向量的增长速率,但是其反映出的是瞬时增长速率。irate函数是通过区间向量中最后两个样本数据来计算区间向量的增长速率的。这种方式可以避免在时间窗口范围内的“长尾问题”,并且体现出更好的灵敏度。通过irate函数绘制的图标能够更好地反映样本数据的瞬时变化状态。irate的调用命令如下所示。

 irate函数相比于rate函数提供了更高的灵敏度,不过分析长期趋势时或者在告警规则中,irate的这种灵敏度反而容易造成干扰。因此,在长期趋势分析或者告警中更推荐使用rate函数。

 仪表盘类型代表一种<font color=red>样本数据可以任意变化的指标,即可增可减</font>。它可以理解为状态的快照,Gauge通常用于表示温度或者内存使用率这种指标数据,也可以表示能随时增加或减少的“总数”,例如当前并发请求的数量node_memory_MemFree(主机当前空闲的内容大小)、node_memory_MemAvailable(可用内存大小)等。在使用Gauge时,用户往往希望使用它们<font color=red>求和、取平均值、最小值、最大值</font>等。

 以Prometheus经典的Node Exporter的指标node_filesystem_size_bytes为例,它可以报告从node_filesystem_size_bytes采集来的文件系统大小,包含device、fstype和mountpoint等标签。如果想要对每一台机器上的总文件系统大小求和(sum),可以使用如下PromQL语句。

 without可以让sum指令根据相同的标签进行求和,但是忽略without涵盖的标签。如果在实际工作中需要忽略更多标签,可以根据实际情况在without里传递更多指标。

补充

node_filesystem_size_bytes指标查询

device, fstype, mountpoint都是他的标签。

sum without(device, fstype, mountpoint)(node_filesystem_size_bytes)查询

 如果要根据Node Exporter的指标node_filesystem_size_bytes计算每台机器上最大的文件安装系统大小,只需要将上述案例中的sum函数改为max函数,如下所示。

 除了求和、求最大值等,利用Gauge的函数求最小值和平均值等原理是类似的。除了基本的操作外,Gauge经常结合PromQL的predict_linear和delta函数使用。

 predict_linear(v range-vector,t scalar)函数可以预测时间序列v在t秒后的值,就是使用线性回归的方式,预测样本数据的Gauge变化趋势。例如,基于2小时的样本数据,预测未来24小时内磁盘是否会满,如下所示:

PromQL还有一个内置函数delta(),它可以获取样本在一段时间内的变化情况,也通常作用于Gauge。例如,计算磁盘空间在2小时内的差异,如下所示。

Histogram是一个对数据分布情况的图形表示,由一系列高度不等的长条图(bar)或线段表示,用于展示单个测度得知的分布。

[图片上传失败...(image-3e55f2-1622153155462)]

上边界、样本值总和、样本总数

例子

这三个查询一起看

所有样本值的总和,命名为<basename>_sum。

prometheus_http_request_duration_seconds_sum{handler="/targets",instance="192.168.16.134:9090",job="prometheus"}0.405075955 表示12 次http请求的总响应时间是0.405075955

命名为<basename>_count,其值和<basename>_bucket{le="+Inf"}相同(所有)。

prometheus_http_request_duration_seconds_count{handler="/targets",instance="192.168.16.134:9090",job="prometheus"}12 表示总共发生了12次请求

 sum函数和count函数相除,可以得到一些平均值,比如Prometheus一天内的平均压缩时间,可由查询结果除以instance标签数量得到,如下所示。

 除了Prometheus内置的压缩时间,prometheus_local_storage_series_chunks_persisted表示Prometheus中每个时序需要存储的chunk数量,也可以用于计算待持久化的数据的分位数。

 Histogram可以用于观察样本数据的分布情况。Histogram的分位数计算需要通过histogram_quantile(φfloat,b instant-vector)函数进行计算,但是histogram_quantile计算所得并非精确值。其中,φ(0<φ<1)表示需要计算的分位数(这个值主要是通过prometheus_http_request_duration_seconds_bucket和prometheus_http_request_duration_seconds_sum两个指标得到的,是一个近似值)。

例子如下。

 与Histogram类型类似,摘要用于表示一段时间内的数据采样的结果(通常是请求持续时间或响应大小等),但它直接存储了分位数(通过客户端计算,然后展示出来),而非通过区间来计算(Histogram的分位数需要通过histogram_quantile(φfloat,b instant-vector)函数计算得到)。因此,对于分位数的计算,Summary在通过PromQL进行查询时有更好的性能表现,而Histogram则会消耗更多的资源。反之,对于客户端而言,Histogram消耗的资源更少。在选择这两种方式时,用户应该根据自己的实际场景选择。

Histogram是在服务端计算的,Summary是在客户端计算的。

 安装并启动Prometheus后,在访问 http://localhost:9090/metrics 时可以看到Prometheus自带的一些Summary信息,这些信息和Histogram一样在注释中(#HELP和#TYPE)也会显示,如下所示。

 在上述例子中,可以看到基于Go语言编写的Prometheus的gc总次数是1907,耗时0.193642882s,其中中位数(quantile=0.5)计算的耗时为4.8366e-05s,代表1907次中50%的次数是小于4.8366e-05s的。

Summary类型的样本也会提供3种指标,假设指标名称为<basename>。

Summary和Histogram的异同

Summary的强大之处就是可以利用除法去计算时间的平均值。如果要从Histogram和Summary中计算最近5分钟内的平均请求持续时间http_request_duration_seconds,可以用如下表达式进行。

count本质上是一个计数器,sum通常情况下也会像计数器那样工作。但是<font color=red>Summary和Histogram可能观察到负值,比如温度(-20℃),这种情况下会导致观察的总量下降,无法再使用rate函数</font>。

比如下面的例子就可以计算过去5分钟内每次响应中返回的平均字节数。

关于这个例子,我们需要注意几点。

·因为http_response_size_bytes_count和http_response_size_bytes_sum是计数器类型,所以必须在计算前先使用rate等函数。

·因为Prometheus的API会有很多handler,所以可以使用without过滤掉handler的返回值。

·PromQL要先执行rate()再执行sum(),不能先执行sum()再执行rate()。

·在统计学上,尤其是计算平均值时,要先进行sum等求和运算再做除法。对一个平均值再求平均是不正确的,如下所示。

count的例子

案例一:计算所有的实例CPU核心数。

count by (instance) ( count by (instance,cpu) (node_cpu_seconds_total{mode=

"system"}) )

案例二:计算单个实例192.168.1.1的CPU核心数。

count by (instance) ( count by (instance,cpu) (node_cpu_seconds_total{mode="system",

instance="192.168.1.1"})

Package org.apache.hadoop.hbase.thrift2 Description

Provides an HBase Thrift

service.

This package contains a Thrift interface definition file for an HBase RPC

service and a Java server implementation.

There are currently 2 thrift server implementations in HBase, the packages:

org.apache.hadoop.hbase.thrift: This may one day be marked as depreceated.

org.apache.hadoop.hbase.thrift2: i.e. this package. This is intended to closely match to the HTable interface and

to one day supercede the older thrift (the old thrift mimics an API HBase no longer has).

What is Thrift?

"Thrift is a software framework for scalable cross-language services

development. It combines a software stack with a code generation engine to

build services that work efficiently and seamlessly between C++, Java, Python,

PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk,

and OCaml. Originally developed at Facebook, Thrift was open sourced in April

2007 and entered the Apache Incubator in May, 2008".

From http://thrift.apache.org/

Description

The HBase API is defined in the

file hbase.thrift. A server-side implementation of the API is in

org.apache.hadoop.hbase.thrift2.ThriftHBaseServiceHandler with the

server boiler plate in org.apache.hadoop.hbase.thrift2.ThriftServer.

The generated interfaces, types, and RPC utility files are checked into SVN under the

org.apache.hadoop.hbase.thrift2.generated directory.

To stop, use:

./bin/hbase-daemon.sh stop thrift

These are the command line arguments the Thrift server understands in addition to start and stop:

-b, --bind

Address to bind the Thrift server to. Not supported by the Nonblocking and HsHa server [default: 0.0.0.0]

-p, --port

Port to bind to [default: 9090]

-f, --framed

Use framed transport (implied when using one of the non-blocking servers)

-c, --compact

Use the compact protocol [default: binary protocol]

-h, --help

Displays usage information for the Thrift server

-threadpool

Use the TThreadPoolServer. This is the default.

-hsha

Use the THsHaServer. This implies the framed transport.

-nonblocking

Use the TNonblockingServer. This implies the framed transport.

Details

HBase currently uses version 0.8.0 of Apache Thrift.

The files were generated by running the commands under the hbase checkout dir:

thrift -strict --gen java:hashcode ./src/main/resources/org/apache/hadoop/hbase/thrift2/hbase.thrift

# Move the generated files into place their expected location under hbase

mv gen-java/org/apache/hadoop/hbase/thrift2/generated/* src/main/java/org/apache/hadoop/hbase/thrift2/generated/

# Remove the gen-java file made by thrift

rm -rf gen-java

The 'thrift' binary is the Thrift compiler, and it is distributed separately from HBase

in a Thrift release. Additionally, specific language runtime libraries are a

part of a Thrift release. A version of the Java runtime is included in HBase via maven.