Golang源码分析系列之sync.Map底层实现

Golang中sync/map提供了并发读写map功能。这里面分析的源码基于go1.14.13版本。

sync.Map的结构

1
2
3
4
5
6
7
8
9
10
11
type Map struct {
mu Mutex // 排他锁,用于对dirty map操作时候加锁处理

read atomic.Value // read map

// dirty map。新增key时候,只写入dirty map中,需要使用mu
dirty map[interface{}]*entry

// 用来记录从read map中读取key时miss的次数
misses int
}

阅读更多

Protocol buffers语法

简介

Protocol Buffers简称Protobuf,是google公司推出的一种数据描述语言。Protocol buffers具有平台无关、语言无关、二进制格式编码、编码后体积小,序列化和反序列化快、类型安全、向后兼容等特点。

Protocol buffers有专门的语法结构来定义数据结构。消息和RPC服务接口是Protocol buffers中两大基本组成。消息类似一个Json object,RPC服务接口定义了服务所具有的接口和所依赖的消息类型。

Protocol buffers定义的数据结构应该保存在.proto后缀名的文件中。目前最新版本的语法协议是proto3。

阅读更多

【译文】Go 反射三定律

原文地址:https://blog.golang.org/laws-of-reflection

简介

Reflection(反射) 在计算机中表示程序能够检查自身结构的能力,特别指通过类型进行处理。它是元编程的一种形式,也是最容易让人迷惑的一部分。

类型和接口

因为反射建立在类型系统之上,所以让我们先回顾一下 Go 中的类型。Go 是静态类型语言。每个变量都有一个静态类型,即只有一种类型,并且在编译时就已经确定了。比如int, float32, *MyType, []byte等。比如我们进行如下声明:

1
2
3
4
type MyInt int

var i int
var j MyInt

阅读更多

Go语言实现简易版netstat命令

netstat工作原理

netstat命令是linux系统中查看网络情况的一个命令。比如我们可以通过netstat -ntlp | grep 8080查看监听8080端口的进程。

netstat工作原理如下:

  1. 通过读取/proc/net/tcp 、/proc/net/tcp6文件,获取socket本地地址,本地端口,远程地址,远程端口,状态,inode等信息
  2. 接着扫描所有/proc/[pid]/fd目录下的的socket文件描述符,建立inode到进程pid映射
  3. 根据pid读取/proc/[pid]/cmdline文件,获取进程命令和启动参数
  4. 根据2,3步骤,即可以获得1中对应socket的相关进程信息

阅读更多

多网卡模式下Golang应用的流量从指定网卡流入流出方案

最近因业务需要,需要在多网卡模式下实现Go应用的流量从指定网卡流入,请求外网服务时候流量需要从该网卡流出功能。从指定网卡流入很容易实现,只要go应用listen对应网卡即可,但请求外网服务时候就相对麻烦些了。在实践中总结出有三种方案可行。各有优劣。

假定服务器网卡情况如下:

网卡 网卡IP 对应的公网IP
eth0 172.31.0.8 109.25.48.65
eth1 172.31.0.14 119.26.38.75

实际上我们的服务器使用云服务器,网卡是弹性网卡(eni),绑定的是弹性ip(eip)。三种方案对普通服务器也是能达到目的的。

阅读更多

Golang源码分析系列之Channel底层实现

Golang中Channel是goroutine间重要通信的方式,是并发安全的,通道内的数据First In First Out,我们可以把通道想象成队列。这里面分析的源码基于go1.13版本。

channel数据结构

Channel底层数据结构是一个结构体。

1
2
3
4
5
6
7
8
9
10
11
12
13
type hchan struct {
qcount uint // 队列中元素个数
dataqsiz uint // 循环队列的大小
buf unsafe.Pointer // 指向循环队列
elemsize uint16 // 通道里面的元素大小
closed uint32 // 通道关闭的标志
elemtype *_type // 通道元素的类型
sendx uint // 待发送的索引,即循环队列中的队尾指针front
recvx uint // 待读取的索引,即循环队列中的队头指针rear
recvq waitq // 接收等待队列
sendq waitq // 发送等待队列
lock mutex // 互斥锁
}

阅读更多

Elasticsearch内存占用分析与管理

Elasticsearch是基于JVM实现的,内存分配分为堆内(on-heap)和堆外(off-heapp)两部分。每部分的内存,可以用于不同目的的缓存,具体可以看下思维导图:

从整体来看如下所示:

堆内存与堆外内存

一般情况下,Java中分配的非空对象都是由Java虚拟机的垃圾收集器管理的,称为堆内内存(on-heap memory)。虚拟机会定期对垃圾内存进行回收,在某些特定的时间点,它会进行一次彻底的回收(full gc)。彻底回收时,垃圾收集器会对所有分配的堆内内存进行完整的扫描,这意味着一个重要的事实——这样一次垃圾收集对Java应用造成的影响,跟堆的大小是成正比的。过大的堆会影响Java应用的性能。

Java虚拟机的堆以外的内存,即直接收操作系统管理的内存属于堆外内存(off-heap memory),通过把内存对象分配在堆外内存中,可以保持一个较小的堆,可以减少垃圾回收对应用的影响。

阅读更多