JEP 321: HTTP Client (Standard)

classic Classic list List threaded Threaded
25 messages Options
12
Reply | Threaded
Open this post in threaded view
|

JEP 321: HTTP Client (Standard)

mark.reinhold
New JEP Candidate: http://openjdk.java.net/jeps/321

- Mark
Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

David Lloyd-2
On Mon, Dec 4, 2017 at 10:17 AM,  <[hidden email]> wrote:
> New JEP Candidate: http://openjdk.java.net/jeps/321

I have concerns.

This will be the first public, NIO-based, asynchronous/non-blocking
network protocol API introduced into the JDK proper, _ever_.

First, I want to note that the API seems to bear no resemblance
whatsoever with the asynchronous NIO.2 API.  Now I'm no fan of that
API as it stands for a couple of reasons, but nevertheless it calls
into question either the validity of the HTTP API as it stands, or the
scope of reusability of the NIO.2 API.

With that items put aside: there are a wide variety of mature,
non-blocking network protocol implementations out there, with
literally thousands of years of experience distributed amongst their
authors, maintainers, supporters, and communities, none of which were
used as a model.  There was, as far as I can see, no kind of study of
existing non-blocking approaches in Java, and their strengths and
weaknesses; there was no round table of engineers with experience in
this field, talking about what works and what doesn't work.

Some new, seemingly general-purpose, concepts are introduced by the
code base, for example: ByteBufferReference, and ByteBufferPool.  Are
these strategies that should be promoted to NIO proper?  If not, then
are they _really_ right for this particular use case, particularly if,
for some reason, a _second_ non-blocking network protocol API might be
introduced some day, probably duplicating these concepts?

Making this thing be the first real platform NIO-based asynchronous
network protocol API, yet being completely removed from the previous
NIO.2 asynchronous APIs and any other existing stable, mature API,
should be done very carefully and deliberately, and perhaps most
importantly, incrementally: first, establish a non-blocking byte
stream API that makes sense generally, and bring that into NIO
(NIO.3?); then, perhaps, enhancements to byte buffers to better
support efficient pooling.  By the time that point is reached, it is
hopefully rapidly becoming obvious that this is not something that
should be taken lightly.

I believe that most third-party implementations are taken less lightly
than this seems to have been.  I and my team have been developing an
asynchronous/non-blocking NIO library for ten years now, and while I'm
proud of our work and the discoveries we've made, I am realistic about
the fact that it's still pretty far from as good as it could be (not
in the least part due to existing platform limitations), certainly far
from something I'd say "hey let's standardize this as is".  I think
that to standardize something of this type that was just written over
the past 18-odd months reflects, to put it kindly, some pretty
incredible confidence that I wish I shared.

Speaking *solely* in the interests of platform quality and integrity,
I think that before _any_ high-level non-blocking/asynchronous
protocol API is ever introduced into the platform, it would be an
incredible waste to not have some kind of design consultation with
other industry experts.  Now I'm not suggesting that a JDK API would
have to be _agreeable_ to every expert, as we all know that is
basically impossible; but at the very minimum, I am very confident
that we can tell you what _doesn't_ work and the pitfalls we've found
along the way, as well as what each of us would consider to be an
ideal API, and that is information that has incredible value.

Talking about introducing the first-ever non-blocking protocol API
into the platform, at _this_ stage, seems premature and needlessly
risky.  I would suggest that maybe it's best for the API to stick to
blocking I/O, at least for now.  Or else, take it outside of the
platform, and let it mature in the wild where it can evolve without an
overbearing concern for compatibility for a decade or so (no, I'm not
kidding).  As long as this thing lives in the JDK, but isn't
standardized, it's probably not going to be used heavily enough to
really feel out its weak points.  And once it's in, its ability to
evolve is severely hampered by compatibility constraints.

I feel like it is impossible to over-emphasize the difficulty of the
problem of non-blocking I/O when it comes to interactions with user
programs.  Though the fruits of such an effort are probably small in
terms of API surface, the complexity is hard: hard enough that it is,
in my mind, a project of a larger scale, maybe JSR scale.  And the
benefit is potentially large: large enough that it could change the
landscape of other specifications and network applications.  Or at
least, I think so, which is why I've spent so many years of my life in
pursuit of such a thing.

--
- DML
Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

Norman Maurer
Well put David,

I couldn’t agree more .... I would even go this far and say this is not something I would include in the platform itself at all.

Bye
Norman


