• 工程上遇到的问题和技巧


    一些文章

    1. python good book

    2. 函数式编程思维

    设计

    接口定义

    1. 一个大系统在设计上:

    // 这里写主要
    message SubMessageBody {
    }
    
    // 这个用来分块合并方便点
    message SubMessage {
      repeated SubMessageBody sub_message_body = 1;
    }
    
    // 这个是用于后面接入更多的message
    messgae GlobalMessage {
      optional SubMessage sub_message = 1;
    }
    View Code 

    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
    View Code

    负载均衡

    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 对象。
    View Code

    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
    Process checker

    写一个看门狗服务

    1. 记录自己的pid(父进程),维护一个进程间可以通信的变量,is_running,在真实的handler里面每次运行前都check一下,不是running就可以关闭了。。

      1.1 父进程自己起一个线程来监控自己,用上面的进程checker就好

    2. 子进程ID记录在一个set里面,子进程每次执行的就是handle函数,这些自己定义就好

    3. 父进程任务就是,监控子进程. 可以用 cpid, status = os.waitpid(-1, os.WNOHANG)来查看有哪一些子进程挂了,挂了就重启

  • 相关阅读:
    TypeError: run() missing 2 required positional arguments: 'rerun' and 'save_last_run'
    在wsl的ubuntu上安装vcpkg
    vscode + WSL +Ubuntu编程解决方案
    clion debug模式带参数运行程序
    关于jdk1.7之后String的intern方法的一点理解
    关于java中split的坑
    关于向HashMap存放数据出现顺序混乱的问题
    oracle外键禁用
    oracle复杂查询(二)
    oracle复杂查询(一)
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/13627661.html
Copyright © 2020-2023  润新知