Sessions: FilesystemStoreの競合状態

䜜成日 2013幎06月11日  Â·  23コメント  Â·  ゜ヌス: gorilla/sessions

FilesystemStoreには、修正する予定の競合状態がありたすが、先に進んで実行する前に、入力をお願いしたす。 基本的に問題は、同じナヌザヌ同じセッションからの同時リク゚ストがある堎合、次の可胜性があるこずです。

  1. リク゚スト1はセッションを開いお、セミロング操䜜を実行したす
  2. リク゚スト2はセッションを開きたす
  3. リク゚スト2「ログアりト」などを実行するためにセッションデヌタを削陀したす
  4. リク゚スト2の保存
  5. リク゚スト1が保存され、セッションがログアりトされなかったかのようになりたす

この欠陥のテストケヌスをcless / sessions @ f84abeda17de0b4fcd72d277412f3d3192f206f2に远加したした。

これを修正する最も簡単な方法は、ファむルシステムレベルでロックを導入するこずです。 ただし、golangにはファむルロックを行うためのクロスプラットフォヌムの方法がありたせん。 syscall flockを公​​開したすが、OSがサポヌトしおいる堎合にのみ機胜したす。 矀れの振る舞いは、UNIXによっおも異なる可胜性があるず思いたすが、そうであるかどうかはわかりたせん。 flockのもう1぀の問題は、NFSでは機胜しない可胜性があるこずです。

たったく異なる解決策は、 FilesystemStoreオブゞェクト自䜓にロックのマップを保持するこずです。 これには別の欠点がありたす。耇数のプロセスが同じファむルシステムセッションにアクセスするこずはできず、単䞀のアプリケヌション内で同じファむルシステムセッションに察しお耇数のストアを䜜成するこずはできたせん。 ただし、これらの䞡方を問題なく実行するこずはすでに䞍可胜です。

結局のずころ、最善の解決策は、ストアオブゞェクトにロックのマップを保持するこずだず思いたす。これは、そのシナリオのすべおの欠点を適切に文曞化でき、異なるシステム間で同じ動䜜であるず返信できるためです。

FilesystemStoreに基づく他のストレヌゞバック゚ンドがこの欠陥をコピヌする可胜性がありたす私のboj / redistore2のプロゞェクトのRedistoreコヌドを確認したずきにこの問題に気づきたした

bug stale

党おのコメント23件

ロックする代わりに、トランザクションベヌスのシステムはどうですか SessionオブゞェクトはlastModifiedフィヌルドを運ぶこずができたす。 セッションをセッションストアに保存し盎そうずするず、最埌に読み取られおから倉曎されたこずを瀺す゚ラヌが返されたす。 その埌、プログラマヌはセッションを再床取埗しお再詊行するこずを遞択できたす。

それはうたくいく可胜性があり、クリヌンアップする必芁のあるロックがなく、デッドロックの可胜性がないずいう利点がありたす。 リク゚ストの実行内容によっおは、開発者が意味のある再詊行を垞に実行できるかどうかはわかりたせん。 ロックは間違いなくより安党なオプションだず思いたすが、APIが倱敗の可胜性を明確に文曞化し、開発者がそれらの゚ラヌを熱心に凊理すれば、トランザクションは確かに機胜する可胜性がありたす。

ずはいえ、 FilesystemStoreがトランザクションを䜿甚する堎合でも、APIは、ロックを䜿甚するストレヌゞバック゚ンド甚に準備する必芁があるず思いたすが、それは、 session.Save()耇数回呌び出すこずを犁止するか、新しいsession.Release()導入するこずを意味したす。

RediStoreに圱響するため、この問題に続いお。 情報をありがずう@cless

長期的には正しいこずをする以倖に、珟時点では特に奜みはありたせん:)もちろん、既存のAPIも維持したいず思いたす。 たた、あちこちにロックを远加するず、耇雑さずオヌバヌヘッドが倧幅に増加したすが、これも避けるずよいでしょう。

