提升 Prometheus 的高可用性:Thanos 的部署与实践!

news2024/11/18 12:39:54

背景

在高可用 prometheus:问题集锦文章中有简单提到 Prometheus 的高可用方案,尝试了联邦、Remote Write 之后,我们最终选择了 Thanos 作为监控配套组件,利用其全局视图来管理我们的多地域、300+集群的监控数据。本文主要介绍 Thanos 的一些组件使用和心得体会。

Prometheus 官方的高可用有几种方案:

  1. HA:即两套 Prometheus 采集完全一样的数据,外边挂负载均衡

  2. HA + 远程存储:除了基础的多副本 Prometheus,还通过 Remote write 写入到远程存储,解决存储持久化问题

  3. 联邦集群:即 Federation,按照功能进行分区,不同的 Shard 采集不同的数据,由 Global 节点来统一存放,解决监控数据规模的问题。

使用官方建议的多副本 + 联邦仍然会遇到一些问题,本质原因是 Prometheus 的本地存储没有数据同步能力,要在保证可用性的前提下再保持数据一致性是比较困难的,基本的多副本 Proxy 满足不了要求,比如:

  • Prometheus 集群的后端有 A 和 B 两个实例,A 和 B 之间没有数据同步。A 宕机一段时间,丢失了一部分数据,如果负载均衡正常轮询,请求打到A 上时,数据就会异常。

  • 如果 A 和 B 的启动时间不同,时钟不同,那么采集同样的数据时间戳也不同,就多副本的数据不相同。就算用了远程存储,A 和 B 不能推送到同一个 TSDB,如果每人推送自己的 TSDB,数据查询走哪边就是问题

  • 官方建议数据做 Shard,然后通过 Federation 来实现高可用,但是边缘节点和 Global 节点依然是单点,需要自行决定是否每一层都要使用双节点重复采集进行保活。也就是仍然会有单机瓶颈。

  • 另外部分敏感报警尽量不要通过 Global 节点触发,毕竟从 Shard 节点到 Global 节点传输链路的稳定性会影响数据到达的效率,进而导致报警实效降低。

目前大多数的 Prometheus 的集群方案是在存储、查询两个角度上保证数据的一致:

  • 存储角度:如果使用 Remote Write 远程存储, A 和 B 后面可以都加一个 Adapter,Adapter 做选主逻辑,只有一份数据能推送到 TSDB,这样可以保证一个异常,另一个也能推送成功,数据不丢,同时远程存储只有一份,是共享数据。方案可以参考这篇文章

  • 存储角度:仍然使用 Remote Write 远程存储,但是 A 和 B 分别写入 TSDB1 和 TSDB2 两个时序数据库,利用 Sync 的方式在 TSDB1 和 TSDB2 之间做数据同步,保证数据是全量的。

  • 查询角度:上边的方案需要自己实现,有侵入性且有一定风险,因此大多数开源方案是在查询层面做文章,比如 Thanos 或者 Victoriametrics,仍然是两份数据,但是查询时做数据去重和 join。只是 Thanos是通过 Sidecar 把数据放在对象存储,Victoriametrics 是把数据 Remote Write 到自己的 Server 实例,但查询层 Thanos Query 和 Victor的 Promxy 的逻辑基本一致,都是为全局视图服务

实际需求

随着我们的集群规模越来越大,监控数据的种类和数量也越来越多:如Master/Node 机器监控、进程监控、4 大核心组件的性能监控,POD 资源监控、kube-stats-metrics、K8S events监控、插件监控等等。除了解决上面的高可用问题,我们还希望基于 Prometheus 构建全局视图,主要需求有:

  • 长期存储:1 个月左右的数据存储,每天可能新增几十G,希望存储的维护成本足够小,有容灾和迁移。考虑过使用 Influxdb,但 Influxdb 没有现成的集群方案,且需要人力维护。最好是存放在云上的 TSDB 或者对象存储、文件存储上。

  • 无限拓展:我们有300+集群,几千节点,上万个服务,单机 Prometheus 无法满足,且为了隔离性,最好按功能做 Shard,如 Master 组件性能监控与 POD 资源等业务监控分开、主机监控与日志监控也分开。或者按租户、业务类型分开(实时业务、离线业务)。

  • 全局视图:按类型分开之后,虽然数据分散了,但监控视图需要整合在一起,一个 Grafana 里 n 个面板就可以看到所有地域+集群 + POD 的监控数据,操作更方便,不用多个 Grafana 切来切去,或者 Grafana 中多个 Datasource 切来切去。

  • 无侵入性:不要对已有的 Prometheus 做过多的修改,因为 Prometheus 是开源项目,版本也在快速迭代,我们最早使用过 1.x,可1.x 和 2.x的版本升级也就不到一年时间,2.x 的存储结构查询速度等都有了明显提升,1.x 已经没人使用了。因此我们需要跟着社区走,及时迭代新版本。因此不能对 Prometheus 本身代码做修改,最好做封装,对最上层用户透明。

