Vespaは、Elasticsearchよりも数癟䞇の男性ず女性を䞀臎させるのに優れおいたす





OkCupidの出䌚い系サむトの䞍可欠な郚分は、朜圚的なパヌトナヌの掚薊です。それらは、あなたずあなたの朜圚的なパヌトナヌが瀺した倚くの奜みの重耇に基づいおいたす。ご想像のずおり、このタスクを最適化する方法はたくさんありたす。



ただし、朜圚的なパヌトナヌずしおあなたを掚薊するたたは他の人の朜圚的なパヌトナヌずしおあなた自身を掚薊する人に圱響を䞎える芁因は、あなたの奜みだけではありたせん。ランク付けせずに、条件に䞀臎するすべおのナヌザヌを衚瀺するだけの堎合、リストはたったく最適ではありたせん。たずえば、最近のナヌザヌアクティビティを無芖するず、サむトにアクセスしおいない人ずの䌚話により倚くの時間を費やすこずができたす。あなたが指定する奜みに加えお、私たちはあなたが芋るべきだず思う人々をあなたに掚薊するために倚くのアルゎリズムず芁因を䜿甚したす。



可胜な限り最高の結果ず、ほが無限の掚奚事項のリストを提䟛する必芁がありたす。コンテンツの倉曎頻床が少ない他のアプリケヌションでは、掚奚事項を定期的に曎新するこずでこれを行うこずができたす。たずえば、Spotifyの「DiscoverWeekly」機胜を䜿甚するず、掚奚トラックのセットを楜しむこずができたす。このセットは来週たで倉曎されたせん。 OkCupidでは、ナヌザヌは自分の掚奚事項をリアルタむムで際限なく衚瀺したす。掚奚される「コンテンツ」は本質的に非垞に動的ですたずえば、ナヌザヌは蚭定、プロファむルデヌタ、堎所を倉曎したり、い぀でも非アクティブ化したりできたす。ナヌザヌは誰をどのように掚薊できるかを倉曎できるため、特定の時間に䞀臎する可胜性のあるものが最適であるこずを確認したいず思いたす。



さたざたなランク付けアルゎリズムを利甚しおリアルタむムの掚奚を行うには、ナヌザヌデヌタで垞に曎新され、朜圚的な候補をフィルタリングしおランク付けする機胜を提䟛する怜玢゚ンゞンを䜿甚する必芁がありたす。



既存の䞀臎怜玢システムの問題は䜕ですか



OkCupidは、独自の内郚怜玢゚ンゞンを䜕幎も䜿甚しおいたす。詳现に぀いおは説明したせんが、高レベルの抜象化では、ナヌザヌスペヌスシャヌド䞊のmap-reduceフレヌムワヌクであり、各シャヌドには関連するナヌザヌデヌタの䞀郚がメモリに含たれ、さたざたなフィルタヌや䞊べ替えをオンザフラむで有効にするずきに䜿甚されたす。怜玢語はすべおのシャヌドで分岐し、最終的に結果が組み合わされお䞊䜍k個の候補が返されたす。私たちが曞いたこのペアリングシステムはうたく機胜したのに、なぜ今それを倉曎するこずにしたのですか



今埌数幎間でさたざたな掚奚ベヌスのプロゞェクトをサポヌトするために、システムを曎新する必芁があるこずはわかっおいたした。私たちのチヌムが成長するこずはわかっおいたしたし、プロゞェクトの数も増えたした。最倧の課題の1぀は、スキヌマの曎新でした。たずえば、新しいナヌザヌデヌタ蚭定の性別タグなどを远加するには、テンプレヌトに数癟行たたは数千行のコヌドが必芁であり、展開には、システムのすべおの郚分が正しい順序で展開されるように泚意深く調敎する必芁がありたした。カスタムデヌタセットをフィルタリングしたり、結果をランク付けしたりする新しい方法を远加しようずするず、゚ンゞニアの時間は半日かかりたした。圌は、各セグメントを手動で本番環境に展開し、朜圚的な問題を監芖する必芁がありたした。さらに重芁なこずに、システムの管理ず拡匵が困難になっおいたす。シャヌドずレプリカは、゜フトりェアがむンストヌルされおいないマシンのフリヌト党䜓に手動で配垃されたためです。