この問題を解決する他のセッションフレヌムワヌクの䟋はありたすか 圌らが䜕をしおいるのか知りたいです。

デフォルトのphpセッションハンドラヌがファむルシステムベヌスのロックを䜿甚しおいるこずを知っおいたすphp 5.4 tarballでは、これがファむルext/session/mod_files.cあるこずを確認したした。 ext/standard/flock_compat.cによっお提䟛されるflockを䜿甚したす。

phpが評刀を考えれば良い䟋かどうかはわかりたせんが、珟時点で私が知っおいるのはphpだけだず思いたす。 他のフレヌムワヌクを芋぀けお、それらがどのように問題を解決するかを確認するために、呚りを芋回しおみたす。

Flask、Pyramid、たたはDjangoがこれらをどのように凊理するかを知りたいず思いたす。 時間があれば芋おいきたす。 誰かがそのコヌドベヌスに粟通しおいれば、Railsも興味深いでしょう。

PyramidずFlaskはどちらもデヌタの保存にCookieを䜿甚しおいるようですが、どちらも競合状態を凊理しおいないず思われたす。 私はドキュメントを簡単に読んだだけなので、間違っおいる可胜性がありたす。

Djangoはサヌバヌ偎のセッションデヌタをサポヌトしおいるので、そのコヌドを少し芋おいきたす。

デフォルトのDjangoセッションバック゚ンドはデヌタベヌスであり、これは私がよく知らないDjangoデヌタベヌス抜象化レむダヌを䜿甚しおいるため、解釈するのが困難です。 しかし、私はこのコメントをファむルシステムバック゚ンドで芋぀けたした

        # Write the session file without interfering with other threads
        # or processes.  By writing to an atomically generated temporary
        # file and then using the atomic os.rename() to make the complete
        # file visible, we avoid having to lock the session file, while
        # still maintaining its integrity.
        #
        # Note: Locking the session file was explored, but rejected in part
        # because in order to be atomic and cross-platform, it required a
        # long-lived lock file for each session, doubling the number of
        # files in the session storage directory at any given time.  This
        # rename solution is cleaner and avoids any additional overhead
        # when reading the session data, which is the more common case
        # unless SESSION_SAVE_EVERY_REQUEST = True.
        #
        # See ticket #8616.

これは、セッションファむルの内容が砎損しないようにするこずを瀺唆しおいるようですが、競合状態が発生しないこずを瀺唆しおいるわけではありたせん。 誰かがDjangoの経隓を持っおいるなら、cless / sessions @ f84abedのようなテストケヌスを芋るずいいでしょう。
Stackoverflowは、Djangoがセッションで競合状態になっおいる可胜性があるこずも瀺しおいるようです http //stackoverflow.com/searchq = django + session + race + condition

了解したした。FileSystemStoreには、セッションストアの砎損を防ぐために、すでに粗粒床のミュヌテックスがありたす。 䞀郚のリク゚ストの䞀貫性を高めるためだけに、リク゚ストごずに倚くのオヌバヌヘッドが远加されるため、ラむブラリに远加の保護をどの皋床远加する䟡倀があるかはわかりたせん。 確かにここでのシナリオは実行可胜ですが、䞀般的な意味で扱うにはおそらく耇雑すぎるず思いたす。 珟圚の状況がたったく問題ない堎合が倚いこずがわかりたすが、䞀郚のアプリケヌションでは問題になる可胜性がありたす。 ずにかく、ほずんどの堎合、特定のセッションに察しお実行䞭のリク゚ストは1぀だけだず思いたす。

実際、これはどのWebリ゜ヌスにも存圚する問題です。情報に基づいお、GETの埌にPUTを実行した堎合も同じこずが起こりたすが、その間に状況が倉わった可胜性がありたす。

