mirror of
https://github.com/pgsty/minio.git
synced 2026-10-07 02:05:58 +03:00
Prefer local disks when fetching data blocks (#9563)
If the requested server is part of the set this will always read from the local disk, even if the disk contains a parity shard. In default setup there is a 50% chance that at least one shard that otherwise would have been fetched remotely will be read locally instead. It basically trades RPC call overhead for reed-solomon. On distributed localhost this seems to be fairly break-even, with a very small gain in throughput and latency. However on networked servers this should be a bigger 1MB objects, before: ``` Operation: GET. Concurrency: 32. Hosts: 4. Requests considered: 76257: * Avg: 25ms 50%: 24ms 90%: 32ms 99%: 42ms Fastest: 7ms Slowest: 67ms * First Byte: Average: 23ms, Median: 22ms, Best: 5ms, Worst: 65ms Throughput: * Average: 1213.68 MiB/s, 1272.63 obj/s (59.948s, starting 14:45:44 CEST) ``` After: ``` Operation: GET. Concurrency: 32. Hosts: 4. Requests considered: 78845: * Avg: 24ms 50%: 24ms 90%: 31ms 99%: 39ms Fastest: 8ms Slowest: 62ms * First Byte: Average: 22ms, Median: 21ms, Best: 6ms, Worst: 57ms Throughput: * Average: 1255.11 MiB/s, 1316.08 obj/s (59.938s, starting 14:43:58 CEST) ``` Bonus fix: Only ask for heal once on an object.
This commit is contained in:
+9
-2
@@ -265,6 +265,7 @@ func (xl xlObjects) getObject(ctx context.Context, bucket, object string, startO
|
||||
return toObjectErr(err, bucket, object)
|
||||
}
|
||||
|
||||
var healOnce sync.Once
|
||||
for ; partIndex <= lastPartIndex; partIndex++ {
|
||||
if length == totalBytesRead {
|
||||
break
|
||||
@@ -284,6 +285,7 @@ func (xl xlObjects) getObject(ctx context.Context, bucket, object string, startO
|
||||
tillOffset := erasure.ShardFileTillOffset(partOffset, partLength, partSize)
|
||||
// Get the checksums of the current part.
|
||||
readers := make([]io.ReaderAt, len(onlineDisks))
|
||||
prefer := make([]bool, len(onlineDisks))
|
||||
for index, disk := range onlineDisks {
|
||||
if disk == OfflineDisk {
|
||||
continue
|
||||
@@ -292,14 +294,19 @@ func (xl xlObjects) getObject(ctx context.Context, bucket, object string, startO
|
||||
partPath := pathJoin(object, fmt.Sprintf("part.%d", partNumber))
|
||||
readers[index] = newBitrotReader(disk, bucket, partPath, tillOffset,
|
||||
checksumInfo.Algorithm, checksumInfo.Hash, erasure.ShardSize())
|
||||
|
||||
// Prefer local disks
|
||||
prefer[index] = disk.Hostname() == ""
|
||||
}
|
||||
err := erasure.Decode(ctx, writer, readers, partOffset, partLength, partSize)
|
||||
err := erasure.Decode(ctx, writer, readers, partOffset, partLength, partSize, prefer)
|
||||
// Note: we should not be defer'ing the following closeBitrotReaders() call as we are inside a for loop i.e if we use defer, we would accumulate a lot of open files by the time
|
||||
// we return from this function.
|
||||
closeBitrotReaders(readers)
|
||||
if err != nil {
|
||||
if decodeHealErr, ok := err.(*errDecodeHealRequired); ok {
|
||||
go deepHealObject(pathJoin(bucket, object))
|
||||
healOnce.Do(func() {
|
||||
go deepHealObject(pathJoin(bucket, object))
|
||||
})
|
||||
err = decodeHealErr.err
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user