Skip to content
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

Prototype/fdb layer replace couch rate #3127

Merged
merged 3 commits into from
Sep 15, 2020

Conversation

davisp
Copy link
Member

@davisp davisp commented Sep 3, 2020

Overview

Replace the couch_rate rate limiting algorithm with couch_views_batch to dynamically optimize the indexer batch size during view updates.

While working on optimizing couch_views I ran into couch_rate behaving oddly. Reading through the implementation it was nearly impossible to predict how changing various parameters would affect the behavior under load. The rate limiting algorithms were also a bit misapplied. We don't really want a rate "limiter" so much as a rate "maximizer".

After failing to comprehend couch_rate and realizing that it was missing some fairly important signals (specifically, the approximate transaction size) I decided to take a whack at simplifying things. The new approach is quite a bit simpler and results in the ability to both successfully index large views (1,000,000 doc ranges were tested) but also has a more predictable and simple behavior.

batch_size_search

The graph above is a representative of the behavior. Batch sizes start out small when a view indexer starts. The batch size is quickly ramped up to search for the threshold of a batch size, and then batch sizes are adjusted in much smaller increments to follow the optimal batch size.

Matching the old behavior of couch_rate to attempt to maintain a consistent transaction time limit can be accomplished trivially by adjusting the couch_views.batch_tx_max_time parameter.

Testing recommendations

make check

Checklist

@davisp davisp force-pushed the prototype/fdb-layer-replace-couch-rate branch from 5c477f3 to 2adc534 Compare September 3, 2020 20:25
@davisp
Copy link
Member Author

davisp commented Sep 3, 2020

I should mention that my hack to generate the batch_size graphs had a bug where it would double count if a transaction would be retried. That spike to ~8500 just happens to be at the transition in this graph. There's always a conflict towards the start of view indexing due to a conflict on the couch_jobs data that I have yet to track down.

@davisp davisp requested review from iilyak, garrensmith, nickva and rnewson and removed request for iilyak September 3, 2020 20:27
Copy link
Member

@garrensmith garrensmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, this looks really good and is a lot simpler than the previous implementation.
I'm not convinced about having the default implementation of batch_module in the same file as couch_views_batch. I initially found it confusing trying to figure out where it starts and where couch_views_batch is. I would prefer we have a couch_batch module similar to couch_rate with the default module and couch_views_batch.

src/couch_views/src/couch_views_batch.erl Outdated Show resolved Hide resolved
src/couch_views/src/couch_views_batch.erl Outdated Show resolved Hide resolved
src/couch_views/src/couch_views_indexer.erl Outdated Show resolved Hide resolved
src/couch_views/README.md Outdated Show resolved Hide resolved
rel/overlay/etc/default.ini Outdated Show resolved Hide resolved
@iilyak
Copy link
Contributor

iilyak commented Sep 8, 2020

I'm not convinced about having the default implementation of batch_module in the same file as couch_views_batch. I initially found it confusing trying to figure out where it starts and where couch_views_batch is. I would prefer we have a couch_batch module similar to couch_rate with the default module and couch_views_batch.

I agree with Garren. This separation would also hide the #batch_st{} record in couch_views_batch module.

@iilyak
Copy link
Contributor

iilyak commented Sep 8, 2020