2019幎の初めに、ペアリングシステムの負荷が増加したため、耇数のマシンにサヌビスむンスタンスを手動で配眮しお、レプリカの別のセットを远加したした。䜜業はバック゚ンドず開発者のために䜕週間もかかりたした。この間、組み蟌みサヌビスの怜出やメッセヌゞキュヌむングなどのパフォヌマンスのボトルネックにも気づき始めたした。これらのコンポヌネントは以前は正垞に機胜しおいたしたが、これらのシステムのスケヌラビリティに疑問を呈するようになりたした。私たちの仕事は、ワヌクロヌドのほずんどをクラりドに移動するこずでした。このペアリングシステムの移怍は、それ自䜓が面倒な䜜業ですが、他のサブシステムも含たれたす。



珟圚、OkCupidでは、これらのサブシステムの倚くがより堅牢でクラりドに適したOSSオプションによっお提䟛されおおり、チヌムは過去2幎間で倧きな成功を収め、さたざたなテクノロゞヌを採甚しおいたす。ここではこれらのプロゞェクトに぀いおは説明したせんが、代わりに、䞊蚘の問題に察凊するために行った手順に焊点を圓お、開発者にずっおより䜿いやすくスケヌラブルな怜玢゚ンゞンであるVespaに移りたす。



それは偶然ですOkCupidがVespaず友達になった理由



歎史的に、私たちのチヌムは小芏暡でした。怜玢゚ンゞンの遞択は非垞に難しいこずを最初から知っおいたので、私たちに圹立぀オヌプン゜ヌスのオプションを怜蚎したした。2぀の䞻芁な候補はElasticsearchずVespaでした。



Elasticsearch



これは、倧芏暡なコミュニティ、優れたドキュメント、およびサポヌトを備えた人気のあるテクノロゞヌです。たくさんの機胜があり、Tinderでも䜿甚されおいたす。 PUTマッピングを䜿甚しお新しいスキヌマフィヌルドを远加でき、構造化されたREST呌び出しを䜿甚しおク゚リを䜜成できたす。ク゚リ時間によるランク付け、カスタムプラグむンを䜜成する機胜などがサポヌトされおいたす。スケヌリングずメンテナンスに関しおは、シャヌドの数を定矩するだけで枈みたす。 、およびシステム自䜓がレプリカ配垃を凊理したす。スケヌリングには、より倚くのシャヌドを䜿甚しお別のむンデックスを再構築する必芁がありたす。



Elasticsearchを廃止した䞻な理由の1぀は、メモリに真の郚分的な曎新がないこずでした。むンデックスを䜜成しようずしおいるドキュメントは、いいねやメッセヌゞなどのために頻繁に曎新する必芁があるため、これはナヌスケヌスにずっお非垞に重芁です。これらのドキュメントは、広告や写真。ほずんどが䞀定の属性を持぀静的オブゞェクトです。したがっお、曎新時の非効率的な読み取り/曞き蟌みサむクルは、パフォヌマンスの倧きな問題でした。



ベスパ



゜ヌスコヌドはほんの数幎前に開かれたした。開発者は、ビッグデヌタをリアルタむムで保存、怜玢、ランク付け、敎理するためのサポヌトを発衚したした。Vespaがサポヌトする機胜



  • ( , 40-50 . )

  • ,

  • (, TensorFlow)

  • YQL (Yahoo Query Language) REST

  • Java-


スケヌリングずメンテナンスに関しおは、シャヌドに぀いおはもう考えたせん ã€‚コンテンツノヌドのレむアりトを蚭定するず、Vespaがドキュメントのシャヌディング、デヌタの耇補、配垃の方法を自動的に凊理したす。さらに、ノヌドを远加たたは削陀するたびに、デヌタが自動的に埩元され、レプリカから再配垃されたす。スケヌリングずは、単に構成を曎新しおノヌドを远加するこずを意味し、Vespaがこのデヌタをリアルタむムで自動的に再配垃できるようにしたす。



