PoolCounter
PoolCounter je služba pro správu zámků napsaná v jazyce C. PoolCounter poskytuje funkce podobné mutexům s omezenou délkou čekací fronty. Pokud se příliš mnoho serverů pokouší provést stejnou věc současně, fronta čekání je "plná" a klientská aplikace může místo toho provést záložní akci, například vrátit zastaralý záznam mezipaměti nebo zobrazit chybovou zprávu.
PoolCounter byl vytvořen pro MediaWiki, aby se zabránilo výpadkům webu v důsledku masivního plýtvání CPU po zneplatnění mezipaměti populárního článku ("Problém Michaela Jacksona"). Signalizační sémantika PoolCounteru umožňuje MediaWiki omezit počet webových serverů, které po úpravě souběžně analyzují stejnou novou revizi článku. PoolCounter se od té doby používá i k jiným účelům, například k omezení rychlosti požadavků na změnu velikosti miniatur.
Instalace
Server
apt install poolcounter.
Podívejte se na packages.debian.org a packages.ubuntu.com.
Alternativně můžete server zkompilovat ze zdrojového kódu v repozitáři mediawiki/services/poolcounter, nebo můžete místo toho použít standardní Redis server.
Klient
MediaWiki používá PoolCounter prostřednictvím klienta napsaného v PHP, konfigurovaného pomocí $wgPoolCounterConf, který v současné době podporuje dva druhy backendů:
PoolCounter_Client– zajištěno serverem poolcounter (používaným Wikipedií).PoolCounterRedis– podpořené serverem Redis.
Zdrojový kód PHP klienta se nachází v adresáři /includes/PoolCounter v jádru MediaWiki.
Pro server poolcounter existuje také experimentální klient Pythonu, který používá Thumbor.
Konfigurace
Chcete-li povolit klienta PoolCounter, povolte ho pomocí parametru $wgPoolCounterConf a poté zadejte adresu serveru pomocí parametru $wgPoolCountClientConf.
Klient MediaWiki může dynamicky specifikovat velikost poolu a časové limity čekání, které bude server PoolCounter používat. Samotný server PoolCounter nevyžaduje konfiguraci.
Architektura
Server je jednovláknový program v jazyce C založený na libeventu. Nepoužívá autoconf, má pouze makefile, který je vhodný pro běžné linuxové prostředí. Momentálně nemá kód pro démonizaci, takže je poháněn systemd.
V MediaWiki musí být klient podtřídou třídy PoolCounter a třída obsahující logiku specifickou pro aplikaci musí být podtřídou třídy PoolCounterWork.
Podrobnosti viz Příručka:$wgPoolCounterConf#Použití.
Protokol
Síťový protokol je řádkový, s parametry oddělenými mezerami (mezery v parametrech jsou kódovány procentuálně). Klient otevře připojení, odešle příkaz pro získání zámku, provede práci, odešle příkaz pro uvolnění zámku a poté připojení ukončí.
Příkazy
Jsou definovány následující příkazy:
- ACQ4ANY <key> <active worker limit> <total worker limit> <timeout>
- Získejte zámek pro klienta, který potřebuje vykonat nějakou práci a je schopen číst položku mezipaměti zapsanou jiným procesem. Pokud je překročen limit aktivních pracovníků fondu, server pozastaví připojení a zpozdí svou odpověď na tento příkaz. Když klient, který obdržel odpověď LOCKED, dokončí svou práci a odešle příkaz RELEASE, všechny procesy čekající s příkazem ACQ4ANY budou okamžitě probuzeny odpovědí DONE a mohou si přečíst dokončenou práci z nového záznamu v mezipaměti.
- ACQ4ME <key> <active worker limit> <total worker limit> <timeout>
- Získejte zámek pro případy, kdy sdílení výsledků práce prostřednictvím mezipaměti není možné nebo není relevantní, například když požadavek na vykreslení článku zahrnuje nestandardní hodnotu stub threshold. Když je uvolněn zámek tohoto typu, probudí se pouze jeden čekající proces, aby se zachovala stejná populace pracovníků.
- RELEASE
- Uvolněte zámek, který klient naposledy získal.
- STATS [FULL|UPTIME]
- Tisk statistik.
Odpovědi
Možné odpovědi pro ACQ4ANY/ACQ4ME:
- LOCKED
- úspěšně získal zámek. Od klienta se očekává, že práci provede a poté odešle RELEASE.
- DONE
- odesláno k probuzení čekajícího klienta
- QUEUE_FULL
- je více pracovníků než <celkový limit pracovníků>
- TIMEOUT
- počet pracovníků je vyšší než <limit aktivních pracovníků>. Po <timeout> sekundách se neuvolnil žádný slot.
- LOCK_HELD
- snaha získat zámek, když je jeden již držen
Pro RELEASE:
- NOT_LOCKED
- klient momentálně nedrží žádné zámky
- RELEASED
- zámek úspěšně uvolněn
Pro libovolný příkaz:
- ERROR <message>
Testování
$ echo 'STATS FULL' | nc -w1 localhost 7531 uptime: 633 days, 15209h 42m 26s total processing time: 85809 days 2059430h 0m 24.000000s average processing time: 0.957994s gained time: 1867 days 44820h 50m 24.000000s waiting time: 390 days 9365h 18m 24.000000s waiting time for me: 389 days 9343h 3m 28.000000s waiting time for anyone: 22h 14m 53.898438s waiting time for good: 520 days 12503h 48m 24.000000s wasted timeout time: 473 days 11375h 2m 44.000000s total_acquired: 7739031655 total_releases: 7736374042 hashtable_entries: 119 processing_workers: 119 waiting_workers: 216 connect_errors: 0 failed_sends: 1 full_queues: 10294544 lock_mismatch: 227 release_mismatch: 0 processed_count: 7739031536
Požadavek na trasování v produkčním prostředí
Rychlá kontrola provozu v produkčním prostředí
Na aplikačním serveru Mediawiki můžete provádět tyto akce:
sudo tcpdump -A 'port 7531 and tcp[tcpflags] & tcp-push != 0'
Obyčejná podpora protokolu Wireshark
Následující Lua skript je obyčejný 'preparátor' pro Wireshark, který jednoduše rozebírá datové části síťových paketů Poolcounter, takže je pak můžete přidat jako sloupec zobrazený v uživatelském rozhraní Wiresharku:
--[[
Obyčejný preparátor protokolu drátu Poolcounter.
Jednoduše vykreslí datovou část jako řetězcové pole, které lze poté povolit jako sloupec.
Copyright © 2020 Chris Danis & the Wikimedia Foundation
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
--]]
poolcounter_protocol = Proto("PoolCounter", "PoolCounter wire protocol")
pc_command_str = ProtoField.string("poolcounter.cmd")
poolcounter_protocol.fields = {pc_command_str}
function poolcounter_protocol.dissector(buffer, pinfo, tree)
length = buffer:len()
if length == 0 then return end
pinfo.cols.protocol = poolcounter_protocol.name
local subtree = tree:add(poolcounter_protocol, buffer(), "PoolCounter protocol data")
subtree:add(pc_command_str, buffer(0,length-1))
end
local tcp_port = DissectorTable.get("tcp.port")
tcp_port:add(7531, poolcounter_protocol)
Na moderních linuxových systémech byste měli být schopni uložit toto jako ~/.local/lib/wireshark/plugins/poolcounter.lua a poté to bude automaticky fungovat jako wireshark or tshark.
Sledování provádění určitých typů požadavků
Představte si, že by vám záleželo na sledování celého konverzačního 'průběhu“' mezi PoolCounterem a jeho klienty pro určitou část klíčového prostoru – v našem příkladu použijeme enwiki:SpecialContributions:a:127.0.0.1.
Protože odpovědi serveru PoolCounter (např. LOCKED) neobsahují klíč, o kterém mluví, není to jednoduché.
Začněte se zachycením paketů z časového úseku, který vás zajímá.
Toto můžete vygenerovat na hostiteli poolcounteru (nebo na hostiteli aplikačního serveru, který používáte pro testování) např.:
sudo tcpdump tcp port 7531 -c 500000 -w poolcounter.pcap
Pak požádáme Wireshark, aby extrahoval seznam svých interních ID TCP streamů pro všechny požadavky, které odpovídají danému klíčovému prostoru:
tshark -r poolcounter.pcap -Y 'poolcounter.cmd contains "enwiki:SpecialContributions:a:127.0.0.1"' -T fields -e tcp.stream | sort | uniq > ids.txt
Jakmile budeme mít tento seznam ID, převedeme ho do filtru zobrazení Wiresharku:
FILTER=$(sed -e 's/^/tcp.stream eq /' -e :a -e 'N;s/\n/ or tcp.stream eq /;ta' ids.txt)
a poté pomocí tohoto filtru vyberte veškerý provoz protokolu PoolCounter pouze z těchto streamů v původním zachycení paketů:
tshark -r poolcounter.pcap -Y "poolcounter and ($FILTER)" -e frame.time_relative -e frame.time -e ip.src -e tcp.stream -e poolcounter.cmd -Tfields
Správce kódu
- Spravováno MediaWiki Platform Team.
- Živý chat (IRC): #mediawiki-core připojit se
- Nástroj pro sledování problémů: Phabricator PoolCounter (nahlášení problému)