Shared DB - Windows
These results should be viewed as guidelines and not performance guarantees, since there are many variables that affect performance (file set, network configurations, hardware characteristics, etc.). If throughput is important to your implementation, OPSWAT recommends site-specific benchmarking before implementing a production solution.
Environment
Using AWS environment with the specification below:
MetaDefender Core
OS | AWS instance type | vCPU | Memory (GB) | Network bandwidth (Gbps) | Disk type | Benchmark | |
---|---|---|---|---|---|---|---|
MetaDefender Core #1 | Windows Server 2022 | c5.4xlarge | 16 | 32 | Up to 10 | SSD | Amazon EC2 c5.4xlarge - Geekbench |
MetaDefender Core #2 | Windows Server 2022 | c5.4xlarge | 16 | 32 | Up to 10 | SSD | Amazon EC2 c5.4xlarge - Geekbench |
RDS
OS | AWS instance type | vCPU | Memory (GB) | Network bandwidth (Gbps) | Disk type |
---|---|---|---|---|---|
Windows Server 2022 | db.m7i.4xlarge | 16 | 64 | Up to 10 | SSD |
Deployment Model

Using a AWS Load Balancer to distribute files sent from the client tool to two (2) different MetaDefender Core servers applying Round Robin algorithm. With this algorithm, each MetaDefender Core server is supposed to receive same number of requests.
Client tool
A simple tool written in Python to collect files in a designated folder and submit requests to Load Balancer mentioned above.
files_to_scan = list of files to scan
scan_futures =[]
for file_path in files_to_scan:
scan_futures.append(asyncio.create_task(self.scan_file(file_path, self.load_balancer_url))
async def scan_file(self, file_path, core_url):
api_url = f'{core_url}/file'
with open(file_path, 'rb') as file:
file_content = file.read()
headers = {'Content-Type': 'application/octet-stream', 'filename': file_path}
max_retries = 20 # Maximum number of retry attempts
retry_delay = 120 # Delay in seconds before retrying
for attempt in range(max_retries + 1):
try:
starttime = time.time()
response = requests.post(api_url, data=file_content, headers=headers)
endtime = time.time()
status_code = response.status_code
if status_code == 200:
self.post_wait = self.post_wait + endtime - starttime
self.num_post_req += 1
response_json = response.json()
data_id = response_json.get('data_id')
return status_code, response_json, data_id
if status_code == 503:
print(f"Received status code {status_code}. Retrying in {retry_delay} seconds...")
await asyncio.sleep(retry_delay)
else:
return None, None, None
except requests.RequestException as e:
return None, None, None
return None, None, None
OS | AWS instance type | vCPU | Memory (GB) | Network bandwidth (Gbps) | Disk type |
---|---|---|---|---|---|
CentOS 7 | c5.4xlarge | 16 | 32 | Up to 10 | SSD |
Dataset
Detailed information of dataset below will be used for testing:
File category | File type | Number of files | Total size (MB) | Average file size (MB) |
---|---|---|---|---|
Adobe | 370 | 385 MB | 1.0 MB | |
Executable | EXE | 45 | 309.5 MB | 6.9 MB |
MSI | 15 | 45.75 MB | 3.1 MB | |
Image | BMP | 80 | 515 MB | 6.4 MB |
JPG | 420 | 237.5 MB | 0.6 MB | |
PNG | 345 | 169 MB | 0.5 MB | |
Media | MP3 | 135 | 865 MB | 6.4 MB |
MP4 | 50 | 500 MB | 10.0 MB | |
Office | DOCX | 235 | 190 MB | 0.8 MB |
DOC | 225 | 486 MB | 2.2 MB | |
PPTX | 365 | 860 MB | 2.4 MB | |
PPT | 355 | 1950 MB | 5.5 MB | |
XLSX | 340 | 283.5 MB | 0.8 MB | |
XLS | 335 | 284.5 MB | 0.8 MB | |
Text | CSV | 100 | 236 MB | 2.4 MB |
HTML | 1075 | 76 MB | 0.1 MB | |
TXT | 500 | 210 MB | 0.4 MB | |
Archive | ZIP | Compressed files: 10 Extracted files: 270 | Compressed size: 125.5 MB Extracted size: 156.5 MB | Avg compressed size: 12.6 MB Avg extracted size: 0.6 MB |
Summary (compressed) | 5000 | 7728.5 MB | 1.55 MB average file size | |
Summary (extracted) | 5260 | 7759.5 MB | 1.48 MB average file size |
Product Information
Product versions:
- MetaDefender Core 5.14.0
- Engines:
- Metascan 8: Ahnlab, Avira, ClamAV, ESET, Bitdefender, K7, Quick Heal, VirIT Explorer
- Metascan 12: Metascan 8, Varist, Ikarus, Emsisoft, Tachyon
- Metascan 16: Metascan 12, NANO, Comodo, VirusBlokAda, Zillya!
- Deep CDR: 7.4.0
- Proactive DLP: 2.23.0
- Archive: 7.4.0
- File type analysis: 7.4.0
- File-based vulnerability assessment: 4.2.416.0
MetaDefender Core settings
General settings
- Turn off data retention
- Turn off engine update
Archive extraction settings
- Max recursion level: 99999999
- Max number of extracted files: 99999999
- Max total size of extracted files: 99999999
- Timeout: 10 minutes
- Handle archive extraction task as Failed: true
- Extracted partially: true
Metascan AV settings
- Max file size: 99999999
- Scan timeout: 10 minutes
- Per engine scan timeout: 1 minutes
Performance test results
MetaDefender Core with single engine (technology)
Summary metrics:
Use case | Scan duration | Throughput | Avg. processing time |
---|---|---|---|
(minutes) | (processed objects/hour) | (seconds/object) | |
Metascan 8 | 8 | 953,812 | 0.004 |
Metascan 12 | 14.4 | 529,895 | 0.007 |
Metascan 16 | 15.7 | 486,019 | 0.007 |
Deep CDR | 9.51 | 802,435 | 0.004 |
Proactive DLP | 7.2 | 1,047,992 | 0.003 |
Vulnerability | 6.2 | 1,230,726 | 0.003 |
System resource utilization:
Use case | Avg./Max CPU usage | Avg./Max CPU usage | Avg./Max RAM usage | Avg./Max RAM usage | Avg. Network speed | Avg. Network speed |
---|---|---|---|---|---|---|
Core 1 | Core 2 | Core 1 | Core 2 | Core 1 | Core 2 | |
(%) | (%) | (%) | (%) | (KB/s) | (KB/s) | |
Metascan 8 | 73.5 / 92.4 | 75.5 / 92 | 49.5 / 55 | 43 / 52 | 9,570 | 9,145 |
Metascan 12 | 87 / 98 | 89.4 / 99 | 53 / 57.4 | 44 / 49 | 5,657 | 5,840 |
Metascan 16 | 80 / 98.6 | 80.4 / 98.2 | 56.8 / 59.5 | 50.7 / 54.2 | 4,168 | 6,031 |
Deep CDR | 72.4 / 91.6 | 72 / 90.5 | 52.6 / 60 | 45.5 / 53 | 5,617 | 5,602 |
Proactive DLP | 43.2 / 80 | 49.4 / 81 | 51.3 / 57.5 | 44.1 / 53.1 | 8,460 | 8,383 |
Vulnerability | 61 / 85.5 | 61.7 / 88.3 | 48.4 / 53.5 | 41.5 / 49.3 | 11,692 | 12,076 |
MetaDefender Core with common engine packages
Summary metrics:
Use case | Scan duration | Throughput | Avg. processing time |
---|---|---|---|
(minutes) | (processed objects/hour) | (seconds/object) | |
Metascan 8 + Deep CDR | 13.2 | 578,068 | 0.006 |
Metascan 8 + Deep CDR + Proactive DLP | 14.92 | 511,553 | 0.007 |
Metascan 8 + Deep CDR + Proactive DLP + Vulnerability | 15.6 | 488,618 | 0.007 |
Metascan 12 + Deep CDR | 18.4 | 414,701 | 0.009 |
Metascan 12 + Deep CDR + Proactive DLP | 19.3 | 395,362 | 0.009 |
Metascan 12 + Deep CDR + Proactive DLP + Vulnerability | 19.4 | 393,324 | 0.009 |
Metascan 16 + Deep CDR | 21.1 | 361,635 | 0.01 |
Metascan 16 + Deep CDR + Proactive DLP | 22.5 | 339,133 | 0.01 |
Metascan 16 + Deep CDR + Proactive DLP + Vulnerability | 22.7 | 336,887 | 0.01 |
System resource utilization:
Use case | Avg./Max CPU usage | Avg./Max CPU usage | Avg./Max RAM usage | Avg./Max RAM usage | Avg. Network speed | Avg. Network speed |
---|---|---|---|---|---|---|
Core 1 | Core 2 | Core 1 | Core 2 | Core 1 | Core 2 | |
(%) | (%) | (%) | (%) | (KB/s) | (KB/s) | |
Metascan 8 + Deep CDR | 86.6 / 99 | 84.5 / 98.5 | 53.3 / 62.5 | 45.6 / 52 | 4,589 | 5,148 |
Metascan 8 + Deep CDR + Proactive DLP | 83 / 99 | 83.7 / 99.4 | 52.7 / 61.8 | 46 / 54 | 4,124 | 4,038 |
Metascan 8 + Deep CDR + Proactive DLP + Vulnerability | 87 / 99.7 | 89 / 99.5 | 53 / 61.2 | 45.3 / 52 | 4,513 | 4,079 |
Metascan 12 + Deep CDR | 87.3 / 99 | 90.4 / 99.3 | 55.1 / 62.3 | 46.8 / 53.8 | 3,438 | 3,340 |
Metascan 12 + Deep CDR + Proactive DLP | 90.7 / 99.3 | 90 / 99.5 | 56.8 / 63 | 47.3 / 56.2 | 4,122 | 3,337 |
Metascan 12 + Deep CDR + Proactive DLP + Vulnerability | 91.3 / 99.7 | 94.5 / 99.8 | 56.8 / 62.6 | 50.7 / 56.4 | 4,154 | 3,311 |
Metascan 16 + Deep CDR | 87.3 / 99.5 | 87.8 / 99.3 | 62.8 / 67.5 | 54.5 / 59.5 | 3,313 | 2,934 |
Metascan 16 + Deep CDR + Proactive DLP | 92.2 / 99.5 | 91.6 / 99.7 | 63.3 / 69.3 | 56 / 66.6 | 3,146 | 2,945 |
Metascan 16 + Deep CDR + Proactive DLP + Vulnerability | 95.4 / 99.5 | 94.8 / 99.6 | 64 / 69.2 | 55.3 / 62.5 | 3,810 | 2,677 |
Recommendations
Controlling total processing time of each MD Core server:
In this deployment model, we should organize and send files in the way that it best utilizes the load of each MD Core server. It is not a good practice if one Core server is free while the other one is busy. By optimizing the distribution of files, we can ensure that each Core server is utilized efficiently, thereby improving overall system performance. Furthermore, this approach can help prevent bottlenecks and minimize the chances of system overload.
Adding proper number of MD Core servers to the cluster:
Adding more Core servers to this model will increase more load on the shared database. When adding a new MD Core server, users should monitor performance of database server such as memory/CPU consumption, disk usage, network bandwidth, request response time and so on… to see if it still can handle the load. This is important in order to maintain optimal performance and ensure that the database server can continue to efficiently serve the needs of the system.
Optimizing database server for better performance:
Continuing to add more Core servers to this model may result in increased strain on the shared database. As such, it is crucial to ensure that the database is optimized to handle the additional load effectively. Users can consider adjusting default database settings of PostgresSQL to optimize for more data load if needed. Here is where we can adjust PostgresSQL database settings: <PostgreSQL install location\version>\data\postgresql.conf.
Besides that, MD Core also supports a parameter (db_connection) for users to specify max connections that MD Core can handle, take a look at this guideline: MetaDefender Configuration.