[{"data":1,"prerenderedAt":1217},["ShallowReactive",2],{"content:\u002Fja\u002Fnotes\u002F65840\u002Freftextendedpaper":3,"series:content_ja":499},{"id":4,"title":5,"authorship":6,"body":7,"categories":471,"date":473,"description":474,"draft":475,"extension":476,"image":477,"meta":478,"navigation":480,"path":481,"permalink":482,"published":482,"readingTime":483,"recommend":482,"references":482,"seo":488,"seoDescription":489,"seoTitle":482,"sitemap":490,"stem":491,"tags":492,"type":497,"__hash__":498},"content_ja\u002Fposts\u002Fnotes\u002F65840\u002Freftextendedpaper.md","Raft論文を読む","human-only",{"type":8,"value":9,"toc":450},"minimark",[10,14,18,29,32,35,38,41,44,47,50,63,68,71,82,85,88,91,94,97,100,103,115,118,121,124,127,130,133,141,144,147,150,156,159,162,165,168,171,174,177,180,191,194,214,217,228,231,234,237,240,248,251,254,265,268,291,294,297,300,303,311,314,322,325,328,331,337,341,347,350,367,371,377,379,386,389,392,405,408,416,419,433,436],[11,12,13],"h3",{"id":13},"はじめに",[15,16,17],"p",{},"Raftは、ログレプリケーションを管理するための合意アルゴリズムです。合意アルゴリズムは、複数のマシンからなるクラスタで、一部が故障してもサービスを提供し続けるために使われます。信頼性の高い大規模ソフトウェアシステムを作るうえで、重要な役割を担っています。",[15,19,20,21,28],{},"Raftの主要な論文は『In Search of an Understandable Consensus Algorithm (Extended Version)』で、",[22,23,27],"a",{"href":24,"rel":25},"https:\u002F\u002Fraft.github.io\u002Fraft.pdf",[26],"nofollow","こちら","から読めます。18ページと、それほど長くありません。冒頭からひとしきり苦労話があり、随所でPaxosと比較しながら、Raft最大の長所である「より理解しやすいこと」を強調しています。",[15,30,31],{},"この記事は、論文を読みながら取ったメモです。",[11,33,34],{"id":34},"前提となる話",[15,36,37],{},"合意アルゴリズムは、主に複製状態機械（replicated state machines）のモデルで使うために考案されました。複製状態機械は通常、複製されたログで実装します。ログには一連の命令が記録され、クラスタ内の各マシンが同じ順序で実行することで、最終的に同じ状態へ到達します。この「最終的に」に注目です。これは強い整合性ではなく、結果整合性を示しています。",[15,39,40],{},"合意アルゴリズムは、クラスタ内で複製されたログの一貫性を保ちます。各マシンの合意モジュールが互いに通信し、一部のマシンが故障しても、最終的に同じ命令を同じ順序で実行できるようにします。こうして複数のマシンが、1台のマシンのようにまとまってサービスを提供します。",[15,42,43],{},"ここで扱う合意アルゴリズムは、非ビザンチン障害を前提とします。つまり、ノードが意図的に情報を偽造することは想定しません。",[11,45,46],{"id":46},"アルゴリズムの説明",[15,48,49],{},"Raftは、比較的独立した3つの部分に分けられます。",[51,52,53,57,60],"ul",{},[54,55,56],"li",{},"リーダー選出：現在のリーダーが故障したら、新しいリーダーを選ぶ。",[54,58,59],{},"ログレプリケーション：リーダーがクライアントからログを受け取り、クラスタ内に複製して、ほかのマシンのログを自身と一致させる。",[54,61,62],{},"安全性の保証：あるマシンが特定の命令を受け入れたら、別のマシンが同じログインデックスで異なる命令を受け入れないようにする。",[64,65,67],"h4",{"id":66},"raftの基本","Raftの基本",[15,69,70],{},"Raftクラスタ内のマシンは、常に次の3つの状態のいずれかにあります。",[51,72,73,76,79],{},[54,74,75],{},"リーダー：すべてのクライアントリクエストを処理する。",[54,77,78],{},"フォロワー：クライアントのリクエストは処理せず、リーダーや候補者からのリクエストを受けて応答する。",[54,80,81],{},"候補者：リーダーを選ぶための状態。",[15,83,84],{},"通常、クラスタにはリーダーが1台だけ存在し、残りはすべてフォロワーです。",[15,86,87],{},"Raftでは時間を任期に分けます。各任期の開始時には選挙が行われ、1台以上の候補者がリーダーを目指します。候補者が選挙に勝てばリーダーとなり、ほかのマシンはフォロワーになります。",[15,89,90],{},"任期は単調増加する整数です。各マシンは現在の任期を保存し、ほかのマシンとの通信にも付加します。相手の任期が自分より大きいと分かったら、自身の任期を更新します。候補者やリーダーが、より新しい任期の存在を知った場合は、ただちにフォロワーへ戻ります。",[15,92,93],{},"Raftの基本的な通信に必要なRPCは2種類だけです。RequestVote RPCは選挙中の候補者が送ります。中国語では「票集めのリクエスト」と訳すと、何だか妙な感じがしますね。AppendEntries RPCはリーダーが送り、ログの複製とハートビートに使います。",[64,95,96],{"id":96},"リーダー選出",[15,98,99],{},"マシンはフォロワーとして起動し、適切なRPCを受け取っている限り、その状態を保ちます。リーダーは命令を含まないAppendEntriesを定期的に送り、ハートビートとして自身の役割を維持します。フォロワーが一定時間リクエストを受け取らなければ、選挙を始めます。",[15,101,102],{},"選挙を始めるフォロワーは候補者になり、現在の任期を1増やし、自分に投票してから、ほかのマシンへ並列にRequestVoteを送ります。その後は、次のいずれかが起こるまで候補者の状態を保ちます。",[104,105,106,109,112],"ol",{},[54,107,108],{},"クラスタの過半数から票を得ると、選挙に勝ちます。各マシンが1つの任期で投票できる候補者は最大1台で、先着順です。そのため、1つの任期で当選できるのも最大1台です。当選した候補者はリーダーとなり、ほかのマシンへハートビートを送ります。",[54,110,111],{},"別のマシンからAppendEntriesを受け取ることもあります。その任期が自分の現在の任期以上なら、フォロワーになります。小さければリクエストを拒否し、候補者のままです。",[54,113,114],{},"複数のフォロワーが同時に候補者になると、誰も過半数を取れないことがあります。その場合、候補者はタイムアウト後に任期を1増やし、新たな選挙を始めます。",[15,116,117],{},"3番目の状況が延々と続かないように、選挙のタイムアウトは一定の範囲でランダムに設定し、同時にタイムアウトしにくくします。",[64,119,120],{"id":120},"ログレプリケーション",[15,122,123],{},"クライアントの各リクエストには、複製状態機械に実行させる命令が含まれます。リーダーは命令をログに追加し、クラスタ内のマシンへ並列にAppendEntriesを送って複製します。複製が完了すると、その命令を状態機械にコミットし、クライアントへ成功を返します。",[15,125,126],{},"AppendEntriesには、複製する命令に加え、リーダーが命令を受け取ったときの任期と、ログ内の位置を示す整数のインデックスも含まれます。",[15,128,129],{},"リーダーが命令を過半数のマシンへ複製できたら、その命令をコミットします。Raftは、コミット済みの命令が永続化され、最終的に利用可能なすべての状態機械で実行されることを保証します。このとき、それ以前のエントリもすべてコミットされます。過去のリーダーが作ったものも含みます。リーダーはコミット位置を記録し、すべてのAppendEntriesにそのインデックスを付けます。フォロワーも、エントリがコミット済みと知ったら、自身の状態機械へ適用します。",[15,131,132],{},"また、Raftは次の2つの性質を保証する必要があります。",[51,134,135,138],{},[54,136,137],{},"2つのログエントリの任期とログインデックスが同じなら、同じ命令を保持している。",[54,139,140],{},"2つのログエントリの任期とログインデックスが同じなら、それ以前のすべてのログエントリも一致している。",[15,142,143],{},"1つ目は比較的簡単なので、主に2つ目の保証を見ます。",[15,145,146],{},"リーダーはAppendEntriesを送る際、新しいエントリの直前にあるエントリの任期とインデックスも含めます。フォロワーが自身のログ内にそのエントリを見つけられなければ、リクエストを拒否します。これが整合性チェックです。リクエストが成功すれば、リーダーはフォロワーのログが自身と一致していると分かります。",[15,148,149],{},"整合性チェックに失敗した場合、リーダーはフォロワーのログを自身に合わせます。具体的には、両者で一致する最後のエントリを探し、フォロワー側のそれ以降を削除して、自身の後続エントリを送ります。リーダーはフォロワーごとにnextIndexを持ち、次に送るエントリのインデックスを記録します。リーダーになった直後は、自身の最後のログインデックスに1を足した値で、すべてのnextIndexを初期化します。あるフォロワーがチェックに失敗したら、そのnextIndexを1減らしてAppendEntriesを再送します。",[151,152,153],"blockquote",{},[15,154,155],{},"この説明は少し曖昧に感じました。おそらく各AppendEntriesでは、nextIndexから最後までのエントリを送るのでしょう。そうでなければ、チェックが通ってもフォロワーのログを一致点まで切り詰めただけで、その後のログが同期されないことになります。",[64,157,158],{"id":158},"安全性の保証",[15,160,161],{},"ここまでの仕組みだけでは、安全性を完全には保証できません。たとえば、あるマシンが到達不能になっている間にリーダーが複数のログをコミットし、その後そのマシンがリーダーに選ばれると、それらのログが上書きされる可能性があります。Raftはこれを防ぐため、選挙に制限を加えます。どの任期のリーダーも、それまでの任期でコミットされたすべてのエントリを保持するという制限です。",[15,163,164],{},"まず、RequestVoteには候補者のログ情報を含めます。受信側は、最後のエントリの任期やログインデックスを比較し、自身のログのほうが新しければ投票を拒否します。",[15,166,167],{},"現在の任期のエントリが過半数のマシンに受け入れられたら、リーダーはそれをコミットします。コミット中にリーダーが落ちた場合、次のリーダーが複製を続けます。ただし、過去の任期のエントリが過半数のマシンに保存されていても、新しいリーダーはそれだけでコミット済みとは判断できません。ここで論文のFigure 8のような問題が起こり得ます。",[15,169,170],{},"そこでRaftは、過去の任期のエントリを複製数だけでコミットしません。複製数でコミットを判断するのは、現在の任期のエントリだけです。現在の任期のエントリがコミットされると、それ以前のエントリも暗黙にコミットされます。",[64,172,173],{"id":173},"クラスタのメンバー変更",[15,175,176],{},"クラスタ全体を停止せずに構成を変えようとすると、独立した2つの過半数が生まれ、リーダーが2台選ばれる可能性があります。",[15,178,179],{},"Raftは安全なメンバー変更のために、2段階の方法を採ります。まずクラスタを共同合意（joint consensus）の状態へ移し、それがコミットされたら新しい構成に切り替えます。共同合意の間もサービスは継続できます。この状態では、次のように動作します。",[51,181,182,185,188],{},[54,183,184],{},"ログは新旧両方の構成に含まれるすべてのマシンへ複製する。",[54,186,187],{},"どちらの構成のマシンもリーダーになれる。",[54,189,190],{},"選挙とログの追加には、新旧それぞれの構成で過半数の同意が必要になる。",[15,192,193],{},"クラスタ構成は、特別なログエントリとして保存・転送します。流れは次のとおりです。",[104,195,196,199,202,205,208,211],{},[54,197,198],{},"リーダーが、構成をC_oldからC_newへ変更するリクエストを受け取る。",[54,200,201],{},"C_oldとC_newをまとめ、共同構成C_old,newとして1つのログエントリに記録する。",[54,203,204],{},"そのエントリを新旧両方の構成のマシンへ追加する。",[54,206,207],{},"マシンはそのエントリをログに追加した時点で、コミット前でも以後の操作に新しい構成を使う。",[54,209,210],{},"C_old,newが必要な過半数に受け入れられたら、リーダーがコミットする。この時点で、C_oldまたはC_newだけに基づいてリーダーを選ぶことはできなくなる。",[54,212,213],{},"リーダーがC_newのログエントリを作り、各マシンへ複製してコミットする。",[15,215,216],{},"メンバー変更には、さらに3つの問題があります。",[104,218,219,222,225],{},[54,220,221],{},"新しく加わるマシンはログを持っておらず、追いつくまで時間がかかるため、一時的に可用性を下げるおそれがあります。Raftでは、その前に新しい段階を設けます。新規マシンはAppendEntriesを受信しますが、投票権は持たず、その同意がなくても合意できます。ログが既存マシンに追いついたら、前述の変更処理へ進みます。",[54,223,224],{},"現在のリーダーが、新構成に含まれない場合があります。その場合、C_newをコミットした時点で退任します。つまり一時的に、自身を含まないクラスタを管理し、ログは複製するものの、自分を過半数の計算には入れない状態になります。",[54,226,227],{},"除外されたサーバーがクラスタを妨害することがあります。ハートビートを受け取れなくなったサーバーが選挙を始め、新しい任期のRequestVoteを送ると、現リーダーがフォロワーに戻ってしまいます。その選挙は成功せず、新しいリーダーも新クラスタから選ばれますが、除外されたマシンが繰り返しタイムアウトすることで可用性が下がります。",[15,229,230],{},"3番目を防ぐため、Raftはもう1つ制限を加えます。現リーダーからのハートビートを受けてからタイムアウトするまでの間にRequestVoteを受け取っても、任期を更新せず、投票もしません。現リーダーがクラスタとのハートビートを維持できている限り、より大きい任期の投票要求だけでは退任させられなくなります。",[64,232,233],{"id":233},"ログの圧縮",[15,235,236],{},"ログが増え続けると、すべてをメモリに保持できなくなります。そこでスナップショットを導入し、システムの状態を定期的に永続ストレージへ保存します。これにより、先頭からスナップショット時点までのログを安全にメモリから削除できます。",[15,238,239],{},"各マシンは独立して自身のスナップショットを管理します。対象はコミット済みのエントリだけです。状態機械の現在の状態に加え、次のメタデータも保存します。",[51,241,242,245],{},[54,243,244],{},"スナップショットに含まれる最後のエントリのログインデックス。",[54,246,247],{},"そのエントリの任期。",[15,249,250],{},"このメタデータは、主にAppendEntriesの整合性チェックで使います。直前のエントリを比較する必要があるためです。前述のメンバー変更にも対応するなら、スナップショット時点の最新構成も含めます。書き込みが終わったら、その時点までのログと古いスナップショットを削除できます。",[15,252,253],{},"新しく参加したノードや遅れているノードへ同期するとき、リーダーが自身のスナップショットを送る必要がある場合があります。このために使う新しいRPCがInstallSnapshotです。",[255,256,262],"pre",{"className":257,"code":259,"language":260,"meta":261},[258],"language-go","type InstallSnapshotRequest struct {\n    \u002F\u002F Term Leader 的任期\n    Term              int64\n    \u002F\u002F LeaderID Follower 可以将客户端请求重定向到 Leader\n    LeaderID          int64\n    \u002F\u002F LastIncludedIndex 快照包含的最后一个条目的索引\n    LastIncludedIndex int64\n    \u002F\u002F LastIncludedTerm 快照包含的最后一个条目的任期\n    LastIncludedTerm  int64\n    \u002F\u002F Offset 快照文件中的该快照块的偏移\n    Offset            int64\n    \u002F\u002F Data 快照块数据\n    Data              []byte\n    \u002F\u002F Done 是否是最后一个快照块\n    Done              bool\n}\n\ntype InstallSnapshotResponse struct {\n    \u002F\u002F Term Follower 当前任期\n    Term    int64\n}\n","go","",[263,264,259],"code",{"__ignoreMap":261},[15,266,267],{},"受信側の処理は次のとおりです。",[104,269,270,273,276,279,282,285,288],{},[54,271,272],{},"TermがCurrentTermより小さければ、ただちに戻る。",[54,274,275],{},"最初のチャンク、つまりOffset = 0なら、スナップショットファイルを作る。",[54,277,278],{},"指定されたオフセットにデータを書き込む。",[54,280,281],{},"Doneがfalseなら、戻って次のInstallSnapshotを待つ。",[54,283,284],{},"LastIncludedIndexとLastIncludedTermに一致するエントリがログにあれば、その後のエントリをすべて残して戻る。",[54,286,287],{},"ログをすべて破棄する。",[54,289,290],{},"スナップショットで状態機械をリセットし、保存されているクラスタ構成を使う。",[15,292,293],{},"通常、スナップショットには受信側がまだ持っていないログが含まれます。その場合、受信側はログをすべて破棄し、スナップショットを使います。一方、対象のログをすべて持っている場合は、その部分をスナップショットで置き換え、以後のエントリを残します。",[15,295,296],{},"最後に、スナップショットが性能へ与える影響です。ログが一定のバイト数に達したらスナップショットを作る方式にできますが、しきい値は大きすぎても小さすぎてもいけません。大きすぎると書き込みに時間がかかり、小さすぎると頻繁に作ることになります。また、ディスクI\u002FOは遅いため、書き込み自体が通常の処理を妨げるおそれがあります。Raftはコピーオンライトを勧めており、スナップショットをディスクへ書く間もログの追加やリクエスト処理を続けられるようにします。",[64,298,299],{"id":299},"クライアントとのやり取り",[15,301,302],{},"クライアントのリクエストは、すべてRaftクラスタのリーダーが処理します。クライアントは起動時に適当なマシンを選んでリクエストを送ります。そのマシンがリーダーでなければ、リクエストを拒否し、最後にハートビートを受け取ったリーダーのアドレスを返します。リーダーが故障するとリクエストがタイムアウトするので、クライアントは再び適当なマシンを選んで試します。",[15,304,305,306,310],{},"Raftが目指すのは、各操作が瞬時に完了し、1度だけ実行されるとみなせる線形化可能な意味論です。ただし、リーダーが命令を実行した後、応答を返す前に落ちることがあります。クライアントが別のリーダーへ再送すると、命令が2回実行される可能性があります。対策として、",[307,308,309],"strong",{},"各クライアント","が命令に単調増加する一意の識別子を付け、状態機械は最後に実行した命令の識別子を記録します。実行済みの命令を受け取ったら、再実行せず成功を返します。",[15,312,313],{},"読み取り専用リクエストはログへの書き込みが不要なので、毎回クラスタの合意を取らずに処理できます。しかし、合意を取らない間に、自身が気づかないうちに新しい任期のリーダーに交代している可能性があります。その場合、古いデータを返してしまいます。Raftは次の2つでこれを防ぎます。",[104,315,316,319],{},[54,317,318],{},"リーダーは、コミット済みエントリの最新情報を持つ必要があります。リーダー完全性によってエントリ自体の保持は保証されますが、任期の開始時点ではどれがコミット済みか分かりません。そのため、任期の最初に何もしないno-opエントリをコミットして、最新のコミット情報を確定します。",[54,320,321],{},"読み取り専用リクエストを処理する前に、自分が今もリーダーであると確認する必要があります。処理前にクラスタの過半数とハートビートをやり取りすれば確認できます。",[11,323,324],{"id":324},"アルゴリズムの実装",[15,326,327],{},"論文のFigure 2には、とても詳しい実装の指針があります。こういうところがRaftのいいところです！ なお、メンバー変更とログ圧縮は含まれません。",[64,329,330],{"id":330},"サーバーの状態",[255,332,335],{"className":333,"code":334,"language":260,"meta":261},[258],"type ServerState struct {\n    \u002F***** 所有 Server 都包含的持久状态 *****\u002F\n    \u002F\u002F CurrentTerm 机器遇到的最大的任期，启动时初始化为 0，单调递增\n    CurrentTerm int64;\n    \u002F\u002F VotedFor 当前任期内投票的 Candidate ID，未投票则为 nil\n    VotedFor    *int64;\n    \u002F\u002F Logs 日志条目，每个条目都包含了一条状态机指令和 Leader 接收该条目时的任期，index 从 1 开始\n    Logs        []*Log;\n\n    \u002F***** 所有 Server 都包含的可变状态 *****\u002F\n    \u002F\u002F CommitIndex 已知的最大的即将提交的日志索引，启动时初始化为 0，单调递增\n    CommitIndex int64;\n    \u002F\u002F LastApplied 最大的已提交的日志索引，启动时初始化为 0，单调递增\n    LastApplied int64;\n\n    \u002F******* Leader 包含的可变状态，选举后初始化 *******\u002F\n    \u002F\u002F NextIndex 每台机器下一个要发送的日志条目的索引，初始化为 Leader 最后一个日志索引 +1\n    NextIndex  []int64;\n    \u002F\u002F MatchIndex 每台机器已知复制的最高的日志条目，初始化为 0，单调递增\n    MatchIndex []int64;\n}\n",[263,336,334],{"__ignoreMap":261},[64,338,340],{"id":339},"appendentries","AppendEntries",[255,342,345],{"className":343,"code":344,"language":260,"meta":261},[258],"type AppendEntriesRequest struct {\n    \u002F\u002F Term Leader 的任期\n    Term         int64\n    \u002F\u002F LeaderID Follower 可以将客户端请求重定向到 Leader\n    LeaderID     int64\n    \u002F\u002F PrevLogIndex 新日志条目前一个日志条目的日志索引\n    PrevLogIndex int64\n    \u002F\u002F PrevLogTerm 前一个日志条目的任期\n    PrevLogTerm  int64\n    \u002F\u002F Entries 需要保存的日志条目，心跳包为空\n    Entries      []*Log\n    \u002F\u002F LeaderCommit Leader 的 CommitIndex\n    LeaderCommit int64\n}\n \ntype AppendEntriesResponse struct {\n    \u002F\u002F Term Follower 当前任期\n    Term    int64\n    \u002F\u002F Success Follower 包含 PrevLogIndex 和 PrevLogTerm 的日志条目为 true\n    Success bool\n}\n",[263,346,344],{"__ignoreMap":261},[15,348,349],{},"受信側の処理です。",[104,351,352,355,358,361,364],{},[54,353,354],{},"TermがCurrentTermより小さければfalseを返す。",[54,356,357],{},"PrevLogIndexとPrevLogTermに一致するエントリがなければfalseを返す。",[54,359,360],{},"既存エントリと新しいエントリのインデックスが同じで任期が異なる場合、そのエントリと後続のすべてを削除する。",[54,362,363],{},"まだログにないエントリを追加する。",[54,365,366],{},"LeaderCommitがCommitIndexより大きければ、LeaderCommitと新しいエントリの最後のインデックスのうち、小さいほうをCommitIndexに設定する。",[64,368,370],{"id":369},"requestvote","RequestVote",[255,372,375],{"className":373,"code":374,"language":260,"meta":261},[258],"type RequestVoteRequest struct {\n    \u002F\u002F Term Candidate 的任期\n    Term         int64\n    \u002F\u002F CandidateId 拉票的 Candidate 的 ID\n    CandidateId  int64\n    \u002F\u002F LastLogIndex Candidate 最后一条日志序列的索引\n    LastLogIndex int64\n    \u002F\u002F LastLogTerm Candidate 最后一条日志序列的任期\n    LastLogTerm  int64\n}\n\ntype RequestVoteResponse struct {\n    \u002F\u002F Term 当前任期\n    Term        int64\n    \u002F\u002F VoteGranted true 则拉票成功\n    VoteGranted bool\n}\n",[263,376,374],{"__ignoreMap":261},[15,378,349],{},[104,380,381,383],{},[54,382,354],{},[54,384,385],{},"VotedForがnilまたはCandidateIdで、候補者のログが受信側と同じかそれ以上に新しければtrueを返す。",[64,387,388],{"id":388},"サーバーの動作規則",[15,390,391],{},"すべてのマシンに共通する規則です。",[51,393,394,402],{},[54,395,396,397,401],{},"CommitIndexがLastAppliedより大きければ、LastAppliedを1増やし、log",[398,399,400],"span",{},"LastApplied","を状態機械へ適用する。",[54,403,404],{},"RPCのリクエストまたは応答のTermがCurrentTermより大きければ、CurrentTermを更新してフォロワーになる。",[15,406,407],{},"フォロワーの規則です。",[51,409,410,413],{},[54,411,412],{},"候補者とリーダーからのRPCに応答する。",[54,414,415],{},"現リーダーからAppendEntriesを受け取らず、候補者への投票も行わないまま選挙タイムアウトを迎えたら、候補者になる。投票要求を受け取ることではなく、実際に投票することが条件です。",[15,417,418],{},"候補者の規則です。",[51,420,421,424,427,430],{},[54,422,423],{},"候補者になったら選挙を始める。任期を1増やし、自分に投票し、選挙タイマーをリセットして、ほかの全マシンへRequestVoteを送る。",[54,425,426],{},"過半数の票を得たらリーダーになる。",[54,428,429],{},"新しいリーダーからAppendEntriesを受け取ったらフォロワーになる。",[54,431,432],{},"選挙がタイムアウトしたら次の選挙を始める。",[15,434,435],{},"リーダーの規則です。",[51,437,438,441,444,447],{},[54,439,440],{},"リーダーになったら、ほかの全マシンへ空のAppendEntriesを送る。処理がない間も繰り返し送り、選挙タイムアウトを防ぐ。",[54,442,443],{},"クライアントから命令を受け取ったらログに追加し、状態機械へ適用してから応答する。",[54,445,446],{},"最後のログインデックスがフォロワーのNextIndexより大きければ、NextIndex以降の全エントリを含むAppendEntriesを送る。成功したら、そのフォロワーのNextIndexとMatchIndexを更新する。ログの不整合で失敗したら、NextIndexを1減らして再試行する。",[54,448,449],{},"CommitIndexより大きいNがあり、過半数のMatchIndexがN以上で、第Nエントリが現在の任期のものなら、CommitIndexをNに設定する。",{"title":261,"searchDepth":451,"depth":451,"links":452},4,[453,455,456,465],{"id":13,"depth":454,"text":13},3,{"id":34,"depth":454,"text":34},{"id":46,"depth":454,"text":46,"children":457},[458,459,460,461,462,463,464],{"id":66,"depth":451,"text":67},{"id":96,"depth":451,"text":96},{"id":120,"depth":451,"text":120},{"id":158,"depth":451,"text":158},{"id":173,"depth":451,"text":173},{"id":233,"depth":451,"text":233},{"id":299,"depth":451,"text":299},{"id":324,"depth":454,"text":324,"children":466},[467,468,469,470],{"id":330,"depth":451,"text":330},{"id":339,"depth":451,"text":340},{"id":369,"depth":451,"text":370},{"id":388,"depth":451,"text":388},[472],"notes","2022-12-03 21:40:09","Raftは、ログレプリケーションの効率を高めるために設計された合意アルゴリズムです。複数のマシンからなるクラスタに適しており、一部のマシンが故障してもサービスを継続できます。複製状態機械モデルを使い、ログに命令の順序を記録することで、クラスタ内の各マシンが同じ状態に到達できるようにします。論文『In Search of an Understandable Consensus Algorithm』は、Raftの設計思想とPaxosとの比較を詳しく論じ、その理解しやすさを示すとともに、信頼できる大規模なソフトウェアシステムを構築するための土台を提供しています。この記事は、その中心的な概念と応用を理解するための読書メモです。",false,"md","https:\u002F\u002Fblog-img.774352199.xyz\u002F7mmvIZ.webp",{"slots":479},{},true,"\u002Fnotes\u002F65840\u002Freftextendedpaper",null,{"text":484,"minutes":485,"time":486,"words":487},"30 min read",29.245,1754700,5849,{"title":5,"description":474},"Raft拡張版論文の読書メモ。任期とリーダー選出、ログ複製、コミットの安全性を確認し、共同合意によるメンバー変更、スナップショット、クライアント処理まで整理します。",{"loc":481},"posts\u002Fnotes\u002F65840\u002Freftextendedpaper",[493,494,495,496],"Raft","分散合意","ログ複製","論文ノート","tech","PITkCiphvtrZkJ5KX9Y2fqBc0iArI6XGA-Y60v1RA0o",[500,518,535,553,570,589,607,625,643,659,676,692,708,724,741,759,774,791,805,822,840,857,872,889,905,924,941,958,976,990,1008,1025,1040,1052,1056,1073,1088,1103,1118,1132,1146,1160,1175,1189,1203],{"categories":501,"date":503,"description":504,"image":505,"path":506,"readingTime":507,"recommend":482,"tags":512,"title":517,"type":497},[502],"daily","2024-09-01 22:03:10","子どもの頃からの胃腸の不調が大学時代には不思議と消えたものの、就職後の夜更かしと飲酒で再発。慢性胃炎との付き合いは一筋縄ではいきませんでした。吐き気や胃のむかつきが日常になり、何度か検査を受けて生活を振り返るうちに、ようやく腰を据えて治療に向き合うようになりました。","https:\u002F\u002Fblog-img.774352199.xyz\u002F0Hr9l5.webp","\u002Fdaily\u002Fanti-chronic-gastritis",{"text":508,"minutes":509,"time":510,"words":511},"7 min read",6.485,389100,1297,[513,514,515,516],"慢性胃炎","受診記録","胃内視鏡検査","健康記録","慢性胃炎の治療記録",{"categories":519,"date":520,"description":521,"image":522,"path":523,"readingTime":524,"recommend":482,"tags":529,"title":534,"type":497},[502],"2022-04-11 00:13:13","『三体』では、劉慈欣が壮大な歴史を通して個人と集団の関係を描いています。西側の民主主義への疑念と、大多数の人々に運命を委ねることへの悲観が、三部作を貫いています。英雄たちが力を尽くしても、その努力は歴史の流れに押し流される。文化大革命から始まる物語に、少数の傑出した人物と平凡な大衆の対立を読み、人間性と社会について考えました。","https:\u002F\u002Fblog-img.774352199.xyz\u002FLTzbFP.webp","\u002Fdaily\u002Fpeople-in-three-body",{"text":525,"minutes":526,"time":527,"words":528},"19 min read",18.495,1109700,3699,[530,531,532,533],"三体","劉慈欣","SF文学","読書ノート","『三体』における「大多数の人々」",{"categories":536,"date":537,"description":538,"image":539,"path":540,"readingTime":541,"recommend":482,"tags":546,"title":552,"type":497},[502],"2024-01-04 02:06:51","2024年の学習目標は、日本語をN2レベルに引き上げること、SICPとTAPLを最後までやり切ること、POSIXを完全に実装したカーネルを作ること、そしてブログのテーマを更新すること。どれも簡単ではありませんが、今年取り組む方向は決まりました。","https:\u002F\u002Fblog-img.774352199.xyz\u002FV3rSQC.webp","\u002Fdaily\u002Fplan2024",{"text":542,"minutes":543,"time":544,"words":545},"1 min read",0.345,20700,69,[547,548,549,550,551],"年間計画","日本語学習","SICP","TAPL","オペレーティングシステム","2024年の学習計画",{"categories":554,"date":555,"description":556,"image":557,"path":558,"readingTime":559,"recommend":482,"tags":564,"title":569,"type":497},[502],"2024-09-28 16:26:00","ByteDanceで働いて3年。変化の速い環境で、時間まで加速したように感じながらも、どうにか心のバランスを保ってきました。杭州のオフィスのベランダから遠くの山を眺めていた入社当初を振り返り、仕事の壁や心境の変化、忙しさの中で自分のペースを探してきた日々を記します。","https:\u002F\u002Fblog-img.774352199.xyz\u002FhnCaht.webp","\u002Fdaily\u002Fwork-for-3-years",{"text":560,"minutes":561,"time":562,"words":563},"20 min read",19.73,1183800,3946,[565,566,567,568],"ByteDance","エンジニアのキャリア","仕事の振り返り","メンタルヘルス","ByteDanceで3年働きながら、ある程度の正気を保つことも不可能ではない",{"categories":571,"date":573,"description":574,"image":575,"path":576,"readingTime":577,"recommend":482,"tags":582,"title":588,"type":497},[572],"fiddling","2025-05-28 22:09:00","ブログをAstroに移行したところ、従来のGoogle Analytics導入方法では性能面が気になるようになりました。headタグにJavaScriptを直接追加してイベントを送ることはできますが、ページの性能に影響します。そこでpartytownでスクリプトをメインスレッドから切り離し、読み込みを妨げないようにしました。サンプルコードに手を加えることでGoogle Analyticsの導入に成功し、性能とアクセス解析を両立できました。","https:\u002F\u002Fblog-img.774352199.xyz\u002FQ0w4RN.webp","\u002Ffiddling\u002Fastro-google-tag-manager",{"text":578,"minutes":579,"time":580,"words":581},"4 min read",3.455,207300,691,[583,584,585,586,587],"Astro","Google Analytics","Google Tag Manager","Partytown","アクセス解析","AstroにGoogle Analyticsを導入する（Tag Manager編）",{"categories":590,"date":591,"description":592,"image":593,"path":594,"readingTime":595,"recommend":600,"tags":601,"title":606,"type":497},[572],"2023-04-08 13:16:36","新しいプログラミング言語の設計は、難しくも面白い作業です。複雑なコンパイラ理論や機能の実装詳細をいったん脇に置き、コードがコンピューターのどこで動くかに注目すると、言語の作り方が見えてきます。RISC-VI命令セットを出発点に、基盤となる構造、階層化されたシステム、仮想マシンのモデルをたどり、言語の本質を考えます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FuO420B.webp","\u002Ffiddling\u002Fchitchat-about-programming-language",{"text":596,"minutes":597,"time":598,"words":599},"28 min read",27.03,1621800,5406,2,[602,603,604,605],"プログラミング言語設計","型システム","コンパイラ設計","RISC-V","プログラミング言語についての雑談",{"categories":608,"date":609,"description":610,"image":611,"path":612,"readingTime":613,"recommend":451,"tags":618,"title":624,"type":497},[572],"2025-04-18 16:43:12","彼女が仕事で北京から上海に引っ越したので、回線の手配も手伝いました。ところが上海電信の500Mは杭州の1000Mより高く、なんとも納得がいきません。そこで上海での透過プロキシ、特定の通信の杭州経由での外部接続、両拠点のLAN相互接続を目指してネットワークを組むことにしました。杭州側はソフトウェアルーターと無線APのシンプルな構成で、普段から自宅経由で通信できる環境があり、次の挑戦に向けた準備はできています。","https:\u002F\u002Fblog-img.774352199.xyz\u002FO6cAGh.webp","\u002Ffiddling\u002Fcross-city-network-setup",{"text":614,"minutes":615,"time":616,"words":617},"11 min read",10.14,608400,2028,[619,620,621,622,623],"Tailscale","mihomo","拠点間ネットワーク","透過プロキシ","ホームネットワーク","上海と杭州の自宅ネットワークをつなぐ",{"categories":626,"date":627,"description":628,"image":629,"path":630,"readingTime":631,"recommend":482,"tags":636,"title":642,"type":497},[572],"2021-12-27 00:09:00","CSAPPの学習では実験が欠かせませんが、Linux環境の構築が壁になりがちです。とくに仮想マシンでは、インストール失敗、互換性、ネットワーク接続などの問題に悩まされます。Windows 10バージョン2004以降なら、WSL（Windows Subsystem for Linux）が有力な選択肢です。従来の仮想マシンの複雑さや性能面の負担を避けながら、Linux環境を手軽に利用できます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FvqOC7N.webp","\u002Ffiddling\u002Fcsapplab0",{"text":632,"minutes":633,"time":634,"words":635},"10 min read",9.585,575100,1917,[637,638,639,640,641],"CSAPP","WSL2","Linux","GDB","実験環境","CSAPP Labの環境構築",{"categories":644,"date":645,"description":646,"image":647,"path":648,"readingTime":649,"recommend":482,"tags":654,"title":658,"type":497},[572],"2024-07-13 17:49:00","Debianをサイドルーターに使うと、OpenWrtやLuCIに依存せず、より安定した柔軟な構成を作れます。Debianを直接設定することでシステムを細かく制御でき、GUIの制約や不安定さを避けられます。一般的なサイドルーター構成と比べて透過プロキシを安定して運用しやすく、性能や効率を重視する場合の選択肢になります。","https:\u002F\u002Fblog-img.774352199.xyz\u002FpPRU5x.webp","\u002Ffiddling\u002Fdebian-as-bypass-router",{"text":650,"minutes":651,"time":652,"words":653},"18 min read",17.525,1051500,3505,[655,656,620,657,622],"Debian","サイドルーター","AdGuard Home","Debianをサイドルーターにする",{"categories":660,"date":661,"description":662,"image":663,"path":664,"readingTime":665,"recommend":482,"tags":670,"title":675,"type":497},[572],"2024-08-16 23:53:00","FakeIPを使った透過プロキシ構成で、従来のサイドルーターの単一障害点、性能不足、複雑なポート転送を改善します。プロキシコアをsing-boxに変えることで、転送性能を高めながら設定も簡単にできます。対応プロトコルが豊富で、従来のClashより最適化も進んでいます。同じ構成はClashでも実現できますが、sing-boxは柔軟な選択肢になります。","https:\u002F\u002Fblog-img.774352199.xyz\u002FS2HHD5.webp","\u002Ffiddling\u002Ffake-ip-based-transparent-proxy",{"text":666,"minutes":667,"time":668,"words":669},"14 min read",13.1,786000,2620,[671,672,622,673,674],"FakeIP","sing-box","ポリシーベースルーティング","トラフィック振り分け","FakeIPを使った透過プロキシの振り分け",{"categories":677,"date":678,"description":679,"image":680,"path":681,"readingTime":682,"recommend":482,"tags":687,"title":691,"type":497},[572],"2024-08-15 23:50:00","サイドルーターを導入すると、メインルーターのポート転送が効かなくなることがあります。ゲートウェイをサイドルーターに変えることで通信経路が変わり、メインルーターを前提とした転送が正常に動かなくなるためです。ゲートウェイはアドレスを変換して内部ネットワークの通信を外部へ転送し、各端末は外部との通信にこれを必要とします。この仕組みを理解すると、ポート転送の問題を解決しやすくなります。","https:\u002F\u002Fblog-img.774352199.xyz\u002FmRqws9.webp","\u002Ffiddling\u002Ffix-port-forward-in-bypass-router",{"text":683,"minutes":684,"time":685,"words":686},"6 min read",5.155,309300,1031,[656,688,689,690],"ポート転送","NAT","ネットワークのトラブルシューティング","サイドルーター環境でポート転送が効かない問題を解決する",{"categories":693,"date":694,"description":695,"image":696,"path":697,"readingTime":698,"recommend":482,"tags":703,"title":707,"type":497},[572],"2023-02-02 23:24:55","春節の帰省列車で、Goをベアメタルで動かす記事を読み、低レベルのシステムインターフェースに興味が湧きました。実際に動く実装を見て、高級言語でOSを作る可能性に胸が躍ります。関連研究を調べると先行例も見つかり、積もった熱意は期待に満ちたプロジェクトへと変わりました。しかし、最後は思いどおりにはいきませんでした。","https:\u002F\u002Fblog-img.774352199.xyz\u002FxB1Ni5.webp","\u002Ffiddling\u002Fgo-os",{"text":699,"minutes":700,"time":701,"words":702},"12 min read",11.81,708600,2362,[704,605,551,705,706],"Go","ベアメタルプログラミング","ランタイム","失敗に終わったプロジェクト：楽しくなかった春節の7日間",{"categories":709,"date":710,"description":711,"image":712,"path":713,"readingTime":714,"recommend":482,"tags":719,"title":723,"type":497},[572],"2022-08-15 01:05:01","システムのリファクタリングで、階層ごとのエンティティ変換に苦労しました。ビュー層の商品VO、ドメイン層のentity、永続化層のPOは似ていても、型のわずかな違いで直接変換できず、ディープコピーが面倒になります。そこでリフレクションを使った汎用的な変換処理を実装し、大量のassemblerメソッドを減らして、保守性と柔軟性を高めることにしました。","https:\u002F\u002Fblog-img.774352199.xyz\u002FBlhm0I.webp","\u002Ffiddling\u002Fgolang-deepcopy-between-different-type",{"text":715,"minutes":716,"time":717,"words":718},"5 min read",4.14,248400,828,[704,720,721,722],"リフレクション","ディープコピー","構造体変換","Goで異なる型の構造体をディープコピーする",{"categories":725,"date":726,"description":727,"image":728,"path":729,"readingTime":730,"recommend":482,"tags":734,"title":740,"type":497},[572],"2025-03-31 23:51:00","Appleヘルスケアの心拍数を定期的にサーバーへ同期し、Grafanaで可視化して直感的に確認できるようにしました。Health Auto ExportのREST API機能でHTTPエンドポイントへデータを送り、InfluxDBに保存します。Grafanaのダッシュボードから、自分の心拍数の変化を追ったり分析したりできます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FF4qD2T.webp","\u002Ffiddling\u002Fheart-rate-to-grafana",{"text":578,"minutes":731,"time":732,"words":733},3.76,225600,752,[735,736,737,738,739],"Apple Watch","Health Auto Export","InfluxDB","Grafana","心拍数モニタリング","My Heart Beats for U：心拍数をGrafanaで可視化する",{"categories":742,"date":743,"description":744,"image":745,"path":746,"readingTime":747,"recommend":751,"tags":752,"title":758,"type":497},[572],"2025-06-10 20:18:00","macOSとiPadOS 26では、新しいデザイン言語Liquid Glassが導入され、アイコンやウインドウの印象が一新されました。とくにiPadのアプリをウインドウで扱えるようになったことは、生産性向上のための端末へ進む大きな一歩です。一方、透明なコントロールセンターやLaunchpadの統合には賛否があり、使い勝手には改善の余地もあります。課題はありつつも、今後につながる更新だと感じました。","https:\u002F\u002Fblog-img.774352199.xyz\u002FTPSaLE.webp","\u002Ffiddling\u002Fmacos-26-trial",{"text":508,"minutes":748,"time":749,"words":750},6.94,416400,1388,5,[753,754,755,756,757],"macOS 26","iPadOS 26","Liquid Glass","Apple Intelligence","OS使用感","macOS 26とiPadOS 26を試してみた",{"categories":760,"date":761,"description":762,"image":763,"path":764,"readingTime":765,"recommend":482,"tags":769,"title":773,"type":497},[572],"2026-06-11 10:00:00","今年もWWDCでmacOS 27の新しいApple Intelligenceが登場しました。macOS 26時代の回避方法はもう使えず、引き続きAppleとの知恵比べです。","https:\u002F\u002Fblog-img.774352199.xyz\u002FfOFucm.webp","\u002Ffiddling\u002Fmacos-27-apple-intelligence-chatgpt",{"text":632,"minutes":766,"time":767,"words":768},9.74,584400,1948,[770,756,771,772],"macOS 27","ChatGPT","中国本土向けMac","中国本土向けMacでApple Intelligenceを使う：地域変更からChatGPTの取り出しまで",{"categories":775,"date":776,"description":777,"image":778,"path":779,"readingTime":780,"recommend":482,"tags":784,"title":790,"type":497},[572],"2025-07-20 23:32:00","MoonTVはNext.jsとReactで作った動画集約プラットフォームで、連続ドラマなどを手軽に楽しむためのものです。LibreTVを改善しようとしたことが始まりで、数か月の開発を経て多くの関心と利用を集めています。Cursorのおかげで効率よく開発できた一方、複数環境への対応や複雑なデータ依存関係には苦労しました。ユーザーが増える中、フィードバックを受けて改善を続けています。","https:\u002F\u002Fblog-img.774352199.xyz\u002FnIeONi.webp","\u002Ffiddling\u002Fmoontv-vibe-coding",{"text":614,"minutes":781,"time":782,"words":783},10.98,658800,2196,[785,786,787,788,789],"MoonTV","LunaTV","Vibe Coding","Cursor","AI支援開発","MoonTV：Vibe Codingを試してみた",{"categories":792,"date":793,"description":794,"image":795,"path":796,"readingTime":797,"recommend":482,"tags":801,"title":804,"type":497},[572],"2024-10-07 16:51:00","BGPをもとに中国国内・国外のIPを振り分けることで、透過プロキシの効率と精度を高めます。国外の宛先をFakeIPで識別すれば、メインルーターでより適切に通信を振り分けられます。sing-boxのDNS設定も見直し、DNSクエリを柔軟かつ効率的に処理して、ネットワーク全体の使い勝手を改善します。","https:\u002F\u002Fblog-img.774352199.xyz\u002FMOmM1s.webp","\u002Ffiddling\u002Fmore-accurate-chnroute",{"text":683,"minutes":798,"time":799,"words":800},5.75,345000,1150,[802,803,673,674],"BGP","IPアドレスデータベース","BGPで中国国内・国外IPの振り分けをより正確にする",{"categories":806,"date":807,"description":808,"image":809,"path":810,"readingTime":811,"recommend":482,"tags":816,"title":821,"type":497},[572],"2025-12-14 14:31:00","友人の一言からシミュレーターに興味が湧き、Microsoft Flight Simulatorを購入。地図やモデルはリアルタイム配信、アカウントは再ログインが必要、チュートリアルは見つけにくく、キーボード操作も難しい。結局フライトスティックを買い、Pico VRまで設定してようやく一通り体験できました。","https:\u002F\u002Fblog-img.774352199.xyz\u002FlfhEuE.webp","\u002Ffiddling\u002Fmsfs2024-joystick-and-pico",{"text":812,"minutes":813,"time":814,"words":815},"9 min read",8.96,537600,1792,[817,818,819,820],"Microsoft Flight Simulator 2024","Thrustmaster TCA","PICO VR","フライトシミュレーション","Microsoft Flight Simulator 2024をあれこれ試す",{"categories":823,"date":824,"description":825,"image":826,"path":827,"readingTime":828,"recommend":482,"tags":833,"title":839,"type":497},[572],"2025-06-05 23:26:00","OnePlusからiPhoneへと何度も機種変更するうち、いじる楽しさからエコシステムへの依存へと関心が変わりました。最近、彼女の一言をきっかけに写真を改善しようとOPPO Find X8 Ultraを購入。Apple環境からの移行では、Androidアプリの質のばらつきと代替探しの難しさを改めて感じました。1か月をかけて、異なるプラットフォームの摩擦に折り合いをつけた記録です。","https:\u002F\u002Fblog-img.774352199.xyz\u002F19NIhZ.webp","\u002Ffiddling\u002Fone-month-using-android",{"text":829,"minutes":830,"time":831,"words":832},"15 min read",14.05,843000,2810,[834,835,836,837,838],"Android","OPPO","iOS","スマートフォン使用感","エコシステム移行","Androidに乗り換えて1か月",{"categories":841,"date":842,"description":843,"image":844,"path":845,"readingTime":846,"recommend":482,"tags":850,"title":856,"type":497},[572],"2026-05-11 22:43:00","GitHub Trendingで旅行計画ツールを見つけ、自分でも動かしたくなりました。どうせ新しいVPSを借りるなら、ついでにもう少し、いや、だいぶ色々入れてしまおうと。","https:\u002F\u002Fblog-img.774352199.xyz\u002FBBdDWW.webp","\u002Ffiddling\u002Fone-trek-twenty-stacks",{"text":614,"minutes":847,"time":848,"words":849},10.34,620400,2068,[851,852,853,854,855],"TREK","Docker Compose","Dockge","VPS","セルフホスティング","TREKひとつのつもりが、20個のスタックに",{"categories":858,"date":859,"description":860,"image":861,"path":862,"readingTime":863,"recommend":482,"tags":867,"title":871,"type":497},[572],"2025-01-16 23:09:00","OPNsenseは、美しい画面と充実した機能を備えるオープンソースのファイアウォール・ルーターです。いくつかの構成を試した末に、透過プロキシやトラフィック振り分けでの可能性に気づきました。BGPベースの振り分けと組み合わせることで安全性と安定性を高められ、IPリストの自動更新で管理もしやすくなります。","https:\u002F\u002Fblog-img.774352199.xyz\u002FxA8C1E.webp","\u002Ffiddling\u002Fopnsense-transparent-proxy",{"text":699,"minutes":864,"time":865,"words":866},11.38,682800,2276,[868,869,620,870,622,674],"OPNsense","FreeBSD","tun2socks","OPNsenseで透過プロキシとトラフィック振り分けを実現する",{"categories":873,"date":874,"description":875,"image":876,"path":877,"readingTime":878,"recommend":454,"tags":882,"title":888,"type":497},[572],"2025-03-15 20:35:00","構文解析では、ユーザー定義型名と通常の変数名を見分けることが課題になります。たとえば`a*b;`は算術式とも宣言とも解釈できます。とくに型指定子に関する文法規則によって変数名が型名と解釈され、正確さや読みやすさに影響します。初期化を伴わない変数宣言は多いため、この曖昧さはソースコードの随所に現れます。","https:\u002F\u002Fblog-img.774352199.xyz\u002F2VKHK9.webp","\u002Ffiddling\u002Fparser-type-variable-ambiguity",{"text":666,"minutes":879,"time":880,"words":881},13.58,814800,2716,[883,884,885,886,887],"構文解析","GLR","シンボルテーブル","スコープ","曖昧性解消","構文解析で型名と変数名の曖昧さを解消する",{"categories":890,"date":891,"description":892,"image":893,"path":894,"readingTime":895,"recommend":482,"tags":899,"title":904,"type":497},[572],"2023-05-24 17:51:09","RISC-Vツールチェーンをインストールするには、まずriscv-gnu-toolchainのソースを取得します。clone時に`--depth=1`を付けるとダウンロード量を減らせます。READMEのPrerequisitesを確認し、必要な依存関係をそろえてから進めます。Debianではコマンドで依存パッケージをまとめて導入できます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FrWNOKx.webp","\u002Ffiddling\u002Fspike-install",{"text":578,"minutes":896,"time":897,"words":898},3.89,233400,778,[605,900,901,902,903],"Spike","riscv-pk","クロスコンパイル","ツールチェーン","RISC-Vツールチェーンとエミュレーターのインストール",{"categories":906,"date":907,"description":908,"image":909,"path":910,"readingTime":911,"recommend":915,"tags":916,"title":923,"type":497},[572],"2026-09-09 23:59:00","これも一種のNTRですよね","https:\u002F\u002Fblog-img.774352199.xyz\u002FNDPUwc.webp","\u002Ffiddling\u002Fsteamdeck-switch-60fps",{"text":666,"minutes":912,"time":913,"words":914},13.905,834300,2781,7,[917,918,919,920,921,922],"Steam Deck","Nintendo Switch","EmuDeck","Eden","Lossless Scaling","フレーム生成","Steam Deckの第二の人生：Switchエミュレーター導入からフレーム補間で60FPSまで",{"categories":925,"date":926,"description":927,"image":928,"path":929,"readingTime":930,"recommend":482,"tags":935,"title":940,"type":497},[572],"2024-06-23 15:31:32","GFWは単に出口のゲートウェイを監視するのではなく、通信経路の脇から国際通信を傍受します。出入国するIPパケットをクラスタへ複製し、詳しく分析・フィルタリングする仕組みです。どこで何をしているかを理解することは、検閲回避の検討に欠かせません。ネットワーク構成を調べることで、遮断の経路や技術、対処方法が見えてきます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FsOpJuL.webp","\u002Ffiddling\u002Ftech-about-gfw",{"text":931,"minutes":932,"time":933,"words":934},"25 min read",24.975,1498500,4995,[936,937,938,939],"GFW","DNSポイズニング","TCP","インターネット検閲","GFWの仕組みを探る",{"categories":942,"date":943,"description":944,"image":945,"path":946,"readingTime":947,"recommend":482,"tags":951,"title":957,"type":497},[572],"2022-04-16 00:01:28","Javaでは`this`を使うことで、コンパイラの定数最適化が効かなくなる場合があります。このコード例の`ab1`と`ab2`は同じstatic final変数`s`を参照しているように見えますが、比較結果は異なります。静的変数を直接参照して文字列を連結する`ab1`に対し、`this`経由の`ab2`では同じ定数伝播の最適化が行われません。わずかな構文の違いが、コンパイル結果を変える例です。","https:\u002F\u002Fblog-img.774352199.xyz\u002FgKtkYe.webp","\u002Ffiddling\u002Fthis-in-javac-string-concat",{"text":578,"minutes":948,"time":949,"words":950},3.88,232800,776,[952,953,954,955,956],"Java","javac","文字列連結","定数伝播","バイトコード","Javaのthisキーワードでコンパイル時の定数伝播が効かなくなる問題",{"categories":959,"date":960,"description":961,"image":962,"path":963,"readingTime":964,"recommend":482,"tags":969,"title":975,"type":497},[572],"2025-01-29 21:58:00","ひとこと投稿機能があれば、静的ブログの記事公開に伴う手間や心理的な負担を減らし、短い思いつきをいつでも共有できます。Cloudflare Workersでバックエンドを実装し、KVで投稿を保存・管理します。フロントエンドはVitePressにVueコンポーネントを埋め込み、投稿を手軽に表示してブログに動きと交流の場を加えます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FhZX6hr.webp","\u002Ffiddling\u002Fvitepress-memos-component",{"text":965,"minutes":966,"time":967,"words":968},"24 min read",23.345,1400700,4669,[970,971,972,973,974],"VitePress","Vue","Cloudflare Workers","Cloudflare KV","マイクロブログ","VitePressにひとこと投稿機能を実装する",{"categories":977,"date":978,"description":979,"image":980,"path":981,"readingTime":982,"recommend":482,"tags":986,"title":989,"type":497},[572],"2025-03-15 16:24:00","ある平凡な午後、Telegramの通知で魅力的なVPSプランを見つけました。中国電信CN2直結、帯域2.5Gという好条件です。IPv6付きで動画配信サービスの地域制限解除にも便利ですが、すべての通信をWARP経由にする必要はありません。以前のスクリプトは手軽な一方、速度と振り分けに不満があり、もっと柔軟な方法を探すことにしました。","https:\u002F\u002Fblog-img.774352199.xyz\u002FMcjrrF.webp","\u002Ffiddling\u002Fvps-warp-ipv6",{"text":715,"minutes":983,"time":984,"words":985},4.09,245400,818,[987,988,854,673,674],"Cloudflare WARP","IPv6","VPSの特定の通信をWARP経由のIPv6で外に出す",{"categories":991,"date":992,"description":993,"image":994,"path":995,"readingTime":996,"recommend":1000,"tags":1001,"title":1007,"type":497},[572],"2026-08-17 23:59:21","いじればいじるほど、もっといじりたくなります。年を取ってもまだまだ元気、まだまだ元気です。","https:\u002F\u002Fblog-img.774352199.xyz\u002FqfxB0h.webp","\u002Ffiddling\u002Fxiaomi17-root-and-hide-root",{"text":812,"minutes":997,"time":998,"words":999},8.83,529800,1766,6,[1002,1003,1004,1005,1006],"Xiaomi 17","Bootloader","Android Root","ファームウェア書き換え","Rootの隠蔽","Xiaomi 17を普段使いに：ロック解除、ROM書き込み、root化とroot隠し",{"categories":1009,"date":1010,"description":1011,"image":1012,"path":1013,"readingTime":1014,"recommend":482,"tags":1019,"title":1024,"type":497},[472],"2022-01-20 22:29:00","Lab 1では、masterとworkerという2つの主要な部分からなるMapReduceシステムを実装します。GoのRPCと並行プログラミングを十分に使いこなし、MapReduceの処理の流れも深く理解する必要があります。実装は2つの版を作り、mutexでロックする方式から、よりすっきりしたchannelによる明示的なロックを使わない方式へと改めました。後者のほうが設計もシンプルで分かりやすくなっています。実習を理解する鍵は、関連資料、特にフローチャートとその説明をしっかり読むことです。","https:\u002F\u002Fblog-img.774352199.xyz\u002FibVwPJ.webp","\u002Fnotes\u002F65840\u002Fmapreducelab",{"text":1015,"minutes":1016,"time":1017,"words":1018},"13 min read",12.39,743400,2478,[1020,1021,704,1022,1023],"MIT 6.5840","MapReduce","RPC","並行プログラミング","6.5840 Lab 1：MapReduce",{"categories":1026,"date":1027,"description":1028,"image":1029,"path":1030,"readingTime":1031,"recommend":482,"tags":1035,"title":1039,"type":497},[472],"2022-01-16 17:32:00","MapReduceは、大規模なデータセットの処理を簡単にするための効率的な並列計算モデルです。利用者はMapとReduceという2つの主要な関数を定義することで、複雑なタスクを簡単な操作に分解できます。データの分配やタスクの割り当てはフレームワークが自動で管理するため、開発者は低レベルの細部に気を取られず、アルゴリズムそのものに集中できます。分散システムで広く使われていることからも、その柔軟性と実用性が分かります。","https:\u002F\u002Fblog-img.774352199.xyz\u002FApIDdC.webp","\u002Fnotes\u002F65840\u002Fmapreducepaper",{"text":812,"minutes":1032,"time":1033,"words":1034},8.085,485100,1617,[1021,1036,496,1037,1038],"分散システム","並列計算","耐障害性","MapReduce論文を読む",{"categories":1041,"date":1042,"description":1043,"image":1044,"path":1045,"readingTime":1046,"recommend":482,"tags":1050,"title":1051,"type":497},[472],"2022-12-16 02:06:10","Lab 2Aでは、Raftのリーダー選出とハートビートを実装し、さまざまな厳しい条件でも任期の交代や選挙が正常に行われるようにします。実習全体は4段階からなり、この後に実装する分散KVストアの土台になります。明示的なロックを使わない設計によって、Raft構造体を簡潔にします。実習の手引きには必要な背景知識が載っていますが、前の実習と比べると参考資料に頼れる部分はほとんどなく、自力で実装することが重視されます。","https:\u002F\u002Fblog-img.774352199.xyz\u002Fc11Uk4.webp","\u002Fnotes\u002F65840\u002Fraftlab2a",{"text":650,"minutes":1047,"time":1048,"words":1049},17.515,1050900,3503,[1020,493,704,96,494],"6.5840 Lab 2A：リーダー選出",{"categories":1053,"date":473,"description":474,"image":477,"path":481,"readingTime":1054,"recommend":482,"tags":1055,"title":5,"type":497},[472],{"text":484,"minutes":485,"time":486,"words":487},[493,494,495,496],{"categories":1057,"date":1059,"description":1060,"image":1061,"path":1062,"readingTime":1063,"recommend":1067,"tags":1068,"title":1072,"type":497},[1058],"projects","2021-11-27 14:43:00","MYDBは、データベースの基本原理を学び、実装してみるための個人プロジェクトです。空き時間を使い、半月あまりかけて作りました。大学のデータベースシステムの授業で基礎には触れたものの、インターン中は授業を口実にサボってばかりでした。面接で正直に答えても大きな問題にはなりませんでしたが、それをきっかけに自分の知識を見直し、実際に手を動かして学ぼうと考えるようになりました。そうして生まれたのがこのプロジェクトです。","https:\u002F\u002Fblog-img.774352199.xyz\u002Fxfci2J.webp","\u002Fprojects\u002Fmydb\u002Fmydb0",{"text":812,"minutes":1064,"time":1065,"words":1066},8.03,481800,1606,1,[1069,952,1070,1071],"MYDB","データベース実装","データベースアーキテクチャ","MYDB 0. プロジェクト構成と、先に伝えておきたいこと",{"categories":1074,"date":1075,"description":1076,"image":1077,"path":1078,"readingTime":1079,"recommend":482,"tags":1084,"title":1087,"type":497},[1058],"2021-11-28 16:10:00","MYDBではXIDファイルでトランザクションを管理します。各トランザクションには1から増える一意のXIDがあり、XID 0は常にコミット済みのスーパートランザクションです。TransactionManagerがこのファイルを管理し、実行中・コミット済み・中止済みという3つの状態を記録します。この仕組みにより状態を正確に照会・管理でき、システムの安定性と信頼性を支えます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FH4zZAK.webp","\u002Fprojects\u002Fmydb\u002Fmydb1",{"text":1080,"minutes":1081,"time":1082,"words":1083},"8 min read",7.42,445200,1484,[1069,952,1085,1086],"トランザクション管理","XID","MYDB 1. まずはシンプルなTMから",{"categories":1089,"date":1090,"description":1091,"image":1092,"path":1093,"readingTime":1094,"recommend":482,"tags":1098,"title":1102,"type":497},[1058],"2021-12-25 18:26:00","MYDBはMySQLに似たC\u002FS構成を採用し、複数のクライアントがソケットでサーバーへ接続してSQLを実行し、結果を受け取れます。通信には専用のバイナリー形式を使いますが、実装を簡単にするならプレーンテキストも選択肢です。サーバーとクライアントの基本的な転送構造によって、データのやり取りと処理を行います。","https:\u002F\u002Fblog-img.774352199.xyz\u002FPAHrUZ.webp","\u002Fprojects\u002Fmydb\u002Fmydb10",{"text":683,"minutes":1095,"time":1096,"words":1097},5.76,345600,1152,[1069,952,1099,1100,1101],"Socket","クライアントサーバー構成","通信プロトコル","MYDB 10. サーバー・クライアントの実装と通信プロトコル",{"categories":1104,"date":1105,"description":1106,"image":1107,"path":1108,"readingTime":1109,"recommend":482,"tags":1113,"title":1117,"type":497},[1058],"2021-11-30 23:18:00","データマネージャー（DM）は上位モジュールとファイルシステムをつなぎ、ページとキャッシュを管理しながら、データの安全性と復旧を支えます。キャッシュには従来のLRUではなく参照カウント方式を採用し、汎用性と効率を高めて、この先のデータ操作の土台を作ります。","https:\u002F\u002Fblog-img.774352199.xyz\u002FWdIGoG.webp","\u002Fprojects\u002Fmydb\u002Fmydb2",{"text":614,"minutes":1110,"time":1111,"words":1112},10.395,623700,2079,[1069,952,1114,1115,1116],"参照カウント","キャッシュ設計","共有メモリ","MYDB 2. 参照カウント方式のキャッシュ基盤と共有バイト配列",{"categories":1119,"date":1120,"description":1121,"image":1122,"path":1123,"readingTime":1124,"recommend":482,"tags":1128,"title":1131,"type":497},[1058],"2021-12-05 15:28:00","DMはファイルシステムをページとして抽象化し、ページ単位で読み書きとキャッシュを行います。データページのデフォルトサイズは8Kで、大量の書き込みではサイズの調整によって性能を高められます。実装済みの汎用キャッシュ基盤を使い、ここではページ構造を具体的に定義して、効率よくページを管理します。","https:\u002F\u002Fblog-img.774352199.xyz\u002FjlFC4E.webp","\u002Fprojects\u002Fmydb\u002Fmydb3",{"text":1080,"minutes":1125,"time":1126,"words":1127},7.14,428400,1428,[1069,952,1129,1130],"データページ","キャッシュ管理","MYDB 3. データページのキャッシュと管理",{"categories":1133,"date":1134,"description":1135,"image":1136,"path":1137,"readingTime":1138,"recommend":482,"tags":1142,"title":1145,"type":497},[1058],"2021-12-08 22:55:00","MYDBでは、クラッシュ後にデータを復旧できるよう、ログファイルが重要な役割を担います。DMは下位のデータを操作するたびにログを生成・記録し、連続したログ列を作ります。チェックサムと各操作の記録を含む所定のバイナリー形式で保存することで、再起動時にデータの状態を正確に再構築し、整合性と完全性を保ちます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FTRcbsj.webp","\u002Fprojects\u002Fmydb\u002Fmydb4",{"text":1015,"minutes":1139,"time":1140,"words":1141},12.685,761100,2537,[1069,952,1143,1144],"データベースログ","クラッシュリカバリ","MYDB 4. ログファイルと復旧戦略",{"categories":1147,"date":1148,"description":1149,"image":1150,"path":1151,"readingTime":1152,"recommend":482,"tags":1156,"title":1159,"type":497},[1058],"2021-12-11 15:16:00","ページインデックスはDM層の重要な構成要素です。各ページの空き容量をキャッシュすることで挿入処理を効率化し、上位モジュールが長い探索をせずに適切なページを素早く見つけられるようにします。実装ではデータ項目（DataItem）の抽象化とも密接に連携し、データベースの効率的な動作を支えます。","https:\u002F\u002Fblog-img.774352199.xyz\u002F22PSG1.webp","\u002Fprojects\u002Fmydb\u002Fmydb5",{"text":632,"minutes":1153,"time":1154,"words":1155},9.86,591600,1972,[1069,952,1157,1158],"ページインデックス","データ管理","MYDB 5. ページインデックスとDMの実装",{"categories":1161,"date":1162,"description":1163,"image":1164,"path":1165,"readingTime":1166,"recommend":482,"tags":1170,"title":1174,"type":497},[1058],"2021-12-18 14:58:00","VMは二相ロックでスケジュールの直列化可能性を保証し、多版型同時実行制御（MVCC）を導入して読み取りと書き込みの相互ブロックを解消します。また、データベース操作の競合を定義し、特に更新と読み取りの関係を整理することで、トランザクションの分離レベルを理解する土台を作ります。","https:\u002F\u002Fblog-img.774352199.xyz\u002F8YzotA.webp","\u002Fprojects\u002Fmydb\u002Fmydb6",{"text":829,"minutes":1167,"time":1168,"words":1169},14.665,879900,2933,[1069,952,1171,1172,1173],"MVCC","トランザクション分離","二相ロック","MYDB 6. レコードのバージョンとトランザクション分離",{"categories":1176,"date":1177,"description":1178,"image":1179,"path":1180,"readingTime":1181,"recommend":482,"tags":1185,"title":1188,"type":497},[1058],"2021-12-23 21:20:00","VMでは、MVCCに伴うバージョンの飛び越しとデッドロックに対処する必要があります。MYDBはトランザクションに印を付けるだけで取り消しやロールバックを行い、abortedなトランザクションのデータがほかへ影響しないようにします。この設計により並行処理の効率と信頼性を高め、従来の2PLで起こりがちなデッドロックを避けて、システム全体の安定性と性能を向上させます。","https:\u002F\u002Fblog-img.774352199.xyz\u002FBF3yDW.webp","\u002Fprojects\u002Fmydb\u002Fmydb7",{"text":699,"minutes":1182,"time":1183,"words":1184},11.32,679200,2264,[1069,952,1186,1187],"デッドロック検出","バージョン管理","MYDB 7. デッドロック検出とVMの実装",{"categories":1190,"date":1191,"description":1192,"image":1193,"path":1194,"readingTime":1195,"recommend":482,"tags":1199,"title":1202,"type":497},[1058],"2021-12-24 21:01:00","MYDBはB+木によるクラスタ化インデックスを実装します。IMはバージョンマネージャー（VM）を経由せず、データマネージャー（DM）と直接やり取りし、インデックスデータをデータベースファイルへ直接書き込みます。この章では二分木インデックスの構造を詳しく説明し、葉フラグ、キー数、兄弟ノードの識別子など、インデックス検索の基盤となる要素を扱います。","https:\u002F\u002Fblog-img.774352199.xyz\u002Ff92X4o.webp","\u002Fprojects\u002Fmydb\u002Fmydb8",{"text":508,"minutes":1196,"time":1197,"words":1198},6.53,391800,1306,[1069,952,1200,1201],"B+木","データベースインデックス","MYDB 8. インデックス管理",{"categories":1204,"date":1205,"description":1206,"image":1207,"path":1208,"readingTime":1209,"recommend":482,"tags":1213,"title":1216,"type":497},[1058],"2021-12-25 15:44:00","テーブルマネージャー（TBM）は、フィールドとテーブルの構造を管理します。ParserはSQL風の文を構造化して解析し、文に含まれる情報を対応するクラスへまとめることで、その後の操作を簡単にします。この章ではMYDBのSQL構文も紹介し、管理処理全体を理解する土台を作ります。","https:\u002F\u002Fblog-img.774352199.xyz\u002FzOMyv5.webp","\u002Fprojects\u002Fmydb\u002Fmydb9",{"text":1080,"minutes":1210,"time":1211,"words":1212},7.99,479400,1598,[1069,952,1214,1215],"SQL解析","テーブル管理","MYDB 9. フィールドとテーブルの管理",1789914059376]