2009-05-19 17 views
43

मैं एक स्कूल प्रोजेक्ट पर काम कर रहा हूं जहां मुझे एक बहु थ्रेडेड सर्वर लिखना पड़ा, और अब मैं इसके खिलाफ कुछ परीक्षण चलाकर अपाचे से तुलना कर रहा हूं। मैं इसके साथ मदद करने के लिए ऑटोबॉन्च का उपयोग कर रहा हूं, लेकिन कुछ परीक्षण चलाने के बाद, या यदि कनेक्शन बनाने के लिए मैं इसे बहुत अधिक दर (लगभग 600+) देता हूं, तो मुझे "बहुत सारी खुली फ़ाइलें" त्रुटि मिलती है।सॉकेट स्वीकार करते हैं - "बहुत सारी खुली फ़ाइलें"

अनुरोध के साथ काम करने के बाद, मैं हमेशा सॉकेट पर close() करता हूं। मैंने shutdown() फ़ंक्शन का उपयोग करने का प्रयास किया है, लेकिन कुछ भी मदद नहीं करता है। इस के आसपास किसी भी तरह से?

उत्तर

47

कई स्थानों रहे हैं जहां लिनक्स हो, तो देखने के लिए

lsof सूची खुली फ़ाइलों

cat /proc/sys/fs/file-max उपलब्ध हो जाती है आपके पास खोलने की अनुमति देने वाले फ़ाइल डिस्क्रिप्टर की संख्या पर सीमा हो सकती है।

आप देख सकते हैं निम्नलिखित:

cat /proc/sys/fs/file-max 

है कि आप सिस्टम फ़ाइल वर्णनकर्ता की व्यापक सीमा दे देंगे।

खोल स्तर पर, यह आप अपने व्यक्तिगत सीमा बता देंगे:

ulimit -n 

यह /etc/security/limits.conf में बदला जा सकता है - यह nofile परम है।

हालांकि, अगर आप अपने सॉकेट को सही तरीके से बंद कर रहे हैं, तो आपको यह तब तक प्राप्त नहीं करना चाहिए जब तक कि आप बहुत से सिमुलेशन कनेक्शन खोल रहे हों। ऐसा लगता है जैसे कुछ आपके सॉकेट को उचित रूप से बंद होने से रोक रहा है। मैं सत्यापित करता हूं कि उन्हें ठीक से संभाला जा रहा है।

+0

मैं संपादित /etc/security/limits.conf के साथ संपादित करता हूं: – linjunhalida

+0

उपयोगकर्ता नाम हार्ड nofile 20000 – linjunhalida

4

यह समय का एक सा लग सकता एक बंद सॉकेट वास्तव में एक सिस्टम सीमा

1

जब आपके प्रोग्राम में खुली फाइलों के मुकाबले अधिक खुले डिस्क्रिप्टर होते हैं तो ulimit (ulimit -a इसे सूचीबद्ध करेगा), कर्नेल किसी और फ़ाइल डिस्क्रिप्टर को खोलने से इंकार कर देगा। सुनिश्चित करें कि आपके पास कोई फ़ाइल डिस्क्रिप्टर लीक नहीं है - उदाहरण के लिए, इसे थोड़ी देर के लिए चलाकर, फिर रोकना और देखना कि क्या कोई अतिरिक्त एफडीएस निष्क्रिय होने पर अभी भी खुला है - और यदि यह अभी भी एक समस्या है, तो अपने लिए नोफाइल ulimit बदलें उपयोगकर्ता /etc/security/limits.conf

12

टीसीपी में "TIME_WAIT" नामक एक सुविधा है जो सुनिश्चित करता है कि कनेक्शन साफ़ रूप से बंद हो जाएं। सॉकेट बंद होने के बाद थोड़ी देर के लिए सुनने के लिए कनेक्शन के एक छोर की आवश्यकता होती है।

एक उच्च प्रदर्शन सर्वर में, यह महत्वपूर्ण है कि यह क्लाइंट जो TIME_WAIT में जाएं, न कि सर्वर पर। ग्राहक एक बंदरगाह खोल सकते हैं, जबकि एक व्यस्त सर्वर बंदरगाहों से तेजी से भाग सकता है या बहुत अधिक खुले एफडी हैं।

इसे प्राप्त करने के लिए, सर्वर को पहले कभी कनेक्शन बंद नहीं करना चाहिए - इसे हमेशा ग्राहक को बंद करने के लिए प्रतीक्षा करनी चाहिए।

+2

