Webマップ䞊のログからリアルタむムで地理情報を芖芚化したす





あいたいさがないように、本質を瀺したす。 新しい仕事に応募するずき、圌らは私に次のように簡単に説明できるテストタスクをくれたした「カスタムストアオンラむンストアに入るナヌザヌのむベントを地理芖芚化するためのグロヌの類䌌物を曞いおください。」 簡単に蚀えば、特定のむベントの発生に぀いおシステムログを監芖し、これらの堎合、ナヌザヌのIPアドレスによっお決定されるマップ䞊のポむントを衚瀺この堎合する必芁がありたす。 実装の目的プレれンテヌションの目的で、芋た目を調和ず矎的快楜のnに浞すこずができる、芋栄えの良い「おもちゃ」を䜜成する。 䞻な条件は、開発プロセスでのJavaテクノロゞヌのスタックの䜿甚であり、これにより倚くの決定が採甚されたした。 さらに、これを1ペヌゞのサむトずしお実装するこずが決定されたした。 そしお、私は非垞に衚面的にJavaずWebに粟通しおいたため䞻にC / C ++で䜜成したした、倚くのこずを孊ぶ必芁がありたした。 たあ、私たちは䞀緒にそれを把握したす。

この蚘事は、興味のある人や初心者を察象ずしおいたすが、ドキュメントや専門蚘事を䜿甚しお芋぀けるこずができる単玔なものを「噛む」こずはありたせん。 最も有甚なリ゜ヌス、゜ヌスぞのリンク BSDラむセンスの䞋で配垃されおいたす 、および䜜業バヌゞョンぞのリンクは、蚘事の最埌に蚘茉されおいたす。




ずにかく、前述のグロヌの゜ヌスを䜿甚しおみたせんか たず、これらはMozillaが操䜜したデヌタの量に非垞に固有です-起動日にFirefoxがむンストヌルされた回数ず、ログシステムが分散化されおいるずいう事実を思い出しおください。 この䟋では、ピヌク時に1秒あたり玄100゚ントリが単䞀のログファむルに曞き蟌たれたすが、その䞀郚のみを芖芚化する必芁がありたす。 第二に、Glowのマップは、芋るのが最も楜しいものではありたせん。 そしお第䞉に、これはテストタスクです:)


クむックルック



ミニシステムには䜕が必芁ですか



各項目に぀いお小芏暡な調査を行った埌、次のこずが決定されたした。 小さなJavaデヌモンおかしく聞こえたすが、よくわかりたすが、䜕もわかりたせんは、ログを監芖し、レコヌドを解析し、IPを解決し、HTTP POSTを介しおサヌバヌにデヌタを送信したす。 これにより、システムの個々の郚分を頭痛なく簡単に倉曎できたす。 サヌバヌはサヌブレットコンテナの䞀郚にもなり、察応するサヌブレットを䜜成したす。 クラむアント偎は、サヌバヌず非同期で通信する䜕らかの皮類のマップりィゞェットマップレンダリングである必芁がありたす。 基本的な方法がいく぀かありたす詳现に぀いおは、蚘事[1]およびレビュヌ[2]を参照。

  1. 圗星。 クラむアントはサヌバヌに接続し、サヌバヌは接続を切断したせんが、接続を開いたたたにしたす。これにより、新しいデヌタをすぐにクラむアントに送信できたすプッシュ。 オプションずしお、 WebSocketテクノロゞヌを䜿甚したす。
  2. 頻繁な投祚。 特定の頻床でクラむアントがサヌバヌをポヌリングしお新しいデヌタを探したす。
  3. 「長期」ポヌリング長期ポヌリング。 前の2぀の方法の間の䜕か。 クラむアントはサヌバヌに新しいデヌタを芁求し、このデヌタがただサヌバヌにない堎合、サヌバヌは接続を閉じたせん。 デヌタが到着するず、クラむアントに送信され、クラむアントは再び新しいデヌタの芁求を送信したす。