在调研了大量的开源方案(Cortex/Thanos/Victoria/StackDriver..)和商业产品之后,我们选择了 Thanos,准确的说 Thanos 只是监控套件,与原生 Prometheus 结合,满足了长期存储 + 无限拓展 + 全局视图 + 无侵入性的需求。

Thanos 架构

Thanos 的默认模式:sidecar 方式

除了 这个 sidecar 方式,Thanos 还有一种不太常用的 receive 模式,后面会提到。

Thanos 是一组组件,在官网上可以看到包括:

  • Bucket

  • Check

  • Compactor

  • Query

  • Rule

  • Sidecar

  • Store

除了官方提到的这些,其实还有:

  • receive

  • downsample

看起来组件很多,但其实部署时二进制只有一个,非常方便。只是搭配不同的参数实现不同的功能,如 query 组件就是 ./thanos query,sidecar 组件就是./thanos sidecar,组件 all in one,代码只有一份,体积很小。

其实核心的 sidecar + query 就已经可以运行,其他的组件只是为了实现更多的功能

最新版 Thanos 在 这里下载release,对于 Thanos 这种仍然在修 bug、迭代功能的软件,有新版本就不要用旧的。

组件与配置

下面会介绍如何组合 Thanos 组件,来快速实现你的 Prometheus 高可用,因为是快速介绍,和官方的 quick start有一部分雷同,不过会给出推荐配置,且本文截止2020.1 月的版本,不知道以后会 Thanos 会迭代成什么样子

第1步:确认已有的 Prometheus

thanos 是无侵入的,只是上层套件,因此你还是需要部署你的 Prometheus,这里不再赘述,默认你已经有一个单机的 Prometheus 在运行,可以是 pod 也可以是主机部署,取决于你的运行环境,我们是在 k8s 集群外,因此是主机部署。Prometheus 采集的是地域A的监控数据。你的 Prometheus 配置可以是:

启动配置:

 
"./prometheus--config.file=prometheus.yml \--log.level=info \--storage.tsdb.path=data/prometheus \--web.listen-address='0.0.0.0:9090' \--storage.tsdb.max-block-duration=2h \--storage.tsdb.min-block-duration=2h \--storage.tsdb.wal-compression \--storage.tsdb.retention.time=2h \--web.enable-lifecycle"

web.enable-lifecycle一定要开,用于热加载时 reload 你的配置,retention 保留 2 小时,Prometheus 默认 2 小时会生成一个 block,Thanos 会把这个 block 上传到对象存储。

采集配置:prometheus.yml

 
global:  scrape_interval:     60s  evaluation_interval: 60s  external_labels:     region: 'A'     replica: 0
rule_files:scrape_configs:  - job_name: 'prometheus'    static_configs:      - targets: ['0.0.0.0:9090']
  - job_name: 'demo-scrape'    metrics_path: '/metrics'    params:    ...

这里需要声明 external_labels,标注你的地域。如果你是多副本运行,需要声明你的副本标识,如 0号,1,2 三个副本采集一模一样的数据,另外2个 Prometheus 就可以同时运行,只是 replica 值不同而已。这里的配置和官方的 Federation方案差不多。

对 Prometheus 的要求:

  • 2.2.1 版本以上

  • 声明你的 external_labels

  • 启用 –web.enable-admin-api

  • 启用 –web.enable-lifecycle