> Am 04.12.2017 um 19:41 schrieb David Lloyd <[hidden email]>:
>
>> On Mon, Dec 4, 2017 at 10:17 AM,  <[hidden email]> wrote:
>> New JEP Candidate: http://openjdk.java.net/jeps/321
>
> I have concerns.
>
> This will be the first public, NIO-based, asynchronous/non-blocking
> network protocol API introduced into the JDK proper, _ever_.
>
> First, I want to note that the API seems to bear no resemblance
> whatsoever with the asynchronous NIO.2 API.  Now I'm no fan of that
> API as it stands for a couple of reasons, but nevertheless it calls
> into question either the validity of the HTTP API as it stands, or the
> scope of reusability of the NIO.2 API.
>
> With that items put aside: there are a wide variety of mature,
> non-blocking network protocol implementations out there, with
> literally thousands of years of experience distributed amongst their
> authors, maintainers, supporters, and communities, none of which were
> used as a model.  There was, as far as I can see, no kind of study of
> existing non-blocking approaches in Java, and their strengths and
> weaknesses; there was no round table of engineers with experience in
> this field, talking about what works and what doesn't work.
>
> Some new, seemingly general-purpose, concepts are introduced by the
> code base, for example: ByteBufferReference, and ByteBufferPool.  Are
> these strategies that should be promoted to NIO proper?  If not, then
> are they _really_ right for this particular use case, particularly if,
> for some reason, a _second_ non-blocking network protocol API might be
> introduced some day, probably duplicating these concepts?
>
> Making this thing be the first real platform NIO-based asynchronous
> network protocol API, yet being completely removed from the previous
> NIO.2 asynchronous APIs and any other existing stable, mature API,
> should be done very carefully and deliberately, and perhaps most
> importantly, incrementally: first, establish a non-blocking byte
> stream API that makes sense generally, and bring that into NIO
> (NIO.3?); then, perhaps, enhancements to byte buffers to better
> support efficient pooling.  By the time that point is reached, it is
> hopefully rapidly becoming obvious that this is not something that
> should be taken lightly.
>
> I believe that most third-party implementations are taken less lightly
> than this seems to have been.  I and my team have been developing an
> asynchronous/non-blocking NIO library for ten years now, and while I'm
> proud of our work and the discoveries we've made, I am realistic about
> the fact that it's still pretty far from as good as it could be (not
> in the least part due to existing platform limitations), certainly far
> from something I'd say "hey let's standardize this as is".  I think
> that to standardize something of this type that was just written over
> the past 18-odd months reflects, to put it kindly, some pretty
> incredible confidence that I wish I shared.
>
> Speaking *solely* in the interests of platform quality and integrity,
> I think that before _any_ high-level non-blocking/asynchronous
> protocol API is ever introduced into the platform, it would be an
> incredible waste to not have some kind of design consultation with
> other industry experts.  Now I'm not suggesting that a JDK API would
> have to be _agreeable_ to every expert, as we all know that is
> basically impossible; but at the very minimum, I am very confident
> that we can tell you what _doesn't_ work and the pitfalls we've found
> along the way, as well as what each of us would consider to be an
> ideal API, and that is information that has incredible value.
>
> Talking about introducing the first-ever non-blocking protocol API
> into the platform, at _this_ stage, seems premature and needlessly
> risky.  I would suggest that maybe it's best for the API to stick to
> blocking I/O, at least for now.  Or else, take it outside of the
> platform, and let it mature in the wild where it can evolve without an
> overbearing concern for compatibility for a decade or so (no, I'm not
> kidding).  As long as this thing lives in the JDK, but isn't
> standardized, it's probably not going to be used heavily enough to
> really feel out its weak points.  And once it's in, its ability to
> evolve is severely hampered by compatibility constraints.
>
> I feel like it is impossible to over-emphasize the difficulty of the
> problem of non-blocking I/O when it comes to interactions with user
> programs.  Though the fruits of such an effort are probably small in
> terms of API surface, the complexity is hard: hard enough that it is,
> in my mind, a project of a larger scale, maybe JSR scale.  And the
> benefit is potentially large: large enough that it could change the
> landscape of other specifications and network applications.  Or at
> least, I think so, which is why I've spent so many years of my life in
> pursuit of such a thing.
>
> --
> - DML
Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

Alan Bateman
In reply to this post by David Lloyd-2
On 04/12/2017 18:41, David Lloyd wrote:

> :
> Speaking *solely* in the interests of platform quality and integrity,
> I think that before _any_ high-level non-blocking/asynchronous
> protocol API is ever introduced into the platform, it would be an
> incredible waste to not have some kind of design consultation with
> other industry experts.  Now I'm not suggesting that a JDK API would
> have to be _agreeable_ to every expert, as we all know that is
> basically impossible; but at the very minimum, I am very confident
> that we can tell you what _doesn't_ work and the pitfalls we've found
> along the way, as well as what each of us would consider to be an
> ideal API, and that is information that has incredible value.
>
The HTTP client API has been an ongoing effort for several years, the
original JEP goes back to 2014. It was initially available in the
OpenJDK sandbox and in the JDK main-line before moving to an incubating
module in 2016. I can't tell if you've been following this project or
not but there has been lots of opportunity to try it out and provide
feedback on both the API and implementation.

You mention general-purpose concepts such as ByteBufferReference and
ByteBufferPool. Note that these are tiny implementation classes (150
lines in total) and not exposed in the API. Promoting these to java.nio
would be outside the scope of this API. If the buffer API were to add
such concepts in the future then there is nothing to stop the HTTP
client implementation making use in its implementation.

-Alan
Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

David Lloyd-2
On Mon, Dec 4, 2017 at 2:01 PM, Alan Bateman <[hidden email]> wrote:

> On 04/12/2017 18:41, David Lloyd wrote:
>>
>> :
>> Speaking *solely* in the interests of platform quality and integrity,
>> I think that before _any_ high-level non-blocking/asynchronous
>> protocol API is ever introduced into the platform, it would be an
>> incredible waste to not have some kind of design consultation with
>> other industry experts.  Now I'm not suggesting that a JDK API would
>> have to be _agreeable_ to every expert, as we all know that is
>> basically impossible; but at the very minimum, I am very confident
>> that we can tell you what _doesn't_ work and the pitfalls we've found
>> along the way, as well as what each of us would consider to be an
>> ideal API, and that is information that has incredible value.
>>
> The HTTP client API has been an ongoing effort for several years, the
> original JEP goes back to 2014. It was initially available in the OpenJDK
> sandbox and in the JDK main-line before moving to an incubating module in
> 2016. I can't tell if you've been following this project or not but there
> has been lots of opportunity to try it out and provide feedback on both the
> API and implementation.