党䜓ずしお、Vespaは私たちのナヌスケヌスに最適であるように思われたした。 OkCupidには、ナヌザヌが最適なものを芋぀けるのに圹立぀さたざたな情報が含たれおいたす。フィルタヌず䞊べ替えだけで、100を超えるパラメヌタヌがありたす。垞にフィルタヌず䞊べ替えを远加するため、このワヌクフロヌを維持するこずは非垞に重芁です。゚ントリずク゚リの点では、Vespaは既存のシステムに最も䌌おいたす。぀たり、私たちのシステムでは、メモリ内の高速な郚分曎新の凊理ず、䞀臎芁求䞭のリアルタむム凊理も必芁でした。 Vespaは、はるかに柔軟でシンプルなランキング構造も備えおいたす。 Elasticsearchのク゚リの構造が䞍䟿であるのずは察照的に、もう1぀の優れたボヌナスはYQLでク゚リを衚珟できるこずです。スケヌリングずメンテナンスの芳点から、その埌、Vespaの自動デヌタ配信機胜は、比范的小芏暡なチヌムにずっお非垞に魅力的であるこずが蚌明されたした。党䜓ずしお、Vespaは、Elasticsearchよりも保守が容易であるず同時に、ナヌスケヌスずパフォヌマンス芁件をより適切にサポヌトするこずがわかりたした。



Elasticsearchはよく知られおいる゚ンゞンであり、Tinderの経隓から恩恵を受けるこずができたすが、どのオプションでも倧量の予備調査が必芁になりたす。同時に、Vespaは、Zedge、数十億の画像を備えたFlickr、1秒あたり10䞇回を超えるク゚リを備えたYahoo Gemini Ads広告プラットフォヌムなど、本番環境で倚くのシステムにサヌビスを提䟛し、月間10億人のアクティブナヌザヌに広告を配信しおいたす。これにより、これは戊闘でテストされた効率的で信頌性の高いオプションであるずいう確信が埗られたした。実際、VespaはElasticsearchの前から存圚しおいたした。



たた、Vespaの開発者は非垞に発信的で圹立぀こずが蚌明されおいたす。Vespaはもずもず広告ずコンテンツのために建おられたした。私たちの知る限り、それはただ出䌚い系サむトで䜿甚されおいたせん。独自のナヌスケヌスがあったため、最初ぱンゞンを統合するのは困難でしたが、Vespaチヌムは非垞に応答性が高く、システムを迅速に最適化しお、発生したいく぀かの問題に察凊できるようにしたした。



Vespaの仕組みずOkCupidでの怜玢の様子







Vespaの䟋に飛び蟌む前に、その仕組みの抂芁を簡単に説明したす。 Vespaは倚数のサヌビスのコレクションですが、各Dockerコンテナは、admin / configホスト、ステヌトレスJavaコンテナホスト、および/たたはステヌトフルC ++コンテンツホストずしお構成できたす。その他の構成、郚品、MLモデルずアプリケヌションパッケヌゞを経由しお展開するこずができおいる状態のAPIコンテナおよびコンテンツクラスタぞの倉曎の適甚を凊理する構成クラスタ内。フィヌド芁求およびその他の芁求は、フィヌドの曎新がコンテンツクラスタヌに到着する前、たたは分散芁求の実行が発生するコンテンツレむダヌに芁求がフォヌクされる前に、HTTPを介しおステヌトレスJavaコンテナヌ凊理のカスタマむズを可胜にするを通過したす。ほずんどの堎合、新しいアプリケヌションパッケヌゞの展開には数秒しかかかりたせん。たた、Vespaはこれらの倉曎をコンテナずコンテンツクラスタでリアルタむムに凊理するため、䜕も再起動する必芁はほずんどありたせん。



怜玢はどのように芋えたすか



Vespaクラスタヌドキュメントには、さたざたなナヌザヌ固有の属性が含たれおいたす。スキヌマ定矩は、ドキュメントタむプフィヌルドず、適甚可胜なランキング匏のセットを含むランキングプロファむルを定矩したす。次のようなナヌザヌを衚すスキヌマ定矩があるずしたす。



search user {

    document user {

        field userId type long {
            indexing: summary | attribute
            attribute: fast-search
            rank: filter
        }

        field latLong type position {
            indexing: attribute
        }

        # UNIX timestamp
        field lastOnline type long {
            indexing: attribute
            attribute: fast-search
        }

        # Contains the users that this user document has liked
        # and the corresponding weights are UNIX timestamps when that like happened 
        field likedUserSet type weightedset<long> {
            indexing: attribute
            attribute: fast-search
        }
        
   }

    rank-profile myRankProfile inherits default {
        rank-properties {
            query(lastOnlineWeight): 0
            query(incomingLikeWeight): 0
        }

        function lastOnlineScore() {
            expression: query(lastOnlineWeight) * freshness(lastOnline)
        }

        function incomingLikeTimestamp() {
            expression: rawScore(likedUserSet)
        }

        function hasLikedMe() {
            expression:  if (incomingLikeTimestamp > 0, 1, 0)
        } 

        function incomingLikeScore() {
            expression: query(incomingLikeWeight) * hasLikedMe
        }

        first-phase {
            expression {
                lastOnlineScore + incomingLikeScore
            }
        }

        summary-features {
            lastOnlineScore incomingLikeScore
        }
    }
    
}


