前言
随着容器技术的兴起,越来越多不同类型的应用开始使用容器的方式进行交付。Golang作为服务器端非常热门的一门语言同时也是容器技术的主要编写语言备受关注。那么将一个Golang应用进行容器化的时候,需要注意哪些事情,在出现问题时该如何进行调优和诊断呢?
先谈谈Golang本身的设计
Golang是谷歌发布的第二款开源编程语言。Golang专门针对多处理器系统应用程序的编程进行了优化,使用Golang编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。Golang在容器相关的场景和领域以及高并发的服务器程序场景下扮演着非常重要的角色。
Golang具有如下三个特点:
● 简洁 快速 安全
● 并行 有趣 开源
● 内存管理 数组安全 编译迅速
在学习一门语言前,通常我会主要关注如下三个方面:第一这门语言的特性是什么;第二这门语言解决的场景和问题是什么;第三这门语言的内部设计是否有需要注意的地方。上面的介绍已经为我们解答了第一个和第二个问题,那么接下来我们主要来讨论第三个问题。那么Golang的这些优秀的特性内部的设计方式是什么样子的,使用起来是否有什么需要特别注意的呢?为了详细解答这个问题,我们将问题拆分成了二个部分分别为大家解答。
● Golang是如何实现并行的
高并发是Golang被大家接纳和认可的最重要一环。对于大型的互联网项目而言,高并发可以说是应用性能的立足之本,再棒的功能与特性也不如稳定运行来得让人安心。从前大家在关注C10K问题,而现在越来越多的人开始思考如何解决C10M问题。从C10K问题到C10M问题,解决问题的方式已经不是简简单单的调整内核参数那么简单的。更多的是要从架构甚至应用自身的角度来解决,一个高效的并发模型,可以从应用程序的交付压榨系统的性能。目前比较成熟的并发模型,主要是通过进程、线程与协程三种不同方式来进行实现的。
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。每个进程都有自己的独立内存空间,不同进程通过进程间通信来通信。由于进程比较重量,占据独立的内存,所以上下文进程间的切换开销(栈、寄存器、虚拟内存、文件句柄等)比较大,但相对比较稳定安全。
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。线程间通信主要通过共享内存,上下文切换很快,资源开销较少,但相比进程不够稳定容易丢失数据。
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
Golang的并发模型是基于协程的,而协程在Linux底层的调度是依赖进程的调度的,而这之间的转换都通过Golang自身的调度器进行了管理,无需开发者关心。但是这个时候有经验的开发者就会提出问题了,golang本身是编译型的语言没有类似JVM一样的虚拟机可以在运行时指定参数,那么Goroutine这种方式是否有参数需要设置来保证性能。