一些文章
2. 函数式编程思维
设计
接口定义
1. 一个大系统在设计上:
// 这里写主要 message SubMessageBody { } // 这个用来分块合并方便点 message SubMessage { repeated SubMessageBody sub_message_body = 1; } // 这个是用于后面接入更多的message messgae GlobalMessage { optional SubMessage sub_message = 1; }
2. 为了实现流式处理,Kafka引入了时间戳的概念
3. 顺序写磁盘比随机访问内存还快
middleware
在python中,很容易实现中间件,只需要一个顺序数组
middleware = [logging_middleware, retry_middleware]
每一个中间件自己控制执行时候(before_request还是after_request)
在py中,函数是一等公民,实现起来很简单
def middleware(): try: # do sth before request result = origin_func() except Exception: # do sth after request on error happend else: # do sth after request return result finally: # do sth after request no matter what error happend
然后只需要简单包装一下目标业务函数func,可以看看函数式编程的compose方法
def compose(ctx, fn): def next(*args, **kw): return fn(*args, **kw) # compose middlewares for middleware in middlewares: # a wrapper for (middleware, next) func def wrapper(middleware=middleware, next=next): def new_next(*args, **kw): ctx.next = next return middlewares(*args, **kw) new_next.__name__ = getattr(middleware, '__name__') return new_next next = wrapper() return next
负载均衡
1. 各大负载均衡算法汇总
2. 普通round robin
就是默认的取余请求, 缺点是没考虑到后端实际的负载,更没考虑到加权,有时候有些后端部署在物理机,有些部署在容器,能力肯定是不一样的
3. 普通加权
就是加上一个权重,每次用的时候随机一个值然后选择。可以参考 leetcode_random_weight_pick
4. 平滑加权轮询
普通加权其实没有平滑可言,有可能出现同一时间5个请求都落在A机器上(因为A机器权重就是5),而且普通加权的是基于概率的,随机来的。这里保持一个全局的堆排之类的,可以做到平滑而且不基于概率。
##### 上面的都没考虑到后端实际负责,其实请求也不是全部都一样,有些请求本来就慢,这些没考虑到这种情况 #####
5. 全局最小链接
通过服务端上报链接数+连接数定时timeout (不然有可能会有bug)的方法,可以知道后端现实的负载,所以可以根据这个来proxy
面向对象
面向对象 object.method(),相比于method(object)的好处有
1. 避免用户改变object这个对象的指向,从而让method里面需要做很多check参数合法性的逻辑
需要特别注意的是,ctx.next 和下一层的中间件或者处理函数签名有一个区别:ctx.next 的函数签名不需要有第一个参数 ctx。
这么设计的原因是,对于中间件来说,传给下一层的输入参数,以及下一层返回的结果都是允许中间件做修改,或者直接替换的。但是对于 ctx,整个处理流程只允许修改、新增其中的数据,但是不允许替换 ctx 对象本身给下一层处理函数,因此设计上就避免了显式传递 ctx 对象。
Util function
进程监控checker
def check_parent_status(self): pps = psutil.Process(self.pid) while True: time.sleep(1.3) try: if pps.status() in (psutil.STATUS_DEAD, psutil.STATUS_STOPPED): self.is_running.value = False except psutil.NoSuchProcess: self.is_running.value = False
写一个看门狗服务
1. 记录自己的pid(父进程),维护一个进程间可以通信的变量,is_running,在真实的handler里面每次运行前都check一下,不是running就可以关闭了。。
1.1 父进程自己起一个线程来监控自己,用上面的进程checker就好
2. 子进程ID记录在一个set里面,子进程每次执行的就是handle函数,这些自己定义就好
3. 父进程任务就是,监控子进程. 可以用 cpid, status = os.waitpid(-1, os.WNOHANG)来查看有哪一些子进程挂了,挂了就重启