{"id":333983,"date":"2022-06-02T15:01:04","date_gmt":"2022-06-02T15:01:04","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=333983"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=333983","title":{"rendered":"<span>\u041a\u0430\u043a \u044f \u0440\u0430\u0437\u043e\u0433\u043d\u0430\u043b fail2ban* \u0432 \u0442\u044b\u0441\u044f\u0447\u0443 \u0440\u0430\u0437 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e SIMD<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p><code>Fail2ban<\/code> \u2014 \u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0447\u0440\u0435\u0437\u0432\u044b\u0447\u0430\u0439\u043d\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u0432\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445. \u0414\u0443\u043c\u0430\u044e, \u043c\u043d\u043e\u0433\u0438\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0435\u0451 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0432 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043d\u0430\u0437\u043e\u0439\u043b\u0438\u0432\u044b\u0445 \u00ab\u043f\u043e\u0441\u0435\u0442\u0438\u0442\u0435\u043b\u0435\u0439\u00bb. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0435\u0441\u043b\u0438 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u043f\u043e\u0442\u043e\u043a \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u0438\u043c, <code>fail2ban<\/code> \u0442\u0435\u0440\u044f\u0435\u0442 \u0432\u0441\u0435 \u0441\u0432\u043e\u0438 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0440\u0430\u0437\u0431\u043e\u0440 \u043b\u043e\u0433\u0430 \u0431\u0435\u0437\u043d\u0430\u0434\u0451\u0436\u043d\u043e \u043e\u0442\u0441\u0442\u0430\u0451\u0442 \u043e\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u0412\u043e\u0442, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043b\u043e\u0433 <code>nginx<\/code> \u0438\u0437 100 \u0442\u044b\u0441\u044f\u0447 \u0441\u0442\u0440\u043e\u0447\u0435\u043a <code>fail2ban<\/code> \u043f\u0440\u0438 \u0441\u0430\u043c\u044b\u0445 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 (<code>failregex='^&lt;ADDR>'<\/code>) \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 \u043f\u043e\u0440\u044f\u0434\u043a\u0430 45 \u0441\u0435\u043a\u0443\u043d\u0434:<\/p>\n<pre><code>$ fail2ban-regex nginx.log '^&lt;ADDR>'  Running tests =============  Use   failregex line : ^&lt;ADDR> Use         log file : nginx.log Use         encoding : UTF-8   Results =======  Failregex: 100000 total |-  #) [# of hits] regular expression |   1) [100000] ^&lt;ADDR> `-  Ignoreregex: 0 total  Date template hits: |- [# of hits] date format |  [100000] Day(?P&lt;_sep>[-\/])MON(?P=_sep)ExYear[ :]?24hour:Minute:Second(?:\\.Microseconds)?(?: Zone offset)? `-  Lines: 100000 lines, 0 ignored, 100000 matched, 0 missed [processed in 44.48 sec]<\/code><\/pre>\n<p>\u0427\u0435\u0441\u0442\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0432 \u043e\u0434\u043d\u043e \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0435, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0440\u044f\u0434\u043a\u0430 2250 \u0441\u0442\u0440\u043e\u043a \u0432\u00a0\u0441\u0435\u043a\u0443\u043d\u0434\u0443. \u0412\u043e\u0437\u044c\u043c\u0451\u043c \u044d\u0442\u0443 \u0446\u0438\u0444\u0440\u0443 \u0437\u0430 \u043e\u0441\u043d\u043e\u0432\u0443. <\/p>\n<p>(\u041f\u043e \u0444\u0430\u043a\u0442\u0443 \u0440\u0430\u0437\u0431\u043e\u0440 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435 \u0438\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e <code>fail2ban<\/code> \u0431\u0430\u043d\u0438\u0442 \u0432\u044b\u044f\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043d\u0430\u0440\u0443\u0448\u0438\u0442\u0435\u043b\u0435\u0439 \u0432 \u0442\u043e\u043c \u0436\u0435 \u043f\u043e\u0442\u043e\u043a\u0435, \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u044f \u0447\u0442\u0435\u043d\u0438\u0435 \u043b\u043e\u0433\u0430)<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u043f\u043e\u0440\u0430 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043e\u0441\u0442\u0430\u0442\u044c\u0441\u044f \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 <code>fail2ban<\/code> \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c, \u043d\u0430 \u0447\u0442\u043e \u0436\u0435 \u043e\u043d \u0442\u0440\u0430\u0442\u0438\u0442 \u0432\u0440\u0435\u043c\u044f. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 <code>fail2ban<\/code> \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 Python, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c <code>cProfile<\/code> \u0431\u0435\u0437 \u0432\u0441\u044f\u043a\u0438\u0445 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0439 \u043a\u043e\u0434\u0430:<\/p>\n<pre><code>$ python -m cProfile -s cumtime \/usr\/bin\/fail2ban-regex nginx.log '^&lt;ADDR>'  ...     Ordered by: cumulative time     ncalls  tottime  percall  cumtime  percall filename:lineno(function)         1    0.001    0.001   52.734   52.734 fail2ban-regex:26(&lt;module>)         1    0.000    0.000   52.640   52.640 fail2banregex.py:784(exec_command_line)         1    0.000    0.000   52.638   52.638 fail2banregex.py:719(start)         1    0.411    0.411   52.636   52.636 fail2banregex.py:571(process)    100000    0.789    0.000   50.909    0.001 fail2banregex.py:448(testRegex)    100000    0.689    0.000   49.839    0.000 filter.py:601(processLine)    100000    3.741    0.000   39.767    0.000 datedetector.py:321(matchTime)   1595350    0.945    0.000   34.731    0.000 datetemplate.py:157(matchDate)   1695573   33.933    0.000   33.933    0.000 {method 'search' of '_sre.SRE_Pattern' objects}    100000    0.205    0.000    5.583    0.000 datedetector.py:469(getTime)    100000    0.187    0.000    5.305    0.000 datetemplate.py:323(getDate)    100000    1.826    0.000    4.858    0.000 strptime.py:172(reGroupDictStrptime)    100000    1.284    0.000    3.519    0.000 filter.py:811(findFailure)   1400000    0.564    0.000    1.479    0.000 utf_8.py:15(decode) 200000\/100000    0.615    0.000    1.303    0.000 strptime.py:143(zone2offset)    100000    0.154    0.000    1.100    0.000 strptime.py:124(validateTimeZone)    100000    0.422    0.000    0.965    0.000 {method 'index' of 'list' objects<\/code><\/pre>\n<p>\u0438 \u0432\u0438\u0434\u0438\u043c \u043d\u0435\u0443\u0442\u0435\u0448\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u0443. \u0411\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 fail2ban \u0442\u0440\u0430\u0442\u0438\u0442 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u043c \u0434\u0430\u0442\u044b. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0435\u043c\u0443 \u0432 \u044d\u0442\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043c\u043e\u0447\u044c \u2014 \u043d\u0443\u0436\u043d\u043e \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0443 \u0441\u0430\u043c\u0443\u044e \u0434\u0430\u0442\u0443 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c. \u0421\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 <code>datepattern<\/code> \u0432 \u0444\u0430\u0439\u043b\u0430\u0445 <code>filter.d\/*.conf<\/code>, \u0430 \u0434\u043b\u044f <code>fail2ban-regex<\/code> \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>-d<\/code>. <\/p>\n<details class=\"spoiler\">\n<summary>\u0412\u044b\u0432\u043e\u0434 fail2ban-regex<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>$ fail2ban-regex nginx.log -d '%d\/%B\/%Y:%H:%M:%S' '^&lt;ADDR> - [^ ]+ '  Running tests =============  Use      datepattern : %d\/%B\/%Y:%H:%M:%S : Day\/MONTH\/Year:24hour:Minute:Second Use   failregex line : ^&lt;ADDR> - [^ ]+ Use         log file : nginx.log Use         encoding : UTF-8   Results =======  Failregex: 100000 total |-  #) [# of hits] regular expression |   1) [100000] ^&lt;ADDR> - [^ ]+ `-  Ignoreregex: 0 total  Date template hits: |- [# of hits] date format |  [100000] Day\/MONTH\/Year:24hour:Minute:Second `-  Lines: 100000 lines, 0 ignored, 100000 matched, 0 missed [processed in 8.07 sec]<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418\u0442\u043e\u0433\u043e \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0440\u0430\u0437\u0431\u043e\u0440\u0430 \u0432\u044b\u0440\u043e\u0441\u043b\u0430 \u043f\u043e\u0447\u0442\u0438 \u0432 \u0448\u0435\u0441\u0442\u044c \u0440\u0430\u0437 \u2014 \u0434\u043e \u043f\u043e\u0447\u0442\u0438 12,5 \u0442\u044b\u0441\u044f\u0447 \u0441\u0442\u0440\u043e\u043a \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443. \u041a\u00a0\u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0442\u0430\u043a\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0438\u0436\u0438\u043c\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u0440\u0430\u0437\u0431\u043e\u0440\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>fail2ban-regex<\/code>: \u043a\u0430\u043a \u0443\u0436\u0435 \u0431\u044b\u043b\u043e \u0441\u043a\u0430\u0437\u0430\u043d\u043e \u0432\u044b\u0448\u0435, \u0432 \u0431\u043e\u0435\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u043f\u0440\u0438 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u043c \u0447\u0442\u0435\u043d\u0438\u0438 \u043b\u043e\u0433\u043e\u0432 \u044d\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435.<\/p>\n<h2>\u041f\u0435\u0440\u0435\u043f\u0438\u0448\u0435\u043c \u043d\u0430 \u0447\u0451\u043c-\u0442\u043e \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u043c\u043e\u043c<\/h2>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043d\u0430 \u044d\u0442\u043e\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 <code>fail2ban<\/code> \u0438\u0441\u0447\u0435\u0440\u043f\u0430\u043b\u0438\u0441\u044c, \u043c\u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0438\u0441\u043a\u0430\u0442\u044c \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u044b. \u0412 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u044f \u043d\u0430\u0447\u0430\u043b \u0438\u0437\u0443\u0447\u0430\u0442\u044c Rust \u0438 \u043f\u0440\u0435\u0431\u044b\u0432\u0430\u044e \u0432 \u043f\u043e\u043b\u043d\u043e\u043c \u0432\u043e\u0441\u0442\u043e\u0440\u0433\u0435 \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u044b\u0431\u0440\u0430\u043b \u0435\u0433\u043e.<\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0431\u0430\u043d\u0438\u0442\u044c \u043d\u0430\u0440\u0443\u0448\u0438\u0442\u0435\u043b\u0435\u0439, \u043d\u0443\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 <code>N<\/code> \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 (\u0438\u043b\u0438 \u043c\u0435\u043d\u044c\u0448\u0435) \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e IP-\u0430\u0434\u0440\u0435\u0441\u0430 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c, \u043d\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043b\u0438 \u0447\u0430\u0441\u0442\u043e \u043e\u043d\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442. \u0417\u0434\u0435\u0441\u044c \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u043a\u043e\u043b\u044c\u0446\u0435\u0432\u043e\u0439 \u0431\u0443\u0444\u0435\u0440 \u0441 \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u043e\u0439: \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u0430\u0439\u043c\u0441\u0442\u0430\u043c\u043f\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u043e \u043a\u0440\u0443\u0433\u0443, \u0438 \u043a\u043e\u0433\u0434\u0430 \u043d\u0430\u043a\u043e\u043f\u0438\u043c <code>ring_size<\/code> \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439, \u0442\u043e \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432\u043d\u043e\u0432\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 <code>N<\/code> \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043d\u0430\u0437\u0430\u0434.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u043a\u043e\u043b\u044c\u0446\u0435\u0432\u043e\u0433\u043e \u0431\u0443\u0444\u0435\u0440\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">struct RingBanBuffer {     timestamps: Vec&lt;Option&lt;i64>>,     last_index: usize, }  impl RingBanBuffer {     fn new(ring_size: usize) -> RingBanBuffer {         RingBanBuffer {             timestamps: vec![None; ring_size],             last_index: 0         }     }      fn add_query(&amp;mut self, ts: i64) -> Option&lt;i64> {         self.timestamps[self.last_index] = Some(ts);         self.last_index = (self.last_index + 1) % self.timestamps.len();          self.timestamps[self.last_index].map(|prev| ts - prev)     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043f\u0430\u0440\u0441\u0435\u0440 \u043b\u043e\u0433\u043e\u0432 \u0442\u043e\u0436\u0435 \u043d\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0441\u043b\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c: \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u0434\u0438\u0440\u0430\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0441 \u043f\u043e\u043b\u044f (IP \u0438 \u0434\u0430\u0442\u0443) \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0433\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u043f\u043e\u0442\u043e\u043c \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u043c \u0438\u0445. \u0415\u0441\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e \u043d\u0435 \u0442\u043e, \u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c <code>None<\/code>.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u043f\u0430\u0440\u0441\u0435\u0440\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use chrono::*; use regex::Regex; use std::net::IpAddr;  struct ParseResult {     ip: IpAddr,     timestamp: i64, }  struct RegexParser {     regex: Regex,     date_format: String, }  impl RegexParser {     fn new(regex: &amp;str, date_format: &amp;str) -> Self {         let re = Regex::new(regex).unwrap();         RegexParser {             regex: re,             date_format: date_format.to_string(),         }     }      fn parse_line(&amp;self, line: &amp;str) -> Option&lt;ParseResult> {         let caps = self.regex.captures(line)?;         let timestamp = DateTime::parse_from_str(&amp;caps[\"DT\"], &amp;self.date_format).ok()?.timestamp();         let ip: IpAddr = caps[\"ip\"].parse().ok()?;         Some(ParseResult { ip, timestamp })     } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u0434\u0430\u0442\u044b \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f <a href=\"https:\/\/crates.io\/crates\/chrono\" rel=\"noopener noreferrer nofollow\">\u043a\u0440\u0435\u0439\u0442 chrono<\/a>.<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0432\u0441\u0451 \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0432\u043e\u0435\u0434\u0438\u043d\u043e. \u0417\u0430\u0432\u0435\u0434\u0451\u043c <code>HashMap<\/code>, \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 IP-\u0430\u0434\u0440\u0435\u0441\u0430 \u0441 \u043a\u043e\u043b\u044c\u0446\u0435\u0432\u044b\u043c\u0438 \u0431\u0443\u0444\u0435\u0440\u0430\u043c\u0438 \u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0437\u0430\u0431\u0430\u043d\u0435\u043d\u043d\u043e\u0441\u0442\u0438, \u0447\u0438\u0442\u0430\u0435\u043c \u0444\u0430\u0439\u043b \u043f\u043e \u0441\u0442\u0440\u043e\u0447\u043a\u0430\u043c \u0438 \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0434\u0430\u043d\u043d\u044b\u0445. \u041a\u043e\u0433\u0434\u0430 \u0432\u0435\u0441\u044c \u0444\u0430\u0439\u043b \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043d, \u0442\u043e \u043f\u0435\u0447\u0430\u0442\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u0431\u0430\u043d\u0435\u043d\u043d\u044b\u0445 \u0432 <code>stdout<\/code> \u0438 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443 \u0432 <code>stderr<\/code>.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 main<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">fn main() {     let reader = BufReader::new(File::open(\"nginx.log\").unwrap());     let parser = RegexParser::new(         r\"^(?P&lt;ip>[\\d.]+) - [^ ]+ \\[(?P&lt;DT>[^\\]]+)\\]\",         \"%d\/%B\/%Y:%H:%M:%S %z\",     );      let mut requests: HashMap&lt;IpAddr, (RingBanBuffer, bool)> = HashMap::new();      let mut line_count = 0;     let start = std::time::Instant::now();     for line in reader.lines() {         line_count += 1;         if let Some(ParseResult { ip, timestamp }) = line.ok().and_then(|l| parser.parse_line(&amp;l) ) {             let entry = requests.entry(ip).or_insert((RingBanBuffer::new(30), false));             if let Some(delta) = entry.0.add_query(timestamp) {                 if delta &lt; 30 {                     entry.1 = true;                 }             };         }     }      let elapsed = start.elapsed();      let banned_ips: Vec&lt;&amp;IpAddr> = requests.iter()         .filter(|(_, (_, banned))| *banned)         .map(|(k, _)| k)         .collect();      for ip in banned_ips.iter() {         println!(\"{}\", ip);     }      eprintln!(         \"elapsed {} ms, {} lines parsed, {} lines\/s, banned = {}\/{}\",         (elapsed.as_micros() as f64 \/ 1e3),         line_count,         line_count as f64 \/ (elapsed.as_micros() as f64 \/ 1e6),         banned_ips.len(),         requests.len()     ); }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c&#8230;<\/p>\n<pre><code>elapsed 208.154 ms, 100000 lines parsed, 480413.5399752107 lines\/s, banned = 565\/3506<\/code><\/pre>\n<p>480 \u0442\u044b\u0441\u044f\u0447 \u0441\u0442\u0440\u043e\u043a \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443, \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432 38 \u0440\u0430\u0437, \u0432\u0430\u0443. \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u044d\u0442\u043e\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0443\u0436\u0435 \u043f\u0435\u0440\u0435\u043a\u0440\u044b\u0432\u0430\u0435\u0442, \u043d\u043e \u0442\u0443\u0442 \u043c\u043d\u0435 \u0441\u0442\u0430\u043b\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u0430 \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0435\u0449\u0451 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c.<\/p>\n<h2>\u0420\u0430\u0437\u0431\u043e\u0440 \u0437\u0430 \u043b\u0438\u043d\u0435\u0439\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f<\/h2>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438, \u0445\u043e\u0440\u043e\u0448\u043e \u0431\u044b \u0432\u044b\u044f\u0441\u043d\u0438\u0442\u044c, \u0430 \u0447\u0442\u043e \u0436\u0435, \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0433\u043e\u0432\u043e\u0440\u044f, \u0442\u043e\u0440\u043c\u043e\u0437\u0438\u0442. \u0414\u043b\u044f \u043f\u0440\u043e\u0444\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u044b\u043c \u043f\u0440\u043e\u0444\u0430\u0439\u043b\u0435\u0440\u043e\u043c <code>perf<\/code> (\u0443 \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c \u0446\u0435\u043b\u0430\u044f <a href=\"https:\/\/perf.wiki.kernel.org\/index.php\/Main_Page\" rel=\"noopener noreferrer nofollow\">wiki \u0441 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439<\/a>, \u0430 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435 \u0435\u0441\u0442\u044c <a href=\"https:\/\/habr.com\/ru\/company\/first\/blog\/442738\/\" rel=\"noopener noreferrer nofollow\">\u0432\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0432 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430\u0445<\/a>).<\/p>\n<pre><code>$ perf record target\/release\/fast2ban > \/dev\/null elapsed 206.889 ms, 100000 lines parsed, 483350.97564394434 lines\/s, banned = 565\/3506 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.031 MB perf.data (789 samples) ] $ perf report<\/code><\/pre>\n<p>\u0412\u0438\u0434\u0438\u043c \u0432\u043f\u043e\u043b\u043d\u0435 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u0443: \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0433\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u2014 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D1%81_%D0%B2%D0%BE%D0%B7%D0%B2%D1%80%D0%B0%D1%82%D0%BE%D0%BC\" rel=\"noopener noreferrer nofollow\">\u0431\u044d\u043a\u0442\u0440\u0435\u043a\u0438\u043d\u0433<\/a>. <\/p>\n<figure class=\"bordered full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/0d8\/447\/10a\/0d844710a271d317a4ad7080a999adf1.png\" alt=\"perf report \u0432 \u0446\u0432\u0435\u0442\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043b\u0443\u0447\u0448\u0435\" title=\"perf report \u0432 \u0446\u0432\u0435\u0442\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043b\u0443\u0447\u0448\u0435\" width=\"1222\" height=\"302\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0d8\/447\/10a\/0d844710a271d317a4ad7080a999adf1.png\"\/><figcaption>perf report \u0432 \u0446\u0432\u0435\u0442\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043b\u0443\u0447\u0448\u0435<\/figcaption><\/figure>\n<p>\u041a\u0430\u043a \u0436\u0435 \u0442\u0430\u043a \u2014 \u0434\u0443\u043c\u0430\u044e \u044f \u2014 \u0432\u0440\u043e\u0434\u0435 \u0436\u0435 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u044b \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u044b, \u0430 \u0437\u0434\u0435\u0441\u044c \u044d\u0442\u043e\u0433\u043e \u044f\u0432\u043d\u043e \u043d\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u043e\u0438\u0441\u043a\u043e\u0432 \u044f \u0432\u044b\u044f\u0441\u043d\u0438\u043b, \u0447\u0442\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0432 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u044b, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e: \u044d\u0442\u043e \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0443\u043c\u0435\u0435\u0442 \u0438 <a href=\"https:\/\/crates.io\/crates\/regex\" rel=\"noopener noreferrer nofollow\">\u043a\u0440\u0435\u0439\u0442 regex<\/a>. \u0415\u0441\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 <a href=\"https:\/\/crates.io\/crates\/regex-automata\" rel=\"noopener noreferrer nofollow\">\u043a\u0440\u0435\u0439\u0442 regex-automata<\/a>, \u043d\u043e \u0434\u043b\u044f \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 capturing groups, \u043e\u043d\u043e \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<p>\u041a\u0440\u043e\u043c\u0435 \u044d\u0442\u043e\u0433\u043e, \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0445 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u043e\u0432 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c Tagged DFA, \u0438 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0430 \u0435\u0433\u043e \u043e\u0441\u043d\u043e\u0432\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"http:\/\/re2c.org\/\" rel=\"noopener noreferrer nofollow\">RE2C<\/a> (\u043e\u043d\u043e \u0434\u0430\u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u0438 \u043d\u0430 Rust). \u0420\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0437\u0434\u0435\u0441\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u0447\u0442\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e\u0435 \u0437\u0434\u0435\u0441\u044c \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0438 \u0441\u0432\u043e\u0438\u043c\u0438 \u0440\u0443\u043a\u0430\u043c\u0438.<\/p>\n<p>\u0417\u0430\u043e\u0434\u043d\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u043c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 <code>decode_utf8<\/code> \u2014 nginx \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e <a href=\"https:\/\/nginx.org\/ru\/docs\/http\/ngx_http_log_module.html#log_format\" rel=\"noopener noreferrer nofollow\">\u043f\u0438\u0448\u0435\u0442 \u043b\u043e\u0433\u0438 \u0432 ASCII<\/a>. \u041b\u0438\u043d\u0435\u0439\u043d\u044b\u0439 \u0440\u0430\u0437\u0431\u043e\u0440 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438 \u043d\u0430 \u0441\u044b\u0440\u043e\u043c \u043c\u0430\u0441\u0441\u0438\u0432\u0435 \u0431\u0430\u0439\u0442\u043e\u0432, \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u044f \u0438\u0445 \u0432 \u0441\u0442\u0440\u043e\u043a\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e unsafe-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 <a href=\"https:\/\/doc.rust-lang.org\/stable\/std\/str\/fn.from_utf8_unchecked.html\" rel=\"noopener noreferrer nofollow\">from_utf8_unchecked<\/a>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e \u0444\u0430\u043a\u0442\u0443 <a href=\"https:\/\/doc.rust-lang.org\/stable\/src\/core\/str\/converts.rs.html#173\" rel=\"noopener noreferrer nofollow\">\u0434\u0435\u043b\u0430\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e<\/a>.<\/p>\n<p>\u0412\u0441\u0451 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0434\u043e \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u043f\u0440\u043e\u0431\u0435\u043b\u0430 \u0431\u0443\u0434\u0435\u043c \u0441\u0447\u0438\u0442\u0430\u0442\u044c IP-\u0430\u0434\u0440\u0435\u0441\u043e\u043c, \u043f\u043e\u0442\u043e\u043c \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u043c \u0442\u0440\u0438 \u0431\u0430\u0439\u0442\u0430, \u0437\u0430\u0442\u0435\u043c \u0434\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u043f\u0440\u043e\u0431\u0435\u043b\u0430, \u0437\u0430\u0442\u0435\u043c \u0434\u043e <code>[<\/code>, \u0430 \u0437\u0430\u0442\u0435\u043c \u0434\u043e <code>]<\/code>. \u041a\u043e\u0434 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u0438\u0441\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0432\u044b\u0441\u043e\u043a\u043e\u0443\u0440\u043e\u0432\u043d\u0435\u0432\u043e, \u043f\u043e\u043b\u044c\u0437\u0443\u044f\u0441\u044c \u0438\u0442\u0435\u0440\u0430\u0442\u043e\u0440\u0430\u043c\u0438: <a href=\"https:\/\/rust.godbolt.org\/z\/KMjPodcMo\" rel=\"noopener noreferrer nofollow\">\u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0438\u0445 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u0443\u0435\u0442.<\/a> \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u0431\u043e\u0440 \u00ab\u0432 \u043b\u043e\u0431\u00bb:<\/p>\n<details class=\"spoiler\">\n<summary>parse_line_automata<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use std::str::from_utf8_unchecked;  fn parse_line_automata(line: &amp;[u8], date_format: &amp;str) -> Option&lt;ParseResult> {     let mut iter = line.iter().enumerate();     let ip_end = iter.position(|(_, &amp;c)| c == b' ')?;      let ip_str = unsafe { from_utf8_unchecked(&amp;line[..ip_end]) };     let ip: IpAddr = ip_str.parse().ok()?;      let mut iter = iter         .skip(3)         .skip_while(|&amp;(_, &amp;c)| c != b' ')         .skip_while(|&amp;(_, &amp;c) | c != b'[');      let (date_start, _) = iter.next()?;     let date_end = iter.position(|(_, &amp;c)| c == b']')?;      let date = unsafe { from_utf8_unchecked(&amp;line[date_start+1..date_start+date_end+1]) };      let timestamp = DateTime::parse_from_str(date, date_format)         .ok()?         .timestamp();      Some(ParseResult { ip, timestamp }) }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0415\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0432 <code>main<\/code>: \u0441\u0442\u0440\u043e\u043a\u0438 \u043d\u0443\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>lines()<\/code>, \u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>split(b'\\n')<\/code>, \u0447\u0442\u043e\u0431\u044b \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u0431\u044b\u043b\u0438 \u043d\u0435 <code>String<\/code> , \u0430 <code>[u8]<\/code>.<\/p>\n<p>\u0423\u0432\u0435\u043b\u0438\u0447\u0438\u0432\u0430\u0435\u043c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b \u0434\u043e \u043e\u0434\u043d\u043e\u0433\u043e \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u0430 \u0441\u0442\u0440\u043e\u043a, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c&#8230;<\/p>\n<pre><code>elapsed 1269.688 ms, 1000000 lines parsed, 787595.0627240709 lines\/s, banned = 1375\/3506<\/code><\/pre>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0432\u044b\u0438\u0433\u0440\u044b\u0448 \u0447\u0443\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435, \u0447\u0435\u043c \u0432 \u043f\u043e\u043b\u0442\u043e\u0440\u0430 \u0440\u0430\u0437\u0430. \u0418\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u0447\u0442\u043e \u0442\u0430\u043c \u0432 \u043f\u0440\u043e\u0444\u0438\u043b\u0435?<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/4d6\/544\/283\/4d65442836a737a106558be46ec368b8.png\" alt=\"\u0422\u0435\u043f\u0435\u0440\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0440\u0430\u0437\u0431\u043e\u0440 \u0432\u0440\u0435\u043c\u0435\u043d\u0438\" title=\"\u0422\u0435\u043f\u0435\u0440\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0440\u0430\u0437\u0431\u043e\u0440 \u0432\u0440\u0435\u043c\u0435\u043d\u0438\" width=\"1212\" height=\"215\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/4d6\/544\/283\/4d65442836a737a106558be46ec368b8.png\"\/><figcaption>\u0422\u0435\u043f\u0435\u0440\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0440\u0430\u0437\u0431\u043e\u0440 \u0432\u0440\u0435\u043c\u0435\u043d\u0438<\/figcaption><\/figure>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0443\u043f\u0451\u0440\u043b\u0438\u0441\u044c \u0432 <code>strftime<\/code>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439, \u0432 \u043e\u0431\u0449\u0435\u043c-\u0442\u043e, \u043d\u0430\u043c \u043d\u0435 \u043d\u0443\u0436\u0435\u043d. \u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0431\u0430\u043d\u0438\u0442\u044c \u043d\u0430\u0440\u0443\u0448\u0438\u0442\u0435\u043b\u0435\u0439 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c <em>\u0434\u0430\u0442\u0443<\/em>, \u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0440\u0435\u043c\u044f. \u041f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u043a \u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u0440\u0430\u0437\u043d\u0438\u0446\u0430\u043c 86400, \u043d\u043e \u0438 \u0431\u0435\u0437 \u044d\u0442\u043e\u0433\u043e \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043f\u043e\u0442\u0435\u0440\u044f\u043d\u043d\u043e\u0439 \u043c\u0430\u043a\u0441\u0438\u043c\u0443\u043c \u043e\u0434\u043d\u0430 \u043c\u0438\u043d\u0443\u0442\u0430 \u0432\u043e\u043a\u0440\u0443\u0433 \u043f\u043e\u043b\u0443\u043d\u043e\u0447\u0438. <\/p>\n<p>\u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u043e\u0441\u043b\u0435 \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u043f\u0440\u043e\u0431\u0435\u043b\u0430 \u043f\u0440\u043e\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0441\u0438\u043c\u0432\u043e\u043b\u044b \u0430\u0436 \u0434\u043e <code>:<\/code>, \u0438 \u043d\u0435 \u043d\u0443\u0436\u043d\u043e \u0438\u0441\u043a\u0430\u0442\u044c \u0437\u0430\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0443\u044e \u0441\u043a\u043e\u0431\u043a\u0443, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0434\u043b\u0438\u043d\u0430 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432\u043e\u0441\u0435\u043c\u044c \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432.<\/p>\n<details class=\"spoiler\">\n<summary>\u0420\u0430\u0437\u0431\u043e\u0440 \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">fn parse_line_automata_time_only(line: &amp;[u8], time_format: &amp;str) -> Option&lt;ParseResult> {     let mut iter = line.iter().enumerate();     let ip_end = iter.position(|(_, &amp;c)| c == b' ')?;      let ip_str = unsafe { from_utf8_unchecked(&amp;line[..ip_end]) };     let ip: IpAddr = ip_str.parse().ok()?;      let mut iter = iter         .skip(3)         .skip_while(|&amp;(_, &amp;c)| c != b' ')         .skip_while(|&amp;(_, &amp;c)| c != b':');      let (date_start, _) = iter.next()?;      let time = unsafe { from_utf8_unchecked(&amp;line[date_start + 1..date_start + 9]) };      let timestamp = NaiveTime::parse_from_str(time, time_format)         .ok()?         .num_seconds_from_midnight() as i64;      Some(ParseResult { ip, timestamp }) }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0440\u0430\u0434\u0443\u044e\u0442:<\/p>\n<pre><code>elapsed 699.125 ms, 1000000 lines parsed, 1430359.3777936706 lines\/s, banned = 1375\/3506<\/code><\/pre>\n<p>\u0423\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435 \u0435\u0449\u0451 \u043f\u043e\u0447\u0442\u0438 \u0432\u0434\u0432\u043e\u0435, \u043d\u043e \u0440\u0430\u0437\u0431\u043e\u0440 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432\u0441\u0451 \u0435\u0449\u0451 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u043f\u043e\u0447\u0442\u0438 20% \u0432\u0440\u0435\u043c\u0435\u043d\u0438:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/04c\/467\/d07\/04c467d0717e1dd1eb367c791e17946f.png\" alt=\"NB: \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0432\u044b\u0437\u043e\u0432\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0438\u0437 chrono:: \u043d\u0443\u0436\u043d\u043e \u0441\u0443\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c\" title=\"NB: \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0432\u044b\u0437\u043e\u0432\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0438\u0437 chrono:: \u043d\u0443\u0436\u043d\u043e \u0441\u0443\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c\" width=\"1010\" height=\"203\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/04c\/467\/d07\/04c467d0717e1dd1eb367c791e17946f.png\"\/><figcaption>NB: \u0432\u0440\u0435\u043c\u044f \u043d\u0430 \u0432\u044b\u0437\u043e\u0432\u044b \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0438\u0437 chrono:: \u043d\u0443\u0436\u043d\u043e \u0441\u0443\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c<\/figcaption><\/figure>\n<h2>\u0420\u0430\u0437\u0431\u043e\u0440 \u0438 \u043f\u0430\u0440\u0441\u0438\u043d\u0433 \u0437\u0430 \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0445\u043e\u0434<\/h2>\n<p>\u0415\u0441\u043b\u0438 \u0432\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0443\u043c\u0430\u0442\u044c \u043d\u0430\u0434 \u0442\u0435\u043c, \u0447\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0435, \u0442\u043e \u043e\u043a\u0430\u0436\u0435\u0442\u0441\u044f, \u0447\u0442\u043e \u043f\u0440\u0438 \u0440\u0430\u0437\u0431\u043e\u0440\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0447\u0430\u0441\u0442\u044c \u0441 IP-\u0430\u0434\u0440\u0435\u0441\u043e\u043c \u0441\u0442\u0440\u043e\u043a\u0438 \u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u0434\u0432\u0430\u0436\u0434\u044b: \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u0438 \u043f\u043e\u0438\u0441\u043a\u0435 \u0435\u0433\u043e \u043a\u043e\u043d\u0446\u0430, \u0430 \u0437\u0430\u0442\u0435\u043c \u2014 \u0435\u0449\u0451 \u0440\u0430\u0437 \u2014 \u043f\u0440\u0438 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0435 \u0432 <code>IpAddr<\/code>. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u0442\u0440\u043e\u043a\u0438 \u0443\u0436\u0435 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u043b\u043e\u0442\u043d\u043e \u043f\u0440\u0438\u0431\u0438\u0442 \u043a \u0444\u0443\u043d\u043a\u0446\u0438\u0438 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430, \u043f\u043e\u0447\u0435\u043c\u0443 \u0431\u044b \u043d\u0435 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u0430\u0434\u0440\u0435\u0441 \u0438 \u0432\u0440\u0435\u043c\u044f \u0441\u0440\u0430\u0437\u0443 \u043f\u043e \u043c\u0435\u0440\u0435 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0430 \u0441\u0442\u0440\u043e\u043a\u0438?<\/p>\n<details class=\"spoiler\">\n<summary>\u0421\u043a\u0443\u0447\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">fn parse_line_v2(line: &amp;[u8]) -> Option&lt;ParseResult> {     let mut ip = 0u32;     let mut cur_grp = 0u32;     let mut timestamp = 0i64;     let mut cur_time = 0i64;      let mut iter = line.iter();     for c in iter.by_ref() {         if *c == b'.' {             ip = ip * 256 + cur_grp;             cur_grp = 0;             continue;         }         if *c == b' ' {             break;         }         cur_grp = cur_grp * 10 + (*c - b'0') as u32;     }     ip = ip * 256 + cur_grp;      let iter = iter.skip(3).skip_while(|c| **c != b' ').skip_while(|c| **c != b':');     for c in iter {         if *c == b':' {             timestamp = timestamp * 60 + cur_time;             cur_time = 0;             continue;         }         if *c == b' ' {             break;         }         cur_time = cur_time * 10 + (*c - b'0') as i64;     }     timestamp = timestamp * 60 + cur_time;     let ip: IpAddr = IpAddr::V4(Ipv4Addr::from(ip));     Some(ParseResult { ip, timestamp }) } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041a\u043e\u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u043e\u0441\u044c, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u043f\u043e\u0431\u043e\u043b\u044c\u0448\u0435, \u043d\u043e \u0447\u0442\u043e \u043d\u0430\u0441\u0447\u0451\u0442 \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e\u0441\u0442\u0438?<\/p>\n<pre><code>elapsed 552.038 ms, 1000000 lines parsed, 1811469.5002880236 lines\/s, banned = 1375\/3506<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/931\/5a2\/ff2\/9315a2ff23a098a0960dd832869825a0.png\" alt=\"\u0412\u0441\u0451 \u0431\u043e\u043b\u044c\u0448\u0435 libc \u0432 \u0432\u0435\u0440\u0445\u043d\u0438\u0445 \u0441\u0442\u0440\u043e\u0447\u043a\u0430\u0445 \u043f\u0440\u043e\u0444\u0438\u043b\u044f\" title=\"\u0412\u0441\u0451 \u0431\u043e\u043b\u044c\u0448\u0435 libc \u0432 \u0432\u0435\u0440\u0445\u043d\u0438\u0445 \u0441\u0442\u0440\u043e\u0447\u043a\u0430\u0445 \u043f\u0440\u043e\u0444\u0438\u043b\u044f\" width=\"734\" height=\"182\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/931\/5a2\/ff2\/9315a2ff23a098a0960dd832869825a0.png\"\/><figcaption>\u0412\u0441\u0451 \u0431\u043e\u043b\u044c\u0448\u0435 libc \u0432 \u0432\u0435\u0440\u0445\u043d\u0438\u0445 \u0441\u0442\u0440\u043e\u0447\u043a\u0430\u0445 \u043f\u0440\u043e\u0444\u0438\u043b\u044f<\/figcaption><\/figure>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0435\u0449\u0451 \u043d\u0430 \u0447\u0435\u0442\u0432\u0435\u0440\u0442\u044c \u0431\u044b\u0441\u0442\u0440\u0435\u0435. \u0412 \u043f\u0440\u043e\u0444\u0438\u043b\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442 \u0437\u0430\u043c\u0435\u0442\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c \u0444\u0443\u043d\u043a\u0446\u0438\u044f <code>__memcpy_ssse3_back<\/code> \u0438\u0437 <code>libc<\/code>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u0447\u0442\u0435\u043d\u0438\u0438 \u0444\u0430\u0439\u043b\u0430, \u0438&#8230; \u043f\u043e\u0434\u043e\u0436\u0434\u0438\u0442\u0435, \u043c\u044b \u0436\u0435 \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c SIMD \u0434\u043b\u044f \u0440\u0430\u0437\u0431\u043e\u0440\u0430!<\/p>\n<h2>\u0420\u0430\u0437\u0431\u043e\u0440 IP \u0438 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0438\u0437 \u0441\u0442\u0440\u043e\u043a\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e SIMD<\/h2>\n<p>\u0420\u0435\u0448\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e, \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043e \u043d\u0430 <a href=\"https:\/\/stackoverflow.com\/a\/31683632\" rel=\"noopener noreferrer nofollow\">\u043e\u0442\u0432\u0435\u0442\u0435 \u043d\u0430 StackOverflow<\/a>, \u0438, \u0435\u0441\u043b\u0438 \u0432\u0435\u0440\u0438\u0442\u044c \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u044e \u043d\u0438\u043a\u043d\u0435\u0439\u043c\u043e\u0432, \u043f\u0440\u0438\u043d\u0430\u0434\u043b\u0435\u0436\u0438\u0442 <a class=\"mention\" href=\"\/users\/stgatilov\">@stgatilov<\/a>. \u041e\u043d\u043e \u043e\u0441\u043d\u043e\u0432\u0430\u043d\u043e \u043d\u0430 \u0442\u043e\u043c, \u0447\u0442\u043e IP-\u0430\u0434\u0440\u0435\u0441 \u0432 \u0432\u0438\u0434\u0435 \u0441\u0442\u0440\u043e\u043a\u0438 \u0446\u0435\u043b\u0438\u043a\u043e\u043c \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u043e\u043c\u0435\u0449\u0430\u0435\u0442\u0441\u044f \u0432 128-\u0431\u0438\u0442\u043d\u044b\u0439 \u0440\u0435\u0433\u0438\u0441\u0442\u0440, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043b\u0435\u0437\u0430\u0435\u0442 16 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432, \u0430 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043b\u0438\u043d\u0430 IP-\u0430\u0434\u0440\u0435\u0441\u0430 \u2014 15 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432 (12 \u0446\u0438\u0444\u0440 \u0438 3 \u0442\u043e\u0447\u043a\u0438).<\/p>\n<p>\u0410\u0432\u0442\u043e\u0440 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e\u0431\u044a\u044f\u0441\u043d\u0438\u043b \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u044d\u0442\u043e\u0433\u043e \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c\u0430, \u044f \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0443 \u0435\u0433\u043e \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0441\u043e\u043a\u0440\u0430\u0449\u0435\u043d\u0438\u044f\u043c\u0438:<\/p>\n<blockquote>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043c\u044b \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0435\u043c 16 \u0431\u0430\u0439\u0442 \u0441 \u043d\u0435\u0432\u044b\u0440\u043e\u0432\u043d\u0435\u043d\u043d\u043e\u0433\u043e \u0430\u0434\u0440\u0435\u0441\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 lddqu. &lt;&#8230;> \u041f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432\u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0431\u0430\u0439\u0442\u043e\u0432 \u043f\u043e\u0441\u043b\u0435 \u043e\u043a\u043e\u043d\u0447\u0430\u043d\u0438\u044f \u0430\u0434\u0440\u0435\u0441\u0430. \u0412 \u043b\u044e\u0431\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0432\u0430\u043c \u043b\u0443\u0447\u0448\u0435 \u0443\u0431\u0435\u0434\u0438\u0442\u044c\u0441\u044f, \u0447\u0442\u043e \u043a\u0430\u0436\u0434\u044b\u0439 IP-\u0430\u0434\u0440\u0435\u0441 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u043d\u0435 \u043c\u0435\u043d\u0435\u0435 16 \u0431\u0430\u0439\u0442 \u043f\u0430\u043c\u044f\u0442\u0438.<\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u043c\u044b \u0432\u044b\u0447\u0438\u0442\u0430\u0435\u043c <code>'0'<\/code> \u0438\u0437 \u0432\u0441\u0435\u0445 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e <code>'.'<\/code> \u043f\u0440\u0435\u0432\u0440\u0430\u0449\u0430\u0435\u0442\u0441\u044f \u0432 <code>-2<\/code>, \u0430 \u0432\u0441\u0435 \u0446\u0438\u0444\u0440\u044b \u043e\u0441\u0442\u0430\u044e\u0442\u0441\u044f \u043d\u0435\u043e\u0442\u0440\u0438\u0446\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u043c\u0438. \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u044b \u0432\u044b\u0447\u0438\u0441\u043b\u044f\u0435\u043c \u0431\u0438\u0442\u043e\u0432\u0443\u044e \u043c\u0430\u0441\u043a\u0443 \u0437\u043d\u0430\u043a\u043e\u0432 \u0432\u0441\u0435\u0445 \u0431\u0430\u0439\u0442\u043e\u0432 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>_mm_movemask_epi8<\/code>.<\/p>\n<p>\u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u043c\u0430\u0441\u043a\u0438 \u043c\u044b \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u043d\u0435\u0442\u0440\u0438\u0432\u0438\u0430\u043b\u044c\u043d\u0443\u044e 16-\u0431\u0430\u0439\u0442\u043e\u0432\u0443\u044e \u043c\u0430\u0441\u043a\u0443 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b <code>shuffleTable<\/code>. \u0422\u0430\u0431\u043b\u0438\u0446\u0430 \u0432\u0435\u0441\u0438\u0442 \u0446\u0435\u043b\u044b\u0439 \u043c\u0435\u0433\u0430\u0431\u0430\u0439\u0442, \u0438 \u0434\u043b\u044f \u043f\u0440\u0435\u0434\u0432\u0430\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u044b\u0447\u0438\u0441\u043b\u0435\u043d\u0438\u044f \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043c\u043d\u043e\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 &lt;&#8230;>.<\/p>\n<p>\u0418\u043d\u0442\u0440\u0438\u043d\u0441\u0438\u043a <code>_mm_shuffle_epi8<\/code> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u0438\u0437\u043c\u0435\u043d\u044f\u0442\u044c \u043f\u043e\u0440\u044f\u0434\u043e\u043a \u0431\u0430\u0439\u0442\u043e\u0432 \u0432 XMM-\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0430\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438. \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440 XMM \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0447\u0435\u0442\u044b\u0440\u0435 4-\u0431\u0430\u0439\u0442\u043e\u0432\u044b\u0445 \u0431\u043b\u043e\u043a\u0430, \u043a\u0430\u0436\u0434\u044b\u0439 \u0431\u043b\u043e\u043a \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0446\u0438\u0444\u0440\u044b (\u0432 little-endian). \u041c\u044b \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u0435\u043c \u043a\u0430\u0436\u0434\u044b\u0439 \u0431\u043b\u043e\u043a \u0432 16-\u0431\u0438\u0442\u043d\u043e\u0435 \u0447\u0438\u0441\u043b\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>_mm_maddubs_epi16<\/code>, \u0437\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u0441\u043b\u0435\u0434\u0443\u0435\u0442 <code>_mm_hadd_epi16<\/code>. \u0417\u0430\u0442\u0435\u043c \u043c\u044b \u043f\u0435\u0440\u0435\u0443\u043f\u043e\u0440\u044f\u0434\u043e\u0447\u0438\u0432\u0430\u0435\u043c \u0431\u0430\u0439\u0442\u044b \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u0432\u0435\u0441\u044c IP-\u0430\u0434\u0440\u0435\u0441 \u0437\u0430\u043d\u0438\u043c\u0430\u043b \u043d\u0438\u0436\u043d\u0438\u0435 4 \u0431\u0430\u0439\u0442\u0430.<\/p>\n<p>\u041d\u0430\u043a\u043e\u043d\u0435\u0446, \u043c\u044b \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u043c\u043b\u0430\u0434\u0448\u0438\u0435 4 \u0431\u0430\u0439\u0442\u0430 \u0438\u0437 XMM-\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>_mm_extract_epi32<\/code>. \u0415\u0441\u043b\u0438 \u0443 \u0432\u0430\u0441 \u0435\u0433\u043e \u043d\u0435\u0442, \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f<code>_mm_extract_epi16<\/code>, \u043d\u043e \u044d\u0442\u043e \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435.<\/p>\n<\/blockquote>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0440\u0430\u0437\u0431\u043e\u0440\u0430 IP<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use std::arch::x86_64::*;  fn parse_ip_simd(addr: &amp;[u8]) -> IpAddr {     let result: u32;     unsafe {         let input = _mm_lddqu_si128(addr.as_ptr() as *const __m128i);          let input = _mm_sub_epi8(input, _mm_set1_epi8(b'0' as i8));         let cmp = input;         let mask = _mm_movemask_epi8(cmp);          let shuf = SHUFFLE_TABLE[mask as usize];         let arr = _mm_shuffle_epi8(input, shuf);          let coeffs = _mm_set_epi8(0, 100, 10, 1, 0, 100, 10, 1, 0, 100, 10, 1, 0, 100, 10, 1);         let prod = _mm_maddubs_epi16(coeffs, arr);         let prod = _mm_hadd_epi16(prod, prod);          let imm = _mm_set_epi8(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 6, 4, 2, 0);         let prod = _mm_shuffle_epi8(prod, imm);         result = transmute(_mm_extract_epi32::&lt;0>(prod))     }     IpAddr::V4(Ipv4Addr::from(result)) }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u0434\u043b\u044f \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u043a\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u043e\u0432\u043e\u043a<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">fn init_shuffle_table() {     for len0 in 1..4 {         for len1 in 1..4 {             for len2 in 1..4 {                 for len3 in 1..4 {                     let slen = len0 + len1 + len2 + len3 + 4;                     let lens = [&amp;len0, &amp;len1, &amp;len2, &amp;len3];                     let rem = 16 - slen;                     for rmask in 0..(1 &lt;&lt; rem) {                         let mut mask = 0;                         let mut shuf: [i8; 16] = [-1; 16];                         let mut pos = 0;                         for i in 0..4 {                             for j in 0..*lens[i] {                                 shuf[((3 - i) * 4 + (lens[i] - 1 - j))] = pos;                                 pos += 1;                             }                             mask ^= (1) &lt;&lt; pos;                             pos += 1;                         }                         mask ^= rmask &lt;&lt; slen;                         unsafe {                             _mm_store_si128(                                 &amp;mut SHUFFLE_TABLE[mask],                                 _mm_loadu_si128(&amp;shuf as *const i8 as *const __m128i),                             );                         }                     }                 }             }         }     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0410\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u0438 \u0432\u0440\u0435\u043c\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e SIMD-\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0439. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0449\u0435, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043c\u0438\u043d\u0443\u0442\u044b, \u0441\u0435\u043a\u0443\u043d\u0434\u044b \u0438 \u0447\u0430\u0441\u044b \u0432\u0441\u0435\u0433\u0434\u0430 \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0442 \u0440\u043e\u0432\u043d\u043e \u043f\u043e \u0434\u0432\u0430 \u0441\u0438\u043c\u0432\u043e\u043b\u0430, \u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u0441 \u043c\u0430\u0441\u043a\u0430\u043c\u0438 \u043f\u0435\u0440\u0435\u0441\u0442\u0430\u043d\u043e\u0432\u043e\u043a \u0437\u0434\u0435\u0441\u044c \u043d\u0435 \u043d\u0443\u0436\u043d\u0430.<\/p>\n<p>\u0421\u0435\u043a\u0443\u043d\u0434\u044b \u0438 \u043c\u0438\u043d\u0443\u0442\u044b \u0440\u0430\u0441\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0442\u0441\u044f \u0432 \u043f\u0435\u0440\u0432\u044b\u0445 \u0434\u0432\u0443\u0445 16-\u0431\u0438\u0442\u043d\u044b\u0445 \u0441\u043b\u043e\u0432\u0430\u0445 (\u0438 \u0443\u043c\u043d\u043e\u0436\u0430\u044e\u0442\u0441\u044f \u043d\u0430 1 \u0438 60, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e), \u0430 \u0447\u0430\u0441\u044b \u2014 \u0432 \u043f\u044f\u0442\u043e\u043c (\u0438 \u0443\u043c\u043d\u043e\u0436\u0430\u044e\u0442\u0441\u044f \u043d\u0430 3600, \u0442. \u0435. 14*256+16). \u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0443\u043c\u043d\u043e\u0436\u0435\u043d\u0438\u0435 \u0441 \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u044b\u043c \u0441\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u0438 \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u0435\u043c \u0434\u0432\u0430 \u0434\u0432\u043e\u0439\u043d\u044b\u0445 \u0441\u043b\u043e\u0432\u0430 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u0441\u043b\u043e\u0436\u0438\u0442\u044c.<\/p>\n<details class=\"spoiler\">\n<summary>\u0420\u0430\u0437\u0431\u043e\u0440 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e SIMD<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">fn parse_time_simd(x: &amp;[u8]) -> u32 {     unsafe {         let input = _mm_loadu_si64(x.as_ptr() as *const _);         let input = _mm_sub_epi8(input, _mm_set1_epi8(b'0' as i8));         let input = _mm_shuffle_epi8(             input,             _mm_set_epi8(7, 6, 4, 3, -1, -1, -1, -1, 1, 0, -1, -1, -1, -1, -1, -1),         );         let coeffs = _mm_set_epi8(1, 10, 1, 10, 1, 10, 0, 0, 1, 10, 0, 0, 0, 0, 0, 0);         let prod = _mm_maddubs_epi16(coeffs, input);         let prod2 = _mm_madd_epi16(             prod,             _mm_set_epi8(0, 1, 0, 60, 0, 0, 0, 0, 14, 16, 0, 0, 0, 0, 0, 0),         );         let ms: u32 = std::mem::transmute(_mm_extract_epi32::&lt;1>(prod2));         let h: u32 = std::mem::transmute(_mm_extract_epi32::&lt;3>(prod2));         ms + h     } }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0430\u043e\u0434\u043d\u043e \u0434\u043b\u044f \u043f\u043e\u0438\u0441\u043a\u0430 \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u0435\u0439 \u0432 \u0441\u0442\u0440\u043e\u043a\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>memchr<\/code>, \u043d\u043e \u043d\u0435 \u0438\u0437 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438, \u0430 \u0438\u0437 <a href=\"https:\/\/crates.io\/crates\/memchr\" rel=\"noopener noreferrer nofollow\">\u043a\u0440\u0435\u0439\u0442\u0430 memchr<\/a> \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438\u043c\u0435\u0435\u0442 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440\u043e\u0432 \u0432\u0435\u0440\u0441\u0438\u0438. \u0417\u0430\u043e\u0434\u043d\u043e \u0438 \u043a\u043e\u0434 \u0441\u0442\u0430\u043b \u043a\u043e\u0440\u043e\u0447\u0435:<\/p>\n<details class=\"spoiler\">\n<summary>parse_line_simd \u0441 memchr<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">fn parse_line_simd(line: &amp;[u8]) -> Option&lt;ParseResult> {     let ip = parse_ip_simd(&amp;line[..16]);      let first_space = memchr(b' ', &amp;line[7..])? + 7;     let second_space = memchr(b' ', &amp;line[(first_space + 3)..])? + first_space + 3;     let time_begin = memchr(b':', &amp;line[second_space..])? + second_space + 1;     let timestamp = parse_time_simd(&amp;line[time_begin..time_begin + 8]) as i64;      Some(ParseResult { ip, timestamp }) }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u043d\u0435\u043f\u043b\u043e\u0445\u043e, \u0434\u043e\u0431\u0430\u0432\u0438\u043b\u043e\u0441\u044c \u0435\u0449\u0451 ~10%:<\/p>\n<pre><code>elapsed 471.925 ms, 1000000 lines parsed, 2118980.77024951 lines\/s, banned = 1375\/3506<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ee0\/fa7\/556\/ee0fa7556901265cd2c412543270e0f7.png\" alt=\"\u041f\u0440\u043e\u0444\u0438\u043b\u044c \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u0438 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439\" title=\"\u041f\u0440\u043e\u0444\u0438\u043b\u044c \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u0438 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439\" width=\"679\" height=\"151\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ee0\/fa7\/556\/ee0fa7556901265cd2c412543270e0f7.png\"\/><figcaption>\u041f\u0440\u043e\u0444\u0438\u043b\u044c \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a \u0436\u0435, \u043a\u0430\u043a \u0438 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0439<\/figcaption><\/figure>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043f\u0430\u043c\u044f\u0442\u0438 \u043f\u0440\u0438 \u0447\u0442\u0435\u043d\u0438\u0438 \u0444\u0430\u0439\u043b\u0430 (<code>__memcpy_ssse3_back<\/code> ), \u0438 \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>mmap<\/code>. \u0414\u0430, \u044d\u0442\u043e \u043d\u0430\u043a\u043b\u0430\u0434\u044b\u0432\u0430\u0435\u0442 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f, \u043d\u043e \u0432 \u043f\u043e\u0433\u043e\u043d\u0435 \u0437\u0430 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c\u044e \u0441\u043b\u043e\u0436\u043d\u043e \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f. \u0418\u0442\u0430\u043a, \u0431\u0435\u0440\u0451\u043c <a href=\"https:\/\/crates.io\/crates\/memmap\" rel=\"noopener noreferrer nofollow\">\u043a\u0440\u0435\u0439\u0442 memmap<\/a> \u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u043a\u043e\u0434 \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430, \u0447\u0442\u043e\u0431\u044b \u043e\u043d \u0437\u0430\u043e\u0434\u043d\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u043b, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0431\u0430\u0439\u0442 \u043e\u043d \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043b:<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u0430\u0440\u0441\u0438\u043d\u0433, \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u044e\u0449\u0438\u0439 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u043d\u044b\u0445 \u0441\u0438\u043c\u0432\u043e\u043b\u043e\u0432<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">fn parse_line_simd(line: &amp;[u8]) -> Option&lt;(ParseResult, usize)> {     let ip = parse_ip_simd(&amp;line[..16]);      let first_space = memchr(b' ', &amp;line[7..])? + 7;     let second_space = memchr(b' ', &amp;line[(first_space + 3)..])? + first_space + 3;     let time_begin = memchr(b':', &amp;line[second_space..])? + second_space + 1;     let timestamp = parse_time_simd(&amp;line[time_begin..time_begin + 8]) as i64;      Some((ParseResult { ip, timestamp }, time_begin + 8)) }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412 \u0433\u043b\u0430\u0432\u043d\u043e\u043c \u0446\u0438\u043a\u043b\u0435, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043a\u0430\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0441\u0438\u043c\u0432\u043e\u043b \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0430 \u0441\u0442\u0440\u043e\u043a\u0438 \u0441 \u0443\u0447\u0451\u0442\u043e\u043c \u044d\u0442\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044f, \u0447\u0442\u043e \u0434\u043e \u043a\u043e\u043d\u0446\u0430 \u0444\u0430\u0439\u043b\u0430 \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0431\u043e\u043b\u044c\u0448\u0435 16 \u0431\u0430\u0439\u0442 (\u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0435\u0442 \u0440\u0430\u0437\u0431\u043e\u0440 IP).<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u0435 \u0444\u0440\u0430\u0433\u043c\u0435\u043d\u0442\u044b main<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">fn main() {          \/\/ ....      let reader = unsafe { MmapOptions::new().map(&amp;File::open(\"nginx.log\").unwrap()).unwrap() };     let mut start_pos = 0;     let mut remains = reader.len();     loop {         let line = &amp;reader[start_pos..start_pos + min(remains, 512)];         if let Some((ParseResult { ip, timestamp }, shift)) = parse_line_simd(line) {             start_pos += shift;             remains -= shift;             let entry = requests                 .entry(ip)                 .or_insert((RingBanBuffer::new(30), false));             if let Some(delta) = entry.0.add_query(timestamp) {                 if delta &lt; 30 {                     entry.1 = true;                 }             };         }         let next_line = memchr(b'\\n', &amp;reader[start_pos..]);         if next_line.is_none() {             break;         }         let shift = next_line.unwrap() + 1;         start_pos += shift;         remains -= shift;         line_count += 1;          if remains &lt; 16 {             break;         }     }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0412\u044b\u0438\u0433\u0440\u044b\u0448 \u043e\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f mmap \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u043d\u0435\u0437\u0430\u043c\u0435\u0442\u0435\u043d \u0432 \u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0435\u0441\u043b\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u0447\u0438\u0442\u0430\u044e\u0442\u0441\u044f \u0441 \u0434\u0438\u0441\u043a\u0430 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0431\u044b\u0441\u0442\u0440\u043e: \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u0430\u043c\u044f\u0442\u0438 \u043d\u0435 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0443\u0437\u043a\u0438\u043c \u043c\u0435\u0441\u0442\u043e\u043c. \u0424\u0430\u0439\u043b \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043c\u0438\u043b\u043b\u0438\u043e\u043d \u0441\u0442\u0440\u043e\u043a \u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 260 \u043c\u0435\u0433\u0430\u0431\u0430\u0439\u0442, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043d\u0430 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438 \u043f\u043e\u0440\u044f\u0434\u043a\u0430 1500 \u043c\u0431\/\u0441 \u0447\u0442\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 \u0437\u0430\u0439\u043c\u0451\u0442 \u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u043e 175 \u043c\u0441. \u041d\u043e \u0435\u0441\u043b\u0438 \u0444\u0430\u0439\u043b \u0443\u0436\u0435 \u043b\u0435\u0436\u0438\u0442 \u0432 \u0444\u0430\u0439\u043b\u043e\u0432\u043e\u043c \u043a\u0435\u0448\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b, \u0442\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 mmap \u0434\u0430\u0451\u0442 \u0437\u0430\u043c\u0435\u0442\u043d\u044b\u0439 \u0432\u044b\u0438\u0433\u0440\u044b\u0448:<\/p>\n<pre><code>elapsed 373.291 ms, 1000000 lines parsed, 2678875.1938835923 lines\/s, banned = 1375\/3506<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/6a7\/d1f\/00b\/6a7d1f00b5d600d22c09f53c83720b6b.png\" alt=\"\u0412 \u044d\u0442\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0442\u0440\u0435\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u043f\u043e\u0438\u0441\u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044f \u0432 \u0444\u0430\u0439\u043b\u0435\" title=\"\u0412 \u044d\u0442\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0442\u0440\u0435\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u043f\u043e\u0438\u0441\u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044f \u0432 \u0444\u0430\u0439\u043b\u0435\" width=\"738\" height=\"142\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/6a7\/d1f\/00b\/6a7d1f00b5d600d22c09f53c83720b6b.png\"\/><figcaption>\u0412 \u044d\u0442\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0442\u0440\u0435\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u043f\u043e\u0438\u0441\u043a \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0442\u0435\u043b\u044f \u0432 \u0444\u0430\u0439\u043b\u0435<\/figcaption><\/figure>\n<p>\u0427\u0442\u043e\u0431\u044b \u0443\u0432\u0438\u0434\u0435\u0442\u044c, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u0430 \u0441\u0430\u043c\u043e\u043c \u0434\u0435\u043b\u0435 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0447\u0442\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430, \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c <code>perf<\/code> \u043e\u0442 \u0440\u0443\u0442\u0430 \u0441 \u043a\u043b\u044e\u0447\u043e\u043c <code>-a<\/code>:<\/p>\n<pre><code># perf record -a target\/release\/fast2ban > \/dev\/null elapsed 370.284 ms, 1000000 lines parsed, 2700629.786866297 lines\/s, banned = 1375\/3506 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.786 MB perf.data (2473 samples) ] # perf report<\/code><\/pre>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c5f\/7bf\/a1a\/c5f7bfa1a9029c24be75428d4b23c684.png\" width=\"902\" height=\"181\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c5f\/7bf\/a1a\/c5f7bfa1a9029c24be75428d4b23c684.png\"\/><figcaption><\/figcaption><\/figure>\n<h2>\u041d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u043c\u0435\u0440\u044b \u0438 \u0438\u0442\u043e\u0433\u0438<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u0430\u043c\u0435\u0440\u044b \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u0438. \u041c\u0435\u0442\u043e\u0434\u043e\u043b\u043e\u0433\u0438\u044f \u0431\u0443\u0434\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f: \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u043a\u0430\u0436\u0434\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 100 \u0440\u0430\u0437, \u043e\u0442\u0431\u0440\u0430\u0441\u044b\u0432\u0430\u0435\u043c 10% \u0441\u0430\u043c\u044b\u0445 \u0431\u044b\u0441\u0442\u0440\u044b\u0445 \u0438 10% \u0441\u0430\u043c\u044b\u0445 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u044b\u0445 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u043e\u0432, \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0435 \u0443\u0441\u0440\u0435\u0434\u043d\u044f\u0435\u043c \u043f\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0443 \u0438 \u0441\u0447\u0438\u0442\u0430\u0435\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0435 \u043e\u0442\u043a\u043b\u043e\u043d\u0435\u043d\u0438\u0435. <\/p>\n<details class=\"spoiler\">\n<summary>lscpu \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u043a\u0438 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u043e\u0432<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>Architecture:          x86_64 CPU op-mode(s):        32-bit, 64-bit Byte Order:            Little Endian CPU(s):                2 On-line CPU(s) list:   0,1 Thread(s) per core:    1 Core(s) per socket:    2 Socket(s):             1 NUMA node(s):          1 Vendor ID:             GenuineIntel CPU family:            6 Model:                 85 Model name:            Intel Xeon Processor (Skylake, IBRS) Stepping:              4 CPU MHz:               2294.608 BogoMIPS:              4589.21 Hypervisor vendor:     KVM Virtualization type:   full L1d cache:             32K L1i cache:             32K L2 cache:              4096K L3 cache:              16384K NUMA node0 CPU(s):     0,1 Flags:                 fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology eagerfpu pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single ssbd ibrs ibpb fsgsbase bmi1 hle avx2 smep bmi2 erms invpcid rtm mpx avx512f avx512dq rdseed adx smap clwb avx512cd avx512bw avx512vl xsaveopt xsavec xgetbv1 arat md_clear spec_ctrl<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u0440\u0430\u0432\u0434\u0430, <code>fail2ban-regex<\/code>  \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u044b\u0439 \u0438 \u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u043b \u0435\u0433\u043e \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e 10 \u0440\u0430\u0437. \u041a\u0440\u043e\u043c\u0435 \u0442\u043e\u0433\u043e, \u043a\u043e\u0434 \u043d\u0430 Rust \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u043b \u043f\u043e \u043e\u0434\u043d\u043e\u043c\u0443 \u043c\u0438\u043b\u043b\u0438\u043e\u043d\u0443 \u0441\u0442\u0440\u043e\u043a, \u0430 <code>fail2ban-regex<\/code> \u2014 \u043f\u043e 100 \u0442\u044b\u0441\u044f\u0447. \u0421\u0430\u043c <code>fail2ban<\/code> \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u0437\u0430\u043c\u0435\u0440\u0435\u043d\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f \u0441 \u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c\u044e \u0434\u043e 10\u043c\u0441, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u044b \u0434\u043b\u044f <code>fail2ban<\/code> \u043e\u043a\u0440\u0443\u0433\u043b\u0435\u043d\u044b \u0434\u043e 100 \u043d\u0441.<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td data-colwidth=\"179\" width=\"179\">\n<p align=\"left\"><strong>\u0412\u0430\u0440\u0438\u0430\u043d\u0442<\/strong><\/p>\n<\/td>\n<td data-colwidth=\"137\" width=\"137\">\n<p align=\"left\"><strong>ns\/line<\/strong><\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"left\"><strong>lines\/s<\/strong><\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"left\"><strong>\u0423\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"left\"><strong>\u041e\u0442\u043d\u043e\u0441\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e<\/strong><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"179\" width=\"179\">\n<p align=\"left\">fail2ban \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0439<\/p>\n<\/td>\n<td data-colwidth=\"137\" width=\"137\">\n<p align=\"left\">488 600 \u00b1 9 500<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"right\">2 047<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"left\">\n<\/td>\n<td>\n<p align=\"left\">\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"179\" width=\"179\">\n<p align=\"left\">fail2ban \u0441 \u0434\u0430\u0442\u043e\u0439<\/p>\n<\/td>\n<td data-colwidth=\"137\" width=\"137\">\n<p align=\"left\">79 900 \u00b1 2 800<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"right\">12 514<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"right\">6,11x<\/p>\n<\/td>\n<td>\n<p align=\"right\">6,11x<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"179\" width=\"179\">\n<p align=\"left\">\u041d\u0430\u0438\u0432\u043d\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f<\/p>\n<\/td>\n<td data-colwidth=\"137\" width=\"137\">\n<p align=\"left\">2 337,55 \u00b1 96,66<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"right\">427 799<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"right\">209,04x<\/p>\n<\/td>\n<td>\n<p align=\"right\">34,19x<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"179\" width=\"179\">\n<p align=\"left\">\u0411\u0435\u0437 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439<\/p>\n<\/td>\n<td data-colwidth=\"137\" width=\"137\">\n<p align=\"left\">1 143,58 \u00b1 73,79<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"right\">874 448<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"right\">427,29x<\/p>\n<\/td>\n<td>\n<p align=\"right\">2,04x<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"179\" width=\"179\">\n<p align=\"left\">\u0420\u0430\u0437\u0431\u043e\u0440 \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438<\/p>\n<\/td>\n<td data-colwidth=\"137\" width=\"137\">\n<p align=\"left\">710,55 \u00b1 43,93<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"right\">1 407 366<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"right\">687,69x<\/p>\n<\/td>\n<td>\n<p align=\"right\">1,60x<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"179\" width=\"179\">\n<p align=\"left\">\u0420\u0430\u0437\u0431\u043e\u0440 \u0432 \u043e\u0434\u0438\u043d \u043f\u0440\u043e\u0445\u043e\u0434<\/p>\n<\/td>\n<td data-colwidth=\"137\" width=\"137\">\n<p align=\"left\">494,64 \u00b1 32,65<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"right\">2 021 688<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"right\">987,87x<\/p>\n<\/td>\n<td>\n<p align=\"right\">1,43x<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"179\" width=\"179\">\n<p align=\"left\">SIMD<\/p>\n<\/td>\n<td data-colwidth=\"137\" width=\"137\">\n<p align=\"left\">457,74 \u00b1 30,96<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"right\">2 184 669<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"right\">1 067,51x<\/p>\n<\/td>\n<td>\n<p align=\"right\">1,08x<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td data-colwidth=\"179\" width=\"179\">\n<p align=\"left\">SIMD+mmap<\/p>\n<\/td>\n<td data-colwidth=\"137\" width=\"137\">\n<p align=\"left\">366,22 \u00b1 23,56<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"right\">2 730 612<\/p>\n<\/td>\n<td data-colwidth=\"124\" width=\"124\">\n<p align=\"right\">1 334,28x<\/p>\n<\/td>\n<td>\n<p align=\"right\">1,24x<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/ee0\/f55\/f2e\/ee0f55f2edaf3e403becdaa7c4b8e8c6.png\" width=\"777\" height=\"438\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/ee0\/f55\/f2e\/ee0f55f2edaf3e403becdaa7c4b8e8c6.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u044f \u0438\u0437\u043c\u0435\u0440\u0438\u043b \u043f\u0440\u043e\u0441\u0442\u043e \u0438\u0442\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u043f\u043e \u0441\u0442\u0440\u043e\u043a\u0430\u043c \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u043c\u0435\u0442\u043e\u0434\u0430\u043c\u0438:<\/p>\n<div>\n<div class=\"table\">\n<table>\n<tbody>\n<tr>\n<td>\n<p align=\"left\"><strong>\u041c\u0435\u0442\u043e\u0434<\/strong><\/p>\n<\/td>\n<td data-colwidth=\"140\" width=\"140\">\n<p align=\"left\"><strong>ns\/line<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"right\"><strong>lines\/s<\/strong><\/p>\n<\/td>\n<td>\n<p align=\"right\"><strong>\u0423\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435<\/strong><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>.lines()<\/code><\/p>\n<\/td>\n<td data-colwidth=\"140\" width=\"140\">\n<p align=\"left\">311,04 \u00b1 12,89<\/p>\n<\/td>\n<td>\n<p align=\"right\">3 214 981<\/p>\n<\/td>\n<td>\n<p align=\"left\">\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\">.split(b&#8217;\\n&#8217;)<\/p>\n<\/td>\n<td data-colwidth=\"140\" width=\"140\">\n<p align=\"left\">245,63 \u00b1 10,82<\/p>\n<\/td>\n<td>\n<p align=\"right\">4 071 210<\/p>\n<\/td>\n<td>\n<p align=\"right\">1,27<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td>\n<p align=\"left\"><code>mmap<\/code> + <code>memchr<\/code><\/p>\n<\/td>\n<td data-colwidth=\"140\" width=\"140\">\n<p align=\"left\">173,55 \u00b1 7,15<\/p>\n<\/td>\n<td>\n<p align=\"right\">5 762 122<\/p>\n<\/td>\n<td>\n<p align=\"right\">1,79<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div>\n<\/div>\n<figure class=\"\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/36d\/52c\/f7f\/36d52cf7f6d1af524a29d24f6c572532.png\" width=\"429\" height=\"393\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/36d\/52c\/f7f\/36d52cf7f6d1af524a29d24f6c572532.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0418\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 <a href=\"https:\/\/github.com\/m0003r\/fast2ban\" rel=\"noopener noreferrer nofollow\">\u0432\u044b\u043b\u043e\u0436\u0435\u043d\u044b \u043d\u0430 github<\/a>, \u043a\u043e\u0434 \u0440\u0430\u0437\u043d\u044b\u0445 \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043e\u0432 \u0438\u0437 \u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0432\u0435\u0442\u043a\u0435 <code>habr<\/code> \u0440\u0430\u0437\u043d\u044b\u043c\u0438 \u043a\u043e\u043c\u043c\u0438\u0442\u0430\u043c\u0438. \u041f\u0443\u043b\u043b-\u0440\u0435\u043a\u0432\u0435\u0441\u0442\u044b, \u043a\u0430\u043a \u0432\u0441\u0435\u0433\u0434\u0430, \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0442\u0441\u044f.<\/p>\n<p>P. S. \u0412\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u0438 \u043c\u043e\u0433\u043b\u0438 \u0437\u0430\u043c\u0435\u0442\u0438\u0442\u044c, \u0447\u0442\u043e \u0441\u0430\u043c\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 SIMD \u043d\u0435 \u0434\u0430\u043b\u043e \u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u0432\u044b\u0438\u0433\u0440\u044b\u0448\u0430 \u2014 \u0432\u0441\u0435\u0433\u043e 8%. \u0422\u0435\u043c \u043d\u0435 \u043c\u0435\u043d\u0435\u0435, \u0436\u0435\u043b\u0442\u043e\u0432\u0430\u0442\u044b\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0441\u0442\u0430\u0442\u044c\u0438 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u0435\u043d: \u0442\u044b\u0441\u044f\u0447\u0435\u043a\u0440\u0430\u0442\u043d\u043e\u0435 \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435 \u0431\u044b\u043b\u043e \u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0443\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430 \u044d\u0442\u043e\u043c \u0448\u0430\u0433\u0435.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/668634\/\"> https:\/\/habr.com\/ru\/post\/668634\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p><code>Fail2ban<\/code> \u2014 \u0443\u0442\u0438\u043b\u0438\u0442\u0430 \u0447\u0440\u0435\u0437\u0432\u044b\u0447\u0430\u0439\u043d\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u0430\u044f \u0432\u043e \u043c\u043d\u043e\u0433\u0438\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445. \u0414\u0443\u043c\u0430\u044e, \u043c\u043d\u043e\u0433\u0438\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u0435\u0451 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u0432 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043d\u0430\u0437\u043e\u0439\u043b\u0438\u0432\u044b\u0445 \u00ab\u043f\u043e\u0441\u0435\u0442\u0438\u0442\u0435\u043b\u0435\u0439\u00bb. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0435\u0441\u043b\u0438 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u043f\u043e\u0442\u043e\u043a \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u0438\u043c, <code>fail2ban<\/code> \u0442\u0435\u0440\u044f\u0435\u0442 \u0432\u0441\u0435 \u0441\u0432\u043e\u0438 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u0440\u0430\u0437\u0431\u043e\u0440 \u043b\u043e\u0433\u0430 \u0431\u0435\u0437\u043d\u0430\u0434\u0451\u0436\u043d\u043e \u043e\u0442\u0441\u0442\u0430\u0451\u0442 \u043e\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u0438.<\/p>\n<p>\u0412\u043e\u0442, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043b\u043e\u0433 <code>nginx<\/code> \u0438\u0437 100 \u0442\u044b\u0441\u044f\u0447 \u0441\u0442\u0440\u043e\u0447\u0435\u043a <code>fail2ban<\/code> \u043f\u0440\u0438 \u0441\u0430\u043c\u044b\u0445 \u043f\u0440\u043e\u0441\u0442\u044b\u0445 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 (<code>failregex='^&lt;ADDR>'<\/code>) \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u0442 \u043f\u043e\u0440\u044f\u0434\u043a\u0430 45 \u0441\u0435\u043a\u0443\u043d\u0434:<\/p>\n<pre><code>$ fail2ban-regex nginx.log '^&lt;ADDR>'  Running tests =============  Use   failregex line : ^&lt;ADDR> Use         log file : nginx.log Use         encoding : UTF-8   Results =======  Failregex: 100000 total |-  #) [# of hits] regular expression |   1) [100000] ^&lt;ADDR> `-  Ignoreregex: 0 total  Date template hits: |- [# of hits] date format |  [100000] Day(?P&lt;_sep>[-\/])MON(?P=_sep)ExYear[ :]?24hour:Minute:Second(?:\\.Microseconds)?(?: Zone offset)? `-  Lines: 100000 lines, 0 ignored, 100000 matched, 0 missed [processed in 44.48 sec]<\/code><\/pre>\n<p>\u0427\u0435\u0441\u0442\u043d\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u0432 \u043e\u0434\u043d\u043e \u043d\u0430 \u0434\u0440\u0443\u0433\u043e\u0435, \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0440\u044f\u0434\u043a\u0430 2250 \u0441\u0442\u0440\u043e\u043a \u0432\u00a0\u0441\u0435\u043a\u0443\u043d\u0434\u0443. \u0412\u043e\u0437\u044c\u043c\u0451\u043c \u044d\u0442\u0443 \u0446\u0438\u0444\u0440\u0443 \u0437\u0430 \u043e\u0441\u043d\u043e\u0432\u0443. <\/p>\n<p>(\u041f\u043e \u0444\u0430\u043a\u0442\u0443 \u0440\u0430\u0437\u0431\u043e\u0440 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435 \u0438\u0437-\u0437\u0430 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e <code>fail2ban<\/code> \u0431\u0430\u043d\u0438\u0442 \u0432\u044b\u044f\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u043d\u0430\u0440\u0443\u0448\u0438\u0442\u0435\u043b\u0435\u0439 \u0432 \u0442\u043e\u043c \u0436\u0435 \u043f\u043e\u0442\u043e\u043a\u0435, \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u043e\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u044f \u0447\u0442\u0435\u043d\u0438\u0435 \u043b\u043e\u0433\u0430)<\/p>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u043f\u043e\u0440\u0430 \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0438. \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u043e\u0441\u0442\u0430\u0442\u044c\u0441\u044f \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 <code>fail2ban<\/code> \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c, \u043d\u0430 \u0447\u0442\u043e \u0436\u0435 \u043e\u043d \u0442\u0440\u0430\u0442\u0438\u0442 \u0432\u0440\u0435\u043c\u044f. \u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 <code>fail2ban<\/code> \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 Python, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c <code>cProfile<\/code> \u0431\u0435\u0437 \u0432\u0441\u044f\u043a\u0438\u0445 \u043c\u043e\u0434\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0439 \u043a\u043e\u0434\u0430:<\/p>\n<pre><code>$ python -m cProfile -s cumtime \/usr\/bin\/fail2ban-regex nginx.log '^&lt;ADDR>'  ...     Ordered by: cumulative time     ncalls  tottime  percall  cumtime  percall filename:lineno(function)         1    0.001    0.001   52.734   52.734 fail2ban-regex:26(&lt;module>)         1    0.000    0.000   52.640   52.640 fail2banregex.py:784(exec_command_line)         1    0.000    0.000   52.638   52.638 fail2banregex.py:719(start)         1    0.411    0.411   52.636   52.636 fail2banregex.py:571(process)    100000    0.789    0.000   50.909    0.001 fail2banregex.py:448(testRegex)    100000    0.689    0.000   49.839    0.000 filter.py:601(processLine)    100000    3.741    0.000   39.767    0.000 datedetector.py:321(matchTime)   1595350    0.945    0.000   34.731    0.000 datetemplate.py:157(matchDate)   1695573   33.933    0.000   33.933    0.000 {method 'search' of '_sre.SRE_Pattern' objects}    100000    0.205    0.000    5.583    0.000 datedetector.py:469(getTime)    100000    0.187    0.000    5.305    0.000 datetemplate.py:323(getDate)    100000    1.826    0.000    4.858    0.000 strptime.py:172(reGroupDictStrptime)    100000    1.284    0.000    3.519    0.000 filter.py:811(findFailure)   1400000    0.564    0.000    1.479    0.000 utf_8.py:15(decode) 200000\/100000    0.615    0.000    1.303    0.000 strptime.py:143(zone2offset)    100000    0.154    0.000    1.100    0.000 strptime.py:124(validateTimeZone)    100000    0.422    0.000    0.965    0.000 {method 'index' of 'list' objects<\/code><\/pre>\n<p>\u0438 \u0432\u0438\u0434\u0438\u043c \u043d\u0435\u0443\u0442\u0435\u0448\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u0443. \u0411\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 fail2ban \u0442\u0440\u0430\u0442\u0438\u0442 \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0437\u043e\u0431\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u0444\u043e\u0440\u043c\u0430\u0442\u043e\u043c \u0434\u0430\u0442\u044b. \u041a \u0441\u0447\u0430\u0441\u0442\u044c\u044e, \u0435\u043c\u0443 \u0432 \u044d\u0442\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043c\u043e\u0447\u044c \u2014 \u043d\u0443\u0436\u043d\u043e \u0441\u043f\u0435\u0446\u0438\u0444\u0438\u0446\u0438\u0440\u043e\u0432\u0430\u0442\u044c, \u043a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u0443 \u0441\u0430\u043c\u0443\u044e \u0434\u0430\u0442\u0443 \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c. \u0421\u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 <code>datepattern<\/code> \u0432 \u0444\u0430\u0439\u043b\u0430\u0445 <code>filter.d\/*.conf<\/code>, \u0430 \u0434\u043b\u044f <code>fail2ban-regex<\/code> \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>-d<\/code>. <\/p>\n<details class=\"spoiler\">\n<summary>\u0412\u044b\u0432\u043e\u0434 fail2ban-regex<\/summary>\n<div class=\"spoiler__content\">\n<pre><code>$ fail2ban-regex nginx.log -d '%d\/%B\/%Y:%H:%M:%S' '^&lt;ADDR> - [^ ]+ '  Running tests =============  Use      datepattern : %d\/%B\/%Y:%H:%M:%S : Day\/MONTH\/Year:24hour:Minute:Second Use   failregex line : ^&lt;ADDR> - [^ ]+ Use         log file : nginx.log Use         encoding : UTF-8   Results =======  Failregex: 100000 total |-  #) [# of hits] regular expression |   1) [100000] ^&lt;ADDR> - [^ ]+ `-  Ignoreregex: 0 total  Date template hits: |- [# of hits] date format |  [100000] Day\/MONTH\/Year:24hour:Minute:Second `-  Lines: 100000 lines, 0 ignored, 100000 matched, 0 missed [processed in 8.07 sec]<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0418\u0442\u043e\u0433\u043e \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0440\u0430\u0437\u0431\u043e\u0440\u0430 \u0432\u044b\u0440\u043e\u0441\u043b\u0430 \u043f\u043e\u0447\u0442\u0438 \u0432 \u0448\u0435\u0441\u0442\u044c \u0440\u0430\u0437 \u2014 \u0434\u043e \u043f\u043e\u0447\u0442\u0438 12,5 \u0442\u044b\u0441\u044f\u0447 \u0441\u0442\u0440\u043e\u043a \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443. \u041a\u00a0\u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0442\u0430\u043a\u0430\u044f \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u0434\u043e\u0441\u0442\u0438\u0436\u0438\u043c\u0430 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0438 \u0440\u0430\u0437\u0431\u043e\u0440\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <code>fail2ban-regex<\/code>: \u043a\u0430\u043a \u0443\u0436\u0435 \u0431\u044b\u043b\u043e \u0441\u043a\u0430\u0437\u0430\u043d\u043e \u0432\u044b\u0448\u0435, \u0432 \u0431\u043e\u0435\u0432\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u043f\u0440\u0438 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u043e\u043c \u0447\u0442\u0435\u043d\u0438\u0438 \u043b\u043e\u0433\u043e\u0432 \u044d\u0442\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043c\u0435\u0434\u043b\u0435\u043d\u043d\u0435\u0435.<\/p>\n<h2>\u041f\u0435\u0440\u0435\u043f\u0438\u0448\u0435\u043c \u043d\u0430 \u0447\u0451\u043c-\u0442\u043e \u043a\u043e\u043c\u043f\u0438\u043b\u0438\u0440\u0443\u0435\u043c\u043e\u043c<\/h2>\n<p>\u041f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043d\u0430 \u044d\u0442\u043e\u043c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 <code>fail2ban<\/code> \u0438\u0441\u0447\u0435\u0440\u043f\u0430\u043b\u0438\u0441\u044c, \u043c\u043d\u0435 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0438\u0441\u043a\u0430\u0442\u044c \u0430\u043b\u044c\u0442\u0435\u0440\u043d\u0430\u0442\u0438\u0432\u043d\u044b\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u044b. \u0412 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0435 \u0432\u0440\u0435\u043c\u044f \u044f \u043d\u0430\u0447\u0430\u043b \u0438\u0437\u0443\u0447\u0430\u0442\u044c Rust \u0438 \u043f\u0440\u0435\u0431\u044b\u0432\u0430\u044e \u0432 \u043f\u043e\u043b\u043d\u043e\u043c \u0432\u043e\u0441\u0442\u043e\u0440\u0433\u0435 \u043e\u0442 \u044d\u0442\u043e\u0433\u043e \u044f\u0437\u044b\u043a\u0430, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u044b\u0431\u0440\u0430\u043b \u0435\u0433\u043e.<\/p>\n<p>\u0414\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u044d\u0444\u0444\u0435\u043a\u0442\u0438\u0432\u043d\u043e \u0431\u0430\u043d\u0438\u0442\u044c \u043d\u0430\u0440\u0443\u0448\u0438\u0442\u0435\u043b\u0435\u0439, \u043d\u0443\u0436\u043d\u043e \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0435 <code>N<\/code> \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 (\u0438\u043b\u0438 \u043c\u0435\u043d\u044c\u0448\u0435) \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e IP-\u0430\u0434\u0440\u0435\u0441\u0430 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c, \u043d\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u043b\u0438 \u0447\u0430\u0441\u0442\u043e \u043e\u043d\u0438 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442. \u0417\u0434\u0435\u0441\u044c \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442 \u043a\u043e\u043b\u044c\u0446\u0435\u0432\u043e\u0439 \u0431\u0443\u0444\u0435\u0440 \u0441 \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u043e\u0439: \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u0430\u0439\u043c\u0441\u0442\u0430\u043c\u043f\u044b \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043f\u043e \u043a\u0440\u0443\u0433\u0443, \u0438 \u043a\u043e\u0433\u0434\u0430 \u043d\u0430\u043a\u043e\u043f\u0438\u043c <code>ring_size<\/code> \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439, \u0442\u043e \u043f\u0440\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c \u0440\u0430\u0437\u043d\u0438\u0446\u0443 \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0432\u043d\u043e\u0432\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 <code>N<\/code> \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u043d\u0430\u0437\u0430\u0434.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u043a\u043e\u043b\u044c\u0446\u0435\u0432\u043e\u0433\u043e \u0431\u0443\u0444\u0435\u0440\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">struct RingBanBuffer {     timestamps: Vec&lt;Option&lt;i64>>,     last_index: usize, }  impl RingBanBuffer {     fn new(ring_size: usize) -> RingBanBuffer {         RingBanBuffer {             timestamps: vec![None; ring_size],             last_index: 0         }     }      fn add_query(&amp;mut self, ts: i64) -> Option&lt;i64> {         self.timestamps[self.last_index] = Some(ts);         self.last_index = (self.last_index + 1) % self.timestamps.len();          self.timestamps[self.last_index].map(|prev| ts - prev)     } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043f\u0430\u0440\u0441\u0435\u0440 \u043b\u043e\u0433\u043e\u0432 \u0442\u043e\u0436\u0435 \u043d\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0441\u043b\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c: \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u0432\u044b\u0434\u0438\u0440\u0430\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0449\u0438\u0435 \u043d\u0430\u0441 \u043f\u043e\u043b\u044f (IP \u0438 \u0434\u0430\u0442\u0443) \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0433\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u043f\u043e\u0442\u043e\u043c \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0435\u043c \u0438\u0445. \u0415\u0441\u043b\u0438 \u0447\u0442\u043e-\u0442\u043e \u043d\u0435 \u0442\u043e, \u0442\u043e \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c <code>None<\/code>.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 \u043f\u0430\u0440\u0441\u0435\u0440\u0430<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">use chrono::*; use regex::Regex; use std::net::IpAddr;  struct ParseResult {     ip: IpAddr,     timestamp: i64, }  struct RegexParser {     regex: Regex,     date_format: String, }  impl RegexParser {     fn new(regex: &amp;str, date_format: &amp;str) -> Self {         let re = Regex::new(regex).unwrap();         RegexParser {             regex: re,             date_format: date_format.to_string(),         }     }      fn parse_line(&amp;self, line: &amp;str) -> Option&lt;ParseResult> {         let caps = self.regex.captures(line)?;         let timestamp = DateTime::parse_from_str(&amp;caps[\"DT\"], &amp;self.date_format).ok()?.timestamp();         let ip: IpAddr = caps[\"ip\"].parse().ok()?;         Some(ParseResult { ip, timestamp })     } }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043f\u0430\u0440\u0441\u0438\u043d\u0433\u0430 \u0434\u0430\u0442\u044b \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f <a href=\"https:\/\/crates.io\/crates\/chrono\" rel=\"noopener noreferrer nofollow\">\u043a\u0440\u0435\u0439\u0442 chrono<\/a>.<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0432\u0441\u0451 \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0432\u043e\u0435\u0434\u0438\u043d\u043e. \u0417\u0430\u0432\u0435\u0434\u0451\u043c <code>HashMap<\/code>, \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 IP-\u0430\u0434\u0440\u0435\u0441\u0430 \u0441 \u043a\u043e\u043b\u044c\u0446\u0435\u0432\u044b\u043c\u0438 \u0431\u0443\u0444\u0435\u0440\u0430\u043c\u0438 \u0438 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435\u043c \u0437\u0430\u0431\u0430\u043d\u0435\u043d\u043d\u043e\u0441\u0442\u0438, \u0447\u0438\u0442\u0430\u0435\u043c \u0444\u0430\u0439\u043b \u043f\u043e \u0441\u0442\u0440\u043e\u0447\u043a\u0430\u043c \u0438 \u043d\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0434\u0430\u043d\u043d\u044b\u0445. \u041a\u043e\u0433\u0434\u0430 \u0432\u0435\u0441\u044c \u0444\u0430\u0439\u043b \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043d, \u0442\u043e \u043f\u0435\u0447\u0430\u0442\u0430\u0435\u043c \u0441\u043f\u0438\u0441\u043e\u043a \u0437\u0430\u0431\u0430\u043d\u0435\u043d\u043d\u044b\u0445 \u0432 <code>stdout<\/code> \u0438 \u0441\u0442\u0430\u0442\u0438\u0441\u0442\u0438\u043a\u0443 \u0432 <code>stderr<\/code>.<\/p>\n<details class=\"spoiler\">\n<summary>\u041a\u043e\u0434 main<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"rust\">fn main() {     let reader = BufReader::new(File::open(\"nginx.log\").unwrap());     let parser = RegexParser::new(         r\"^(?P&lt;ip>[\\d.]+) - [^ ]+ \\[(?P&lt;DT>[^\\]]+)\\]\",         \"%d\/%B\/%Y:%H:%M:%S %z\",     );      let mut requests: HashMap&lt;IpAddr, (RingBanBuffer, bool)> = HashMap::new();      let mut line_count = 0;     let start = std::time::Instant::now();     for line in reader.lines() {         line_count += 1;         if let Some(ParseResult { ip, timestamp }) = line.ok().and_then(|l| parser.parse_line(&amp;l) ) {             let entry = requests.entry(ip).or_insert((RingBanBuffer::new(30), false));             if let Some(delta) = entry.0.add_query(timestamp) {                 if delta &lt; 30 {                     entry.1 = true;                 }             };         }     }      let elapsed = start.elapsed();      let banned_ips: Vec&lt;&amp;IpAddr> = requests.iter()         .filter(|(_, (_, banned))| *banned)         .map(|(k, _)| k)         .collect();      for ip in banned_ips.iter() {         println!(\"{}\", ip);     }      eprintln!(         \"elapsed {} ms, {} lines parsed, {} lines\/s, banned = {}\/{}\",         (elapsed.as_micros() as f64 \/ 1e3),         line_count,         line_count as f64 \/ (elapsed.as_micros() as f64 \/ 1e6),         banned_ips.len(),         requests.len()     ); }<\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c&#8230;<\/p>\n<pre><code>elapsed 208.154 ms, 100000 lines parsed, 480413.5399752107 lines\/s, banned = 565\/3506<\/code><\/pre>\n<p>480 \u0442\u044b\u0441\u044f\u0447 \u0441\u0442\u0440\u043e\u043a \u0432 \u0441\u0435\u043a\u0443\u043d\u0434\u0443, \u0443\u0441\u043a\u043e\u0440\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0432 38 \u0440\u0430\u0437, \u0432\u0430\u0443. \u041d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0443\u044e \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0441\u043a\u043e\u0440\u043e\u0441\u0442\u044c \u044d\u0442\u043e\u0442 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0443\u0436\u0435 \u043f\u0435\u0440\u0435\u043a\u0440\u044b\u0432\u0430\u0435\u0442, \u043d\u043e \u0442\u0443\u0442 \u043c\u043d\u0435 \u0441\u0442\u0430\u043b\u043e \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u0430 \u043d\u0430\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0435\u0449\u0451 \u044d\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u0441\u043a\u043e\u0440\u0438\u0442\u044c.<\/p>\n<h2>\u0420\u0430\u0437\u0431\u043e\u0440 \u0437\u0430 \u043b\u0438\u043d\u0435\u0439\u043d\u043e\u0435 \u0432\u0440\u0435\u043c\u044f<\/h2>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u0437\u0430\u043d\u0438\u043c\u0430\u0442\u044c\u0441\u044f \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438, \u0445\u043e\u0440\u043e\u0448\u043e \u0431\u044b \u0432\u044b\u044f\u0441\u043d\u0438\u0442\u044c, \u0430 \u0447\u0442\u043e \u0436\u0435, \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0433\u043e\u0432\u043e\u0440\u044f, \u0442\u043e\u0440\u043c\u043e\u0437\u0438\u0442. \u0414\u043b\u044f \u043f\u0440\u043e\u0444\u0438\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u0434\u0430 \u043c\u043e\u0436\u043d\u043e \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u044b\u043c \u043f\u0440\u043e\u0444\u0430\u0439\u043b\u0435\u0440\u043e\u043c <code>perf<\/code> (\u0443 \u043d\u0435\u0433\u043e \u0435\u0441\u0442\u044c \u0446\u0435\u043b\u0430\u044f <a href=\"https:\/\/perf.wiki.kernel.org\/index.php\/Main_Page\" rel=\"noopener noreferrer nofollow\">wiki \u0441 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0435\u0439<\/a>, \u0430 \u043d\u0430 \u0425\u0430\u0431\u0440\u0435 \u0435\u0441\u0442\u044c <a href=\"https:\/\/habr.com\/ru\/company\/first\/blog\/442738\/\" rel=\"noopener noreferrer nofollow\">\u0432\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0432 \u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0430\u0445<\/a>).<\/p>\n<pre><code>$ perf record target\/release\/fast2ban > \/dev\/null elapsed 206.889 ms, 100000 lines parsed, 483350.97564394434 lines\/s, banned = 565\/3506 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.031 MB perf.data (789 samples) ] $ perf report<\/code><\/pre>\n<p>\u0412\u0438\u0434\u0438\u043c \u0432\u043f\u043e\u043b\u043d\u0435 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u0443\u044e \u043a\u0430\u0440\u0442\u0438\u043d\u0443: \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0433\u043e \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u2014 <a href=\"https:\/\/ru.wikipedia.org\/wiki\/%D0%9F%D0%BE%D0%B8%D1%81%D0%BA_%D1%81_%D0%B2%D0%BE%D0%B7%D0%B2%D1%80%D0%B0%D1%82%D0%BE%D0%BC\" rel=\"noopener noreferrer nofollow\">\u0431\u044d\u043a\u0442\u0440\u0435\u043a\u0438\u043d\u0433<\/a>. <\/p>\n<figure class=\"bordered full-width\"><figcaption>perf report \u0432 \u0446\u0432\u0435\u0442\u0435 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043b\u0443\u0447\u0448\u0435<\/figcaption><\/figure>\n<p>\u041a\u0430\u043a \u0436\u0435 \u0442\u0430\u043a \u2014 \u0434\u0443\u043c\u0430\u044e \u044f \u2014 \u0432\u0440\u043e\u0434\u0435 \u0436\u0435 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u043d\u044b \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u043e\u043f\u0442\u0438\u043c\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u044b, \u0430 \u0437\u0434\u0435\u0441\u044c \u044d\u0442\u043e\u0433\u043e \u044f\u0432\u043d\u043e \u043d\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043f\u043e\u0438\u0441\u043a\u043e\u0432 \u044f \u0432\u044b\u044f\u0441\u043d\u0438\u043b, \u0447\u0442\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0432 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0435 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u044b, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e: \u044d\u0442\u043e \u0432 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u043b\u0443\u0447\u0430\u044f\u0445 \u0443\u043c\u0435\u0435\u0442 \u0438 <a href=\"https:\/\/crates.io\/crates\/regex\" rel=\"noopener noreferrer nofollow\">\u043a\u0440\u0435\u0439\u0442 regex<\/a>. \u0415\u0441\u0442\u044c \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 <a href=\"https:\/\/crates.io\/crates\/regex-automata\" rel=\"noopener noreferrer nofollow\">\u043a\u0440\u0435\u0439\u0442 regex-automata<\/a>, \u043d\u043e \u0434\u043b\u044f \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u044b\u0445 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 capturing groups, \u043e\u043d\u043e \u043d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442.<\/p>\n<p>\u041a\u0440\u043e\u043c\u0435 \u044d\u0442\u043e\u0433\u043e, \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u043a\u043e\u043d\u0435\u0447\u043d\u044b\u0445 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u043e\u0432 \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c Tagged DFA, \u0438 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f \u043d\u0430 \u0435\u0433\u043e \u043e\u0441\u043d\u043e\u0432\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, <a href=\"http:\/\/re2c.org\/\" rel=\"noopener noreferrer nofollow\">RE2C<\/a> (\u043e\u043d\u043e \u0434\u0430\u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434 \u0438 \u043d\u0430 Rust). \u0420\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0435 \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u0437\u0434\u0435\u0441\u044c \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0435, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435\u0447\u0442\u043e \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u043e\u0435 \u0437\u0434\u0435\u0441\u044c \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u043e \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0438 \u0441\u0432\u043e\u0438\u043c\u0438 \u0440\u0443\u043a\u0430\u043c\u0438.<\/p>\n<p>\u0417\u0430\u043e\u0434\u043d\u043e \u043e\u0431\u0440\u0430\u0442\u0438\u043c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u0431\u0435\u0441\u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0439 \u0432\u044b\u0437\u043e\u0432 <code>decode_utf8<\/code> \u2014 nginx \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e <a href=\"https:\/\/nginx.org\/ru\/docs\/http\/ngx_http_log_module.html#log_format\" rel=\"noopener noreferrer nofollow\">\u043f\u0438\u0448\u0435\u0442 \u043b\u043e\u0433\u0438 \u0432 ASCII<\/a>. \u041b\u0438\u043d\u0435\u0439\u043d\u044b\u0439 \u0440\u0430\u0437\u0431\u043e\u0440 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0438 \u043d\u0430 \u0441\u044b\u0440\u043e\u043c \u043c\u0430\u0441\u0441\u0438\u0432\u0435 \u0431\u0430\u0439\u0442\u043e\u0432, \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u0443\u044f \u0438\u0445 \u0432 \u0441\u0442\u0440\u043e\u043a\u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f \u043a\u043e\u043c\u043f\u0438\u043b\u044f\u0442\u043e\u0440\u0430 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e unsafe-\u0444\u0443\u043d\u043a\u0446\u0438\u0438 <a href=\"https:\/\/doc.rust-lang.org\/stable\/std\/str\/fn.from_utf8_unchecked.html\" rel=\"noopener noreferrer nofollow\">from_utf8_unchecked<\/a>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u043e \u0444\u0430\u043a\u0442\u0443 <a href=\"https:\/\/doc.rust-lang.org\/stable\/src\/core\/str\/converts.rs.html#173\" rel=\"noopener noreferrer nofollow\">\u0434\u0435\u043b\u0430\u0435\u0442 \u043d\u0438\u0447\u0435\u0433\u043e<\/a>.<\/p>\n<p>\u0412\u0441\u0451 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-333983","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/333983","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=333983"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/333983\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=333983"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=333983"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=333983"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}