この衚蚘indexing: attributeは、これらのフィヌルドの読み取りおよび曞き蟌みパフォヌマンスを最高にするために、これらのフィヌルドをメモリに栌玍する必芁があるこずを瀺しおいたす。



これらのカスタムドキュメントをクラスタヌに入力したずしたしょう。次に、䞊蚘のフィヌルドのいずれかでフィルタリングしおランク付けできたす。たずえば、デフォルトの怜玢゚ンゞンhttp://localhost:8080/search/にPOSTリク゚ストを送信しお777、珟圚地から50マむル以内で、タむムスタンプ以降オンラむンで、1592486978最埌のアクティビティでランク付けされ、䞊䜍2぀の候補を維持しおいる自分のナヌザヌ以倖のナヌザヌを怜玢したす。たた、summaryfeaturesを遞択しお、ランキングプロファむルの各ランキング匏の寄䞎を確認したしょう。



{
    "yql": "select userId, summaryfeatures from user where lastOnline > 1592486978 and !(userId contains \"777\") limit 2;",
    "ranking": {
        "profile": "myRankProfile",
        "features": {
            "query(lastOnlineWeight)": "50"
        }
    },
    "pos": {
        "radius": "50mi",
        "ll": "N40o44'22;W74o0'2",
        "attribute": "latLong"
    },
    "presentation": {
        "summary": "default"
    }
}


次のような結果が埗られたす。



{
    "root": {
        "id": "toplevel",
        "relevance": 1.0,
        "fields": {
            "totalCount": 317
        },
        "coverage": {
            "coverage": 100,
            "documents": 958,
            "full": true,
            "nodes": 1,
            "results": 1,
            "resultsFull": 1
        },
        "children": [
            {
                "id": "index:user/0/bde9bd654f1d5ae17fd9abc3",
                "relevance": 48.99315843621399,
                "source": "user",
                "fields": {
                    "userId": -5800469520557156329,
                    "summaryfeatures": {
                        "rankingExpression(incomingLikeScore)": 0.0,
                        "rankingExpression(lastOnlineScore)": 48.99315843621399,
                        "vespa.summaryFeatures.cached": 0.0
                    }
                }
            },
            {
                "id": "index:user/0/e8aa37df0832905c3fa1dbbd",
                "relevance": 48.99041280864198,
                "source": "user",
                "fields": {
                    "userId": 6888497210242094612,
                    "summaryfeatures": {
                        "rankingExpression(incomingLikeScore)": 0.0,
                        "rankingExpression(lastOnlineScore)": 48.99041280864198,
                        "vespa.summaryFeatures.cached": 0.0
                    }
                }
            }
        ]
    }
}


結果のランク付けを照合しおフィルタリングした埌、結果をランク付けするための第1フェヌズ第1フェヌズの蚈算された匏。返される関連性relevanceは、ク゚リで指定したランキングプロファむルrank-profileの最初のフェヌズのすべおのランキング機胜を実行した結果ずしおの党䜓的なスコアですranking.profile myRankProfile。リストに50ranking.featuresを定矩したすquery(lastOnlineWeight)。これは、䜿甚する唯䞀のランキング匏によっお参照されたすlastOnlineScore。属性のタむムスタンプが珟圚のタむムスタンプず比范しお最近のものである堎合、1に近い数倀である組み蟌みのランキング関数 freshnessを䜿甚したす。すべおが順調に進んでいる限り、ここで耇雑なこずは䜕もありたせん。



静的コンテンツずは異なり、このコンテンツは、ナヌザヌに衚瀺されるかどうかに圱響を䞎える可胜性がありたす。たずえば、圌らはあなたを奜きかもしれたせん奜きなナヌザヌのIDをキヌずしお、それが発生したずきのタむムスタンプを倀ずしお含む、各ナヌザヌドキュメントの加重フィヌルドに むンデックスを付けるこずができたすlikedUserSet。次に、あなたを奜きな人を陀倖するのは簡単ですたずえば、likedUserSet contains \”777\”YQLに匏を远加するが、ランク付け䞭にこの情報を含めるにはどうすればよいですか結果で私たちの人を奜きなナヌザヌのtogrを増やす方法は



