kubernetes之ingress的基本使用
由于最近服务迁移,进行了各种调整,调整的过程中也顺便修改了 ingress 的相关配置,发现这块之前没有写过,于是今天就来看看 ingress 的基本使用。
其实 ingress 本身不复杂,只要理解了概念,很快就能上手。
PS:本文需要前置知识点 kubernetes 的 service
什么是 ingress
如果用一句话总结什么是 ingress,那我觉得:ingress 就是 service 的 service
其实 ingress 就是在 service 之前再加入了一层网关/路由,根据配置的不同规则,将请求路由到不同的 service 中,然后对外集群只暴露一个访问的地方
为什么需要 ingress在 k8s 集群中,我们知道,想要暴露一个 deployment 那么就需要创建一个 service,这个 service 会帮助我们路由到多个 pod 上。但 service 想要被外部访问,有下面几种方式:
ClusterIP 只能内部访问
NodePort 需要占用端口,当服务数量多,管理麻烦
LoadBalance 要么自己用轮子(metallb)也会占用端 ...
《笨开发学习操作系统》6输入输出系统
当你敲键盘的时候,为什么显示器会显示字符?
当我们第一次使用电脑的时候,你会觉得神奇吗?为什么我们在键盘上敲击或者使用鼠标进行点击,就能实现各种操作;为什么显示器会显示出这些图标?这些用户操作的背后,是谁在同一管理他们呢?
今天我们就来说说,这些看得见摸得到的人际交互设备与我们操作系统的输入输出系统的关系。
设备分类首先,我们来对我们常见的输入输出设备大致进行分类:
块设备:每个块有自己的地址,信息存储在对应的块中,如硬盘
字符设备:没有结构也无法寻址,都是直接传递的字节流,如鼠标
网络设备:也就是我们常说的 socket,数据单位是网络包。
然后我们将开始一步步的探索:首先,我们计算机中的大脑(CPU)要控制这些设备,比如想要控制显示器显示数字,还需要接收来自一些设备的控制,如键盘的输入等。那么形形色色的设备都需要进行管理,我们的 “大脑” 就需要 “手” 来帮忙,这就是设备控制器。
设备控制器键盘、鼠标、显示器…. 设备之间功能不同,为了统一管理,每个设备都有一个设备控制器。设备控制器可以帮助我们屏蔽不同设备之间的差异。
设备控制器有寄存器,这些寄存器用来与 CPU 进行通 ...
《笨开发学习操作系统》5文件系统
在 Linux 中一切皆文件
这是我们经常能听到很多大佬说的一句话,那为什么说 Linux 中都是文件呢?这句话究竟代表着什么具体的含义呢?在操作系统中,文件系统又扮演着一个什么样的角色?作为一个普通的开发者,我们究竟对文件系统要有怎么样的认识?今天我们就来看看这个大哥 —— 文件系统
文件在认识文件系统之前,首先来看看我们的文件是什么。当我们在 Linux 系统上创建的一个文件,究竟有哪些东西?是只有文件内容本身吗?
文件的两个数据结构首先,来认识今天的第一个重点:
index node: 索引节点
directory entry: 目录项
索引节点当我们创建一个文件的时候,其实不仅仅只是创建了文件本身的内容,还有很多相关的属性也被创建了,如:这个文件的访问权限,修改时间等等。我们的索引节点(index node) 就是我们常说的 inode,这个结构中就存放了文件的必要属性,也被称为文件的元数据。
1234567891011121314151617/* * Structure of an inode on the disk */struct ext4_inode { ...
《笨开发学习操作系统》4进程间通信
在操作系统中,两个进程之间是如何进行通信的?
随着我们的应用系统越来越大,单进程往往无法满足我们的要求,将一个大的系统拆分成多个功能模块,解耦,往往是一种常用的设计。无论是从将功能模块化、数据隔离等方面考虑,多进程协作都有着优势。
那么就意味着进程之间需要进行数据的传递,于是进程间通信(Inter-Process Communication)也就是我们常说的 IPC 就非常重要了。今天我们就来看看有哪些方式能实现 IPC。
大纲,我们主要围绕着 IPC 的方式展开,今天比较简单:
共享内存
管道
信号
信号量
消息队列
套接字
管道
1ps -ef |grep target
通过 shell 的管道符号 “ | “,将第一个命令的输出通过管道作为第二个命令的输入。
特点:
单方向:由一方发送,另一方接收
使用功能内存作为缓冲区,没有持久化
创建:
匿名管道:通过 pipe 系统调用创建
命名管道:通过 mkfifo 创建
其实本质是创建了两个文件描述符,然后通过内存作为缓冲区,来实现通信。
消息队列
UNIX 系统提供了 System V 消息队列来作为一种进程间通信 ...
go 中 struct 是否可以比较?
今天来水一篇,最近比较忙,一直没有时间写 go 相关的,今天从一个小问题入手,来说说 struct 的比较问题。
由于已经有很多其他的文章说过这个问题,我这里赘述就显得多余,所以我直接给出结论,并直接说明在实际中用的上的。
为什么要比较?原本这应该是某人想出的面试题,但是如果光光是解决这个问题的话,太应试了。大白话就是,谁没事去比较两个 struct 呢?为什么要比较呢?
那比较的原因,肯定是我们需要知道两个结构体是否相等。
比较的依据两个结构体是否相等,比价的依据有两个:
两个结构体的地址是否相等?(比较地址)
两个结构体中的所有字段是否都相等?(比较内容)
重点1:如果两个 struct 类型不同,一定是无法比较的,会直接编译报错,也没有人这么干吧。。
比较地址其实大多数情况下,我们不需要知道这个问题的答案,至少我无法想象到为什么要比较两个对象的地址是不是一样。
123456789101112131415package main import "fmt" type User struct { Name string ...
《笨开发学习操作系统》3内存
OOM 往往是我们经常遇到的 “严重” 问题之一,那内存究竟是如何被合理分配和使用的呢?
本期大纲
首先我们要知道一个重要概念就是 虚拟地址
虚拟地址和物理地址的映射关系
内存中放了什么东西
内存是如何分配的
内存不够了怎么办
前言你的电脑上或许此时插着一根 8G 的内存条,你经常在使用它,但你有没有想过操作系统是如何管理内存的?如果让你来分配使用,你是否会想着:给正在运行的游戏分配其中的 4G,给我的视频软件分配 2G,给音乐软件分配 1G,分配各自独立,互不干扰。但当我的游戏需要更多的内存的时候,是否我的视频就无法播放了呢?
那么对于操作系统来说,如何合理的分配和管理好内存就是我们今天要解决的问题。
虚拟地址首先要引出一个概念:虚拟地址。我们将实际在内存条上存储的地址称为:物理地址。所谓虚拟地址,就是我们人为创建的一个地址,对于进程来说,只能看见虚拟地址。
为什么需要虚拟地址就像前言中所描述的,如果我们直接都使用物理地址会出现什么问题呢?
随着程序的运行,使用的内存不断变化,我们无法预见到需要使用多少内存,无法事先分配;即使事先分配,也会造成使用浪费。
如果不事先分配, ...
《笨开发学习操作系统》2进程
进程和线程有什么区别?一个常常被问到的面试题
我们在实际的开发过程中,经常打交道的就是线程,而进程呢,通常就是我们整个运行的程序。对于他们两个来说其实并不陌生,你要让我说出个一二三也可以讲,但可能也都是从使用的角度,而今天我们就从 操作系统 的角度来重新认识一下他们两个(从内核的角度看进程和线程长什么样)。
大纲:
首先我会让你直观感受我们的进程和基本的分类
优先理解他们的数据结构
状态的变化是非常重要的一环
接着是重点:如何创建他们
最后再来看调度
你所需要把握的重点是:结构、创建和调度。这些对于以后的开发或是问题的解决都是有着密切联系的。
进程的直观感受首先让我们从实际角度来直观感受什么是进程,通过 ps -ef 命令可以查看当前进程的相关情况
1234567891011121314151617181920212223242526UID PID PPID C STIME TTY TIME CMDroot 1 0 0 2021 ? 00:38:48 /usr/lib/systemd/systemd ...
《笨开发学习操作系统》1启动
问问自己,如果你都不知道计算机是怎么启动的,那以后怎么修电脑呢?
虽然我们程序员不是修电脑的,虽然计算机启动到操作系统启动这个部分其实对工作的意义可能不大,但就是上面说的那句话,不知道启动,总是说不过去的,所以我还是单独把它拿出来,作为我们万里长征的第一步。
那你是否想过,当你按下开机键的那一刻,电脑做了什么事情呢?是不是直接读取操作系统的代码,然后一条条往下执行,最终就启动了整个系统,然后你就可以使用了?其实整个启动过程复杂而又神秘。
回忆让我们先来看两张图
你是否曾经在开机的时候见过这两个画面?没错,蓝色的这张是 BIOS,而黑色的这张则是 GRUB,为什么我要先拿这两张图出来呢?没错,其实操作系统的启动过程你需要记住这两个画面,今天你就能通过下面的学习将原有的这两幅画面串起来了。
前置知识点首先来标记一些你需要了解的基本术语和概念,方便我们后面的描述和讨论。
ROMROM(read-only memory) 只读内存,开机程序就在这里面
BIOSBIOS(Basic Input/Output System) 基本输入输出系统,如果你自己尝试重装操作系统,应该对它 ...
《笨开发学习操作系统》0前言
本专栏就是为了记录从一个普通开发的视角去学习操作系统基础知识的过程,其中的“笨”开发就是指作者我
面向的用户
可能没有系统学习过操作系统的基础知识,或是大学学了之后就忘了
常年的业务开发,却没有怎么了解操作系统相关的知识
看了操作系统的书就觉得困,觉得无法继续坚持
如果你和曾经的我一样,也有这样的问题,那么我觉得份专栏应该会对你有用。
学习的角度我将从一个”笨”开发的学习视角让你从一个不一样的角度来学习操作系统的知识,我尽可能的做到简单易懂并且能联系实际,让知识本身不过于枯燥。
其实对于很多业务开发的工程师来说,操作系统是经常打交道的,但是一旦学习起来就会发现,它的知识大多是无法在实际的生产马上发挥作用的,对于这种及时正反馈很差的知识来说,学习起来就会变得很困难。
于是我就在学习的过程中开始整理,将学习的知识尽可能的联系我们的业务,或是代码的设计,或者是中间件的使用,从其他方面着手去理解和学习这些知识。希望我整理的整个学习过程和思路可以帮到准备开始迈出第一步的你。
广度和深度作为一个普通的开发者,我觉得,对于操作系统来说,如果你不是做内核开发或是运维开发,或是嵌入式开发,总之如果 ...
kubernetes调度之分配规则
前言
正所谓每一次事故都是一次成长
事情是这样的,最近行业不景气(摆烂),由于业务收缩,所以需要对其中一个小的 k8s 集群中的节点做收缩,下掉几台不需要使用的服务器,在对 k8s node 做变更的时候出现了一个意外:coredns 在某个 node 被删除之后重启后发现无法正常启动,并且出现报错
0/7 nodes are available: 3 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn’t tolerate, 4 node(s) didn’t match Pod’s node affinity.
在救火之后,让我想到,之前没有写过和调度相关问题的博客,于是今天先来说一些最基本的规则,让我们能控制一个 pod 能被调度到整个集群的哪一个 node 上去。本文最后回过头再来解决这个问题。
其实合理的控制 pod 调度也是我们一个非常实用且必会的技能之一。
nodeName这个很少用到,也最简单最粗暴,就是直接指定你这个 pod 只能到哪个 node 上去。 ...
工作默默无闻的sysmon
sysmon 默默无闻的后台监控golang 里面里面有一个默默无闻的工作者在后台跑着,它的名字叫 sysmon ,你可能在某个地方见到过它。我最早是在 gc 中第一次见到了它,当时只知道默认有一个两分钟的 gc 是由它来控制的,那么它究竟还做了什么工作呢?今天我们就来看看它。
启动首先让我们来看看 sysmon 是谁启动的。
123456789101112131415// The main goroutine.func main() { ........... if GOARCH != "wasm" { // no threads on wasm yet, so no sysmon // For runtime_syscall_doAllThreadsSyscall, we // register sysmon is not ready for the world to be // stopped. atomic.Store(&sched.sysmonStarting, 1) systemstack(func() { ...
博客装修(2022年3月)
博客装修记录一(2022年3月)
过去一年都没有装修我的博客,虽然还看的过去,但是见过了很多大佬的魔改之后发现改进的地方还有很多,于是花了一周的时间进行了这个主题的第一次装修
装修主要改变
新增主页顶部推荐分类
新增主页顶部固定栏目
新增用爱发电页面
将部分公用图片资源挪到 cdn 下
修改评论组件
调整分页等字体、背景颜色、图标等
…
下面我先来说说如何装修的
新增页面元素新增主页顶部推荐分类、新增主页顶部固定栏目 这两个装修都是通过新增页面元素来完成的
大致步骤 :
在 theme\butterfly\layout\includes 新增所需页面元素的 xxx.pug
然后所需页面,如 index.pug 引入
添加自定义 css,在 _config.yml 文件的 配置项 inject 中配置即可
其实关键还是在你需要熟悉 pug 的语法和 css 的语法,就很快能实现你所需要的功能,如果不熟悉的话还需要参考别的大佬的魔改后的样式,然后照着修改
pug 的语法参考 https://sobaigu.com/hexo-pug-notes.html
新增页面这个很简单,只需 ...
loki 自定义部署配置
loki 自定义部署配置前言之前有简单的提到 loki 的部署和基本的一些使用,能支持用户最基本的在 k8s 中的部署和使用,非常简单。但是因为很多配置是默认的以至于并不满足需求,所以这里就来更新一下一些自定义配置的更改以便更好的支持当前的使用。下面举例包括:
过期日志如何删除?如何只保留 14 天的日志
如何更换 loki 的存储位置
非 stdout 输出日志的项目如何进行日志采集?
日志采集 promtail 配置有什么需要注意的地方
下面以 helm 默认部署 loki 之后为例进行修改
如何配置定期删除过期日志我们最常见的一个需求就是只保留固定天数的日志,因为由于日志量大,所以过期的日志不做保留,以避免磁盘占用量过大。那么在 loki 里面配置也很简单。
官方文档位置:https://grafana.com/docs/loki/latest/operations/storage/retention/
如果你使用 helm 进行部署,那么 loki 的配置文件位置是在 Secrets 下的,名称默认为 loki。
123456789101112131415161718192 ...
k8s StorageClass使用攻略
在 k8s 中当我们需要持久化存储一些数据的使用,会使用到的就是 PV 和 PVC,但 PV 和 PVC 都是需要手动创建的话会很麻烦,特别是当有 StatefulSet 应用存在的时候,如果你需要手动对每个 pod 都创建一个 PVC 和 PV 就非常麻烦,于是 StorageClass 就是来解决这个问题的。
准备首先你需要一个 nfs 或其他存储,这里我以 nfs 为例进行部署
我们先来梳理一下思路和几个需要的东西:
nfs 是我们最终的存储
nfs-client 是用来动态创建 pv 和 pvc 的,我们称为 provisioner
StorageClass 关联到对应的 provisioner 就可以使用
statefulset(或别的资源)需要配置 storageClassName 进行使用
部署创建 ServiceAccount创建对应需要使用的 ServiceAccount,因为需要操作 pv 和 pvc
123456789101112131415161718192021222324252627282930313233343536373839404142apiV ...
go 应用在 k8s 中如何优雅停止
每次当我们发布新版本的时候总是慌兮兮,一方面是担心有 bug,另一方面其实重启应用会带来一些抖动,可能有几秒钟或者几个请求的不正常,从而担心用户在这段时间内的操作。那么如何在应用重启的过程中尽可能的保证不会带来抖动,从而平滑又优雅的重启呢?
本文只针对于应用版本更新时,进行版本发布时进行的重启操作,从而导致的相关问题的解决。不涉及由于应用本身 panic 导致的重启,也不涉及蓝绿发布或回滚等操作。当前版本更新是在 k8s 中进行的重启操作,访问负载均衡交由 k8s 的 service 处理,再上层的网关层面的负载则不在本次讨论范围内。
通过本文你可以学到:
go 应用优雅退出所需要做的事情
go 应用优雅退出 k8s 所需要的配置
k8s 应用关闭时 pod 的生命周期
测试程序先写一个最简单的测试程序(当然有很多压测工具都能满足需求,但是我还是想自己弄个最简单的,不想搞复杂),当然这个测试程序不能满足所有使用场景和情况,如并发的一些场景等,只是为了展现出固定的问题。
1234567891011121314151617181920212223242526272829packag ...
defer 原理分析
很早之前我有写过有关 defer 的博客,现在看来起标题的时候有点蠢,有点标题党,(https://www.linkinstars.com/post/48e6221e.html) 其中主要是注重与 defer 的使用,避免使用上的问题,对于 defer 具体实现其实只是点了一下,而今天就让我们详细看看 defer 究竟是如何实现的。
前置知识点
在阅读本文之前你可能需要有两个基础知识前提
defer 的基本使用规则
逃逸分析:https://www.linkinstars.com/post/1ceb1a77.html
函数调用规约:https://www.linkinstars.com/post/fecd400.html
因为在 1.14 之后 defer 是有优化过的(https://golang.org/doc/go1.14#runtime),所以需要注意,本文使用的 go 版本是 1.17
引子问题
编译器是如何处理 defer 关键字的?
defer 的执行顺序是怎么样实现的?
defer 数据结构首先我们来看看 defer 究竟是长什么样子
1234567891 ...
go 函数调用规约
函数调用规约?如果你是第一次听到这个名词可能会有疑惑,这是在说什么?难道两个函数之间调用还需要约定什么吗?难道不是定好入参出参就可以了吗?没错函数的调用规约其实就是:我在调用其他函数的时候我的参数和返回值要如何分布?
那么其实在 golang 底层函数的调用还是有很多细节的,比如你的入参放在哪里?返回值存放在哪里?相信看完这篇你就都明白了。
栈
首先我们定一下基调,因为我们今天讨论的是函数调用规约,所以我们今天的主角是栈,没有堆什么事,也就是说,所有变量都默认分配在栈上,不考虑逃逸的情况
栈的样子先来看看我们今天主角的样子:
我们今天说的要说的栈,其实应该叫调用栈 call stack 而不是我们平常说的数据结构中栈。栈的增长方向是从高位地址到低位地址向下进行增长的,栈底是我们的高地址,而栈顶是我们的低地址,栈的作用是存放程序执行过程中使用的局部变量。
调用规约说简单也简单,说复杂也复杂,这里准备由浅入深,首先用一张图来直接描述 go 里面的函数调用规约究竟是怎么样的
左边是调用者栈情况,右边是被调用者栈情况
可以看到调用者栈里有本地的一些变量、当前调用函数的返回值、调用函 ...
go 中其实不复杂的 timer
在 go 中当我们需要延迟一段时间后执行,或者需要间隔固定时间去执行某个行为的时候就需要使用到 timer,那么 timer 到底是如何实现的呢?我们今天就来看看 timer 里面是什么样的。
同时因为 1.14 版本前后 timer 的实现有很大的区别,我们顺便来了解一下之前的版本和现在的版本有什么样的不一样,到底做了什么样的优化。
前置知识点有以下的知识点支持才能更好的理解今天的分析
需要有 GMP 模型的基础
需要有 go 调度相关的基础
需要有数据结构中’堆‘的基础
ticker要看 timer 可以先从 ticker 入手,ticker 其实我们经常使用到,ticker 顾名思义就是每次间隔一段时间触发一次,下面我们就来看看它的具体实现
带着问题
Ticker 如果当前时间到了,没有及时处理,下一次时间到了,会保留吗?是都在后面排队,还是直接被丢弃了?
NewTicker() 和 Tick() 有什么区别?使用上需要注意什么?
数据结构123456// A Ticker holds a channel that delivers ``ticks'' ...
我怎么从来没见过 sync.Cond
sync.Cond 作为 go 标准库提供的一个并发原语,但是可能你从来没听过,可见它使用场景挺少的,但是我们需要有这个知识储备,只有储备了之后才能在需要用的时候用出来。
其实如果你之前和我一样接触过 java,那么其实对于这个并发原语其实应该很熟悉,其实就是常说的等待通知机制,也就是 wait 方法和 notify 方法。
使用我们首先从使用的角度的出发,先来看看 cond 是如何使用的
三个方法首先我用最白话的方式描述一下 cond 的三个方法
Wait 当前调用者等待执行,直到被唤醒,调用该方法时需要加锁
Signal 唤醒一个调用者
Broadcast 唤醒所有调用者
一把锁一个队列cond 初始化需要传入一个锁,用于并发控制,调用 wait 的时候需要加锁
cond 内部维护着一个队列,等待调用者排队等待
使用我们创建两个 goroutine 使用 cond 等待执行任务,然后使用 signal 方法唤醒试试
123456789101112131415161718192021222324252627282930package mainimport ( " ...
golang 使用 rabbitmq 延迟队列
你在实际业务中是否有遇到过下面这样的场景:
订单十分钟没有支付,自动取消
用户注册成功后无任何操作,一天后自动提醒
预定票之后,在出发之前的一天自动提醒用户
这样类似的场景经常会发生在实际的业务中,它们总有一个共性,就是当前并不是马上触发,而是需要过一段时间才进行触发,当触发时间到达时才进行具体的执行。那么问题就来了,为了实现这样的功能,我们如何更加灵活的实现呢?
为什么使用延迟队列我们以 订单十分钟过期 场景举例:
方案 1:为当前订单创建一个定时器,定时器时间到了之后自动去查询当前订单状态,如果没有支付,则进行取消操作
方案 2:设定一个总的定时器,每一分钟检查一次,当检查发现过期的订单就直接进行取消操作
方案 3:如果你有一个延迟队列,你只需将任务丢进去,等到了对应的时间,这个任务会出队,然后出队的时候进行订单过期时间判断
方案比较正所谓抛弃场景谈方案都是耍流氓:我的观点也很明确,这三种方案都有自己所试用的场景。
方案 1如果全局只有一个用户,并且这个订单又是那种量比较小的,可能每天有个 30 个已经撑死了,这样的后台的系统,可能都谈不上需要高可用的情况,那么方 ...
K8S之CNI
之前我们解决了跨主机间容器间通信的问题,但是这也只能说我们铺好了路,村里通路了,但是其实作为 k8s 来说,还有好多其他的问题等待着我们解决。今天我们就通过这些问题来看看 k8s 的 CNI 的设计。CNI 到底究竟是个什么东西,到底是不是和你想的一样那么困难。
问题IP 分配我们知道 k8s 整个集群里面有许多的 pod 那么 IP 怎么分配呢?总不能分配着之后出现 IP 冲突了吧。k8s 集群里面是不是能不有一个类似 DHCP 的东西来管这个 IP 地址分配呢?
流量转发当流量打到宿主机上时,应该有一个什么设备来快速将请求转到对应的 pod 才对吧?那么谁来做这个事情呢?
那为了解决上面的问题,我们一步步出发。
k8s 网络模型首先有关 k8s 的网络模型,官网有下面的描述:(https://kubernetes.io/zh/docs/concepts/cluster-administration/networking/)
节点上的 Pod 可以不通过 NAT 和其他任何节点上的 Pod 通信
节点上的代理(比如:系统守护进程、kubelet)可以和节点上的所有Pod通信
...
K8S之跨主机通信
你是否之前看过 k8s 的网络部分,第一次看是否会觉得很困难?或者说你有没有想过为什么 k8s 要这样设计它的网络,跨主机之间的网络通信究竟是怎么实现的?今天就来搞一篇干货,其实想写这个很久了,但是一直拖延症,这次正好碰到了一个新的点想让我仔细重新审视一下。
本文可能需要你有以下知识基础:
docker基本原理
k8s基本架构
网络基础知识
本文不想引出过多细节的概念,因为网络本身确实有很多细节,每一个细节其实都可以写一篇,如果篇幅过长就会让人觉得没有重点,于是本文的重点将会放在从外部的大视角来看跨主机的网络通信,其中的细节先挖坑,后面慢慢填。
引子问题我们知道 k8s 往往会有很多主机进行集群的部署,k8s 要管理很多 pod,而这些 pod 里面有很多容器,每个容器都是一个小的服务,服务与服务之间往往需要互相访问,而 pod 并不总是在同一宿主机上,那么问题来了:k8s 是如何做到让服务之间能够互相访问的呢?这里网络的链路到底是怎么走的?
时刻记住,本文将围绕这个问题展开。
假设和思考如果说每个容器都绑定一个宿主机的端口来进行通信,那么一旦容器很多就要占用非常多的宿主机的 ...
go 中没怎么用过的 sync.Map
我们知道 golang 的 map 并发会有问题,所以 go 官方在 sync 包中加入了一个 sync.map 来作为一个官方的并发安全的 map 实现。
如果你了解过 java 中常用的一个并发安全的 map 叫做 ConcurrentHashMap 就会知道它有两个亮点设计:一是当链表长度过长的时候会转换为红黑树的实现,还有一个就是分段锁。得益于这两个设计也导致 java 中实现的代码非常复杂,偷笑。
那么 go 里面是如何设计的呢?今天我们就来看看它是怎么实现的。
PS: 本文 go 源码基于版本1.16.2,我觉得当有了泛型之后这个库十有八九是要改的….
数据结构定义123456type Map struct { mu Mutex read atomic.Value // readOnly dirty map[interface{}]*entry misses int}
123456// readOnly is an immutable struct stored atomically in the Map ...
k8s 基于角色的权限控制 RBAC
RBAC 之所以一直没有写这个,一方面是因为它确实并不复杂,二来平常确实接触不多,今天就来顺路讲讲它
定义Role-Based Access Control 我们常说的 RBAC,我们知道在一个后台管理系统里面经常会有权限管理。而最常用的一种权限设计方式就是基于角色的权限设计,A 用户是管理员拥有所有的权限,B 是普通用户角色只有部分权限等等,而 k8s 也是如此,k8s 内部也有许许多多的资源,通过 RBAC 的权限设计进行管理授权工作。
Role: 角色,定义了一组对 Kubernetes API 对象的操作权限
Subject: 用户,绑定角色的对象
RoleBinding: 用户和角色的绑定关系
其实非常好理解: 用户 -> 角色 -> 权限
Role123456789apiVersion: rbac.authorization.k8s.io/v1kind: Rolemetadata: namespace: default name: pod-readerrules:- apiGroups: [""] # "" 标 ...
k8s 部署 prometheus
看到很多部署 prometheus 到 k8s 集群的教程,发现都是非常麻烦的各种配置,懒人的我就想整个一键部署的,开箱即用的,既然有了 helm 那肯定只要一个 charts 就可以搞定了吧,想着就是这样,所以在网上找来找去,终于被我发现了。下面记录一下使用过程,方便以后进行部署。
PS: 本文适用于开发者单 k8s 集群部署 prometheus,如果是运维可建议进行独立部署,一方面不需要占用集群内部资源并保证多活,另一方面可以支持多集群扩展。
安装12345# helm 添加对应 repohelm repo add prometheus-community https://prometheus-community.github.io/helm-charts# helm 安装 可以添加参数 --set rbacEnable=true,-n 指定安装的 namespacehelm install prometheus prometheus-community/kube-prometheus-stack -n monitoror
默认用户名密码admin/prom- ...
让你最快上手 go 的 pprof 性能分析大杀器
前言,发现一直没有记录过 pprof 分析的博客,其实在实际的业务场景中已经使用它很多次了,对于性能分析来说它真的是一大杀器,基本上有了它,80% 的性能问题都能被一目了然。每次出现性能问题,总是下面几个步骤,测试环境开 pprof,启动,流量重放,火焰图生成,一看,仔细分析一下,问题就浮于水面。
今天来用最简单的一个案例,来让你快速上手 pprof,所以本博客包含以下内容
最快能让你用上 pprof
能让你最快学会认识火焰图
学会了之后其他剩下的功能你就可以慢慢自己摸索了
废话不多直接上案例
前期准备首先你肯定有 go 环境,需要看火焰图还需要安装 graphviz http://www.graphviz.org/download/
第一个坑来了,如果 mac 使用 brew install graphviz 安装容易出现失败,还有很多奇怪的依赖如 svn java 等,所以建议使用 sudo port install graphviz 安装
问题发现
使用一些监控软件发现问题,如当前我发现有一个项目在刚启动之后,其他相同类似的项目 cpu 使用都是 20 多,但是它有 ...
初识 CGO - 利用 CGO 使用 C++ STL
之前我也了解过 CGO 相关的知识,但是当时给我的印象全部都是 “CGO 性能差” “完全没有必要,实际根本用不到”,但是这次听了大佬的一些分享发现 CGO 其实就是黑科技啊,有了它你在使用 go 的时候有了更多的想象力。本文将带你初步了解和使用 CGO,本文只是抛砖头,因为有关 CGO 的文档其实蛮少的,在其中也有很多坑,所以今天来踩一次,不知道会不会留下什么坑….
有了 CGO,Go 就有机会继承 C/C++近半个世纪的遗产 by 曹大
CGO 使用案例分享 首先来看一下最近我看到使用 CGO 的两个案例
案例 1 mosn
https://github.com/mosn/mosn
其中 mosn 通过 CGO 的能力,想办法在 envoy 后面加了一层,使得其底层网络具备 C 同等的处理能力的同时,又能使上层业务可高效复用 mosn 的处理能力及 go 的高开发效率。
案例 2 主动式缓存
这个 GopherChina 上一个学而思网校的分享,主要讲的是如何设计一个主动式内存缓存,其中提到了 Go 的 GC 导致当有大量内存缓存的时候,对象数量过多,GC 扫描 ...
Golang逃逸分析
逃逸分析,看着一个非常高大上的名词,很多人第一次听到它的感觉会觉得它好厉害的样子,其实说到底它很好理解,并不复杂。之前一直没有写也是有原因的,因为其实在实际中,我真的很难用上它。这次写也是有原因的,因为有人催更了…其实拖了有一段时间了,最近终于忙完了,开始补债了。
栈和堆在说逃逸分析之前,我们需要有一些前置知识点
栈我们常说的栈是一种数据结构,当然这里说的栈特指我们在谈论内存分配的时候说的栈。它的作用是在函数调用的过程中保存函数的参数局部变量等数据。而且当函数调用完毕后,它所使用的栈空间将立即释放。所以它“便宜”。
堆堆的概念我们就应该非常熟悉了,它用来存放很多需要使用的对象,这些对象的生命,在 go 里面是交给 GC 去管理的,当我们再也不使用的时候,GC 会将它们回收。所以它“贵”,因为它需要额外的做功才能将它回收掉。
为什么?那为什么需要堆?不用堆不行吗?其实答案显然不行,因为如果所有的变量对象都在栈上,用完了就扔掉,那么其他人想要再使用的时候就无法使用了。
那全部都在堆上不行吗?答案也很显然不行,因为栈便宜,用完就扔,堆很贵,你不能将所有的东西都扔给 GC,这样它要累死。 ...
GopherChina2021 个人总结
今年本来没想着要去的,因为确实有点远,加上疫情之下不太方便,但是意料之外来了一张门票,那就必须去一下了,这次收获也不少,有了上次的经验,这次就听得很舒服,不像上次那样那么累了,这次能准确的知道什么应该仔细听,什么应该略过,所以这次的笔记就相对来说少一些,精炼一点。
这次去也面基了大佬,果然北京的都是大佬,都比我卷的厉害,以后还要多学习,哈哈哈,膜拜膜拜~
基于 Golang 构建高可扩展的云原生 PaaS 平台端点 PaaS 介绍整个历程 主要是推 Erda,主要有以下几点个人觉得可以
自定义 pipeline 开箱即用
微服务治理 兼容 java 族(spring 那一套,还有 dubbo)
可观察性数据采集
个人总结:写个这的一定是 java 过来的,autowired 很 java 味道
https://github.com/erda-project/erda
MOSN 云原生演进历程MOSN 之前就有听说的,我觉得很像给 Envoy 加个 buff
CGO 并没有想的那么性能堪忧
通过 hacker 的方式可以在调用链路中加一层 filter 实现
想办法做到 zer ...
轻量级 k8s 应用日志收集方案 loki
微服务早已是一个过时的热词,同时,容器 和 k8s 的出现让它更一步成为了一种时尚。同样会带来很多附赠的问题,日志收集就是其中一个比较重要的问题。当应用容器化之后,需要查看日志,如果还需要登录服务器,找到对应目录,然后 tail 查看,成本太高了,极大的影响效率。当前其实日志收集方案很多,在实践了多个方案之后,我终于能在今天写出我个人认为我最喜欢的一个方案了 loki
我的需求技术上没有银弹,需要根据实际需求来选择方案,那么我的需求是这样的,你可以做个比较:
当前所有的应用是部署在 k8s 中的,需要收集所有的应用的日志到一个地方做展示
部署最好要轻量,对于性能要求并不高(当前日志量并不大)
日志展示方式友好,能支持基本的时间查询,或者是定位到某个关键字
可选方案从之前的公司包括个人的一些项目上都尝试过很多不同的组合和方案,列举出三个最具有可比性的方案:(以下为个人使用案例,并不能代表所有大众观点,图片来源本地测试服,线上日志不允许公开,但同样禁止转载~)
ELK
这似乎是业界最成熟的日志收集方案之一了,因为无论你问哪个有点经验的程序员,提到日志收集,必然会给到这个,我当然不是 ...
monitoror/monitoror 最轻量的监控大屏
一提到监控大屏,那第一想法就是 grafana 对吧,各种样式图形都非常好看,而且支持各种数据源。而今天要分享的是一个更加轻量的监控大屏 monitoror/monitoror
有了它能帮你快读构建一个的对于网站或者应用的监控页面,特别是在小应用数量多的时候非常简单易用,作为一个大屏展示时它我觉得它足够简洁
demo & repohttps://demo.monitoror.com/
https://github.com/monitoror/monitoror
优点
部署轻量
配置简单
大屏简洁
部署二进制部署https://monitoror.com/documentation/get-started/
非常简单,只需要将二进制文件下载,然后按照要求配置对应的配置文件,就可以了
12chmod +x monitoror./monitoror
配置文件.env
1MO_CONFIG="./config.json"
配置文件config.json
12345678910111213141516171819202122 ...
k8s 意外集锦 - oom 的连锁反应
一开始觉得 oom 是一个常见问题,应该没有什么大问题,反正 k8s 集群会调度的,但其实它造成的连锁反应很恐怖。
问题描述具体简单描述过程:一台机器 OMM, 导致将对应的pod调度到了其他节点上,导致其他节点 OOM 然后开始疯狂输出日志信息,然后导致 master 磁盘不足开始清理并驱逐,然后导致驱逐(Evicted)的应用再次调度到其他节点,然后连锁反应,最终相关大量服务不可用….
pod 出现告警信息 The node had condition: [DiskPressure].
总的来说就是一个 应用的 oom 不停的被调度来调度去,导致日志疯狂的输出,导致磁盘不足了。
问题解决设置合适的内存请求和限制条件限制单个应用的使用内存还是非常有必要的,免得出现很多意外的情况
1234567resources: requests: cpu: 100m memory: 128Mi limits: cpu: 200m memory: 256Mi
应用 bug 修复代码 bug 肯定要修复的,这个毕竟是导致问题的主要原因
升级 ECS 的内 ...
k8s 意外集锦 - configmap 挂载 目录 只读
OCI runtime create failed:
/var/lib/docker/overlay2/6573e40fef5bc51b4e565ad9554f225806f05a9f9089cc9e210c0e35a80e6e1f/merged/etc/resolv.conf: read-only
报错信息123456789Error response from daemon: OCI runtime create failed: container_linux.go:344: starting container process caused"process_linux.go:424: container init caused \"rootfs_linux.go:58: mounting\\\"/var/lib/docker/containers/1ec387b2e168281ed480c5050b08893976ac84a2751691e1a9429ae6a66a ...
k8s 小技巧
本博客持续更新…用于记录 k8s 使用过程中的很多的小技巧,也希望你能提供更多的小技巧来~
图形化管理工具 lens图形化 k8s 管理工具: https://github.com/lensapp/lens
我觉得可以少部署一个 dashboard,并且比官方的 dashboard 好看很多
重启 deployment 命令我一开始总是 delete 一次 apply 一次,感觉很蠢,又换成调整 scle 但是还是很慢,查了之后发现原来本来就有重启的命令
1kubectl rollout restart deployment nginx-dep
查看链接配置信息1kubectl config view --minify --raw
kubectx当你需要使用 kubectl 操作多个集群的时候,可以使用 kubectx 切换 context,非常方便
多集群管理切换工具:https://github.com/ahmetb/kubectx
更新 configmap 脚本对于配置文件 configmap 的更新我真的没有找到合适的命令,直接 使用 kubectl edit 那么原来 ...
Weave Scope 监控 k8s 集群
之前一直在寻找一个 k8s 监控的工具,因为一直使用的是本地的 lens 的客户端,虽然使用上已经非常方便了,但是其实对于资源消耗的监控少了一点,有些资源消耗并不是能容易看到,并且服务间依赖是没有办法表现出来的,后来发现了 Weave Scope 满足了我的需求。
链接https://github.com/weaveworks/scope
特点
资源监控:能实时反映整个集群中的资源状况 cpu 内存 使用情况 并且支持各种角度
服务间依赖:能通过图形展现出服务之间访问的依赖关系
容器交互:实时查看日志和描述信息
支持插件:可以通过插件扩展
部署方便:一个命令即可部署完成
监控页面资源监控
可以清楚的看到每个 node 的资源使用情况
服务间依赖
因为内部服务与服务之间通过 rpc 进行交互,从这里可以很容易看出,某个服务被别的五个服务所依赖调用
容器交互
可以看到占用的 cpu 和内存的情况,然后占用的端口等,还有日志信息
部署支持直接部署在 k8s 集群中,不需要额外的任何配置
https://www.weave.works/docs/scope/latest/installi ...
GopherChina2020 个人总结
之前去过几次相关 go 的线下 meetup,这次相对来说比较大型一些,两天的听下来还是比较烧脑的,光是记录的笔记都有近千行了,整体来说收获很大。
有的人问,值票价吗?我回答:对喜欢的投资没有不值得的。对我来说值了~
有的人问,值得去吗?我回答:不一定,因为可能在很多大佬看来能听到的点不多(采访了几位现场的大厂观众,普遍表示只有其中 1 到 2 场满足他们的要求)但是如果你的小白或者一年到两年左右,还是能见识很多东西的。可能是我听多了,和之前自己学到的有点重复…
下面是个人精炼总结,全是个人总结,自己如果对这个知识或者相关点比较清晰的我就没有记录了。其中会伴随一些个人思考和疑问,可以小声 bb 。大会分 1和 2 会场,所以只能选其中一个听,我也是记录我自己听到的,另外一个会场不清楚(我交叉穿来穿去的)注意并不是有的老师讲的真的不好,而是对我个人来说意义不明显,可能由于知识点已经掌握,也可能是由于工作上确实用不到哦
最后会附上会上笔记,仅做个人使用,乱了也不管~ 最后无论如何,感谢每一位老师的付出~~~
要点总结
分布式数据库设计难题:数据分片,节点加入和减少
如果让你设计一个系统 ...
下一个 nginx?caddy 自动 https 真香
我们通常在部署 web 服务的时候往往会选择 nginx 作为最前面的一个狠角色,它的性能和能力大家也是有目共睹的,反向代理负载均衡等等。而作为后起之秀 caddy 却不被人所熟知,不过渐渐的也开始展露头角。今天我就来介绍这个 caddy ,为什么我会称它有可能成为下一个 nginx。
我先列举几个痛点你看下:
nginx 的配置文件你是否感觉有时候有点臃肿
https 需要购买或者申请证书,然后配置是否觉得麻烦?
linux 下安装 nginx 需要部分依赖
而 caddy 确实给我了一种眼前一亮的感觉。
使用官网:https://caddyserver.com/
安装https://caddyserver.com/docs/download安装很简单,直接下载对应的二进制文件即可,或者按照对应到操作系统去安装也可以。没有其他依赖。
使用https://caddyserver.com/docs/getting-started一个命令就可以启动,caddy,默认会去当前目录下寻找 Caddyfile 配置文件,也可以通过 –config 去指定文件位置
123caddy sta ...
openfaas/faas 环境搭建和开发使用
serverless 大环境下出现了 faas,即 function as a service,函数即服务;其意思也非常好理解,就是能将一个函数作为一个服务进行使用,用户只需要编写一个函数功能即可,不需要额外去关心别的东西。https://github.com/openfaas/faas 是其中的一种实现方式。
环境准备以下环境在 mac 上进行搭建:
首先需要准备 docker 和 kubernetes 的环境,先做 k8s 的环境直接能通过 docker 桌面进行配置,已经算是很方便了。
安装步骤openfaas-cli1curl -sL https://cli.openfaas.com | sh
namespace123git clone https://github.com/openfaas/faas-netescd faas-neteskubectl apply -f namespaces.yml
password12345678$ cat passwd.sh # PASSWORD=$(head -c 12 /dev/urandom | sha1sum |c ...
Golang Mutex 到底是否应该使用指针
在写 go 的时候,你使用 Mutex 的时候使用的是指针还是说没有使用指针,还是随意来?
前两天我收到了下面这样的一个 PR,我突然就想到了这个问题,于是就有了这篇博客。
我一开始的想法其实我一开始的想法很简单,因为我一直没有使用指针
在我的某些印象中我曾经记得,使用锁不申明为指针是一个代码规范类似的东西
大多数的(我看过的一些)源码中,没有见过将锁申明为指针的用法
但是当时我没有办法回答这个 PR,你总不能说我是一厢情愿吧…需要一个更加合理的解释
仔细分析上网搜索一番https://www.reddit.com/r/golang/comments/6uyf16/confusion_about_mutex_and_reference/
很多类似的问题都在问(你不用点开,只是举个例子)
问题关键sync.Mutex 这个东西不能被 copy!(这个我之前也是知道的,毕竟都分析过源码了)
刨根问底虽然这个锁不能被拷贝,那么就应该被申明为指针防止拷贝出现问题吗?
别慌,先写个例子测测看
1234567891011121314151617181920212223242526272 ...
Linux 图形化监控工具
最近在分析线上问题,需要监控 Linux 相关指标,如果只是用命令,总是只能知道当前的值,无法记录过程。而设备不是云厂商的设备,所以没有相关监控,zabbix 有,但是没有相关权限可以看到。所以找到一些好用的监控小方案。
nmon安装yum install nmon
使用
总结
安装方便,使用简单,最快速度能搞定,无需过多依赖,控制台展示
当然它还有其他内存等相关信息的展示
不是特别好看(毕竟是控制台要求也不能太高),精度相对低,只能有个大概峰值
bottom安装因为是 rust 搞的,所以可能有相关依赖,需要手动处理
12345678910111213141516wget https://github.com/ClementTsang/bottom/releases/download/0.4.5/bottom_x86_64-unknown-linux-gnu.tar.gztar xvf bottom_x86_64-unknown-linux-gnu.tar.gz./btm# 如果出现以下错误需要安装 glibc # /btm: /lib64/libc.so.6: version ...