नहीं। टीसीपी TIME_WAIT ऑपरेटिंग सिस्टम स्तर पर खुले सॉकेट रखेगा और अंततः सर्वर आने वाले कनेक्शन को अस्वीकार कर देगा। जब आप फ़ाइल हैंडल बंद करते हैं, तो यह बंद हो जाता है। http://stackoverflow.com/questions/1803566/what-is-the-cost-of-many-time-wait-on-the-server-side –

+0

यह सच है कि फ़ाइल हैंडल तुरंत बंद हो जाता है और मैं गलत टाइप करता हूं। लेकिन मेरा मुख्य बिंदु अभी भी खड़ा है, भले ही एफडी मुक्त हो गया हो, टीसीपी बंदरगाह TIME_WAIT के दौरान आवंटित रहता है, और एक व्यस्त सर्वर टीसीपी बंदरगाहों से बाहर हो सकता है, या उन्हें बहुत अधिक कर्नेल मेमोरी ट्रैक कर सकता है। – Ed4

5

उपयोग lsof -u `whoami` | wc -l कितने खुली फ़ाइलों उपयोगकर्ता

15

मैं इसी तरह की समस्या थी है खोजने के लिए। त्वरित समाधान है:

ulimit -n 4096 

विवरण इस प्रकार है - प्रत्येक सर्वर कनेक्शन एक फ़ाइल जानकारी देता है।CentOS में, Redhat और Fedora, शायद अन्य, फ़ाइल उपयोगकर्ता सीमा 1024 है - कोई विचार क्यों नहीं। जब आप टाइप करते हैं तो इसे आसानी से देखा जा सकता है: ulimit -n

ध्यान दें कि इसका सिस्टम सिस्टम फ़ाइलों (/ proc/sys/fs/file-max) से कोई अधिक संबंध नहीं है।

मेरे मामले में यह Redis के साथ समस्या थी, इसलिए मैंने किया:

ulimit -n 4096 
redis-server -c xxxx 

redis के बजाय आपके मामले में, आप अपने सर्वर शुरू करने के लिए की जरूरत है।

+2

और मेमोरी लीक का जवाब है ... और मेमोरी खरीदें? फ़ाइल रिसाव ठीक नहीं है। –

+2