第2步:部署 Sidecar 组件

关键的步骤来了,最核心莫过于 sidecar 组件。sidecar是 k8s 中的一种模式

Sidecar 组件与 Prometheus server 部署于同一个 pod 中。他有两个作用:

  1. 它使用 Prometheus 的 Remote Read API,实现了 Thanos 的 Store API。这使后面要介绍的Query 组件可以将 Prometheus 服务器视为时间序列数据的另一个来源,而无需直接与 Prometheus API交互(这就是 Sidecar 的拦截作用)

  2. 可选配置:在 Prometheus 每2小时生成一次 TSDB 块时,Sidecar 将 TSDB 块上载到对象存储桶中。这使得 Prometheus 服务器可以以较低的保留时间运行,同时使历史数据持久且可通过对象存储查询。

当然,这不意味着 Prometheus 可以是完全无状态的,因为如果它崩溃并重新启动,您将丢失2个小时的指标,不过如果你的 Prometheus 也是多副本,可以减少这 2h 数据的风险。

sidecar配置:

 
./thanos sidecar \--Prometheus.url="http://localhost:8090" \--objstore.config-file=./conf/bos.yaml \--tsdb.path=/home/work/opdir/monitor/Prometheus/data/Prometheus/"

配置很简单,只需要声明 Prometheus.url 和数据地址即可。objstore.config-file 是可选项。如果你要把数据存放在对象存储(这也是推荐做法),就配置下对象存储的账号信息。

Thanos 默认支持谷歌云/AWS 等,以 谷歌云为例,配置如下:

 
type: GCSconfig:  bucket: ""  service_account: ""

因为 Thanos 默认还不支持我们的云存储,因此我们在 Thanos 代码中加入了相应的实现,并向官方提交了 PR。

需要注意的是:别忘了为你的另外两个副本 1号 和 2号 Prometheus 都搭配一个 sidecar。如果是 pod运行可以加一个 container,127 访问,如果是主机部署,指定 Prometheus 端口就行。

另外 sidecar 是无状态的,也可以多副本,多个 sidecar 可以访问一份 Prometheus 数据,保证 sidecar 本身的拓展性,不过如果是 pod 运行也就没有这个必要了,sidecar 和 Prometheus 同生共死就行了。

sidecar 会读取 Prometheus 每个 block 中的 meta.json 信息,然后扩展这个 json 文件,加入了 Thanos 所特有的 metadata 信息。而后上传到块存储上。上传后写入 thanos.shipper.json 中

第3步:部署 query 组件

sidecar 部署完成了,也有了3个一样的数据副本,这个时候如果想直接展示数据,可以安装 query 组件

Query 组件(也称为“查询”)实现了 Prometheus 的 HTTP v1 API,可以像 Prometheus 的 graph一样,通过 PromQL 查询 Thanos 集群中的数据。

简而言之,sidecar 暴露了 StoreAPI,Query 从多个 StoreAPI 中收集数据,查询并返回结果。Query 是完全无状态的,可以水平扩展。

配置:

 
"./thanos query \--http-address="0.0.0.0:8090" \--store=relica0:10901 \--store=relica1:10901 \--store=relica2:10901 \--store=127.0.0.1:19914 \"

store 参数代表的就是刚刚启动的 sidecar 组件,启动了 3 份,就可以配置三个relica0、relica1、relica2,10901 是 sidecar 的默认端口。

http-address 代表 query 组件本身的端口,因为他是个 web 服务,启动后,页面是这样的:

和 Prometheus 几乎一样对吧,有了这个页面你就不需要关心最初的 Prometheus 了,可以放在这里查询。

点击 store,可以看到对接了哪些 sidecar。

query 页面有两个勾选框,含义是:

  • deduplication:是否去重。默认勾选代表去重,同样的数据只会出现一条,否则 replica0 和 1、2 完全相同的数据会查出来 3 条。

  • partial response:是否允许部分响应,默认允许,这里有一致性的折中,比如 0、1、2 三副本有一个挂掉或者超时了,查询时就会有一个没有响应,如果允许返回用户剩下的 2 份,数据就没有很强的一致性,但因为一个超时就完全不返回,就丢掉了可用性,因此默认允许部分响应。