以前の結果ではincomingLikeScore、これらのヒットの䞡方でランキング匏は0でした。ナヌザヌは6888497210242094612実際にナヌザヌを気に入りたした777しかし、私たちが入れたずしおも、珟圚ランキングでは利甚できたせん"query(incomingLikeWeight)": 50。我々は䜿甚するこずができたすランク機胜をYQL第1および機胜ぞの唯䞀の最初の匕数はrank()文曞が䞀臎しおいるかどうかを刀断したすが、すべおの匕数は、ランキングスコアを蚈算するために䜿甚されおいる、その埌、䜿甚ドット積を、この堎合には店舗ぞの私たちのYQL順䜍匏の䞭で、生のスコアを取埗したすナヌザヌが私たちを気に入ったずきのタむムスタンプ、たずえば、次のように



{
    "yql": "select userId,summaryfeatures from user where !(userId contains \"777\") and rank(lastOnline > 1592486978, dotProduct(likedUserSet, {\"777\":1})) limit 2;",
    "ranking": {
        "profile": "myRankProfile",
        "features": {
            "query(lastOnlineWeight)": "50",
            "query(incomingLikeWeight)": "50"
        }
    },
    "pos": {
        "radius": "50mi",
        "ll": "N40o44'22;W74o0'2",
        "attribute": "latLong"
    },
    "presentation": {
        "summary": "default"
    }
}


{
    "root": {
        "id": "toplevel",
        "relevance": 1.0,
        "fields": {
            "totalCount": 317
        },
        "coverage": {
            "coverage": 100,
            "documents": 958,
            "full": true,
            "nodes": 1,
            "results": 1,
            "resultsFull": 1
        },
        "children": [
            {
                "id": "index:user/0/e8aa37df0832905c3fa1dbbd",
                "relevance": 98.97595807613169,
                "source": "user",
                "fields": {
                    "userId": 6888497210242094612,
                    "summaryfeatures": {
                        "rankingExpression(incomingLikeScore)": 50.0,
                        "rankingExpression(lastOnlineScore)": 48.97595807613169,
                        "vespa.summaryFeatures.cached": 0.0
                    }
                }
            },
            {
                "id": "index:user/0/bde9bd654f1d5ae17fd9abc3",
                "relevance": 48.9787037037037,
                "source": "user",
                "fields": {
                    "userId": -5800469520557156329,
                    "summaryfeatures": {
                        "rankingExpression(incomingLikeScore)": 0.0,
                        "rankingExpression(lastOnlineScore)": 48.9787037037037,
                        "vespa.summaryFeatures.cached": 0.0
                    }
                }
            }
        ]
    }
}


68888497210242094612圌は私たちのナヌザヌが奜きで、それincomingLikeScoreは完党な意味を持っおいるので、 今、ナヌザヌはトップに匕き䞊げられたす。もちろん、より耇雑な衚珟で䜿甚できるように、実際には圌が私たちを気に入ったずきのタむムスタンプがありたすが、今のずころは単玔なたたにしおおきたす。



これは、ランキングシステムを䜿甚しお結果をフィルタリングおよびランキングするメカニズムを瀺しおいたす。ランキングフレヌムワヌクは、ク゚リ䞭に䞀臎する匏ほずんどは数孊的なものを適甚する柔軟な方法を提䟛したす。



Javaでミドルりェアを蚭定する



別のルヌトを䜿甚しお、このdotProduct匏を暗黙的にすべおのリク゚ストの䞀郚にしたい堎合はどうなりたすかこれがカスタムJavaコンテナレむダヌの出番です。カスタムサヌチャヌコンポヌネントを䜜成できたす。これにより、任意のパラメヌタヌを凊理し、ク゚リを曞き盎しお、特定の方法で結果を凊理できたす。Kotlinの䟋を次に瀺したす。



@After(PhaseNames.TRANSFORMED_QUERY)
class MatchSearcher : Searcher() {

    companion object {
        // HTTP query parameter
        val USERID_QUERY_PARAM = "userid"

        val ATTRIBUTE_FIELD_LIKED_USER_SET = “likedUserSet”
    }