ऐसा लगता है कि आप समस्या को समझ नहीं पाते हैं (या आप गलत उत्तर के तहत टिप्पणी डालते हैं? इसे फ़ाइल डिस्क्रिप्टर सीमा के साथ करना है, और स्मृति या स्मृति रिसाव के साथ कुछ भी नहीं करना है। – Nick

+1

फ़ाइल सीमा 1024 है क्योंकि अन्यथा आप चलाते हैं 'चुनिंदा() '] (http://beesbuzz.biz/blog/e/2013/10/10-the_problem_with_select_vs_poll.php) के साथ मौलिक समस्या में। – fluffy

1

मुझे एक ही समस्या थी और मैं करीबी() कॉल के वापसी मूल्यों की जांच करने के लिए परेशान नहीं था। जब मैंने वापसी मूल्य की जांच शुरू कर दी, तो समस्या रहस्यमय तरीके से गायब हो गई।

मैं केवल संकलक (मेरे मामले में जीसीसी) की एक ऑप्टिमाइज़ेशन गड़बड़ मान सकता हूं, यह मान रहा है कि करीबी() कॉल साइड इफेक्ट्स के बिना हैं और यदि उनके रिटर्न वैल्यू का उपयोग नहीं किया जाता है तो उन्हें छोड़ा जा सकता है।

+2

मुझे खेद है कि यह बिल्कुल सही नहीं है। अगर आपके कोड में बहुत मामूली बदलाव ने बग को "दूर जाना" बनाया, तो आप सबसे अधिक शायद आपके कोड में एक गंभीर बग है कि परिवर्तन छिपा हुआ है। इसे ट्रैक करने के लिए 'वालग्रींड' या ऐसे अन्य टूल्स का उपयोग करें। 'क्लोजर' कॉल को ऑप्टिमाइज़ करने वाला एक कंपाइलर आपदाजनक होगा सी। – Mat

5

मुझे यह समस्या भी थी। आपके पास फाइल हैंडल रिसाव है। आप (इसे POSIX सिस्टम पर) सभी खुले फ़ाइल हैंडल की एक सूची मुद्रण द्वारा इस डिबग कर सकते हैं:

void showFDInfo() 
{ 
    s32 numHandles = getdtablesize(); 

    for (s32 i = 0; i < numHandles; i++) 
    { 
     s32 fd_flags = fcntl(i, F_GETFD); 
     if (fd_flags == -1) continue; 


     showFDInfo(i); 
    } 
} 

void showFDInfo(s32 fd) 
{ 
    char buf[256]; 

    s32 fd_flags = fcntl(fd, F_GETFD); 
    if (fd_flags == -1) return; 

    s32 fl_flags = fcntl(fd, F_GETFL); 
    if (fl_flags == -1) return; 

    char path[256]; 
    sprintf(path, "/proc/self/fd/%d", fd); 

    memset(&buf[0], 0, 256); 
    ssize_t s = readlink(path, &buf[0], 256); 
    if (s == -1) 
    { 
     cerr << " (" << path << "): " << "not available"; 
     return; 
    } 
    cerr << fd << " (" << buf << "): "; 

    if (fd_flags & FD_CLOEXEC) cerr << "cloexec "; 

    // file status 
    if (fl_flags & O_APPEND ) cerr << "append "; 
    if (fl_flags & O_NONBLOCK) cerr << "nonblock "; 

    // acc mode 
    if (fl_flags & O_RDONLY ) cerr << "read-only "; 
    if (fl_flags & O_RDWR ) cerr << "read-write "; 
    if (fl_flags & O_WRONLY ) cerr << "write-only "; 

    if (fl_flags & O_DSYNC ) cerr << "dsync "; 
    if (fl_flags & O_RSYNC ) cerr << "rsync "; 
    if (fl_flags & O_SYNC ) cerr << "sync "; 

    struct flock fl; 
    fl.l_type = F_WRLCK; 
    fl.l_whence = 0; 
    fl.l_start = 0; 
    fl.l_len = 0; 
    fcntl(fd, F_GETLK, &fl); 
    if (fl.l_type != F_UNLCK) 
    { 
     if (fl.l_type == F_WRLCK) 
     cerr << "write-locked"; 
     else 
     cerr << "read-locked"; 
     cerr << "(pid:" << fl.l_pid << ") "; 
    } 
} 

सभी खुली फ़ाइलों आप जल्दी से यह पता लगाने जाएगा जहां अपनी फ़ाइल हैंडल रिसाव है बाहर डंपिंग के द्वारा।

यदि आपका सर्वर subprocesses spawns। जैसे यदि यह एक 'कांटा' शैली सर्वर है, या यदि आप अन्य प्रक्रियाओं (जैसे सीजीआई के माध्यम से) उत्पन्न कर रहे हैं, तो आपको वास्तविक फाइलों और सॉकेट दोनों के लिए "क्लॉएक्सैक" के साथ अपनी फ़ाइल हैंडल बनाना सुनिश्चित करना होगा।

क्लॉएक्सैक के बिना, हर बार जब आप कांटा या स्पॉन करते हैं, तो सभी खुले फ़ाइल हैंडल बाल प्रक्रिया में क्लोन किए जाते हैं।

नेटवर्क सॉकेट को बंद करने में असफल होना भी वास्तव में आसान है - उदा। रिमोट पार्टी डिस्कनेक्ट होने पर बस उन्हें छोड़ दें। यह पागल की तरह रिसाव संभाल जाएगा।

4

इसका मतलब है कि एक साथ खुली फ़ाइलों की अधिकतम संख्या।

हल: (sudo काम नहीं करता है) करने के लिए जड़ से

* soft nofile 16384 
* hard nofile 16384 

वर्तमान कंसोल में:

फ़ाइल के अंत में /etc/security/limits.conf आप निम्नलिखित लाइनों को जोड़ने की आवश्यकता

ulimit -n 16384 

हालांकि यह वैकल्पिक है, यदि सर्वर को पुनरारंभ करना संभव है।

/etc/nginx/nginx.conf फ़ाइल में नया मान मूल्य worker_processes द्वारा 16384 विभाजन के worker_connections बराबर रजिस्टर करने के लिए।

यदि ulimit -n 16384 नहीं किया गया है, तो रीबूट करने की आवश्यकता है, तो समस्या वापस आ जाएगी।

पुनश्च:

हैं के बाद मरम्मत लॉग error accept() failed (24: Too many open files) में दिख रहा है:

nginx विन्यास में, propevia (उदाहरण के लिए):

worker_processes 2; 

worker_rlimit_nofile 16384; 

events { 
    worker_connections 8192; 
} 
0

बस CentOS के बारे में एक और जानकारी । इस मामले में, प्रक्रिया को लॉन्च करने के लिए "systemctl" का उपयोग करते समय। आप सिस्टम फ़ाइल को संशोधित करने के लिए है ==> /usr/lib/systemd/system/processName.service .Had फ़ाइल में इस लाइन:

LimitNOFILE=50000 

और बस अपने सिस्टम को फिर से लोड conf:

systemctl daemon-reload 
संबंधित मुद्दे