Just wanted to mention that the scope of couch_rate was bigger. The idea behind couch_rate was to provide a rate limiter/batch size estimator which can be used anywhere where we have a chance of a transaction failure from FDB and where we can be better off by adjusting transaction size (one possible use case is to unify with https://github.com/apache/couchdb/blob/prototype/fdb-layer/src/couch_replicator/src/couch_replicator_rate_limiter.erl). However since it seems like we are getting a consensus that we should introduce limits we might not need a generic solution and couch_view specific one might suffice.

@iilyak
Copy link
Contributor

iilyak commented Sep 8, 2020

In regards to Move error reporting test to EUnit commit you've mentioned:

This test doesn't fail correctly any longer. Rather than attempting to
create a new pathological view case I've just moved it to eunit where we can use meck to throw errors directly.

The meck can be used from ExUnit.

  defp with_fdb_error(_ctx) do
    :ok = :meck.new(:couch_views_batch, [:passthrough])
    :meck.expect(:couch_views_batch, :start, [], fn() ->
      :erlang.error({:erlfdb_error, 2101})
    end)
    on_exit(fn ->
      :meck.unload()
    end)
  end

describe "something something" do
    setup [....,  :with_fdb_error]
    test "something something", ctx do
       ...
    end
end

@davisp davisp force-pushed the prototype/fdb-layer-replace-couch-rate branch 2 times, most recently from e04b8ef to 309d388 Compare September 8, 2020 16:30
@davisp
Copy link
Member Author

davisp commented Sep 8, 2020

@garrensmith I've split the behavior/implementation between couch_views_batch (behavior) and couch_views_batch_impl (implementation). I don't believe this behavior is nearly abstract enough to cover anything besides couch_views so it doesn't make a lot of sense to me to create a new application to hold a new module that only couch_views will use.

@iilyak For the scope I agree that this is a lot more narrow. I started by trying to figure out the AIMD/congestion algorithms in both couch_rate and couch_replicator but after thinking awhile I realized that having an AIMD based algorithm isn't appropriate for batch sizes since we want to avoid failing batches as much as possible because every failed batch is wasted time when building a view. I did a number of different approaches to try and measure optimal batch sizes and behaviors. An earlier version of this work actually tried to optimize the rate of indexing within the bounds of transaction sizes. That lead to the realization that just maximizing the work done in a single transaction was most beneficial overall for indexing throughput. That's how it ended up being so simple and narrow in the end.

For the meck-via-Elixir, that would have worked if this test were running in the same VM but those tests are run separately against an instance of dev/run.

src/couch_views/src/couch_views_indexer.erl Outdated Show resolved Hide resolved
src/couch_views/src/couch_views_indexer.erl Outdated Show resolved Hide resolved
src/couch_views/src/couch_views_batch.erl Outdated Show resolved Hide resolved
src/couch_views/src/couch_views_indexer.erl Outdated Show resolved Hide resolved
@iilyak
Copy link
Contributor

iilyak commented Sep 8, 2020

For the meck-via-Elixir, that would have worked if this test were running in the same VM but those tests are run separately against an instance of dev/run.

We have two kinds of Elixir tests

  • integration tests which live in test/elixir/test
  • unit tests which live in src/<app>/test/exunit/

Unit tests are run on the same VM

@davisp davisp force-pushed the prototype/fdb-layer-replace-couch-rate branch from 309d388 to 46f355b Compare September 8, 2020 18:18
@davisp
Copy link
Member Author

davisp commented Sep 8, 2020

@nickva I've addressed your three main suggestions. For the metrics I don't have a good answer other than maybe expose the timing logs I've currently somewhat hacked in the views branch. Let me know if you think some sort of combined metric there would be useful and I can add that.

@nickva
Copy link
Contributor

nickva commented Sep 8, 2020

@davisp Looks, let's skip the metrics for now, could be a future enhancement

I am getting a consistent timeout in the couch_views_indexer_test:39: indexer_test_ (indexed_empty_db)... test while it passes on prototype/fdb-layer. Looking a bit into that

@davisp
Copy link
Member Author

davisp commented Sep 8, 2020

@nickva I sometimes have one but it seems to be only occasionally for the first run after compiling and then doesn't happen again. Let me know if you find anything though. Flaky tests are never good.

@nickva
Copy link
Contributor

nickva commented Sep 9, 2020

@davisp Found the issue, couch_views builds are were fast enough to trigger a race condition in couch_jobs monitoring code. The job was completing before the type monitor for couch_views jobs even started.

Made a PR to fix it:
#3135

src/couch_views/README.md Outdated Show resolved Hide resolved
Copy link
Contributor

@nickva nickva left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 Nice work!

And good comments from Ilya and Garren about re-structuring it as two modules.

Left a few style and param validation comments, up to you there if you feel they are too nitpicky

@davisp davisp force-pushed the prototype/fdb-layer-replace-couch-rate branch from 46f355b to c3511dd Compare September 10, 2020 21:14
@davisp
Copy link
Member Author

davisp commented Sep 10, 2020

@nickva I've addressed all of your suggestions. Let me know if you have anything else.

@iilyak @garrensmith I'm pretty sure I've addressed all of your concerns, let me know if there's anything left to handle.

@nickva
Copy link
Contributor

nickva commented Sep 10, 2020

@davisp lgtm +1 to merge, also good job adding extra tests!

Copy link
Member

@garrensmith garrensmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One small change from me and then it looks good.

src/couch_views/README.md Show resolved Hide resolved
@davisp davisp force-pushed the prototype/fdb-layer-replace-couch-rate branch from c3511dd to df3b74a Compare September 14, 2020 18:19
; batch_initial_size = 100 ; Initial batch size in number of documents
; batch_search_increment = 500 ; Size change when searching for the threshold
; batch_sense_increment = 100 ; Size change increment after hitting a threshold
; batch_max_tx_size = 9000000 ; Maximum transaction size in bytes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we name it batch_max_tx_size_bytes to make it clear that units are different compared to batch_initial_size?

Copy link
Contributor

@iilyak iilyak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. after batch_max_tx_size -> batch_max_tx_size_bytes rename.

Copy link
Member

@garrensmith garrensmith left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

@davisp davisp force-pushed the prototype/fdb-layer-replace-couch-rate branch from df3b74a to 77f9c8b Compare September 15, 2020 16:06
@davisp
Copy link
Member Author

davisp commented Sep 15, 2020

Updated the max size parameter to include bytes. Will merge when CI comes back green.

@davisp davisp force-pushed the prototype/fdb-layer-replace-couch-rate branch from 77f9c8b to 718b7b0 Compare September 15, 2020 17:06
This implementation was difficult to understand and had behavior that
was too difficult to predict. It would break if view behavior changed in
significant ways from what was originally expected.
The couch_views_batch module is responsible for sensing the largest
batch sizes that can be successfully processed for a given indexer
process. It works by initially searching for the maximum number of
documents that can be included in a batch. Once this threshold is found
it then works by slowly increasing the batch size and decreasing when
its found again.

This approach works to maximise batch sizes while being reactive to when
a larger batch would cross over the FoundationDB transaction limits
which causes the entire batch to be aborted and retried which wastes
time during view builds.
This test doesn't fail correctly any longer. Rather than attempting to
create a new pathological view case I've just moved it to eunit where we
can use meck to throw errors directly.
@davisp davisp merged commit 8cd1792 into prototype/fdb-layer Sep 15, 2020
@davisp davisp deleted the prototype/fdb-layer-replace-couch-rate branch September 15, 2020 17:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants