
ఏదైనా భాషలో అధిక-లోడ్ ప్రాజెక్ట్లను అభివృద్ధి చేయడానికి ప్రత్యేక విధానం మరియు ప్రత్యేక సాధనాలను ఉపయోగించడం అవసరం, కానీ PHPలోని అనువర్తనాల విషయానికి వస్తే, మీరు అభివృద్ధి చేయాల్సిన పరిస్థితి చాలా తీవ్రతరం అవుతుంది, ఉదాహరణకు, . ఈ నోట్లో మేము పంపిణీ చేయబడిన సెషన్ స్టోరేజ్ మరియు మెమ్క్యాష్డ్లో డేటా కాషింగ్తో తెలిసిన నొప్పి గురించి మరియు ఒక “వార్డ్” ప్రాజెక్ట్లో మేము ఈ సమస్యలను ఎలా పరిష్కరించాము అనే దాని గురించి మాట్లాడుతాము.
ఈ సందర్భంగా హీరో సింఫోనీ 2.3 ఫ్రేమ్వర్క్ ఆధారంగా PHP అప్లికేషన్, ఇది అప్డేట్ చేయడానికి వ్యాపార ప్రణాళికలలో అస్సలు చేర్చబడలేదు. చాలా ప్రామాణిక సెషన్ నిల్వతో పాటు, ఈ ప్రాజెక్ట్ పూర్తిగా ఉపయోగించబడింది "ప్రతిదీ కాష్ చేయడం" విధానం memcachedలో: డేటాబేస్ మరియు API సర్వర్లకు అభ్యర్థనలకు ప్రతిస్పందనలు, వివిధ ఫ్లాగ్లు, కోడ్ అమలును సమకాలీకరించడానికి లాక్లు మరియు మరెన్నో. అటువంటి పరిస్థితిలో, memcached యొక్క విచ్ఛిన్నం అప్లికేషన్ యొక్క ఆపరేషన్కు ప్రాణాంతకం అవుతుంది. అదనంగా, కాష్ నష్టం తీవ్రమైన పరిణామాలకు దారి తీస్తుంది: DBMS అతుకుల వద్ద పగిలిపోవడం ప్రారంభమవుతుంది, API సేవలు అభ్యర్థనలను నిషేధించడం మొదలవుతాయి. పరిస్థితిని స్థిరీకరించడానికి పదుల నిమిషాలు పట్టవచ్చు మరియు ఈ సమయంలో సేవ చాలా నెమ్మదిగా ఉంటుంది లేదా పూర్తిగా అందుబాటులో ఉండదు.
మేము అందించాల్సిన అవసరం ఉంది తక్కువ ప్రయత్నంతో అప్లికేషన్ను అడ్డంగా స్కేల్ చేయగల సామర్థ్యం, అనగా సోర్స్ కోడ్లో కనీస మార్పులు మరియు పూర్తి కార్యాచరణ భద్రపరచబడింది. కాష్ను వైఫల్యాలకు నిరోధకతను మాత్రమే కాకుండా, దాని నుండి డేటా నష్టాన్ని తగ్గించడానికి కూడా ప్రయత్నించండి.
స్వయంగా మెమ్క్యాష్ చేయడంలో తప్పు ఏమిటి?
సాధారణంగా, PHP కోసం memcached పొడిగింపు పంపిణీ చేయబడిన డేటా మరియు బాక్స్ వెలుపల సెషన్ నిల్వకు మద్దతు ఇస్తుంది. స్థిరమైన కీ హ్యాషింగ్ కోసం మెకానిజం అనేక సర్వర్లలో డేటాను సమానంగా ఉంచడానికి మిమ్మల్ని అనుమతిస్తుంది, ప్రతి నిర్దిష్ట కీని సమూహం నుండి నిర్దిష్ట సర్వర్కు ప్రత్యేకంగా సంబోధిస్తుంది మరియు అంతర్నిర్మిత ఫెయిల్ఓవర్ సాధనాలు కాషింగ్ సేవ యొక్క అధిక లభ్యతను నిర్ధారిస్తాయి (కానీ, దురదృష్టవశాత్తు, సమాచారం లేదు).
సెషన్ నిల్వతో విషయాలు కొంచెం మెరుగ్గా ఉన్నాయి: మీరు కాన్ఫిగర్ చేయవచ్చు memcached.sess_number_of_replicas, దీని ఫలితంగా డేటా ఒకేసారి అనేక సర్వర్లలో నిల్వ చేయబడుతుంది మరియు ఒక మెమ్క్యాచ్ చేసిన సందర్భంలో విఫలమైన సందర్భంలో, డేటా ఇతరుల నుండి బదిలీ చేయబడుతుంది. అయినప్పటికీ, సర్వర్ డేటా లేకుండా తిరిగి ఆన్లైన్కు వచ్చినట్లయితే (సాధారణంగా పునఃప్రారంభించిన తర్వాత జరిగే విధంగా), కొన్ని కీలు దాని అనుకూలంగా పునఃపంపిణీ చేయబడతాయి. నిజానికి ఇది అర్థం అవుతుంది సెషన్ డేటా నష్టం, తప్పిపోయిన సందర్భంలో మరొక ప్రతిరూపానికి "వెళ్ళడానికి" మార్గం లేనందున.
ప్రామాణిక లైబ్రరీ సాధనాలు ప్రధానంగా లక్ష్యంగా ఉన్నాయి అడ్డంగా స్కేలింగ్: అవి కాష్ను భారీ పరిమాణాలకు పెంచడానికి మరియు వివిధ సర్వర్లలో హోస్ట్ చేయబడిన కోడ్ నుండి దానికి ప్రాప్యతను అందించడానికి మిమ్మల్ని అనుమతిస్తాయి. అయినప్పటికీ, మా పరిస్థితిలో, నిల్వ చేయబడిన డేటా వాల్యూమ్ అనేక గిగాబైట్లను మించదు మరియు ఒకటి లేదా రెండు నోడ్ల పనితీరు చాలా సరిపోతుంది. దీని ప్రకారం, పని పరిస్థితిలో కనీసం ఒక కాష్ ఉదంతాన్ని కొనసాగించేటప్పుడు మెమ్క్యాచ్ లభ్యతను నిర్ధారించడం మాత్రమే ఉపయోగకరమైన ప్రామాణిక సాధనాలు. అయితే, ఈ అవకాశాన్ని కూడా సద్వినియోగం చేసుకోవడం సాధ్యం కాలేదు... ఇక్కడ ప్రాజెక్ట్లో ఉపయోగించిన ఫ్రేమ్వర్క్ యొక్క పురాతనతను గుర్తుచేసుకోవడం విలువైనదే, అందుకే సర్వర్ల పూల్తో పని చేయడానికి అప్లికేషన్ను పొందడం అసాధ్యం. సెషన్ డేటాను కోల్పోవడం గురించి కూడా మనం మరచిపోకూడదు: వినియోగదారుల యొక్క భారీ లాగ్అవుట్ నుండి కస్టమర్ యొక్క కన్ను కదిలింది.
ఆదర్శవంతంగా ఇది అవసరం మెమ్క్యాచ్ చేయబడిన మరియు బైపాస్ చేసే ప్రతిరూపాలలో రికార్డుల ప్రతిరూపం పొరపాటు లేదా పొరపాటు విషయంలో. ఈ వ్యూహాన్ని అమలు చేయడంలో మాకు సహాయపడింది .
mcrouter
ఇది ఫేస్బుక్ తన సమస్యలను పరిష్కరించడానికి అభివృద్ధి చేసిన మెమ్క్యాష్డ్ రూటర్. ఇది అనుమతించే మెమ్క్యాచ్డ్ టెక్స్ట్ ప్రోటోకాల్కు మద్దతు ఇస్తుంది స్కేల్ memcached సంస్థాపనలు పిచ్చి నిష్పత్తులకు. mcrouter యొక్క వివరణాత్మక వర్ణనను చూడవచ్చు . ఇతర విషయాలతోపాటు ఇది మనకు అవసరమైనది చేయగలదు:
- ప్రతిరూప రికార్డు;
- లోపం సంభవించినట్లయితే సమూహంలోని ఇతర సర్వర్లకు ఫాల్బ్యాక్ చేయండి.
వ్యాపారం కోసం!
mcrouter కాన్ఫిగరేషన్
నేను నేరుగా కాన్ఫిగరేషన్కి వెళ్తాను:
{
"pools": {
"pool00": {
"servers": [
"mc-0.mc:11211",
"mc-1.mc:11211",
"mc-2.mc:11211"
},
"pool01": {
"servers": [
"mc-1.mc:11211",
"mc-2.mc:11211",
"mc-0.mc:11211"
},
"pool02": {
"servers": [
"mc-2.mc:11211",
"mc-0.mc:11211",
"mc-1.mc:11211"
},
"route": {
"type": "OperationSelectorRoute",
"default_policy": "AllMajorityRoute|Pool|pool00",
"operation_policies": {
"get": {
"type": "RandomRoute",
"children": [
"MissFailoverRoute|Pool|pool02",
"MissFailoverRoute|Pool|pool00",
"MissFailoverRoute|Pool|pool01"
]
}
}
}
}మూడు కొలనులు ఎందుకు? సర్వర్లు ఎందుకు పునరావృతమవుతాయి? ఇది ఎలా పనిచేస్తుందో తెలుసుకుందాం.
- ఈ కాన్ఫిగరేషన్లో, రిక్వెస్ట్ కమాండ్ ఆధారంగా రిక్వెస్ట్ పంపబడే మార్గాన్ని mcrouter ఎంచుకుంటుంది. ఆ వ్యక్తి అతనికి ఈ విషయం చెబుతాడు
OperationSelectorRoute. - GET అభ్యర్థనలు హ్యాండ్లర్కి వెళ్తాయి
RandomRouteఇది యాదృచ్ఛికంగా శ్రేణి వస్తువుల మధ్య పూల్ లేదా మార్గాన్ని ఎంచుకుంటుందిchildren. ఈ శ్రేణిలోని ప్రతి మూలకం ఒక హ్యాండ్లర్గా ఉంటుందిMissFailoverRoute, ఇది డేటాతో ప్రతిస్పందనను స్వీకరించే వరకు పూల్లోని ప్రతి సర్వర్ గుండా వెళుతుంది, ఇది క్లయింట్కు తిరిగి ఇవ్వబడుతుంది. - మేము ప్రత్యేకంగా ఉపయోగించినట్లయితే
MissFailoverRouteమూడు సర్వర్ల పూల్తో, అన్ని అభ్యర్థనలు మొదటి మెమ్క్యాచ్ చేసిన ఉదాహరణకి వస్తాయి మరియు మిగిలినవి డేటా లేనప్పుడు అవశేష ప్రాతిపదికన అభ్యర్థనలను స్వీకరిస్తాయి. అలాంటి విధానం దారి తీస్తుంది జాబితాలోని మొదటి సర్వర్పై అధిక లోడ్, కాబట్టి వేర్వేరు సీక్వెన్స్లలో చిరునామాలతో మూడు పూల్లను రూపొందించాలని మరియు వాటిని యాదృచ్ఛికంగా ఎంచుకోవాలని నిర్ణయించారు. - అన్ని ఇతర అభ్యర్థనలు (మరియు ఇది రికార్డ్) ఉపయోగించి ప్రాసెస్ చేయబడతాయి
AllMajorityRoute. ఈ హ్యాండ్లర్ పూల్లోని అన్ని సర్వర్లకు అభ్యర్థనలను పంపుతుంది మరియు వాటిలో కనీసం N/2 + 1 నుండి ప్రతిస్పందనల కోసం వేచి ఉంటుంది. ఉపయోగం నుండిAllSyncRouteఈ పద్ధతికి సానుకూల స్పందన అవసరం కాబట్టి వ్రాత కార్యకలాపాలను వదిలివేయవలసి వచ్చింది всех సమూహంలోని సర్వర్లు - లేకుంటే అది తిరిగి వస్తుందిSERVER_ERROR. mcrouter అందుబాటులో ఉన్న కాష్లకు డేటాను జోడిస్తుంది, కాలింగ్ PHP ఫంక్షన్ లోపాన్ని తిరిగి ఇస్తుంది మరియు నోటీసును రూపొందిస్తుంది.AllMajorityRouteఅంత కఠినంగా లేదు మరియు పైన వివరించిన సమస్యలు లేకుండా సగం వరకు యూనిట్లను సేవ నుండి తీసివేయడానికి అనుమతిస్తుంది.
ప్రధాన ప్రతికూలత ఈ పథకం ఏమిటంటే, కాష్లో నిజంగా డేటా లేనట్లయితే, క్లయింట్ నుండి ప్రతి అభ్యర్థన కోసం N అభ్యర్థనలు memcachedకి అమలు చేయబడతాయి - కు అందరికీ పూల్ లో సర్వర్లు. మేము పూల్లలోని సర్వర్ల సంఖ్యను తగ్గించవచ్చు, ఉదాహరణకు, రెండుకి: నిల్వ విశ్వసనీయతను త్యాగం చేయడం, మేము పొందుతాముоఅభ్యర్థనల నుండి తప్పిపోయిన కీల వరకు అధిక వేగం మరియు తక్కువ లోడ్.
NB: మీరు mcrouter నేర్చుకోవడానికి ఉపయోగకరమైన లింక్లను కూడా కనుగొనవచ్చు и (మూసివేయబడిన వాటితో సహా), వివిధ కాన్ఫిగరేషన్ల మొత్తం స్టోర్హౌస్ను సూచిస్తుంది.
mcrouter నిర్మించడం మరియు అమలు చేయడం
మా అప్లికేషన్ (మరియు మెమ్క్యాచ్ చేయబడింది) కుబెర్నెట్స్లో నడుస్తుంది - తదనుగుణంగా, mcrouter కూడా అక్కడ ఉంది. కోసం కంటైనర్ అసెంబ్లీ మేము ఉపయోగిస్తాము , దీని కోసం కాన్ఫిగర్ ఇలా కనిపిస్తుంది:
NB: వ్యాసంలో ఇవ్వబడిన జాబితాలు రిపోజిటరీలో ప్రచురించబడ్డాయి .
configVersion: 1
project: mcrouter
deploy:
namespace: '[[ env ]]'
helmRelease: '[[ project ]]-[[ env ]]'
---
image: mcrouter
from: ubuntu:16.04
mount:
- from: tmp_dir
to: /var/lib/apt/lists
- from: build_dir
to: /var/cache/apt
ansible:
beforeInstall:
- name: Install prerequisites
apt:
name: [ 'apt-transport-https', 'tzdata', 'locales' ]
update_cache: yes
- name: Add mcrouter APT key
apt_key:
url: https://facebook.github.io/mcrouter/debrepo/xenial/PUBLIC.KEY
- name: Add mcrouter Repo
apt_repository:
repo: deb https://facebook.github.io/mcrouter/debrepo/xenial xenial contrib
filename: mcrouter
update_cache: yes
- name: Set timezone
timezone:
name: "Europe/Moscow"
- name: Ensure a locale exists
locale_gen:
name: en_US.UTF-8
state: present
install:
- name: Install mcrouter
apt:
name: [ 'mcrouter' ]()
... మరియు దానిని గీయండి హెల్మ్ చార్ట్. ఆసక్తికరమైన విషయం ఏమిటంటే, ప్రతిరూపాల సంఖ్య ఆధారంగా కాన్ఫిగరేషన్ జనరేటర్ మాత్రమే ఉంది (ఎవరైనా మరింత లాకోనిక్ మరియు సొగసైన ఎంపికను కలిగి ఉంటే, దానిని వ్యాఖ్యలలో భాగస్వామ్యం చేయండి):
{{- $count := (pluck .Values.global.env .Values.memcached.replicas | first | default .Values.memcached.replicas._default | int) -}}
{{- $pools := dict -}}
{{- $servers := list -}}
{{- /* Заполняем массив двумя копиями серверов: "0 1 2 0 1 2" */ -}}
{{- range until 2 -}}
{{- range $i, $_ := until $count -}}
{{- $servers = append $servers (printf "mc-%d.mc:11211" $i) -}}
{{- end -}}
{{- end -}}
{{- /* Смещаясь по массиву, получаем N срезов: "[0 1 2] [1 2 0] [2 0 1]" */ -}}
{{- range $i, $_ := until $count -}}
{{- $pool := dict "servers" (slice $servers $i (add $i $count)) -}}
{{- $_ := set $pools (printf "MissFailoverRoute|Pool|pool%02d" $i) $pool -}}
{{- end -}}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: mcrouter
data:
config.json: |
{
"pools": {{- $pools | toJson | replace "MissFailoverRoute|Pool|" "" -}},
"route": {
"type": "OperationSelectorRoute",
"default_policy": "AllMajorityRoute|Pool|pool00",
"operation_policies": {
"get": {
"type": "RandomRoute",
"children": {{- keys $pools | toJson }}
}
}
}
}()
మేము దానిని పరీక్షా వాతావరణంలోకి పంపుతాము మరియు తనిఖీ చేస్తాము:
# php -a
Interactive mode enabled
php > # Проверяем запись и чтение
php > $m = new Memcached();
php > $m->addServer('mcrouter', 11211);
php > var_dump($m->set('test', 'value'));
bool(true)
php > var_dump($m->get('test'));
string(5) "value"
php > # Работает! Тестируем работу сессий:
php > ini_set('session.save_handler', 'memcached');
php > ini_set('session.save_path', 'mcrouter:11211');
php > var_dump(session_start());
PHP Warning: Uncaught Error: Failed to create session ID: memcached (path: mcrouter:11211) in php shell code:1
Stack trace:
#0 php shell code(1): session_start()
#1 {main}
thrown in php shell code on line 1
php > # Не заводится… Попробуем задать session_id:
php > session_id("zzz");
php > var_dump(session_start());
PHP Warning: session_start(): Cannot send session cookie - headers already sent by (output started at php shell code:1) in php shell code on line 1
PHP Warning: session_start(): Failed to write session lock: UNKNOWN READ FAILURE in php shell code on line 1
PHP Warning: session_start(): Failed to write session lock: UNKNOWN READ FAILURE in php shell code on line 1
PHP Warning: session_start(): Failed to write session lock: UNKNOWN READ FAILURE in php shell code on line 1
PHP Warning: session_start(): Failed to write session lock: UNKNOWN READ FAILURE in php shell code on line 1
PHP Warning: session_start(): Failed to write session lock: UNKNOWN READ FAILURE in php shell code on line 1
PHP Warning: session_start(): Failed to write session lock: UNKNOWN READ FAILURE in php shell code on line 1
PHP Warning: session_start(): Unable to clear session lock record in php shell code on line 1
PHP Warning: session_start(): Failed to read session data: memcached (path: mcrouter:11211) in php shell code on line 1
bool(false)
php >లోపం యొక్క వచనం కోసం శోధించడం ఎటువంటి ఫలితాలను ఇవ్వలేదు, కానీ ప్రశ్న కోసం ""ప్రాజెక్ట్ యొక్క పురాతన పరిష్కారం కాని సమస్య ముందంజలో ఉంది - memcached బైనరీ ప్రోటోకాల్.
NB: memcachedలోని ASCII ప్రోటోకాల్ బైనరీ కంటే నెమ్మదిగా ఉంటుంది మరియు స్థిరమైన కీ హ్యాషింగ్ యొక్క ప్రామాణిక సాధనాలు బైనరీ ప్రోటోకాల్తో మాత్రమే పని చేస్తాయి. కానీ ఇది ఒక నిర్దిష్ట సందర్భంలో సమస్యలను సృష్టించదు.
ట్రిక్ బ్యాగ్లో ఉంది: మీరు చేయాల్సిందల్లా ASCII ప్రోటోకాల్కి మారడం మరియు ప్రతిదీ పని చేస్తుంది.... అయితే ఈ విషయంలో సమాధానాలు వెతకడం అలవాటు క్రూరమైన జోక్ ఆడాడు. మీరు అక్కడ సరైన సమాధానం కనుగొనలేరు... అయితే, మీరు చివర వరకు స్క్రోల్ చేస్తే తప్ప, విభాగంలో ఎక్కడ "వినియోగదారు అందించిన గమనికలు" విశ్వాసపాత్రంగా ఉంటుంది మరియు .
అవును, సరైన ఎంపిక పేరు memcached.sess_binary_protocol. ఇది తప్పనిసరిగా నిలిపివేయబడాలి, ఆ తర్వాత సెషన్లు పనిచేయడం ప్రారంభిస్తాయి. PHPతో పాడ్లో mcrouter ఉన్న కంటైనర్ను ఉంచడమే మిగిలి ఉంది!
తీర్మానం
అందువల్ల, కేవలం మౌలిక మార్పులతో మేము సమస్యను పరిష్కరించగలిగాము: మెమ్క్యాచ్డ్ ఫాల్ట్ టాలరెన్స్తో సమస్య పరిష్కరించబడింది మరియు కాష్ నిల్వ యొక్క విశ్వసనీయత పెరిగింది. అప్లికేషన్ కోసం స్పష్టమైన ప్రయోజనాలతో పాటు, ప్లాట్ఫారమ్లో పనిచేసేటప్పుడు ఇది యుక్తికి గదిని ఇచ్చింది: అన్ని భాగాలు రిజర్వ్ను కలిగి ఉన్నప్పుడు, నిర్వాహకుడి జీవితం చాలా సరళీకృతం చేయబడుతుంది. అవును, ఈ పద్ధతి దాని లోపాలను కూడా కలిగి ఉంది, ఇది "క్రచ్" లాగా ఉండవచ్చు, కానీ అది డబ్బును ఆదా చేస్తే, సమస్యను పూడ్చివేస్తుంది మరియు కొత్త వాటికి కారణం కాదు - ఎందుకు కాదు?
PS
మా బ్లాగులో కూడా చదవండి:
- "డాప్తో ప్రాక్టీస్ చేయండి" (సింఫోనీ-డెమోను ఉదాహరణగా ఉపయోగించడం): и ;
- «".
మూలం: www.habr.com
