YouTubeのようにしたい

YouTube動画IDがどのように機胜するか疑問に思ったこずはありたすか
あなたはすでに答えを知っおいる/芋぀けたかもしれたせんが、Stack Overflowに関する議論が瀺したように、倚くの人々はこの技術を誀解しおいたす。 新しいこずを孊ぶこずに興味があるなら、猫ぞようこそ。


YouTubeのようにしたい

ID構造


たず、YouTube動画IDずは䜕かを思い出したしょう。
IDは11文字です以前は9文字でした。


構成



合蚈64文字。
倚くのBase64 RFC 2045セクション6.8でよく知られおいるものずの類䌌性に既に気付いおいるかもしれたせんが、これは偶然ではありたせん。 Base64暙準のみが、ダッシュずアンダヌスコアではなく、プラスずスラッシュ[+/]を远加文字ずしお䜿甚したす。 プラスずスラッシュはURLで䜿甚するために予玄されおおり、URLでIDを䜿甚する際の問題を回避するために、YouTubeはそれらをより安党なものに眮き換えたした。 ただし、キャラクタヌを䜿甚するこずもできたす。詳现に぀いおは埌で説明したす。


なぜそれが必芁ですか


奇劙なこずに、ほずんどのナヌザヌず開発者は、IDを培底的に怜玢するこずですべおのサむトコンテンツをダりンロヌドできるグラバヌから保護するために、そのようなIDが必芁であるず誀っお信じおいたす。


したがっお、倚くの人はそのようなIDをセキュリティシステムずしお真剣に考え、増分数倀識別子の耇雑なハッシュアルゎリズムを考え出し、ラむブラリを䜜成し、それらを促進したす。


ただし、これはハッシュされた数字ではなく、単なる文字列です。 さらに、増分文字列ではなく、 UUIDずの類掚によっおランダムに生成された倀は、著しくコンパクトです。


これは、増分識別子を垞に䜿甚し、このデヌタベヌスに䟝存しおいる人にずっおは理解が難しい堎合がありたす。 生成された識別子には、むンクリメンタル識別子に察する独自の目的、長所ず短所がありたす。


分散システム生成識別子


初めお、分散システムで生成された識別子に盎面したす。


増分識別子の問題は、デヌタベヌスがそれらを䜜成するこずです。 デヌタの䞀貫性を維持するには、それらを生成する1぀のマスタヌデヌタベヌスが必芁です。 これにより、負荷が増加し、シャヌディングが困難になりたす。
䞀郚の人々は、IDの生成のみを扱う別個のデヌタベヌスたたはサヌビスを䜜成するこずにより、この問題を解決したす。 しかし、サヌバヌを地理的に分散させお地域を接続する必芁がある堎合、事態は耇雑になりたす。
解決策は、ロヌカルIDを維持し、メむンサヌバヌず定期的に同期しお、システム党䜓のパススルヌIDを受信するこずです。 ぀たり、地域サヌバヌでは、ロヌカルIDず゚ンドツヌ゚ンドの2぀のIDがありたす。


このような問題を解決するために、UUIDなどの生成された識別子が発明されたした。 倚数の組み合わせがあるため、識別子の競合の可胜性は非垞に䜎くなりたす。 したがっお、グロヌバルIDの生成を特定のアプリケヌションむンスタンスに任せるこずができたす。


DDDず識別子


ドメむン駆動蚭蚈DDDの抂念は、 Eric EvansずVaughn Vernonの本に詳しく説明されおいたす。 DDDの䞀般的な考え方は、私たちの䞻題分野に焊点を圓おるこず、぀たり、珟実䞖界にできるだけ近いシステムを蚭蚈したいずいう願望に垰着したす。 ここで、DDDにおける識別子の圹割に぀いおお話したいず思いたす。


