Apigee Edge adds proxy chaining support - internal beta

13 30 6,123

If you are part of our SE or CS team, you would have heard of the term "proxy chaining" a lot in the last few months. Apigee Edge finally supports proxy chaining in an attempt to optimise the network route for target endpoints, which are nothing but api proxies running on Edge.

Let's take a very simple example. Let's say I have 2 api proxies both deployed to my org "edge" in the "test" environment. Let's call these two proxies as apigee-proxy and apigee-target. Following are the proxy endpoints for these two api proxies:

apigee-proxy: http://apigee-edge-test.apigee.net/apigee/proxy
apigee-target: http://apigee-edge-test.apigee.net/apigee/target

The target endpoint for apigee-proxy is the proxy endpoint of apigee-target api proxy. In the current version of Edge, if we have to reference the target we would do something like:

    <HTTPTargetConnection>
        <URL>http://apigee-edge-test.apigee.net/apigee/target</URL>
    </HTTPTargetConnection>

where apigee-edge-test.apigee.net is my virtual host alias and /apigee/target is the base path of apigee-target api proxy.

What this means is an extra network hop, because the request has to be router through ELB>Router>MP runtime path, just like any other api proxy call. With proxy-chaining, you should be able to reference the target endpoint locally, without having to make that extra hop. This would require slight changes to the apigee-proxy api though, which is as follows:

    <!--
    <HTTPTargetConnection>
        <URL>http://apigee-func-test.e2e.apigee.net/apigee/target</URL>
    </HTTPTargetConnection>
    -->
    <LocalTargetConnection>
        <APIProxy>apigee-target</APIProxy>
        <ProxyEndpoint>default</ProxyEndpoint>
    </LocalTargetConnection>

So instead of specifying the proxy endpoint as the URL for HTTPTargetConnection, you define something called LocalTargetConnection with the following elements:

APIProxy: Api proxy name that you want to reference in the local target connection

ProxyEndpoint: Proxy Endpoint name that you want to be reference as the target.

These 2 would let you uniquely identify the target and allow the request to be router locally to that target. Instead of Api proxy name and Proxy Endpoint, you can also specify base path like below:

<LocalTargetConnection>
        <Path>/apigee/target</Path>
</LocalTargetConnection>

This would essentially make a http call to http://localhost:8998/apigee/target the the message-processor not go through the ELB>Router>MP route thus optimising the target endpoint routing.

I am attaching the same api proxy bundles so that folks can start playing around it and give some great feedback on the feature. Remember this feature is still an "internal beta" and we haven't published it officially. This feature is currently available in the E2E planet but would soon be available in enterprise cloud, once the 150930 release is pushed out. We need to figure out a few things like validation cases, accounting for proxy calls in analytics, target flow variables when local target reference is used, trace UI etc. before making it official. Any feedback would only allow us to improve this feature further and make it a real value proposition for our customers.

Comments
adas
Participant V

@Dino, @sarthak @Diego Zuluaga @David Allen @Mukundha Madhavan @Maruti Chand hoping to get some feedback from you guys...

ceber
Staff

Can we use LocalTargetConnection instead of HTTPTargetConnection in the service callout policy?

adas
Participant V
@Carlos Eberhardt

Yes you can. The construct would be similar to what I have shown above.

sarthak
Participant V

@arghya das Thanks a lot for letting us know about this feature. This is definitely a long awaited feature.

Can you elaborate about the use cases which this feature will help to accomplish ? I would think proxy chaining is a way of achieving "global" policies eg. If an enterprise do not want to create a audit logging policy, authentication policy etc. across each proxy then they would define all of those in one proxy which then call another proxy. Is this the primary use case you are also thinking ? Or there are other use cases too ?

If above is correct then I might end up having multiple proxies chained together. One before my actual proxy and one after that and any number in between. Won't it become a management overhead ?

Also if a customer has many proxies and some are "global" and others are calling the actual target I think if there is someway to identify that from the proxy listing page (might be a filter using which I can search) that will help quite a bit. We can definitely say follow some proxy naming conventions but if something better can be done then proxy management might be easier.

I will add more comments (If I have) once I get a chance to play with this.

adas
Participant V

@sarthak Yes you are absolutely right. One of the major usecases is global proxies (its a slightly logn shot though). Apart from that optimising the network route I mentioned was definitely one of the motivations.

Some time back we introduced a feature by which you could control the number of circular references in a proxy. That would apply here as well, so the number of proxies that can be chained would have a finite limit.

I like the idea of flagging the proxies which are being used as local targets, in the UI so that we know what are the proxies and which all proxies are calling them. I was planning to open a new JIRA story for that.

sarthak
Participant V

@arghya das If I keep aside global proxies/policies use case , why else would I care about the network optimization which you mentioned ? For what other use cases it is applicable ?