第4步:部署 store gateway 组件

你可能注意到了,在第 3 步里,./thanos query有一条–store是 xxx:19914,并不是一直提到的 3 副本,这个 19914 就是接下来要说的 store gateway组件。

在第 2 步的 sidecar 配置中,如果你配置了对象存储 objstore.config-file,你的数据就会定时上传到 bucket 中,本地只留 2 小时,那么要想查询 2 小时前的数据怎么办呢?数据不被 Prometheus 控制了,应该如何从 bucket 中拿回来,并提供一模一样的查询呢?

Store gateway 组件:store gateway 主要与对象存储交互,从对象存储获取已经持久化的数据。与sidecar一样,store gateway也实现了 store api,query 组可以从 store gateway 查询历史数据。

配置如下:

./thanos store \--data-dir=./thanos-store-gateway/tmp/store \--objstore.config-file=./thanos-store-gateway/conf/bos.yaml \--http-address=0.0.0.0:19904 \--grpc-address=0.0.0.0:19914 \--index-cache-size=250MB \--sync-block-duration=5m \--min-time=-2w \--max-time=-1h \

grpc-address 就是 store api 暴露的端口,也就是 query 中–store 是 xxx:19914的配置。

因为Store gateway需要从网络上拉取大量历史数据加载到内存,因此会大量消耗 cpu 和内存,这个组件也是 thanos 面世时被质疑过的组件,不过当前的性能还算可以,遇到的一些问题后面会提到。

Store gateway也可以无限拓展,拉取同一份 bucket 数据。

放个示意图,一个 Thanos 副本,挂了多个地域的 store 组件

其中一个地域的数据统计:

查询一个月历史数据速度还可以,主要是数据持久化没有运维压力,随意扩展,成本低。

到这里,Thanos 的基本使用就结束了,至于 compact 压缩和 bucket 校验,不是核心功能,compact的资源消耗也特别大,rule组件我们没有使用,就不做介绍了。

第5步:查看数据

有了多地域多副本的数据,就可以结合 Grafana 做全局视图了,比如:

按地域和集群查看 ETCD 的性能指标:

按地域、集群、机器查看核心组件监控,如多副本 Master 机器上的各种性能

数据聚合在一起之后,可以将所有视图都集中展示,比如还有这些面板:

  • 机器监控:node-exporter、process-exporter

  • POD资源使用: Cadvisor

  • Docker、kube-proxy、kubelet 监控

  • scheduler、controller-manager、etcd、apiserver 监控

  • kube-state-metrics 元信息

  • K8S Events

  • mtail 等日志监控

Receive 模式

前面提到的所有组件都是基于 sidecar 模式配置的,但 Thanos 还有一种 Receive 模式,不太常用,只是在Proposals中出现

因为一些网络限制,我们之前尝试过 Receive 方案,这里可以描述下 Receive 的使用场景:

  1. sidecar 模式有一个缺点:就是2 小时内的数据仍然需要通过 sidecar->Prometheus来获取,也就是仍然依赖 Prometheus,并不是完全的数据在外部存储。如果你的网络只允许你查询特定的存储数据,无法访问到集群内的 Prometheus,那这 2 小时的数据就丢失了,而 Receive 模式采用了remote write 就没有所谓的 2 小时 block 的问题了。

  2. sidecar 模式对网络连通性是有要求的,如果你是多租户环境或者是云厂商,对象存储(历史数据)query 组件一般在控制面,方便做权限校验和接口服务封装,而 sidecar 和 Prometheus 却在集群内,也就是用户侧。控制面和用户侧的网络有时候会有限制,是不通的,这个时候会有一些限制导致你无法使用 sidecar

  3. 租户和控制面隔离,和第2条类似,希望数据完全存在控制面,我一直觉得 Receive 就是为了云厂商服务的。。

    不过 Receive 毕竟不是默认方案,如果不是特别需要还是用默认的 sidecar 为好

一些问题

Prometheus 压缩

