Memcached
 sql >> база данни >  >> NoSQL >> Memcached

Python + Memcached:Ефективно кеширане в разпределени приложения

Когато пишете Python приложения, кеширането е важно. Използването на кеш памет за избягване на преизчисляване на данни или достъп до бавна база данни може да ви осигури голямо повишаване на производителността.

Python предлага вградени възможности за кеширане, от прост речник до по-пълна структура от данни като functools.lru_cache . Последният може да кешира всеки елемент, използвайки най-малко използван алгоритъм, за да ограничи размера на кеша.

Тези структури от данни обаче са по дефиниция локални към вашия Python процес. Когато няколко копия на вашето приложение работят на голяма платформа, използването на структура от данни в паметта забранява споделянето на кешираното съдържание. Това може да бъде проблем за широкомащабни и разпределени приложения.

Следователно, когато една система е разпределена в мрежа, тя също се нуждае от кеш, който се разпределя в мрежа. В днешно време има много мрежови сървъри, които предлагат възможност за кеширане - вече разгледахме как да използваме Redis за кеширане с Django.

Както ще видите в този урок, memcached е друга чудесна опция за разпределено кеширане. След кратко въведение в основното използване на memcached, ще научите за разширени модели като „кеш и настройка“ и използване на резервни кешове, за да избегнете проблеми с производителността на студен кеш.


Инсталиране на memcached

Memcached е наличен за много платформи:

  • Ако използвате Linux , можете да го инсталирате с помощта на apt-get install memcached или yum install memcached . Това ще инсталира memcached от предварително изграден пакет, но можете също да изградите memcached от източник, както е обяснено тук.
  • За macOS , използването на Homebrew е най-простият вариант. Просто стартирайте brew install memcached след като инсталирате мениджъра на пакети Homebrew.
  • На Windows , ще трябва сами да компилирате memcached или да намерите предварително компилирани двоични файлове.

Веднъж инсталиран, memcached може просто да се стартира чрез извикване на memcached команда:

$ memcached

Преди да можете да взаимодействате с memcached от Python-land, ще трябва да инсталирате memcached клиент библиотека. Ще видите как да направите това в следващия раздел, заедно с някои основни операции за достъп до кеша.



Съхранение и извличане на кеширани стойности с помощта на Python

Ако никога не сте използвали memcached , доста е лесно за разбиране. По същество предоставя огромен мрежов речник. Този речник има няколко свойства, които се различават от класическия речник на Python, главно:

  • Ключовете и стойностите трябва да са байтове
  • Ключовете и стойностите се изтриват автоматично след изтичане на срока на валидност

Следователно двете основни операции за взаимодействие с memcached са set и get . Както може би се досещате, те се използват съответно за присвояване на стойност на ключ или за получаване на стойност от ключ.

Предпочитаната от мен библиотека на Python за взаимодействие с memcached е pymemcache — Препоръчвам да го използвате. Можете просто да го инсталирате с помощта на pip:

$ pip install pymemcache

Следният код показва как можете да се свържете с memcached и го използвайте като мрежово разпределен кеш във вашите Python приложения:

>>> from pymemcache.client import base

# Don't forget to run `memcached' before running this next line:
>>> client = base.Client(('localhost', 11211))

# Once the client is instantiated, you can access the cache:
>>> client.set('some_key', 'some value')

# Retrieve previously set data again:
>>> client.get('some_key')
'some value'

memcached мрежовият протокол е наистина прост и неговото изпълнение е изключително бързо, което го прави полезно за съхраняване на данни, които иначе биха били бавни за извличане от каноничния източник на данни или за повторно изчисление:

Макар и достатъчно ясен, този пример позволява съхраняване на кортежи ключ/стойност в мрежата и достъп до тях чрез множество, разпределени, работещи копия на вашето приложение. Това е опростено, но мощно. И това е чудесна първа стъпка към оптимизирането на вашето приложение.



Автоматично изтичащи кеширани данни

Когато съхранявате данни в memcached , можете да зададете време на изтичане – максимален брой секунди за memcached за да запазите ключа и стойността наоколо. След това забавяне memcached автоматично премахва ключа от неговия кеш.

За какво трябва да зададете това време за кеширане? Няма магическо число за това забавяне и ще зависи изцяло от типа данни и приложение, с които работите. Може да са няколко секунди или може да са няколко часа.

Невалиден кеш , който определя кога да премахнете кеша, тъй като не е синхронизиран с текущите данни, също е нещо, с което вашето приложение ще трябва да се справи. Особено ако представяте данни, които са твърде стари или застояли трябва да се избягва.

Тук отново няма магическа рецепта; зависи от типа приложение, което създавате. Има обаче няколко извънредни случая, които трябва да бъдат разгледани – които все още не сме разгледали в горния пример.

Сървърът за кеширане не може да нараства безкрайно - паметта е ограничен ресурс. Следователно ключовете ще бъдат изтрити от кеширащия сървър веднага щом той се нуждае от повече място за съхранение на други неща.

Някои ключове може също да са с изтекъл срок на валидност, тъй като са достигнали времето си на изтичане (също понякога наричано „време на живот“ или TTL). В тези случаи данните се губят и каноничният източник на данни трябва да бъде запитан отново.

Това звучи по-сложно, отколкото е в действителност. Като цяло можете да работите със следния модел, когато работите с memcached в Python:

from pymemcache.client import base


def do_some_query():
    # Replace with actual querying code to a database,
    # a remote REST API, etc.
    return 42


# Don't forget to run `memcached' before running this code
client = base.Client(('localhost', 11211))
result = client.get('some_key')

if result is None:
    # The cache is empty, need to get the value
    # from the canonical source:
    result = do_some_query()

    # Cache the result for next time:
    client.set('some_key', result)

# Whether we needed to update the cache or not,
# at this point you can work with the data
# stored in the `result` variable:
print(result)

Забележка: Работата с липсващи ключове е задължителна поради нормалните операции за измиване. Също така е задължително да се обработва сценарий за студен кеш, т.е. когато memcached току-що започна. В този случай кешът ще бъде напълно празен и кешът трябва да бъде напълно попълнен, една заявка в даден момент.

Това означава, че трябва да разглеждате всички кеширани данни като ефимерни. И никога не трябва да очаквате кешът да съдържа стойност, която сте му записали преди това.



Загряване на студен кеш

Някои от сценариите на студен кеш не могат да бъдат предотвратени, например memcached катастрофа. Но някои могат, например да мигрират към нов memcached сървър.

Когато е възможно да се предвиди, че ще се случи сценарий за студен кеш, е по-добре да го избегнете. Кеш, който трябва да се попълни, означава, че внезапно каноничното съхранение на кешираните данни ще бъде силно засегнато от всички потребители на кеша, които нямат данни за кеш паметта (известен също като проблем с гръмотевичното стадо).

pymemcache предоставя клас с име FallbackClient което помага при прилагането на този сценарий, както е показано тук:

from pymemcache.client import base
from pymemcache import fallback


def do_some_query():
    # Replace with actual querying code to a database,
    # a remote REST API, etc.
    return 42


# Set `ignore_exc=True` so it is possible to shut down
# the old cache before removing its usage from 
# the program, if ever necessary.
old_cache = base.Client(('localhost', 11211), ignore_exc=True)
new_cache = base.Client(('localhost', 11212))

client = fallback.FallbackClient((new_cache, old_cache))

result = client.get('some_key')

if result is None:
    # The cache is empty, need to get the value 
    # from the canonical source:
    result = do_some_query()

    # Cache the result for next time:
    client.set('some_key', result)

print(result)

FallbackClient запитва стария кеш, предаден на неговия конструктор, спазвайки реда. В този случай новият кеш сървър винаги ще бъде запитан първи, а в случай на пропуск на кеша, старият ще бъде запитан - избягвайки възможно връщане към основния източник на данни.

