1. 程式人生 > >使用protostuff自定義編解碼器優化springcloud-feign效能

使用protostuff自定義編解碼器優化springcloud-feign效能

前言

Spring Cloud feign是偽RPC方式解決微服務間的呼叫。翻看FeignCloudFeign原始碼,可以看到Feign預設使用HttpUrlConnection; 程式碼在DefaultFeignLoadBalancedConfiguration 的Client.Default。

這裡特意說明下,其他替代方式有OKhttp和HTTPClient,這兩種方式有連線池,可以減少建立連線的效能損耗,但是多家實測效果表明,HttpUrlConnection的效率上是最高的,這也是feign預設的原因,如果在輕型應用不考慮速度考慮CPU的情況下,可以考慮替換成OKhttp和HttpClient。

在序列化方面,springboot中HttpMessageConverters 預設使用jackson2方式進行序列化和反序列化。 jackson的效率在於GSON和fastjson之上。

正常情況下使用jackson2支援前後端開發基本沒有什麼問題,但是如果是微服務間頻頻通訊,使用jackson2序列化和反序列化會佔用不少系統資源,並且效率較差。 這裡有個git地址來對比各種序列化和反序列化框架的效能 https://github.com/eishay/jvm-serializers/wiki,部分內容如下:

Ser Time+Deser Time (ns)Size, Compressed size [light] in bytes

 

可見jackson在各種測試中都不佔優勢,網上現在很多的教程使用protobuf來替換jackson提升feign的效能,但是由於nafos中使用的是更加方便的protostuff,而且由圖中可以看出protostuff的效能比protobuf更勝一籌。所以我決定用protostuff來替換。

在feign中,protobuff有預設提供的編解碼器,因此參考其他教程使用即可,但是protostuf卻沒有預設提供,所以我們必須自己動手擼了。

在手擼之前,我們肯定是需要先了解protostuff和feign提供的protobuf編解碼器的,畢竟protostuff的編解碼器,在網上貌似還沒得教程。

通過檢視feign提供的protobuff編解碼器的原始碼,可以看到他是繼承AbstractHttpMessageConverter<Object>,主要實現了supports,readInternal,writeInternal這三個方法。分別是返回類的校驗,解碼器,和編碼器。

程式碼如下:

/**
 * @Author 黃新宇
 * @Date 2018/10/30 下午1:24
 * @Description feign呼叫中protostuff編解碼器
 **/
public class ProtostuffHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
    private static final Logger logger = LoggerFactory.getLogger(ProtostuffHttpMessageConverter.class);

    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    public static final MediaType PROTOBUF;

    static {
        PROTOBUF = new MediaType("application", "x-protobuf", DEFAULT_CHARSET);
    }

    public ProtostuffHttpMessageConverter() {
        super(new MediaType[]{PROTOBUF, MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML});
    }


    @Override
    protected boolean supports(Class<?> aClass) {
       return Object.class.isAssignableFrom(aClass);
    }

    @Override
    protected Object readInternal(Class<?> aClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        MediaType contentType = inputMessage.getHeaders().getContentType();
        if (contentType == null) {
            contentType = PROTOBUF;
        }
        if (!PROTOBUF.isCompatibleWith(contentType)) {
            logger.error("不支援的解碼格式,請用x-protobuf作為contentType");
        }

        try {
            return ProtoUtil.deserializeFromByte(inputMessage.getBody(),aClass);
        } catch (Exception var7) {
            throw new HttpMessageNotReadableException("Could not read Protobuf message: " + var7.getMessage(), var7);
        }
    }

    @Override
    protected void writeInternal(Object object, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {
        MediaType contentType = outputMessage.getHeaders().getContentType();
        if (contentType == null) {
            contentType = PROTOBUF;
        }

        Charset charset = contentType.getCharset();
        if (charset == null) {
            charset = DEFAULT_CHARSET;
        }

        if (!PROTOBUF.isCompatibleWith(contentType)) {
            logger.error("不支援的編碼格式,請用x-protobuf作為contentType");
        }


        FileCopyUtils.copy(ProtoUtil.serializeToByte(object), outputMessage.getBody());

    }
}

用法:

新增如下配置,ProtostuffHttpMessageConverter在nafos.remote.feign.ProtostuffHttpMessageConverter下

View Code

然後在需要用protostuff的feignClient上註明configuration = ProtoFeignConfiguration.class)即可

@FeignClient(value = "service",path ="/nafosRemoteCall/test" , configuration = ProtoFeignConfiguration.class)

詳細程式碼請參考nafos-network: https://gitee.com/huangxinyu/BC-NETTYGO

NAFOS

一個基於netty的輕量級高效能服務端框架。 

簡介

nafos是一個基於netty的高效能伺服器框架,其目的在於易上手,易擴充套件,讓開發人員更致力於業務開發。 在前後端分離的web架構上,或者APP,手遊,nafos都是一個很不錯的選擇。

除此之外,sample中也給出了超簡單的擴充套件方案,使得nafos在分散式擴充套件上能更勝一籌。

文件

特點

    • 1、簡單易用:通過簡單的配置檔案即可建立完善的啟動方案,然後就可以開心的關注業務程式碼了;
    • 2、序列設計 :單使用者的所有請求都是序列進行,完美解決單使用者併發問題,減少鎖的使用;
    • 3、高效能:網路層採用netty作為中介軟體,同等配置及優化條件下,相比tomcat效能可提升一倍;
    • 4、易擴充套件:整合了springBoot,可完美支援spring大家族系列;
    • 5、強相容: 可單機同時支援HTTP,TCP,websocket等服務,小規模應用下不用多開佔用資源;
    • 6、工具類豐富:封裝所有開發中常見工具類可直接呼叫;
    • 7、房間策略:封裝常見遊戲的房間策略,開房,比賽,聊天可直接呼叫,無需多寫;
    • 8、模組化:多個模組之間相互解耦,喜歡哪個用哪個,不喜歡直接丟棄。
    • 9、指令碼支援:內有現成的shell指令碼可以直接使用,開關機,資料庫備份等;
    • 10、自帶分散式限流器,有IP策略和總流量策略等漏桶限流,抵禦攻擊。
    • 11、自帶protostuff的feign編解碼器,操作簡單的同時可以極大程度優化feign端對端的通訊問題。
    • 12、封裝了kafa和rabbitMQ,工具類一般超簡單使用,無需關注內部業務;
    • 13、豐富教程:除了詳細文件外,在sample模組中還有多模組使用案例,開發無憂~