ずにかく、それは珟時点での私の考えですが、さらに議論できおうれしいです。

長期的には、これはアプリケヌションドメむンの問題のようです。

clessが投皿したシナリオを考えるず、リク゚スト1が十分に長く実行されおリク゚スト2が䞊行しお発生する可胜性がある堎合たずえば、Angular.jsで蚘述されたシングルペヌゞアプリケヌション、たたはいく぀かのAPIにヒットする非同期Node.jsアプリ、長時間実行されるリク゚ストはセッションから切り離し、その時点で独立したワヌカヌプロセスず芋なす必芁がありたす。

もちろん、これは問題に盎接察凊するものではありたせんが、kisielkが述べたように、あらゆる皮類のロックを実行するず、限界的なケヌスのように芋えるものに倚くのオヌバヌヘッドが远加されたす。

これは、セッションの競合状態の圱響の実際の䟋です。 バグはデバッグが難しく、䞀芋ランダムに衚瀺され、開発者ずナヌザヌの䞡方にずっお迷惑です。 ajaxを倚甚する十分に倧きなアプリケヌションを考えるず、これらの競合状態は遅かれ早かれ珟れるでしょう。
http://www.hiretheworld.com/blog/tech-blog/codeigniter-session-race-conditions
http://www.chipmunkninja.com/Troubles-with-Asynchronous-Ajax-Requests-g@

同様の問題を扱っおいるEllisLab / CodeIgniter1746のスレッド党䜓を読みたしたが、CodeIgniterが時々セッションIDを匷制的に再生成するずいう事実によっお問題が耇雑になり、そこでの議論のほずんどはこの事実を䞭心に展開しおいたす。

互換性のない方法でセッションを倉曎したり、既存のアプリケヌションを壊す可胜性のあるAPIに埮劙な違いを導入したりするこずに抵抗があるこずを理解しおいたす。 ただし、オプションのロックが必芁だず思いたす。 次のようにストアAPIに2぀の関数を远加するのはどうですか。

type Store interface {
    Get(r *http.Request, name string) (*Session, error)
    New(r *http.Request, name string) (*Session, error)
    Save(r *http.Request, w http.ResponseWriter, s *Session) error
    Lock(r *http.Request, name string) error
    Release(r *http.Request, name string) error
}

これらの関数の䜿甚は完党にオプションでありセッションに曞き蟌むすべおの芁求をロックするこずを個人的に掚奚したすが、既存のアプリケヌションに圱響を䞎えるこずはありたせん。

提案されたロックむンタヌフェむスには問題がありたす。ロックがMySQLなどのデヌタベヌスに保持されおいお、ロックを取埗した埌にデヌタベヌス接続が切断された堎合、ロックを解攟するこずはできず、セッションは事実䞊デッドロックされたす。 ロックは䜕らかの方法で期限切れになるはずですが、それが開発者にどのように公開されるべきか完党にはわかりたせん。

申し蚳ありたせんが、投皿したずきにBojの返信を芋逃したした。
長時間実行される芁求は、競合状態をトリガヌするための芁件ではないこずに泚意するこずが重芁です。 私のテストケヌスでの500ミリ秒のスリヌプは、競合状態がトリガヌされるこずを確認するためだけにありたす。 珟実の䞖界では、これらの競合状態は「短い」芁求でも発生したすが、頻床は䜎くなりたす。そのため、デバッグが困難になりたす。

たた、高負荷では、短いリク゚ストでも実行に時間がかかる堎合があるこずに泚意する必芁がありたす。

@cless良い点。

私はあなたの提案されたむンタヌフェヌスの倉曎が奜きです。

ロックの有効期限はRediStoreに比范的簡単に実装できたす。Redisには、キヌにTTLを蚭定できるEXPIREコマンドがありたす。

この皮のきめ现かいロックは、倚くの皮類のセッションストアにずっお䟝然ずしおかなり非効率的ではないでしょうか。 そしお、有効期限も問題です。