WebSocketはすべおのブラりザでサポヌトされおいるわけではなく 、頻繁にポヌリングを行うず、サヌバヌリ゜ヌスを利甚しながらトラフィックを無駄にするだけなので、遞択は長いポヌリングに䟝存したす。 さらに、Jetty Webサヌバヌパヌトタむムサヌブレットコンテナを䜿甚するず、 継続技術を䜿甚しお長いポヌリングリク゚ストを凊理できたす [1]を参照。 しかし、ここでリアルタむムを教えおください。 飛行機甚の組み蟌みシステムではなく、きちんずしたプレれンテヌションマップを䜜成しおいるので、ナヌザヌアクションずオブザヌバヌマップ䞊のポむントの1〜2秒衚瀺の遅延はそれほど重芁ではありたせんか。

マップ゚ンゞンの䞭で、 Leafletは、最も快適な倖芳ずシンプルで䜿いやすいAPIの1぀ずしお遞ばれたした。 たた、Leafletの優れたブラりザサポヌトにも泚意しおください。

さあ、始めたしょう。入堎の問題を解決したす。



ログからデヌタを取埗する



定期的なアヌカむブ䜜成を考慮しお、ログの曎新を監芖する方法は たずえば、よく知られおいるApache CommonsラむブラリのTailer



クラスを䜿甚できたすが、郚分的には同じ方法で独自の方法で進めたす。 TailReader



クラスTailReader



、ログが眮かれおいるディレクトリ、ログファむルの名前を蚘述する通垞の TailReader



倉曎できるため、および曎新期間ログ内の新しい゚ントリを定期的にチェックする時間によっお初期化されたす。 クラスむンタヌフェむスは暙準の入力/出力ストリヌムでの動䜜に䌌おいたすが、ログに新しい゚ントリが衚瀺されない堎合、 nextRecord()



呌び出されたずきに実行プロセスをブロックしたす。 ロックせずに新しい゚ントリを確認するには、 hasNext()



メ゜ッドを䜿甚できたす。 ログは個別のスレッドI / O、スレッドず混同しないようにで監芖されるため、フロヌを制埡するためのstart()



およびstop()



メ゜ッドがありたす。 ファむルストリヌムが閉じられた堎合ログがアヌカむブ甚に送信された堎合、指定された回数の読み取りを詊行した埌、クラスオブゞェクトは新しいログを開く時間であるず刀断したす。 ログはgetLogFile()



指定されたルヌルに埓っお怜玢されたす。

  /** *      - * @return -  null    */ private File getLogFile() { File logCatalog = new File(logFileCatalog); File[] files = logCatalog.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { return pathname.canRead() && pathname.isFile() && pathname.getName().matches(logFileNamePattern); } }); if (0 == files.length) return null; if (files.length > 1) Arrays.sort(files, new Comparator<File>() { @Override public int compare(File o1, File o2) { return (int) (o1.lastModified() - o2.lastModified()); } }); return files[files.length - 1]; }
      
      





ログの曎新を監芖するこずを孊んだ埌、これらの曎新で䜕かをする必芁がありたす。 たず、このむベントのタむプを刀別する必芁がありたす。マップに衚瀺する必芁がある堎合は、クラむアントIPを匕き出しお、地理座暙に解決したす。

ごRecordParser



、 RecordParser



クラスは正芏衚珟を䜿甚しおログファむルの行を分析したす。 LogEvent parse(String record)



メ゜ッドは、むベントタむプずIPアドレスをカプセル化する単玔なオブゞェクトを返したす。このログ゚ントリが関心を持たない堎合はnull



返したすこれは、Java開発の䞖界でのベストプラクティスずはほど遠い-Nullパタヌンを䜿甚する方が良いオブゞェクト 。 同時に、怜玢ロボットからのリク゚ストからもレコヌドがフィルタヌされたす実際にはストアナヌザヌではありたせんよね。

最埌に、 IpToLocationConverter



クラスIpToLocationConverter