I've had opportunity to give feedback, perhaps, though the API always
seemed incomplete.  At least nobody (that I saw) sent out a message
saying "Here it is, it's all done, what do you think?".  I've
certainly never had opportunity to try it out: given its status as an
incubating module present only in OpenJDK, the only people who are
really in a position to try it out are those using OpenJDK (as opposed
to other JDKs) with the flexibility to rewrite their use case if and
when the API changes status (being integrated or disappearing) or form
(evolving, presumably as a response to feedback), or people writing
throwaway applications for the sole purpose of testing this particular
API.  But those who are best able to make this kind of determination
are those who need to be able to immediately use the API, and rely
upon it indefinitely (for good or bad), which is definitely not the
case for anything incubated in the OpenJDK project.  Why take the risk
when you can use the Apache HTTP client instead?

The lack of feedback on a proposed standard should not be considered a
tacit endorsement of it - quite the opposite in fact.  It should be
considered overwhelming disinterest (i.e. there's nothing particularly
compelling about it), or at absolute best, insufficient information to
make a determination.  The burden should be on the proposer to
evangelize their idea and seek out feedback, rather than waiting for
interest to appear and feedback to come to them.

> You mention general-purpose concepts such as ByteBufferReference and
> ByteBufferPool. Note that these are tiny implementation classes (150 lines
> in total) and not exposed in the API.

Yes they are, currently - at least ByteBufferReference is at the heart of it:

http://hg.openjdk.java.net/jdk/jdk/file/6dcbdc9f99fc/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/AsyncConnection.java#l61

And that class relies directly on ByteBufferPool in its own API.

Unless the jdk/jdk branch does not reflect the latest incarnation of
this JEP, in which case I definitely haven't have been up to date with
it, despite following this list.

> Promoting these to java.nio would be
> outside the scope of this API. If the buffer API were to add such concepts
> in the future then there is nothing to stop the HTTP client implementation
> making use in its implementation.

See above.


--
- DML
Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

David Lloyd-2
On Mon, Dec 4, 2017 at 3:56 PM, David Lloyd <[hidden email]> wrote:

> On Mon, Dec 4, 2017 at 2:01 PM, Alan Bateman <[hidden email]> wrote:
>> On 04/12/2017 18:41, David Lloyd wrote:
>>>
>>> :
>>> Speaking *solely* in the interests of platform quality and integrity,
>>> I think that before _any_ high-level non-blocking/asynchronous
>>> protocol API is ever introduced into the platform, it would be an
>>> incredible waste to not have some kind of design consultation with
>>> other industry experts.  Now I'm not suggesting that a JDK API would
>>> have to be _agreeable_ to every expert, as we all know that is
>>> basically impossible; but at the very minimum, I am very confident
>>> that we can tell you what _doesn't_ work and the pitfalls we've found
>>> along the way, as well as what each of us would consider to be an
>>> ideal API, and that is information that has incredible value.
>>>
>> The HTTP client API has been an ongoing effort for several years, the
>> original JEP goes back to 2014. It was initially available in the OpenJDK
>> sandbox and in the JDK main-line before moving to an incubating module in
>> 2016. I can't tell if you've been following this project or not but there
>> has been lots of opportunity to try it out and provide feedback on both the
>> API and implementation.
>
> I've had opportunity to give feedback, perhaps, though the API always
> seemed incomplete.  At least nobody (that I saw) sent out a message
> saying "Here it is, it's all done, what do you think?".  I've
> certainly never had opportunity to try it out: given its status as an
> incubating module present only in OpenJDK, the only people who are
> really in a position to try it out are those using OpenJDK (as opposed
> to other JDKs) with the flexibility to rewrite their use case if and
> when the API changes status (being integrated or disappearing) or form
> (evolving, presumably as a response to feedback), or people writing
> throwaway applications for the sole purpose of testing this particular
> API.  But those who are best able to make this kind of determination
> are those who need to be able to immediately use the API, and rely
> upon it indefinitely (for good or bad), which is definitely not the
> case for anything incubated in the OpenJDK project.  Why take the risk
> when you can use the Apache HTTP client instead?
>
> The lack of feedback on a proposed standard should not be considered a
> tacit endorsement of it - quite the opposite in fact.  It should be
> considered overwhelming disinterest (i.e. there's nothing particularly
> compelling about it), or at absolute best, insufficient information to
> make a determination.  The burden should be on the proposer to
> evangelize their idea and seek out feedback, rather than waiting for
> interest to appear and feedback to come to them.
>
>> You mention general-purpose concepts such as ByteBufferReference and
>> ByteBufferPool. Note that these are tiny implementation classes (150 lines
>> in total) and not exposed in the API.
>
> Yes they are, currently - at least ByteBufferReference is at the heart of it:
>
> http://hg.openjdk.java.net/jdk/jdk/file/6dcbdc9f99fc/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/AsyncConnection.java#l61

I see my error, this is a non-public interface.  Nonetheless, I'm not
sure that it's really safe to say that this is ready.  Has there been
_any_ external feedback on this API?

--
- DML
Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

Chris Hegarty
In reply to this post by David Lloyd-2

On 4 Dec 2017, at 21:56, David Lloyd <[hidden email]> wrote:
...
You mention general-purpose concepts such as ByteBufferReference and
ByteBufferPool. Note that these are tiny implementation classes (150 lines
in total) and not exposed in the API.

Yes they are, currently - at least ByteBufferReference is at the heart of it:

http://hg.openjdk.java.net/jdk/jdk/file/6dcbdc9f99fc/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/AsyncConnection.java#l61

And that class relies directly on ByteBufferPool in its own API.

Unless the jdk/jdk branch does not reflect the latest incarnation of
this JEP, in which case I definitely haven't have been up to date with
it, despite following this list.

