对蚂蚁金服面试中几个题目的浅析

简介: 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhaobryant/article/details/80738819 本文对今天蚂蚁金服面试中的几个问题进行简单阐述分析,望批评指正。
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhaobryant/article/details/80738819

本文对今天蚂蚁金服面试中的几个问题进行简单阐述分析,望批评指正。

搜索DAG问题

问题描述:给定一个图,寻找出里面所有的有向无环图(DAG)。

问题分析:

有向无环图

在图论中,如果一个有向图无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图(DAG图)。

解题思路

给定一个图,如下:

这里写图片描述

该图包括多个DAG有向无环图。

于是,对于整个算法,我们使用两个阶段来完成:

第一阶段:计算每个节点到其他节点的有向路径。为了防止成环,我们需要在合并时进行成环检测。

代码如下:

public class GraphDAGFinder {
    private Map<Node, NodeDAGList> nodeDAGListMap = new HashMap<>();

    public void findAllDAGinGraph(Set<Node> graphNodes) {
        for (Node node : graphNodes) {
            NodeDAGList dagList = this.findAllDAGbyNode(node);
            System.out.println("NODE [" + node.getId() + "] DAGS = ");
            for (NodeDAGItem item : dagList.getAllDagItems()) {
                item.printDAG();
            }
            System.out.println("-------------------------------");
        }
    }

    private NodeDAGList findAllDAGbyNode(Node n) {
        NodeDAGList dagList = this.nodeDAGListMap.get(n);
        if (dagList != null)
            return dagList;

        dagList = new NodeDAGList();
        NodeDAGItem item = new NodeDAGItem();
        item.addNode(n);
        dagList.addNodeDAGItem(item);

        if (n.getNextHops().isEmpty()) {
            return dagList;
        }

        for (Node nd : n.getNextHops()) {
            NodeDAGList tmplist = this.findAllDAGbyNode(nd);
            for (NodeDAGItem tmpit : tmplist.getAllDagItems()) {
                if (tmpit.hasNode(n))
                    continue;

                NodeDAGItem itm = tmpit.copyDAG();
                itm.addNode(n);

                dagList.addNodeDAGItem(itm);
            }
        }

        this.nodeDAGListMap.put(n, dagList);

        return dagList;
    }
}

第二阶段:路径合并成图。有了每个节点到其他节点的路径,我们可以对其所有路径进行合并,合并的规则是节点顺序不能交叉,否则会导致成环。在这里,为了合并路径,需要对不同的路径进行组合,然后再合并。

组合的代码如下,主要是寻找出对应路径集合的ID组合:

    private static Set<List<Integer>> computeCombs(List<Integer> idxs) {
        Set<List<Integer>> combinations = new HashSet<>();
        List<Integer> comb = new ArrayList<>();
        for (int i = 1; i < idxs.size(); i++) {
            getNCombs(nodes, 0, i, comb, combinations);
        }
        return combinations;
    }

    private static void getNCombs(List<Integer> idxs, int index, int len, List<Integer> comb, Set<List<Integer>> combinations) {
        if (len == 0) {
            combinations.add(comb);
            return;
        }

        if (index == idxs.size())
            return;

        comb.add(idxs.get(index));
        getNCombs(idxs, index + 1, len - 1, comb, combinations);
        comb.remove(idxs.get(index));
        getNCombs(idxs, index + 1, len, comb, combinations);
    }

合并流程如下:

从源节点开始,所有路径向后遍历,直到出现交叉,此时,选择某一分支停止向后遍历。以此类推,直到所有分支全部停止或遍历完成。

这里的合并可能有多个结果,统一存储。

最后的结果如下所示:

这里写图片描述

后续工作

对于整个问题,我们这里采用了两阶段的处理过程,能够得到结果,但是对于大规模节点图,仍然存在时间复杂度较高的问题。因此,后续工作可以围绕如何进一步降低搜索空间的方式来进行进一步的优化。比如,换一个维度,从边入手,而不是从节点入手;又如,使用回溯非递归+全局变量存储的方式来代替现有的递归方案,从而进一步减少栈溢出错误;再如,查阅论文文献,参考别人的算法,理解吃透优化。

脑裂问题

摘自CSDN博客:

在高可用HA系统中,当联系两个节点的心跳线断开时,原本为一个整体的动作协调的HA系统,就会分裂成为两个独立的个体。这时,由于两个节点相互失去了联系,都以为是对方出现了故障,两个节点上的HA软件就会像裂脑人一样,争夺共享资源,争相提供应用服务,这个时候就会出现严重后果:

  • 共享资源被瓜分,两个节点的服务都起不来;
  • 两个节点的服务都起来了,但同时读写共享资源,导致数据损坏。

一般来说,脑裂问题产生的原因主要包括下面几个:

  • 高可用服务器之间的心跳线发生故障,导致无法正常通信;
  • 高可用服务器开启了iptables防火墙,阻挡了心跳消息传输;
  • 高可用服务器上网卡地址等信息配置不正确,导致发送心跳消息失败。

