20211128のGoに関する記事は3件です。

Cloud FunctionsをGo言語で動かす

概要 firebase で Cloud Functions を使ったときに、JavaScript と golang で作った function とで性能に差がでるかを簡単に確認したのでそのメモ firebase の Cloud Functions で Go言語使える? らしい。のでやってみました。 やり方としては、以下参考の「go言語でCloud Functions + FireStoreをhttpで使ってみた」を参照しつつ、ざっくりとは次の手順で環境を構築しました firebase のコンソールでプロジェクトを作成 firebase に javascript 版の Cloud Functions の関数をデプロイする golang で Cloud Functions の関数を作成し、GCP にデプロイする firebase のプロジェクトを使いまわして、GCP の Cloud Functions を作成するのがミソ 参考 go言語でCloud Functions + FireStoreをhttpで使ってみた Cloud FunctionsをGoで書く。またはFirebaseのためのマイクロサービスアーキテクチャ 測定結果 メモリは、なんとなく128MBに変更しました。測定は、vegeta を利用しました。 結果は、レイテンシが JavaScript 版が平均 5.138s に対して、Go 言語版が 161.252ms と 32倍の差がでました あと、GCP のコンソールから目分量ですが、メモリとアクティブインスタンス数に大きな違いがでました - JS Go 比較 メモリ 100MB 15MB 6.6倍 アクティブインスタンス 50 3 16倍 参考 Firebase Functions の割り当てメモリを変更する ちょっと良さげな負荷ツール vegeta をつかって分散負荷試験を実現してみる JavaScript 版 10rps を 1秒間 gosshys@gosshysnoMacBook-Air perf % vegeta attack --rate 10 -duration=1s -targets=target.txt | vegeta report Requests [total, rate, throughput] 10, 11.10, 1.17 Duration [total, attack, wait] 8.57s, 900.524ms, 7.669s Latencies [min, mean, 50, 90, 95, 99, max] 3.124s, 4.734s, 3.826s, 7.376s, 7.669s, 7.669s, 7.669s Bytes In [total, mean] 5920, 592.00 Bytes Out [total, mean] 400, 40.00 Success [ratio] 100.00% Status Codes [code:count] 200:10 Error Set: 10rps を 10秒間 gosshys@gosshysnoMacBook-Air perf % vegeta attack --rate 10 -duration=10s -targets=target.txt | vegeta report Requests [total, rate, throughput] 100, 10.10, 6.08 Duration [total, attack, wait] 16.45s, 9.901s, 6.549s Latencies [min, mean, 50, 90, 95, 99, max] 2.439s, 5.138s, 4.602s, 8.011s, 8.437s, 9.379s, 9.571s Bytes In [total, mean] 59200, 592.00 Bytes Out [total, mean] 4000, 40.00 Success [ratio] 100.00% Status Codes [code:count] 200:100 Error Set: golang 版 10rps を 1秒間 gosshys@gosshysnoMacBook-Air perf % vegeta attack --rate 10 -duration=1s -targets=target_go.txt | vegeta report Requests [total, rate, throughput] 10, 11.18, 9.01 Duration [total, attack, wait] 1.11s, 894.571ms, 215.591ms Latencies [min, mean, 50, 90, 95, 99, max] 135.716ms, 259.473ms, 178.427ms, 563.063ms, 691.467ms, 691.468ms, 691.468ms Bytes In [total, mean] 610, 61.00 Bytes Out [total, mean] 0, 0.00 Success [ratio] 100.00% Status Codes [code:count] 200:10 Error Set: 10rps を 10秒間 gosshys@gosshysnoMacBook-Air perf % vegeta attack --rate 10 -duration=10s -targets=target_go.txt | vegeta report Requests [total, rate, throughput] 100, 10.10, 9.96 Duration [total, attack, wait] 10.044s, 9.9s, 143.807ms Latencies [min, mean, 50, 90, 95, 99, max] 142.071ms, 161.252ms, 148.575ms, 163.501ms, 184.75ms, 623.21ms, 942.147ms Bytes In [total, mean] 6100, 61.00 Bytes Out [total, mean] 0, 0.00 Success [ratio] 100.00% Status Codes [code:count] 200:100 Error Set: 付録 測定に利用した functions リクエストで指定された url にアクセスして、OGP(https://ogp.me/)を metaタグから抜き出して返却する関数 JavaScript JS の書き方が悪いせいで遅くなっていたらすみません const functions = require("firebase-functions"); const axios = require('axios'); const jsdom = require('jsdom'); const { JSDOM } = jsdom; exports.getOgpFromExternalWebsite = functions.https.onCall(async (data, context) => { if (!data.url) { console.log("not exists url"); return {}; } const headers = {'User-Agent': 'bot'}; const res = await axios.get(data.url, {headers: headers}); const html = res.data; const dom = new JSDOM(html); const meta = dom.window.document.head.querySelectorAll("meta"); const ogp = {}; let i = 0, len = meta.length; for (; i < len; i++) { if (!meta[i].hasAttribute("property")) { continue; } const property = meta[i].getAttribute("property"); const content = meta[i].getAttribute("content"); ogp[property] = content; } if (Object.keys(ogp).length===0) { return {}; } return ogp; }) golang package ogp import ( "fmt" "golang.org/x/net/html" "golang.org/x/net/html/atom" "log" "net/http" ) type OGType int const ( Type OGType = iota Title Description URL Image ) type OG struct { Type, Title, Description, URL, Image string } func findMeta(node *html.Node, og OG) OG { for c := node.FirstChild; c != nil; c = c.NextSibling { if c.Type == html.ElementNode { if c.DataAtom == atom.Meta { var val, t string for _, attr := range c.Attr { if attr.Key == "property" { t = attr.Val continue } if attr.Key == "content" { val = attr.Val } } switch t { case "og:type": og.Type = val case "og:title": og.Title = val case "og:description": og.Description = val case "og:url": og.URL = val case "og:image": og.Image = val } } if og.Type != "" && og.Title != "" && og.Description != "" && og.URL != "" && og.Image != "" { break } og = findMeta(c, og) } } return og } func OGPGet(w http.ResponseWriter, r *http.Request) { url := r.URL.Query().Get("url") if url == "" { w.Write([]byte("welcome")) return } resp, err := http.Get(url) if err != nil { fmt.Fprintf(w, "err: %+v", err) return } defer resp.Body.Close() node, err := html.Parse(resp.Body) if err != nil { log.Fatal(err) } og := OG{} og = findMeta(node, og) fmt.Fprintf(w, "url:%s, og:%+v", url, og) } GCP にデプロイするコマンド gcloud functions deploy OGPGet --runtime go116 --trigger-http --project <firebase のプロジェクトID> 測定に利用したリクエスト (vegeta の targetsファイル) JavaScript ※ 東京リージョンに作成したかったが、なぜか us-central1 に作成されたようです target.txt POST https://us-central1-<firebase のプロジェクトID>.cloudfunctions.net/getOgpFromExternalWebsite Content-Type: application/json @req.json req.json {"data":{"url": "https://yahoo.co.jp"}} golang target_go.txt GET https://us-central1-<firebase のプロジェクトID>.cloudfunctions.net/OGPGet?url=https%3A%3A%2F%2Fyahoo.co.jp
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Goのソースコードのファイル名の末尾が_ios.goだとビルド対象にならない

問題 Goで以下のファイル名を使うと多くの場合に問題が生じます。 なぜでしょうか? hoge_ios.go 解答 ファイル末尾の _ios.go がbuild constraintだとみなされるため。 Goにはビルド対象の環境毎にソースコードを変えることができるbuild constraintという仕組みがあります。 そのため、Windows環境でのみ利用できる機能とLinux環境でのみ利用できる機能を混在させることもできます。 この指定はファイルの先頭に以下のように書くことができますが、ファイル名で指定することもできます。 // +build windows ファイル名で指定する場合は、ファイル名の末尾を _windows.go とすると、上記と同じ効果が得られます。 windowsやlinuxなどは良く知られたものなので、目にする機会も多いかと思います しかし、このbuild constraintに指定できる対象は意外な程に多いです。 以下のドキュメントにかかれているもの全てが対象になります。 特にiosやjsは文字数が少なく、これらの環境向けのGoバイナリを生成することがほぼないため、問題が発生した場合に発見が遅れがちです。 ディレクトリ内の全てのファイルがbuild constraintによってビルド対象から除外された場合は、以下のエラーが発生しますが、そうでない場合は未定義の関数や構造体に関するエラーとしてコンパイルエラーになることが多いです。 build constraints exclude all Go files in XXXXX
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【os.FileInfo】ファイルの属性情報【Golang】

はじめに Golangでファイルに関するインターフェースの一つ、os.FileInfoを簡単に調べたのでメモ 定義 type FileInfo interface { Name() string // base name of the file Size() int64 // length in bytes for regular files; system-dependent for others Mode() FileMode // file mode bits ModTime() time.Time // modification time IsDir() bool // abbreviation for Mode().IsDir() Sys() interface{} // underlying data source (can return nil) } その名の通り、ファイルの情報に関するインターフェース FileInfoはファイル情報を取得するメソッドが使用できる FileInfo自体はos.Stat()かos.Lstat()で得ることができる os.Stat()/Lstat() func Stat(name string) (FileInfo, error) func Lstat(name string) (FileInfo, error) どちらもファイルパスを指定すれば、そのファイルに関する属性FileInfoを返す。基本的には違いがない。 異なるのはシンボリックリンクの扱いである。 Lstatはシンボリックリンク(他のファイルを参照するリンク)のファイルを渡すと、そのリンク自体のFileInfoを返す。 一方でStatはリンクを渡すとリンクの先を追跡してFileInfoを返す。 詳しくは以下 FileInfoのサンプル FileInfoの取得方法がわかったので、書いてみる 事前準備として、任意のディレクトリにtest.txtという空のテキストファイルを作成した package main import ( "log" "os" "path/filepath" ) func main() { filepath := filepath.FromSlash("C:/Users/xxxx/Documents/test.txt") fileinfo, err := os.Stat(filepath) if err != nil { log.Fatal(err) } log.Println(fileinfo.Name()) log.Println(fileinfo.Size()) log.Println(fileinfo.Mode()) log.Println(fileinfo.ModTime()) log.Println(fileinfo.IsDir()) log.Println(fileinfo.Sys()) } 実行結果は以下の通り 2021/11/28 12:09:47 test.txt 2021/11/28 12:09:47 0 2021/11/28 12:09:47 -rw-rw-rw- 2021/11/28 12:09:47 2021-11-28 11:47:28.5960394 +0900 JST 2021/11/28 12:09:47 false 2021/11/28 12:09:47 &{32 {1214173898 30925826} {1214173898 30925826} {1214173898 30925826} 0 0} testという新規ディレクトリを作成して再実行 filepath := filepath.FromSlash("C:/Users/xxxx/Documents/test") 2021/11/28 12:11:24 test 2021/11/28 12:11:24 0 2021/11/28 12:11:24 drwxrwxrwx 2021/11/28 12:11:24 2021-11-28 12:10:25.3242045 +0900 JST 2021/11/28 12:11:24 true 2021/11/28 12:11:24 &{16 {2096553661 30925829} {2145054610 30925829} {2096553661 30925829} 0 0} Sys()だけドキュメントに記載している内容が殆どなかったので調べてみたところ いい記事を発見したので引用 これによると、OS特有のファイル属性を利用するときに使うメソッドとのこと。FileInfoにないOS特有の情報もまとまっていたが、Linuxでファイル作成日時が取得できないのは知らなかった。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む