zoukankan      html  css  js  c++  java
  • 配置文件那些事

    深夜的办公室灯火通明,为了今晚的大版本上线,同事们已经连续奋战了几十个日日夜夜。"但愿今晚平安上线,接下来就能休息几天了",小明这样想着,打开终端登录服务器,等待操作时间到来。

    作为一名运维工程师,这样的版本升级小明经历过无数次,况且在之前进行过数次模拟升级,这次想必也不会出什么太大的问题。

    升级时间到了,小明深吸一口气,手指开始在键盘上飞舞,停止进程、备份文件、更新程序、启动、验证,一系列步骤有条不紊的进行着……

    “小明,为什么我这里vi打开文件是乱码?”小明停下手中的事情,循声望去,原来是开发人员小刚。“把你的终端编码改一下” “在哪里改?” “就在设置那里” “找不到啊,过来帮忙看看啦” 小明无奈起身,走到小刚身边,教他修改终端字符编码……

    同事们都在紧张的忙碌着,墙上挂钟那红色的指针也在不知疲惫的一圈又一圈的行进。。。

    “警告警告,XX服务器 /data 占用率 100%,请及时处理。”小明赶紧登录检查,发现该目录下的一个 log 占了90%的磁盘空间,里面的 xx.debug.log 占用达几十个G。看来是有人打开了调试模式,小明一边清理日志,一边在群里发问。
    原来是小刚验证的时候发现逻辑有点对不上,然后把调试模式打开了,大量的信息很快就把磁盘空间撑爆。处理完这个问题,小明继续之前的工作。。。

    “小明,我加了个配置项,需要同步一下全部服务器。”小刚走了过来,“好,没问题。”小明平静的说到,心想这家伙又来搞事。

    过了一会,小刚又过来了:“不好意思啊,刚刚那个配置项要改一下,改成xxx。” 小明有点想骂人了,但还是平淡的说:“要改成什么?”

    ……

    配置文件那些痛

    故事有些夸大的成份,但里面的场景确实有发生过,相信很多运维同学也是深有体会。维护一套系统,少不了的就是配置文件,故事里修改配置的几大痛点就是我想要解决的:

    • 连接服务器的终端字符编码不一,配置内容可能显示乱码
    • 不同的人修改了配置项,不知道改了什么内容
    • 修改了配置项后如何同步
    • 同步后又反悔了,怎样快速改回之前的内容

    如果我们提供一个统一的修改入口,那么编码不一的问题是不是就解决了?
    有人修改了内容,我们就保存一个快照;后面若是反悔,可以马上使用这个快照,是不是同时满足了保存修改和修改历史?
    快速同步,从主控端分发过去行不行?

    我看行!

    配置文件管理

    使用B/S架构来做配置管理是很自然的事情,实现起来也比较简单:

    • 浏览器作为统一的修改入口
    • 后端保存文件的修改历史,每一次修改都生成一个新的修订号
    • 同步到相关服务器就是将配置内容下发

    那么问题又来了:
    单个配置文件管理起来不难,要是多个不同的文件呢?多个文件我只改了其中一个呢?新增加一个文件又不想改动原来的呢?

    配置文件包

    上述问题,我们可以引入“包”这个概念,一个“包”里可以有一个或多个配置文件,我们对“包”作一个快照,也就是历史版本,那么问题就迎刃而解。

    比如可以设计成下图的样子:

    配置文件包

    A B C 代表3个配置文件包,里面的 a.con b.conf aa.txt 就是具体的文件,数字代表修订号。这样就保存了修改历史,方便回溯,对应的数据模型用 django 的 models 来表示:

    class ConfRevision(models.Model):
        name = models.CharField(max_length=48, help_text='名称')
        revision = models.PositiveIntegerField(help_text='修订号')
        is_default = models.BooleanField(default=False, help_text='是否默认')
        created = models.DateTimeField(auto_now_add=True)
        created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
        description = models.CharField(max_length=120, blank=True, null=True)
    
    class ConfDetail(models.Model):
        FILE_TYPE = (
            ('ini', 'ini'),
            ('conf', 'conf'),
            ('json', 'json'),
            ('yml', 'yml'),
            ('toml', 'toml'),
        )
        name = models.CharField(max_length=48, help_text='配置文件名称')
        type = models.CharField(max_length=4, choices=FILE_TYPE)
        content = models.TextField(null=True, blank=True)
        created = models.DateTimeField(auto_now_add=True)
        created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.DO_NOTHING)
        description = models.CharField(max_length=120, blank=True, null=True)
        rev = models.ForeignKey(ConfRevision, on_delete=models.DO_NOTHING)
    

    内容下发

    有句名言如是说:“手里拿着锤子,看什么都像是钉子”。

    ansible 作为运维利器简直是深得我心,有了这把锤子,很多操作都是经由它去完成的,比如文件下发、备份、系统操作等。一开始就是想着用ansible去同步全部主机的内容,但是一些情况下会有问题:

    • 假如当前有个待同步的主机宕机,本次的同步会漏掉一部分主机
    • 资源抢占问题:多个人同时修改,如果后面的修改先同步到目标主机,而前面的修改延迟到达,导致内容覆盖,本来应该全网统一的内容在个别机器上不一致

    为了尽量避免上面情况发生,我们需要另一种方式,即使出现极端情况也能保证配置文件全网一致性:
    在每台主机上启动一个代理,从一个中心存储拉取内容,当中心存储的内容变化时通知代理。

    分析配置文件,全部是文本内容,很方便使用 key-value 存储,进而想到业界知名的 k-v 存储redis,然而数据持久化并非redis擅长,排除。

    etcd 倒是一个不错的选择,满足我们所有要求:

    • 支持 key-value
    • 分布式、强一致性
    • 支持发布-订阅模式

    那么决定是他了。

    配置同步代理

    主机上的代理程序要简单、支持etcd、少依赖,有现成的 confd 就不用重新造轮子了。

    功能实现

    当收到新增请求(因为做了版本管理,所以每次的修改请求都是创建一个新的版本),后台的处理流程:

    1. 校验数据:非空校验、内容格式校验
    2. 写入数据库,同时将内容写入etcd
    3. 主机上的 confd 监听到对应 key 的内容变化,同步内容到本地

    若要回退,只需要将对应的历史版本内容写入etcd
    而且记录历史版本,搞事的人就无法甩锅,大家可以尽情的嘲讽他~~~

    这里实现了全网配置统一,但是如果有某个新功能需要个性化的配置,又该怎么办呢?欲知方法如何,且听下回分解。

  • 相关阅读:
    小编见过的验证方式汇总
    Burp Suite Professional 针对APP抓包篡改数据提交【安全】
    关于Chrome 67 以后版本无法离线安装扩展的解决方法
    Postman 中上传图片的接口怎么做参数化呢?
    字符串-不同的编码格式下所占用的字节数【转】
    Java RandomAccessFile用法 【转】
    URI和URL的区别 【转】
    Java多线程-线程的同步与锁【转】
    浅谈Java多线程的同步问题 【转】
    Java中浮点数的精度问题 【转】
  • 原文地址:https://www.cnblogs.com/wbjxxzx/p/12078297.html
Copyright © 2011-2022 走看看