压缩:官方文档有提到,使用 sidecar 时,需要将 Prometheus 的 –storage.tsdb.min-block-duration 和 –storage.tsdb.max-block-duration 这两个值设置为2h,两个参数相等才能保证Prometheus 关闭了本地压缩,其实这两个参数在 Prometheus -help 中并没有体现,Prometheus 作者也说明这只是为了开发测试才用的参数,不建议用户修改。而 Thanos 要求关闭压缩是因为 Prometheus 默认会以2,25,25*5的周期进行压缩,如果不关闭,可能会导致 thanos 刚要上传一个 block,这个 block 却被压缩中,导致上传失败。

不过你也不必担心,因为在 sidecar 启动时,会检查这两个参数,如果不合适,sidecar会启动失败

store-gateway

store-gateway: store 组件资源消耗是最大的,毕竟他要拉取远程数据,并加载到本地供查询,如果你想控制历史数据和缓存周期,可以修改相应的配置,如:

--index-cache-size=250MB \--sync-block-duration=5m \ --min-time=-2w \ 最大查询 1 周--max-time=-1h \

store-gateway 默认支持索引缓存,来加快 TSDB 块的查找速度,但有时候启动会占用了大量的内存,在 0.11.0之后的版本做了修复,可以查看这个issue

Prometheus 2.0 已经对存储层进行了优化。例如按照时间和指标名字,连续的尽量放在一起。而 store gateway可以获取存储文件的结构,因此可以很好的将指标存储的请求翻译为最少的 object storage 请求。对于那种大查询,一次可以拿成百上千个 Chunks 数据。

而在 store 的本地,只有 Index 数据是放入 Cache 的,Chunk 数据虽然也可以,但是就要大几个数量级了。目前,从对象存储获取 Chunk 数据只有很小的延时,因此也没什么动力去将 Chunk 数据给 Cache起来,毕竟这个对资源的需求很大。

store-gateway中的数据:

每个文件夹中其实是一个个的索引文件 index.cache.json

compactor组件

Prometheus 数据越来越多,查询一定会越来越慢,Thanos 提供了一个 compactor 组件来处理,他有两个功能,

  • 一个是做压缩,就是把旧的数据不断的合并。

  • 一个是降采样,他会把存储的数据,按照一定的时间,算出最大,最小等值,会根据查询的间隔,进行控制,返回采样的数据,而不是真实的点,在查询特别长的时间的数据的时候,看的主要是趋势,精度是可以选择下降的。

  • 注意的是 Compactor 并不会减少磁盘占用,反而会增加磁盘占用(做了更高维度的聚合)。

thanos 组件的优化并不是万能的,因为业务数据总在增长,这时候可能要考虑业务拆分了。我们需要对业务有一定的划分,不同的业务监控放在不同bucket里(需要改造或者多部署几个 sidecar)。例如有5个 bucket ,再准备5个 store gateway 进行代理查询。减少单个 store 数据过大的问题。

第二个方案是时间切片,也就是上面提到的 store gateway,可以选择查询多长时间的数据。store gateway配置支持两种表达式,一种是基于相对时间的,例如–max-time 是3d前到5d前的。一种是基于绝对时间的,如19年3月1号到19年5月1号。例如想查询3个月的数据,一个 store 可以代理一个月的数据,那么就需要部署3个store来合作。

query 的去重

query 组件启动时,默认会根据 query.replica-label 字段做重复数据的去重,你也可以在页面上勾选deduplication 来决定。query 的结果会根据你的 query.replica-label的 label 选择副本中的一个进行展示。可如果 0,1,2 三个副本都返回了数据,且值不同,query 会选择哪一个展示呢?

Thanos 会基于打分机制,选择更为稳定的 replica 数据, 具体逻辑在:https://github.com/thanos-io/thanos/blob/55cb8ca38b3539381dc6a781e637df15c694e50a/pkg/query/iter.go

参考

  • https://thanos.io/

  • https://www.percona.com/blog/2018/09/20/Prometheus-2-times-series-storage-performance-analyses/

  • https://qianyongchao.blog/2019/01/03/Prometheus-thanos-design-%E4%BB%8B%E7%BB%8D/

  • https://github.com/thanos-io/thanos/issues/405

  • https://katacoda.com/bwplotka/courses/thanos

  • https://medium.com/faun/comparing-thanos-to-victoriametrics-cluster-b193bea1683

  • https://www.youtube.com/watch?v=qQN0N14HXPM

