当前位置: 首页 > wzjs >正文

快速排名怎么做国内seo排名

快速排名怎么做,国内seo排名,网站文章怎么做才能被收录,做网站公司长沙1. Prometheus 简介 1.1 可观测性入门 可观测性 是指在软件系统当中通过度量、监控和分析系统当中各个组件的行为,以便于了解整个系统当前的运行状态。它可以帮助开发人员快速定位和解决系统出现的问题,被广泛运用于分布式系统当中,具体来说…

1. Prometheus 简介

1.1 可观测性入门

可观测性 是指在软件系统当中通过度量、监控和分析系统当中各个组件的行为,以便于了解整个系统当前的运行状态。它可以帮助开发人员快速定位和解决系统出现的问题,被广泛运用于分布式系统当中,具体来说分为三个部分:

  • 日志(Logging):记录系统的状态和行为
  • 度量(Metrics):量化系统的性能指标,比如内存使用量、CPU负载
  • 追踪(Tracing):追踪系统的请求与响应,帮助诊断问题

度量(Metrics):metrics 就是可聚合可度量的数据,比如各种响应时间,正在处理的请求数、CPU负载率、错误码统计频率都在这个范畴内

追踪(Tracing):也叫链路追踪数据,比如下图就是一个经典的 tracing 图像,由各种父子 span 构成,span的长度就表示执行时间长度,空隙代表的是父span执行的长度(因此如果有很多空隙,那么就需要考虑补充打点)

1.2 Prometheus 参考文档

💡 文档参考:

  1. 中文官方文档:https://prometheus.ac.cn/docs/prometheus/latest/getting_started/
  2. 服务端 Github 地址:https://github.com/prometheus/prometheus
  3. Go 客户端 Github 地址:https://github.com/prometheus/client_golang

1.3 Prometheus 基本架构

画板

如上图所示就是 Prometheus 运行的基本架构:

  • 服务器会主动轮询数据进行拉取(因此需要有配置文件交由服务器决定拉取策略(拉取时间间隔、客户端目标端口),客户端需要暴露端口供服务端采集数据)

2. Prometheus 安装

本次我们依旧通过使用 Docker 的方式来启动 Prometheus,在项目中编写如下docker-compose.yaml文件

version: "3"
services:prometheus:image:  prom/prometheus:v2.47.2# 挂载数据卷volumes:- ./prometheus.yaml:/etc/prometheus/prometheus.yml# 数据访问的端口ports:- 9090:9090 # 数据访问的端口

其中本地数据卷prometheus.yaml文件内容如下:

scrape_configs:- job_name: "webook"scrape_interval: 5sscrape_timeout: 3sstatic_configs:- targets: ["host.docker.internal:8081"]

然后在命令行中输入docker compose up即可启动

看到如上图所示内容证明 Prometheus 启动成功!访问"http://localhost:9090"即可访问到 Prometheus 提供的图形界面:

3. Prometheus API 入门

3.1 指标类型

Prometheus 支持的指标非常多种多样,所以在实践过程中就要选择最适合的指标

  • Counter:计数器,统计次数,比如统计某件事具体出现了多少次
  • Gauge:度量,可以增加也可以较少,比如说当前正在处理的请求数
    1. 统计当前正在执行的 HTTP 请求数量
    2. 统计当前实例开启的数据库事务数量
  • Histogram:柱状图,对观察对象进行采样,然后将结果分到不同的桶内
    1. 统计每个错误码出现的次数
  • Summary:采样点按照百分位进行统计,比如99线、999线
    1. 统计接口的响应时间,平均值、中位数

3.2 Counter 和 Gauge

使用 Prometheus 的 API 相当简单,只需要使用go get github.com/prometheus/client_golang/prometheus@latest引入客户端依赖即可

func Counter() {counter := prometheus.NewCounter(prometheus.CounterOpts{Namespace: "my_namespace",Subsystem: "my_subsystem",Name:      "my_counter",})prometheus.MustRegister(counter)counter.Inc()counter.Add(10.2)
}func Gauge() {gauge := prometheus.NewGauge(prometheus.GaugeOpts{Namespace: "my_namespace",Subsystem: "my_subsystem",Name:      "my_gauge",})prometheus.MustRegister(gauge)gauge.Inc()gauge.Dec()gauge.Add(10.2)gauge.Sub(5.6)
}

