MessagePack vs POF(Coherence)でシリアライズサイズの勝負!
前回はJBoss MarshallingとMessagePackのシリアライズサイズを比較してみましたが、今回はCoherenceで使用しているPortable Object Format(POF)も比較してみましょう。
Oracleのページから評価版のCoherenceをダウンロードすれば良かったのかもしれませんが、手っ取り早くWebから情報を探してきました。「CoherenceのPOF形式でシリアライズされたオブジェクトのサイズ見積もりツール」(山本大@クロノスの日記)にPOFのシリアライズサイズについて載っています(こういう情報、ありがとうございます)。このページでは「Person.java」に「ExampleMain.java」でサンプルデータを入れてサイズ測定をしています。同じクラス、データでMessagePackでシリアライズして比較してみました。
各フレームワークの紹介
Coherenceで使われているシリアライズの仕組み。Javaのシリアライズでは効率が悪いため、独自に開発されました。言語に依存しないシリアライズの仕組みです。
その他についての紹介は、前回を参照してください。
シリアライズ結果
早速ですが、シリアライズ結果です。今回はJava標準のシリアライズも計測してみました。
Java標準
171byteのサイズにシリアライズされました。山本大さんのページに書いてある結果とも一致しています。
JBoss Marshallingと同じくクラス名の情報がシリアライズされたデータに入っているため、大きなデータになっています。
JBoss Marshalling
141byteのサイズにシリアライズされました。
Java標準より82%のサイズになっていますが、大きく変わったようには見えませんね。java.langパッケージの場合は、クラス名を短く表記できるようになってそうですね。
さて、ここからが本題です。
Portable Object Format
山本大さんのページの調査結果によると29byteのサイズにシリアライズされるそうです。手元にCoherenceがないので、すみませんがキャプチャはありません。Java標準の17%、JBoss Marshallingの21%のサイズになっています。
MessagePack
24byteのサイズにシリアライズされました。
おおっ、さすが。接戦ですが、POFに5byte勝ちました。Java標準の14%、JBoss Marshallingの17%、POFの83%のサイズになっています。MessagePackとPOFは、Java標準やJBoss Marshallingと比べると随分小さくシリアライズできるんですね。
という訳で、今回もMessagePackの勝ち!サイズ勝負だと、POFもなかなかでしたが、MessagePackが強いですね。
この結果は、シリアライザの総合力を比較しているのではなく、特定のデータをいかに小さなサイズにシリアライズできるかのみの観点で見ています。あくまでも、ひとつの側面としてご参考ください。
JBoss Marshalling vs MessagePackでシリアライズサイズの勝負!
ちょっと興味があり、シリアライズフレームワークについて調べてみました。Java標準のシリアライズはサイズが大きくなってしまうため、いろんな人が工夫して小さくシリアライズする仕組みを考えています。そんな中で、今回は(今回しかやらないかもしれませんが)、JBoss MarshallingとMessagePackでどちらが小さなサイズにシリアライズできるのか測ってみました。
各フレームワークの紹介
JBossの周辺で使われているシリアライズの仕組み。Javaのシリアライズでは効率が悪いため、独自に開発されました。
言語に依存しないシリアライズの仕組み。Format specificationを読むと、シリアライズの小さくするための工夫が徹底している感じがします。
シリアライズ対象のデータ
次のような、どこにでもありそうなクラスを作ってみました。
package jp.gr.java_conf.snuffkin.sandbox.infinispan; import java.io.Serializable; import org.msgpack.annotation.Message; @Message public class Tweet implements Serializable{ private static final long serialVersionUID = -7144860256641395394L; private String userid; private long timestamp; private String message; public String getUserid() { return userid; } public void setUserid(String userid) { this.userid = userid; } public long getTimestamp() { return timestamp; } public void setTimestamp(long timestamp) { this.timestamp = timestamp; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } @Override public String toString() { return "Tweet [userid=" + userid + ", timestamp=" + timestamp + ", message=" + message + "]"; } }
コメントは書いていませんが、簡単なクラスなのでご勘弁ください。要は、以下のようなプロパティを持つクラスです。
String userid long timestamp String message
各プロパティには、以下のような値を設定します。
userid="snuffkin" timestamp=現在時刻をミリ秒単位で表現した値 message=140文字のASCII文字列
シリアライズの結果
JBoss Marshalling、MessagePackをシリアライズし、ネットワークに流した結果をWiresharkで解析してみました。その結果は、次の通りです。
JBoss Marshalling
269byteのサイズにシリアライズされました。
クラス名やプロパティ名がシリアライズされたデータに入っているので、パッケージ名が長かったりするとデータが大きくなりますね。固い仕組みなのかもしれませんが、サイズだけ見るとロスがあります。手元に仕様書がないのですが、「3e」でプロパティを区切って、次にデータ長・データと並んでいるように見えます。
MessagePack
162byteのサイズにシリアライズされました。
うおっ。見るからにこちらの方が小さいです。MessagePackはサイズが小さなデータについては、型とデータ長を合わせて1byteに収めるようになっているせいか、見るからに隙間が少ないですね。また、プロパティは定義した順に配列として表現されており、プロパティ名の情報は失われています。
という訳で、結果はMessagePackの勝ち! 約40%もの差をつけての圧勝ですね。シリアライズに特性があったり(この仕組みだと、小さなデータほどサイズ比が大きくなりますね)、実際に使用するときにはサイズだけでなくシリアライズ速度も重要だったり、観点はいろいろあるべきだと思うのですが、ここでは、そのあたりは考慮に入れていません。サイズを比較したのみですので、あくまでも、ひとつの側面としてご参考ください。
イベントドリブンなネットワークプログラミングができるフレームワークNetty
このところ、JBoss関係のプロダクトに触ることが多いのですが、その中で特に気に入ったプロダクトがNettyです(NettyはJBossから独立していますが)。優れたプロダクトだと思うのですが、それほどドキュメントもないため、Nettyについて使ったり調べたことをまとめて行こうと思います。
Nettyとは?
Nettyは、イベントドリブンな非同期通信を行うアプリケーションを開発するためのフレームワークです。ソケット周りを直接触る処理はNettyが行ってくれて、イベントドリブンで接続・切断時の処理を記述したり、電文受信時の処理を記述することができ、簡潔で見通しの良いネットワークプログラミングができます。また、Nettyには電文処理を行うアプリケーションを開発するときに必要なライブラリが用意されているため、オリジナルプロトコルを使う場合にもNettyを使えば開発しやすいです。
「Netty: Home」がプロジェクトのサイトです。解説ドキュメントはあまり豊富ではありませんが、Javadocは充実しています。今のところ、Nettyを知る一番のドキュメントはJavadocではないかと思います。また、stackoverflow.comのNettyページでは、活発にQ&Aがやりとりされているため、こちらも参考になると思います。
ライセンスはApache License 2.0です。また、NettyはJavaで書かれています。
私がNettyを使いたくなった動機
RPCやらHTTPやら、異なる言語のプロセスと簡単に通信できる仕組みがいろいろと考えられてきたため、自力でネットワークプログラミングする機会は随分減りました。ですが、既存システムに合わせることが必須のプロジェクトもあり、TCP上のオリジナルプロトコルも健在です。「MessagePack-RPCとか使おうよ!」と言いたいところですが、どうにもなりません。
ネットワークプログラミングは、結構繊細なお決まりの処理をしなきゃいけないため、正直面倒です。JDBC周りでお決まりのclose処理を書くより遥かに面倒です。私はアプリケーションロジックを開発したいのに!
これが一体どれだけ面倒なのか、ちょっと見てみましょう。
まずは、NIO以前からある、昔ながらのSocketクラスを使ったプログラミング。エラー処理とか考えると、「Javaネットワークプログラミング講座」にあるサンプルのような処理が必要です(コードへのリンクがあるので、SocketConnector.java、MessageReciever.java、MessageSender.javaあたりを参照してください)。考えないといけないことが多く、結構大変です。
NIOの導入で便利になったものの、サーバ側だけでも「Java In The Box」にあるサンプルのような処理を書く必要があります。アプリケーションロジックを開発したいのに、依然として、このあたりの処理は面倒です。
とまあ、自分で書くのが面倒なので、他のサイトを参照させて頂きました。さて、ここまで読んだ人で、これらのサイトのコードをしっかり追った方はどのくらいいるでしょうか。正直、呪文のようなコードに挫折した人も多いのでは。サイトのコードが悪いのではなく、面倒な処理が必要なAPIになっているのです。
こういう実装は嫌だったので、いろいろ探してたどり着いたのがNettyでした。Nettyを使うと、ネットワークプログラミングをもっと見通し良く記述することができます。
Nettyを使った具体例
それでは、サンプルとしてクライアントから"Hello, World!"という文字列を受信してそのまま返すエコーサーバを紹介します。
「データの先頭に電文長があり、その後に実際の電文内容が続く」という電文プロトコルに、文字列を詰めて送信することにします。最初の4byteに電文長を格納し、残りは電文内容(文字列をbyteにしたもの)だとしましょう。
まずはサーバ側です。EchoServerがメインクラスです。具体的に受信した電文を処理しているアプリケーションロジックがEchoServerHandlerです。細かな説明は今回は省略し、別の機会に書きます。
- EchoServer
package jp.gr.java_conf.snuffkin.sandbox.netty.echo; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ServerBootstrap; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory; import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.LengthFieldPrepender; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; /** * サーバ側メインクラス */ public class EchoServer { public static void main(String[] args) { ChannelFactory factory = new NioServerSocketChannelFactory( // server Executors.newCachedThreadPool(), Executors.newCachedThreadPool() ); ServerBootstrap bootstrap = new ServerBootstrap(factory); bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() { ChannelPipeline pipeline = Channels.pipeline(); // Downstream(送信) pipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); pipeline.addLast("stringEncoder", new StringEncoder()); // Upstream(受信) pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(8192, 0, 4, 0, 4)); pipeline.addLast("stringDecoder", new StringDecoder()); // Application Logic Handler pipeline.addLast("handler", new EchoServerHandler()); // server return pipeline; } }); bootstrap.bind(new InetSocketAddress(9999)); // 9999番ポートでlisten } }
- EchoServerHandler
package jp.gr.java_conf.snuffkin.sandbox.netty.echo; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; /** * サーバ側アプリケーションロジック */ public class EchoServerHandler extends SimpleChannelHandler { /** * クライアントから電文を受信した際に呼び出されるメソッド */ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent event) { String msg = (String) event.getMessage(); // 受信電文を取りだす ctx.getChannel().write(msg); // クライアントに送信 } }
次にクライアント側です。EchoClientがメインクラスです。アプリケーションロジックを実装しているのが、EchoClientHandlerです。こちらも、細かな説明は今回は省略し、別の機会に書きます。
- EchoClient
package jp.gr.java_conf.snuffkin.sandbox.netty.echo; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ClientBootstrap; import org.jboss.netty.channel.ChannelFactory; import org.jboss.netty.channel.ChannelFuture; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory; import org.jboss.netty.handler.codec.frame.LengthFieldBasedFrameDecoder; import org.jboss.netty.handler.codec.frame.LengthFieldPrepender; import org.jboss.netty.handler.codec.string.StringDecoder; import org.jboss.netty.handler.codec.string.StringEncoder; /** * クライアント側メインクラス */ public class EchoClient { public static void main(String[] args) { ChannelFactory factory = new NioClientSocketChannelFactory( // client Executors.newCachedThreadPool(), Executors.newCachedThreadPool() ); ClientBootstrap bootstrap = new ClientBootstrap(factory); bootstrap.setPipelineFactory(new ChannelPipelineFactory() { public ChannelPipeline getPipeline() { ChannelPipeline pipeline = Channels.pipeline(); // Downstream(送信) pipeline.addLast("frameEncoder", new LengthFieldPrepender(4)); pipeline.addLast("stringEncoder", new StringEncoder()); // Upstream(受信) pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(8192, 0, 4, 0, 4)); pipeline.addLast("stringDecoder", new StringDecoder()); // Application Logic Handler pipeline.addLast("handler", new EchoClientHandler()); // client return pipeline; } }); ChannelFuture future = bootstrap.connect(new InetSocketAddress("localhost", 9999)); // 9999番ポートにconnect future.getChannel().getCloseFuture().awaitUninterruptibly(); bootstrap.releaseExternalResources(); } }
- EchoClientHandler
package jp.gr.java_conf.snuffkin.sandbox.netty.echo; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ChannelStateEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelHandler; /** * クライアント側アプリケーションロジック */ public class EchoClientHandler extends SimpleChannelHandler { /** * サーバに接続した際に呼び出されるメソッド */ @Override public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent event) { ctx.getChannel().write("Hello, World!"); } /** * サーバから電文を受信した際に呼び出されるメソッド */ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent event) { String msg = (String) event.getMessage(); System.out.println(msg); } }
動作の流れを解説すると、以下の通りです。
- EchoServerを起動してください。9999番ポートでクライアントからの接続を待ちます。
- サーバが起動したら、EchoClientを起動してください。EchoClientは9999番ポートに接続します。
- クライアントがサーバに接続すると、EchoClientHandler#channelConnectedがNettyから呼び出されます。この中で、サーバに対して文字列"Hello, World!"を送信します。
- サーバがクライアントからの電文を受信すると、EchoServerHandler#messageReceivedがNettyから呼び出されます。クライアントから受信した文字列を、クライアントに送信します。
- クライアントがサーバからの電文を受信すると、EchoClientHandler#messageReceivedがNettyから呼び出されます。サーバから受信した文字列を標準出力します。
Hello, World!
import文を除いたとしても、よくあるRPCのサンプルと比べるとコード量は多いです。ですが、この例はオリジナルプロトコルを実装したものであり、RPCライブラリに乗っかって通信したものより、多くの処理を自分で作ったことになります。なので、単純には比較できないですね。
アプリケーションロジックを書いているEchoServerHandlerやEchoClientHandlerを見てください。このくらい簡単にオリジナルプロトコルで通信することができます。このサンプルではエラー処理を省略したところがありますが、ネットワークプログラミングをイベントドリブンで記述できるようになると、こんなにも見通しが良くなります。Nettyを使わないサンプルと違って、コードを読む気になりますよね?
この例を振り返ってみると、byteの変数がまったく登場しません。このくらい簡単な例なら、byteの変数すら使わずに書けるのが、ネットワークアプリケーションを開発するためのフレームワークであるNettyの良さだと思います。
さて、Nettyの印象はどうだったでしょうか。Nettyの気持ち良さの一端が伝われば幸いです。今回書いたコードの具体的な解説は、また今度書きたいと思います。
AKBのぐぐたすリスト
数日前、Google+ ランキング G+Naviで調べたところ、Google+のフォロワー数トップ100にAKB関係者が79人も入っていました。物凄いことになってますね。日本のぐぐたすだけ、他の国とは別の発展の仕方をするかもしれませんね。
あまりに凄いので、Google+で公開されているメンバの一覧を作ってみました(データはGoogle+にあるこのページを元にしています)。https://plus.google.com/の後ろにGoogle+のidをつければ、そのidの人のpostが見れます。
こういうのがあれば、Google+ APIを使っていろいろ遊べそうですね。(一応断っておくと、私の興味の主眼はソーシャルデータです。芸能ネタも好きではありますが)
名前 | ふりがな | 所属グループ | 所属チーム | Google+のid |
---|---|---|---|---|
秋元才加 | あきもと さやか | AKB | K | 105020230123170728064 |
阿比留李帆 | あびる りほ | SKE | K2 | 102764447672444416615 |
石田晴香 | いしだ はるか | AKB | B | 101026469701528255144 |
板野友美 | いたの ともみ | AKB | K | 108406705498777962659 |
今出舞 | いまで まい | SKE | SKE48研修生 | 106656898590733509216 |
内田眞由美 | うちだ まゆみ | AKB | K | 105842454176256413407 |
梅田彩佳 | うめだ あやか | AKB | K | 112077362806147944184 |
梅本まどか | うめもと まどか | SKE | E | 118425778047788093453 |
大島優子 | おおしま ゆうこ | AKB | K | 105229500895781124316 |
大場美奈 | おおば みな | AKB | 4 | 110216234612751595989 |
大家志津香 | おおや しづか | AKB | A | 108367535733172853340 |
大矢真那 | おおや まさな | SKE | S | 116324240483798147615 |
小木曽汐莉 | おぎそ しおり | SKE | K2 | 107135851528812577523 |
小野晴香 | おの はるか | SKE | S | 111145641865855965824 |
河西智美 | かさい ともみ | AKB | B | 110230842586402039931 |
柏木由紀 | かしわぎ ゆき | AKB | B | 109547251260290757268 |
片山陽加 | かたやま はるか | AKB | A | 108485060451296256117 |
加藤智子 | かとう ともこ | SKE | K2 | 108340808318911923001 |
菊地あやか | きくち あやか | AKB | K | 102861211420357915358 |
北原里英 | きたはら りえ | AKB | B | 114392080665434978357 |
鬼頭桃菜 | きとう ももな | SKE | SKE48研修生 | 102982862918484502371 |
木下有希子 | きのした ゆきこ | SKE | S | 117533056464814306425 |
倉持明日香 | くらもち あすか | AKB | A | 103787924613525409143 |
桑原みずき | くわばら みずき | SKE | S | 100200160956657706975 |
小嶋陽菜 | こじま はるな | AKB | A | 114739367195523292316 |
小林亜実 | こばやし あみ | SKE | E | 103904242672756284899 |
小林香菜 | こばやし かな | AKB | B | 111171583195412578810 |
指原莉乃 | さしはら りの | AKB | A | 104375100134443203420 |
佐藤亜美菜 | さとう あみな | AKB | B | 108623251197634437138 |
佐藤すみれ | さとう すみれ | AKB | B | 112309691086068535265 |
佐藤聖羅 | さとう せいら | SKE | K2 | 112980138521977900424 |
佐藤夏希 | さとう なつき | AKB | B | 102181587900817571440 |
佐藤実絵子 | さとう みえこ | SKE | K2 | 114397630658650917209 |
篠田麻里子 | しのだ まりこ | AKB | A | 105312608513060875034 |
柴田阿弥 | しばた あや | SKE | E | 113499890803474188597 |
島田晴香 | しまだ はるか | AKB | 4 | 102844391735210836268 |
島田玲奈 | しまだ れな | NMB | NMB48研修生 | 106176150979443047095 |
鈴木まりや | すずき まりや | AKB | B | 109273326082502819549 |
須田亜香里 | すだ あかり | SKE | S | 115975634910643785199 |
高木由麻奈 | たかぎ ゆまな | SKE | E | 100806834975375116663 |
高城亜樹 | たかじょう あき | AKB | A | 107954758685270685108 |
高田志織 | たかだ しおり | SKE | S | 112166094088653039891 |
高野祐衣 | たかの ゆい | NMB | NMB48研修生 | 114488817218493827050 |
高橋みなみ | たかはし みなみ | AKB | A | 116816132092699657436 |
高柳明音 | たかやなぎ あかね | SKE | K2 | 106926723626971174827 |
竹内舞 | たけうち まい | SKE | E | 111253632744203791499 |
田名部生来 | たなべ みく | AKB | K | 115449512138863581856 |
近野莉菜 | ちかの りな | AKB | B | 103259286719163415846 |
出口陽 | でぐち あき | SKE | S | 101713591556895969107 |
仲川遥香 | なかがわ はるか | AKB | A | 102249965218267255722 |
中田ちさと | なかた ちさと | AKB | A | 106819068054122298292 |
中塚智実 | なかつか ともみ | AKB | K | 106902079329146402543 |
中西優香 | なかにし ゆうか | SKE | S | 107061289389523750061 |
仲俣汐里 | なかまた しおり | AKB | 4 | 115842256718368316968 |
中村麻里子 | なかむら まりこ | AKB | 4 | 100757137373116382078 |
仲谷明香 | なかや さやか | AKB | A | 117151902078571783647 |
仁藤萌乃 | にとう もえの | AKB | K | 106541618903520668641 |
野中美郷 | のなか みさと | AKB | K | 101031357714890657558 |
秦佐和子 | はた さわこ | SKE | K2 | 108037953963364967101 |
平嶋夏海 | ひらじま なつみ | AKB | B | 117480374878682152542 |
平田璃香子 | ひらた りかこ | SKE | S | 100593468647281401358 |
平松可奈子 | ひらまつ かなこ | SKE | S | 111254737005235237589 |
福本愛菜 | ふくもと あいな | NMB | N | 101854092637878212405 |
古川愛李 | ふるかわ あいり | SKE | K2 | 111050677534976069347 |
前田敦子 | まえだ あつこ | AKB | A | 116582420246242769167 |
増田有華 | ますだ ゆか | AKB | B | 116563387779051485156 |
松井咲子 | まつい さきこ | AKB | K | 111700319553120354024 |
松井玲奈 | まつい れな | SKE | S | 108536765591006886419 |
松原夏海 | まつばら なつみ | AKB | A | 110106903212386059477 |
松村香織 | まつむら かおり | SKE | SKE48研修生 | 108705263081706477178 |
松本梨奈 | まつもと りな | SKE | K2 | 111792731544936626652 |
峯岸みなみ | みねぎし みなみ | AKB | K | 113175170244847276511 |
宮崎美穂 | みやざき みほ | AKB | B | 105599945949824406376 |
宮澤佐江 | みやざわ さえ | AKB | K | 111186383073996701022 |
村上文香 | むらかみ あやか | NMB | NMB48研修生 | 117655629637021320261 |
矢方美紀 | やかた みき | SKE | K2 | 102565671074822095382 |
山口夕輝 | やまぐち ゆうき | NMB | N | 103663030781390958288 |
山田菜々 | やまだ なな | NMB | N | 102277090985412703374 |
山本彩 | やまもと さやか | NMB | N | 101423472932208115437 |
横山由依 | よこやま ゆい | AKB | K | 109380179669644031316 |
米沢瑠美 | よねざわ るみ | AKB | K | 110841113220926588945 |
渡辺美優紀 | わたなべ みゆき | NMB | N | 109544372058574620997 |
ACLとJ2を同時に戦う夢のようなことは起きず
男子は史上初のJ2対決の決勝。今年の天皇杯は本当に番狂わせでしたね。決勝のJ2対決だけでなく、JFLの松本山雅がJ2横浜FC・J1アルビレックス新潟を撃破したのもビックリ。なぜか大きく報道されていないと思いますが、一番の驚きはJ1の大宮アルディージャが大学生に負けたこと。一体どうなっているんでしょう。J1昇格した年に柏レイソルが優勝したし、何かおかしなことになっていませんか。
で、一番期待したのは京都サンガが優勝して、ACLとJ2を同時に戦う夢のようなことが起きること。なので、京都サンガを応援しましたが、さすがにFC東京はJ2チャンピオンでしたね。京都が先制するも、今野のゴールですぐに追いつく(FC東京のファンには感慨深いゴールでしょうね)と、森重のフリーキックで勝ち越し点。このフリーキック、斜め横方向から見ていたのですが、キーパーが若干変な動きして、ゴールのそれほど隅でもないところに決まりました。「なんとなく伸びた?」とは思いましたが、あまり気にしていませんでした。その後、VTRで分かったのですが、実はコレ、無回転シュートだったんですね。初めて生で見ました。横から見ていると良く分かりませんね。。。
あとは、ルーカスや石川が上手すぎて、歯が立たない感じでした。このサッカーができれば、J1に入っても上位に行けるはず。スコアは4-2でしたが、京都もひどかった訳ではなく、ちゃんとしていました。今日のようなレベルを年間通してキープできれば、J1で戦えるチームだと思いました。偶然決勝に来たわけではなく、両チームとも調子が良かったから決勝に来たのだろうと思います。