来源:http://www.xuyasong.com/?p=1925

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/419386.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NC237662 葫芦的考验之定位子串(SAM + 后缀链接树上倍增)

题意&#xff1a; 给出一个字符串S&#xff0c;|S| ≤ 250000&#xff0c;给出 Q < 250000 次询问&#xff0c;每次需要回答 S[l, r] 在 S 中共出现了多少次。 思路&#xff1a; 如果使用 SAM&#xff0c;我们提前求出每个状态的 cnt[u]&#xff0c;询问就是要求我们快速…

Nuxt3中的中间件-middleware

参考&#xff1a;nuxt3中间件(middleware)详解 - 简书nuxt3中间件(middleware)详解 在项目中有时候需要在网站切换路由的过程中添加一些自定义的逻辑&#xff0c;比如权限什么的。这个时候可以使用nuxt的middleware。 ...https://www.jianshu.com/p/bd22637c6447 中间件的作用…

【算法系列之动态规划】子序列篇

300.最长递增子序列 力扣题目链接 给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1…

Ubunutu18.04+Qt5.14+Dlib19.24+Opencv3.4.16实时人眼监测实验

文章目录1 前言2 效果3 Ubuntu18.04下Qt、Opencv、Dlib的配置3.0 Ubuntu18.04的安装以及一些基本配置3.1 Qt3.2 Opencv3.3 Dlib4 核心代码4.1 pro文件4.2 Widget.cpp4.3 fatiguedetect.cpp5 资源下载1 前言 在Ubuntu18.04实现的一个人眼监测小程序&#xff0c;使用Qt5.14、Dlib…

仿京东放大镜效果的实现

仿京东放大镜 &#xff08;1&#xff09; 整个案例可以分为三个功能模块 &#xff08;2&#xff09; 鼠标经过小图片盒子&#xff0c; 黄色的遮挡层 和 大图片盒子显示&#xff0c;离开隐藏2个盒子功能 &#xff08;3&#xff09;黄色的遮挡层跟随鼠标功能。 &#xff08;4&…

百度文心一言与Notion的比较(机器人通信的例子)

文心一言出来有一段时间了&#xff0c;也经常会去问问&#xff0c;感觉对于简单的语义理解还是可以&#xff0c;其答案对于一些常见的常识等还是可以给出不错的答案&#xff0c;但是在数学与代码等方面基本上很差&#xff0c;基本的贷款利率、微积分、没有理解语义的代码等都是…

一篇五分生信临床模型预测文章代码复现——Figure 10.机制及肿瘤免疫浸润(一)

之前讲过临床模型预测的专栏,但那只是基础版本,下面我们以自噬相关基因为例子,模仿一篇五分文章,将图和代码复现出来,学会本专栏课程,可以具备发一篇五分左右文章的水平: 本专栏目录如下: Figure 1:差异表达基因及预后基因筛选(图片仅供参考) Figure 2. 生存分析,…

C++篇 ---- 命名空间namespace

由于在c语言中在定义时可能会出现重命名现象&#xff0c;造成空间冲突&#xff0c;c语言中有命名冲突&#xff1a;1 和库冲突。2 互相之间的冲突&#xff0c;变量命名冲突。所以c中就有了对其改进的关键字namespace&#xff0c;针对重定义&#xff0c;解决空间冲突。 文章目录命…

总结820

学习目标&#xff1a; 4月&#xff08;复习完高数18讲内容&#xff0c;背诵21篇短文&#xff0c;熟词僻义300词基础词&#xff09; 学习内容&#xff1a; 高等数学&#xff1a;巩固所学&#xff0c;1~10讲内容回顾 rule No.1:never lost your knowledge. rule No.2:never f…

C++基础语法(模板)

C的模板是什么&#xff1f;有什么用&#xff1f;如果你想知道问题的答案&#xff0c;那么看这篇博客就对了&#xff0c;在这篇博客中&#xff0c;我们将探讨泛型编程&#xff0c;C模板的具体内容 目录 模板概念 函数模板 显示实例化与隐式实例化 模板不支持声明和定义分离 类模…

