androidでHTML5 audio使ったHLS形式のストリーミング再生が上手くいかない
スマホのブラウザ上で、音声のstreaming配信がしたい。
そこでhtml5 audioでHLS形式のURL(*.m3u8)指定して再生した時に
動かないandroid端末が一部あった。その対応した話。
結論は、単に、audio.type指定すれば良かったというだけの話だけど、
せっかくなので、スマホのストリーミング配信の話から、まとめる。
目次
flashとスマホ
ストリーミング配信というと、PCは未だ、flash使う事が多いと思われる。
- iphoneでflashは入らない。
- iOS8でflash対応という記事が少し前にあったが、日付の通り、エイプリルフールのネタなので、注意。
- androidもいつの間にやらflash入れれなくなってた
- adobeからGoogle Playでのflash提供は終了
- adobeのアーカイブからinstallして使う手順もあったが、これも4.3までで、android最新機種は出来ないらしい
- 4.4以降は、別のブラウザ入れるとか、改造版?player入れるとか、小細工しないと使えないらしい。正規の方法では使えないという事。
そこで、HLS使うのが選択肢として出て来る。
HLS
HLSはappleの作ったhttp経由でストリーミングを実現する技術。
IETFで標準化しようとしている。
所謂、擬似的なストリーミング技術で、
progressive downloadに、帯域制御を追加した物になる。
公式sampleの中身を見てみる
例えば、公式のsampleを見てみると、以下のm3u8ファイルをDLしてる。
#EXTM3U #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=232370,CODECS="mp4a.40.2, avc1.4d4015" gear1/prog_index.m3u8 #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=649879,CODECS="mp4a.40.2, avc1.4d401e" gear2/prog_index.m3u8 ・・・省略・・・
帯域幅(Bandwidth)毎に音声ファイルを切り替えていて、
最後の部分がその音声ファイル(別のm3u8ファイル)なので、それをURLに打ってみる。
例えば、一行目は、https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/prog_index.m3u8
#EXTM3U #EXT-X-TARGETDURATION:10 #EXT-X-VERSION:3 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-PLAYLIST-TYPE:VOD #EXTINF:9.97667, fileSequence0.ts #EXTINF:9.97667, fileSequence1.ts #EXTINF:9.97667, fileSequence2.ts ・・・省略・・・
約10秒毎に切り替える音声ファイル(tsファイル)を指定している。
なので、これを直接、また、urlに入れてみる。
例えば、一つ目であれば、https://devimages.apple.com.edgekey.net/streaming/examples/bipbop_4x3/gear1/fileSequence0.ts
このURLをDLすると、ストリーム配信の癖に、実はダウンロード出来てしまう。
また、このコンテンツは、キャッシュ禁止を書かない限りクライアント次第ではキャッシュする事がありえるらしい ※公式doc参照
こんな感じでprogressive downloadは、ファイルがクライアントに残ったり辿れたりする。
これが、問題無いのかは確認しないといけない。
著作権上の問題と、それ以外の契約等。wikipediaに軽く書かれている。
※公式doc によると、断片化ファイルを作る時に暗号化する事は出来るらしい。
HLSの対応状況
HLSは、appleの仕様なので、iosは問題無く一通り動くが、androidが端末毎に色々出てきてしまう。
- HLS対応状況は、ここのページを参考にすると
やっぱり、後でandroidで苦労する事になった。
html5 audio
今回は、最終的にブラウザで再生したかったので、html5のaudioタグを使った。
再生は単純で、単にこのHLS形式のURLを埋め込めば良いだけ。
一応、このaudioタグの対応状況も書いておくと、
- html audio対応状況は、caniuseによると
という事で、HLS対応とhtml5 audio対応状況から、大体、ios4とandroid4以降で行けるはずだが…
androidの一部の端末(ver4以降も含む)でHLS形式のm3u8ファイルの再生が出来なかった。
一部のandroidでHLS再生出来ない
沢山android端末で再生確認して、確か1,2割くらい再生不可の端末があった気がする。
超ありがたかったのが、ここの個人のデモページ。
これを見ていて気付いたが、実は、一部のandroidでは、
ストリームのresponseのcontent-typeが以下の場合、そのままでは再生出来ない
- application/x-mpegurl
- application/vnd.apple.mpegurl
これらの、content-typeは、appleの仕様的にも正しいし、
ietf上も、特に後者のcontent-type使えと書いてあるので正しい。(ただ、その記述の前にand/orと曖昧に書かれているのが、ちょっと気になるが)
仕様上正しいのだが、何故か、androidの一部端末は受け付けない。
これは予想だけど、おそらく、google的にそもそもandroid内のブラウザとしては、apple的な仕様で気に入らない所は拒否する仕様にしていて、それに気付いている多くのメーカーがブラウザをカスタマイズして変えていて、逆にこの対応をしていない端末が再生できないのでは?(予想ね)
対応
さて、html5 audioのtypeで単にaudioを指定してあげたら、動いた。
audio.type = "audio/mpeg";
こうすると、殆どの端末で動いた。
判定箇所
同じく、canPlayTypeとか判定している所も、上記x-mpegurlやvnd.apple.mpegurlだと拒否られるので、
audio/mpegでチェックするように変えた。
となると、どこで再生可否判定するんだよ、という話だが、
errorイベントでキャッチする事で、判定するようにした。
(再生前にエラーが起きる)
はまってる人々
やっぱり同じくハマってる人々がいるけど、原因や対応等、ふわふわしてる感じ。
参考
Marionetteからractiveへ
昨日、天下一クライアントサイドJS MV*フレームワーク武道会で話してきた。
以下、そのスライドです。
今日は
自分が現場で使ってきた FWの変遷の軽ーい話をする
元々
- Marionette.js使ってた
- 振り返ると、実装が冗長になってしまった
- 何を言ってるか?というと...
例えば
- ulとliで、その中の要素追加削除やeventを作りたい時
- image
<ul> <li>1st track click me</li> <li>2nd track click me</li> </ul> <button>new track</button>
Marionetteだと...
- 1.html書いて全体像を作って
- 2.templateに切り刻んで
- 3.CompositeView作ってテスト書いて
- 4.ItemView作ってテスト書いて
- 5.CompositeViewをnewする処理書いて
- 6.元のhtmlと繋いで、 ようやく実現
うわー
- やっぱりちょっと大変だった
- Backbone単体より遥かにマシだけど
- 実現までのコストかかりすぎ
- お引っ越しした方が良さそう..
気になってたのは
- やっぱりangular
- ただ、独自の仕組みと多すぎる学習コストが受け入れられなかった
そこで
- 偶々ractive.jsと出会った
ractive.js
- theguardian.comの開発者が開発
- MVVM系のFW
- ここ数年量産されてる簡易版angularの1つ
- IFが大変分かり易くsimple
- ブログまとめたから詳細はブログで
- これでいいじゃん
こんな感じ
<div id="result"> </div> <script id='myTemplate' type="text/ractive"> <p>こんにちわ{{user}} さん。 <strong>{{messages.unread}} 件の未読メッセージがあります。</strong> </p> </script> <script type="text/javascript"> var ractive = new Ractive({ el: "#result", // 出力先の要素 template: "#myTemplate", // template data: { // Reactiveに値を変えたいdata user: '太郎', messages: { total: 11, unread: 4 } } }); </script>
現場でractiveその1
- 勿論、既存のMarionette処理があった
- そのため、当初は、Marionette.Viewのrender(template)内に埋め込んでいた
- 当時、ractiveの強制描写も効かず、setTimeout 0で、ractive描写のtimingズラして使ってた
- が、test書き辛くなって、この書き方は途中で辞めた
現場でractiveその2
- その後、Viewだけ完全にractive.js使うようになった
- Backbone.ViewやMarionette.View要らなくなった
- MarionetteのCompositeViewやstickit等も不要になった
- rails環境だったのでerbに直接template書いた
- image的に、以下のMVC構成になった
- Model : Backbone.Model
- Controller : Marionette.AppRouter + Marionette.Controller
- View : Ractive.js
- カオス感が漂っているが..
ractiveでhappy?
- やっぱり、ReactiveなMVVM FWは生産性が高い
- 特にractive学習コスト低いので、素晴らしい
- 殆ど大きくハマる事は無かった
本当にハマる事が無かったのか?
- 必ずひっかかるのは、以下ぐらい
- 1.ractive.getできるobjが実はpureなobjじゃないので、若干動作違う
- 2.observeはoptionにinit=falseしないとinitでも反応する
- いずれもdoc見ればすぐ解決できる軽微な罠
- これらで大きくハマる事は無い。
ractiveの良くない所
結局、また、jQueryみたいに命令的な所が増えた
- view内で使うhelper的な関数はstatic methodっぽくclassyに書けるが、
- 確かinstanceに対しての挙動は、当時、ゴリゴリcallback書かなきゃいけなかった気がする
そして、何より大事な問題が…
ractive使ってるのが
- 俺しかいなかった
~∞ (ノ^p^)ノ ( ) ~ノ ヽ wwwwwww .
blog書いたけど
- 中々、流行らなかった。
- 最近は、本家の動きも少なくなってきた
- ※追記しておくと、ここ最近は動きが再開してた。一時期、停滞していたという話。
- SNS見ててもractive言及どんどん少なくなってる
今は?
- もう、ractive使ってない
- 振り返ればractive触ってたのも半年前の話
- project変わり諸条件から、
- 裸jsで作ってる
裸js
- BackboneとかMarionetteとかMVVM系FW等
- 色々知ってから裸js戻ると面白い
- 色んなパターン当てはめようとオレオレ実装してる
- scaleしないから良くないけど、
- FW入れる程の物でもないのでそうしてる
振り返ると
- ここ1年でjs FW何個踏んできたのだろうか...
- MVVM周りで落ち着きそうだがRedOcean状態は変わらず
- vue.jsとても良さそう
- 結局、どこに落ち着くか不明だが、日本で仕事する分にはvue.jsが良さそうですな
まとめ
ractiveは、もういいや...
おしまい
以上。
ちなみに、翌日仕事だったので、途中で帰りました。
ビールごちそうさまでしたー。
IT勉強会の会場探し
もう、長い事、jsCafeというjavascriptの勉強会をやっていて、
最近、お世話になってた会場がオフィスになってしまったので、
改めて、会場を探した。
IT勉強会の会場探しは、結構、面倒くさいし、大変。
他に会場探してる方の役に立つかもしれないので、そのメモ残しておく。
IT勉強会の会場
まとめが幾つかある。
見てみると、当然、IT企業が多く、また、無料の会場も多い。
なお、ちゃんとそれぞれの会場のページも見た方が良い。
今、閉鎖した、とか、移転して今使えないとか色々あった。
通常は、この辺りのどこかで確保できるのだろう。。。
ただ、jsCafeの場合、土日開催で頻度が高く、
企業だと頻繁に土日出社して頂く事になり会場管理者に負担をかけるので、
結局、IT企業の会議室貸し出し系には手を出さなかった。
マナーですな。
貸し会議室
それ以外の選択肢に、貸し会議室という物がある
ピンキリだが、安くても、30人位で2時間だと、1万は超える。
更にprojecter + screen使うとなると、もう少しかかる。(1万位)
結局、安くても2万前後はかかる。
コワーキングスペース系
よくあるのが、コワーキングスペースやカフェっぽい所。
探すと開催は無料の所があるが、参加者に一人500円〜1000円位の
ドリンクオーダー等を課す所が一般的。
まあ、商売だし、当然だけど。
30人でやるとなると、30 × 1000円 = 3万円の会議室借りてるのと一緒だったりする。
公民館
最終的に、jsCafeは、公民館を選んでみた。
公民館も色々あって、殆どが、プロジェクタすら無い机椅子だけのスペースだったり、
ダンス教室?とかが用途の部屋ばかり。
だが、探せば、プロジェクタも使える公民館もある。
- 中央区立産業会館
- 中央区民館
- 公民館じゃないけど、オリンピックセンターもいいかもしれない
部屋もピンキリあり、多い所で、200人以上入る様な場所もびっくりするような値段で(数千円とか)で借りれたりする。
今回は
中央区民館の銀座区民館をとってみた。
プロジェクタも言えば使えて、夜3時間でたった2600円になった。(30名入るらしい)
とりあえず、参加者一人100円位払えば、どうにかなる。
素晴らしい。
ただ、こういう会場は当然、
wifi使えず、また、電源も使える量に限界があるので、IT勉強会向きではないが。
いつか、気が向いたら、どんな感じの会場だったか、記事に残す。
つぶやき
どこかに
- 無料で使えて、
- 土日開催出来て、
- 会場側にも負担かけなくて、
- 電源がちゃんと使えて
- wifi整理されてて、
- 最低でも30名は入る
夢の会議室無いかな…
(心当たりある方は、twitter @lxyuma までこっそり教えて下さい>< )
coffeescriptの使いどころ
最近、普通の現場で、coffeescriptの使いどころが分かってきた。
今日は、そのメモと、最後に設定(また、gulpとkarmaの話)を軽く書いておく。
railsとcoffee
自分は、ずっと、rails環境にいたので、coffeescriptで書いてた。
通常のコードも、テストコードも。勿論。
railsはjs周りもレールが敷かれていてcoffeeである事に特に何も違和感ないし、
メンバーも皆coffee使う前提で話進めれる。
他のrails以外の環境に入ると、
皆に、やっぱりcoffeescript使おうぜ、という空気に持っていきにくい。
宗教上の問題で。。。
coffee
coffeeとても、簡易な記述で素晴らしい。
が、classやthis(@)の扱いで、玉に分かり辛い所が出てきて、
多分、そういう所があまり好まれない。と勝手に思ってる。
でも、最近、どこでも使える良いシチュエーションを見つけた。
現場とcoffee
- ビルド環境の設定ファイル
- テスト
この2つで、coffee使うと明らかに幸せになれる。
ビルド環境の設定ファイルやテストの中の「function」にあまり意味は無く、
テストやビルド環境の内部での動きはあまり意識する事は無いので、
記号(->)で書いた方が楽。
また、いずれも、その内容(設定やテストを通して伝える仕様)を伝える事に価値があるので、
coffeeの簡潔な記述にすると、大分、すっきり内容を伝えられる。
coffeeの嫌な所
さっき書いた、classとか、this周りの動き等、coffeeでおそらく嫌がられる所は、
testやビルド環境の設定ファイルでは出てこないので、
(例えば、thisなら、テストで@val入れて、@val取る位しか使わないので、)
そこまで、coffeescript固有の面倒くさい所を意識する事はない。
学習コスト非常に低い。
テストとcoffee
昔、jasmine+coffeeで書いてたが、
それが、jasmine+生jsに変わると、
毎回、function書かなきゃ行けないのが、めっちゃ苦痛だった。
書くのもつらいけど、読むのもつらくなる。
階層が深くなると、括弧やインデントに、もう、イライラしてしまうが、
coffeeでテスト書くと、インデントも浅いし、functionも括弧もなく、
目に優しくなって、テスト内の仕様だけが浮き上がってくるので、
やっぱり、こっちの方が断然良い。
この時、他メンバーのためにも、jsでもテスト書けるようにしておくと、逃げ道があって良いかと。
この辺りの柔軟性もテストだから気軽に出来る。
実践
さて、ここから、実際にcoffee使う編の話。
最近使ってる、gulpとkarmaで書く。
とはいえ、coffeescriptも古いので、利用するやり方は整理されていて、非常に簡単。
設定と言う程の内容では無い。
gulpでcoffee
gulpは最近の3.7以降は、coffeeをデフォルトでサポートしてるらしい。
なので、coffeescriptのnpm入れるだけで書ける。
- npm install
npm install --save-dev coffee-script
- gulpfile.coffee
- こんな感じ
gulp = require('gulp') pl = require('gulp-load-plugins')() gulp.task 'scripts', -> gulp.src(["app/scripts/main.js", "app/scripts/*.js"]) .pipe(pl.concat(dist.js)) .pipe(gulp.dest(dist.dirJs)) .pipe(pl.connect.reload())
karmaでcoffee
- npm
npm install karma-coffee-preprocessor --save-dev
- karma.config.js
files: [ 'tests/**/*_spec.coffee' ], preprocessors: { "tests/**/*.coffee": ['coffee'] },
この時、filesの中に、jsのテストパスも入れてしまえば、生jsのテストと共存できる。
altjs
最近は、altjsいっぱい選択肢がある。
その中でも、coffeeであれば、
から、こういうシチュエーションで、coffee改めてオススメです。
テストや設定ファイルがごちゃごちゃしてきて大変になってきた方は、
coffee入れてみてはいかがでしょう?
以上。
最近のjsテスト/ビルド環境
最近のテスト環境
最近、ブログ書かないうちに、また、
自分のjs周りのテストやビルド環境が変わってきた。
具体的には、karmaとかgulpとかに変わった。
今日は、
その環境にしてどうだったか?とか、
設定ファイル(gulpfile)とか書いてみる。
去年と今年と
去年、勉強会等でyeomanとかgruntの話をしていて、このblogでもどこかに書いてた。
テストはmocha chaiが良いのかなーと思ってた。これもblog書いた。
所が、世の中どんどん変わっていく。
最近の環境
今はこんな感じ。
- build tool
- gulp
- test
- jasmine2
- sinon
- karma
gulp vs Grunt
gulpどうなんだろう?と思いながら色々試していくうちに、かなりしっくりきた。
stream baseで書き易いので、カスタマイズし易い。
gruntは、設定ファイルが何画面にも渡って長くなると、メンテが怠い。
何がどうなってるのか分からなくなって来る。
gulpは、小分けでタスク分けて依存関係も整理しながらstreamで書くので、非常にsmartで良い。
しかも、色々タスク積んでも並行実行はやっぱり早くて気持ちがよい。
Gruntも今後、色々gulpっぽくなりそうだけど、いつどうなるか、よくわかんない。
とりあえず、今日から始めるならgulpがいい。
yeoman
初め、yeomanとgulp組み合わせて使おうと思ってたけど、
なんか、最近、yeoman要らなくなってきた。
gulpだけでも、scaffoldingっぽい事も作れる。
yeoman色々事前に用意してくれてるんだけど、
実際の現場では、殆どの場合、使えない。(勿論、家で遊ぶなら、それでいいけど)
自分でカスタマイズしていかないといけない。
となるとカスタマイズし易いgulpだけで完結した方が扱い易い。という事でyeomanもう見てない。
jasmine vs mocha
mocha + chaiは、slideでも書いたんだけど、
language chainが気持ち悪くて結局、jasmineに戻った。
※should.jsもあるけど、もうrspecもshouldじゃなくてexpectなんだよな...shouldはobject破壊するので、いつか無理がでる
jasmineは2になって、非同期テストdoneが付いてて、
もう、mochaに大きなメリットが無くなってる。
jasmineは公式pageの1枚だけ調べれば何でも出来るAll in Oneのシンプルさが素晴らしい。
sinon
sinonはまだまだ使ってるなー。
最近は、要件上、htmlが大きく動く事が少ないので、そのままhtmlFixture使ってて、
TestDoubleそんなにしなくなったんだけど、
それでも、FakeTimerとかめっちゃ使う。
。。。これ書いてて思い出したけど、そういえば、
jasmine2にもtimerあったから、sinonのtimerでなくてもいいかも。明日から変えよう...
karma
昔は、それぞれのテスト環境の上にのっかったテストランナーを使ってた。
今、karma使うようになった。
こういう大きなeco systemに乗っかるメリットは、
困った時にググるとほぼ100%同じ事やってる人がいる事。
大体pluginとか助けてくれる。
HtmlFixtureもあるし、browser実行環境、report等、揃ってる。
勿論、他のtoolやtest FW単体でも出来るんだけど、
共通化されて整理されてるのは素晴らしい。
以前mocha固有の設定とかでイライラする事あったんだけど、karmaのおかげで大分助かってる。
gulpの設定等
今から使ってるgulp設定をおいておく
これは、今、componentっぽい物を幾つか作ってるのに使ってる設定で、
それぞれのprojectで使うには色々調整必要だと思う。
けど、なんかの参考迄に。
gulpのコマンド
- 以下を準備してる
// all(buildして、testして、監視します) gulp // build(js/cssをbuildします) gulp build // test(jsをtestします) gulp test // 単にindex.htmlが見たい gulp server // 新たにコンポーネントを追加したい gulp scaffold --name your_new_component_name
設定
- gulpfileはこんな感じにしてる
- $は、
var $ = require('gulp-load-plugins')();
の事。
- $は、
gulp.task("hint", function() { return gulp.src(paths.scripts) .pipe($.jshint()) .pipe($.jshint.reporter("default")) }); gulp.task('scripts', ['hint'], function() { return gulp.src(paths.scripts) .pipe($.uglify()) .pipe($.concat(dist.script)) .pipe(gulp.dest(dist.dir)) .pipe($.connect.reload()); }); gulp.task('styles', function() { return gulp.src(paths.styles) .pipe($.compass({ project: path.join(__dirname, 'app/styles') })) .pipe($.csso()) .pipe($.concatCss(dist.style)) .pipe(gulp.dest(dist.dir)) .pipe($.connect.reload()); }) gulp.task('connect', ['scripts', 'styles'], function() { $.connect.server({ root: './', port: server_port, livereload: true }); }); gulp.task('html', function(){ return gulp.src(paths.html) .pipe($.connect.reload()); }); gulp.task('watch', function(){ gulp.watch(paths.scripts, ['scripts']); gulp.watch(paths.styles, ['styles']); gulp.watch(paths.html, ['html']); gulp.src(karma_filepaths) .pipe($.karma({ configFile: karma_config, action: 'watch' })); }); gulp.task('test', function(){ return gulp.src(karma_filepaths) .pipe($.karma({ configFile: karma_config, action: 'run' })) .on('error', function(err) { throw err; }); }); gulp.task('scaffold', function(){ gulp.src(paths.templates.script) .pipe($.rename(argv.name + ".js")) .pipe($.template({name: argv.name})) .pipe(gulp.dest('app/scripts/')); gulp.src(paths.templates.style) .pipe($.rename(argv.name + ".scss")) .pipe($.template({name: argv.name})) .pipe(gulp.dest('app/styles/sass/')); gulp.src(paths.templates.test) .pipe($.rename(argv.name + "_spec.js")) .pipe($.template({name: argv.name})) .pipe(gulp.dest('tests/')); gulp.src(paths.templates.html) .pipe($.rename(argv.name + ".html")) .pipe($.template({name: argv.name})) .pipe(gulp.dest('tests/fixtures/')); }); gulp.task('server', ['connect'], function(){ gulp.src('./index.html') .pipe($.open('', {url: "http://localhost:" + server_port})); }); gulp.task('default', ['server', 'watch']); gulp.task('build', ['scripts', 'styles']);
gulpfileは現在進行形で編集中
- 今現在もこのgulpfile色々追加したり直したりしながら、使ってる
- 例えば、今日は、testからdocument生成用のtaskを書いてた。
- scaffold系は、それ専用のpluginもググるといっぱいあるので、そっち使ってもいいかもしれない。
- 無駄な所あったらごめんなさいね(concat周りとか)
gulpとjasmine2
- 環境設定はここにメモしてるので、良ければ。
まとめ
- FrontendはRedOceanで次々に変化起きるので、どんどん乗っかって楽するのが良い
1章レイテンシと帯域幅:ハイパフォーマンスブラウザネットワーキング
今、社内でO'Reillyの
「ハイパフォーマンスブラウザネットワーキング」
ハイパフォーマンス ブラウザネットワーキング ―ネットワークアプリケーションのためのパフォーマンス最適化
- 作者: Ilya Grigorik,和田祐一郎/株式会社プログラミングシステム社
- 出版社/メーカー: オライリージャパン
- 発売日: 2014/05/16
- メディア: 大型本
- この商品を含むブログ (1件) を見る
の勉強会(読書会)をしていて、
1章のレイテンシーをやったので、以下にも貼っておきます。
今この本読んでる方、沢山いらっしゃると思うので、
読書の手助けによければどうぞ。
ハイパフォ読書会
- 1章
パフォーマンスを左右する要素
レイテンシー構成要素
ルータ時間を消費する主要な構成要素
- 伝搬遅延(propagation delay)
- 伝送遅延(transmission delay)
- 処理遅延(processing delay)
- キューイング遅延(queuing delay)
書籍の中の説明文が分かり辛いので
- 別サイト参考に言い換えていくと
伝搬遅延
- パケット送信時にかかる物理的な遅延
- 例えば、光ファイバーだと、光の屈折等で遅延する時間の事(後で出て来る)
伝送遅延
- 書籍では、
パケットの全ビットをリンクに載せるまでにかかる時間
- リンクとは?データリンク層?何の事か?と思ってしまうが、
- ネットワークの話でリンクとは、ネットワークの構成要素(ノード)間をつなぐ線の事
- 伝送遅延を言い換えると
- 0,1の数字の羅列が転送。初めから最後のbitまで転送される時間が伝送遅延
- これは、単純に量や幅の話。パケットサイズ大きいか、帯域幅が狭いと大きくなる。その遅れの話。
処理遅延
- パケットのヘッダー処理
- パケットの次の方向を決定する間に、ルータが行うビットレベルのエラー検知
- これらによっての遅れの話。
キューイング遅延
伝搬遅延
- 光は毎秒29万km(真空中の早さ)
- 光を運搬する素材により遅くなる
- 屈折率が大きい程光も遅く伝わる
- 光ファイバの屈折率(1.4~1.6)による遅延も含めて概算すると
- 毎秒約20万km(元と比べると10万kmも違うんですね)
東京版伝搬時間の表
ルート | 距離 | 真空中の伝搬時間 | 光ファイバの伝搬時間 | 光ファイバでの往復時間 |
---|---|---|---|---|
東京-サンフランシスコ | 8280km | 28 ms | 41ms | 83ms |
東京-シンガポール | 5350km | 18ms | 27ms | 54ms |
東京版伝搬時間
- 東京-SFはNY-SF距離4000kmの2倍。NY-Sydneyが1.5万kmなので、その半分。
- 意外と短い(勿論、直線距離なので、実際はもっと複雑で距離かかるが)
- RTT:往復時間(Round Trip Time)
- NY-Sydneyが1.5万kmで160msと非常に遅い(北半球と南半球またぐと距離かかりますね)
人間の遅れの知覚
- 100-200msの遅延:遅れを知覚
- 300msの遅延:反応が鈍いと報告
- 1000ms超える:ユーザーの意識が切り替わる。
- この数値とさっきのNY-Sydney(160ms)と比べると、いかに伝搬時間大きいか分かる。
ラストマイル問題
- 大幅なレイテンシ:大抵、最後の数マイル
traceroute
- 経路するルータを見るならtraceroute
- 参考
googleにtraceroute
$ traceroute google.com traceroute: Warning: google.com has multiple addresses; using 74.125.235.101 traceroute to google.com (74.125.235.101), 64 hops max, 52 byte packets 1 xx.xx.xx.xx ( xx.xx.xx.xx) 1.416 ms 1.073 ms 1.470 ms 2 xx.xx.xx.xx ( xx.xx.xx.xx) 1.991 ms 2.660 ms 1.772 ms 3 xx.xx.xx.xx ( xx.xx.xx.xx) 2.167 ms 1.334 ms 1.391 ms 4 xx.xx.xx.xx ( xx.xx.xx.xx) 1.726 ms 1.682 ms 1.927 ms ・・・省略・・・ 11 209.85.251.39 (209.85.251.39) 2.467 ms nrt19s02-in-f5.1e100.net (74.125.235.101) 2.543 ms 209.85.251.39 (209.85.251.39) 2.665 ms
tracerouteの見方
$ traceroute to google.com (74.125.235.101), 64 hops max, 52 byte packets 1 12.34.56.789 (12.34.56.789) 1.416 ms 1.073 ms 1.470 ms // 順序番号(TTL) IPアドレス 1回目のTTL=1パケット往復時間 2回目 3回目
- ホップ:ルータがサブネット間を超える度に1カウント
- ここでは、最大64回迄ルータ移動する
- tracerouteはTTLを使ってる
TTL
- Time To Live:パケットの生存期間
traceroute 原理
- tracerouteは、TTL=1から初めて、エラー返されたらIPや時間計測して、1ずつ増やして繰り返す
- ここの記事の図が分かりやすい
tracerouteのエラー
- tracerouteは、多くのサーバーでFW等の都合で、最後まで辿れない。
各ユーザーの帯域幅
- Userが使用できる帯域幅はクライアントと宛先サーバー間の一番小さい帯域幅に依存する
- speedtestで、近くのサーバー(多分、東京)への上がり下りスピードを計測できる
- 家のブロードバンド環境で試してみて、プロバイダーの言ってた値と比較すると面白いかも
余談
- AWS tokyoのregion開設した時に検証されてる方のブログ記事
- traceroutesで内部ネットワーク調べたり
- pathcharで帯域幅を調べてる
- 実際にこれらの知識をどう使うか分かるので、要チェック。
- regionの距離やホップ数等の記事
次は
土日にまとめよう。
gulp vs Grunt
概要
gulpの入門記事を以下に書いて行きます。
- 目次
- gulpとは
- gulp sample
- gulp支える技術(Streamと並行性)
- grunt vs gulp どっち使う?
gulp.jsとは
- いわゆるフロントエンド周りの
- task runner
- build tool
Gruntあるでしょ
- その通り
- いわば、Gruntの簡易版
- 去年位?出来た後発のtool
- 最近、blog記事も増えてきた
公式Page売り文句
- 複雑なtaskも管理し易く、simpleで、使うのが簡単
- 一時fileのdisk書き込みが無いので早くて能率的
- simpleで期待通り動くようにPluginのGuidelineがある
- APIが小さく学習時間かからない
リソース
- gulp公式page
- 入門記事
sample多め
全体像
使い方の流れ
- Gruntと一緒
- pluginを追加
npm install gulp-xxx --save-dev
- gulpfileの更新
gulp.task('task-name', function(){ /* settings */ });
gulpfileとは
- 設定file(Gruntfileと一緒)
// 公式pageより // requireは省略。 gulp.task('scripts', function() { return gulp.src(paths.scripts) .pipe(coffee()) .pipe(uglify()) .pipe(concat('all.min.js')) .pipe(gulp.dest('build/js')); }); gulp.task('watch', function() { gulp.watch(paths.scripts, ['scripts']); }); gulp.task('default', ['scripts', 'watch']);
install
npm install -g gulp
$ gulp -v [gulp] CLI version 3.6.2
やってみる
- 今から、jsファイルをミニファイする簡単なgulp project作ってみる
project作成
- まずは、地盤固めから
mkdir my_first_gulp cd my_first_gulp npm init npm install --save-dev gulp
plugin追加
- minifyするplugin
npm install gulp-uglify --save-dev
設定ファイル
- gulpfile.jsを作成
var gulp = require('gulp'); var uglify = require('gulp-uglify'); gulp.task("uglify", function() { return gulp.src('js/*js') .pipe(uglify()) .pipe(gulp.dest("build/js")); }); gulp.task("watch", function() { return gulp.watch('js/*js', ['uglify']); }); gulp.task('default', ['uglify', 'watch']);
実験
- 試しにBackbone突っ込む
mkdir js cd js curl -O http://backbonejs.org/backbone.js cd ..
run
- 実行
- build/js/backbone.jsがminifyした?
gulp
振り返ってみる
- 今作ったsampleを一つずつ振り返ってみる
- 関連する技術をピックアップしながら進める
- streamや並列性の話
library呼び出し
var gulp = require('gulp'); var uglify = require('gulp-uglify');
- gulp本体とplugin呼び出してる
task
gulp.task("uglify", function() { return // ...any action });
- これで、taskを定義している
- この後、以下を黒い画面で実行できる
gulp uglify
taskの中身
return gulp.src('js/*js') .pipe(uglify()) .pipe(gulp.dest("build/js"));
- src => pipe => destという流れ
- gulp = node.jsのstreamを使ってる(後述)
- pipeの中で、uglify()等、先ほど呼び出した関数を実行
streamとは
- stream
- データの流れを抽象化したもの
- unixの pipeでやりとりしてる物と同じ
例示
- ※stream handbookより
- 今から以下の2つを比較して、何故stream要るか見てみる
- text読んで渡す処理を
- 通常とstream使用で比較してみる
通常で書くと
var http = require('http'); var fs = require('fs'); var server = http.createServer(function (req, res) { fs.readFile(__dirname + '/data.txt', function (err, data) { res.end(data); }); }); server.listen(8000);
- 問題点
- 扱いづらい
- memoryにfile内容をbufferしてる
- もし、data.txt馬鹿でかいと、多くのUserがメモリを食い散らかす
Stream使うと
var http = require('http'); var fs = require('fs'); var server = http.createServer(function (req, res) { var stream = fs.createReadStream(__dirname + '/data.txt'); stream.pipe(res); }); server.listen(8000);
- happy
- 奇麗
- diskからdata受け取るときに、data破片毎にclientに書き込める
- さっきの、でかいバッファ分の利用がなくなった
- このstreamの運搬してるのがpipe
- ここまでstream handbookでしたー
gulpのpipe
return gulp.src('js/*js') .pipe(uglify()) .pipe(gulp.dest("build/js"));
- gulp.src : file のstreamを作ってる
- pipe : streamを流す
- dest : streamを保存
gulp.srcについて
- 第2引数がoptions objでbuffer有無を設定出来る
- falseにすると、streamとしてfile.contentsを渡せるが
- 実はデフォルトはtrue
- File bufferも一応残してる
- pluginがstream対応していない事があるので、そうしてるらしい
sample
gulp.task('default', ['uglify', 'watch']);
- default taskを指定
- これで、黒い画面で
gulp
だけで打つと、uglifyとwatchタスクを実行する - ※ちなみに、以前あったgulp.runは今使えないっぽいので注意
- これで、黒い画面で
並列化について
gulp.task('default', ['uglify', 'watch']);
- 基本的に、自動的に並列化(並行化※後述)される
- 例だと、uglifyとwatchは順序は保証されない
並列化の仕組み
- js = single thread
- あれ?並列化?
- どうやってるんだろう?
言葉の整理から
- 1task以上を同時に実行する言葉は2つある
- parrallel(並列)
- concurrent(並行)
- 違いは、後者の並行が、
- 本当に並列である場合もあれば、
- 場合によっては時間毎に切り替える等の仮想的な並列である場合もある
- 参考
gulpは?
- gulpは、concurrency(並行)
- orchestratorを使ってるらしい
- orchestratorは、出来る範囲の並行性の中でタスクや依存性の順序並べや実行をしていくmodule
Orchestratorのconcurrency
- ソースを追うと、どうやら、
- 単に全task実行して
- それぞれ終了時のcallbackを指定していってるだけっぽい
- IO部分は確かに並列だが、それ以外はいつも通り
- (実際は、後述の直列の要素もあるのでもう少し複雑だが)
- "In node, everything runs in parallel, except your code" っていうヤツでしょうか。
gulpのTask実行順を指定
- gulpの話に戻ると
- taskを並列(並行)でなく直列にするには、以下、2つの条件が必要
- 1)依存してるtaskは非同期
- 2)taskの依存関係を指定
1)依存してるtaskは非同期
- 以下、いずれかの方法
- streamを返す事(src->pipe->destまでは非同期で直列)
- callbackを呼び出す事(mochaのdoneと同じ)
- promiseを返す事
2)taskの依存関係を指定
- 以下のdepsに、依存してるタスク名を書く
- taskの関数
gulp.task(name[, deps], fn)
- name : taskの名前
- deps:依存関係のあるタスク
- fn:その後実行する関数
gulp.task('default', ['uglify', 'watch'], function(){ // uglifyとwatch終わった後に実行される });
複雑な順番
gulp.task('a'); gulp.task('b', ['a']); gulp.task('c', ['a']); gulp.task('d', ['b', 'c']);
- この場合、いずれか
- a -> b -> c -> d
- a -> c -> b -> d
- orchestratorの中のsequencifyというlibが巧い事やってくれるらしい
- 参考
以上
- 大体ここまでの内容分かれば使えるはず
- 以下から好きなプラグイン探して入れて設定して使って行けばよい
gulp vs Grunt
- これも、どっちが生き残るのかな?
pluginの数は?
- Gruntが勿論、多い
- 2899個
- gulpは比較すると少ないが、数は増えてる
- 706個
- 普通に使う分には困らなさそう
- 数値はいずれも、公式ページから(2014/5/25現在)
Gruntのこれから
- 視点を変えてGruntの方を見てみる
- ver0.5で、並列実行が付く?(Roldmap)
grunt.registerTask('name', ['jshint', 'concat'], { parallel:true });
- ver1.0で、先程出てきたOrchestrator対応する?(grunt 1.0 alfa)
Gruntさん
- 大分gulpを意識してる?
- 並列性(並行性?)が入ってきそう
- 書き方も変わりそう
Gruntでgulp like
- gulp本家がsrcからdestまでのstream使う仕組みを外出し
- これでGruntでもgulp likeに書ける