2019-06-17 13:24 靈雀雲 分類:istio 閱讀(22) 評論(0) [編輯]
Envoy是istio的核心組件之一,以sidecar的方式與服務運行在一塊兒,對服務的流量進行攔截轉發。 具備路由,流量控制等等強大特性。mysql
Envoy利用libevent實現了基於事件觸發的異步架構,全部的網絡阻塞操做包括 accept,read, connect, write 都是由eventloop進行callback觸發。c++
本文以istio1.1所對應的Envoy版本進行源碼流程分析。redis
名詞解釋:sql
下游: 發送請求給Envoy的服務,client
上游:接收Envoy發送的請求,並返回響應的服務, server
Filter流程圖
下面的流程圖爲istio架構下,訪問80端口的http服務的流程。
網絡
2.Client發送請求給Envoy,Envoy通過路由後找到上游Server,併發送請求架構
3.上游Server返回響應給Envoy,Envoy利用event_active當即返回響應給下游的client併發
Filter分類cors
listener.listener_filters負載均衡
用於接收到下游新鏈接的時候回調dom
接口:
onAccept(callback)
內置類型:
envoy.listener.original_dst (istio中的15001端口經常使用)
根據iptables轉換以前的dst port,查找到真實的Listener,查找到Listener會根據新的Listener的配置繼續處理
envoy.listener.tls_inspector
註冊read callback,識別tls和進行tls握手,握手結束後會進行下一步的filterChain的處
註冊filter:
listener.filter_chains.filters
用於接受到下游新鏈接的時候回調
上游或者下游鏈接上有數據能夠讀取的時候的回調,通常用於協議的解析
接口:
onNewConnection()
onData(data, end_stream)
…
內置類型:
Envoy::Http::CodecClient 只在向上遊的鏈接用到,且向上遊的鏈接只有這個filter,用於讀取響應
envoy.http_connection_manager
處理http請求的主要filter
envoy.tcp_proxy
envoy.redis_proxy
…
註冊filter:
listener.filter_chains.filters
用於向上遊的鏈接寫入數據的時候回調(目前內置的writeFilter沒有http相關的)
接口:
onWrite(data, end_stream)
內置類型:
envoy.filters.network.dubbo_proxy
envoy.mongo_proxy
envoy.filters.network.mysql_proxy
envoy.filters.network.zookeeper_proxy
註冊filter:
listener.filter_chains.filters[envoy.http_connection_manager].http_filters
用於解析http請求各個部分的時候回調執行
接口:
decodeHeaders(headers, end_stream)
decodeData(data, end_stream)
decodeTrailers(HeaderMaps& trailers)
decodeComplete()
…
內置類型:
envoy.cors
envoy.fault
envoy.router
…
註冊filter:
(envoy.http_connection_manager 下獨有的filter)
listener.filter_chains.filters[envoy.http_connection_manager].http_filters
發送響應各個部分給下游client的時候執行
接口:
encode100ContinueHeaders(headers)
encodeHeaders(headers, end_stream)
encodeData(data, end_stream)
encodeTrailers(HeaderMap& trailers)
encodeMetadata(metadata_map)
encodeComplete()
…
內置類型:
envoy.cors
envoy.fault
envoy.lua
…
註冊filter:
route.virtual_hosts.per_filter_config
位於route上的字段,只有當對應Listener上http_connection_manager包含對應httpfilter的時候纔有用,結構爲 map<string, Struct> 用法由filter本身實現
7.ConnectionCallbacks
listener.filter_chains.filters
接口:
onEvent(event)
事件分爲 RemoteClose, LocalClose, Connected 會在各個階段調用
onAboveWriteBufferHighWatermark()
onBelowWriteBufferLowWatermark()
route.virtual_hosts.per_filter_config
類型:
Envoy::Http::CodeClient只在向上遊的鏈接用到,且向上遊的鏈接只有這個filter,用於檢測上游鏈接斷開
envoy.http_connection_manager
envoy.tcp_proxy
envoy.redis_proxy
註冊filter:
接口:
log(request_headers, response_headers, response_trailers, stream_info)
類型:
Envoy::Http::Mixer::Filter
istio爲Envoy添加的Filter,在AccessLogHandlers這邊主要用於Report
Envoy::Extensions::AccessLoggers::File::FileAccessLog
Envoy::Extensions::HttpGrpc::File::HttpGrpcAccessLog
Envoy::Extensions::HttpFilters::TapFilter::Filter
Filter流程中關鍵步驟解析
根據socket的localaddress和port選擇合適的Listener處理
1.利用syscall找到iptables轉化以前的dst port (若是有envoy.listener.original_dst)
os_syscalls.getsockopt(fd, SOL_IP, SO_ORIGINAL_DST, &orig_addr, &addr_len)
2.先匹配address和port和socket都一致的Listener,若是沒找到再找port一致,address==0.0.0.0的Listener
在構造RouteMatcher的時候會遍歷virtual_hosts 下的domains,並根據通配符的位置和domain的長度分爲4個 map<domain_len, std::unordered_map<domain, virtualHost>, std::greater<int64_t>>
default_virtual_host_ domain就是一個通配符(只容許存在一個)
wildcard_virtual_host_suffixes_ domain中通配符在開頭
wildcard_virtual_host_prefixes_ domain中通配符在結尾
virtual_hosts_ 不包含通配符
同時按照map的迭代順序(domain len降序)查找最早除去通配符後能匹配到的virtualhost,若是沒有直接返回 404
3.在一個virtualhost上查找對應route和cluster
在經過domain匹配到virtualhost,會在那個virtualhost上匹配查找cluster,若是沒匹配上,會直接返回404
match能夠根據配置分爲 prefix, regex, path 三種route進行匹配
若是存在weighted_clusters ,會根據stream_id , 和clusters的weight進行分發,stream_id 自己是每一個請求獨立隨機生成,因此weighted_clusters 的權重分發能夠視爲隨機分發
3.負載均衡策略選擇endpoint
1.在上一步查找到了clusterName, 對於clusterEntry,都是從ThreadLocalClusterManagerImpl 中取出,每一個worker都一份本身的數據
2.對於ThreadLocalClusterManagerImpl , 維護了多份根據類型和協議區分的map
其中http協議才用的是host_http_conn_pool_map_ 這個map,大體的結構爲 map<host, map<protocol, connpool>> , 由於http分爲 Http10, Http11, Http2 不一樣協議的connpool都是獨立的
對於http請求,會從 host_http_conn_pool_map_ 中查到對應的connpool,每一個worker都維護了一份本身獨有的threadlocal connpool
Mixer
mixerclient是istio基於Envoy,添加filter進行check和report的模塊
註冊到Envoy
註冊到Envoy主要就是兩行
第一行註冊了 StreamDecodeFilter 和 StreamEncodeFilter, Http::Mixer::Filter 在decodeHeader 這個hook中實現了Check,發送attributes給mixerserver進行檢查
第二行註冊了 AccessLogHandler ,這個會在 一個請求結束的時候執行
在Mixer filter的log method中,會進行report操做
能夠看到Mixer雖然是每一個請求結束都會調用log,但實際的上報mixer是批量發送(累計必定大小或者到達必定時間間隔)。
總結
1.能夠在Envoy處理請求的各個階段加入filter來定製化功能,能夠本身編寫c++的filter,用REGISTER_FACTORY 註冊到對應的Factory map中。