Gateway technology implementation is shown in the figure below:
When the gateway is initialized, the configuration is obtained from Redis, including routing information, the key of the institution (used for encrypting and decrypting business data), the public and private key of the platform to the institution (used for signature verification), the authority of the institution to access the API, and the black-and-white list of the institution. And save this configuration information to memory. This information is configured on the administrative side. If there is a change, then update the memory or rebuild the route. Routing information includes the back-end docking method, the back-end address, and assertions according to the API name and version. There are three ways to connect with the back-end:
- HTTP: The normal Gateway forwarding function
- LB: Gatewa forwards to the service registered to Eureka. The application scenario is the adapter. If the parameter format of the gateway output does not match that of the backend, the parameters need to be tailored
- MQ: Asynchronous invocation
HTTP support:
- Adding a PATH assertion exposes the same external entry
- Add apiName and apiVersion assertion, find the background route that needs to be forwarded, and enter the corresponding filter
- Overwrite PATH to a custom back-end service address. If it passes through a series of filters, it is forwarded to the appropriate service
LB support:
- Adding a PATH assertion exposes the same external entry
- Add apiName and apiVersion assertion, find the background route that needs to be forwarded, and enter the corresponding filter
- /service-name/url: /service-name/url: /service-name/url: /service-name/url: /service-name: /service-name/url: /service-name: /service-name: /service-name: /service-name: /service-name: /service-name: /service
- AddRequestHeader adds the request header, sets the password, and marks the request as forwarded by the Gateway. The LB backend service validates the header.
MQ support:
- Adding a PATH assertion exposes the same external entry
- Add apiName and apiVersion assertion, find the background route that needs to be forwarded, and enter the corresponding filter
- Configure the back-end scheme as MQ
-
Define a global filter: If Scheme is MQ, then the route of the MQ class.
- Create a new UUID, put (UUID, RSP) in the Map, and then send the request containing the UUID to MQ. When the gateway receives the MQ response, it also gets the UUID and the RSP from the Map for the response.
- When (uuid, RSP) is placed in the map, (uuid,curenttime) is also placed in exceedMap, and the gateway periodically checks whether the transactions of the MQ class have timed out. (exceedMap converted to LinkedHashMap)
- MQfilter isAlready.. Since it is a global route, it handles the last filter of the MQ/HTTP protocol; For HTTP, avoid going nettyRoute and then forward
Technology evolution:
- At the beginning, there was only an Internet gateway, which was connected to external institutions. It was necessary to encrypt and decrypt parameters and verify signatures. Then there are new requirements:
-
Develop internal gateway: the internal system of the company as the caller, the internal network does not need to be encrypted, only MD5 verification can be done. Internet gateway and internal gateway have common filter, also have their own unique filter. The docking with the back end is also different, the internal gateway does not have the LB docking form.
- Extract the public filter, define the personality filter, and freely combine the filter and predicate to build the gateway
-
On-demand configuration: Sometimes you need to deploy a gateway to an Intranet environment for functional testing, and only need to configure an HTTP route. It is not necessary to deploy Redis and MQ, so the configuration information should support reading from the configuration file and not listening for configuration changes. Routing information reading should also be divided into HTTP, LB and MQ categories according to the docking mode, and configured according to the needs of the gateway.
- Routing configuration removes dependencies on Redis
- Gateway functions are combined on demand
- Global and local filters: The original architecture filters are all global filters, and the map decides whether the transaction will take this route. Now change to local route, add when creating route addCommonFilter. (Not implemented, because the routing model needs to be changed, which is troublesome)
For the same type of gateway, the assertions and public filters are the same, while different docking forms have their own filters. In order to realize the reuse of filter and flexible configuration, defines the GatewayRouteDynamicService classes, including RouteUpdate method to create a class of routing process template:
- Retrieves routing information from the data source ApiPlan
- Add Gateway Common Assertions (implement the AddCommonPredicate interface)
- Add a public filter (implement AddCommonFilter)
- Add specific assertions/filters (implement AddSpecific DynamicRoute)
- Release the routing
Extensibility implementation:
- Different gateways implement their own AddCommonPredicate, AddCommonFilter interfaces, and you can add common assertions and interfaces to this class of gateways.
- If token validation, encryption and decryption are implemented in a different way, rewrite the filter and add it to CommonFilter
- Different routing types implement the AddSpecific DynamicRoute interface, such as HTTP, MQ, LB
- Data sources are Redis and configuration files
- Optionally listen for data source changes, and if so, use Redis
- Subsequent data sources and monitoring support select middleware such as ZK
- Currently the assertion is that apiName+version corresponds to a route. AddCommonPredicate also supports routing based on the institution number and bank number passed in. AddCommonPredicate can be implemented by inheriting the PredicateFactory class.
Several functional modules of Gateway:
-
Loads and initializes the route:
- Mainly according to the docking mode with the back end, if there is a new docking mode, implement AddSpecific DynamicRoute interface
-
If there is a route for MQ:
- Configure MQ response listening: Since there are multiple Gateway instances, requests and responses for the same transaction should be handled by the same Gateway. The request queue addresses of different Gateways are the same, but the response queue is different. The response queue address is in the Reply field of the JMS message for the request transaction, so the back-end service only configures the request queue, which is included in the JMS message for the request. Here the response queue address is service_name + docker.slot(1, 2, 3…) . In this way, each time the service is restarted, the response Queue address will not change. If the Gateway expands flexibly, slot+1 can be automatically expanded without changing the configuration file. If the response queue is virtual IP for the Docker container, the service will create a new queue every time, which can be very confusing.
- Timeout MQ message processing: Check for timeout transactions at exceedMap
-
Read configuration:
- Removes the dependency on Redis, optionally from Redis or configuration files. Inject the implementation class of a Redis or configuration file. Implement the separation of configuration acquisition from implementation, configuration change listening from configuration acquisition
-
Listen for configuration changes:
- You can choose not to listen, or you can listen through Redis ZK
- Listen for a new configuration, such as the flow limit size of an API, listen for a key such as change, and if the change value is value, find the bean named value from Spring and call the run method.
- If you add a new configuration, no more if else or switch code changes, you can create a new class, and the implementation is open for extension, closed for modification.
Advantage:
- It’s more abstract, it’s more extensible,
Disadvantage:
- The architecture is more complex, debugging is difficult, and the learning curve is steep
After the gateway is built, it is necessary to improve the monitoring function of gateway transactions. We need real time (quasi-real time) information about the transactions and the operation of the gateway, such as:
-
Transaction monitoring statistics:
- Changes in the total number of trades over time
- Which institutions call which APIs from which banks, and which APIs have been called the most in the past
- There are no abnormal transactions, such as timeout, backend service suspended caused by failed transactions
-
Transaction alarm:
- Alert rules, if there are abnormal transactions, timely notification
-
Transaction link log view:
- View the log of the gateway link by stream number
-
The report:
- For some time in the past, institutions, banks, API level calls statistics, easy to count charges
-
Gateway service monitoring:
- Gateway memory usage, GC, number of active threads, and other JVM information in the past, if there is an exception in time to alert
Exception handling:
-
Exception where the gateway forwards a request to the background:
- Unable to connect to background
- Connection timeout
-
Custom exceptions:
- Filter fails to pass the exception, such as parameter verification failure, token verification failure, encryption and decryption failure, etc.
- Assertion exception, gateway does not match to route
-
Unknown exceptions:
- Runtime exceptions, etc
These exceptions are handled by handlers in the same place. For MQ class trading exceptions, there are generally only response timeout exceptions, which are handled by the daemon thread AutoGCFlux.