-
Notifications
You must be signed in to change notification settings - Fork 9.4k
Split X-Magento-Tags HTTP header into multiple headers #12831
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Split X-Magento-Tags HTTP header into multiple headers #12831
Conversation
I'm open to recommendations for this one - especially the part adding header to StaticMap. It appears a bit difficult to add another header mapping to Header splitting might also be improved, but curious to see if this is the right approach to solve this issue. |
…void issues with max header length
Any news about this one? |
@magento-team @magento-engcom-team Anyone caring enough to discuss this? Don't think we should be sending MBs inside a single X-Magento-Tags header, but keep to hear what you think. |
@kokoc @paliarush, you're responsible for page cache module. Could you review this PR? |
I think you mean to implode $newTags, not $tags there :) |
@sidolov could you review these changes? |
Hi @sambolek
|
Hi @ishakhsuvarov , As per my initial message, if a category has about 2500 products, a single header X-Magento-Tags gets too large, causing issues with Varnish (having to adjust parameters all around), web server (Apache and nginx have 8kB header limit), and LoadBalancers (HAProxy and nginx have 8kB limit as well). Even if there is a limit to adjust, the solution isn't to keep adjusting the limit as you add more products to the system and assign them to categories. Many merchants could easily have categories with large amount of products, or anchor categories with plenty subcategories - since Magento is targeting mid/large merchants, catalog should work regardless of these factors. Since RFC allows for multiple headers with the same name, the logical way forward would be do build the application (Magento) in a way that headers are split properly, without a need to adjust limits on the entire system. This pull request solves the problem at hand, without going too deep into architectural choices of Magento system/platform. Of course, it might be wise to explore splitting all cookies that can be comma-separated (as per RFC) on platform level, but, in the meantime implement this pull request, which shouldn't have any BC to help other merchants that have the same issue we did. |
Hi @sambolek
This PR indeed, seems to solve the problem. However, it could be better to try and implement the desired state approach right away, as fixing only one header type just masks the problem. I'll submit more thoughts on it via the code review to the Pull Request to continue the discussion. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To accept this solution to the core I would suggest making it more generic, as current state of it seems to be a perfect solution for a third-party module, but not a core component
* | ||
* @return Subject|mixed | ||
*/ | ||
public function aroundSetHeader(Subject $subject, \Closure $proceed, $name, $value, $replace = false) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not recommended to add new around plugins, as it has a greater performance penalty, specifically, in such a critical part of the system.
|
||
$this->addHeaderToStaticMap(); | ||
|
||
if ($name == 'X-Magento-Tags') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are already plugins in the system which set X-Magento-Tags
. Did you consider updating those instead of processing same header again?
public function aroundSetHeader(Subject $subject, \Closure $proceed, $name, $value, $replace = false) | ||
{ | ||
//if varnish isn't enabled, don't do anything | ||
if (!$this->config->isEnabled() || $this->config->getType() != Config::VARNISH) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While the issue described in the Pull Request only relates to Varnish, this header is also used by Builtin Implementation. Would it make sense to make it more generic?
$newTags[] = $tag; | ||
} | ||
|
||
return $subject; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Different plugins, for example solving similar issue for other header types may be theoretically broken in this way. Does it make sense to tune the actual Response implementation instead?
* @throws Exception\InvalidArgumentException | ||
* @return string | ||
*/ | ||
public function toStringMultipleHeaders(array $headers) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method seems to be copied from the Zend's default implementation of \Zend\Http\Header\GenericMultiHeader::toStringMultipleHeaders
which could make it more challenging to support in the future
*/ | ||
public function getFieldName() | ||
{ | ||
return 'X-Magento-Tags'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
X-Magento-Tags
literal occurs many times across this this PR, would it make sense to move it to a constant?
Hi @sambolek , I am closing this PR now due to inactivity. |
Are there any updates for this issue? This problem still exists in M2.3.3 |
Would like to add some summary on this PR: This solution is quite good, but it's not finalized in order to be accepted. I have only one concern - such change might break some services like Fastly (for instance used in Magento Cloud), so probably it should be double checked additionally |
It would still be nice if a solution for this could get implemented anywhere in the future for this problem. We currently run against this huge @ishakhsuvarov, @sidolov, are there plans to ever support this somehow? Not necessarily by splitting the header, but maybe by using some other (and fewer) cache tags in search results so it doesn't list every single product id from the resultset? #26960 should also get re-opened in my opinion, since it's not fixed yet. |
Sorry, ignore comment above, we had this issue because the pagination on search results pages didn't work, all products were always being displayed instead of only one page. So, once we solve this the pagination of search result pages, we won't run into this anymore. Sorry for the noise 🙂 |
@hostep we're having the same issue with showing all products on search. Were you able to find the reason for that issue? |
@ihor-sviziev: in our case it was a custom module that loaded the product collection too soon before the pagination was getting applied (or something like that, still trying to figure out exactly is going on and how to fix it). If you have this issue with all products being shown in the search result page, it's most likely not a core Magento bug, but some customisation done to your shop, either in the custom theme or in custom/3rd party modules. Try switching to a default theme and/or disabling modules and test again, until you find the culprit, that's how I found out about which module caused the issue in our case. |
Update @ihor-sviziev, seems to have something to do with this change: #27263, when I add Also possibly related issue: #34292 We use the Sorry to the readers of this thread, this has nothing to do with it, I'll try to shut up now 😄 |
On Magento sites with large catalogs, it's easy to hit HTTP header length limit on Varnish or HTTP server, for categories that have large amount of products and are set as anchor. This is because all of the product tags are sent in initial backend_fetch request.
This is usually addressed by implementing a workaround from the documentation http://devdocs.magento.com/guides/v2.2/config-guide/varnish/tshoot-varnish-503.html . Thing is, that workaround doesn't solve the issue, as you end up increasing the limit constantly as categories grow larger.
Furthermore, you might hit another limit on your Apache/nginx HTTP server, as both have 8kB max header value by default.
In M2.2 2529ec4 , cache tags have been refactored to be a bit shorter (e.g. cat_p_xx instead of catalog_product_xx), which is another workaround to address the same issue.
According to RFC2616 https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html:
Description
This pull request proposes splitting the X-Magento-Tags header into multiple X-Magento-Tags headers that would stay roughly under 8kB limit each.
Fixed Issues (if relevant)
Manual testing scenarios
FetchError http read error: overflow
onbereq 2 fetch
requestContribution checklist