Golang编程模式:functional options

配置选项问题 当我们需要创建一个对象时,往往需要对这个对象的某些成员参数进行配置,比如下面这个结构体: type Server struct { Addr string Port int Protocol string Timeout time.

继续阅读

K8s的RBAC权限控制机制

RBAC(Role-Based Access Control) 基于角色的权限控制,其实只有三个最基本的概念: Role:角色,每个角色都定义了一组对k8s API对象的操作权限,就是一系列权限的集合 Subject:权限被作用者,即Role提供的权限要作用到的用户,人,或机器 RoleBinding:通过RoleBinding把Role和Subject绑定到一起 总之,就是通过Role来定义权限,通过Subject来认证,通过RoleBinding将Role和Subject绑定到一起,那么Subject即可拥有Role所定义的权限了。

继续阅读

Docker的底层原理——Namespace和Cgroups技术

Docker容器技术 容器是一种沙盒技术,可以像一个集装箱一样,把你写的应用程序包起来,这样多个应用之间就会有各自的边界而不互相干扰,而这个容器也可以随意的搬来搬去。容器在外在表现上就像一个轻量级的虚拟机,它有自己的文件系统,自己的CPU和内存大小,自己的网络栈等等,多个容器运行在同一台宿主机上,就像每个容器各自从一台物理机上切了一块一样。但是容器并不像虚拟机一样采用了虚拟化技术,而是直接在操作系统上就可以隔离出多个容器。下面这张图就是容器和虚拟机的对比图: 左侧就是虚拟机的实现原理,通过Hypervisor提供硬件虚拟化功能,模拟出一个操作系统的各种硬件状况,然后在这个虚拟的硬件上安装一个新的操作系统,也就是图上的Guest OS。 而右侧就是容器技术,可以看到容器是使用了Docker Engine替代了Hypervisor,并且不需要创建Guest OS,而是直接就构造出了多套文件目录。 那么容器技术到底是怎么实现的呢? 通过Namespace让进程"隔离" Linux系统在使用clone()或者fork()函数创建一个进程时,可以给它指定很多参数,比如CLONE_NEWPID参数,就可以在进程创建起来后,让这个进程"看到"一个全新的进程空间:

继续阅读

InnoDB的非锁定一致性读

非锁定一致性读 在《MySQL的锁》这篇文章中我介绍了MySQL的锁定一致性读,即通过加锁的方式来保证读取数据的正确性。而为了提高效率,InnoDB还实现了非锁定的一致性读,即读取操作不需要等待行锁的释放就可以完成数据读取,提高读的效率。这也是InnoDB默认的读取方式。 实现方式 InnoDB通过版本控制的方式读取当前执行时间数据库中的快照数据,快照数据是指该行之前版本的数据,如上图所示,当要读取的数据被加了X锁时,可以不等到锁释放,而是直接读取数据旧版本的快照,即可实现一致性读。而在不同的事务隔离级别下,读取数据的版本也不同,这就是行多版本技术,由此带来的并发控制,就是多版本并发控制(Multi Version Concurrency Control,MVCC)。 MVCC MVCC是一种概念,很多数据库都有自己的实现,而InnoDB的实现方式是结合自己的undo log和在表中增加了两个隐藏的字段实现的。

继续阅读

MySQL的锁

数据库的锁 锁的作用就是确保每一个用户都能以一致的方式读取和写入数据。MySQL中的锁分为两种:闩锁latch和lock锁。 latch:轻量级的锁,用于锁定mysql应用程序中的一些对象,要求锁定的时间必须非常短,mysql中分为mutex(互斥锁)和rwlock(读写锁),是应用程序级别的,就是我们在程序中使用的mutex和rwmutex。通过命令show engine innodb mutex可以查看,一般mysql的开发人员会关注。 通过命令show engine innodb mutex可以观察当前数据库中的latch信息。

继续阅读

Redis的持久化机制

Redis的持久化 Redis 的读写都是在内存中,所以它的性能较高,但在内存中的数据会随着服务器的重启而丢失,为了保证数据不丢失,我们需要将内存中的数据存储到磁盘,以便 Redis 重启时能够从磁盘中恢复原有的数据,而整个过程就叫做 Redis 持久化。 Redis的可持久化也是redis和memcached的主要区别之一,Memcached没有持久化机制。 Redis持久化的方式 快照方式RDB RDB(Redis DataBase),某一个时刻,将当前内存中存储的所有数据形成一个快照,并以二进制形式写入磁盘。

继续阅读

Docker开启TLS远程连接

Docker远程连接 Docker是C/S架构,通过docker的客户端连接到docker daemon,然后由docker daemon在宿主机上执行构建镜像,运行容器等指令。 Docker支持多种方式将docker客户端连接到server。如果docker客户端和server都在同一台宿主机上,那么可以直接使用Unix域套接字文件/var/run/docker.sock连接,我们直接使用docker命令时实际上就是采用这种方式进行连接的。 Docker也支持远程通过socket进行连接,可以选择开启或者不开启TLS,为了安全我们大多数时候还是采用开启TLS的方式进行远程连接。 启动远程连接的过程 首先需要保证宿主机上docker daemon已安装,安装过程可查看官网 制作证书 首先需要制作证书,包括服务端证书,和客户端证书。

继续阅读

k8s的Informer机制

Client-go client-go与其他语言版本的k8s不同的地方在于,它不仅仅是一个k8s的客户端,而且还是k8s的核心库,k8s中各个组件与api-server之间的通信都是通过client-go的iformer机制实现的快速低延迟的数据同步。kubernetes中的各个组件和api-server之间都是通过http通信,那么需要非常高的可靠性,时效性。核心就是使用了client-go的informer机制。 Informer机制 下图是client-go中Informer机制的架构图: 最外层是一个Informer,可以看到所有功能都被封装到了Informer中,通过Informer与kube-apiserver通信,实现对API资源的list/watch(所谓ListAndWatch就是通过List获取到所有最新版本的API对象,然后再通过Watch机制监听这些API对象的变化),Informer也可以连接用户定义的eventHandler对捕获到的某些事件进行处理,还可以将watch到的更新,输出到外部,比如存到本地数据库等等。总体而言,所谓的 Informer,就是一个自带缓存和索引机制,可以触发 Handler 的客户端库。 Informer的三个组成部分 Reflector 如上图,Reflector包含一个通过clientset实现的ListerWatcher对象和一个Store对象,Reflector会通过ListerWatcher方法对api-server进行watch,通过比对resourceVersion来捕获API资源的变化,然后送入store。store是一个FIFO Queue(先入先出队列)。

继续阅读

redo log的两阶段提交

WAL技术 WAL(Write-Ahead Logging),就是先些日志,再写磁盘。 当我们向MySQL更新一条记录的时候,InnoDB存储引擎就会把记录顺序的写到redo log中,然后更新InnoDB的buffer pool,并不更新磁盘中的数据页,然后这次更新操作就算是完成了,之后InnoDB存储引擎就会在它有空的时候,把redo log中记录的记录刷到磁盘上的数据页中完成最终的持久化。 由于磁盘的顺序写入效率要远高于随机写入,并且还有组提交等优化,这种方式可以大大提高数据更新时的效率。 关于磁盘的顺序写入,需要注意一下。不是说打开一个文件之后append就是顺序写入了。顺序写入需要知道磁盘上要写入的 位置,直接操作磁盘,向某个特定的地址写入,顺序写入时,磁盘的磁头不需要移动就可以直接写入,这样才有效率的提升。 Redo log Redo log是Innodb存储引擎提供的用于优化更新操作的日志。它的结构可以看成是个环形的磁盘区域。

继续阅读

Innodb存储引擎的特性

InnoDB存储引擎的体系架构 InnoDB存储引擎的体系架构大致如下图所示,可以看到主要包含了一系列后台线程,和一个大的缓冲池。最底层则是文件系统。 InnoDB的线程模型 InnoDB的线程主要分为Master线程、IO线程、Purge线程和Page Cleaner线程。 Master 线程 是核心的后台线程,主要负责调度其他线程,以及脏页的刷新,undo页的回收,redo log的刷新,合并缓冲区等。(版本不同做的工作不一样) IO线程 innodb中大量使用了AIO(异步IO)来处理写请求,以提高性能,IO线程用于处理这些IO操作的回调。

继续阅读