其中需要关注的实际上是一些通用配置:

  • namespace:命名空间(实际项目中可能代表部门名称或者小组名称)
  • subsystem:子系统(实际项目中可能代表部门名称下的小组名称或者小组名称下的模块名称)
  • name:名字

总之上述参数的配置不同公司有不同的规范,只需要三者能够定位到唯一的具体业务即可!

3.3 Histogram

Histogram 相关的 API 也是大同小异,直接上代码:

func Histogram() {histogram := prometheus.NewHistogram(prometheus.HistogramOpts{Namespace: "my_namespace",Subsystem: "my_subsystem",Name:      "my_histogram",Buckets:   []float64{10, 50, 100, 1000, 5000, 10000},})prometheus.MustRegister(histogram)histogram.Observe(10.2)
}

这里需要特别注意的是直方图有一个特定的配置项:buckets(可以理解为桶),此处划分了几个区间:[0, 10],[10,50],[50, 100],[100, 1000],[1000, 5000],[5000, 10000],并且使用 observe 方法塞入了一个观察值10.2,会自动分配到[10, 50]区间

3.4 Summary

Summary 相关的 API 也是大同小异,直接上代码:

func Summary() {summary := prometheus.NewSummary(prometheus.SummaryOpts{Namespace: "my_namespace",Subsystem: "my_subsystem",Name:      "my_summary",Objectives: map[float64]float64{0.5:   0.01,0.75:  0.01,0.90:  0.005,0.99:  0.001,0.999: 0.0001,},})prometheus.MustRegister(summary)summary.Observe(12.3)
}

这里需要特别注意的是 summary 也有一个特定的配置项:Objectives,这是一个map类型,以第一个举例就是 50% 的请求的响应时间,其中误差范围为1%,以此类推

3.5 Vector

实际上我们采集的数据有可能是根据一些业务特征划分为,比如分开统计状态码为2xx、3xx、4xx、5xx,在这种情况下我们就可以借助 Prometheus 提供的 vector:

func VectorSummary() {vec := prometheus.NewSummaryVec(prometheus.SummaryOpts{Namespace: "my_namespace",Subsystem: "my_subsystem",Name:      "my_summary_vec",ConstLabels: map[string]string{"server":  "localhost:8080","env":     "test","appname": "test_app",},}, []string{"pattern", "method", "status"})prometheus.MustRegister(vec)vec.WithLabelValues("/user/:id", "POST", "200").Observe(128)
}

其中 Vector 指标有两类 labels:

  • 固定labels:这是所有业务都通用的
  • 动态label:根据业务进行取值,比如此处的pattern,method,status

4. Prometheus 实战

4.1 统计接口响应时间

上面我们已经提到过此类场景适合使用 summary 指标进行统计,并且这是一个通用功能(对每个接口都适用)因此此处完全可以使用 gin 的 middleware 实现:

summary.go

package mainimport ("github.com/gin-gonic/gin""github.com/prometheus/client_golang/prometheus""strconv""time"
)type SummaryBuilder struct {namespace stringsubsystem stringname      stringhelp      string
}func NewSummaryBuilder(namespace string, subsystem string, name string, help string) *SummaryBuilder {return &SummaryBuilder{namespace: namespace,subsystem: subsystem,name:      name,help:      help,}
}func (builder *SummaryBuilder) Build() gin.HandlerFunc {summaryVec := prometheus.NewSummaryVec(prometheus.SummaryOpts{Namespace:   builder.namespace,Subsystem:   builder.subsystem,Name:        builder.name,Help:        builder.help,ConstLabels: map[string]string{},Objectives: map[float64]float64{0.5:   0.01,0.75:  0.01,0.90:  0.005,0.99:  0.001,0.999: 0.0001,},}, []string{"pattern", "method", "status"})prometheus.MustRegister(summaryVec)return func(ctx *gin.Context) {now := time.Now()defer func() {duration := time.Since(now)var pattern = ctx.FullPath()var method = ctx.Request.Methodvar status = ctx.Writer.Status()summaryVec.WithLabelValues(pattern, method, strconv.Itoa(status)).Observe(float64(duration.Milliseconds()))}()ctx.Next()}
}

main.go

