同样遇到以下链接所示错误:
通过单步跟踪,定位到运行函数 std::vector
参考链接
- __acrt_first_block == header错误的一种办法,by hansen_fu.
- vector 的push_back() 报错,by 爱钓鱼的歪猴.
同样遇到以下链接所示错误:
通过单步跟踪,定位到运行函数 std::vector
最近遇到一个软件,使用exeinfo pe查看,发现其使用 Themida & WinLicense 2.0 - 2.4.6 加了壳,于是想办法给该软件脱壳,记录一下过程。
壳是一种专用的加密软件技术,它能够保护软件的二进制程序,避免其直接暴露在不怀好意的同行面前。要理解壳,要脱壳,首先得了解一些基本知识。
壳所保护的软件二进制程序通常采用PE文件格式,包括壳自身也是如此。因此有必要了解PE文件格式。
常用的壳可分为压缩壳、加密壳、虚拟机保护壳。
脱壳技术的核心是寻找目标程序的 OEP(Original Entry Point,原程序入口点),然后将目标程序恢复出来。
请参考[分享]Themida & WinLicense 2.0 - 2.4.6 脱壳。脱壳过程需要注意的是:
需要在 X64 的 Ubuntu 20.04 平台交叉编译 ARM64 架构的程序,研究一下交叉编译工具链的使用方法。
交叉编译工具链是一个由编译器、连接器和解释器组成的综合开发工具集,交叉编译工具链主要由binutils、gcc和glibc三个部分组成。有时出于减小 libc 库大小的考虑,也可以用别的 c 库来代替 glibc,例如 uClibc、dietlibc 和 newlib。
目前主流的 ARM 交叉编译工具链主要有三种:
DeepSeek如此火热,不禁也研究一下本地部署DeepSeek的方法。
Ollama是一款启动并运行大型语言模型的工具。
安装完成后,我们直接打开命令行执行 ollama –version 判断是否安装成功。
ollama 会在我们本地服务监听 11434 端口。
我们可以直接使用 ollama run 模型名称 来下载和运行我们想要的模型。例如:
1 | # 查看ollama版本 |
1 | # 在联网生成大模型描述文件 |
Chatbox 是一款开源的 AI 客户端,专为与各种大型语言模型进行交互而设计。它支持包括 Ollama 在内的多种主流模型的 API 接入,无论是本地部署的模型,还是其他服务提供商的模型,都能轻松连接。
请参考:
Open-WebUI是一个可扩展、功能丰富且用户友好的自托管人工智能平台,设计上完全离线运行。它支持各种大语言模型(LLM)执行器,如 Ollama和兼容OpenAI的APIs ,并内置了用于检索增强生成(RAG)的推理引擎,使其成为一个强大的AI部署解决方案 。
部署过程请参考:
Chatbox 提供了联网功能,但是 DeepSeek R1 模型是没办法联网。
想要让本地模型联网我们还得靠一个浏览器插件 Page Assist。
Page Assist 是一款开源的浏览器扩展程序,旨在为本地 AI 模型(如 Ollama)提供便捷的交互界面。
RAG(Retrieval-Augmented Generation,检索增强生成)是一种结合信息检索与生成模型的人工智能技术,旨在通过检索外部知识库中的信息来增强语言模型的生成能力。
LLM(Large Language Model,大语言模型)
Embedding(嵌入):通过一个专门的模型来把你上传的文本、表格数据等本地文件处理成机器能理解的 “数字代码”。相似的文本在这个向量空间中距离会更近。比如,“苹果”和“水果”这两个词的嵌入向量就会比较接近,而“苹果”和“汽车”就会离得很远。
Vector Database(向量数据库):用来存储上一步处理好的 “数字代码” 的数据库,它能够高效地存储和检索这些向量。当你有一个问题时,它会把问题转换成向量,然后在这个仓库里快速找到和问题最相关的向量。比如,你问“苹果是什么?”它会在这个仓库里找到和“苹果”相关的向量,比如“水果”“红色”“圆形”等。
Anything LLM 是一款基于 RAG架构的本地知识库工具,能够将文档、网页等数据源与本地运行的大语言模型(LLM)相结合,构建个性化的知识库问答系统。
知识库的构建请参考:
Fine-tuning(微调):通过特定领域数据对预训练模型进行针对性优化,以提升其在特定任务上的性能。
请参考:
构建一个较大桌面GUI应用程序,采用插件架构是必由之路。首先插件架构有利于多人分工协作,有利于系统功能的扩展和维护,有利于用户需求的快速响应。
插件架构系统主要由以下三部分构成:
请参考:
最近研究了一下麒麟V10 Linux设置VNC连接的方法,记录一下。
VNC Server应该能够以服务的形式开机自启动,对外以 80 端口提供VNC远程连接服务。
创建VNC Systemd 服务,实现麒麟 V10 开机后 VNC 服务器自启动。
1 | cd /lib/systemd/system/ |
1 | # 重新加载配置文件 |
修改 vncserver 配置,使 :1 对应 80 端口。
1 | # 查看 vncserver 的位置 |
最终找到麒麟 V10 使用的 vncserver 为 TigerVNC,使用 Vim 修改 TigerVNC配置文件,将 5900 替换为 79。
1 | vim /usr/bin/tigervncserver |
Linux 对于非 root 用户禁止使用 1024 以下端口,但为了避免 VNC 服务被防火墙阻挡,应将 VNC 服务端口调整到 80 。修改 sysctl.conf 文件配置达到此目的。
1 | #临时生效 |
1 | # 设置 VNC 客户端连接密码 |
使用各种 VNC 客户端,填入相关配置连接即可。连接 VNC 服务器遇到一些问题,记录如下。
基于 Systemd 设置 VNC 服务开机自启动成功,但是使用 RealVNC Viewer 客户端连接成功后显示黑屏,目前没有解决。但是使用 vncserver 直接创建 vnc 服务,然后使用 RealVNC Viewer 客户端连接成功后没有出现该问题。
打开终端,输入如下命令:
1 | fcitx-autostart |
原因是主目录下的 .Xauthority 文件拥有者变成了 root ,导致用户登录时无法获取该文件,解决方法如下:
1 | sudo chown user:user .Xauthority |
麒麟 V10 自带的 Remmina 能够连接 VNC 服务器的默认的 5901 端口,但是无法连接 VNC 服务器的 80 端口。该问题暂未解决。
建议使用 RealVNC Viewer 客户端,麒麟 v10 自带的 Remmina 客户端连接 80 端口有问题,暂时无法解决。
最近遇到一个运维问题,编写SQL语句判断某个字段是否从1开始,是否是连续的,记录一下问题解决过程。
目标数据表 Department 结构如下:
departId | personId |
---|---|
7523 | 7523001 |
7523 | 7523002 |
7523 | 7523003 |
7524 | 7524001 |
7524 | 7524002 |
7524 | 7524003 |
1 | select * from Department a |
1 | select * from |
从虚拟化技术的发展中,我们看到业务的工作负载由物理机转向虚拟机,资源有了初级的隔离,并且分配/利用更加合理。
对于 XaaS 的一路演进,可以简单归纳为:
Docker 创新性地提出了“镜像”(image)的概念,实现了一种新型的应用打包、分发和运行机制,开发人员能够在几秒钟内完成应用程序的部署、运行,无需再担心环境不一致的问题。
部分软件已经变成水电煤一样的社会经济中的基础设施。
过去二十年间,云的底层基础设施和平台越来越强大,软件架构的发展也逐渐和云匹配:
应用程序中的非业务逻辑不断被剥离,并下沉到云/基础设施层,代码越来越轻量。由此,工程师的开发工作回归本质(软件开发的本质是解决业务需求,各类“高深”、“复杂”的技术难题是业务需求的副产物,并不是软件开发的主题)。
CNCF 云原生的定义 v1.0 版本
云原生技术有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用。云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式 API。
这些技术能够构建容错性好、易于管理和便于观察的松耦合系统。结合可靠的自动化手段,云原生技术使工程师能够轻松地对系统作出频繁和可预测的重大变更。
云原生的几个关键目标:
云原生的代表技术:容器技术、微服务、服务网格、不可变基础设施、声明式设计以及 DevOps。
Google Cloud 对容器的定义: 容器是轻量级应用代码包,它还包含依赖项,例如编程语言运行时的特定版本和运行软件服务所需的库。
容器技术发展历程:
chroot 被认为是最早的容器技术之一,它能将进程的根目录重定向到某个新目录,复现某些特定环境,同时也将进程的文件读写权限限制在该目录内。
至 2013 年,Linux 虚拟化技术已基本成型,通过 cgroups、namespace 以及安全防护机制,大体上解决了容器核心技术“运行环境隔离”,但此时仍需等待另一项关键技术的出现,才能迎来容器技术的全面繁荣。
Docker 的核心创新“容器镜像(container image)”:
OCI 组织着力解决容器的构建、分发和运行标准问题,其宗旨是制定并维护 OCI Specifications(容器镜像格式和容器运行时的标准规范)。
OCI 有了三个主要的标准:
以 Kubernetes 为代表的容器编排框架,就是把大型软件系统运行所依赖的集群环境也进行了虚拟化,让集群得以实现跨数据中心的绿色部署,并能够根据实际情况自动扩缩。
就像用 docker run 可以启动单个程序一样,现在用 kubectl apply -f 就能部署和运行一个分布式集群应用,而无需关心是在私有云还是公有云或者具体哪家云厂商上。
Netflix 云架构师 Adrian Cockcroft定义:微服务架构是一种面向服务的架构,由松耦合的具有有限上下文的元素组成。
Adrian Cockcroft 的观点中有两个核心概念:
微服务架构中,有一些必须解决的问题,如负载均衡、伸缩扩容、传输通讯等等,这些问题可以说只要是分布式架构的系统就无法完全避免。
Kubernetes 在基础设施层面,解决分布式系统问题的方案:
当虚拟化的基础设施从单个服务的容器扩展至由多个容器构成的服务集群,并开始解决分布式的问题。
服务网格(Service Mesh)的概念最早由 Buoyant 公司的创始人 William Morgan 于 2016 年提出。
服务网格的定义
服务网格(ServiceMesh)是一个基础设施层,用于处理服务间通信。云原生应用有着复杂的服务拓扑,服务网格保证请求在这些拓扑中可靠地穿梭。在实际应用当中,服务网格通常是由一系列轻量级的网络代理组成的,它们与应用程序部署在一起,但对应用程序透明。
—— by William Morgan
业内绝大部分服务网格产品通常由“数据平面”和“控制平面”两部分组成:
可变的基础设施会导致以下问题:
不可变基础设施思想的核心是,任何基础设施的运行实例一旦创建之后就变成只读状态。如需修改或升级,应该先修改基础设施的配置模版(例如 yaml、Dockerfile 配置),之后再使用新的运行实例替换。
声明式设计是指一种软件设计理念:“我们描述一个事物的目标状态,而非达成目标状态的流程”。至于目标状态如何达成,则由相应的工具在其内部实现。
和声明式设计相对的是命令式设计(又叫过程式设计),两者的区别是:
DevOps 是个很复杂的概念,几句话很难解释清楚。我们延用之前的惯例,如果要理解一个复杂的概念,就先去了解它出现的背景,以及发展的历史。
DevOps 核心本质是解决软件开发生命周期中的管理问题,我们先从一种名为“瀑布模型”的项目管理方法说起。
虽然敏捷开发提升了开发效率,但它的范围仅限于开发和测试环节,并没有覆盖到部署环节。显然,运维部门并没有收益。相反的,甚至可以说“敏捷”加重了运维的负担。运维追求的目标是稳定,频繁变更是破坏稳定的根源。
DevOps 运动始于 2007 年左右,当时技术社区对开发与运维之间分开工作的方式以及由此引发的冲突感到担忧。
DevOps 的定义
DevOps(Development 和 Operations 的合成词)是一种重视“软件开发人员(Dev)”和“IT 运维技术人员(Ops)”之间沟通合作的文化、运动或惯例。
通过自动化“软件交付”和“架构变更”的流程,来使得构建、测试、发布软件能够更加地快捷、频繁和可靠。
—— from 维基百科
DevOps 的成功实践离不开工具上的支持,这其中包括最重要的自动化 CI/CD 流水线,通过自动化的方式打通软件从构建、测试到部署发布的整个流程。还有实时监控、事件管理、配置管理、协作平台等一系列工具/系统的配合。
一个完整、未复用连接的 HTTPS 请求需要经过以下 5 个阶段:DNS 域名解析、TCP 握手、SSL 握手、服务器处理、内容传输。
RTT(Round-Trip Time)一个网络数据包从起点到目的地然后再回到起点所花费的时长。
TTFB(Time To First Byte,首字节时间)指从浏览器请求页面到接收来自服务器发送的信息的第一个字节的时间。
网络吞吐量与 RTT、带宽密切相关:
一些术语:
QUIC(Quick UDP Internet Connection,快速 UDP 网络连接)是一种基于 UDP 封装的安全可靠传输协议,旨在取代 TCP,成为新一代互联网的主流传输协议。
从 Linux 内核 2.4 版本开始,内核引入了一套通用的过滤框架 —— Netfilter,允许外界对网络数据包在内核协议栈流转过程中进行代码干预。
Linux 系统中的各类网络功能,如地址转换、封包处理、地址伪装、协议连接跟踪、数据包过滤、透明代理、带宽限速和访问控制等,都是基于 Netfilter 提供的代码拦截机制实现的。可以说,Netfilter 是整个 Linux 网络系统最重要(没有之一)的基石。
对于网络密集型应用,内核态与用户态的频繁切换、复杂的网络协议栈处理,常常使 Linux 内核成为性能瓶颈。
在人们想办法提升 Linux 内核性能的同时,另外一批人抱着它不行就绕开它想法,提出了一种“内核旁路“(Kernel bypass)思想的技术方案。其中,DPDK 和 XDP 是主机内“内核旁路”思想的代表技术,RDMA 是主机之间“内核旁路”思想的代表技术。
基于物理设备实现的网络拓扑结构是相对固定的,很难跟得上云原生时代下系统频繁变动的频率。例如,容器的动态扩缩容、集群跨数据中心迁移等等,都要求网络拓扑随时做出调整。正因为如此,软件定义网络(Software Defined Networking,SDN)的需求变得前所未有的迫切。
SDN 思想的核心是,在现有的物理网络之上新增一层虚拟网络,将控制平面(操作系统和各类网络控制软件等)和数据平面(底层通信的物理设备,以及各类通信协议等)解耦,将网络服务从底层硬件设备中抽象出来,由代码直接编程控制。
SDN 网络模型如图 3-16 所示:
从处理请求的网络层次角度看,所有的负载均衡器可归纳为两大类:四层负载均衡和七层负载均衡,分别对应 OSI 模型的第四层(传输层)和第七层(应用层)。
“四层负载均衡”并非严格限定于 OSI 模型的第四层(传输层)。实际上,它的工作模式涉及多个网络层次:
七层负载均衡器工作在应用层,这意味着负载均衡器必须与后端服务器建立新的传输层连接,并将客户端的请求代理到后端服务器。
七层负载均衡器工作在应用层,因此能够检测和处理请求内容,包括:
四层负载均衡器的典型代表是 LVS(Linux Virtual Server,Linux 虚拟服务器),由中国程序员章文嵩于 1998 年发起和开发。
引入事务的目的,是为了保证数据的“一致性”(Consistency)。
这里的一致性指的是,对数据有特定的预期状态,任何数据更改操作必须满足这些状态约束(或者恒等条件)。
想要达成数据的一致性,需要 3 个方面的努力:
这也就是常说的事务的“ACID 特性”。值得一提的是,对于一致性而言,更多的是指数据在应用层的外部表现。应用程序借助数据库提供的原子性、隔离性和持久性,来实现一致性目标。也就是说,A、I、D 是手段,C(Consistency)是 3 者协作的目标,弄到一块完全是为了读起来更顺口。
CAP 是一致性与可用性权衡的理论,是理解分布式系统的起点。
1999 年,美国工程院院士 Eric A.Brewer 发表了论文《Harvest, Yield, and Scalable Tolerant Systems》[1] ,首次提出了“CAP 原理”(CAP Principle)。不过,彼时的 CAP 仅是一种猜想,尚未得到理论上的证明。2002 年,麻省理工学院的 Seth Gilbert 和 Nancy Lynch 用严谨的数学推理证明了 CAP 的正确性。此后,CAP 从原理转变成定理,在分布式系统领域产生了深远的影响。
CAP 定理描述的是一个分布式系统中,涉及共享数据问题时,以下三个特性最多只能满足两个。
由于 CAP 定理已有严格的证明,我们不再探讨为何 CAP 不可兼得,直接分析舍弃 C、A、P 时所带来的不同影响。
对于分布式系统而言,必须实现分区容错性(P)。因此,CAP 定理实际上要求在可用性(A)和一致性(C)之间选择,即在 AP 和 CP 之间权衡取舍。
工程师们又重新给一致性下了定义,将 CAP、ACID 中讨论的一致性(C)称为“强一致性”,而把牺牲了 C 的 AP 系统但又要尽可能获得正确结果的行为称为追求“弱一致性”。不过,若只是单纯地谈论“弱一致性”,通常意味着不保证一致性。在弱一致性中,工程师们进一步总结出了一种较强的特例,称为“最终一致性”(Eventual Consistency),它由 eBay 的系统架构师 Dan Pritchett 在 BASE 理论中提出。
2008 年,eBay 架构师 Dan Pritchett 在 ACM 发表了论文《Base: An Acid Alternative》[1]。这篇论文中,作者基于实践总结出一种独立于 ACID 之外,通过消息队列和幂等机制来达成数据一致性的技术手段,并提出了“最终一致性”的概念。
BASE 是“Basically Available”、“Soft State”和“Eventually Consistent”的缩写,其核心理念为:
幂等性是一个数学概念,后来被引入计算机科学中,用来描述某个操作可以安全地重试,即多次执行的结果与单次执行的结果完全一致。
世界上只有一种共识算法,就是 Paxos,其他所有的共识算法都是 Paxos 的退化版本。
尽管“共识”和“一致”在汉语中含义相近,但在计算机领域,这两个术语具有截然不同的含义:
在分布式系统中,节点故障不可避免,但部分节点故障不应该影响系统整体状态。通过增加节点数量,依据“少数服从多数”原则,只要多数节点(至少 N/2+1 )达成一致,其状态即可代表整个系统。这种依赖多数节点实现容错的机制称为 Quorum 机制。
Quorum 机制
节点个数为 N 的集群,能容忍 (N−1)/2 个节点故障。你注意到了么?3 节点和 4 节点集群的故障容忍性一致。所以,一般情况下,以容错为目的的分布式系统没必要使用 4 个节点。
根据上述的讨论,基于 Quorum 的机制,在不可靠的环境下,通过“少数服从多数”协商机制达成一致的决策,从而对外表现为一致的运行结果。这一过程被称为节点间的“协商共识”。
一旦解决共识问题,便可提供一套屏蔽内部复杂性的抽象机制,为应用层提供一致性保证,满足多种需求,例如:
Paxos 算法由 Leslie Lamport[1] 于 1990 年提出,是一种基于消息传递、具备高度容错特性的共识算法,是当今分布式系统中最重要的理论基础,几乎就是“共识系统”的代名词。
Lamport 在分布式系统理论方面有非常多的成就,比如 Lamport 时钟、拜占庭将军问题、Paxos 算法等等。除了计算机领域之外,其他领域的无数科研工作者也要成天和 Lamport 开发的一套软件打交道,目前科研行业应用最广泛的论文排版系统 —— LaTeX (名字中的 La 就是指 Lamport)
在 Paxos 算法中,节点分为三种角色:
Paxos 算法中“节点众生平等”,每个节点都可以发起提案。多个提议者并行发起提案,是活锁、以及其他异常问题的源头。那如何不破坏 Paxos 的“节点众生平等”基本原则,又能在提案节点中实现主次之分,限制节点不受控的提案权利?
Raft 算法的设计机制是明确领导者、增加选举机制交接提案权利。Raft 算法中,节点分为以下三种角色:
为了减轻管理容器的心智负担,实现容器调度、扩展、故障恢复等自动化机制,容器编排系统应运而生。过去十年间,Kubernetes 发展成为容器编排系统的事实标准,成为大数据分析、机器学习以及在线服务等领域广泛认可的最佳技术底座。
Kubernetes 在解决复杂问题的同时,本身也演变成当今最复杂的软件系统之一。目前,包括官方文档在内的大多数 Kubernetes 资料都聚焦于“怎么做”,鲜有解释“为什么这么做”。自 2015 年起,Google 陆续发布了《Borg, Omega, and Kubernetes》及《Large-scale cluster management at Google with Borg》等论文,分享了 Google 内部开发和运维 Borg、Omega 和 Kubernetes 系统的经验与教训。
Google 先后设计了三套不同的容器管理系统,Borg、Omega 和 Kubernetes,并向外界分享了大量的设计思想、论文和源码,直接促进了容器技术的普及和发展,对整个行业的技术演进产生了深远的影响。
从 Borg 到 Kubernetes,容器技术的价值早已超越了单纯提升资源利用率。更深远的影响在于,系统开发和运维的理念从“以机器为中心”转变为“以应用为中心”:
chroot 是“change root”的缩写,它允许管理员将进程的根目录锁定在特定位置,从而限制进程对文件系统的访问范围。chroot 的隔离功能对安全性至关重要。
1 | $ mkdir -p new-root/{bin,lib64,root} |
除了 /bin 之外,如果我们将程序依赖的 /etc、/proc 等目录一同打包进去,实际上就得到了一个 rootfs 文件。因为 rootfs 包含的不仅是应用,还有整个操作系统的文件和目录,这意味着应用及其所有依赖都被封装在一起,这正是容器被广泛宣传为一致性解决方案的由来。
从 Linux 内核 2.6.19 起,逐步引入了 UTS、IPC、PID、Network 和 User 等命名空间功能。到了 3.8 版本,Linux 实现了容器所需的六项最基本的资源隔离机制。Linux 4.6 版本起,新增了 Cgroup 和 Time 命名空间。
进程的资源隔离已经完成,如果再对使用资源进行额度限制,就能对进程的运行环境实现“进乎完美”的隔离。这就要用 Linux 内核的第二项技术 —— Linux Control Cgroup(Linux 控制组群,简称 cgroups)。
cgroups 是 Linux 内核用于隔离、分配并限制进程组使用资源配额的机制。例如,它可以控制进程的 CPU 占用时间、内存大小、磁盘 I/O 速度等。
登录到 Linux 机器后,执行 pstree -g 命令可以查看当前系统中的进程树状结构。
1 | $ pstree -g |
在 Kubernetes 中,与“进程组”对应的设计概念是 Pod。Pod 是一组紧密关联的容器集合,它们共享 IPC、Network 和 UTS 等命名空间,是 Kubernetes 管理的最基本单位。
所谓的“容器镜像”,其实就是一个“特殊的压缩包”,它将应用及其依赖(包括操作系统中的库和配置)打包在一起,形成一个自包含的环境。
1 | $ docker build 镜像名称 |
Docker 镜像利用联合文件系统的分层设计。整个镜像从下往上由 6 个层组成:
通过镜像分层设计,以 Docker 镜像为核心,不同公司和团队的开发人员可以紧密协作。每个人不仅可以发布基础镜像,还可以基于他人的基础镜像构建和发布自己的软件。镜像的增量操作使得拉取和推送内容也是增量的,这远比操作虚拟机动辄数 GB 的 ISO 镜像要更敏捷。
Docker 通过将宿主机目录挂载到容器内部的方式,实现数据持久化存储。如图 7-21 所示,目前它支持三种挂载方式:bind mount、volume 和 tmpfs mount。
服务网格是一个处理服务通讯的专门的基础设施层。它的职责是在由云原生应用组成服务的复杂拓扑结构下进行可靠的请求传送。在实践中,它是一组和应用服务部署在一起的轻量级的网络代理,对应用服务透明。
—— What’s a service mesh?And why do I need one?,William Morgan
服务网格是一个基础设施层,用于处理服务间通信。云原生应用有着复杂的服务拓扑,服务网格保证请求在这些拓扑中可靠地穿梭。在实际应用当中,服务网格通常是由一系列轻量级的网络代理组成的,它们与应用程序部署在一起,但对应用程序透明。
实施微服务架构时,需要解决问题(服务注册、服务发现、负载均衡、熔断、限流等)的本质是保证服务间请求的可靠传递。站在业务的角度来看,无论上述逻辑设计的多么复杂,都不会影响业务请求本身的业务语义与业务内容发生任何变化,实施微服务架构的技术挑战和业务逻辑没有任何关系。
回顾前面提到的 TCP/IP 协议案例,我们思考是否服务间的通信是否也能像 TCP 协议栈那样:“人们基于 HTTP 协议开发复杂的应用,无需关心底层 TCP 协议如何控制数据包”。如果能把服务间通信剥离、并下沉到微服务基础层,工程师将不再浪费时间编写基础设施层的代码,而是将充沛的精力聚焦在业务逻辑上。
第一代服务网格由一系列独立运行的代理型服务(Sidecar)构成,但并没有思考如何系统化管理这些代理服务。为了提供统一的运维入口,服务网格继续演化出了集中式的控制面板(Control Plane)。
典型的第二代服务网格以 Google、IBM 和 Lyft 联合开发的 Istio 为代表。根据 Istio 的总体架构(见图 8-8),第二代服务网格由两大核心组成部分:一系列与微服务共同部署的边车代理(称为数据平面),以及用于管理这些代理的控制器(称为控制平面)。控制器向代理下发路由、熔断策略、服务发现等策略信息,代理根据这些策略处理服务间的请求。
遥测数据(telemetry data)是指采样和汇总有关软件系统性能和行为的数据,这些数据(接口的响应时间、请求错误率、服务资源消耗等)用于监控和了解系统的当前状态。
实际上,软件领域的观测与上述火箭发射系统相似,都是通过全面收集系统运行数据(遥测数据),以了解内部状态。因此,观测本质上是一种数据收集与分析的科学,旨在帮助解决复杂系统中的故障检测、性能优化和风险预警等问题。
可观测性与监控的关系
监控告诉我们系统哪些部分是正常的,可观测性告诉我们系统为什么不正常了。
——by《高性能 MySQL》作者 Baron Schwartz
业界将系统输出的数据总结为三种独立的类型,它们的含义与区别如下:
指标(metric):量化系统性能和状态的“数据点”,每个数据点包含度量对象(如接口请求数)、度量值(如 100 次/秒)和发生的时间,多个时间上连续的数据点便可以分析系统性能的趋势和变化规律。指标是发现问题的起点,例如你半夜收到一条告警:“12 点 22 分,接口请求成功率下降到 10%”,这表明系统出现了问题。接着,你挣扎起床,分析链路追踪和日志数据,找到问题的根本原因并进行修复。
日志(log):系统运行过程中,记录离散事件的文本数据。每条日志详细描述了事件操作对象、操作结果、操作时间等信息。例如下面的日志示例,包含了时间、日志级别(ERROR)以及事件描述。日志为问题诊断提供了精准的上下文信息,与指标形成互补。当系统故障时,“指标”告诉你应用程序出现了问题,“日志”则解释了问题出现的原因。
链路追踪(trace):记录请求在多个服务之间的“调用链路”(Trace),以“追踪树”(Trace Tree)的形式呈现请求的“调用”(span)、耗时分布等信息。
为便于理解和使用不同类型的指标,Prometheus 定义了四种指标类型:
处理日志本来是件稀松平常的事情,但随着数据规模的增长,量变引发质变,高吞吐写入(GB/s)、低成本海量存储(PB 级别)以及亿级数据的实时检索(1 秒内),已成为软件工程领域最具挑战性的难题之一。
2010 年 4 月,Google 工程师发表了论文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》[1],论文总结了他们治理分布式系统的经验,并详细介绍了 Google 内部分布式链路追踪系统 Dapper 的架构设计和实现方法。
如今的链路追踪系统大多以 Dapper 为原型设计,因为它们也统一继承了 Dapper 的核心概念:
可观测性领域的性能剖析(Profiling)的目标是分析运行中的应用,生成详细的性能数据(Profiles),帮助工程师全面了解应用的运行行为和资源使用情况,从而识别代码中的性能瓶颈。
性能数据通常以火焰图或堆栈图的形式呈现,分析这些数据是从“是什么”到“为什么”过程中的关键环节。
火焰图分析说明
分析火焰图的关键是观察横向条形的宽度,宽度越大,函数占用的时间越多。如果某个函数的条形图出现“平顶”现象,表示该函数的执行时间过长,可能成为性能瓶颈。
核心转储(Core dump)中的 “core” 代表程序的关键运行状态,“dump” 的意思是导出。
正是因为以应用为中心,整个云原生技术体系无限强调基础设施更好地服务于应用,以更高效的方式为应用提供基础设施能力,而不是反其道行之。而相应的,Kubernetes 也好、Docker 也好、Istio 也好,这些在云原生生态中起到了关键作用的开源项目,就是让这种思想落地的技术手段。
分析 Kubernetes 的工作原理可以发现,无论是 kube-scheduler 调度 Pod,还是 Deployment 管理 Pod 部署,亦或是 HPA 执行弹性伸缩,它们的整体设计都遵循“控制器模式”。
最近拿到一个VC6 MFC编写的遗留程序源代码,需要将其升级到最新的Windows系统,记录一下升级过程。
程序是从Main(WinMain)开始和结束。 但是在Main(WinMain)开始之前会对全局的变量或者对象进行初始化。
故在MFC中,通过全局类(theApp) 的初始化, 进入theApp的构造函数,根据类的规则,初始子类的构造函数,必须先要运行父类的构造函数。 在这过程把包含WinMain的文件连接了进来。 这样就隐藏了WinMain函数。
在WinMain函数中调用了AfxWinMain函数,在AfxWinMain函数中通过调用InitInstance函数完成了窗口的设计 窗口的注册 窗口的创建 窗口的显示和更新。然后在AfxWinMain中调用了Run方法,完成消息循环。
遗留程序依赖 MFC 扩展库BCGControlBar,因此需要安装和配置 BCGControlBar,否则编译链接出错。例如:
BCGCBProInc.h : No such s file or dictionary. 解决方案:安装BGB界面库
BCGControlBar是一个基于MFC的扩展库,您可以通过完全的用户化操作构成一些类似于Microsoft Office 2000/XP/2003和Microsoft Visual Studio.NET的应用程序(用户工具栏、菜单、键盘等等)。BCGControlBar库包含了大约150多个经过精心设计,测试和具有完备文档的MFC扩展类。这些都可以很容易的应用于您的应用程序,节省大量的开发和调试时间。
在编译之前,要先设置其附加包含目录和附加库目录。
vc6.0在其tools>>options>>directoris下进行设置。在show directories for选择include files,添加BCGControlBar安装目录下的BCGCBPro目录。
然后再选择show directories for下的Library files并添加BCGControlBar安装目录下的bin目录。
遗留程序依赖 MFC 扩展库 MapX,因此需要安装和配置 MapX,否则编运行出错。
MapX控件是Map Info公司向用户提供的具有强大地图分析功能的ActiveX控件,适用于大多数面向对象语言,可以无缝嵌入到各个领域的应用系统当中去。
层叠样式表(Cascading Style Sheets,缩写为 CSS)是一种样式表语言,用来描述 HTML 或 XML(包括如 SVG、MathML 或 XHTML 之类的 XML 分支语言)文档的呈现方式。CSS 描述了在屏幕、纸质、音频等其他媒体上的元素应该如何被渲染的问题。
通常在开始一个新的项目之前,应对CSS进行重置,建立一个基线,以便使网页在不同浏览器上有一致的显示。