Here is the new flatbuffer schema: https://github.com/spacewander/incubator-apisix/blob/step1/apisix/plugins/ext-plugin/ext-plugin.fbs
Zexuan Luo <spacewan...@apache.org> 于2021年4月16日周五 下午2:52写道: > > 1. Background > > APISIX currently only supports writing plugins in Lua. If other > languages are supported, it will greatly broaden the APISIX ecosystem > and user base. > > 2. Solution > > Since WASM is not yet mature, we consider implementing it through local IPC. > > For the sake of discussion, the following will assume that the plugin > is written in Java. However, in practice, our solution can be > interfaced with other languages. > > 2.1 Terminology > > Several terms are defined here. > > Plugin Runner: The service that runs the plugin, written in the same > language as the plugin. In the first version, we assume that there > will be only one Plugin Runner. > > 2.2 Plugin Runner lifecycle > > To simplify user operation and reduce the difficulty of upgrading, > Plugin Runner is managed by APISIX. > > APISIX starts the Plugin Runner when it starts and ends it when it > ends. if the Plugin Runner quits in the middle, APISIX will restart it > automatically. > > 2.3 Timing of APISIX communication with Plugin Runner > > ``` > Router ----> Global Plugin (written in Lua) ---> Ext Plugin > (ext-plugin-pre-req) ----> Lua Plugin (Router) > ---> Ext plugin (ext-plugin-post-req) ---> Upstream > ``` > > Running the Ext Plugin in the Global Plugin is not supported at this > time, as the global logic can be executed uniformly in the Plugin > Runner. > > Running Ext Plugin after getting an upstream response is not supported > at this time. We can support it later with a buffering response. > > ext-plugin-pre runs before all non-global Lua plugins, and > ext-plugin-post runs after all non-global Lua plugins. > > 2.4 How APISIX communicates with Plugin Runner > > APISIX communicates with Plugin Runner through a unix socket. The > communication protocol is as follows. > > 2.4.1 Communication format > > ``` > 1 byte of type + 3 bytes of length + data > ``` > > The type can be 0 ~ 7, and the length can be [0, 8M). data length is > determined by length. > Since Ext Plugin usually does not exchange too much data, 8M should be > enough. The reason for taking 4 bytes is to keep the header small > enough to be read efficiently. > > The current type takes the following values. > > 0 means error > 1 means prepare_conf > 2 means http_req_call > > The data is serialized in capnproto, a binary serialization format. > > capnproto is supported by many programming languages: > https://capnproto.org/otherlang.html > > The advantages of choosing capnproto are. > 1. focus on serialization performance > 2. partial deserialization support, so that decode can be done only > when it is needed > > 2.4.2 Communication steps > > Each ext plugin will have the following configuration. > > ``` > { > "conf": [ > { > "name": "configuration name", > "value": "configuration value" > } > ], > "extra_info": [ > ... > ] > } > ``` > > conf can be used to set the execution configuration of the > plugin-related requests inside Plugin Runner. > > The default data sent to Plugin Runner is only the most common > information. If you want additional information, you need to declare > it in extra_info beforehand. > > To save communication costs, conf is sent separately. > > 1. APISIX will check if conf has a corresponding token in the local cache. > 2. If not, APISIX sends a prepare_conf request to ask Plugin Runner > to cache the conf and return a token. > (Note that Plugin Runner's cache time needs to be longer than APISIX's > cache time.) > 3. APISIX sends an http_req_call request to Plugin Runner. > 4. Plugin Runner executes the request and returns a response to APISIX. > 5. APISIX processes the request based on the response > > 2.4.3 proto > > Refer to https://capnproto.org/language.html > > The following is the proto for error > > response > ``` > enum ErrorCode { > BAD_REQUEST @0; # Plugin Runner can't understand APISIX > SERVICE_UNAVAILABLE @1; # Plugin Runner can't handle the request > CONF_TOKEN_NOT_FOUND @2; > } > struct ErrorResp { > Code @0 :ErrorCode; > } > ``` > > The following is the proto of prepare_conf > > request > ``` > struct PrepareConfReq { > conf @0 :List(Pair); > } > ``` > > Response > ``` > struct PrepareConfResp { > conf_token @0 :UInt32; > } > ``` > > Here is the proto for http_req_call > > request > ``` > struct Pair { > name @0 :Text; > value @1 :Text; > } > struct PairData { > name @0 :Text; > value @1 :Data; > } > enum Method { > GET @0; > ... > } > > struct HTTPReqCallReq { > id @0 :UInt32; > src_ip @1 :Data; > > method @2 :Method; > > path @3 :Text; > args @4 :List(Pair); > headers @5 :List(Pair); > > conf_token @6 :UInt32; > > extra_info @7 :List(PairData); > } > ``` > > Response > ``` > struct HTTPReqCallResp { > id @0 :UInt32; > > struct Stop { > status @0 :UInt16; > headers @1 :List(Pair); > body @2 :Data; > } > struct Rewrite { > path @0 :Text; > headers @1 :List(Pair); > # Note that args are modified in full. > # Either empty, meaning no args need to be moved > # or the entire modified args, not the incrementally changed parts > args @2 :List(Pair); > } > > # What needs to be done when the response is received action > action :union { > # Do nothing > continue @1 :Void; > # Equivalent to core.response.exit(status, body), allowing > additional headers to be set > stop @2 :Stop; > # Rewrite the request > rewrite @3 :Rewrite; > } > } > ``` > > 2.4.4 Error handling > > Logging and returning 503 error codes > > 2.4.5 Environment variables > > APISIX configures the Plugin Runner with a number of environment > variables when it is started. > > APISIX_LISTEN_ADDRESS: the address that the Plugin Runner needs to listen to > APISIX_CONF_EXPIRE_TIME: Plugin Runner needs to cache conf for longer than > this