Example #1
0
        // 检查App间的冲突
        public bool IsConflictWith(AppInst inst)
        {
            var appB    = inst.App;
            var appBCnt = AppCountKv.GetValueOrDefault(appB, defaultValue: 0);

            foreach (var kv in AppCountKv)
            {
                //<appA, appB, bLimit>
                var appA = kv.Key; //appA是已部署的应用
                if (appA == null)
                {
                    continue;
                }

                var bLimit = appA.XLimit(appB.Id);

                if (appBCnt + 1 > bLimit)
                {
                    return(true);
                }

                //同时,已部署的应用不会与将要部署的inst的规则冲突
                //<appB, appA, aLimit>
                var aLimit  = appB.XLimit(appA.Id);
                var appACnt = kv.Value;

                if (appACnt > aLimit)
                {
                    return(true);
                }
            }

            return(false);
        }
Example #2
0
        // 假设从机器上移除 instOld 之后, 检查 instNew 是否有亲和冲突
        // 注意参数顺序
        private static bool HasConflict(AppInst instOld, AppInst instNew)
        {
            var m          = instOld.Machine;
            var appCountKv = m.AppCountKv; //直接修改

            var appOld = instOld.App;

            //appOld的所有实例都在之前的循环move到别的机器了
            if (!appCountKv.ContainsKey(appOld))
            {
                return(false);
            }

            var appOldCnt = appCountKv[appOld];

            if (appOldCnt == 1)
            {
                appCountKv.Remove(appOld);
            }
            else
            {
                appCountKv[appOld] = appOldCnt - 1;
            }

            var result = m.IsConflictWith(instNew);

            appCountKv[appOld] = appOldCnt; //恢复原状

            return(result);
        }
Example #3
0
        //将inst移动到mDest,如果移动失败,deta为正数,或double.MaxValue
        //TODO: Move到空机器
        private static bool TryMove(Machine mDest, AppInst inst, out double delta)
        {
            delta = double.MaxValue;

            if (!mDest.HasApp || !mDest.CanPut(inst))
            {
                return(false);
            }

            var mSrc        = inst.Machine;
            var scoreBefore = mSrc.Score + mDest.Score;

            mDest.TryPut(inst, ignoreCheck: true);
            var scoreAfter = mSrc.Score + mDest.Score;

            delta = scoreAfter - scoreBefore;

            if (delta > 0.0
                // delta == 0.0 && scoreAfter == 2.0
                // 即 move 前后两个机器的 cpu util 均小于 0.5,需要 move
                // ReSharper disable once CompareOfFloatsByEqualityOperator
                || delta == 0.0 && scoreAfter > 2.0 ||
                delta < 0.0 && delta > -0.00001)
            {
                mSrc.TryPut(inst, ignoreCheck: true); //恢复原状
            }

            return(delta <= 0.0);
        }
Example #4
0
        // 检查当前累积使用的资源量 usage **加上 r 之后** 是否会超出 capacity,
        // 不会修改当前资源量
        public bool IsOverCapacityWith(AppInst inst, double cpuUtilLimit = 1.0)
        {
            var r = inst.R;

            return(_usage.Disk + r.Disk > CapDisk ||
                   _usage.P + r.P > Capacity.P ||
                   _usage.Pm + r.Pm > Capacity.Pm ||
                   _usage.M + r.M > Capacity.M ||
                   _usage.Cpu.MaxWith(r.Cpu) > CapCpu * cpuUtilLimit || //TODO: Round?
                   _usage.Mem.MaxWith(r.Mem) > CapMem);
        }
Example #5
0
        public void Remove(AppInst inst,
                           // 兼容:如果从是 PrevMachine 调用的,则不修改 Machine及Deployed 字段,仅扣减资源和相关计数
                           bool setDeployFlag = true)
        {
            //
            if (!AppInstSet.Remove(inst))
            {
                return;
            }

            AppInstCount -= 1;
            HasApp        = AppInstCount != 0;
            _usage.Subtract(inst.R);

            _score = double.MinValue;
            _avail.Invalid();
            _xUsage.Invalid();

            AppCountKv[inst.App] -= 1;
            if (AppCountKv[inst.App] == 0)
            {
                AppCountKv.Remove(inst.App);
                AppKv.Remove(inst.App);
            }
            else if (AppKv[inst.App] == inst)
            {
                //要移除的 inst 恰好是该类 App 的代表,移除后需要找一个替补
                //因为计数不为0,肯定存在替补
                var found = false;
                foreach (var i in AppInstSet)
                {
                    if (i.App == inst.App)
                    {
                        AppKv[i.App] = i;
                        found        = true;
                        break;
                    }
                }

                if (!found)
                {
                    throw new Exception($"[RemoveInst]: AppKv cannot find a substitution for {inst}");
                }
            }

            // 兼容:如果是从 PrevMachine 调用的,不修改下面这两个字段
            if (!setDeployFlag)
            {
                return;
            }

            inst.Machine    = null;
            inst.IsDeployed = false;
        }