問題の䞀郚は、セッションが長く存圚しおいおも保存が成功する可胜性があるこずです。そうでない堎合、問題の解決に倧いに圹立぀のではないでしょうか。

@kisielk 、非効率な店舗の䟋を挙げおいただけたすか ほずんどのKey-Valueデヌタベヌスには、ロックを䜜成できる䜕らかの圢匏のアトミック操䜜がありたす。 SQLデヌタベヌスは通垞、行ベヌスのロックにアクセスできたすただし、ここでの詳现に぀いおはよく知らないず蚀わざるを埗たせん。
redisのようなKey-Valueストアのロック方法では、デヌタベヌスぞの耇数のラりンドトリップが必芁ですが、おそらくそれがあなたの意図したこずですか
goはファむルロックにアクセスするためのクロスプラットフォヌムの方法を提䟛しないため、ファむルシステムストアに問題がありたす。 cgoを䜿甚するず、メむンプラットフォヌムをサポヌトするプラットフォヌムを䜜成できるず思いたすが、それはおそらく回避する゜リュヌションです。

珟圚のセッションを削陀し、セッション固定を防ぐために新しいセッションに眮き換えるこずに぀いお話しおいるのでない限り、セッションが存圚しなくなったずきに保存するこずは実際の問題ではないず思いたすが、正盎なずころ、それはたったく別の問題です。

@boj 、問題は、プログラマヌが保存を詊みる前に、ロックがただ期限切れになっおいないこずを確認するための䜕らかの方法が必芁なこずです。 ロックの有効期限はどのくらいにする必芁がありたすか

これはそれを実行するための1぀の可胜な方法ですが、私はそれがずおも奜きかどうかはわかりたせん。 あなたは時蚈が突然前進したり埌退したりしないこずに䟝存しおおり、それは安党な仮定ではありたせん

func Lock(expiration time.Duration) time.Time {
    // Block here until the lock becomes your. Set the lock to expire after
    // dur+50ms. This extra 50 ms ensures that you never assume you own an
    // expired lock
    return time.Now().Add(expiration)
}

func main() {
    end := Lock(1000 * time.Millisecond)

    // Do your thing here ...
    // time.Sleep(1100 * time.Millisecond)

    if time.Now().After(end) {
        fmt.Println("Lock expired, throw an error")
    } else {
        fmt.Println("Good to go, save the session")
    }
}

@clessあなたのコメント党䜓は、 @ kisielkの心配事のように思われるこずを

提案したようにゎリラ/セッションのむンタヌフェヌス郚分を実装するのは非垞に簡単かもしれたせんが、同じように簡単にロック/リリヌスを実装しない限り、バック゚ンドを簡単に亀換できる堎合ずできない堎合があるシナリオを䜜成したすそしお効率的な方法。 あなたが提案するものに関しおは、どうやら倚すぎるようです。䜕よりもたず、「バック゚ンドはハックのプログラミングに頌らずにこれを実装できたすか」、続いお「FileSystemStoreからFooBarStoreにスワップしようずしたしたが、そうではありたせん。 Lock / Releaseを実装しおいるようで、プログラムが期埅どおりに動䜜したせん。」

セッションごずのロックの埮劙な違いに぀いおの良い蚘事がここにありたす

http://thwartedefforts.org/2006/11/11/race-conditions-with-ajax-and-php-sessions/

ここですでに結論を出しおいるように、䜕か問題が発生した堎合のロックのタむムアりトは、この皮のスキヌムを実装する際の䞻芁な問題の1぀です。 これにはさらに怜蚎が必芁であり、バック゚ンドに倧きく䟝存したす

Lock / Releaseを実装する限り、個別のむンタヌフェむスを䜿甚するこずで、セッションごずのロックの実装をオプションにするこずができたす。 その埌、バック゚ンドをそのむンタヌフェむスに察しおアサヌトできたす。バック゚ンドが実装されおいない堎合は、メモリ内ロックを䜿甚しおデフォルトの実装を提䟛できたす。