Sorry, before replying further, there is clearly some confusion here. As Alan already said, the above types are NOT part of the API, they are non-public implementation.

The ‘http-client-branch’ of the JDK sandbox [1] contains the very latest code.

-Chris.

Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

Chris Hegarty
In reply to this post by David Lloyd-2

On 4 Dec 2017, at 22:03, David Lloyd <[hidden email]> wrote:
...

You mention general-purpose concepts such as ByteBufferReference and
ByteBufferPool. Note that these are tiny implementation classes (150 lines
in total) and not exposed in the API.

Yes they are, currently - at least ByteBufferReference is at the heart of it:

http://hg.openjdk.java.net/jdk/jdk/file/6dcbdc9f99fc/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/AsyncConnection.java#l61

I see my error, this is a non-public interface.  Nonetheless, I'm not
sure that it's really safe to say that this is ready.  Has there been
_any_ external feedback on this API?

[ You can probably ignore my previous email, I sent it before receiving your reply. The confusion seems to have been resolved now. ]

Yes, there has been external feedback on the API. I’ll dig it up, I need to trawl the net-dev archives and JIRA issues.

For your, and others, reference, here is a snapshot of the latest API, built from the ‘http-client-branch’ of the sandbox:


-Chris.


Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

David Lloyd-2
On Mon, Dec 4, 2017 at 5:01 PM, Chris Hegarty <[hidden email]> wrote:

> On 4 Dec 2017, at 22:03, David Lloyd <[hidden email]> wrote:
>
> ...
>
> You mention general-purpose concepts such as ByteBufferReference and
> ByteBufferPool. Note that these are tiny implementation classes (150 lines
> in total) and not exposed in the API.
>
>
> Yes they are, currently - at least ByteBufferReference is at the heart of
> it:
>
> http://hg.openjdk.java.net/jdk/jdk/file/6dcbdc9f99fc/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/AsyncConnection.java#l61
>
>
> I see my error, this is a non-public interface.  Nonetheless, I'm not
> sure that it's really safe to say that this is ready.  Has there been
> _any_ external feedback on this API?
>
>
> [ You can probably ignore my previous email, I sent it before receiving your
> reply. The confusion seems to have been resolved now. ]
>
> Yes, there has been external feedback on the API. I’ll dig it up, I need to
> trawl the net-dev archives and JIRA issues.
>
> For your, and others, reference, here is a snapshot of the latest API, built
> from the ‘http-client-branch’ of the sandbox:
>
>
> http://cr.openjdk.java.net/~chegar/httpclient/javadoc/api/jdk/incubator/http/package-summary.html

Thanks.  If you don't mind answering one more question: is there any
possibility to intercept authentication completely?  There does not
seem to be a lot of documentation about authentication in this API, or
what happens (for example) if there is no Authenticator.

--
- DML
Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

Alan Bateman
In reply to this post by David Lloyd-2
On 04/12/2017 21:56, David Lloyd wrote:

> :
> I've had opportunity to give feedback, perhaps, though the API always
> seemed incomplete.  At least nobody (that I saw) sent out a message
> saying "Here it is, it's all done, what do you think?".  I've
> certainly never had opportunity to try it out: given its status as an
> incubating module present only in OpenJDK, the only people who are
> really in a position to try it out are those using OpenJDK (as opposed
> to other JDKs) with the flexibility to rewrite their use case if and
> when the API changes status (being integrated or disappearing) or form
> (evolving, presumably as a response to feedback), or people writing
> throwaway applications for the sole purpose of testing this particular
> API.  But those who are best able to make this kind of determination
> are those who need to be able to immediately use the API, and rely
> upon it indefinitely (for good or bad), which is definitely not the
> case for anything incubated in the OpenJDK project.
Incubator modules (JEP 11) is the means to get non-final APIs and
features into the hands of developers. In this case, the HTTP client was
an incubator module in JDK 9 and is proposed to continue (with a new
implementation and some API refinements [1]) as an incubator module in
JDK 10. So there has been lots of time to try out the API, send
feedback, contribute, etc. Yes, the onus is on interested developers to
get involved and there has been useful feedback on this mailing mail. If
you read JEP 11 then you'll know that an API or feature can't stay in
the incubator forever, it either moves forever or it is removed. In this
case, the API has been through numerous iterations and is looking quite
good, hence JEP 321 proposes to move it forward so that it can be
promoted to a platform module.

-Alan.

[1] http://mail.openjdk.java.net/pipermail/net-dev/2017-November/011017.html
Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

Chris Hegarty
In reply to this post by David Lloyd-2

> On 4 Dec 2017, at 23:09, David Lloyd <[hidden email]> wrote:
>> ...
>
> Thanks.  If you don't mind answering one more question: is there any
> possibility to intercept authentication completely?

As with HttpURLConnection, if no Authenticator is set then, application code should be able to manually inspect and set the appropriate headers to perform authentication.

-Chris.

Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

dalibor topic-2
In reply to this post by David Lloyd-2
On 04.12.2017 22:56, David Lloyd wrote:
> saying "Here it is, it's all done, what do you think?".  I've
> certainly never had opportunity to try it out: given its status as an
> incubating module present only in OpenJDK, the only people who are
> really in a position to try it out are those using OpenJDK (as opposed
> to other JDKs)

That's not quite correct. The jdk.incubator.httpclient module is part of
Oracle JDK 9, as well. It has been part of the JDK 9 Early Access builds
since about a year ago, afaik. The Early Access builds can be found at
jdk.java.net, fwiw.

> But those who are best able to make this kind of determination
> are those who need to be able to immediately use the API, and rely
> upon it indefinitely (for good or bad), which is definitely not the
> case for anything incubated in the OpenJDK project.

