A case of GC tuning for Golang program on line

Source: Internet
Author: User
This is a creation in Article, where the information may have evolved or changed.

Golang is a very interesting language, the first time to see it introduced, it is very like. Six months ago to join the American Regiment, have the opportunity to write a few online programs. One of the programs router to forward tens of millions of requests per day. Since the route path needs to be determined based on the requested content, it needs to load hundreds of thousands of deal (US-order) information into memory for querying. The problem is, using the hundreds of thousands of data from map makes the GC very hard.

Deal data

// Deal的定义typeDealTinystruct{Dealid    int32Classid   int32Mttypeid  int32Bizacctidint32Isonline  boolGeocnt    int32}

GC pauses

Write a simple Web program with go, set GOGCTRACE the environment variable to start the program after 1, use the WRK stress test, observe the GC pause time played by the console.

GOGCTRACE=1 go run gc.go  # 设置环境变量,go gc时会打印详细信息wrk http://localhost:8080/ -d 10s  # 压力测试,发送大量请求,让程序“忙”起来,触发gc

Test program main part code:

func Main() {Const SIZE = 500000 //500,000m :=  Make(Map[Int32]Dealtiny, SIZE) for I := 0; I < SIZE; I++ { //Put data into memorym[Rand.Int31()] = Dealtiny{}}http.Handlefunc("/", func(W http.Responsewriter, R *http.Request) {//Simulate memory allocations, do some calculationsN := Rand.INTN(4096) + 1024x768Buffer :=  Make([]int, N) for I := 0; I < N; I++ {Buffer[I] = Rand.INTN(1024x768)}C := 0 for I := 0; I < N; I++ {if Buffer[I] >  + {C += 1}}FMT.fprintf(W, "N:%d, more than count:%d", N, C)})Log.Fatal(http.Listenandserve(": 8080", Nil))}

Partial output of the program in the console

# Go 1.1.1; Linux 3.2.0; CPU Intel (R) Core (TM) i7-2600 CPU 3.40GHzGc83(1): 8+0+0 MS, 19455-3211 MB(1291202-1287991)objects, 0(0)Handoff, 0(0)Steal, 0/0/0 yieldsgc84(1): 8+0+0 MS, 19087-3213 MB(1307079-1303866)objects, 0(0)Handoff, 0(0)Steal, 0/0/0 yieldsgc85(1): 8+0+0 MS, 18935-3212 MB(1322802-1319590)objects, 0(0)Handoff, 0(0)Steal, 0/0/0 yields

The GC pause time is 8ms, and the online CPU is lower than the test machine, and is a virtual machine, the pause time is longer than 8ms. Such a long pause is clearly unacceptable. Need to find ways to optimize.

Check out the code for Go src/pkg/runtime/mgc0.c#985 found that GC requires a scan of a map key and value, which is naturally quite expensive.

The

Go does not have as many parameters as the JVM can adjust, and it is not generational recycling. The way to optimize GC is only by optimizing the program. But go has one advantage: there is a real array (and just an array of referece). Go's GC algorithm is Mark and Sweep,array is friendly to this: The entire array is processed at once. You can use an array to implement map with open addressing, which optimizes the GC (which also reduces memory usage, as you can see later)

// DealMap 为array backend hash tabledm:=NewDealMap(SIZE)fori:=0;i<SIZE;i++{    dm.Put(DealTiny{Dealid:rand.Int31()})}

This time, the GC log is

gc80(1)(507340-506537) objects, 0(0) handoff, 0(0) steal, 0/0/0 yieldsgc81(1)(513722-512919) objects, 0(0) handoff, 0(0) steal, 0/0/0 yieldsgc82(1)(520260-519457) objects, 0(0) handoff, 0(0) steal, 0/0/0 yields

As you can see, GC recycling is very fast (0MS), and memory usage is reduced from 31M to 12M after the original GC. The optimization effect is very obvious.

The realization of Dealmap

type Dealmap struct {    Table   []Dealtiny    Buckets int    size    int}//round to a multiple of the nearest 2func minbuckets(v int) int {    v--    v |= v >> 1    v |= v >> 2    v |= v >> 4    v |= v >> 8    v |= v >>  -    v++    return v}func HashInt32(x int) int {    x = ((x >>  -) ^ x) * 0x45d9f3b    x = ((x >>  -) ^ x) * 0x45d9f3b    x = ((x >>  -) ^ x)    return x}func Newdealmap(maxsize int) *Dealmap {    Buckets := minbuckets(maxsize)    return &Dealmap{size: 0, Buckets: Buckets, Table:  Make([]Dealtiny, Buckets)}}//TODO Rehash policyfunc (m *Dealmap) Put(D Dealtiny) {    Num_probes, Bucket_count_minus_one := 0, m.Buckets-1    Bucknum := HashInt32(int(D.Dealid)) & Bucket_count_minus_one     for {        if m.Table[Bucknum].Dealid == 0 { //INSERT, does not support putting deal with ID 0            m.size += 1            m.Table[Bucknum] = D            return        }        if m.Table[Bucknum].Dealid == D.Dealid { //Update            m.Table[Bucknum] = D            return        }        Num_probes += 1 //Open addressing with Linear probing        Bucknum = (Bucknum + Num_probes) & Bucket_count_minus_one    }}func (m *Dealmap) Get(ID Int32) (Dealtiny, BOOL) {    Num_probes, Bucket_count_minus_one := 0, m.Buckets-1    Bucknum := HashInt32(int(ID)) & Bucket_count_minus_one     for {        if m.Table[Bucknum].Dealid == ID {            return m.Table[Bucknum], true        }        if m.Table[Bucknum].Dealid == 0 {            return m.Table[Bucknum], false        }        Num_probes += 1        Bucknum = (Bucknum + Num_probes) & Bucket_count_minus_one    }}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.