もちろん、もう1぀の問題は、ラむブラリのナヌザヌがロックずリリヌスを䜿甚するようにコヌドを曎新する必芁があるこずですが、それがなければ、珟圚ず同じ動䜜になるず思いたす。

「メモリ内ロックを䜿甚しおデフォルトの実装を提䟛できたす」

これは、リク゚ストが負荷分散されおいるマルチサヌバヌ環境では意味がありたせん。

セッションを䜿甚する既存のコヌドの動䜜を倉曎せずに正しく実装できるため、ロック甚にたったく異なるむンタヌフェむスを提䟛するずいうアむデアが気に入っおいたす。

@bojが指摘したように、デヌタベヌスストアに意味のある方法でメモリロックを提䟛するこずはできたせん。 ロック機胜を提䟛する負担は、おそらくストア開発者にあるはずです。 ロックむンタヌフェむスがない堎合でも、セッションがロックむンタヌフェむスを䜿甚しようずするず゚ラヌが返される可胜性がありたす。 これは実際には問題にはならないはずです。デフォルトのストアがロックを提䟛する堎合、他の開発者がそれに远随し、ナヌザヌは、たずえあったずしおも、最小限の䞍䟿を感じるでしょう。

䞀郚のストアではメモリロックがただ意味をなす可胜性があり、 FilesystemStoreがそれらの候補ずしお適しおいるず思いたす。 珟実的には、負荷分散された状況でファむルシステムストアを䜿甚するこずはありたせん理論的にはネットワヌクファむルシステムで可胜ですが。 ファむルシステムロックは望たしいように思われたすが、クロスプラットフォヌムを倖出先で実装するのは難しいようです。さらに、NFSでの動䜜も保蚌されおいたせん。

@boj 同意したしたが、 @ clessが指摘しおいるように、それはあなたが持っおいる店の皮類に基づいおいたす。 FilesystemStoreは、セッションストアの同時倉曎を防ぐために、すでにRWMutexに䟝存しおいたす。 ほずんどのバック゚ンドは実際には少なくずも最終的にはロックむンタヌフェむスを実装するず思いたすが、デフォルトを蚭定するず、開発者はそれたでの間、単䞀サヌバヌ環境に適したリリヌスを行うこずができたす。 FilesystemStoreは、Goラむブラリのクロスプラットフォヌムロック状況が改善されるたではその1぀です。

私は@clessに完党に同意し、セッションロックの重芁性を匷調したいず思いたす。成熟したプラットフォヌムPHPなどはセッションストアに実装したす。 ファむルでは、「flock」システムコヌルを䜿甚し、memcacheでは、「add」操䜜の戻り倀ず、「。lock」サフィックスず有効期限が蚭定された远加のキヌを䜿甚したす。 たた、 @ kisielkが新しいむンタヌフェむスを䜿甚するずいうアプロヌチにも同意したす関数「Lock」ず「Release」を䜿甚するのは理にかなっおいたす。これを䜿甚できたすかGoは、高いパフォヌマンスず信頌性を実珟するための蚀語です。私はたずえば、いく぀かの実装FileSystem、Redis、Memcacheに貢献する甚意がありたす。いく぀かの新しい構成オプションが必芁であるこずに泚意しおください。

  • spinLockWaitロックを取埗する詊行の間にスリヌプするミリ秒デフォルト150
  • lockMaxWaitロックを埅機する秒数デフォルト30
  • lockMaxAge自動的に解攟される前にロックを保持できる秒数デフォルトlockMaxWait

この問題は、最近の曎新が確認されおいないため、自動的に叀いものずしおマヌクされおいたす。 数日で自動的に閉鎖されたす。

このペヌゞは圹に立ちたしたか
0 / 5 - 0 評䟡