This seems to be a more general criticism of the incubator module
mechanism as defined in JEP 11, rather than directed at this API
specifically. It wasn't raised on jdk-dev when JEP 11 was discussed
about a year ago, fwiw.

I would take issue with the qualifier 'best' in the above, as the
qualification offered for making best determinations is necessity,
rather than expertise, for example. In some cases, both properties may
hold, of course, but I don't think that's a valid assertion in general.

cheers,
dalibor topic
--
<http://www.oracle.com> Dalibor Topic | Principal Product Manager
Phone: +494089091214 <tel:+494089091214> | Mobile: +491737185961
<tel:+491737185961>

ORACLE Deutschland B.V. & Co. KG | Kühnehöfe 5 | 22761 Hamburg

ORACLE Deutschland B.V. & Co. KG
Hauptverwaltung: Riesstr. 25, D-80992 München
Registergericht: Amtsgericht München, HRA 95603

Komplementärin: ORACLE Deutschland Verwaltung B.V.
Hertogswetering 163/167, 3543 AS Utrecht, Niederlande
Handelsregister der Handelskammer Midden-Niederlande, Nr. 30143697
Geschäftsführer: Alexander van der Ven, Jan Schultheiss, Val Maher

<http://www.oracle.com/commitment> Oracle is committed to developing
practices and products that help protect the environment
Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

David Lloyd-2
On Tue, Dec 5, 2017 at 5:48 AM, dalibor topic <[hidden email]> wrote:

> On 04.12.2017 22:56, David Lloyd wrote:
>>
>> saying "Here it is, it's all done, what do you think?".  I've
>> certainly never had opportunity to try it out: given its status as an
>> incubating module present only in OpenJDK, the only people who are
>> really in a position to try it out are those using OpenJDK (as opposed
>> to other JDKs)
>
> That's not quite correct. The jdk.incubator.httpclient module is part of
> Oracle JDK 9, as well. It has been part of the JDK 9 Early Access builds
> since about a year ago, afaik. The Early Access builds can be found at
> jdk.java.net, fwiw.

Sure, but that's all the same ecosystem.  An organization tied to,
say, the IBM JDK won't have access to these.

>> But those who are best able to make this kind of determination
>> are those who need to be able to immediately use the API, and rely
>> upon it indefinitely (for good or bad), which is definitely not the
>> case for anything incubated in the OpenJDK project.
>
> This seems to be a more general criticism of the incubator module mechanism
> as defined in JEP 11, rather than directed at this API specifically. It
> wasn't raised on jdk-dev when JEP 11 was discussed about a year ago, fwiw.

Of course; sometimes a thing must be tried before the weaknesses are
apparent.  If we all designed perfect things from the start, we
wouldn't need standards and evolution. :)

--
- DML
Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

dalibor topic-2


On 05.12.2017 14:48, David Lloyd wrote:

> On Tue, Dec 5, 2017 at 5:48 AM, dalibor topic <[hidden email]> wrote:
>> On 04.12.2017 22:56, David Lloyd wrote:
>>>
>>> saying "Here it is, it's all done, what do you think?".  I've
>>> certainly never had opportunity to try it out: given its status as an
>>> incubating module present only in OpenJDK, the only people who are
>>> really in a position to try it out are those using OpenJDK (as opposed
>>> to other JDKs)
>>
>> That's not quite correct. The jdk.incubator.httpclient module is part of
>> Oracle JDK 9, as well. It has been part of the JDK 9 Early Access builds
>> since about a year ago, afaik. The Early Access builds can be found at
>> jdk.java.net, fwiw.
>
> Sure, but that's all the same ecosystem.  An organization tied to,
> say, the IBM JDK won't have access to these.

Fwiw, IBM's OpenJ9 builds for JDK 9 would seem to include this incubator
module as well. I'd naively assume the same to be the case for Azul's
JDK 9 builds, etc.

>> This seems to be a more general criticism of the incubator module mechanism
>> as defined in JEP 11, rather than directed at this API specifically. It
>> wasn't raised on jdk-dev when JEP 11 was discussed about a year ago, fwiw.
>
> Of course; sometimes a thing must be tried before the weaknesses are
> apparent.  If we all designed perfect things from the start, we
> wouldn't need standards and evolution. :)

Touché -

The sample size of one for modules going through the incubation module
mechanism may still be too small for a categorical critique, though. ;)

cheers,
dalibor topic
--
<http://www.oracle.com> Dalibor Topic | Principal Product Manager
Phone: +494089091214 <tel:+494089091214> | Mobile: +491737185961
<tel:+491737185961>

ORACLE Deutschland B.V. & Co. KG | Kühnehöfe 5 | 22761 Hamburg

ORACLE Deutschland B.V. & Co. KG
Hauptverwaltung: Riesstr. 25, D-80992 München
Registergericht: Amtsgericht München, HRA 95603

Komplementärin: ORACLE Deutschland Verwaltung B.V.
Hertogswetering 163/167, 3543 AS Utrecht, Niederlande
Handelsregister der Handelskammer Midden-Niederlande, Nr. 30143697
Geschäftsführer: Alexander van der Ven, Jan Schultheiss, Val Maher

<http://www.oracle.com/commitment> Oracle is committed to developing
practices and products that help protect the environment
Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

Viktor Klang
In reply to this post by David Lloyd-2
Hi David,

I think you raise some valid concerns, particularly with the byte buffer pools.

That said, I'm interested in knowing whether your concerns extend to choice of using the JDK9 Flow API for handling asynchronous IO?

Cheers,

