Sobes.tech
Middle+

Ի՞նչ պետք է անել, եթե երկու աշխատող միաժամանակ դիմում են նույն տվյալներին:

sobes.tech AI

Պատասխան AI-ից

Պետք է ապահովել տվյալների մուտքի հոսքային անվտանգությունը։ Հիմնական մոտեցումները՝

  1. Բլոկավորումներ (Locks): Օգտագործվում են կտրուկ հատվածների մուտքը սահմանափակելու համար։ Միայն մեկ հոսք կարող է ունենալ բլոկավորումը տվյալ պահին։

    # Մոդել Mutex-ով Ruby-ում
    require 'thread'
    
    $shared_data = 0
    $mutex = Mutex.new
    
    def increment_data
      $mutex.lock # Բլոկավորման ձեռքբերում
      begin
        # Կրիտիկական հատված
        temp = $shared_data
        sleep(0.01) # Աշխատանքի իմիտացիա
        $shared_data = temp + 1
      ensure
        $mutex.unlock # Բլոկավորման ազատում
      end
    end
    
    threads = []
    10.times do
      threads << Thread.new { increment_data }
    end
    
    threads.each(&:join)
    puts $shared_data # Անպայման կլինի 10
    
  2. Տվյալների բազայի տրանզակցիաներ: Եթե տվյալները պահվում են տվյալների բազայում, օգտագործեք տրանզակցիաներ՝ ատոմիկ գործողությունների համար։ Տրանզակցիայի մեկուսացման մակարդակը որոշում է, թե ինչպես են տեսանելի փոփոխությունները, որոնք կատարվել են այլ տրանզակցիաներով։

    # Rails-ում ActiveRecord-ի օրինակով
    ActiveRecord::Base.transaction do
      # Բոլոր գործողությունները բլոկում կատարվում են ատոմիկ
      user = User.find(user_id)
      user.balance -= amount
      order = Order.create!(user: user, amount: amount)
      user.save!
      # Եթե ինչ-որ բան սխալ լինի, ամբողջ տրանզակցիան հետ է տարվում
    end
    
  3. Ատոմիկ գործողություններ: Որոշ լեզուներ և գրադարաններ տրամադրում են ատոմիկ տվյալների տիպեր կամ գործողություններ, որոնք երաշխավորված են ամբողջությամբ կատարվել առանց միջամտության այլ հոսքերի կողմից։

    # Ruby-ն չունի ներքին ատոմիկ տիպեր ցանկացած տվյալների համար,
    # բայց որոշ գործողություններ (օրինակ, նշանակումը) կարող են լինել ատոմիկ
    # պարզ տիպերի համար։ Ավելի բարդ սցենարների համար անհրաժեշտ են բլոկավորումներ։
    
  4. Օպտիմիստական համաժամանակության վերահսկում: Փոխարենը բլոկավորումների, յուրաքանչյուր գրառում ունի վերանայման համար թիվ կամ ժամանակային նշան։ Ավելացման ժամանակ ստուգվում է, արդյոք գրառումը փոխվել է այն ժամանակից ի վեր, երբ այն կարդացել է։ Եթե փոխվել է, գործողությունը վերագործարկվում է։

    # ActiveRecord::Locking::Optimistic-ի օրինակ
    # Ավելացրեք `lock_version` (լուծում) ձեր աղյուսակին
    class Product < ApplicationRecord
      # ...
    end
    
    product = Product.find(id)
    # Այլ հոսք նույն արտադրանքը թարմացնում է...
    begin
      product.price += 10
      product.save! # Գեներացնում է ActiveRecord::StaleObjectError, եթե lock_version-ը փոխվել է
    rescue ActiveRecord::StaleObjectError
      # Կոնֆլիկտի մշակումը, օրինակ, վերից բեռնում և կրկին փորձ
      retry
    end
    
  5. Հաղորդագրության միջնորդներ / հերթեր: Փոխարենը ուղիղ մուտք գործելու տվյալների, աշխատողները ուղարկում են հաղորդագրություններ միջնորդին (օրինակ, RabbitMQ, Sidekiq-ով Redis-ով): Հաղորդագրությունների մշակումը կատարվում է հերթական կամ կառավարելի կարգով, ինչը նվազեցնում է կոնֆլիկտների հավանականությունը։

  6. Անփոփոխ օբյեկտների օգտագործում: Եթե տվյալները անփոփոխ են, միաժամանակյա մուտքը նրանց ապահով է, քանի որ ոչ մի աշխատող չի կարող փոխել դրանք։

Ընտրությունը կամ մոտեցումների համակցությունը կախված է տվյալների տեսակից, կատարողականի պահանջներից և ծրագրի ճարտարապետությունից։ Ruby on Rails-ով վեբ ծրագրերում հաճախ օգտագործվում են ActiveRecord տրանզակցիաներ և օպտիմիստական բլոկավորումներ տվյալների բազայում, իսկ ընդհանուր ռեսուրսների համար՝ Mutex։ Պատկերային առաջադրանքները (օրինակ, Sidekiq) սովորաբար մշակվում են հերթերից հաղորդագրություններով, որոնք ապահովում են որոշակի կարգապահություն։