LoginSignup
6
2

More than 5 years have passed since last update.

案件で得た小ネタのような知見

Posted at

ある案件の機能開発、保守をしていましたが、
サービス終了という事で小ネタのような知見を共有しようと思います。
知見というかただの小ネタだった事に気付いた。
パフォーマンスチューニングだったり外部システム連携だったり色々やりました。

しょうもない話

2017年3月くらいからこの案件に関わり始めて、9ヵ月も経ちました。
案件の終わりがサービス終了だととても微妙な気分です。
関わり始めた頃はGo難しすぎる、コンパイル一生通らないとか思っていましたが、
今は学習コスト低いしそれなりに速度も出るし書きやすいと思ってたり考えがわりと変わりました。
gitlabとかbacklog見直しながら書いてますが、思ったのは成長出来る案件ではあったけどやっぱり保守だと技術的な中身が薄いなあと思いました。
今の環境だと周りもあまり技術に興味ある人が多いわけではないし、案件的にも成長が厳しいと感じているので転職がしたいです。
どこか誘ってください

システム概要

ECシステムと連携し、顧客情報や購買情報、アクセス情報に基づいてメール配信やプッシュ通知を送ったりするシステムです。
主に触っていたのがサーバなので、フロントはあんまり触れないでおきます。

ECシステム 連携バッチ Nginx このシステム
PHP PHP => Node
Go Go
MySQL MongoDB

外部連携(SendGrid)

レスポンスの仕様が変わって動かなくなる

Marketing Campaignsという機能を使っていて、メールが送られていないという連絡を受けてから確認したところ
レスポンスの形式が変わっていた事が原因でした。
(SendGridのサポートにも確認済み)
外部システムに連携する際にはこういう事にも注意しようと思いました。

GO

Too many open files

プッシュ通知に外部システムを使っていて、外部システムにリクエストを送っている途中でこのエラーが出るみたいな事がありました。
以下のように変えたらエラーが出る事はなくなったので、deferを使っていた事で起きる問題でした。

  • 変更前
resp, err := client.Do(req)
if err != nil {
    panic(err)
}
defer resp.Body.Close()
// 処理
  • 変更後
resp, err := client.Do(req)
if err != nil {
    panic(err)
}
//resp.Bodyから必要な値だけ取得
resp.Body.Close()
//処理

jsonでfalseとか0とかを扱う時

EC側のデータをJSONにして、Goで受け取り、データ更新を行っていました。
EC側であるカラムの値をfalseにしても更新されないという事がありました。
型をポインタ型にするだけで扱えるようになります。

  • 変更前
flag bool `json:"flag,omitempty" bson:"flag,omitempty"`
  • 変更後
flag *bool `json:"flag,omitempty" bson:"flag,omitempty"`

Node

pm2.logを見ると勝手に再起動している

原因はunhandledRejectionでした。
該当箇所を修正したら起きなくなりました。

フロントで使うデータは絞るべき

思い返すとわりと当たり前のことだけど。
顧客等の検索結果をCSVに出力する機能があります。
CSVに出力するのは3000件までと決まっているのに、
サーバから10万件返してフロントで3000件にしていました。
サーバ側で3000件までにしたら早くなりました。

データを取ってくるのが遅い

coを使っている前提ですが、並列にする事で早くできました。

  • 変更前
let list = [];
for (let i = 0; i < length; i++) {
    let db_data = yield get() //MongoDBから取ってくる
    list = list.concat(db_data)
}
  • 変更後
let list = [];
for (let i = 0; i < length; i+=3) {
    let db_data = yield [get(), get(), get()] //並列にする
    for (let j = 0; j < db_data.length; j++) {
        list = list.concat(db_data[j])
    } 
}

時間のパディングにlodashを使う事で起きていた問題

これについてはテストしてたの?という感じです。
lodashにはpadpadStartという関数があり、以下のような動作をします。
N日後のM時という動作を元々padでやっていたのですが、以下のように90となり、
3日後の18時という動作になり問題になりました。
padStartを使う事で解決しました。

const {pad, padStart} = require("lodash");

pad("9", 2, "0") //90
padStart("9", 2, "0") //09

Can't set headers after they are sent.

原因はそのままで、以下の修正で起きなくなりましたが、
対応としては微妙だったなあという感じがあります。

  • 変更前
if flag
  return res.status(204).json().end()
#処理
res.status(200)
  • 変更後
if flag
  return
#処理
res.status(200)

MongoDB

勝手に落ちる

原因はOut of memory: Kill process 25921 (mongod)でした。
インデックス貼りまくったり、クエリ投げまくると起きます。
システム側の修正もありましたが、結局はメモリを4GBから8GBに増やす事で解決しました。

レプリケーション時に落ちる

原因ちゃんとわかっていませんが、インデックスの構築中に落ちました。
再起動させると同期できていたデータ全部消されて最初からになります。
これもメモリが少ないのが原因だと思っています。

普通に遅い

SSDにしたら早くなりました。

100万件程度のデータを取ってくるのが遅い

100万件を一回で取ってくるよりも10万件を10回の方が早かったです。

MySQL

LEFT JOINが遅い

外部結合なので遅いです。
解決方法は色々ありますが、unionを使い別クエリに分ける事で早くする事ができました。
約6秒から約0.3秒くらいまで改善しました。

Nginx

URLが長すぎてエラー(414)

原因はそのままです。
large_client_header_buffers 4 256k;を設定に追加で解決しました。

終わり

6
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
2