可以认为,在集群或者主备模式下,由于网络原因导致节点之间不可达,此时,每个网络分区就会自主选择出master节点,从而造成原来的集群存在多个master节点。这些master节点会争夺共享资源,从而导致系统出现服务不可用或资源损坏等问题。

解决方案:

  1. 添加冗余的心跳线,如双心跳线,尽量减少“脑裂”的发生几率。
  2. 设置仲裁机制,当心跳线完全断开时,两个节点相互ping一下参考IP,不通则表示断点就出在本端,此时可自动重启,从而彻底释放可能还占用的共享资源。
  3. 增加节点至奇数个,通过raft或paxos协议来进行投票选举主节点。
目录
相关文章
|
8月前
|
Web App开发 缓存 前端开发
浏览器常见面试题目及详细答案解析
本文围绕浏览器常见面试题及答案展开,深入解析浏览器组成、内核、渲染机制与缓存等核心知识点。内容涵盖浏览器的主要组成部分(如用户界面、呈现引擎、JavaScript解释器等)、主流浏览器内核及其特点、从输入URL到页面呈现的全过程,以及CSS加载对渲染的影响等。结合实际应用场景,帮助读者全面掌握浏览器工作原理,为前端开发和面试提供扎实的知识储备。
348 4
|
8月前
|
缓存 NoSQL Java
Java Redis 面试题集锦 常见高频面试题目及解析
本文总结了Redis在Java中的核心面试题,包括数据类型操作、单线程高性能原理、键过期策略及分布式锁实现等关键内容。通过Jedis代码示例展示了String、List等数据类型的操作方法,讲解了惰性删除和定期删除相结合的过期策略,并提供了Spring Boot配置Redis过期时间的方案。文章还探讨了缓存穿透、雪崩等问题解决方案,以及基于Redis的分布式锁实现,帮助开发者全面掌握Redis在Java应用中的实践要点。
474 6
|
8月前
|
算法 Java 关系型数据库
校招 Java 面试基础题目解析及学习指南含新技术实操要点
本指南聚焦校招Java面试,涵盖Java 8+新特性、多线程与并发、集合与泛型改进及实操项目。内容包括Lambda表达式、Stream API、Optional类、CompletableFuture异步编程、ReentrantLock与Condition、局部变量类型推断(var)、文本块、模块化系统等。通过在线书店系统项目,实践Java核心技术,如书籍管理、用户管理和订单管理,结合Lambda、Stream、CompletableFuture等特性。附带资源链接,助你掌握最新技术,应对面试挑战。
198 2
|
8月前
|
安全 Java 编译器
Java 校招面试题目合集及答案 120 道详解
这份资料汇总了120道Java校招面试题目及其详细答案,涵盖Java基础、JVM原理、多线程、数据类型、方法重载与覆盖等多个核心知识点。通过实例代码解析,帮助求职者深入理解Java编程精髓,为校招面试做好充分准备。无论是初学者还是进阶开发者,都能从中受益,提升技术实力和面试成功率。附带的资源链接提供了更多学习材料,助力高效备考。
497 3
|
8月前
|
存储 算法 Java
校招 java 面试基础题目及解析
本文围绕Java校招面试基础题目展开,涵盖平台无关性、面向对象特性(封装、继承、多态)、数据类型、关键字(static、final)、方法相关(重载与覆盖)、流程控制语句、数组与集合、异常处理等核心知识点。通过概念阐述和代码示例,帮助求职者深入理解并掌握Java基础知识,为校招面试做好充分准备。文末还提供了专项练习建议及资源链接,助力提升实战能力。
209 0
|
运维 Linux Docker
Docker笔记(个人向) 简述,最新高频Linux运维面试题目分享
Docker笔记(个人向) 简述,最新高频Linux运维面试题目分享
|
监控 架构师 Java
从蚂蚁金服面试题窥探STW机制
在Java虚拟机(JVM)中,垃圾回收(GC)是一个至关重要的机制,它负责自动管理内存的分配和释放。然而,垃圾回收过程并非没有代价,其中最为显著的一个影响就是STW(Stop-The-World)机制。STW机制是指在垃圾回收过程中,JVM会暂停所有应用线程的执行,以确保垃圾回收器能够正确地遍历和回收对象。这一机制虽然保证了垃圾回收的安全性和准确性,但也可能对应用程序的性能产生显著影响。
220 2
|
缓存 关系型数据库 MySQL
面试题目总结
面试题目总结
368 6
|
Java C++ Python
【面试宝典】深入Python高级:直戳痛点的题目演示(下)
【面试宝典】深入Python高级:直戳痛点的题目演示(下)
|
设计模式 Unix Python
【面试宝典】深入Python高级:直戳痛点的题目演示(上)
【面试宝典】深入Python高级:直戳痛点的题目演示(上)