1. 程式人生 > >一個最簡單的微服務架構

一個最簡單的微服務架構

catch height 去掉 esc con idt nginx bubuko per

前言

微服務架構一般會有一個開放網關作為總入口,負責分發流量到實際的應用服務上。下面看圖。

架構圖

技術分享圖片

項目結構

技術分享圖片

這個架構分別由反向代理nginx,註冊中心zookeeper,開放網關gateway,和兩個服務goodservice,priceservice組件而成。為了方便測試,我把建了兩個一樣的gateway和goodservice。而common作為公共的二方包存在,也是為了簡單起見,gateway和service引用同一個二方包。

nginx

nginx除了作為反向代理,也具有負載均衡的功能,默認策略是輪詢地址列表。我這裏設置8080和8081兩個端口,如下

  upstream mygateway {
          server   localhost:8080;
          server   localhost:8081;
        }

    server {
        listen       80;
        server_name  localhost;

        location /route{
           proxy_pass http://mygateway;
        }
    }

priceservice

非常簡單的服務,只提供一個價格查詢的接口,如

@Service
public class PriceServiceImpl implements PriceService {
    @Override
    public Integer getGoodPrice(String name) {
        return 100;
    }
}

goodservice

也只提供一個接口,但是依賴priceservice,如

@Service
public class GoodServiceImpl implements GoodService {

    private final String SERVICENAME="goodservice";

    @Reference(check
=false) PriceService priceService; @Override public List<GoodInfo> getGoodList(String name) { List<GoodInfo> goodInfoList=new ArrayList<>(); GoodInfo goodInfo=new GoodInfo(); goodInfo.setName(name); goodInfo.setDescription(SERVICENAME); Integer price= priceService.getGoodPrice(name); goodInfo.setPrice(price); goodInfoList.add(goodInfo); return goodInfoList; } }

gateway

gateway這裏的作用是提供一個統一對外的接口,當然還可以加上鑒權,限流,防黑,監控等功能。實現上是通過dubbo的泛化調用將流量通過負載均衡策略轉到實際的應用中,均衡策略默認是隨機。dubbo的泛化調用是需要去匹配對應接口的方法名和參數類型。正常情況下,是需要通過api註冊和管理錄入到數據庫,再提供給gateway使用的。我這裏通過靜態塊構造一些數據充當api註冊。如下

@RestController
public class RouteController {
    private final static List<ServiceModel> serviceModels = new ArrayList<>();
    private final static Map<String,GenericService>  genericServiceMap=new HashMap<>();
    private final static String GATEWAYNAME="gateway";
    
    static {
        ParameterModel parameterModel = new ParameterModel();
        parameterModel.setName("name");
        parameterModel.setType("java.lang.String");
        List<ParameterModel> parameterModelList = new ArrayList<>();
        parameterModelList.add(parameterModel);

        ServiceModel serviceModel = new ServiceModel();
        serviceModel.setApiName("api.service.goodservice");
        serviceModel.setServiceName("com.example.demo.common.service.GoodService");
        serviceModel.setMethodName("getGoodList");

        serviceModel.setParameterModels(parameterModelList);
        serviceModels.add(serviceModel);
    }

    @RequestMapping(value = "/route", method = RequestMethod.GET)
    public ResultModel execute(@RequestParam String api, @RequestParam String data) {

        Optional<ServiceModel> serviceModelOptional = serviceModels.stream().filter(x -> x.getApiName().equals(api)).findFirst();
        ResultModel resultModel=new ResultModel();

        if (!serviceModelOptional.isPresent()) {
            resultModel.setDescription("api不存在");
        }
        ServiceModel serviceModel=serviceModelOptional.get();

        GenericService genericService= genericServiceMap.get(api);
        if(genericService==null){
            ReferenceConfig<GenericService> reference = new ReferenceConfig<>();
            reference.setInterface(serviceModel.getServiceName());
            reference.setGeneric(true);
            genericService = reference.get();
            genericServiceMap.put(api,genericService);
        }
        Object result = genericService.$invoke(serviceModel.getMethodName(),getTypeList(serviceModel).toArray(new String[]{}), dataToValueList(serviceModel,data).toArray());

        resultModel.setData(result);
        resultModel.setDescription(GATEWAYNAME);
        return resultModel;
    }

    /**
     * 獲取參數類型列表
     * @param serviceModel
     * @return
     */
    private List<String> getTypeList(ServiceModel serviceModel) {
        List<ParameterModel> parameterModelList = serviceModel.getParameterModels();
        if (CollectionUtils.isEmpty(parameterModelList)) {
            return null;
        }
        return parameterModelList.stream().map(x -> x.getType()).collect(Collectors.toList());
    }

    /**
     * 獲取data中的值列表
     * @param serviceModel
     * @param data
     * @return
     */
    private List<Object> dataToValueList(ServiceModel serviceModel, String data) {
        Map<String, Object> parameterMap = jsonToMap(data);
        List<ParameterModel> parameterModelList = serviceModel.getParameterModels();

        if (CollectionUtils.isEmpty(parameterModelList)) {
            return null;
        }
        List<Object> valueList = new ArrayList<>();

        parameterModelList.stream().forEach(x -> {
            valueList.add(parameterMap.get(x.getName()));
        });
        return valueList;
    }

    /**
     * 將map格式的string轉成map對象
     * @param json
     * @return
     */
    public static Map<String, Object> jsonToMap(String json) {
        ObjectMapper mapper = new ObjectMapper();
        try {
            return mapper.readValue(json, Map.class);
        } catch (IOException e) {
            System.out.println(e);
        }
        return null;
    }
}

測試

接下來,方便起見,只需要在一臺電腦把幾個module全部啟動起來,在瀏覽器輸入

http://mygateway/route?api=api.service.goodservice&data={"name":"蘋果"}

多測試幾遍,會看到返回如下

{"data":[{"price":100,"name":"蘋果","description":"goodservice","class":"com.example.demo.common.model.GoodInfo"}],"description":"gateway1"}
{"data":[{"price":100,"name":"蘋果","description":"goodservice1","class":"com.example.demo.common.model.GoodInfo"}],"description":"gateway"}
{"data":[{"price":100,"name":"蘋果","description":"goodservice","class":"com.example.demo.common.model.GoodInfo"}],"description":"gateway"}
{"data":[{"price":100,"name":"蘋果","description":"goodservice1","class":"com.example.demo.common.model.GoodInfo"}],"description":"gateway1"}

實際上整個調用鏈路會在gateway集群和goodservice集群交叉流轉,如果這個時候把goodservice或者gateway停掉,瀏覽器的調用還是會正常返回的,這就是集群的好處。

但是如果這個時候把停掉nginx,zookeeper和priceservice其中一個,瀏覽器將會調用失敗,因為是單點的。在生產環境中,要保證高可用,架構上是不可以出現單點的應用。

小結

上面的架構只是微服務架構中的一種形態。阿裏內部在這方面做得更極致一點,直接將gateway這層去掉,而是作為一個二方包集成到業務應用中,由接入層直接轉發流量。簡單來說,就是這樣的。終端->LVS集群->Aserver集群(nginx的加強版)->應用服務。

git地址: https://github.com/mycaizilin/microservice

一個最簡單的微服務架構