(Adding my colleague, James Roper, to the conversation)

On Dec 4, 2017 19:42, "David Lloyd" <[hidden email]> wrote:
On Mon, Dec 4, 2017 at 10:17 AM,  <[hidden email]> wrote:
> New JEP Candidate: http://openjdk.java.net/jeps/321

I have concerns.

This will be the first public, NIO-based, asynchronous/non-blocking
network protocol API introduced into the JDK proper, _ever_.

First, I want to note that the API seems to bear no resemblance
whatsoever with the asynchronous NIO.2 API.  Now I'm no fan of that
API as it stands for a couple of reasons, but nevertheless it calls
into question either the validity of the HTTP API as it stands, or the
scope of reusability of the NIO.2 API.

With that items put aside: there are a wide variety of mature,
non-blocking network protocol implementations out there, with
literally thousands of years of experience distributed amongst their
authors, maintainers, supporters, and communities, none of which were
used as a model.  There was, as far as I can see, no kind of study of
existing non-blocking approaches in Java, and their strengths and
weaknesses; there was no round table of engineers with experience in
this field, talking about what works and what doesn't work.

Some new, seemingly general-purpose, concepts are introduced by the
code base, for example: ByteBufferReference, and ByteBufferPool.  Are
these strategies that should be promoted to NIO proper?  If not, then
are they _really_ right for this particular use case, particularly if,
for some reason, a _second_ non-blocking network protocol API might be
introduced some day, probably duplicating these concepts?

Making this thing be the first real platform NIO-based asynchronous
network protocol API, yet being completely removed from the previous
NIO.2 asynchronous APIs and any other existing stable, mature API,
should be done very carefully and deliberately, and perhaps most
importantly, incrementally: first, establish a non-blocking byte
stream API that makes sense generally, and bring that into NIO
(NIO.3?); then, perhaps, enhancements to byte buffers to better
support efficient pooling.  By the time that point is reached, it is
hopefully rapidly becoming obvious that this is not something that
should be taken lightly.

I believe that most third-party implementations are taken less lightly
than this seems to have been.  I and my team have been developing an
asynchronous/non-blocking NIO library for ten years now, and while I'm
proud of our work and the discoveries we've made, I am realistic about
the fact that it's still pretty far from as good as it could be (not
in the least part due to existing platform limitations), certainly far
from something I'd say "hey let's standardize this as is".  I think
that to standardize something of this type that was just written over
the past 18-odd months reflects, to put it kindly, some pretty
incredible confidence that I wish I shared.

Speaking *solely* in the interests of platform quality and integrity,
I think that before _any_ high-level non-blocking/asynchronous
protocol API is ever introduced into the platform, it would be an
incredible waste to not have some kind of design consultation with
other industry experts.  Now I'm not suggesting that a JDK API would
have to be _agreeable_ to every expert, as we all know that is
basically impossible; but at the very minimum, I am very confident
that we can tell you what _doesn't_ work and the pitfalls we've found
along the way, as well as what each of us would consider to be an
ideal API, and that is information that has incredible value.

Talking about introducing the first-ever non-blocking protocol API
into the platform, at _this_ stage, seems premature and needlessly
risky.  I would suggest that maybe it's best for the API to stick to
blocking I/O, at least for now.  Or else, take it outside of the
platform, and let it mature in the wild where it can evolve without an
overbearing concern for compatibility for a decade or so (no, I'm not
kidding).  As long as this thing lives in the JDK, but isn't
standardized, it's probably not going to be used heavily enough to
really feel out its weak points.  And once it's in, its ability to
evolve is severely hampered by compatibility constraints.

I feel like it is impossible to over-emphasize the difficulty of the
problem of non-blocking I/O when it comes to interactions with user
programs.  Though the fruits of such an effort are probably small in
terms of API surface, the complexity is hard: hard enough that it is,
in my mind, a project of a larger scale, maybe JSR scale.  And the
benefit is potentially large: large enough that it could change the
landscape of other specifications and network applications.  Or at
least, I think so, which is why I've spent so many years of my life in
pursuit of such a thing.

--
- DML
Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

Chris Hegarty
Viktor,

I would like to address your first comment only, as your question is
directed to someone else.

> On 6 Dec 2017, at 10:01, Viktor Klang <[hidden email]> wrote:
> ..
> I think you raise some valid concerns, particularly with the byte buffer pools.

The conversation got off to a bad start as there was a misunderstanding
about what was actually being proposed, so I would like to clear that
up.

The reference to byte buffer pools is not relevant here. They were
introduced as a performance optimization that allowed better reuse of
byte buffers between the socket channel and the SSL engine, in the
implementation. That's all, nothing more. They have no bearing on the
API, and this JEP is not proposing to make any changes in the NIO area.

What is relevant is the use of byte buffers as a Flow of request and
response body data. The API provides no mechanism for reuse, or pooling,
of these byte buffers ( it did in a previous revision but was removed
because of its complexity ). The latest version of the API for
BodySubscriber [1] contains the following: “... the ByteBuffers,
once passed to the subscriber, are no longer used by the HTTP client.”,
and the BodyPublisher [2] contains: “Instances of ByteBuffer published
by the publisher must be allocated by the publisher, and must not be
accessed after being handed over to the library.". I accept that this
could be made more clear in the API.

The API uses byte buffers as carriers of data in a way that is
consistent with other APIs. In the case of the publisher, it is the
responsibility of the user to allocate the buffer and pass it to the
HTTP Client, after which it should not be modified by user code. In the
case of the subscriber, once the byte buffer is passed to `onNext`, it
is then the sole responsibility of the subscriber.