    override fun search(query: Query, execution: Execution): Result {
        val userId = query.properties().getString(USERID_QUERY_PARAM)?.toLong()

        // Add the dotProduct clause
        If (userId != null) {
            val rankItem = query.model.queryTree.getRankItem()
            val likedUserSetClause = DotProductItem(ATTRIBUTE_FIELD_LIKED_USER_SET)
            likedUserSetClause.addToken(userId, 1)
            rankItem.addItem(likedUserSetClause)        
       }

        // Execute the query
        query.trace("YQL after is: ${query.yqlRepresentation()}", 2)
        return  execution.search(query)
    }
}


次に、services.xmlファむルで、このコンポヌネントを次のように構成できたす。



...       
         <search>
            <chain id="default" inherits="vespa">
                <searcher id="com.okcupid.match.MatchSearcher" bundle="match-searcher"/>
            </chain>
        </search>
        <handler id="default" bundle="match-searcher">
            <binding>http://*:8080/match</binding>
        </handler>
...


次に、アプリケヌションパッケヌゞを䜜成しおデプロむし、カスタムハンドラヌにリク゚ストを送信したすhttp://localhost:8080/match-?userid=777。



{
    "yql": "select userId,summaryfeatures from user where !(userId contains \"777\") and rank(lastOnline > 1592486978) limit 2;",
    "ranking": {
        "profile": "myRankProfile",
        "features": {
            "query(lastOnlineWeight)": "50",
            "query(incomingLikeWeight)": "50"
        }
    },
    "pos": {
        "radius": "50mi",
        "ll": "N40o44'22;W74o0'2",
        "attribute": "latLong"
    },
    "presentation": {
        "summary": "default"
    }
}


以前ず同じ結果が埗られたすKotlinコヌドでは、倉曎埌にYQLビュヌを出力するためのトレヌスバックを远加したためtracelevel=2、URLパラメヌタヌで蚭定するず、応答も衚瀺されるこずに泚意しおください。



...
                    {
                        "message": "YQL after is: select userId, summaryfeatures from user where ((rank(lastOnline > 1592486978, dotProduct(likedUserSet, {\"777\": 1})) AND !(userId contains \"777\") limit 2;"
                    },
...


Javaミドルりェアコンテナは、サヌチャヌを介しおカスタム凊理ロゞックを远加したり、レンダラヌを䜿甚しお結果をネむティブに生成したりするための匷力なツヌルです。Searcherコンポヌネントをカスタマむズしたす䞊蚘のようなケヌスや、怜玢で暗黙的に䜜成したいその他の偎面を凊理するため。たずえば、私たちがサポヌトする補品コンセプトの1぀は、「盞反性」のアむデアです。特定の基準幎霢範囲や距離などでナヌザヌを怜玢できたすが、候補者の怜玢基準も満たす必芁がありたす。 Searcherコンポヌネントでこれをサポヌトするために、怜玢しおいるナヌザヌのドキュメントをフェッチしお、フィルタリングずランク付けのための埌続のフォヌクされたク゚リでその属性の䞀郚を提䟛するこずができたす。ランキングフレヌムワヌクずカスタムミドルりェアは䞀緒になっお、耇数のナヌスケヌスをサポヌトする柔軟な方法を提䟛したす。これらの䟋では、いく぀かの偎面のみを取り䞊げたしたが、ここでは 詳现なドキュメントを芋぀けるこずができたす。



Vespaクラスタヌを構築しお本番環境に移行する方法



2019幎春、新システムの䌁画を開始したした。この間、Vespaチヌムにも連絡を取り、ナヌスケヌスに぀いお定期的に盞談したした。運甚チヌムはクラスタヌの初期蚭定を評䟡および構築し、バック゚ンドチヌムはさたざたなVespaのナヌスケヌスの文曞化、蚭蚈、およびプロトタむプ䜜成を開始したした。



プロトタむピングの最初の段階



OkCupidバック゚ンドシステムはGolangおよびC ++で蚘述されおいたす。カスタムVespaロゞックコンポヌネントを䜜成し、Java Vespa HTTPフィヌドクラむアントAPIを䜿甚しお高いフィヌドレヌトを提䟛するには、JVM環境に少し慣れる必芁がありたした。Vespaコンポヌネントの構成時ずフィヌドパむプラむンでKotlinを䜿甚するこずになりたした。



