Quantcast
Channel: Node.jsタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 8829

GASの処理速度が遅いし制約が厳しいのでNode.jsに移行した(Webアプリ)

$
0
0

はじめに

弓道で用いるwebアプリを開発しているんですが、データの読み書きがクソ遅いので、
GoogleAppsScript+スプレッドシートからNode.js+Firebaseに移行しました。
(GoogleAppsScript Web APIからCloud Functions APIに変えたいうこと)

Google Apps ScriptもNode.jsも基本は一緒ですが...

これでかなりwebアプリの待機時間が短くなったので、記事にしようと思います。

私の使用用途は、スプレッドシートにユーザーやデータを保管し、それを読み書きする、つまりwebアプリのバックエンドとしての利用でGASの処理速度が遅いと感じたものであるので読む際は注意してください。

結果から

どれだけ早くなったか先に紹介しておきます。

的中を記録し、その月のデータをとってくる処理を例に紹介します。記録するデータは日付、中たった数、引いた本数、的中率の四つのデータです。月のデータは付けた日の月のデータ全てとってきます。

↓Google Apps Script + スプレッドシート
gas.gif
ちなみにタイムは2.5秒ほど
スクリーンショット 2020-04-16 18.25.04.png

↓Node.js + Firebase(Cloud Functions API使用)

ezgif.com-video-to-gif (1).gif

スクリーンショット 2020-04-16 18.36.14.png

タイムは驚異の0.4秒!!!!!!!!!!!

約2秒ほど早くなりました。ユーザビリティも右肩上がりでとどまることを知らないでしょう。

*上のフェッチしてきたgifの後半に表示されるデータを見ればわかりますが、ばらつきがある状態で行ったので正確ではないですがほぼ同じデータ量です。
*cloud Funcions APIを使用した方は、ある程度時間を置いてAPIアクセスした際には4秒くらいかかっていました。これは、一定時間おくとcloud Funcionsが寝ちゃうからです。詳細は別記事にしようかと思います。

GoogleAppsScript + スプレッドシートでの読み書きが遅いのはなぜか?

Webアプリのバックエンドとして使っていて、GoogleAppsScript+スプレッドシート(データベース)の読み書きが遅いのはなぜだろう。

1、APIの呼び出し回数が多い

Spreadsheetサービスでは、以下のようなメソッドなどを使ってスプレッドシートにアクセスをするたびにAPIが呼び出される。

・getActiveSpreadsheet()
・getSheetByName()
・getDataRange()
・getLastRow()
・getRange()
・getValue()
・setValue()

二重のfor文の中で
sheet.getRange(i,j).getValue();
なんかした日には終わりで、行数×列数分APIアクセス実行されるので、かなり時間がかかる。

なので、下のようにできるだけ呼び出すAPIを減らすために全てのセルのデータを配列として一回のアクセスでとるよう設計している。
sheet.getDataRange().getValues();

私のwebアプリで、部員全員のデータをとってくる処理があるんですが、この処理に二回のAPIの呼び出し✖️部員数30だったので計60回ほどAPIアクセスをしていました。60回とはいえ、体感3秒ほど待たされたのでユーザビリティがすこぶる悪いかったです。

2、読み書きするデータ量が多いと一回のAPIリクエストが遅い
一回のスプレッドシートの読み書き自体がおそらく長い。*ここで長いと言うのはNode.js+Firebaseと比較して

読み書きするデータ量にもよるだろうけど、パスワード、Eメール、その他ユーザーを管理するデータをスプレッドシートにデータベースとして管理するのには少し難があった。それもユーザー数が多いとなおさら。

膨大なユーザーを管理したりせず、個人で使うデータ量なら全然問題ない。

GoogleAppsScript(WebAPI)の制約

次に各制約について紹介する。
GoogleAppsScript(WebAPI)の制約は、

https://www.bugbugnow.net/2018/12/GoogelAppsScript-restriction.html

これをみればわかるが一日のURLフェッチ(APIアクセス)が20,000/日、さらには無料のGoogleアカウントでは、スクリプトの実行時間が6分と地味に少ない。

いや用途によっては十分なんだろうが、私の使用目的では、一日10回URLフェッチを行うとして、ユーザー数2000を超えると上限に達してしまう。もう少し大規模なSPAにしようと思ったら物足りない。

有料プランもあるがそちらも上限が決まっているので、ユーザーが増えて上限がきたら嫌なのでやはりwebアプリのバックエンドとして使うのは厳しいのかもしれない。そもそもそんな使い方する人はほとんどいないだろうが、個人開発をしている人なら同じような境遇にあった人もいそう。

Cloud Functions APIの制約

それに比べてCloud Functions APIの制約というと

https://firebase.google.com/docs/firestore/quotas?hl=ja

呼び出し
関数の呼び出し料金は定額制です。HTTP リクエストから呼び出される関数(HTTP 関数)、バックグラウンド関数、call API から行われる呼び出しなど、呼び出し元によって料金が変わることはありません。

月間呼び出し回数料金(100 万単位)
最初の 200 万回無料
200 万回を超えた分$0.40

米ドル以外の通貨でお支払いの場合は、Cloud Platform SKU に記載されている該当通貨の料金が適用されます。
呼び出し料金は 1 回あたり $0.0000004 の単価制で、関数の結果や実行時間に関係なく請求されます。ただし、毎月最初の 200 万回までは無料です。

だそう。ほー。無料枠がかなり多いw
一ユーザーが一日に10回APIアクセスするとして