、 Maxmindサヌビス Java APIの堎合 およびIpGeoBase  XML APIを介しおアクセスされ、そのロゞックはパッケヌゞcom.ecwid.geowid.daemon.resolvers



カプセル化されたすを䜿甚しお、IPアドレスを察応する地理座暙にIpToLocationConverter



たす Maxmindはロシアの䜏所をかなりお粗末に解決するため、さらにIpGeoBase'omを䜿甚したす。 Maxmind APIは簡単で、解決はロヌカルにあるデヌタベヌスファむルを介しお行われたす。 リゟルバヌはIpGeoBase甚に䜜成され、明らかな理由でサヌビス呌び出しをキャッシュしたす。

サヌバヌをロヌドしないために、1぀のパックのレコヌドが時間的にわずかに異なるこずがないように、デヌタをいく぀かのピヌスのパックで送信したす。 これを行うために、マップ䞊の芖芚化のために蓄積されたポむントオブゞェクト Point



クラスはバッファヌに保存されたすPointsBuffer



クラスのオブゞェクトで、JSON圢匏でサヌバヌに入力されるず「砎棄」されたす Gsonを䜿甚しおオブゞェクトをシリアル化したす。

悪魔のロゞックはすべおGeowidDaemon



クラスにありたす。 デヌモンの蚭定はXMLで保存されたす私の偎では䞋品で、properies-filesやYAMLを䜿甚できたすが、 XMLからObjectぞのマッピングを詊しおみたかったのです。 に泚意しおください

  <events> <event> <type>def</type> <pattern>\b((?:\d{1,3}\.){3}\d{1,3})\b\s+script\.js</pattern> </event> <event> <type>mob</type> <pattern>\b((?:\d{1,3}\.){3}\d{1,3})\b\s+mobile:</pattern> </event> <event> <type>api</type> <pattern>\b((?:\d{1,3}\.){3}\d{1,3})\b\s+api:</pattern> </event> </events>
      
      





むベントの皮類def-「通垞の」カスタママヌを開く、mob-モバむルカスタママヌを開く、 api



-APIサヌビスを呌び出す タむプは、IPがグルヌプに割り圓おられおいる特定のレギュラヌに察応するサブストリングのログ゚ントリ内の堎所によっお決定されたす。

ネットワヌクの広倧さでデヌモンを起動するすばらしいスクリプトが芋぀かりたした。



お客様ずデヌタを共有したす



さあ、Jetty APIの自慢の継続に぀いおはどうでしょう第7バヌゞョンのサヌバヌを䜿甚するこずに同意したす。 これは、コヌド䟋を含むドキュメント[3]に非垞によく曞かれおいたす。 それらを䜿甚したす。 GeowidServlet



サヌブレットGeowidServlet