Example #6
0
        //如果交换失败,deta为正数,或double.MaxValue
        //引入u1,u2,diff,shrink这几个参数是为了减少GC
        private static bool TrySwap(AppInst inst1, AppInst inst2,
                                    Resource u1, Resource u2, Resource diff, Resource shrink, out double delta)
        {
            var m1 = inst1.Machine;
            var m2 = inst2.Machine;

            diff.DiffOf(inst1.R, inst2.R);

            delta = double.MaxValue;
            m1.Usage.ShrinkTo(shrink);
            u1.DiffOf(shrink, diff);
            if (u1.AnyLargerThan(m1.Capacity))
            {
                return(false);
            }

            m2.Usage.ShrinkTo(shrink);
            u2.SumOf(shrink, diff);
            if (u2.AnyLargerThan(m2.Capacity))
            {
                return(false);
            }

            m1.Usage.Cpu.ShrinkTo(shrink.Cpu);
            var scoreBefore = shrink.Cpu.Score(m1.CapCpu, m1.AppInstCount);

            m2.Usage.Cpu.ShrinkTo(shrink.Cpu);
            scoreBefore += shrink.Cpu.Score(m2.CapCpu, m2.AppInstCount);

            delta = u1.Cpu.Score(m1.CapCpu, m1.AppInstCount) + u2.Cpu.Score(m2.CapCpu, m2.AppInstCount)
                    - scoreBefore;

            //期望delta是负数,且绝对值越大越好
            if (delta >= 0.0 || delta < 0.0 && delta > -0.00001)
            {
                return(false);
            }

            if (HasConflict(inst1, inst2) ||
                HasConflict(inst2, inst1))
            {
                return(false);
            }

            m1 = inst1.Machine;
            m2 = inst2.Machine;

            m1.TryPut(inst2, ignoreCheck: true);
            m2.TryPut(inst1, ignoreCheck: true);

            return(true);
        }
Example #7
0
        // 读取实例,保持原有顺序!
        private void ReadAppInst(string csv)
        {
            var i = 0;

            Util.ReadCsv(csv, parts => {
                var instId = parts[0].Id();
                var appId  = parts[1].Id();
                var app    = DataSet.AppKv[appId];
                var inst   = new AppInst(instId, app);
                app.InstCount++;
                AppInsts[i++] = inst;
            }
                         );
        }
Example #8
0
        // 如果添加成功,会自动从旧机器上迁移过来(如果有的话)
        public bool TryPut(AppInst inst, double cpuUtilLimit = 1.0, bool ignoreCheck = false,
                           bool autoRemove = true) // 兼容:分轮次迁移不自动迁移
        {
            if (AppInstSet.Contains(inst))
            {
                return(true); //已经存在inst了,幂等
            }

            if (!ignoreCheck && !CanPut(inst, cpuUtilLimit))
            {
                return(false);
            }

            if (!AppInstSet.Add(inst))
            {
                throw new Exception($"[TryPut]: {inst}");
            }

            AppInstCount += 1;
            HasApp        = true;
            _usage.Add(inst.R);

            _score = double.MinValue;
            _avail.Invalid();
            _xUsage.Invalid();

            AppCountKv[inst.App] = AppCountKv.GetValueOrDefault(inst.App, defaultValue: 0) + 1;

            // 每类App只需保存一个inst作为代表即可
            AppKv.TryAdd(inst.App, inst);

            if (autoRemove)
            {
                inst.Machine?.Remove(inst);
            }
            else
            {
                inst.PrevMachine = inst.Machine;
            }

            inst.Machine    = this;
            inst.IsDeployed = true;

            return(true);
        }
Example #9
0
 public string FailureMsg(AppInst inst)
 {
     return($"inst_{inst.Id},m_{Id}" +
            $"{(IsOverCapacityWith(inst) ? ",R" : "")}" +
            $"{(IsConflictWith(inst) ? ",X" : "")}");
 }
Example #10
0
 public bool CanPut(AppInst inst, double cpuUtilLimit = 1.0)
 {
     return(!IsOverCapacityWith(inst, cpuUtilLimit) &&
            !IsConflictWith(inst));
 }