104.(cesium篇)cesium卫星轨道模拟

听老人家说:多看美女会长寿 地图之家总目录(订阅之前建议先查看该博客) 文章末尾处提供保证可运行完整代码包,运行如有问题,可“私信”博主。 效果如下所示: 下面献上完整代码,代码重要位置会做相应解释 <html lang="en"> <

【数据结构】带你细致理解八大排序

文章目录前言一.冒泡排序前一个数跟后一个数比较后一个数跟前一个数比较优化复杂度与稳定性二.插入排序初始化条件从第一个元素开始初始化条件从第二个元素开始复杂度与稳定性三.选择排序一趟选出一个最小的一趟选出一个最大的和一个最小的复杂度与稳定性四.堆排序建堆用向下调…

数据结构入门(C语言版)栈和队列之栈的介绍及实现

栈栈的概念栈的实现过程栈的结构体与接口的定义1、静态栈结构2、动态栈结构3、栈的接口定义栈的接口实现①初始化栈(StackInit)②入栈(StackPush)③出栈(StackPop)④栈顶(StackTop)⑤栈元素个数(StackSize)⑥检测栈是否为空(StackEmpty)⑦销毁栈(StackDestroy)结语栈的概念 栈…

【EXata】在 Visual Studio 2010 上编译与调试 EXata

一、在 VS2010 中编译 Exata 通过命令行的形式来编译调试 EXata 的方式太过麻烦&#xff0c;一次两次还好&#xff0c;时间长了慢慢就烦了&#xff0c;于是想着有没有什么方法能够简化这些操作&#xff0c;翻看手册&#xff0c;发现是可以在 IDE 中进行编译&#xff0c;于是就有…

mysql分库分表分片分区及常见问题

1.前言 MySQL单库数据量在5000万以内性能比较好&#xff0c;超过阈值后性能会随着数据量的增大而变弱。MySQL单表的数据量是500w-1000w之间性能比较好&#xff0c;超过1000w性能也会下降。 2.mysql分布式 分库 分库一般有两种目的&#xff1a;将库中不同表进行拆分&#xff…

英国访问学者T5签证所需相关材料

英国访问学者T5签证所需相关材料,下面就随知识人网小编一起来看一看。 1、完整填写的申请表格并亲笔签名。 2、近期护照规格白色背景彩色照片并贴在签证表格首页右上角。 3、签证后至少剩余6个月有效期的护照及申请人所持有的旧护照。 4、邀请信原件。 邀请信主要内容包括&…

基于SSM框架便利店管理系统(进销存管理系统)(java+spring+springmvc+mybatis+maven+mysql+html)

一、项目简介 本项目是一套基于SSM框架便利店管理系统(进销存管理系统)&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者。 包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等&#xff0c;该项目附带全部源码可作为毕设使用。…

BT8918D---huart模块分析

1 huart模块 huart模块从名字可以看出&#xff0c;用于串口UART通讯&#xff0c;H的含义&#xff0c;目前还不知道&#xff0c;待了解。该模块源码未公开&#xff0c;已经编译成库文件&#xff0c;供开发者使用。 2 huart模块分析 2.1 特性 默认特性&#xff1a; Baud rat…

R语言处理数据——janitor包的介绍及使用

janitor功能介绍 janitor可以检查并清理脏数据&#xff0c;适用于R语言用户。主要功能如下&#xff1a; 1、完美格式化数据框的列名&#xff1b; 2、创建并格式化1-3个变量的频率表&#xff0c;可以看作是一个改进的table()函数&#xff1b; 3、提供用于清理和检查数据框的其他…

CCS通过dat文件导入数据计算出结果再导出数据

之前有很多博主讲过在matlab当中导出数据&#xff0c;到DSP里面进行计算&#xff0c;然后再将数据导出到matlab当中进行使用。 以前使用过matlab当中的dat数据&#xff0c;大家可以看一下区别&#xff1a; fid fopen(A.dat,wt);%将所得的数据存在A.dat当中 fprintf(fid,%g\n…