func initPrometheus() {go func() {http.Handle("/metrics", promhttp.Handler())http.ListenAndServe(":8081", nil)}()
}func main() {initPrometheus()server := gin.Default()// 接入中间件server.Use(NewSummaryBuilder("my_namespace","my_subsystem","test","统计响应时间").Build())server.GET("/test", func(ctx *gin.Context) {num := rand.Intn(5)time.Sleep(time.Duration(num) * time.Second)})server.Run(":8080")
}

然后我们使用 wrk 接口测试工具模拟发送100个请求,观察现象:

以下是 Prometheus 统计结果:

4.2 统计当前活跃的请求数量

上面我们已经提到过此类场景适合使用 gauge 指标进行统计,并且这是一个通用功能(对每个接口都适用)因此此处也可以使用 gin 的 middleware 实现:

gauge.go

package mainimport ("github.com/gin-gonic/gin""github.com/prometheus/client_golang/prometheus"
)type GaugeBuilder struct {namespace stringsubsystem stringname      stringhelp      string
}func NewGaugeBuilder(namespace string, subsystem string, name string, help string) *GaugeBuilder {return &GaugeBuilder{namespace: namespace,subsystem: subsystem,name:      name,help:      help,}
}func (builder *GaugeBuilder) Build() gin.HandlerFunc {gauge := prometheus.NewGauge(prometheus.GaugeOpts{Namespace: builder.namespace,Subsystem: builder.subsystem,Name:      builder.name + "_active_req",Help:      builder.help,})prometheus.MustRegister(gauge)return func(ctx *gin.Context) {gauge.Inc()defer gauge.Dec()ctx.Next()}
}

main.go

func initPrometheus() {go func() {http.Handle("/metrics", promhttp.Handler())http.ListenAndServe(":8081", nil)}()
}func main() {initPrometheus()server := gin.Default()// 接入中间件server.Use(NewSummaryBuilder("my_namespace","my_subsystem","test","统计响应时间").Build())server.Use(NewGaugeBuilder("my_namespace","my_subsystem","http_req","统计当前活跃的请求数").Build())server.GET("/test", func(ctx *gin.Context) {num := rand.Intn(5)time.Sleep(time.Duration(num) * time.Second)})server.Run(":8080")
}

然后我们使用 wrk 接口测试工具模拟发送100个请求,观察现象:

以下是 Prometheus 统计结果:

4.3 统计 GORM 执行时间

事实上在整个业务系统当中,数据库操作比 HTTP 更加高频,因此我们特别需要关注 SQL 执行的时间效率,那么我们如何获取到 GORM 当中 SQL 执行的时长呢?事实上 GORM 提供了一些钩子函数(如果感兴趣可以在 GORM 官网上寻找相关资料),此处我们使用一个更加底层的API:Callback 机制

callback.go

package mainimport ("github.com/prometheus/client_golang/prometheus""gorm.io/gorm""time"
)type Callback struct {summaryVec *prometheus.SummaryVec
}func NewCallback(namespace string, subsystem string, name string, help string) *Callback {summaryVec := prometheus.NewSummaryVec(prometheus.SummaryOpts{Namespace:  namespace,Subsystem:  subsystem,Name:       name,Help:       help,Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.99: 0.001},},[]string{"type"},)prometheus.MustRegister(summaryVec)return &Callback{summaryVec: summaryVec,}
}func (c *Callback) Before(tx *gorm.DB) {now := time.Now()tx.Set("startTime", now)
}func (c *Callback) After(tx *gorm.DB, typ string) {val, _ := tx.Get("startTime")startTime, _ := val.(time.Time)duration := time.Since(startTime)c.summaryVec.WithLabelValues(typ).Observe(float64(duration.Milliseconds()))
}

main.go

