from olc.statistic.sliding_window import SlidingWindow
from olc.utils.atomic_num import AtomicNum
class _RequestBucket:
"""
请求统计桶
承载通过/拒绝请求计数、通过请求响应时间相关聚合值
所有计数字段使用 AtomicNum 保证多线程下累加不丢失;
min/max 响应时间使用普通可空字段,并发下接受少量竞争误差。
"""
def __init__(self):
self.pass_num: AtomicNum = AtomicNum(0)
self.block_num: AtomicNum = AtomicNum(0)
self.pass_rt: AtomicNum = AtomicNum(0.0)
self.min_pass_rt: float | None = None
self.max_pass_rt: float | None = None
def add_pass_num(self, count: int = 1):
"""
原子地累加通过请求计数
:param count: 累加值,默认为 1
:return:
"""
self.pass_num.add(count)
def add_block_num(self, count: int = 1):
"""
原子地累加拒绝请求计数
:param count: 累加值,默认为 1
:return:
"""
self.block_num.add(count)
def add_pass_rt(self, rt: float):
"""
记录单次通过请求响应时间,同步更新累计响应时间、记录次数、最小值与最大值
:param rt: 单次响应时间(毫秒)
:return:
"""
self.pass_rt.add(rt)
if self.min_pass_rt is None or rt < self.min_pass_rt:
self.min_pass_rt = rt
if self.max_pass_rt is None or rt > self.max_pass_rt:
self.max_pass_rt = rt
def get_pass_num(self) -> int:
"""
获取当前桶的通过请求次数
:return: 通过请求次数
"""
return int(self.pass_num.get())
def get_block_num(self) -> int:
"""
获取当前桶的拒绝请求次数
:return: 拒绝请求次数
"""
return int(self.block_num.get())
def get_pass_rt(self) -> float:
"""
获取当前桶的累计通过响应时间
:return: 累计响应时间
"""
return float(self.pass_rt.get())
def get_min_pass_rt(self) -> float | None:
"""
获取当前桶的最小响应时间
:return: 最小响应时间,无记录时返回 None
"""
return self.min_pass_rt
def get_max_pass_rt(self) -> float | None:
"""
获取当前桶的最大响应时间
:return: 最大响应时间,无记录时返回 None
"""
return self.max_pass_rt
def reset(self):
"""
将桶内所有统计字段复位到初始值
:return:
"""
self.pass_num.set(0)
self.block_num.set(0)
self.pass_rt.set(0)
self.min_pass_rt = None
self.max_pass_rt = None
class RequestStatSlidingWindow(SlidingWindow[_RequestBucket]):
"""
请求统计滑动窗口
在通用滑动窗口骨架上提供"通过/拒绝请求数 + 通过请求响应时间"业务接口
"""
def _create_bucket(self) -> _RequestBucket:
return _RequestBucket()
def _reset_bucket(self, bucket: _RequestBucket) -> None:
"""
请求统计桶复位:把通过/拒绝计数与响应时间统计字段重置为初始值
:param bucket: 待复位的桶
:return:
"""
bucket.reset()
def record_pass_num(self, count: int = 1) -> None:
"""
记录通过请求次数到当前时间所在桶
:param count: 通过请求次数,默认为 1
:return:
"""
bucket = self.current_bucket()
bucket.value.add_pass_num(count)
def get_pass_num_sum(self) -> int:
"""
获取所有活跃桶的通过请求次数总和
:return: 通过请求次数总和
"""
buckets = self.get_all_buckets()
pass_num_sum: int = 0
for bucket in buckets:
pass_num_sum += bucket.get_pass_num()
return pass_num_sum
def record_block_num(self, count: int = 1) -> None:
"""
记录拒绝请求次数到当前时间所在桶
:param count: 拒绝请求次数,默认为 1
:return:
"""
bucket = self.current_bucket()
bucket.value.add_block_num(count)
def get_block_num_sum(self) -> int:
"""
获取所有活跃桶的拒绝请求次数总和
:return: 拒绝请求次数总和
"""
buckets = self.get_all_buckets()
block_num_sum: int = 0
for bucket in buckets:
block_num_sum += bucket.get_block_num()
return block_num_sum
def record_pass_rt(self, rt: float) -> None:
"""
记录单次通过请求响应时间到当前时间所在桶
同时更新桶内的响应时间总和、响应时间计数、最小响应时间和最大响应时间
:param rt: 单次请求响应时间(毫秒)
:return:
"""
bucket = self.current_bucket()
bucket.value.add_pass_rt(rt)
def get_pass_avg_rt(self) -> float:
"""
获取通过平均时延
"""
buckets = self.get_all_buckets()
pass_rt_sum: float = 0.0
pass_num: float = 0.0
for bucket in buckets:
pass_rt_sum += bucket.get_pass_rt()
pass_num += bucket.get_pass_num()
if pass_rt_sum == 0 or pass_num == 0:
return 0.0
return pass_rt_sum / pass_num
def get_pass_rt_sum(self) -> float:
"""
获取所有活跃桶的响应时间总和
:return: 响应时间总和
"""
buckets = self.get_all_buckets()
pass_rt_sum: float = 0.0
for bucket in buckets:
pass_rt_sum += bucket.get_pass_rt()
return pass_rt_sum
def get_pass_rt_min(self) -> float | None:
"""
获取所有活跃桶的最小响应时间
:return: 最小响应时间,无记录时返回 None
"""
buckets = self.get_all_buckets()
min_rt: float | None = None
for bucket in buckets:
bucket_min = bucket.get_min_pass_rt()
if bucket_min is None:
continue
if min_rt is None or bucket_min < min_rt:
min_rt = bucket_min
return min_rt
def get_pass_rt_max(self) -> float | None:
"""
获取所有活跃桶的最大响应时间
:return: 最大响应时间,无记录时返回 None
"""
buckets = self.get_all_buckets()
max_rt: float | None = None
for bucket in buckets:
bucket_max = bucket.get_max_pass_rt()
if bucket_max is None:
continue
if max_rt is None or bucket_max > max_rt:
max_rt = bucket_max
return max_rt