`

微服务架构下的服务关联图

阅读更多

在微服务架构下,服务之间的关系是非常复杂的,是一个典型的有向有环图,在一个中等规模的项目中,一般会有100多个服务,而大型项目中,则会有数百个服务。

 

假设我们有如下6个服务:

 

 

每个服务都指定了自己依赖的服务:

 

AaaSvc:

BbbSvc:

CccSvc:

DddSvc:

EeeSvc:

FffSvc:

我们如何把如上6个服务中跟服务AaaSvc相关的服务可视化呢?如下图所示:

要完成这样的服务关联图,需要如下几个步骤:

 

1、遍历指定项目下的所有服务,构造两个map,serviceToServiceMap 和 reverseServiceToServiceMap,存储所有服务的直接依赖和反向直接依赖。

 

    public static void runService(String projectId,
                            Map<String, Set<String>> serviceToServiceMap,
                            Map<String, Set<String>> reverseServiceToServiceMap){
        if(! (serviceToServiceMap instanceof ConcurrentHashMap) ){
            throw new RuntimeException("参数serviceToServiceMap必须是ConcurrentHashMap的实例");
        }
        if(! (reverseServiceToServiceMap instanceof ConcurrentHashMap) ){
            throw new RuntimeException("参数reverseServiceToServiceMap必须是ConcurrentHashMap的实例");
        }
        MetaServiceRepository metaServiceRepository = SpringContextUtils.getBean("metaServiceRepository");
        List<MetaService> services = metaServiceRepository.findByProjectId(projectId);
        services.parallelStream().filter(item->!item.getName().contains("Deprecate")).forEach(item->{
            List<DependencyService> dependencyServices = item.constructDependencyServices();
            String key = item.getName()+"("+item.getDescription()+")";
            if(dependencyServices != null){
                dependencyServices.parallelStream().filter(dep->!dep.getName().contains("Deprecate")).forEach(dependencyService->{
                    String value = dependencyService.getName()+"("+dependencyService.getDescription()+")";
                    serviceToServiceMap.putIfAbsent(key, Collections.newSetFromMap(new ConcurrentHashMap<>()));
                    serviceToServiceMap.get(key).add(value);
                    reverseServiceToServiceMap.putIfAbsent(value, Collections.newSetFromMap(new ConcurrentHashMap<>()));
                    reverseServiceToServiceMap.get(value).add(key);
                });
            }
        });
    }

 

2、以服务AaaSvc为入口,利用直接依赖和反向直接依赖,构造服务依赖图和反向服务依赖图。

 

String name = metaService.getName()+"("+metaService.getDescription()+")";

Set<String> set = serviceToServiceMap.get(name);
ServiceDependencyGraph serviceDependencyGraph = new ServiceDependencyGraph(new HashMap<>(), name, set, serviceToServiceMap);

set = reverseServiceToServiceMap.get(name);
ServiceDependencyGraph reverseServiceDependencyGraph = new ServiceDependencyGraph(new HashMap<>(), name, set, reverseServiceToServiceMap);
 
import org.apache.commons.collections4.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 服务依赖图
 * @date 2017-09-2
 * @author 杨尚川
 */
public class ServiceDependencyGraph {
    private String name;
    private List<ServiceDependencyGraph> children = new ArrayList<>();

    public ServiceDependencyGraph(Map<String, AtomicInteger> stopServiceNames, String name, Set<String> set, Map<String, Set<String>> serviceToServiceMap){
        this.name = name;
        if(CollectionUtils.isNotEmpty(set)) {
            for (String item : set) {
                String key = name+"_"+item;
                stopServiceNames.putIfAbsent(key, new AtomicInteger());
                stopServiceNames.get(key).incrementAndGet();
                if(stopServiceNames.get(key).get()<10) {
                    Set<String> sub = serviceToServiceMap.get(item);
                    ServiceDependencyGraph serviceDependencyGraph = new ServiceDependencyGraph(stopServiceNames, item, sub, serviceToServiceMap);
                    children.add(serviceDependencyGraph);
                }
            }
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public List<ServiceDependencyGraph> getChildren() {
        return children;
    }
}
 

3、利用服务依赖图和反向服务依赖图,构造带有点和边描述信息的JSON结构:

 

List<Map<String, String>> nodes = new ArrayList<>();

addNode(serviceDependencyGraph, nodes);
addNode(reverseServiceDependencyGraph, nodes);

List<Map<String, Object>> edges = new ArrayList<>();

addEdge(reverseServiceToServiceMap, serviceDependencyGraph, edges, false);
addEdge(reverseServiceToServiceMap, reverseServiceDependencyGraph, edges, true);

Map<String, Object> graph = new HashMap<>();
graph.put("edges", edges);
graph.put("nodes", nodes);

 

private void addNode(String node, List<Map<String, String>> nodes){
    for(Map<String, String> item : nodes){
        if(node.equals(item.get("id"))){
            return;
        }
    }
    Map<String, String> nodeMap = new HashMap<>();
    nodeMap.put("id", node);
    nodeMap.put("name", node);
    nodes.add(nodeMap);
}

private void addNode(ServiceDependencyGraph serviceDependencyGraph, List<Map<String, String>> nodes){
    if(serviceDependencyGraph == null){
        return;
    }
    String node = serviceDependencyGraph.getName();
    addNode(node, nodes);
    if(serviceDependencyGraph.getChildren() != null){
        serviceDependencyGraph.getChildren().forEach(item->addNode(item, nodes));
    }
}

private void addEdge(Map<String, Set<String>> reverseServiceToServiceMap, ServiceDependencyGraph serviceDependencyGraph, List<Map<String, Object>> edges, boolean reverse){
    if(serviceDependencyGraph == null){
        return;
    }
    String source = serviceDependencyGraph.getName();
    serviceDependencyGraph.getChildren().forEach(target -> {
        boolean duplicate = false;
        Map<String, Object> map = new HashMap<>();
        if(reverse){
            String id = target.getName()+"-->"+source;
            for(Map<String, Object> item : edges){
                if(id.equals(item.get("id"))){
                    duplicate = true;
                }
            }
            map.put("id", id);
            map.put("target", source);
            map.put("source", target.getName());
            map.put("directed", true);
            map.put("source_score", reverseServiceToServiceMap.get(target.getName()) == null ? 0 : reverseServiceToServiceMap.get(target.getName()).size());
            map.put("target_score", reverseServiceToServiceMap.get(source) == null ? 0 : reverseServiceToServiceMap.get(source).size());
        }else {
            String id = source+"-->"+target.getName();
            for(Map<String, Object> item : edges){
                if(id.equals(item.get("id"))){
                    duplicate = true;
                }
            }
            map.put("id", id);
            map.put("source", source);
            map.put("target", target.getName());
            map.put("directed", true);
            map.put("source_score", reverseServiceToServiceMap.get(source) == null ? 0 : reverseServiceToServiceMap.get(source).size());
            map.put("target_score", reverseServiceToServiceMap.get(target.getName()) == null ? 0 : reverseServiceToServiceMap.get(target.getName()).size());
        }
        if(!duplicate) {
            edges.add(map);
        }
        addEdge(reverseServiceToServiceMap, target, edges, reverse);
    });
}

 

生成的JSON结构如下所示:

 

{
    "nodes":[
        {
            "globalWeight":4,
            "name":"AaaSvc(服务Aaa)"
        },
        {
            "globalWeight":4,
            "name":"CccSvc(服务Ccc)"
        },
        {
            "globalWeight":5,
            "name":"DddSvc(服务Ddd)"
        },
        {
            "globalWeight":4,
            "name":"EeeSvc(服务Eee)"
        },
        {
            "globalWeight":4,
            "name":"FffSvc(服务Fff)"
        },
        {
            "globalWeight":3,
            "name":"BbbSvc(服务Bbb)"
        }
    ],
    "edges":[
        {
            "distance":8,
            "source":0,
            "target":1
        },
        {
            "distance":8,
            "source":1,
            "target":0
        },
        {
            "distance":9,
            "source":0,
            "target":2
        },
        {
            "distance":9,
            "source":2,
            "target":3
        },
        {
            "distance":9,
            "source":3,
            "target":2
        },
        {
            "distance":9,
            "source":2,
            "target":4
        },
        {
            "distance":8,
            "source":4,
            "target":3
        },
        {
            "distance":8,
            "source":3,
            "target":4
        },
        {
            "distance":9,
            "source":4,
            "target":2
        },
        {
            "distance":7,
            "source":0,
            "target":5
        },
        {
            "distance":7,
            "source":5,
            "target":1
        },
        {
            "distance":7,
            "source":1,
            "target":5
        }
    ]
}

 

4、使用d3-force对如上的JSON进行展示:

 

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>测试项目_testDemo -- 服务Aaa_AaaSvc -- 服务关联图</title>
    <style>
        .node {
            stroke: #fff;
            stroke-width: 1.5px;
        }
        .node-active{
            stroke: #555;
            stroke-width: 1.5px;
        }
        .link {
            stroke: #555;
            stroke-opacity: .3;
        }
        .link-active {
            stroke-opacity: 1;
            stroke-width: 1.5px;
        }
        .overlay {
            fill: none;
            pointer-events: all;
        }
        #map{
            height:100%;
        }

        #ex1Slider .slider-selection {
            background: #BABABA;
        }

        #ex2Slider .slider-selection {
            background: #BABABA;
        }

        #ex3Slider .slider-selection {
            background: #BABABA;
        }

        #ex4Slider .slider-selection {
            background: #BABABA;
        }

        #ex5Slider .slider-selection {
            background: #BABABA;
        }

    </style>
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/10.2.0/css/bootstrap-slider.min.css"/>
    <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
    <script src="https://code.jquery.com/jquery-2.2.4.min.js" charset="utf-8"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/10.2.0/bootstrap-slider.min.js" charset="utf-8"></script>
    <script type="text/javascript">
        var gravity = 0.03;
        var linkDistanceMultiFactor = 10;
        var linkDistance = 100;
        var circleRadiusMultiFactor = 2;
        var circleRadius = 4;
        var arrowhead = 10;

        var graph;

        function load(graph){
            console.log("loading ...... ");
            console.log("gravity: "+gravity);
            console.log("linkDistanceMultiFactor: "+linkDistanceMultiFactor);
            console.log("linkDistance: "+linkDistance);
            console.log("circleRadiusMultiFactor: "+circleRadiusMultiFactor);
            console.log("circleRadius: "+circleRadius);


            var margin = {top: -5, right: -5, bottom: -5, left: -5};
            var width = $(window).width() - margin.left - margin.right,
                height = $(window).height() - margin.top - margin.bottom;

            var color = d3.scale.category10();

            var force = d3.layout.force()
                .charge(-200)
                .linkDistance(function(d) {return (d.source.weight+d.target.weight)*linkDistanceMultiFactor+linkDistance;})
                .size([width + margin.left + margin.right, height + margin.top + margin.bottom])
                .charge([-500])
                .theta(0.1)
                .gravity(gravity);

            var zoom = d3.behavior.zoom()
                .scaleExtent([0.3, 10])
                .on("zoom", zoomed);

            var drag = d3.behavior.drag()
                .origin(function(d) { return d; })
                .on("dragstart", dragstarted)
                .on("drag", dragged)
                .on("dragend", dragended);

            var svg = d3.select("#map").append("svg")
                .attr("width", width + margin.left + margin.right)
                .attr("height", height + margin.top + margin.bottom)
                .append("g")
                .attr("transform", "translate(" + margin.left + "," + margin.right + ")")
                .call(zoom);

            var rect = svg.append("rect")
                .attr("width", width)
                .attr("height", height)
                .style("fill", "none")
                .style("pointer-events", "all");

            var container = svg.append("g");

            force
                .nodes(graph.nodes)
                .links(graph.edges)
                .start();

            var link = container.append("g")
                .attr("class", "links")
                .selectAll(".link")
                .data(force.links())
                .enter()
                .append("line")
                .attr("class", "link")
                .attr('marker-end', function(d,i) { return d.rpm === 0 ? '' : 'url(#arrowhead)'})
                .style("stroke-width", function(d) { return Math.sqrt(d.value); });

            var node = container.append("g")
                .attr("class", "nodes")
                .selectAll(".node")
                .data(force.nodes())
                .enter().append("g")
                .attr("class", "node")
                .attr("cx", function(d) { return d.x; })
                .attr("cy", function(d) { return d.y; })
                .call(drag);

            var nodeLabel = container.selectAll(".nodelabel")
                .data(force.nodes())
                .enter()
                .append("text")
                .style("pointer-events", "none")
                .attr({"x":function(d){return d.x;},
                    "y":function(d){return d.y;},
                    "class":"nodelabel",
                    "stroke":"#666"})
                .text(function(d){return d.name;});

            var linkPath = container.selectAll(".linkpath")
                .data(force.links())
                .enter()
                .append('path')
                .attr({'d': function(d) {return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y},
                    'class':'linkpath',
                    'fill-opacity':0,
                    'stroke-opacity':0,
                    'fill':'blue',
                    'stroke':'red',
                    'id':function(d,i) {return 'linkpath'+i}})
                .style("pointer-events", "none");

            var linkLabel = container.selectAll(".linklabel")
                .data(force.links())
                .enter()
                .append('text')
                .style("pointer-events", "none")
                .attr({'class':'linklabel',
                    'id':function(d,i){return 'linklabel'+i},
                    'dx':90,
                    'dy':-5,
                    'font-size':12,
                    'fill':'#666'});

            linkLabel.append('textPath')
                .attr('xlink:href',function(d,i) {return '#linkpath'+i})
                .style("pointer-events", "none")
                .text(function(d,i){ return d.rpm > 0 ? d.rpm + ' req/min' : ""; });

            container.append('defs').append('marker')
                .attr({'id':'arrowhead',
                    'viewBox':'-0 -5 10 10',
                    'refX':25,
                    'refY':0,
                    'orient':'auto',
                    'markerWidth':arrowhead,
                    'markerHeight':arrowhead,
                    'xoverflow':'visible'})
                .append('svg:path')
                .attr('d', 'M 0,-5 L 10 ,0 L 0,5')
                .attr('fill', '#000')
                .attr('stroke','#000');

            node.append("circle")
                .attr("r", function(d) { return d.weight*circleRadiusMultiFactor + circleRadius; })
                .style("fill", function(d,i) { return "#e7ba52"; });

            force.on("tick", function() {
                link.attr("x1", function(d) { return d.source.x; })
                    .attr("y1", function(d) { return d.source.y; })
                    .attr("x2", function(d) { return d.target.x; })
                    .attr("y2", function(d) { return d.target.y; });

                node.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

                nodeLabel.attr("x", function(d) { return d.x; })
                    .attr("y", function(d) { return d.y; });

                linkPath.attr('d', function(d) {
                    var path='M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y;
                    return path;
                });

                linkLabel.attr('transform',function(d){
                    if (d.target.x < d.source.x) {
                        bbox = this.getBBox();
                        rx = bbox.x+bbox.width/2;
                        ry = bbox.y+bbox.height/2;
                        return 'rotate(180 ' + rx + ' ' + ry + ')';
                    }
                    else {
                        return 'rotate(0)';
                    }
                });
            });

            var linkedByIndex = {};
            force.links().forEach(function(d) {
                linkedByIndex[d.source.index + "," + d.target.index] = 1;
            });

            function isConnected(a, b) {
                return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index];
            }

            node.on("mouseover", function(d) {
                node.classed("node-active", function(o) {
                    thisOpacity = isConnected(d, o) ? true : false;
                    this.setAttribute('fill-opacity', thisOpacity);
                    return thisOpacity;
                });

                link.classed("link-active", function(o) {
                    return o.source === d || o.target === d ? true : false;
                });

                d3.select(this).classed("node-active", true);
                d3.select(this).select("circle").transition()
                    .duration(750)
                    .attr("r", function(d) { return (d.weight*circleRadiusMultiFactor + circleRadius)*1.5; });
            })
                .on("mouseout", function(d){
                    node.classed("node-active", false);
                    link.classed("link-active", false);

                    d3.select(this).select("circle").transition()
                        .duration(750)
                        .attr("r", function(d) { return d.weight*circleRadiusMultiFactor + circleRadius; });
                });

            function dottype(d) {
                d.x = +d.x;
                d.y = +d.y;
                return d;
            }

            function zoomed() {
                container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
            }

            function dragstarted(d) {
                d3.event.sourceEvent.stopPropagation();
                d3.select(this).classed("dragging", true);
                force.start();
            }

            function dragged(d) {
                d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y);
            }

            function dragended(d) {
                d3.select(this).classed("dragging", false);
            }
        }


        $(function() {
            $('#ex1').slider({
                tooltip: 'hide'
            }).on('slideStop', function (e) {
                //获取新值
                gravity = e.value/100;
                load(graph);
            });
            $('#ex2').slider({
                tooltip: 'hide'
            }).on('slideStop', function (e) {
                //获取新值
                linkDistance = e.value;
                load(graph);
            });
            $('#ex3').slider({
                tooltip: 'hide'
            }).on('slideStop', function (e) {
                //获取新值
                linkDistanceMultiFactor = e.value;
                load(graph);
            });
            $('#ex4').slider({
                tooltip: 'hide'
            }).on('slideStop', function (e) {
                //获取新值
                circleRadius = e.value;
                load(graph);
            });
            $('#ex5').slider({
                tooltip: 'hide'
            }).on('slideStop', function (e) {
                //获取新值
                circleRadiusMultiFactor = e.value;
                load(graph);
            });
            $('#ex6').slider({
                tooltip: 'hide'
            }).on('slideStop', function (e) {
                //获取新值
                arrowhead = e.value;
                load(graph);
            });
            graph = JSON.parse('{"nodes":[{"globalWeight":4,"name":"AaaSvc(服务Aaa)"},{"globalWeight":4,"name":"CccSvc(服务Ccc)"},{"globalWeight":5,"name":"DddSvc(服务Ddd)"},{"globalWeight":4,"name":"EeeSvc(服务Eee)"},{"globalWeight":4,"name":"FffSvc(服务Fff)"},{"globalWeight":3,"name":"BbbSvc(服务Bbb)"}],"edges":[{"distance":8,"source":0,"target":1},{"distance":8,"source":1,"target":0},{"distance":9,"source":0,"target":2},{"distance":9,"source":2,"target":3},{"distance":9,"source":3,"target":2},{"distance":9,"source":2,"target":4},{"distance":8,"source":4,"target":3},{"distance":8,"source":3,"target":4},{"distance":9,"source":4,"target":2},{"distance":7,"source":0,"target":5},{"distance":7,"source":5,"target":1},{"distance":7,"source":1,"target":5}]}');
            load(graph);
        });

    </script>
</head>
<body>

<h3>测试项目_testDemo -- 服务Aaa_AaaSvc -- 服务关联图</h3>
<table>
    <tr>
        <td width="50"></td>
        <td>
            <span class="item">
                重力调节
                <input id="ex1" type="text" data-slider-id="ex1Slider" class="span2" data-slider-min="0" data-slider-max="100" data-slider-step="1" data-slider-value="0.03"/>
            </span>
        </td>
        <td width="50"></td>
        <td>
            <span class="item">
                最短边长
                <input id="ex2" type="text" data-slider-id="ex2Slider" class="span2" data-slider-min="0" data-slider-max="250" data-slider-step="1" data-slider-value="100"/>
            </span>
        </td>
        <td width="50"></td>
        <td>
            <span class="item">
                边长放大倍数
                <input id="ex3" type="text" data-slider-id="ex3Slider" class="span2" data-slider-min="0" data-slider-max="50" data-slider-step="1" data-slider-value="10"/>
            </span>
        </td>
        <td width="50"></td>
        <td>
            <span class="item">
                最短半径
                <input id="ex4" type="text" data-slider-id="ex4Slider" class="span2" data-slider-min="0" data-slider-max="10" data-slider-step="1" data-slider-value="4"/>
            </span>
        </td>
        <td width="50"></td>
        <td>
            <span class="item">
                半径放大倍数
                <input id="ex5" type="text" data-slider-id="ex5Slider" class="span2" data-slider-min="0" data-slider-max="5" data-slider-step="1" data-slider-value="2"/>
            </span>
        </td>
        <td width="50"></td>
        <td>
            <span class="item">
                箭头大小
                <input id="ex6" type="text" data-slider-id="ex5Slider" class="span2" data-slider-min="10" data-slider-max="30" data-slider-step="1" data-slider-value="10"/>
            </span>
        </td>
    </tr>
</table>
<div id="map"></div>
</body>
</html>

 

最终运行的效果如下:

 

 

 

 

1
0
分享到:
评论

相关推荐

    微服务架构适用场景分析

    在本文中,我们将会深入研究主数据管理(MasterDataManagement,MDM)场景中微服务架构的适用情况,并且会分析在问题域中,如果需要计算密集型的任务,基于微服务的架构所面临的挑战,比如在计算无担保消费信贷组合...

    SOA架构:服务和微服务分析及设计(原书第2版)

    新版的案例研究示例和图例进一步阐释和定位微服务模型,并与更传统的服务类型相关联。本书可作为应用架构师、企业架构师、软件开发人员以及任何有兴趣了解或负责设计与实现现代、面向服务解决方案的IT专业人士的参考...

    微服务架构下的数据一致性:可靠事件模式

    在《微服务架构下的数据一致性:概念及相关模式》中介绍了在微服务中实现数据一致性的三种方式,包括可靠事件模式、业务补偿模式、TCC模式。本文重点说一下可靠事件投递。可靠事件模式属于事件驱动架构,微服务完成...

    微服务架构,RPC细节

    什么是RPC调用? 像调用本地函数一样,调用一个远端服务。...它通过“请求id”来关联请求包-响应包-回调函数,用上下文管理器来管理上下文,用超时管理器中的timer触发超时回调,推进业务流程的超时处理。

    基于微服务的水电站手机端监测系统的开发与研究

    由于微服务架构本身的特性,增加某种功能时,无需缩小服务范围,因此,使用微服务架构在开发过程中会节省很多的时间。设计的APP可以充分展示与电站效益直接关联的参数信息,软件具有响应时间短,数据的时效性强等...

    SOA和微服务架构的区别? - 面向服务的架构(SOA) - 知乎1

    1.系统复杂:内部多个模块紧耦合,关联依赖复杂,牵一发而动全身 2.运维困难:变更或升级的影响分析困难,任何一个小修改都可能导致单体应用整体运行出现故障 3.无

    微服务架构下分布式Session管理

    但是随着Web应用的发展,Web服务器需要按照用户的一系列业务操作向客户端提供某些特定的、按需的内容,这就需要想办法将原本相对独立的HTTP请求进行关联。Session管理正是上述问题的解决方案,把用户的信息与状态...

    SOA架构 服务和微服务分析及设计 中英文版本

    新版的案例研究示例和图例进一步阐释和定位微服务模型,并与更传统的服务类型相关联。本书可作为应用架构师、企业架构师、软件开发人员以及任何有兴趣了解或负责设计与实现现代、面向服务解决方案的IT专业人士的参考...

    微服务架构如何保障99.99%高可用

    微服务架构本身最最核心的保障高可用的措施,就是两点:一个是基于Hystrix做资源隔离以及熔断;另一个是做备用降级方案。如果资源隔离和降级都做的很完善,那么在双11这种高并发场景下,也许可能会出现个别的服务...

    springboot+mybatis+dubbo 本项目是基于微服务架构的班车预约系统.zip

    MySQL基于关系型数据库模型,数据以表格形式组织,并通过预定义的键(如主键、外键)在表之间建立关联。它完全支持结构化查询语言(SQL),允许用户进行数据查询、插入、更新、删除、创建和管理数据库结构等操作。...

    ihaowu:基于nestjs 的微服务架构搭建的在线商城服务端

    基于 的微服务架构搭建的在线商城服务端 关联应用 架构设计 粗略设计,项目分成 , ihaowu-web 和 ihaowu-mobile,都采用 monorepo 进行管理,整体结构保持一致。 后端技术栈 - web 框架 - 数据库工具 微服务 架构...

    美团的Mtrace分布式会话跟踪系统架构设计与实践

    分布式会话跟踪系统架构设计与实践 张志桐@美团点评基础架构中心 20160625 链路追踪(调用链路监控)最出名的是谷歌公开的...在复杂的微服务架构系统中,几乎每一个前端请求都会形成一个复杂的分布式服务调用链路。

    微服务测试之性能测试

    传统性能测试更多的是以事务为核心,更多的是由单个或者多个事务构成业务场景进行压测。...因此,微服务架构下的性能测试的重要性就不言而喻了。 微服务系统系统间调用关系复杂,当出现业务流量暴涨的情况

    阿里巴巴的鹰眼全链路监控系统各组件实现介绍

    鹰眼下的淘宝 ---分布式调用跟踪系统介绍 全链路追踪(调用链路监控)最出名的是谷歌公开的论文提到的Dapper(中文版)。...在复杂的微服务架构系统中,几乎每一个前端请求都会形成一个复杂的分布式服务调用链路。

    micro-service-for-peopleops

    人民微服务微服务架构可以... 微服务架构所做的是将我们的应用程序划分为尽可能小的服务,并拥有自己的数据库并以这种方式运行它。 服务越小,我们就越能最大限度地发挥微服务架构的优势,并最大程度地降低其负面影响。

    如何有效提升团队的微服务落地能力?

    这篇文章希望讨论一些在团队中实行微服务架构时值得考虑的『增值项目』,它们中的一些看起来已经是理所应当的,而另一些似乎和微服务并没有必然的关联,但许多经验能够证明这些项目都是保障微服务系统长期运作并最大...

Global site tag (gtag.js) - Google Analytics