func initPrometheus() {go func() {http.Handle("/metrics", promhttp.Handler())http.ListenAndServe(":8081", nil)}()
}func initDB() *gorm.DB {db, err := gorm.Open(mysql.Open("root:QWEzxc123456@tcp(localhost:3306)/webook"))if err != nil {panic(err)}var callBack = NewCallback("my_namespace","my_subsystem","gorm_test","统计GORM执行时间")err = db.Callback().Query().Before("*").Register("prometheus_query_before", func(tx *gorm.DB) {callBack.Before(tx)})err = db.Callback().Query().After("*").Register("prometheus_query_after", func(tx *gorm.DB) {callBack.After("query", tx)})return db
}// User 对应数据库中的user表
type User struct {Id       int64  `gorm:"primaryKey,autoIncrement"`Email    string `gorm:"unique"`Phone    string `gorm:"unique"`Password stringNickname string `gorm:"type=varchar(128)"`// YYYY-MM-DDBirthday int64Aboutme  string `gorm:"type=varchar(4096)"`// 时区,UTC 0 的毫秒数// 创建时间Ctime int64// 更新时间Utime int64// json 存储//Addr stringWeChatOpenID   string `gorm:"unique"`WeChatUniqueID string `gorm:"unique"`
}func VectorSummary() {vec := prometheus.NewSummaryVec(prometheus.SummaryOpts{Namespace: "my_namespace",Subsystem: "my_subsystem",Name:      "my_summary_vec",ConstLabels: map[string]string{"server":  "localhost:8080","env":     "test","appname": "test_app",},}, []string{"pattern", "method", "status"})prometheus.MustRegister(vec)vec.WithLabelValues("/user/:id", "POST", "200").Observe(128)
}func main() {initPrometheus()db := initDB()server := gin.Default()// 接入中间件server.Use(NewSummaryBuilder("my_namespace","my_subsystem","test","统计响应时间").Build())server.Use(NewGaugeBuilder("my_namespace","my_subsystem","http_req","统计当前活跃的请求数").Build())server.GET("/test", func(ctx *gin.Context) {num := rand.Intn(5)time.Sleep(time.Duration(num) * time.Second)})server.GET("/gorm", func(ctx *gin.Context) {// 执行数据库操作var users []Usererr := db.WithContext(ctx).Find(&users).Errorif err != nil {ctx.JSON(http.StatusOK, gin.H{"code": 500,"msg":  "系统错误",})return}ctx.JSON(http.StatusOK, gin.H{"code": 200,"data": users,"msg":  "OK",})})server.Run(":8080")
}

然后我们使用 wrk 接口测试工具模拟发送100个请求,观察现象:

以下是 Prometheus 统计结果:

4.4 统计 Redis 执行时间

同理我们有需求获取 redis 缓存的执行时间,这里我们可以借助 redis 客户端提供的钩子函数

redis_hook.go

package mainimport ("context""github.com/prometheus/client_golang/prometheus""github.com/redis/go-redis/v9""net""strconv""time"
)type PrometheusHook struct {summaryVec *prometheus.SummaryVec
}func NewPrometheusHook(namespace string, subsystem string, name string, help string) *PrometheusHook {summaryVec := prometheus.NewSummaryVec(prometheus.SummaryOpts{Namespace: namespace,Subsystem: subsystem,Name:      name,Help:      help,Objectives: map[float64]float64{0.5:   0.01,0.75:  0.01,0.9:   0.01,0.99:  0.001,0.999: 0.0001,},}, []string{"cmd", "keyExists"},)prometheus.MustRegister(summaryVec)return &PrometheusHook{summaryVec: summaryVec,}
}func (p *PrometheusHook) DialHook(next redis.DialHook) redis.DialHook {return func(ctx context.Context, network, addr string) (net.Conn, error) {return next(ctx, network, addr)}
}func (p *PrometheusHook) ProcessHook(next redis.ProcessHook) redis.ProcessHook {return func(ctx context.Context, cmd redis.Cmder) error {startTime := time.Now()var err errordefer func() {duration := time.Since(startTime)keyExists := err == redis.Nilp.summaryVec.WithLabelValues(cmd.Name(), strconv.FormatBool(keyExists)).Observe(float64(duration.Milliseconds()))}()err = next(ctx, cmd)return err}
}func (p *PrometheusHook) ProcessPipelineHook(next redis.ProcessPipelineHook) redis.ProcessPipelineHook {return func(ctx context.Context, cmds []redis.Cmder) error {return next(ctx, cmds)}
}

main.go

