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

improve region reload strategy #1122

Merged
merged 12 commits into from
Jan 31, 2024
Merged

improve region reload strategy #1122

merged 12 commits into from
Jan 31, 2024

Conversation

zyguan
Copy link
Contributor

@zyguan zyguan commented Jan 17, 2024

This PR add a new reload strategy: if a region is marked as needExpireAfterTTL, we don't update lastAccess any more, thus the region will expire after RegionCacheTTL. Currently, we set this flag:

  • if a region has down peers
  • if a region has a store which is stale or not reachable

This ensure that those region will be reloaded every RegionCacheTTL. So the issues like #879 and pingcap/tidb#35418 should be resolved.

This PR also optimize region fields and replace async-reload with delayed-reload.

Also ref: #1104

Regression test for #879

set region-cache-ttl and max-store-down-time to 5m, see the following timeline:

  • 16:08 killed tikv-1@z3, the store turned to disconnect
  • 16:13 store became down, pd started down-peer scheduling
  • 16:13 ~ 16:33 regions were moved to tikv-0@z3, tidb reloaded regions periodically, cross-zone traffic decreased
  • 16:33 ~ 16:45 all regions were health, no region reload
  • 16:45 recovered tikv-1@z3, pd started to balance regions

2024-01-17_171157

Regression test for #1029

set region-cache-ttl and max-store-down-time to 5m, see the following timeline:

  • 20:30 kill tiflash-0, the store turned to disconnect
  • 20:35 store became down
  • 20:35 ~ 20:42 no region reload since the cached regions had no down peer
  • 20:42 exec show table regions to reload regions manually
  • 20:42 ~ 21:02 reloaded regions every 5m since regions had a down peer after show table regions
  • 21:00 recovered tiflash-0, load didn't blance due to down peer
  • 21:02 load blanced after last region reload

2024-01-17_211009

Regression test for #843

2024-01-18_125059

Signed-off-by: zyguan <zhongyangguan@gmail.com>
Signed-off-by: zyguan <zhongyangguan@gmail.com>
Signed-off-by: zyguan <zhongyangguan@gmail.com>
Signed-off-by: zyguan <zhongyangguan@gmail.com>
@zyguan zyguan marked this pull request as ready for review January 17, 2024 13:24
Signed-off-by: zyguan <zhongyangguan@gmail.com>
Signed-off-by: zyguan <zhongyangguan@gmail.com>
Signed-off-by: zyguan <zhongyangguan@gmail.com>
@cfzjywxk
Copy link
Contributor

@crazycs520 PTAL

Signed-off-by: zyguan <zhongyangguan@gmail.com>
Signed-off-by: zyguan <zhongyangguan@gmail.com>
Comment on lines +1103 to +1107
if reloadOnAccess {
lr, err = c.loadRegion(bo, key, isEndKey)
} else {
lr, err = c.loadRegionByID(bo, r.GetID())
}
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the difference here using by id or by key?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here is the replacement of previous async reload introduced by #843, which uses loadRegionByID. I just try to keep the original implementation but do not very sure about why we use loadRegionByID actually. Maybe it's more efficient than loadRegionByKey.

updated int32 = iota // region is updated and no need to reload.
needSync // need sync new region info.
needReloadOnAccess int32 = 1 << iota // indicates the region will be reloaded on next access
needExpireAfterTTL // indicates the region will expire after RegionCacheTTL (even when it's accessed continuously)
Copy link
Contributor

Choose a reason for hiding this comment

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

The strategy is to expire these regions with certain conditions like down peers, we may need to consider how to make the region reloads smoother as the current TTL is a constant value.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it's relative fine for regions that have stale or unreachable peers, since the cache GC only scan 50 regions per seconds. For regions that have down peers, maybe we can add a random value to lastAccess when constructing them by newRegion?

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe we could do some improvements about smoothing region reloads in another PR, considering both expire reloading and region cache miss reloading. I rembember we've encountered lots of region reload caused by sudden TTL expire or something like it.

Copy link
Contributor Author

@zyguan zyguan Jan 30, 2024

Choose a reason for hiding this comment

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

Agreed. One idea I'm thinking about is that we may change lastAccess to TTL and push it to now + RegionCacheTTL + RandomJitter on access.

Copy link
Contributor

@cfzjywxk cfzjywxk left a comment

Choose a reason for hiding this comment

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

LGTM

Copy link
Contributor

@you06 you06 left a comment

Choose a reason for hiding this comment

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

rest LGTM

@@ -1123,9 +1093,18 @@ func (c *RegionCache) findRegionByKey(bo *retry.Backoffer, key []byte, isEndKey
c.insertRegionToCache(r, true, true)
c.mu.Unlock()
}
} else if r.checkNeedReloadAndMarkUpdated() {
} else if flags := r.resetSyncFlags(needReloadOnAccess | needAsyncReloadReady); flags > 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems the async reload becomes sync here.

Copy link
Contributor Author

@zyguan zyguan Jan 30, 2024

Choose a reason for hiding this comment

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

Yes, this is a potential regression. In the current implementation, reloading is divided into three levels:

  1. invalidate: the region cannot be used any more, reloading is required.
  2. reload on access: we need to reload the region on access, but we can tolerate reloading failure. (it's equivalent to the previous syncflag)
  3. async reload: the region needs to be reload later, but not too emergent.

So, it's not a real "async" reload and the name is somehow misleading. I've considered keeping the async reload goroutine or doing reload in cache GC, but gave up for simplicity.

Currently, we mark a region as NeedAsyncReload only when we find it has a store which is stale but reachable or its leader store is stale. Please let me know if the real async reload matters here, I'll change it. Or maybe we just rename the flag (eg. DelayedReload)?

Copy link
Contributor

Choose a reason for hiding this comment

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

Rename or comment the flag, both OK to me.

The current comment indicates it will be reloaded in async mode, which is inaccurate.

	needAsyncReloadPending                   // indicates the region will be reloaded in async mode
	needAsyncReloadReady                     // indicates the region is ready to be reloaded in async mode

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Renamed, PTAL.

continue
}
if syncFlags&needAsyncReloadPending > 0 {
region.setSyncFlags(needAsyncReloadReady)
Copy link
Contributor

Choose a reason for hiding this comment

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

May I understand the flag change here is to avoid too frequent meaningless reloading?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it tries to limit the rate of reloading here.

Co-authored-by: ekexium <eke@fastmail.com>
Signed-off-by: zyguan <zhongyangguan@gmail.com>
@cfzjywxk cfzjywxk merged commit 6e501a1 into tikv:master Jan 31, 2024
10 checks passed
@cfzjywxk
Copy link
Contributor

@zyguan
An PR to update the client-go dependency of tidb is also needed.

@zyguan
Copy link
Contributor Author

zyguan commented Jan 31, 2024

@zyguan An PR to update the client-go dependency of tidb is also needed.

I'll submit another PR soon, which tries to make reloading caused by TTL smooth (#1122 (comment)) and adds some metrics to observe the reason of reloading.

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.

4 participants