<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><br></div><div><br>On 13/12/2012, at 11:07 PM, Jim Fulton &lt;<a href="mailto:jim@zope.com">jim@zope.com</a>&gt; wrote:<br>
<br></div><blockquote type="cite"><div><span>On Wed, Dec 12, 2012 at 6:31 PM, Dylan Jay &lt;<a href="mailto:djay@pretaweb.com">djay@pretaweb.com</a>&gt; wrote:</span><br><blockquote type="cite"><span>Hi,</span><br></blockquote>
<blockquote type="cite"><span></span><br></blockquote><span></span><br><blockquote type="cite"><span>I&#39;ve been working with zope for over 12 years and something that</span><br></blockquote><blockquote type="cite"><span> keeps coming up is sacling IO bound operations in Zope. The typical</span><br>
</blockquote><blockquote type="cite"><span> example is where you build an app that calls external apis. While</span><br></blockquote><blockquote type="cite"><span> this is happening a zope thread isn&#39;t doing any other processing</span><br>
</blockquote><blockquote type="cite"><span> and because there is a 1 thread 1 zodb cache limit.  You can run</span><br></blockquote><blockquote type="cite"><span> into scalability problems as you can only have as many threads your</span><br>
</blockquote><blockquote type="cite"><span> RAM / average cache size. The end result is low throughput while</span><br></blockquote><blockquote type="cite"><span> still having low CPU. I&#39;ve consulted on some $$$ sites where others</span><br>
</blockquote><blockquote type="cite"><span> have made this mistake. It&#39;s an easy mistake to make as SQL/PHP</span><br></blockquote><blockquote type="cite"><span> systems don&#39;t tend to have this limitation so new developers to</span><br>
</blockquote><blockquote type="cite"><span> zope often don&#39;t to think of it.</span><br></blockquote><span></span><br><span>I was listening to a talk by a Java guy on Friday where he warned that</span><br><span>a common newbie mistake was to have too large a database connection</span><br>
<span>pool, causing lots of RAM usage.  I expect though that ZODB caches,</span><br><span>consisting of live Python objects exacerbate this effect.</span><br><span></span><br><span></span><br><blockquote type="cite"><span> The possible workarounds aren&#39;t</span><br>
</blockquote><blockquote type="cite"><span> pretty. You can segregate your api calling requests to zeo clients</span><br></blockquote><blockquote type="cite"><span> with large numbers of threads with small caches using some fancy</span><br>
</blockquote><blockquote type="cite"><span> load balancing rules. You can rework that part of your application</span><br></blockquote><blockquote type="cite"><span> to not use zope, perhaps using edge side includes to make it seem p</span><br>
</blockquote><blockquote type="cite"><span> art of the same app.</span><br></blockquote><span></span><br><blockquote type="cite"><span>Feel free to shoot down the following makes no sense.  What if two</span><br></blockquote>
<blockquote type="cite"><span>or more threads could share a zodb cache up until the point at which</span><br></blockquote><blockquote type="cite"><span>one wants to write. This is the point at which you can&#39;t share a</span><br>
</blockquote><blockquote type="cite"><span>cache in a consistent manner in my understanding. At that point the</span><br></blockquote><blockquote type="cite"><span>transaction could be blocked until other readonly transactions had</span><br>
</blockquote><blockquote type="cite"><span>finished and continue by itself? or perhaps the write transaction</span><br></blockquote><blockquote type="cite"><span>could be aborted and restarted with a special flag to ensure it was</span><br>
</blockquote><blockquote type="cite"><span>processed with the cache to itself. As long as requests which</span><br></blockquote><blockquote type="cite"><span>involve external access are readonly with regard to zope then this</span><br>
</blockquote><blockquote type="cite"><span>would improve throughput. This might seem an edge case but consider</span><br></blockquote><blockquote type="cite"><span>where you want to integrate an external app into a zope or Plone</span><br>
</blockquote><blockquote type="cite"><span>app. Often the external api is doing the writing not the zope</span><br></blockquote><blockquote type="cite"><span>part. For example clicking a button on a plone site to make plone</span><br>
</blockquote><blockquote type="cite"><span>send a tweet. It might also improve throughput on zope requests</span><br></blockquote><blockquote type="cite"><span>which involve zodb cache misses as they are also IO bound.</span><br>
</blockquote><span></span><br><span>A simpler approach might be to manage connections better at the</span><br><span>application level so you don&#39;t need so many of them.  If you&#39;re goinng</span><br><span>to spend a lot of time blocked waiting on some external service, why</span><br>
<span>not close the database connection and reopen it when you need</span><br><span>it? Then you could have a lot more threads than database connections.</span><br></div></blockquote><div><br></div><div>I&#39;d never considered that the cache was attached to the db connection rather than the thread. I just reread <span style="font-size:15px;line-height:19px;white-space:nowrap"><a href="http://docs.zope.org/zope2/zope2book/MaintainingZope.html">http://docs.zope.org/zope2/zope2book/MaintainingZope.html</a> and it says exactly that. </span></div>
<div><span style="font-size:15px;line-height:19px;white-space:nowrap">So what your saying is I&#39;d tune db connections down to memory size on an instance dedicated to io bound and then increase the threads. Whenever a thread requests a db connection and there isn&#39;t one available it will block. So I just optimize my app the release the db connection when not needed. </span></div>
<div><span style="font-size:15px;line-height:19px;white-space:nowrap">In fact I could tune all my copes this way since a zone with 10 threads and 2 connections is going to end up queuing requests the same as 2 threads and 10 connections?</span></div>
<div><span style="font-size:15px;line-height:19px;white-space:nowrap">This should be easier to achieve and changes the application less than the erp5 background task solution mentioned. </span></div><div><span style="font-size:15px;line-height:19px;white-space:nowrap"><br>
</span></div><div><br></div><div><br></div><br><blockquote type="cite"><div><span></span><br><span>It&#39;s possible that ZODB could help at the savepoint level.  For</span><br><span>example, maybe you could somehow allow savepoints to be used accross</span><br>
<span>tranasctions and connections.  This would be a lot saner that tring to</span><br><span>share a cache accross threads.</span><br></div></blockquote><div><br></div><div>I can see from the previous post, as there is no checkout semantics in zodb, you are free to write anytime so there is no sane way to block at the point someone wants to write to an object, so it wouldn&#39;t work. </div>
<div>You perhaps could have a single read only db connection which is shared? So in the case above during io bound operations or if you knew you never want to write, you could close the normal connection and open a read only one. </div>
<div><br></div><br><blockquote type="cite"><div><span></span><br><span>Jim</span><br><span></span><br><span>--</span><br><span>Jim Fulton</span><br><span><a href="http://www.linkedin.com/in/jimfulton">http://www.linkedin.com/in/jimfulton</a></span><br>
<span>Jerky is better than bacon! <a href="http://zo.pe/Kqm">http://zo.pe/Kqm</a></span><br></div></blockquote></body></html>