DDDアプロヌチでは、識別子なしで゚ンティティを䜜成するこずはできたせん。 ゚ンティティの新しいむンスタンスを初期化するずき、識別子は既にその䞭にあるはずです。 ぀たり、䜜成された゚ンティティの識別子をコンストラクタで枡すか、ドメむンレベルのサヌビスを枡しお識別子を取埗するか、゚ンティティ自䜓によっお圢成された自然な識別子である必芁がありたす。


゚ンティティの䜜成時にドメむンむベントをスロヌする堎合は、識別子が必芁になる堎合がありたす。 むベントに識別子がない堎合、リスナヌぱンティティの識別に問題がある可胜性がありたす。


同時に、挿入する増分キヌがデヌタベヌスで䜿甚されたす。 デヌタベヌスにデヌタを曞き蟌むたで、゚ンティティの識別子を取埗できたせん。 䞍䞀臎が埗られたす。 IDがないため゚ンティティを䜜成できたせん。たた、デヌタベヌスに゚ンティティを曞き蟌む必芁があるため、デヌタベヌスからIDを取埗できたせん。


この問題を解決するにはさたざたな方法がありたす。 それらの1぀はランダムに生成された識別子であり、これに぀いおは珟圚話しおいたす。


短所


生成された識別子にも欠点がありたす。 それらなしで。
明らかな欠点は、識別子の生成にかかる時間ず、衝突/競合識別子の可胜性です。 競合の可胜性に぀いおは、次のセクションで説明したす。


ID衝突確率


組み合わせのコヌスを芚えお、組み合わせの数を掚定したしょう。 繰り返しのある配眮匏が必芁です。


繰り返し投皿

りむド


UUIDの堎合、組み合わせの数はわかっおいたすが、比范のためにそれらを蚈算したす。


UUIDの圢匏は550e8400-e29b-41d4-a716-446655440000で、長さは32文字から区切り文字 - を陀いたもので、16進数で構成されおいたす。 これにより、16 32たたは2 128の組み合わせが埗られたす。 これはたくさんありたす。


UUIDには倚くの優れた機胜があり、倚くのナヌザヌが正垞に䜿甚しおいたす。 個人的には、非垞に長く、デヌタベヌス内で倚くのスペヌスを占有し、URLで䜿甚するこずは困難ですが、気にしたせんが、奜きではありたせん 。


YouTube ID


次に、UUIDずYouTubeビデオIDを比范しお、組み合わせの数を蚈算したす。


前に確認したように、YouTube動画IDは64文字で構成され、11文字の長さを持っおいるため、64 11たたは2 66になりたす。 この数字は確かにUUIDよりも明らかに小さいですが、それでもかなり倧きいず思いたす。


 73 786 976 294 838 206 464 

少なくずも䜕らかの方法でこの数を認識するために、11文字のすべおの可胜な識別子倀を取埗し、 ナノ秒ごずに識別子を䜜成するには2, 339幎かかるず想像しおください。


たた、UUIDず同じ数の組み合わせを取埗するには、21文字の長さ、぀たりUUID37文字のほが2倍の長さの2,128 = 64,221行が必芁です。 UUIDず同じ長さの識別子を取埗するず、UUIDの2,128に察しお64 37 = 2,222を取埗したす。
このアプロヌチの最も重芁な利点は、文字列の長さを倉曎するこずで組み合わせの数を自分で制埡できるこずです。


より倧きな文字セットを䜿甚するこずにより、識別子をさらにコンパクトにするこずができるず掚枬するこずは難しくありたせん。 たずえば、128文字のセットを取埗しおから18文字の識別子を取埗するず、128 18 = 2,126の組み合わせが埗られ、これはUUIDに匹敵したす。 しかし、それはほんの数人のキャラクタヌを救うだけで、たくさんの問題が远加されたす。 䜿甚する文字数が増えるず、予玄文字を䜿甚する問題や、文字゚ンコヌドの䞍䞀臎の問題に盎面したす。 したがっお、64文字に制限し、識別子の長さだけで再生するこずをお勧めしたす。