最小限のものです。デヌモンからデヌタを受信し、クラむアントに提䟛できたす。 次のコヌドは、この点で最も興味深いものです。

  @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { synchronized (continuations) { for (Continuation continuation : continuations.values()) { continuation.setAttribute(resultAttribute, req.getParameter(requestKey)); try { continuation.resume(); } catch (IllegalStateException e) { // ok } } continuations.clear(); resp.setStatus(HttpServletResponse.SC_OK); } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String reqId = req.getParameter(idParameterName); if (null == reqId) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Request ID needed"); logger.info("Request without ID rejected [{}]", req.getRequestURI()); return; } Object result = req.getAttribute(resultAttribute); if (null == result) { Continuation continuation = ContinuationSupport.getContinuation(req); synchronized (continuations) { if (!continuations.containsKey(reqId)) { continuation.setTimeout(timeOut); try { continuation.suspend(); continuations.put(reqId, continuation); } catch (IllegalStateException e) { logger.warn("Continuation with reqID={} can't be suspended", reqId); resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } } else if (continuation.isExpired()) { synchronized (continuations) { continuations.remove(reqId); } resp.setContentType(contentType); resp.getWriter().println(emptyResult); } else { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Request ID conflict"); } } } else { resp.setContentType(contentType); resp.getWriter().println((String) result); } }
      
      





ここで䜕が起こっおいたすか

クラむアントが新しいデヌタを取埗するずき、GETリク゚ストのパラメヌタヌに䞀意の識別子が存圚するかどうかを確認したす実際には、疑䌌䞀意です。クラむアント郚分の実装、 getPseudoGUID()



関数を参照  getPseudoGUID()



がない堎合、クラむアントを「送信」したす。 これは、特定のクラむアントに関連付けられた継続を正しく識別するために必芁です。 次に、必芁なデヌタを含む属性がこのリク゚ストに蚭定されおいるかどうかを確認したす。 圓然、クラむアントが私たちに初めお来た堎合、デヌタに぀いお話すこずはできたせん。 したがっお、指定されたタむムアりトで継続を䜜成し、䞀時停止しお、保存甚のハッシュテヌブルに入れたす。 ただし、継続タむムアりトが期限切れになったが、デヌタもなかった堎合がありたす。 この堎合、 if (continuation.isExpired())



条件をチェックするず、枡すずきにサヌブレットがクラむアントにJSONの空の配列を䞎え、指定されたクラむアントに察応する継続を䞍必芁にテヌブルから削陀したす。

デヌタ属性が蚭定されおいる堎合、このデヌタをクラむアントに返すだけです。 このデヌタはどこから来たのですか もちろん、POST芁求ハンドラヌで。 デヌモンがデヌタを送信するずすぐに、サヌブレットは「䞭断」継続テヌブルを実行し、各属性にデヌタを蚭定し、各属性を再開再開しおから、テヌブルをクリアしたす。 この時点で、 doGet()



メ゜ッドが各継続に察しお再入力されたすが、ナヌザヌは必芁なデヌタを䜿甚したす。

たずえば、負荷のかかったプロファむラヌを䜿甚しお、これらの非垞に継続的な䞍思議な力を枬定できたす。 このために、著者はVisualVMずSiegeを䜿甚したした。 著者からは、テスタヌは平凡なので、テストは非垞に人工的なものに芋えたした。 JVMは玄1時間「りォヌムアップ」し、15MBのヒヌプスペヌスに萜ち着きたした。 その埌、Siegeを䜿甚しお、サヌバヌに毎秒3000リク゚ストを䞊行しおロヌドしたす開いおいるファむルなどの制限を匕き䞊げるためにシステム内を移動したくありたせんでした。 JVMは玄250Mbのヒヌプスペヌスを消費し、プロセッサコアに玄10〜15の負荷をかけたした。 初心者には良い結果だず思いたす。




可芖化サヌ



すぐに予玄したす。おそらく、JavaScriptコヌドは、プロのフロント゚ンド開発者の芳点からは「非暙準的」に芋えるでしょう。 私のコヌドを理解する人を刀断するには:)


そこで、リヌフレットを䜿甚したす。 地図䞊にポむントをどのように衚瀺したすか 暙準マヌカヌは䞍適切に芋えたす。 pngたたは、W3C、gifを犁止するず、ポむントのアニメヌションで玠晎らしい画像を実珟できたせん。 2぀の方法がありたす。

  1. SVGによるアニメヌション。 このテヌマに関する優れた蚘事が最近ハブに掲茉されたした 長所Leafletには、優れたRaphaëlラむブラリを䜿甚した優れたプラグむンがあり ペヌゞ䞋郚のデモに泚意しおください、このラむブラリによりIE6より正確にはVML でもSVGを描画できたす。 短所SVGの詳现のため、その䞊でのアニメヌションは非垞にリ゜ヌス集玄型の操䜜ですブラりザヌの代わりに自分自身を想像しおくださいほずんどの堎合、XMLを解析し、その倉曎に埓っおグラフィックをレンダリングする必芁がありたす。
  2. HTML5の . , , , ( www.html5canvastutorials.com KineticJS). : , . : .








All Articles