adas
Participant V

@sarthak Like I said, global policies is the primary use case. Apart from that if you want to make service callouts or target api calls to endpoints which in turn are api proxies hosted on edge (which many of our customers do, not necessarily to overcome the global policies limitation), this would help there. At this point I don't think we have any other major use cases in mind.

Another potential use case I see is to use this feature as an outbound proxy, so all api-proxies that eventually call a target can go through this, which means when you change things such as target endpoint or sslinfo etc. you only make the change at one point. In a way, it goes back to the idea of global policies though, but a slightly different variation. I am sure there would be more, as we start exploring the opportunities.

sarthak
Participant V

Ok got it, that makes sense.

sgilson
Participant V

@arghya das Should the target-url end in "target"? Currently, it is:

apigee-target: http://apigee-edge-test.apigee.net/apigee/proxy

Should it be:

apigee-target: http://apigee-edge-test.apigee.net/apigee/target

Stephen

adas
Participant V

Thanks. I made that change earlier, not sure why it never got reflected. Updated again.

Not applicable

Thanks @arghya das. Many folks in CS are looking for this feature. I'm looking at you @srichardson, @Hansel Miranda, @dmehi, @Alex Koo.

Alex and I were discussing about it - if one wanted to avoid the extra hop from Node.js, would you just make an http call as localhost? Also, is there any benchmark with and without proxy chaining to see what improvements we get with a simple passthrough api proxy? I'm being lazy :-P, we can go ahead and try it and figure it out ourselves,

adas
Participant V

@Diego Zuluaga I will be doing the benchmarks with/without proxy chaining for a simple proxy. Regarding the node.js scenario, can give a little bit of detail about what exactly you are trying to do ?

Not applicable

Thanks @arghya das. A common scenario in Node.js would be similar to what I believe @sarthak mentioned before for XML-based API Proxies, reusability. So if a few Node.js API Proxies are required to leverage logging or security features for instance, they wouldn't need to duplicate the same code on each of them. I understand that you could leverage Express Middleware NPM private modules, but API proxy chaining also seems a workable solution as well.

DChiesa
Staff

@arghya das - I see how it would work, and it's a very clean way to specify a local target. It DOES solve the problem of "proxy chaining" about as efficiently as possible, if the goal is to chain proxies.

However I think the original goal, the thing people are asking for, is not to chain proxies. The real goal is "re-use proxy logic." Rather that being an end-goal, "chaining proxies" is a proposed solution for that goal. And if our main goal is "Re-use proxy logic" then I think proxy chaining is the wrong solution.

For one thing, making an http call out to port 8998 in order to re-use logic will lead to perf challenges at high concurrency. You identified some other issues - like analytics, and the complete loss of request context when calling the local target. Solving any of those problems is going to be messy and expensive, to the extent that I don't think we should solve them. For those reasons I think we should dismiss a general solution for "proxy logic re-use" that involves http communication.

I think we need something that involves Java calls only - no network calls and no IO. The analogy of "abstract proxies" with inheritance is appealing. @David Padgett may have more on this.

On the other hand there may be exceptional cases where "chaining proxies" is just what someone wants. I cannot think of a case right now, but it is possible. In that case, this will be a nice solution. I think we should be careful about recommending it, and using it for general re-use purposes, though.

ceber
Staff

I don't think it's "exceptional" cases only. This is a nice solution for building APIs on top of APIs, especially if the base APIs are more generic "micro-services" APIs and the second level APIs are app-specific. Whether or not it's a great solution for generically re-using proxy logic, up for debate.

Not applicable

My two cents. I agree with both of you. Therefore, I think we need both solutions.

1. Reusing API Proxy code (Dino). In this case, we do some not so elegant solutions such us search and replacing text in XML files with Maven plugins. In the Java world, you would use Maven or Grails, in Node.js, you would use NPM (this one works just fine). For XML policies, we don't have a clean solution for it, though.

2. Reusing APIs at HTTP level (Carlos). My understanding of API proxy chaining is trying to address this use case while reducing a network call. So for instance, I can build a more CRUD API proxy, which is leveraged by another API, which provides some mashup capabilities catered for a specific audience. My concern with this approach is that by leveraging locahost in the API chain, we're creating a monolithic application that depends on another app. In the world of Micro services, this approach would not be recommended, as it makes the consumer facing API too tightly coupled with the underlying APIs over the same machine, making it difficult to scale and apply separation of concerns. I think by benchmarking how bad it is a network call vs. a localhost, we can assess whether or not API proxy chaining is necessary. I believe some customers iare willing to sacrifice latency degradation to some degree to gain more scalability and reduction of complexity. So, similar to high vs. eventual consistency, in which customers are willing to take the hit to gain high availability.

Not applicable

