August 7, 2021
服务网格Istio之服务入口 ServiceEntry
"使用服务入口(Service Entry) 来添加一个服务入口到 Istio 内部维护的服务注册中心。添加了服务入口后,Envoy 代理可以向服务发送流量,就好像它是网格内部的服务一样,可参考 https://istio.io/latest/zh/docs/concepts/traffic-management/#service-entries。\n简单的理解就是允许内网向外网服务发送流量请求,但你可能会说正常情况下在pod里也是可以访问外网的,这两者有什么区别呢?\n确实默认情况下,Istio 配置 Envoy 代理可以将请求传递给外部服务。但是无法使用 Istio 的特性来控制没有在网格中注册的目标流量。这也正是 ServiceEntry 真正发挥的作用,通过配置服务入口允许您管理运行在网格外的服务的流量。\n此外,可以配置虚拟服务和目标规则,以更精细的方式控制到服务条目的流量,就像为网格中的其他任何服务配置流量一样。\n为了更好的理解这一块的内容,我们先看一下普通POD发送请求的流程图普通 Pod 请求\n创建 ServiceEntry 资源 举例来说:\nsvc-entry.yaml …"
July 31, 2021
在linux下安装Kubernetes
"环境 ubuntu18.04 64位\nKubernetes v1.21.3\n这里需要注意,本教程安装的k8s版本号 \u0026lt;- v1.24.0,主要是因为从v1.24.0以后移除了 Dockershim,无法继续使用 Docker Engine,后续将默认采用 containerd ,它是一个从 CNCF 毕业的项目。如果仍想使用原来 Docker Engine 的方式可以安装 cri-dockerd ,它是 Dockershim 的替代品。\n如果你想将现在 Docker Engine 的容器更换为 containerd,可以参考官方迁移教程 将节点上的容器运行时从 Docker Engine 改为 containerd\n为了解决国内访问一些国外网站慢的问题,本文使用了国内阿里云的镜像。\n更换apt包源 这里使用aliyun镜像 , 为了安全起见,建议备份原来系统默认的 /etc/apt/sources.list 文件\n编辑文件 /etc/apt/sources.list,将默认网址 或 替换为\n更新缓存\n$ sudo apt-get clean all $ sudo apt-get …"
June 27, 2021
SPIFFE 学习参考资料
"The SPIFFE Workload API\nEnvoy spiffe spire\n简而言之SPIFFE\nSPIFFE信任域\n使用SPIRE(自动)提供TLS证书给Envoy以进行更强大的身份验证\n谁使用SPIFFE?\nSecuring the Service Mesh with SPIRE 0.3"
May 23, 2021
Golang中的runtime.LockOSThread 和 runtime.UnlockOSThread
"在runtime中有 [runtime.LockOSThread](https://github.com/golang/go/blob/go1.16.3/src/runtime/proc.go#L4248-L4278) 和 [runtime.UnlockOSThread](https://github.com/golang/go/blob/go1.16.3/src/runtime/proc.go#L4302-L4323) 两个函数,这两个函数有什么作用呢?我们看一下标准库中对它们的解释。\nruntime.LockOSThread // LockOSThread wires the calling goroutine to its current operating system thread. // The calling goroutine will always execute in that thread, // and no other goroutine will execute in it, // until the calling goroutine has made …"
May 21, 2021
认识无锁队列
"无锁队列是 lock-free 中最基本的数据结构,一般应用在需要一款高性能队列的场景下。\n对于多线程用户来说,无锁队列的入队和出队操作是线程安全的,不用再加锁控制\n什么是无锁队列 队列每个开发者都知道,那么什么又是无锁队列呢?字面理解起来就是一个无锁状态的队列,多个线程(消费者)同时操作数据的时候不需要加锁,因为加/解锁都是一个很消耗资源的动作。\n实现原理 我们先看一下无锁队列的底层实现数据结构。\n数据结构 无锁队列底层的数据结构实现方式主要有两种:数组 和 链接。\n数组 在首次初始化时,需要申请一块连接的大的内存。读写数据直接从数据的指定位置操作即可,时间复杂度为O(1)。\n缺点:数组长度有限,一旦数组索引位置写满,则无法继续写入,即队列有上限。\n链表 不用像数组一样,刚开始就申请一块连接的大的内存空间。只有在每次写时数据的时候,申请这个数据节点大小的内存即可,这样就可以实现无限的写入,没有长度限制问题。\n缺点:每次写数据都要申请内存,在写的场景,最差的情况是多少个数据就申请多少次内存,而每次申请都是一个消耗资源的动作。\n可以看到无锁底层的实现的不同各有优势。多数据情况下,我们都采 …"
May 10, 2021
Runtime: goroutine的暂停和恢复源码剖析
"上一节《 GC 对根对象扫描实现的源码分析》中,我们提到过在GC的时候,在对一些goroutine 栈进行扫描时,会在其扫描前触发 G 的暂停([suspendG](https://github.com/golang/go/blob/go1.16.2/src/runtime/preempt.go#L76-L254))和恢复([resumeG](https://github.com/golang/go/blob/go1.16.2/src/runtime/preempt.go#L256-L280))。\n// markroot scans the i\u0026#39;th root. // // Preemption must be disabled (because this uses a gcWork). // // nowritebarrier is only advisory here. // //go:nowritebarrier func markroot(gcw *gcWork, i uint32) { baseFlushCache := uint32(fixedRootCount) …"
May 7, 2021
goroutine栈的申请与释放
"对于提高对 stack 的使用效率,避免重复从heap中分配与释放,对其使用了 pool 的概念,runtime 里为共提供了两个pool, 分别为 stackpool ,另一个为 stackLarge。stack pool\nstackpool: 16b~32k 对应通用的大小的stack。获取时通过调用 stackpoolalloc(), 释放时调用 stackpoolfree()。\nstackLarge:对应 \u0026gt; 32K 的 stack\n在程序全局调度器 初始化 时会通过调用 stackinit() 实现对 stack 初始化。\n当我们执行一个 go func() 语句的时候,runtime 会通过调用 newproc() 函数来创建G。而内部真正创建G的函数为 [newproc1()](https://github.com/golang/go/blob/go1.16.3/src/runtime/proc.go#L3990-L4098),在没有G可以复用的情况下,会通过 newg = malg(_StackMin) 语句创建一个包含stack的G。\n// Allocate a …"
May 7, 2021
Golang的GPM 模型在网络编程中存在的问题
"现状 目前在网络编程中,golang采用的是一种 goroutine-per-connection 的模式,即为每一个连接都分配一个goroutine,一个连接就是一个goroutine,多个连接之间没有关系。\npackage main import ( \u0026#34;fmt\u0026#34; \u0026#34;io/ioutil\u0026#34; \u0026#34;net\u0026#34; \u0026#34;time\u0026#34; ) //模拟server端 func main() { tcpServer, _ := net.ResolveTCPAddr(\u0026#34;tcp4\u0026#34;, \u0026#34;:8080\u0026#34;) listener, _ := net.ListenTCP(\u0026#34;tcp\u0026#34;, tcpServer) for { //当有新客户端请求时拿到与客户端的连接 conn, err := listener.Accept() if err != nil { fmt.Println(err) continue } // 处理逻辑 goroutine-per-connection go handle(conn) } } …"
May 1, 2021
Linux 内核select、poll 和 eventpoll 的实现
"Linux 内核仓库 https://github.com/torvalds/linux\nLinux 内核文档: https://www.kernel.org/doc/html/latest/index.html( 中文)\n开发工具参考: https://www.kernel.org/doc/html/latest/dev-tools/index.html\n也可以使用 VSCode + 插件C/C++ GNU Global\n通过前面三个博客可以得知 select,** poll, eventpoll** 的详细实现,现在来总结对比下它们之间的不同:\nselect 流程图 poll 流程图 eventpoll 流程图 优缺点总结 \u0026lt;1\u0026gt; 监控文件最大数不同:select和poll都是以数组形式传入药监控的文件句柄,而这个数组是有大小限制的1024个左右(不是很清楚).而epoll则是每add一个文件句柄会new一个新epi出来,挂载在ep的红黑树中,监控的文件个数没有明确限制(可能会受限于系统最大打开文件句柄数)从这点上看,epoll是优于select和poll. …"
April 30, 2021
缓存池 bytebufferpool 库实现原理
"上一节 《Runtime: Golang 之 sync.Pool 源码分析》 我们介绍了sync.Pool 的源码分析,本节介绍一个 fasthttp 中引用的一缓存池库 [bytebufferpool](https://github.com/valyala/bytebufferpool),这两个库是同一个开发者。对于这个缓存池库与同类型的几个库的对比,可以参考 https://omgnull.github.io/go-benchmark/buffer/。\n建议大家了解一下[fasthttp](https://github.com/valyala/fasthttp) 这个库,性能要比直接使用内置的 net/http 高出很多,其主要原因是大量的用到了缓存池 sync.Pool 进行性能提升。\n用法 // https://github.com/valyala/bytebufferpool/blob/18533face0/bytebuffer_example_test.go package bytebufferpool_test import ( \u0026#34;fmt\u0026#34; …"
April 29, 2021
初识kubernetes 组件
"对于一个刚刚接触kubernetes(k8s)的新手来说,想好更好的学习它,首先就要对它有一个大概的认知,所以本文我们先以全局观来介绍一个kubernetes。\nkubernetes架构 kubernetes 架构图 kubernets整体可以分为两大部分,分别为 Master 和 Node ,我们一般称其为节点,这两种角色分别对应着控制节点和计算节点,根据我们的经验可以清楚的知道 Master 是控制节点。\nMaster 节点 控制节点 Master 节点由三部分组成,分别为 Controller Manager 、 API Server 和 Scheduler ,它们相互紧密协作,每个部分负责不同的工作职责。\ncontroller-manager 全称为 kube-controler-manager 组件,主要用来负责容器编排。如一个容器(实际上是pod,pod是最基本的调度单元。一般一个pod里会部署一个容器服务)服务可以指定副本数量,如果实际运行的副本数据与期望的不一致,则会自动再启动几个容器副本,最终实现期望的数量。这个组件,就是一系列控制器的集合。 …"
April 26, 2021
docker如何利用cgroup对容器资源进行限制
"在容器里有两个非常重要的概念,一个是 namespace 用来实现对容器里所有进程进行隔离;另一个就是 cgroup,用来对容器进程内使用资源进行限制。那 cgroup 又是如何实现对资源进行限制的呢,今天我们来了解一下它的实现原理。\n什么是cgroup cgroup 是 Control Groups 的缩写,是 Linux 内核提供的一种可以限制、记录、隔离 进程组 所使用的物理资源(如 cpu、memory、磁盘IO等等) 的机制,被 LXC、docker 等很多项目用于实现进程资源控制。cgroup 是将任意进程进行分组化管理的 Linux 内核功能。 cgroup 本身是提供将进程进行分组化管理的功能和接口的基础结构,I/O 或内存的分配控制等具体的资源管理功能是通过这个功能来实现的。 一定要切记,这里的限制单元为 进程组,而不是进程。\n子系统 上面提到的具体的资源管理功能统称为 cgroup 子系统,所有子系统列表可以通过 cat /proc/cgroups 命令查看,主要有以下几大子系统:\n# cat /proc/cgroups #subsys_name\thierarchy …"
April 12, 2021
Golang 内存组件之mspan、mcache、mcentral 和 mheap 数据结构
"Golang中的内存组件关系如下图所示golang 内存分配组件\n在学习golang 内存时,经常会涉及几个重要的数据结构,如果不熟悉它们的情况下,理解起来就显得格外的吃力,所以本篇主要对相关的几个内存组件做下数据结构的介绍。\n在 Golang 中,mcache、mspan、mcentral 和 mheap 是内存管理的四大组件,mcache 管理线程在本地缓存的 mspan,而 mcentral 管理着全局的 mspan 为所有 mcache 提供所有线程。\n根据分配对象的大小,内部会使用不同的内存分配机制,详细参考函数 mallocgo() ,所于内存分配与回收,参考文件介绍 malloc.go\n\u0026lt;16KB 会使用微小对象内存分配器从 P 中的 mcache 分配,主要使用 mcache.tinyXXX 这类的字段 16-32KB 从 P 中的 mcache 中分配 \u0026gt;32KB 直接从 mheap 中分配 对于golang中的内存申请流程,大家应该都非常熟悉了,这里不再进行详细描述。Golang 内存组件关系\nmcache 在GPM关系中,会在每个 P …"
April 9, 2021
GC 对根对象扫描实现的源码分析
"工作池gcWork 工作缓存池(work pool)实现了生产者和消费者模型,用于指向灰色对象。一个灰色对象在工作队列中被扫描标记,一个黑色对象表示已被标记不在队列中。\n写屏障、根发现、栈扫描和对象扫描都会生成一个指向灰色对象的指针。扫描消费时会指向这个灰色对象,从而将先其变为黑色,再扫描它们,此时可能会产生一个新的指针指向灰色对象。这个就是三色标记法的基本知识点,应该很好理解。\ngcWork 是为垃圾回收器提供的一个生产和消费工作接口。\n它可以用在stack上,如\n(preemption must be disabled) gcw := \u0026amp;getg().m.p.ptr().gcw .. call gcw.put() to produce and gcw.tryGet() to consume .. 在标记阶段使用gcWork可以防止垃圾收集器转换到标记终止,这一点很重要,因为gcWork可能在本地持有GC工作缓冲区。可以通过禁用抢占(systemstack 或 acquirem)来实现。\n数据结构\ntype gcWork struct { wbuf1, wbuf2 …"
April 7, 2021
Runtime: Golang GC源码分析
"在阅读此文前,需要先了解一下三色标记法以及混合写屏障这些概念。\n源文件 [src/runtime/mgc.go](https://github.com/golang/go/blob/go1.16/src/runtime/mgc.go) 版本 1.16.2。\n基本知识 在介绍GC之前,我们需要认识有些与GC相关的基本信息,如GC的状态、模式、统计信息等。\n三种状态 共有三种状态\nconst ( _GCoff = iota // GC not running; sweeping in background, write barrier disabled _GCmark // GC marking roots and workbufs: allocate black, write barrier ENABLED _GCmarktermination // GC mark termination: allocate black, P\u0026#39;s help GC, write barrier ENABLED ) _GCoff GC未运行 _GCmark 标记中, …"