Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1reXWN-00BvTG-0U for pgsql-hackers@arkaria.postgresql.org; Mon, 26 Feb 2024 09:43:39 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.94.2) (envelope-from ) id 1reXWL-00CTj3-5f for pgsql-hackers@arkaria.postgresql.org; Mon, 26 Feb 2024 09:43:37 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1reXWK-00CTiv-QJ for pgsql-hackers@lists.postgresql.org; Mon, 26 Feb 2024 09:43:37 +0000 Received: from mail-ed1-x52e.google.com ([2a00:1450:4864:20::52e]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1reXWH-0017Py-3K for pgsql-hackers@lists.postgresql.org; Mon, 26 Feb 2024 09:43:35 +0000 Received: by mail-ed1-x52e.google.com with SMTP id 4fb4d7f45d1cf-565a3910f86so2437639a12.3 for ; Mon, 26 Feb 2024 01:43:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=enterprisedb.com; s=google; t=1708940611; x=1709545411; darn=lists.postgresql.org; h=content-transfer-encoding:in-reply-to:from:references:cc:to :content-language:subject:user-agent:mime-version:date:message-id :from:to:cc:subject:date:message-id:reply-to; bh=qNA7nZxrOBOfMbWv6qvB0Yuly7PMF8cdYis923HLIMk=; b=XqbJIDXbpuIgrz7J/bGbeWpO4rsHZ101ihZ1LO2u+EqKLIkXhQumn1ROrlTUnMIHNt cNPIWYu30jXSW+VQQkhtK6oYNAJPfEooUlTY/nE3vtfCSz8U2ofeuH2PLrvOAEAwQGpQ 0Cv3jjoIbOhNxINmoZRc2RqX77oHped8c3FJ/sCe75a0SPiiDIO8sbDbqdiT5vpMfZa2 +b+cZ7j0ze/bnISv4oa9GmLo0733W9/FZM/95+rcnj/RhxvMe4OPw4fp0k26Gf84DnF5 AEpNTpbOe6J6P0fLBWF1LmVlqgPJrgrvTkTY+rlMXn+qT0VJ+84QVRInkWACyFgBx6lk /WWQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1708940611; x=1709545411; h=content-transfer-encoding:in-reply-to:from:references:cc:to :content-language:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=qNA7nZxrOBOfMbWv6qvB0Yuly7PMF8cdYis923HLIMk=; b=bfmjd2j1f7XqMKAA5CVWK01xqdtPDdBFfVEhSrihSa15sXSvJDGZbE3/su79gyb0gd wRprcPAtZSBnkEN1s2i2Govfxl8Ddfinsa3V8UQ/1JZ80RfM3wBjp/9zDUN2a89pAnvh 6rNxPLzkl418tSl44r7JQCTFl5YlMhB2Yo7Sg6cNrFXizgSzR5EBcmxHs6vw11utruGO iGHMFM+/jaNpWUKt0w7FgUdxmSnXsHz3n+FY/ijacISrv6rN4+20Zj/HFlI13M2ai2Fv m8iwJKVey3lBBANF4n0TM/oxc1aJqphMUiC4W/0RLEBr8YiYCop77pcx29Bo4xTLGOSO cIjQ== X-Forwarded-Encrypted: i=1; AJvYcCUkCHWGIxsFbK5ZACoaY2uetFozRb4zgSfMUOpZzdirj+6LU9JLcnapq/aCk6NRfm1RzV+PzBFgd+axYCE3mXn2MZFeOpggZ3aCWpGGxW2jYvyJ X-Gm-Message-State: AOJu0Yz7OX539pvJnqy0d6vsaHHWdrVtCcJvWH3IbffILg4K+0L+7pe8 OjMwYuvvVdt1RyPsLTrGNVk/DAS/PRk0b7MrZ7dX1Mfof1ZIEp7UIKQl3/D11g== X-Google-Smtp-Source: AGHT+IG2GVmjJcraet2i2PSrUCsu5yvnqSbyi6ieUVWy2Z7AXt+lMGLeGPDwyDCa5vXyj4Rmp07LqA== X-Received: by 2002:aa7:d6d5:0:b0:566:139:517d with SMTP id x21-20020aa7d6d5000000b005660139517dmr786674edr.18.1708940611499; Mon, 26 Feb 2024 01:43:31 -0800 (PST) Received: from [10.137.0.18] (ip-86-49-229-30.bb.vodafone.cz. [86.49.229.30]) by smtp.gmail.com with ESMTPSA id fj25-20020a0564022b9900b005643b41d128sm2147200edb.5.2024.02.26.01.43.30 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 26 Feb 2024 01:43:31 -0800 (PST) Message-ID: <787cd90b-48ff-4c4a-a63e-a2b3f494385d@enterprisedb.com> Date: Mon, 26 Feb 2024 10:43:31 +0100 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: Improve eviction algorithm in ReorderBuffer Content-Language: en-US To: Masahiko Sawada Cc: vignesh C , "Hayato Kuroda (Fujitsu)" , Shubham Khanna , Amit Kapila , Dilip Kumar , PostgreSQL Hackers References: <23e03725-8c77-431d-9f53-51709260ffeb@enterprisedb.com> From: Tomas Vondra In-Reply-To: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 2/26/24 07:46, Masahiko Sawada wrote: > On Sat, Feb 24, 2024 at 1:29 AM Tomas Vondra > wrote: >>... >> >> overall design >> -------------- >> >> As for the design, I agree with the approach of using a binaryheap to >> track transactions by size. When going over the thread history, >> describing the initial approach with only keeping "large" transactions >> above some threshold (e.g. 10%), I was really concerned that'll either >> lead to abrupt changes in behavior (when transactions move just around >> the 10%), or won't help with many common cases (with most transactions >> being below the limit). >> >> I was going to suggest some sort of "binning" - keeping lists for >> transactions of similar size (e.g. <1kB, 1-2kB, 2-4kB, 4-8kB, ...) and >> evicting transactions from a list, i.e. based on approximate size. But >> if the indexed binary heap seems to be cheap enough, I think it's a >> better solution. > > I've also considered the binning idea. But it was not clear to me how > it works well in a case where all transactions belong to the > particular class. For example, if we need to free up 1MB memory, we > could end up evicting 2000 transactions consuming 50 bytes instead of > 100 transactions consuming 1000 bytes, resulting in that we end up > serializing more transactions. Also, I'm concerned about the cost of > maintaining the binning lists. > I don't think the list maintenance would be very costly - in particular, the lists would not need to be sorted by size. You're right in some extreme cases we might evict the smallest transactions in the list. I think on average we'd evict transactions with average size, which seems OK for this use case. Anyway, I don't think we need to be distracted with this. I mentioned it merely to show it was considered, but the heap seems to work well enough, and in the end is even simpler because the complexity is hidden outside reorderbuffer. >> >> The one thing I'm a bit concerned about is the threshold used to start >> using binary heap - these thresholds with binary decisions may easily >> lead to a "cliff" and robustness issues, i.e. abrupt change in behavior >> with significant runtime change (e.g. you add/remove one transaction and >> the code takes a much more expensive path). The value (1024) seems >> rather arbitrary, I wonder if there's something to justify that choice. > > True. 1024 seems small to me. In my environment, I started to see a > big difference from around 40000 transactions. But it varies depending > on environments and workloads. > > I think that this performance problem we're addressing doesn't > normally happen as long as all transactions being decoded are > top-level transactions. Otherwise, we also need to improve > ReorderBufferLargestStreamableTopTXN(). Given this fact, I think > max_connections = 1024 is a possible value in some systems, and I've > observed such systems sometimes. On the other hand, I've observed > > 5000 in just a few cases, and having more than 5000 transactions in > ReorderBuffer seems unlikely to happen without subtransactions. I > think we can say it's an extreme case, the number is still an > arbitrary number though. > > Or probably we can compute the threshold based on max_connections, > e.g., max_connections * 10. That way, we can ensure that users won't > incur the max-heap maintenance costs as long as they don't use > subtransactions. > Tying this to max_connections seems like an interesting option. It'd make this adaptive to a system. I haven't thought about the exact value (m_c * 10), but it seems better than arbitrary hard-coded values. >> >> In any case, I agree it'd be good to have some dampening factor, to >> reduce the risk of trashing because of adding/removing a single >> transaction to the decoding. >> >> >> related stuff / GenerationContext >> --------------------------------- >> >> It's not the fault of this patch, but this reminds me I have some doubts >> about how the eviction interferes with using the GenerationContext for >> some of the data. I suspect we can easily get into a situation where we >> evict the largest transaction, but that doesn't actually reduce the >> memory usage at all, because the memory context blocks are shared with >> some other transactions and don't get 100% empty (so we can't release >> them). But it's actually worse, because GenerationContext does not even >> reuse this memory. So do we even gain anything by the eviction? >> >> When the earlier patch versions also considered age of the transaction, >> to try evicting the older ones first, I think that was interesting. I >> think we may want to do something like this even with the binary heap. > > Thank you for raising this issue. This is one of the highest priority > items in my backlog. We've seen cases where the logical decoding uses > much more memory than logical_decoding_work_mem value[1][2] (e.g. it > used 4GB memory even though the logical_decoding_work_mem was 256kB). > I think that the problem would still happen even with this improvement > on the eviction. > > I believe these are separate problems we can address, and evicting > large transactions first would still be the right strategy. We might > want to improve how we store changes in memory contexts. For example, > it might be worth having per-transaction memory context so that we can > actually free memory blocks by the eviction. We can discuss it in a > separate thread. > Yes, I think using per-transaction context for large transactions might work. I don't think we want too many contexts, so we'd start with the shared context, and then at some point (when the transaction exceeds say 5% of the memory limit) we'd switch it to a separate one. But that's a matter for a separate patch, so let's discuss elsewhere. >> >> For example, a system may be doing a lot of eviction / spilling with >> logical_decoding_work_mem=64MB, but setting 128MB may completely >> eliminate that. Of course, if there are large transactions, this may not >> be possible (the GUC would have to exceed RAM). But I don't think that's >> very common, the incidents that I've observed were often resolved by >> bumping the logical_decoding_work_mem by a little bit. >> >> I wonder if there's something we might do to help users to tune this. We >> should be able to measure the "peak" memory usage (how much memory we'd >> need to not spill), so maybe we could log that as a WARNING, similarly >> to checkpoints - there we only log "checkpoints too frequent, tune WAL >> limits", but perhaps we might do more here? Or maybe we could add the >> watermark to the system catalog? > > Interesting ideas. > > The statistics such as spill_count shown in pg_stat_replication_slots > view could already give hints to users to increase the > logical_decoding_work_mem. In addition to that, it's an interesting > idea to have the high water mark in the view. > The spill statistics are useful, but I'm not sure it can answer the main question: How high would the memory limit need to be to not spill? Maybe there's something we can measure / log to help with this. regards -- Tomas Vondra EnterpriseDB: http://www.enterprisedb.com The Enterprise PostgreSQL Company