hyperscan開源了!正則表達式
官網:https://01.org/zh/hyperscan數據庫
當地時間10月19日,intel將它的高速正則表達式匹配引擎hyperscan開源了,版本4.0,基於BSD許可。這個基於自動機(Automata)的引擎通過了多年開發(2008年起),通過不斷優化與完善,效率很是之高,雖然沒有pcre等對正則語法支持全面,但很是適用於網絡設備。用戶能夠在網絡設備數據面(Data Plane)使用hyperscan進行規則匹配,實現高性能DPI/lPS/IDS等應用。以前開源的dpdk,搭配hyperscan,簡直是雙劍合璧。express
今後以後,DPI/IPS/IDS/NGFW開發人員能夠把精力更多地放在業務上,而不須要苦於優化報文轉發(dpdk之功)和規則匹配(hyperscan之力)的性能。對於DPI來講,今後以後,也許特徵/規則纔是核心價值,軟件自己已經不重要了。而基於dpdk的軟件產品,憑藉其不輸太多的性能、較低的成本、較低的開發門檻和靈活性,也對相同功能的硬件產品發起了挑戰。網絡
hyperscan的實現基於自動機(automata, 如NFA/DFA)而不是回溯(back-tracking)。這麼作有好有壞。好處是能夠支持流模式(streaming)和多模正則表達式;壞處是,基於自動機的正則匹配沒法很容易地處理某些正則構造 - backreferences and arbitrary lookaround asserts(好吧,我也不知道這倆到底啥意思)是不支持的兩個主要特性。函數
hyperscan所使用的一些技術包括:佈局
Discovery of literal (fixed string) factors and decomposition of regular expressions into smaller chunks (which we call "engines") separated by these literal factors. These engines can be of many different types: Deterministic Finite Automata (DFA) Bit-parallel Glushkov Non-deterministic Finite Automata (NFA) engines Custom engines for special cases (such as large bounded repeats). These engines can take many different roles: "Prefix" engines that precede our literal factors "Suffix" engines that follow our literal factors "Infix" engines that lie between two literal factors "Outfix" engines that aren’t connected at all with literal factors (when no satisfactory factors can be found in a regular expression) These engines can often run lazily or not at all to reduce overhead. We merge smaller DFA/NFA engines into larger ones, where this can be done without performance loss. SIMD "acceleration" of automata based scanning: where we can substitute relatively simple SIMD tests of our input for complex automata execution, we do it. We use Intel SIMD instructions to handle larger-scale NFA and literal matching tasks: having 128 or 256 (or more) bits for a bit-parallel automaton is often helpful. ... and many more short-cuts to attempt to avoid doing expensive automata calculations that we ultimately won’t need.
hyperscan設計目標:性能
另外,還有一些設計要求或限制:優化
hyperscan以C++實現,使用了boost庫和C++11特性,但它的API卻以簡潔的C形式提供。hyperscan API主要分爲兩個部分:編譯與匹配 (compile & scan)。用戶提供的多個正則表達式先要通過編譯,生成database,而後才能夠調用匹配接口,使用此database進行匹配。this
編譯就是將多個正則表達式編譯爲hyperscan database,調用編譯接口時能夠傳入一些flags和mode等參數,控制匹配行爲和運行模式。hyperscan的運行模式主要有3個:BLOCK、STREAM和VECTORED。BLOCK模式就是對多個數據塊分別進行匹配;STREAM模式將特定的一組數據庫視爲一個STREAM,爲每個STREAM維護狀態信息,它能夠跨數據塊進行匹配;VECTORED模式能夠一次匹配多個數據塊。使用不一樣模式參數編譯的database在匹配時不能混用。spa
hyperscan的database能夠序列化成文件(固然也能夠反序列化),也能夠在不一樣機器間進行傳遞。
編譯的API主要有
hs_compile()
hs_compile_multi()
hs_compile_ext_multi()
匹配就是基於編譯好的database,對數據進行匹配,並獲得匹配結果。 hyperscan在進行匹配時須要有一個臨時數據(scratch),這塊數據須要在數據面運行前就分配(不在運行時分配和釋放,保證性能),且須要保證同一時刻僅有一個匹配過程在使用同一塊臨時數據。若是使用流模式,還須要預先爲每一個流分配流狀態數據。
匹配結果是經過用戶自定義的回調函數獲取的。匹配過程當中只要發生命中,就會調用此函數。此函數返回0表示繼續匹配,非0表示中止匹配。此函數的原型由hyperscan約定,用戶經過實參,能夠得到命中正則表達式對應的ID、匹配位置等信息。
匹配回調函數的原型:
typedef (* match_event_handler)(unsigned int id, unsigned long long from, unsigned long long to, unsigned int flags, void *context)
匹配的API主要有
hs_scan()
hs_scan_vector()
hs_scan_stream()
流模式的匹配較爲複雜,這裏不說起,下文有相關示例解讀。