アプリケヌションロゞックを移怍しおVespa機胜を発衚し、必芁に応じおVespaチヌムに盞談するのに、数幎かかりたした。マッチ゚ンゞンのシステムロゞックのほずんどはC ++で蚘述されおいるため、珟圚のフィルタヌず゜ヌトデヌタモデルを、RESTを介しおVespaクラスタヌに発行する同等のYQLク゚リに倉換するロゞックも远加したした。早い段階で、ドキュメントの完党なナヌザヌベヌスでクラスタヌを再䜜成するための優れたパむプラむンの䜜成にも取り組みたした。プロトタむピングには、䜿甚する正しいフィヌルドタむプを決定するために倚くの倉曎を含める必芁があり、誀っおドキュメントフィヌドを再送信する必芁がありたす。



モニタリングずストレステスト



Vespa怜玢クラスタヌを䜜成したずき、2぀のこずを確認する必芁がありたした。それは、予想される量の怜玢ク゚リずレコヌドを凊理できるこずず、システムが提䟛する掚奚事項の品質が既存のペアリングシステムず同等であるこずです。



負荷テストの前に、Prometheusメトリックをいたるずころに远加したした。Vespa-exporterは倧量の統蚈を提䟛し、Vespa自䜓も远加のメトリックの小さなセットを提䟛したす。これに基づいお、1秒あたりのリク゚スト数、埅ち時間、Vespaプロセスによるリ゜ヌス䜿甚率など、さたざたなGrafanaダッシュボヌドを䜜成したした。たた、vespa-fbenchを実行しおク゚リのパフォヌマンスをテストしたした。 Vespa開発者の助けを借りお、私たちは比范的高いためにそれを決定したした静的な芁求のコストは、私たちのグルヌプ化された既補のレむアりトは、より高速な結果を提䟛したす。フラットレむアりトでは、ノヌドを远加するず、基本的に動的ク゚リ぀たり、むンデックス付けされたドキュメントの数に䟝存するク゚リの郚分のコストが削枛されるだけです。グルヌプ化されたレむアりトずは、構成された各サむトグルヌプにドキュメントの完党なセットが含たれるため、1぀のグルヌプが芁求を凊理できるこずを意味したす。静的リク゚ストのコストが高いため、ノヌドの数を同じに保ちながら、スルヌプットを倧幅に向䞊させ、フラットグルヌプの数を1぀から3぀に増やしたした。最埌に、静的ベンチマヌクの信頌性に自信が持おるようになったずきに、報告されおいない「シャドりトラフィック」もリアルタむムでテストしたした。



パフォヌマンスの最適化



チェックアりトのパフォヌマンスは、私たちが早い段階で盎面した最倧のハヌドルの1぀でした。圓初、1000 QPS1秒あたりのリク゚スト数でも曎新の凊理に問題がありたした。加重セットフィヌルドを倚甚したしたが、最初は効果がありたせんでした。幞いなこずに、Vespaの開発者は、これらの問題やデヌタ配垃に関連する他の問題の解決を迅速に支揎したした。圌らは埌に、フィヌドのサむズ蚭定に関する広範なドキュメントも远加したした。これは、ある皋床䜿甚しおいたす。倧きな加重セットの敎数フィヌルドは、可胜であれば、visibility-delay耇数の条件付き曎新を䜿甚し、属性フィヌルド぀たり、メモリ内に䟝存するずずもに、fmdovパむプラむンの操䜜を圧瞮およびマヌゞするこずにより、クラむアントからのラりンドトリップパケットの数を枛らしたす。珟圚、パむプラむンは定垞状態で3000 QPSを静かに凊理しおおり、このようなスパむクが䜕らかの理由で発生した堎合、私たちの謙虚なクラスタヌは11KQPSの曎新を凊理しおいたす。



掚奚の品質



クラスタが負荷を凊理できるこずを確認した埌、掚奚事項の品質が既存のシステムよりも悪くないこずを確認する必芁がありたした。ランク付けの実装にわずかな違いがあるず、掚奚事項の党䜓的な品質ず党䜓的な゚コシステムに倧きな圱響を及がしたす。実隓システムを適甚したした䞀郚のテストグルヌプではVespaが䜿甚されたしたが、コントロヌルグルヌプでは匕き続き既存のシステムが䜿甚されたした。次に、いく぀かのビゞネスメトリックが分析され、Vespaグルヌプがコントロヌルグルヌプよりも優れおいるずは蚀えないたでも、パフォヌマンスが向䞊するたで問題が繰り返され、文曞化されたした。Vespaの結果に自信が持おれば、䞀臎リク゚ストをVespaクラスタヌに転送するのは簡単でした。すべおの怜玢トラフィックを問題なくVespaクラスタヌに起動するこずができたした。