Hi Dino, I had started to implement this via a direct java call, but so much of the message processor code assumes an underlying socket that it became quite complicated. The main advantage of doing it this way is we are reusing all the existing code so we will be completely compatible with existing behavior (including bug compatible). The performance cost of a loopback http call is low, a few milliseconds at most, so I think this is an acceptable way to achieve the goal. On the second issue of request context. The chained proxy can inherit the message context of the outer proxy. It doesn't do that now because as you say right now we are just trying to solve the narrow problem of proxy chaining. But later for global proxies and "re-use proxy logic" problem we would pass the outer message context to the inner proxy one so that variables set in the original context would be visible, and it would show up as one call in AX with complete latency times. And, depending on how we display it in the UI, it might not even be evident that proxy chaining was the mechanism that we used.

Not applicable

Hi, Just to clarify. When we implement Global policies we will use proxy chaining under the hood. The global proxies will be managed separately and at runtime the implementation will dynamically chain the request 1st through the global proxy and then through the 'real' proxy. The users will not be aware that we are using proxy chaining to achieve this. The same is true for the "re-use proxy logic" that Dino mentioned below.

DChiesa
Staff

Just seeing this now... This makes sense. If the loopback is fast, and if the io behavior is stable and predictable at high load, and if the initial message context is available in the "chained" proxy, I'd think this approach would be useful for reusing API Proxy code.

sgopalam
Participant I

@arghya das and @Peter Johnson is this proxy chaining feature only available as a target endpoint definition? Is there a way to use javascript or node.js code to refer to the internal chaining flow? i.e can I use javascript and construct the URL as http://localhost:8998/apigee/target and make the proxy chaining call from there?

adas
Participant V

@sgopalam@apigee.com No. That is not advised since we may block localhost calls on the MP for security reasons. Also MP http port can change so it would cause additional overhead on the proxy developers. Right now its only available for target endpoint in target and service callouts. We think we might be able to add it for nodejs and javascript too, but that work has not yet begun.

Not applicable

Hi,

I have tried to do this in my service callout. Where the target will point to a node.js script. However, when I try and use LocalTargetConnection, I get the following error. Does anyone know what I am doing wrong?

"Error creating object. Failed to import the bundle : java.lang.ClassCastException: org.apache.xerces.dom.ElementNSImpl cannot be cast to com.apigee.messaging.config.beans.TargetConnection."

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ServiceCallout async="false" continueOnError="false" enabled="true" name="callout_verify_signed_state">
    <DisplayName>callout_verify_signed_state</DisplayName>
    <Properties/>
    <Request clearPayload="true" variable="signedStateRequest">
        <Set>
            <Headers>
                <Header name="Content-Type">application/x-www-form-urlencoded</Header>
            </Headers>
            <FormParams>
                <FormParam name="callbackState">{callbackState}</FormParam>
            </FormParams>
        </Set>
        <IgnoreUnresolvedVariables>false</IgnoreUnresolvedVariables>
    </Request>
    <Response>signedStateResponse</Response>
    <LocalTargetConnection>
        <APIProxy>sso</APIProxy>
        <ProxyEndpoint>default</ProxyEndpoint>
    </LocalTargetConnection>
</ServiceCallout>

Not applicable

Which version of OPDK have this

Not applicable

Which version of OPDK have support for 'LocalTargetConnection' ? We are using OPDK v4.15.07.00 ?

adas
Participant V

@Hemana opdk 1601 has all the changes from the runtime perspective however 1605 would ship with all the management UI changes for the proxy editor with proxy chaining support.

adas
Participant V

@marlene.pecotich are you trying this on cloud or on premise ? Can you share your proxy bundles for both both the proxies, for me to take a look.

maivizhi_arunag
Participant IV

Thanks for the info @arghya das.

Glad that i have achieved the same using Service callout and the response was successful.My query is that

  1. Can i achive the same functionality(Proxy Chaining) in JavaScript?
  2. If so , a sample usecase would be helpful

Thanks in Advance!

maivizhi_arunag
Participant IV

any updates?

adas
Participant V
@maivizhi

Proxy chaining support for javascript is not available yet. As a workaround you can try doing this, but its not a recommended approach:

If your proxy basepath that you want to call via chaining is /v1/chain, then from your javascript you can call http://localhost:8998/v1/chain. The default http port on the message processors is 8998 (which is configurable), so you can hit the request locally from another proxy on that port using the basepath. I say its not recommended since the http port on the message processors is configurable and is an internal property that can change in future. We were looking at extending the proxy chaining feature to javascript but its not implemented yet.

Not applicable

@arghya das

For a number of reasons I am not going to be able to bring my on prem environment to 16.01 until (at the earliest) November 2016...

Can you confirm which versions of on prem are able to use proxy chaining? we have a client requirement for this now....

Version history
Last update:
‎09-29-2015 10:53 PM
Updated by: