2016-07-22 11 views
6

Ich möchte die Zugriffszeit zu meinem Tisch auf meinem Golang RestApi reduzieren.Reduzieren Sie die Zugriffszeit auf Bigtable mit Golang

Ich habe eine Go RestAPI mit einem Enpoint, der Zugriff auf eine BigTabellen-Datenbank für jeden Code benötigt, der im Anfragetext angegeben ist. Mein Design des Schlüsselzugriffs ist "Provider | Client | Produktcode | Datum | .." (und andere 4 Parameter).

Für jeden ProductCode des Anfragekörpers mache ich einen Async-Aufruf, um die Zeile mit einem angegebenen Schlüssel zu lesen.
Bei meinem Test habe ich 1000 Produktcodes angefordert und die erhaltenen Zeiten auf meiner lokalen Maschine sind ungefähr 800 ~ 900ms. Die Zeiten auf einer Cloud-Maschine sind etwa 550 ~ 450 ms.

Ich bin mit dem bigtable package zum Bigtable zuzugreifen und ich bin mit dem folgenden Code:

package main 

import (
    "log" 
    "time" 

    "golang.org/x/net/context" 
    "google.golang.org/cloud/bigtable" 
) 

func main() { 
    start2 := time.Now() 

    listPKs := []string{"PROV|CLI|6030|20160714|8|30301.30302|ES", "PROV|CLI|44103|20160714|8|30301.30302|ES", "PROV|CLI|1454871|20160714|8|30301.30302|ES"} 

    providerRS := getBDresponse(listPKs, 50000) 
    if providerRS != nil { 
     ///do something 
    } 
    elapsed2 := time.Since(start2) 
    log.Printf("Time access BT: %s", elapsed2) 
} 

func getBDresponse(listPKs []string, timeoutMiliseconds int) []string { 

    resp := make(chan string) 
    table := myClient.Client.Open(TABLE_NAME) 
    //async call to BT 
    for _, key := range listPKs { 
     go asyncDoUniqueCall(key, resp, myContext, table) 
    } 
    //get all responses 
    providerRS := getResponses(resp, timeoutMiliseconds, len(listPKs)) 
    return providerRS 
} 

func asyncDoUniqueCall(pk string, ch chan string, ctx *context.Context, table *bigtable.Table) { 
    ch <- GetRowValue(pk, ctx, table) 
} 

func getResponses(resp chan string, timeoutMiliseconds int, totalNumRQ int) []string { 
    var ret []string 

    for j := 0; j < totalNumRQ; j++ { 
     select { 
     case rowResponse := <-resp: //catch the response 
      if rowResponse != "" { 
       ret = append(ret, rowResponse) 
      } 
     case <-time.After(time.Duration(timeoutMiliseconds) * time.Millisecond): // timeout control 
      return nil 
     } 
    } 
    return ret 
} 

//GetRowValue open the table and get the row indexed by pk and returns the stored message 
func GetRowValue(pk string, ctx *context.Context, table *bigtable.Table) string { 

    var response string 

    r, err := table.ReadRow(*ctx, pk) 
    if err != nil { 
     return "" 
    } 
    if len(r) > 0 { 
     row := r[COLUMN_FAMILY_NAME] 
     numCol := len(row) 

     response = string(row[0].Value) 
    } 
    return response 
} 

Ich versuchte this Beispiel zu und die Zeiten sind nicht besser:

Bin ich mit die Gorutines und chanels correctyl? Ist die Art, wie ich auf den BT zugreife, korrekt? Vielleicht stimmt das Schlüsseldesign nicht?

Antwort

3

Ich denke, das Problem ist, dass Sie eine 1 Dimension verwenden chan:

resp := make(chan string) 

Sie sollten versuchen, seine Dimension zu erweitern, indem Sie tun:

resp := make(chan string,len(listPKs)) 

Das ist, weil, wenn Ihre Asynchron-Funktion beendet ist, bevor Die Info in der chan wird gelesen, als die chan wird blockiert.

Eine Randnotiz: Spawning-Go-Routinen ohne jede Überprüfung könnte eine mögliche Quelle von Problemen sein.

Ich würde vorschlagen, dass Sie eine working queue implementieren, um Ihre Aufgabe zu optimieren.