システム図



簡略化した圢匏では、新しいシステムの最終的なアヌキテクチャ図は次のようになりたす。







Vespaの珟圚の仕組みず次のステップ



Vespaペアファむンダヌの状態を以前のシステムず比范しおみたしょう。



  • スキヌマの曎新

    • 以前数癟行の新しいコヌドを含む1週間、耇数のサブシステムず慎重に調敎された展開

    • :
  • /

    • :

    • : . , !


    • : ,

    • : , Vespa . -


党䜓ずしお、Vespaクラスタヌの蚭蚈ず保守の偎面は、すべおのOkCupid補品の開発に圹立っおいたす。2020幎1月末に、Vespaクラスタヌを本番環境に移行し、ペアの怜玢におけるすべおの掚奚事項を提䟛したす。たた、今幎はStacksなどのすべおの新機胜をサポヌトするために、数十の新しいフィヌルド、ランキング匏、およびナヌスケヌスを远加したした。たた、以前のマッチメむキングシステムずは異なり、ク゚リ時にリアルタむムの機械孊習モデルを䜿甚するようになりたした。



次は䜕ですか



私たちにずっお、Vespaの䞻な利点の1぀は、テンサヌを䜿甚したランキングの盎接サポヌトず、TensorFlowなどのフレヌムワヌクを䜿甚しおトレヌニングされたモデルずの統合です。これは、今埌数か月で開発する䞻な機胜の1぀です。すでにいく぀かのナヌスケヌスでテンサヌを䜿甚しおおり、ナヌザヌの結果ず䞀臎をより正確に予枬できるように、さたざたな機械孊習モデルの統合を間もなく怜蚎したす。



さらに、Vespaは最近、完党にリアルタむムで、同時に怜玢可胜で、動的に曎新される倚次元最近傍むンデックスのサポヌトを発衚したした。リアルタむムの最近傍むンデックス怜玢の他の䜿甚䟋を調査するこずに非垞に興味がありたす。



OkCupidずVespa。行く



倚くの人がElasticsearchを聞いたり、䜿甚したりしおいたすが、Vespaの呚りにはそれほど倧きなコミュニティはありたせん。他の倚くのElasticsearchアプリケヌションがVespaでより適切に機胜するず信じおいたす。 OkCupidにずっおは玠晎らしいこずであり、切り替えおよかったです。この新しいアヌキテクチャにより、新しい機胜をはるかに迅速に進化および開発するこずができたした。私たちは比范的小さな䌚瀟なので、サヌビスの耇雑さに぀いおあたり心配しないのは玠晎らしいこずです。これで、怜玢゚ンゞンをスケヌルアりトする準備が敎いたした。 Vespaがなければ、過去1幎間の進歩は確かにあり埗たせんでした。 Vespaの技術的機胜の詳现に぀いおは、@ jobergumのeコマヌスガむドラむンにあるVespaAIを確認しおください。



私たちは最初の䞀歩を螏み出し、Vespa開発者が奜きでした。圌らは私たちにメッセヌゞを送り返したした、そしおそれは偶然であるこずがわかりたした Vespaチヌムの助けがなければ、これを行うこずはできたせんでした。感謝@jobergumず@geirstランキングずク゚リ凊理に関する掚奚事項に぀いおは、および@kkrauneず@vekterli圌らのサポヌトのため。 Vespaチヌムが私たちに䞎えおくれたサポヌトず努力のレベルは本圓に驚くべきものでした-私たちのナヌスケヌスぞの深い掞察からパフォヌマンスの問題の蚺断ずVespa゚ンゞンの即時の改善たで。同志@vekterliはニュヌペヌクの私たちのオフィスに飛んで、゚ンゞンの統合を支揎するために1週間私たちず盎接協力したした。 Vespaチヌムに感謝したす



結論ずしお、Vespaの䜿甚法のいく぀かの偎面に觊れただけですが、過去1幎間のバック゚ンドチヌムず運甚チヌムの倚倧な䜜業がなければ、これは䞍可胜でした。既存のシステムず最新のテクノロゞヌスタックずの間のギャップを埋めるために、倚くの固有の課題に盎面したしたが、これらは他の蚘事のトピックです。



All Articles