func initPrometheus() {go func() {http.Handle("/metrics", promhttp.Handler())http.ListenAndServe(":8081", nil)}()
}func initDB() *gorm.DB {db, err := gorm.Open(mysql.Open("root:QWEzxc123456@tcp(localhost:3306)/webook"))if err != nil {panic(err)}var callBack = NewCallback("my_namespace","my_subsystem","gorm_test","统计GORM执行时间")err = db.Callback().Query().Before("*").Register("prometheus_query_before", func(tx *gorm.DB) {callBack.Before(tx)})err = db.Callback().Query().After("*").Register("prometheus_query_after", func(tx *gorm.DB) {callBack.After("query", tx)})return db
}func initRedis() redis.Cmdable {client := redis.NewClient(&redis.Options{Addr:     "localhost:6379",Password: "",DB:       0,})hook := NewPrometheusHook("my_namespace", "my_subsystem", "redis_test", "统计redis执行时间")client.AddHook(hook)return client
}// User 对应数据库中的user表
type User struct {Id       int64  `gorm:"primaryKey,autoIncrement"`Email    string `gorm:"unique"`Phone    string `gorm:"unique"`Password stringNickname string `gorm:"type=varchar(128)"`// YYYY-MM-DDBirthday int64Aboutme  string `gorm:"type=varchar(4096)"`// 时区,UTC 0 的毫秒数// 创建时间Ctime int64// 更新时间Utime int64// json 存储//Addr stringWeChatOpenID   string `gorm:"unique"`WeChatUniqueID string `gorm:"unique"`
}func main() {initPrometheus()db := initDB()client := initRedis()server := gin.Default()// 接入中间件server.Use(NewSummaryBuilder("my_namespace","my_subsystem","test","统计响应时间").Build())server.Use(NewGaugeBuilder("my_namespace","my_subsystem","http_req","统计当前活跃的请求数").Build())server.GET("/test", func(ctx *gin.Context) {num := rand.Intn(5)time.Sleep(time.Duration(num) * time.Second)})server.GET("/gorm", func(ctx *gin.Context) {// 执行数据库操作var users []Usererr := db.WithContext(ctx).Find(&users).Errorif err != nil {ctx.JSON(http.StatusOK, gin.H{"code": 500,"msg":  "系统错误",})return}ctx.JSON(http.StatusOK, gin.H{"code": 200,"data": users,"msg":  "OK",})})server.GET("/redis", func(ctx *gin.Context) {// 执行redis操作err := client.Set(ctx, "test_key", []byte("aaaaaa"), time.Second*60).Err()if err != nil {ctx.JSON(http.StatusOK, gin.H{"code": 500,"msg":  "系统错误",})return}ctx.JSON(http.StatusOK, gin.H{"code": 200,"msg":  "OK",})})server.Run(":8080")
}

然后我们使用 wrk 接口测试工具模拟发送100个请求,观察现象:

以下是 Prometheus 统计结果:

http://www.dtcms.com/wzjs/195654.html

相关文章:

  • 网站升级改版方案成都网站快速排名优化
  • 如何利用淘宝建设网站挣钱网络推广有哪几种方法
  • 建设网站第一部分上海百度推广电话客服
  • 用html怎么做网站尾部百度推广网站平台
  • 做网站搞个物理服务器可以发外链的网站整理
  • 做房产买卖哪些网站可以获客seo外包公司报价
  • 网站建设颜色流量平台有哪些
  • 桂园精品网站建设费用抖音关键词挖掘工具
  • 在线做mtv网站西安百度公司官网
  • 网站建设 技术 哪些方面重庆网络推广公司
  • 怎么做新网站的推广seo分析案例
  • zencart官方网站优化师是干嘛的
  • 电影网站建设报价优化seo是什么
  • 做词云图的网站西安百度推广竞价托管
  • 自己做局域网站免费关键词挖掘网站
  • 无锡网站建设2345网址大全
  • 上海做网站哪里有线上营销推广的公司
  • 酒店网站建设项目报告书永久免费客服系统有哪些软件
  • thinkphp怎么做网站最新新闻事件今天疫情
  • 四川省建设领域信用系统网站在线crm软件
  • 做设计的网站有哪些网站建设制作
  • 南通做网站优化公司淮北seo排名
  • 荆门网站开发有哪些百度云盘搜索引擎入口
  • 大连网站怎么百度网页版怎么切换
  • 做问卷赚钱网站百度商家平台
  • 优秀网站大全在线bt种子
  • 泰州专门做网站外链网
  • 安徽华强建设集团网站广告seo是什么意思
  • 公司百度网站怎么做的关键词自助优化
  • 手机触屏版网站开发网上教育培训机构