The primary motivation for the use byte buffers, as described above, is
to provide maximum flexibility to an implementation to avoid copying
and buffering of data.

---

Through contacts from Viktor, we have recently received some feedback on
the use of the body subscriber and publisher in the API. This feedback
is very helpful and we will soon send out a proposal that will better
support integration with existing publishers and subscribers.  [ I will
work with Viktor to bring this to the mailing list ].


-Chris.

[1] http://cr.openjdk.java.net/~chegar/httpclient/javadoc/api/jdk/incubator/http/HttpResponse.BodySubscriber.html
[2] http://cr.openjdk.java.net/~chegar/httpclient/javadoc/api/jdk/incubator/http/HttpRequest.BodyPublisher.html
Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

Viktor Klang
Thanks for those clarifcations, Chris, I really appreciate it!

--
Cheers,

On Dec 6, 2017 13:31, "Chris Hegarty" <[hidden email]> wrote:
Viktor,

I would like to address your first comment only, as your question is
directed to someone else.

> On 6 Dec 2017, at 10:01, Viktor Klang <[hidden email]> wrote:
> ..
> I think you raise some valid concerns, particularly with the byte buffer pools.

The conversation got off to a bad start as there was a misunderstanding
about what was actually being proposed, so I would like to clear that
up.

The reference to byte buffer pools is not relevant here. They were
introduced as a performance optimization that allowed better reuse of
byte buffers between the socket channel and the SSL engine, in the
implementation. That's all, nothing more. They have no bearing on the
API, and this JEP is not proposing to make any changes in the NIO area.

What is relevant is the use of byte buffers as a Flow of request and
response body data. The API provides no mechanism for reuse, or pooling,
of these byte buffers ( it did in a previous revision but was removed
because of its complexity ). The latest version of the API for
BodySubscriber [1] contains the following: “... the ByteBuffers,
once passed to the subscriber, are no longer used by the HTTP client.”,
and the BodyPublisher [2] contains: “Instances of ByteBuffer published
by the publisher must be allocated by the publisher, and must not be
accessed after being handed over to the library.". I accept that this
could be made more clear in the API.

The API uses byte buffers as carriers of data in a way that is
consistent with other APIs. In the case of the publisher, it is the
responsibility of the user to allocate the buffer and pass it to the
HTTP Client, after which it should not be modified by user code. In the
case of the subscriber, once the byte buffer is passed to `onNext`, it
is then the sole responsibility of the subscriber.

The primary motivation for the use byte buffers, as described above, is
to provide maximum flexibility to an implementation to avoid copying
and buffering of data.

---

Through contacts from Viktor, we have recently received some feedback on
the use of the body subscriber and publisher in the API. This feedback
is very helpful and we will soon send out a proposal that will better
support integration with existing publishers and subscribers.  [ I will
work with Viktor to bring this to the mailing list ].


-Chris.

[1] http://cr.openjdk.java.net/~chegar/httpclient/javadoc/api/jdk/incubator/http/HttpResponse.BodySubscriber.html
[2] http://cr.openjdk.java.net/~chegar/httpclient/javadoc/api/jdk/incubator/http/HttpRequest.BodyPublisher.html
Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

David Lloyd-2
In reply to this post by Chris Hegarty
On Wed, Dec 6, 2017 at 6:31 AM, Chris Hegarty <[hidden email]> wrote:
> Viktor,
>
> The reference to byte buffer pools is not relevant here. They were
> introduced as a performance optimization that allowed better reuse of
> byte buffers between the socket channel and the SSL engine, in the
> implementation. That's all, nothing more. They have no bearing on the
> API, and this JEP is not proposing to make any changes in the NIO area.

+1, that was my fault, sorry about that.

> What is relevant is the use of byte buffers as a Flow of request and
> response body data. The API provides no mechanism for reuse, or pooling,
> of these byte buffers ( it did in a previous revision but was removed
> because of its complexity ). The latest version of the API for
> BodySubscriber [1] contains the following: “... the ByteBuffers,
> once passed to the subscriber, are no longer used by the HTTP client.”,
> and the BodyPublisher [2] contains: “Instances of ByteBuffer published
> by the publisher must be allocated by the publisher, and must not be
> accessed after being handed over to the library.".

Just out of curiosity, what kind of issues came up?  What did the
mechanism look like - was it just a callback to return depleted
buffers to the HTTP client or user (as appropriate)?

It sure would be nice to somehow finally tackle the problem of direct
buffer allocation, pooling, and freeing for good; it's a bit of a
nightmare right now.  The lack of a good, standard pooling strategy is
a big part of what makes me nervous about introducing an entire new
async paradigm based on buffers, particularly with no possibility for
pooling or reuse.  I have many thoughts in this area (*crowd groans*)
but it would be interesting to know what practical problems were
encountered.

> The API uses byte buffers as carriers of data in a way that is
> consistent with other APIs. In the case of the publisher, it is the
> responsibility of the user to allocate the buffer and pass it to the
> HTTP Client, after which it should not be modified by user code. In the
> case of the subscriber, once the byte buffer is passed to `onNext`, it
> is then the sole responsibility of the subscriber.
>
> The primary motivation for the use byte buffers, as described above, is
> to provide maximum flexibility to an implementation to avoid copying
> and buffering of data.

Is my reading of the API correct in that flow control is happening in
terms of buffers, not of bytes?  Could there ever be any odd effects
from very small or very large buffers passing through the plumbing?

--
- DML
Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

James Roper
On 7 December 2017 at 06:58, David Lloyd <[hidden email]> wrote:
On Wed, Dec 6, 2017 at 6:31 AM, Chris Hegarty <[hidden email]> wrote:

[snip]
 