10✖️30 = 300

毎月最初の 200 万回まで無料なので2000,000÷300 = 6,666人まで無料枠でいけるぞ!

一日10回APIアクセスを行うとして、ユーザー数2,000を超えると上限に達してしまうGASのAPIに大してCloud Functions APIは 6,666人までいける
断然、Cloud Functions APIの方がいい。さらに超えた分に対しては超えた分の請求なので都合がいい。上限を超えた際には一回のAPIアクセスをするのに約0.0004円ほどだし格安すぎる。

ユーザーが6万6666人にて毎月2,000万回APIアクセスするとしたら約8,000円ほど。
ガソリン代くらいでしょう。車持ってないけど。

gas+スプレッドシート からNode.js + Firebaseに移行

以上よりGoogle Apps Script + スプレッドシート ⇨ Node.js + Firebase に移行しました。

gasのコード全部で500行くらいだったのでNode.jsに書き換えるのも一週間くらいで終わりました。

↓冒頭で見せたアプリ内で使われる的中率を書き込みに行き、月のデータをフェッチする処理
gasのコードとNode.jsのコードの比較(一部)を紹介します。

gas
//的中率書き込みfunctionsubmitFetchData(e){varsheetID=e.parameter["id"];varsheetName=e.parameter["name"];vardate=e.parameter.p1;varhitArrow=e.parameter.p2;varallArrow=e.parameter.p3;varhitRate=hitArrow/allArrow*100;varyear=e.parameter["year"];varmonth=e.parameter["month"];//JSONオブジェクト格納用の入れ物varrowData={};//書込先スプレッドシートのIDを入力varsheet=SpreadsheetApp.openById(sheetID).getSheetByName(sheetName);vararrayData=[[date,hitArrow,allArrow,hitRate]];varrows=arrayData.length;varcols=arrayData[0].length;sheet.insertRows(2,1);//シートに配列を書き込みsheet.getRange(2,1,1,cols).setValues(arrayData);varthisDate=year+month;varsheet=SpreadsheetApp.openById(sheetID).getSheetByName(sheetName);vardata=sheet.getDataRange().getValues();vararray=data.map(function(value,index){return(value.reduce(function(r,c,i){varresult=r;switch(i){case0:result.month=c;break;}returnresult;},{}))});array.shift();vardate=array.map(function(value,index){varthisDate={};varyear,month;year=value.month.split('/');thisDate.year=year[0];month=year[1].split('/');thisDate.month=month[0];returnthisDate;})vardateArray=date.map(function(value,index){returnvalue.year+value.month;});varfirstIndex=dateArray.indexOf(thisDate);varlastIndex=dateArray.lastIndexOf(thisDate);varnewData=sheet.getRange(Number(firstIndex+2),1,Number(lastIndex+2)-Number(firstIndex+2)+1,data[0].length).getValues();//オブジェクトに変換varnewArray=newData.map(function(value,index){return(value.reduce(function(r,c,i){varresult=r;switch(i){case0:result.date=c;break;case1:result.hit_arrow=c;break;case2:result.all_arrow=c;break;case3:result.hit_rate=c;break;}returnresult;},{}))});varoutput=ContentService.createTextOutput(JSON.stringify(newArray,null,2));output.setMimeType(ContentService.MimeType.TEXT);returnoutput;}
Node.js
//的中率書き込み&月のデータフェッチapp.get('/hitWrite',async(req,res)=>{console.log('-----hitWrite-----')constrec_name=req.query["rec_name"];constid=req.query["id"];constteam=req.query["team"];consthit_arrow=req.query["hit_arrow"];constall_arrow=req.query["all_arrow"];consthit_rate=hit_arrow/all_arrow*100;constdate=req.query["date"];constyear=req.query["year"];constmonth=req.query["month"];constarrayData={all_arrow:Number(all_arrow),date,hit_arrow:Number(hit_arrow),hit_rate:Number(hit_rate),id:Math.random().toString(32).substring(2)//ランダムID生成};letrecords;awaitdb.collection("college").doc(team).collection(id).doc("user_data").update({[rec_name]:admin.firestore.FieldValue.arrayUnion(arrayData)}).then(()=>{return(db.collection("college").doc(team).collection(id).doc("user_data").get().then((snapshot)=>{return(records=snapshot.data()[[rec_name]].filter((value)=>{if(value.date.split('/')[0]===year&&value.date.split('/')[1]===month){returnvalue;}}),res.json(JSON.stringify(records)))}).catch((err)=>{console.log(err)res.end();}))}).catch((err)=>{console.log(err)res.end();})})

かなりすっきりしました。

読みやすい、書きやすい、共同開発しやすくなりましたね。

おわりに

アプリの待機時間が短くなったので、Google Apps Script + スプレッドシート から Node.js + Firebase に移行してかなりよかったです。

ただ、金額的にも月にできるAPIアクセス数にも厳しさがあったGoogle Apps Scriptですが、スプレッドシートに書き込めれるので、部内でシートの共有なんかして直接記録を見たりできるのでこっちも便利だったりします。

ただ、ユーザー数が増えると厳しいのでやっぱり捨てざるをおえないってことでおさらばしないとけません。

このwebアプリのユーザー数は自分の大学のユーザーのみの30人なので、当分気にすることはないのですがね。ふふ

最後まで見ていただき、ありがとうございました。


Viewing all articles
Browse latest Browse all 8829

Trending Articles