Ако е зададен някой ключ, той ще бъде настроен само на новия кеш. След известно време старият кеш може да бъде изведен от експлоатация и FallbackClient може да бъде заменен насочен с new_cache клиент.



Проверка и настройка

Когато комуникирате с отдалечен кеш, обичайният проблем с едновременността се връща:може да има няколко клиента, които се опитват да осъществят достъп до един и същ ключ по едно и също време. memcached предоставя проверка и настройка операция, съкратена до CAS , което помага за решаването на този проблем.

Най-простият пример е приложение, което иска да преброи броя на потребителите, които има. Всеки път, когато посетител се свърже, броячът се увеличава с 1. Използване на memcached , простата реализация би била:

def on_visit(client):
    result = client.get('visitors')
    if result is None:
        result = 1
    else:
        result += 1
    client.set('visitors', result)

Какво се случва обаче, ако две копия на приложението се опитат да актуализират този брояч едновременно?

Първото извикване client.get('visitors') ще върне един и същ брой посетители и за двамата, да кажем, че е 42. Тогава и двамата ще добавят 1, изчисляват 43 и задават броя на посетителите на 43. Това число е грешно и резултатът трябва да бъде 44, т.е. 42 + 1 + 1.

За да разрешите този проблем с едновременността, CAS операцията на memcached е удобен. Следният фрагмент прилага правилно решение:

def on_visit(client):
    while True:
        result, cas = client.gets('visitors')
        if result is None:
            result = 1
        else:
            result += 1
        if client.cas('visitors', result, cas):
            break

gets методът връща стойността, точно както get метод, но също така връща CAS стойност .

Това, което е в тази стойност, не е от значение, но се използва за следващия метод cas обадете се. Този метод е еквивалентен на set операция, с изключение на това, че се проваля, ако стойността се е променила след gets операция. В случай на успех, цикълът се прекъсва. В противен случай операцията се рестартира отначало.

В сценария, при който два екземпляра на приложението се опитват да актуализират брояча едновременно, само един успява да премести брояча от 42 на 43. Вторият екземпляр получава False стойност, върната от client.cas обадете се и трябва да опитате отново цикъла. Този път ще извлече 43 като стойност, ще го увеличи до 44 и неговия cas обаждането ще успее, като по този начин решим нашия проблем.

Увеличаването на брояч е интересно като пример за обяснение как работи CAS, защото е опростено. Въпреки това, memcached също така предоставя incr и decr методи за увеличаване или намаляване на цяло число в една заявка, вместо да се правят множество gets /cas обаждания. В реални приложения gets и cas се използват за по-сложен тип данни или операции

Повечето отдалечени сървъри за кеширане и хранилища на данни предоставят такъв механизъм за предотвратяване на проблеми с паралелността. Важно е да сте наясно с тези случаи, за да използвате правилно функциите им.



Отвъд кеширането

Простите техники, илюстрирани в тази статия, ви показаха колко лесно е да използвате memcached за да ускорите производителността на вашето Python приложение.

Само с помощта на двете основни операции „set“ и „get“ често можете да ускорите извличането на данни или да избегнете повторното изчисляване на резултатите отново и отново. С memcached можете да споделяте кеша в голям брой разпределени възли.

Други, по-разширени модели, които видяхте в този урок, като Проверка и задаване (CAS) операцията ви позволява да актуализирате данни, съхранявани в кеша, едновременно в множество нишки или процеси на Python, като същевременно избягвате повреда на данните.

Ако се интересувате да научите повече за усъвършенстваните техники за писане на по-бързи и по-мащабируеми Python приложения, вижте Scaling Python. Той обхваща много напреднали теми като мрежово разпространение, системи за опашка, разпределено хеширане и профилиране на код.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Инсталиране на Memcached на Ubuntu 16.04/18.04 с Nginx и PHP-7.3

  2. Как да проверите връзката между mysql и memcached в php

  3. Инсталирайте Memcached на Ubuntu 16.04

  4. Как да използвате Memcached с Yii2 Framework

  5. Инсталиране на Memcached на Debian 9