> The primary motivation for the use byte buffers, as described above, is
> to provide maximum flexibility to an implementation to avoid copying
> and buffering of data.

Is my reading of the API correct in that flow control is happening in
terms of buffers, not of bytes?  Could there ever be any odd effects
from very small or very large buffers passing through the plumbing?

Your reading is correct. In my experience, it varies wildly by use case. In the technology I work with (Akka), we do exactly this, we have ByteStrings (essentially immutable byte buffer), and flow control is done on the number of ByteStrings, not the number of bytes in those strings. Generally, in reading, the size of ByteStrings is limited by a configurable amount, for example, 8kb. And then Akka's flow control will, by default, keep up to 8 ByteStrings in flight in its asynchronous processing pipeline. So we have a maximum buffer size of 64kb per connection. For most HTTP use cases, this is fine, something reading an HTTP message body might be collecting those buffers up to a maximum size of 100kb by default, and then parsing the buffer (eg, as json). So it's within the tolerances of what the amount of memory that the user expects to use per request. If the data read in to the buffers were very small, this would be due to the client trickle feeding the server - care must be taken on the server to ensure that if 8kb buffers are allocated for reads, but only a small amount of data is read, that these large buffers are released, and the small data copied to a small buffer.

I think where it can possible cause a problem is if for some reason something sending data is only generating small byte buffer chunks, but there's a long (and expensive) pipeline for the chunks to go through before they get written out. This is not a use case that we see that often, but I have seen it. The solution there is to either increase the number of elements in flight in the stream (most reactive streams implementations allow this to be done trivially), or to put an aggregating buffer in the middle before the expensive processing (again, streaming implementations such as RxJava, Reactor or Akka streams provide straight forward stages to do this).

One issue that I'm not sure about is the consequences of using direct buffers with regards to garbage collection. If direct buffers are never copied onto the heap, and are never reused, lets say you're just implementing a proxy passing buffers through from one connection to another, then the heap usage of the application may be very small, and this could mean that garbage collection is done very infrequently. As I understand it, this can result in direct buffers staying around for a long time, and possibly causing the system to run out of memory. Does anyone have any experience with that, and how to deal with it? We don't generally have this problem in Akka because we always copy our buffers onto the heap into an immutable structure, so even if we do use direct buffers and don't reuse them, our heap usage grows at least as fast as our direct buffer usage grows, which means total memory usage won't exceed twice the size of the heap since eventually garbage collection will clean both up.
 

--
- DML



--
James Roper
Senior Octonaut

Lightbend – Build reactive apps!
Twitter: @jroper

Reply | Threaded
Open this post in threaded view
|

Re: JEP 321: HTTP Client (Standard)

Viktor Klang
Sidenote: a byte is an 8-bit buffer chunk.

:-)

--
Cheers,

On Dec 7, 2017 01:19, "James Roper" <[hidden email]> wrote:
On 7 December 2017 at 06:58, David Lloyd <[hidden email]> wrote:
On Wed, Dec 6, 2017 at 6:31 AM, Chris Hegarty <[hidden email]> wrote:

[snip]
 
> The primary motivation for the use byte buffers, as described above, is
> to provide maximum flexibility to an implementation to avoid copying
> and buffering of data.

Is my reading of the API correct in that flow control is happening in
terms of buffers, not of bytes?  Could there ever be any odd effects
from very small or very large buffers passing through the plumbing?

Your reading is correct. In my experience, it varies wildly by use case. In the technology I work with (Akka), we do exactly this, we have ByteStrings (essentially immutable byte buffer), and flow control is done on the number of ByteStrings, not the number of bytes in those strings. Generally, in reading, the size of ByteStrings is limited by a configurable amount, for example, 8kb. And then Akka's flow control will, by default, keep up to 8 ByteStrings in flight in its asynchronous processing pipeline. So we have a maximum buffer size of 64kb per connection. For most HTTP use cases, this is fine, something reading an HTTP message body might be collecting those buffers up to a maximum size of 100kb by default, and then parsing the buffer (eg, as json). So it's within the tolerances of what the amount of memory that the user expects to use per request. If the data read in to the buffers were very small, this would be due to the client trickle feeding the server - care must be taken on the server to ensure that if 8kb buffers are allocated for reads, but only a small amount of data is read, that these large buffers are released, and the small data copied to a small buffer.

I think where it can possible cause a problem is if for some reason something sending data is only generating small byte buffer chunks, but there's a long (and expensive) pipeline for the chunks to go through before they get written out. This is not a use case that we see that often, but I have seen it. The solution there is to either increase the number of elements in flight in the stream (most reactive streams implementations allow this to be done trivially), or to put an aggregating buffer in the middle before the expensive processing (again, streaming implementations such as RxJava, Reactor or Akka streams provide straight forward stages to do this).

One issue that I'm not sure about is the consequences of using direct buffers with regards to garbage collection. If direct buffers are never copied onto the heap, and are never reused, lets say you're just implementing a proxy passing buffers through from one connection to another, then the heap usage of the application may be very small, and this could mean that garbage collection is done very infrequently. As I understand it, this can result in direct buffers staying around for a long time, and possibly causing the system to run out of memory. Does anyone have any experience with that, and how to deal with it? We don't generally have this problem in Akka because we always copy our buffers onto the heap into an immutable structure, so even if we do use direct buffers and don't reuse them, our heap usage grows at least as fast as our direct buffer usage grows, which means total memory usage won't exceed twice the size of the heap since eventually garbage collection will clean both up.
 

--
- DML



--
James Roper
Senior Octonaut

Lightbend – Build reactive apps!
Twitter: @jroper

12