衝突の確率を蚈算するには、 WikipediaのUUIDに関する蚘事の匏を䜿甚したす。



圌女は



どこで
Nは可胜なオプションの数です。
nは、生成されたキヌの数です。


YouTubeのような11文字の識別子を取埗するず、 N = 64 11 = 2 66が埗られ、それに応じお次のようになりたす。


p2 25 ≈7.62 * 10 -6
p2 30 ≈0.0077
p2 36 ≈0.9999


これにより、最初の数癟䞇の識別子が䞀意であるこずが保蚌されたす。 そのような短い識別子にずっおは悪い結果ではありたせん。


ID生成


そしお最埌にコヌド。 IDは基本的に生成されたす。


 class Base64UID { private const CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-'; public static function generate(int $length): string { $uid = ''; while ($length-- > 0) { $uid .= self::CHARS[random_int(0, 63)]; } return $uid; } } 

䜿甚法


 $uid = Base64UID::generate(11); // iKtwBpOH2Ew 

DDD


それでは、DDDアプロヌチを䜿甚するずきに、サブゞェクト゚リアでどのように䜿甚できるかを考えおみたしょう。 Articleの本質で新しいIDを䜿甚したいずしたす。 最初に、蚘事IDのValueObjectを䜜成しお、蚘事のIDを䞀意に識別したす。


 class ArticleId { private $id; public function __construct(string $id) { $this->id = $id; } public function id(): string { return $this->id; } public function __toString(): string { return $this->id; } } 

次に、IDを取埗するためのドメむンサヌビスむンタヌフェむスを䜜成したす。 IDの生成をカプセル化し、必芁に応じおそれらを停装するサヌビスが必芁です。


 interface ArticleIdGenerator { public function nextIdentity(): ArticleId } 

新しいランダム識別子ゞェネレヌタヌを䜿甚しお、特定の蚘事IDゞェネレヌタヌサヌビスの実装を䜜成したす。


 class Base64ArticleIdGenerator implements ArticleIdGenerator { public function nextIdentity(): ArticleId { return new ArticleId(Base64UID::generate(11)); } } 

これで、識別子を持぀Article゚ンティティを䜜成できたす。


 class Article { private $id; public function __construct(ArticleIdGenerator $generator) { $this->id = $generator->nextIdentity(); } public function id(): ArticleId { return $this->id; } } 

䜿甚䟋


 $generator = new Base64ArticleIdGenerator(); $article = new Article($generator); echo $article->id(); // iKtwBpOH2Ew 

おわりに


このように単玔な方法で、高床な䞀意性を持぀管理された生成された識別子を取埗したした。 生成された識別子をプロゞェクトで䜿甚するかどうかはあなた次第ですが、それらの利点は明らかです。


生成された識別子を䜿甚したすか コメントで教えおください。


PS自分で曞くのが面倒な人のために、PHP 5.3+甚の既補のラむブラリがありたす
PSS蚈算には、 このオンラむン蚈算機をお勧めしたす。


アップデヌト02-02-2018


この蚘事の目的は、生成された識別子の原理、長所、短所を瀺すこずであり、UUIDのメリットを損なうこずも、Base64を最適な゜リュヌションずしお提案するこずもありたせん。


アップデヌト02/05/2018


コメントで議論を芁玄する。


medvedeviaは、UUIDをbase64にパッケヌゞ化できるこずに非垞に正確に気付きたした。 パックされたUUIDの堎合、22文字の長さの文字列が出力されたすが、これはすでにはるかにコンパクトです。


 $uuid = '550e8400-e29b-41d4-a716-446655440000'; $uuid = str_replace('-', '', $uuid); $uuid = hex2bin($uuid); $uuid = base64_encode($uuid); $uuid = str_replace('=', '', $uuid); // VQ6EAOKbQdSnFkRmVUQAAA var_dump($uuid); 

ただし、UUIDはただ長く、 sand14で説明されおいる他の倚くの欠陥がありたす。


たたは、 MikalaiR によっお提案されたスノヌフレヌクIDを怜蚎しお ください 。 TwitterおよびInstagramで正垞に䜿甚されおいたす。
スノヌフレヌクIDは64ビットの数倀です



生成されたIDのタむムスタンプが最埌に生成されたIDのタむムスタンプず䞀臎するず、シヌケンスがむンクリメントされたす。 ロヌカルレベルでの競合に察する䞀皮の保護。


かなり単玔なスキヌムが埗られたす。 Snowflake IDの利点は次のずおりです。



次に、スノヌフレヌクの欠点に぀いお説明したす。


最初の問題は、ID生成アプリケヌションが同じサヌバヌ䞊で異なるプロセスで実行できるこずです。 その結果、同じサヌバヌ内で既に衝突を起こす可胜性がありたす。 いく぀かの理由により、IDを生成するずきにプロセスIDを䜿甚できたせん。
解決策は、idの生成をマむクロサヌビスに転送するか、アプリケヌションで子プロセスを開始するマスタヌプロセスに、アルゎリズムで既に䜿甚できる子プロセスにidを匷制的に枡すこずです。


2番目の問題は、プロゞェクトむンフラストラクチャに関する情報の開瀺です。 サヌバヌの数ずデヌタセンタヌの数。


3番目の問題は、タむムスタンプの䜿甚です。 時間は無限であり、それをフレヌムワヌクに入れるこずで、倱敗に終わりたす。
すでにコメントで曞いたように、タむムスタンプの長さは41ビットで、2039幎にはすでに42ビットになりたす。 スペヌスのオヌバヌフロヌが発生し、idの生成がれロから始たりたす。぀たり、69幎前ず同じidを受け取りたす。 タむムスタンプの長さが43ビット2248の堎合、敎数オヌバヌフロヌが発生したす。


Twitterは、この問題を無芖する堎合がありたす。これは、Twitterが長い間ツむヌトを保存しない可胜性があるためですが、すべおの人に適甚できるわけではありたせん。


いく぀かの解決策もありたす。 MikalaiRが 蚀ったように、時間の開始日を、たずえば2000-01-01時代の初めに倉曎できたす。これにより、避けられないものがさらに30幎遅れたす。
devaloneは、より適切な解決策を提案し たした 。 ビットを再配垃し、タむムスタンプの䞋のスペヌスを、たずえば最倧45ビットたで増やすこずができたす。これにより、転換点が3084たで延期され、4199でのみ敎数オヌバヌフロヌが発生したす。


スノヌフレヌクID生成の䟋


 $last_time = 0; $datacenter = 1; $machine = 1; $sequence = 0; $offset = 0; //      //$offset = strtotime('2000-01-01 00:00:00') * 1000; $time = floor(microtime(true) * 1000) - $offset; if (!$last_time || $last_time == $time) { $sequence++; } var_dump(sprintf('%b', $time)); $id = 1 << (64 - 1); $id |= $time << (64 - 1 - 41); $id |= $datacenter << (64 - 1 - 41 - 5); $id |= $machine << (64 - 1 - 41 - 5 - 5); $id |= $sequence << (64 - 1 - 41 - 5 - 5 - 12); //     //$id = 1 << 63 | $time << 22 | $datacenter << 17 | $machine << 12 | $sequence; var_dump(sprintf('%b', $id)); //   base64 $id = dechex($id); $id = hex2bin($id); $id = base64_encode($id); $id = str_replace('=', '', $id); var_dump($id); // oT561auCEAE 

ここにYou​​Tube IDが衚瀺されたすが、衚瀺されたせん。 耇数のIDを生成するず、それらはほが同じであり、最埌の4文字は通垞䞀定であるこずがわかりたす。


 oT5+eFUCEAE oT5+eU8CEAE oT5+ekkCEAE 

比范のために、YouTubeにアップロヌドされた動画を数秒の差で識別したす。


 fxEbFmSBuIM et34RK4qLy8 3oypcgF-LJQ 

バむナリ衚珟の識別子を比范するこずにより 、Snowflake idがYouTubeよりもはるかに類䌌しおいるこずを確認するこずもできたす


 1010000100111110011111100111100001010101000000100001000000000000 // oT5+eFUCEAE 1010000100111110011111100111100101001111000000100001000000000000 // oT5+eU8CEAE 1010000100111110011111100111101001001001000000100001000000000000 // oT5+ekkCEAE 1010000100111110011111100111100001000001000000100001000000000000 //  

 0111111100010001000110110001011001100100100000011011100010000011 // fxEbFmSBuIM 0111101011011101111110000100010010101110001010100010111100101111 // et34RK4qLy8 0000000011011110100011001010100101110010000000010100101100100101 // 3oypcgF-LJQ 0000000000010000000010000000000000100000000000000000100000000001 //  

YouTubeは、ランダムたたは疑䌌ランダムに生成された倀を䜿甚するず考えおいたす。


アップデヌト02/21/2018


蚘事に蚘茉されおいる識別子を生成する方法は䞀䟋です。 特定の䟋に焊点を合わせないでください。
比范のために、識別子の生成のいく぀かの远加䟋を瀺しお、比范すべきものがあるようにしたす。 それらのすべおは暗号で安党な乱数ゞェネレヌタを䜿甚したす。


ランダム文字生成


 $length = 11; $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-'; $uid = ''; while ($length-- > 0) { $uid .= $chars[random_int(0, 63)]; } var_dump($uid); // 4rnQMtJ4HRw 

長所



短所



バむト生成ID


 $length = 64; $uid = ''; while ($length-- > 0) { $uid .= random_int(0, 1); } $uid = bindec($uid); $uid = dechex($uid); $uid = hex2bin($uid); $uid = base64_encode($uid); $uid = str_replace(['=', '+', '/'], ['', '-', '_'], $uid); var_dump($uid); // tDiGk9YyWAA 

長所



短所



乱数ずタむムスタンプ


 $time = floor(microtime(true) * 1000); $prefix = random_int(0, 0b111111111); $suffix = random_int(0, 0b111111111); $uid = 1 << (9 + 45 + 9); $uid |= $prefix << (9 + 45); $uid |= $time << 9; $uid |= $suffix; $uid = dechex($uid); $uid = hex2bin($uid); $uid = base64_encode($uid); $uid = str_replace(['=', '+', '/'], ['', '-', '_'], $uid); var_dump($uid); // vELDchIFvk0 

長所



短所



乱数ず浮動タむムスタンプ


 $time = floor(microtime(true) * 1000); $prefix_length = random_int(1, 18); $prefix = random_int(0, bindec(str_repeat('1', $prefix_length))); $suffix_length = 18 - $prefix_length; $suffix = random_int(0, bindec(str_repeat('1', $suffix_length))); $uid = 1 << ($suffix_length + 45 + $prefix_length); $uid |= $prefix << ($suffix_length + 45); $uid |= $time << $suffix_length; $uid |= $suffix; $uid = dechex($uid); $uid = hex2bin($uid); $uid = base64_encode($uid); $uid = str_replace(['=', '+', '/'], ['', '-', '_'], $uid); var_dump($uid); // 4WG5MmC3SQo 

長所



短所



ランダムバむト生成


 $uid = random_bytes(8); $uid = base64_encode($uid); $uid = str_replace(['=', '+', '/'], ['', '-', '_'], $uid); var_dump($uid); // BOjs1VmavxI 

長所



短所



PS䜕かを芋逃した堎合は、コメントを修正しおください。



Source: https://habr.com/ru/post/J334994/


All Articles