Skip to content

Add operation estimations for HDD devices, KIKIMR-17759 #909

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

Merged
merged 2 commits into from
Jan 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 30 additions & 7 deletions ydb/core/blobstorage/vdisk/common/blobstorage_cost_tracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,35 @@

namespace NKikimr {

class TBsCostModelMirror3dc : public TBsCostModelBase {};
const TDiskOperationCostEstimator TBsCostModelBase::HDDEstimator{
{ 80000, 1.774 }, // ReadCoefficients
{ 6500, 11.1 }, // WriteCoefficients
{ 6.089e+06, 8.1 }, // HugeWriteCoefficients
};

class TBsCostModel4Plus2Block : public TBsCostModelBase {};
class TBsCostModelMirror3dc : public TBsCostModelBase {
public:
TBsCostModelMirror3dc(NPDisk::EDeviceType deviceType)
: TBsCostModelBase(deviceType)
{}
};

class TBsCostModelMirror3of4 : public TBsCostModelBase {};
class TBsCostModel4Plus2Block : public TBsCostModelBase {
public:
TBsCostModel4Plus2Block(NPDisk::EDeviceType deviceType)
: TBsCostModelBase(deviceType)
{}
};

TBsCostTracker::TBsCostTracker(const TBlobStorageGroupType& groupType, const TIntrusivePtr<::NMonitoring::TDynamicCounters>& counters)
class TBsCostModelMirror3of4 : public TBsCostModelBase {
public:
TBsCostModelMirror3of4(NPDisk::EDeviceType deviceType)
: TBsCostModelBase(deviceType)
{}
};

TBsCostTracker::TBsCostTracker(const TBlobStorageGroupType& groupType, NPDisk::EDeviceType diskType,
const TIntrusivePtr<::NMonitoring::TDynamicCounters>& counters)
: GroupType(groupType)
, CostCounters(counters->GetSubgroup("subsystem", "advancedCost"))
, UserDiskCost(CostCounters->GetCounter("UserDiskCost", true))
Expand All @@ -19,15 +41,16 @@ TBsCostTracker::TBsCostTracker(const TBlobStorageGroupType& groupType, const TIn
{
switch (GroupType.GetErasure()) {
case TBlobStorageGroupType::ErasureMirror3dc:
CostModel = std::make_unique<TBsCostModelMirror3dc>();
CostModel = std::make_unique<TBsCostModelMirror3dc>(diskType);
break;
case TBlobStorageGroupType::Erasure4Plus2Block:
CostModel = std::make_unique<TBsCostModelMirror3dc>();
CostModel = std::make_unique<TBsCostModel4Plus2Block>(diskType);
break;
case TBlobStorageGroupType::ErasureMirror3of4:
CostModel = std::make_unique<TBsCostModelMirror3of4>();
CostModel = std::make_unique<TBsCostModelMirror3of4>(diskType);
break;
default:
CostModel = std::make_unique<TBsCostModelErasureNone>(diskType);
break;
}
}
Expand Down
118 changes: 80 additions & 38 deletions ydb/core/blobstorage/vdisk/common/blobstorage_cost_tracker.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,47 @@

namespace NKikimr {

class TDiskOperationCostEstimator {
using Coefficients = std::pair<double, double>;
public:
TDiskOperationCostEstimator(Coefficients readCoefficients,
Coefficients writeCoefficients,
Coefficients hugeWriteCoefficients)
: ReadCoefficients(readCoefficients)
, WriteCoefficients(writeCoefficients)
, HugeWriteCoefficients(hugeWriteCoefficients)
{}

ui64 Read(ui64 chunkSize) const {
return ReadCoefficients.first + ReadCoefficients.second * chunkSize;
}

ui64 Write(ui64 chunkSize) const {
return WriteCoefficients.first + WriteCoefficients.second * chunkSize;
}

ui64 HugeWrite(ui64 chunkSize) const {
return HugeWriteCoefficients.first + HugeWriteCoefficients.second * chunkSize;
}

private:
// cost = Coefficients.first + Coefficients.second * chunkSize
Coefficients ReadCoefficients;
Coefficients WriteCoefficients;
Coefficients HugeWriteCoefficients;
};

class TBsCostModelBase {
public:
TBsCostModelBase(NPDisk::EDeviceType deviceType)
: DeviceType(deviceType)
{}

virtual ~TBsCostModelBase() = default;

protected:
NPDisk::EDeviceType DeviceType = NPDisk::DEVICE_TYPE_UNKNOWN;

// Disk Settings
ui64 DeviceSeekTimeNs = 5'000'000;
ui64 HugeBlobSize = 1'000'000; // depends on erasure
Expand All @@ -26,16 +62,7 @@ class TBsCostModelBase {
ui64 DeviceWriteBlockSize = 4 * 1'000; // 4 kB
ui64 PDiskWriteBlockSize = 4ull * 1'000'000; // 4MB

// Estimated Coefficients
// cost = A + B * size
double WriteA = 6500;
double WriteB = 11.1;

double ReadA = WriteA;
double ReadB = WriteB;

double HugeWriteA = 6.089e+06;
double HugeWriteB = 8.1;
static const TDiskOperationCostEstimator HDDEstimator;

private:
enum class EMemoryOperationType {
Expand Down Expand Up @@ -68,31 +95,44 @@ class TBsCostModelBase {
}

ui64 WriteCost(ui64 chunkSize) const {
ui64 seekTime = 1. * chunkSize * DeviceSeekTimeNs;
ui64 writeTime = chunkSize * 1'000'000'000ull / DeviceWriteSpeedBps;
return seekTime + writeTime;
switch (DeviceType) {
case NPDisk::DEVICE_TYPE_ROT: {
return HDDEstimator.Write(chunkSize);
}
default: {
ui64 seekTime = DeviceSeekTimeNs / 100u; // assume we do one seek per 100 log records
ui64 writeTime = chunkSize * 1'000'000'000ull / DeviceWriteSpeedBps;
return seekTime + writeTime;
}
}
}

ui64 HugeWriteCost(ui64 chunkSize) const {
ui64 blocksNumber = (chunkSize + DeviceWriteBlockSize - 1) / DeviceWriteBlockSize;
ui64 seekTime = 1. * blocksNumber * DeviceSeekTimeNs;
ui64 writeTime = chunkSize * 1'000'000'000ull / DeviceWriteSpeedBps;
return seekTime + writeTime;
switch (DeviceType) {
case NPDisk::DEVICE_TYPE_ROT: {
return HDDEstimator.HugeWrite(chunkSize);
}
default: {
ui64 blocksNumber = (chunkSize + DeviceWriteBlockSize - 1) / DeviceWriteBlockSize;
ui64 seekTime = 1. * blocksNumber * DeviceSeekTimeNs;
ui64 writeTime = chunkSize * 1'000'000'000ull / DeviceWriteSpeedBps;
return seekTime + writeTime;
}
}
}

ui64 ReadCost(ui64 chunkSize) const {
ui64 blocksNumber = (chunkSize + DeviceReadBlockSize - 1) / DeviceReadBlockSize;
ui64 seekTime = 1. * blocksNumber * DeviceSeekTimeNs;
ui64 readTime = chunkSize * 1'000'000'000ull / DeviceReadSpeedBps;
return seekTime + readTime;
}

ui64 EstimatedWriteCost(ui64 chunkSize) const {
return WriteA + WriteB * chunkSize;
}

ui64 EstimatedHugeWriteCost(ui64 chunkSize) const {
return HugeWriteA + HugeWriteB * chunkSize;
switch (DeviceType) {
case NPDisk::DEVICE_TYPE_ROT: {
return HDDEstimator.Read(chunkSize);
}
default: {
ui64 blocksNumber = (chunkSize + DeviceReadBlockSize - 1) / DeviceReadBlockSize;
ui64 seekTime = 1. * blocksNumber * DeviceSeekTimeNs;
ui64 readTime = chunkSize * 1'000'000'000ull / DeviceReadSpeedBps;
return seekTime + readTime;
}
}
}

public:
Expand Down Expand Up @@ -154,11 +194,11 @@ class TBsCostModelBase {

/// WRITES
ui64 GetCost(const TEvBlobStorage::TEvVBlock& ev) const {
return EstimatedWriteCost(ev.GetCachedByteSize());
return WriteCost(ev.GetCachedByteSize());
}

ui64 GetCost(const TEvBlobStorage::TEvVCollectGarbage& ev) const {
return EstimatedWriteCost(ev.GetCachedByteSize());
return WriteCost(ev.GetCachedByteSize());
}

ui64 GetCost(const TEvBlobStorage::TEvVPut& ev) const {
Expand All @@ -168,9 +208,9 @@ class TBsCostModelBase {

NPriPut::EHandleType handleType = NPriPut::HandleType(HugeBlobSize, handleClass, size);
if (handleType == NPriPut::Log) {
return EstimatedWriteCost(size);
return WriteCost(size);
} else {
return EstimatedHugeWriteCost(size);
return HugeWriteCost(size);
}
}

Expand All @@ -183,9 +223,9 @@ class TBsCostModelBase {
const ui64 size = ev.GetBufferBytes(idx);
NPriPut::EHandleType handleType = NPriPut::HandleType(HugeBlobSize, handleClass, size);
if (handleType == NPriPut::Log) {
cost += EstimatedWriteCost(size);
cost += WriteCost(size);
} else {
cost += EstimatedHugeWriteCost(size);
cost += HugeWriteCost(size);
}
}
return cost;
Expand All @@ -206,13 +246,14 @@ class TBsCostModelBase {
// WRITES
ui64 GetCost(const NPDisk::TEvChunkWrite& ev) const {
if (ev.PriorityClass == NPriPut::Log) {
return EstimatedWriteCost(ev.PartsPtr->ByteSize());
return WriteCost(ev.PartsPtr->ByteSize());
} else {
return EstimatedHugeWriteCost(ev.PartsPtr->ByteSize());
return HugeWriteCost(ev.PartsPtr->ByteSize());
}
}
};

using TBsCostModelErasureNone = TBsCostModelBase;
class TBsCostModelMirror3dc;
class TBsCostModel4Plus2Block;
class TBsCostModelMirror3of4;
Expand All @@ -231,7 +272,8 @@ class TBsCostTracker {
::NMonitoring::TDynamicCounters::TCounterPtr InternalDiskCost;

public:
TBsCostTracker(const TBlobStorageGroupType& groupType, const TIntrusivePtr<::NMonitoring::TDynamicCounters>& counters);
TBsCostTracker(const TBlobStorageGroupType& groupType, NPDisk::EDeviceType diskType,
const TIntrusivePtr<::NMonitoring::TDynamicCounters>& counters);

template<class TEv>
ui64 GetCost(const TEv& ev) const {
Expand Down
2 changes: 1 addition & 1 deletion ydb/core/blobstorage/vdisk/common/vdisk_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ namespace NKikimr {
, ReplPDiskWriteQuoter(std::move(replPDiskWriteQuoter))
, ReplNodeRequestQuoter(std::move(replNodeRequestQuoter))
, ReplNodeResponseQuoter(std::move(replNodeResponseQuoter))
, CostTracker(std::make_shared<TBsCostTracker>(Top->GType, vdiskCounters))
, CostTracker(std::make_shared<TBsCostTracker>(Top->GType, type, vdiskCounters))
, OutOfSpaceState(Top->GetTotalVDisksNum(), Top->GetOrderNumber(ShortSelfVDisk))
, CostMonGroup(vdiskCounters, "subsystem", "cost")
, Logger(as ? ActorSystemLogger(as) : DevNullLogger())
Expand Down