Kitex поддерживает протокол Dubbo: облегчает интеграцию многоязычных облачных экосистем.

Автор: Ван Юйсюань (github: DMwangnima), Kitex Committer

1. История

Kitex — это микросервисная RPC-инфраструктура Go, созданная командой ByteDance. Она поддерживает такие протоколы сообщений, как Thrift, Kitex Protobuf и gRPC, и характеризуется высокой производительностью и сильной масштабируемостью. После официального открытия исходного кода в сентябре 2021 года он был успешно внедрен во многих сторонних компаниях, что принесло им реальные преимущества в плане затрат, производительности и стабильности.

В процессе использования сервисов трансформации Kitex многим корпоративным пользователям необходим Kitex для взаимодействия с сервисами, реализованными в существующей платформе Dubbo. Это совпадает с целью сообщества CloudWeGo активно расширять экосистему. Поэтому проект совместимости Dubbo codec-dubbo. появился на свет.

Благодаря активной помощи студентов сообщества codec-dubbo в настоящее время может взаимодействовать между Kitex и Dubbo-Java, Kitex и Dubbo-Go, а также поддерживает пользователей Dubbo в переходе на Kitex.

В этой статье в качестве примера будет рассмотрена успешная трансформация сервиса Founder Securities с использованием Kitex и codec-dubbo, объяснены основные функции codec-dubbo, используемые в процессе трансформации, и кратко проанализированы детали реализации.

2. Случаи внедрения на предприятии

Оригинальные сервисы Founder Securities написаны на платформах Java и Dubbo. Оба они стабильны и проверены в большом количестве сценариев, отвечающих потребностям производства и разработки. Если взять в качестве примера страницу с подробной информацией об отдельных акциях Xiaofang, которая имеет большое количество запросов, то интерфейс QPS в пиковые периоды составляет 3-4 тыс., а для хостинга используются 16 виртуальных машин 16 Core 64G.

С появлением облачной архитектуры Go постепенно стал важным технологическим вариантом для создания корпоративных сервисов благодаря своим преимуществам в использовании памяти и эффективности выполнения, а также естественной способности адаптироваться к облачным технологиям. Чтобы лучше сократить расходы и повысить эффективность, после всестороннего рассмотрения таких факторов, как стоимость, производительность и стабильность, они решили перейти с Java на Go для новых приложений, представили Kitex, Hertz и другие проекты CloudWeGo для разработки и реконструкции сервисов, а также перенесли вся среда Kubernetes.

В процессе реконструкции codec-dubbo опиралась на пользовательский интерфейс, близкий к нативному Kitex + Thrift, и хорошую поддержку концепций Dubbo, чтобы снизить стоимость использования и понимания. Это успешно помогло им решить проблему совместимости Kitex <-> Dubbo и позволить. Служба Kitex Плавно вызывайте исходную службу Dubbo.

На данный момент сервис Kitex с использованием codec-dubbo успешно запущен и стабильно работает уже два месяца. Если взять в качестве примера страницу с информацией об отдельных запасах Xiaofang, то Kitex и Hertz размещают около половины интерфейсов на этой странице. Когда QPS остается неизменным, необходимо предоставить только 12 модулей 4 Core 4G, что значительно снижает использование ресурсов.

3. Функциональные особенности codec-dubbo

Кодек протокола Dubbo

Служба Dubbo в основном использует протокол Dubbo для связи. Чтобы поддерживать совместимость Kitex <-> Dubbo, нам необходимо реализовать протокол Dubbo в Kitex. Благодаря превосходной масштабируемости Kitex, codec-dubbo реализует DubboCodec, основной кодек, основанный на интерфейсе кодека, предоставляемом Kitex. Вам нужно только внедрить DubboCodec во время инициализации, чтобы использовать протокол Dubbo.

Сопоставление типов и расширение

сопоставление типов

Dubbo в основном использует протокол сериализации Hessian2 для кодирования и декодирования полезной нагрузки. Его самая большая особенность — это самоописывающийся тип сериализации, то есть он не полагается на внешнюю схему или определения интерфейса. Процесс сериализации основан на сопоставлении типов языка программирования и типов Hessian2. В качестве примера рассмотрим преобразование типов Go в типы Java:

После анализа мы обнаружили, что базовая система типов Hessian2 в основном пересекается с Thrift. Чтобы гарантировать, что использование Kitex + codec-dubbo в основном такое же, как и Kitex + Thrift, мы генерируем каркасный код Kitex Dubbo-Hessian2 на основе Thrift IDL. На данный момент процесс преобразования типов выглядит следующим образом:

Обратитесь к официальному сопоставлению типов dubbo-go-hessian2 от Dubbo . codec-dubbo предоставляет следующее сопоставление типов (здесь включена только часть сопоставления. Дополнительные меры предосторожности см. в файле Readme для codec-dubbo):

В соответствии с сопоставлением типов, предоставленным codec-dubbo, мы можем легко преобразовать определение интерфейса Dubbo в Thrift IDL, использовать инструмент командной строки Kitex для генерации кода проекта и, наконец, внедрить DubboCodec для завершения связи Kitex -> Dubbo. В качестве примера возьмем следующее определение интерфейса Dubbo:

package org.cloudwego.kitex.samples.api;

public interface GreetProvider {
    GreetResponse Greet(GreetRequest req) throws Exception;
}

public class GreetRequest implements Serializable {
    String req;

    public GreetRequest(String req) {
        this.req = req;
    }
}

public class GreetResponse implements Serializable {
    String resp;

    public GreetResponse(String resp) {
        this.resp = resp;
    }
}

Соответствующий файл api.thrift выглядит следующим образом. Следует отметить, что определения структуры в нем должны быть аннотированы JavaClassName, что соответствует имени пакета + класса в определении интерфейса Dubbo.

struct GreetRequest {
    1: required string req,
} (JavaClassName="org.cloudwego.kitex.samples.api.GreetRequest")

struct GreetResponse {
    1: required string resp,
} (JavaClassName="org.cloudwego.kitex.samples.api.GreetResponse")

service GreetService {
    GreetResponse Greet(1: GreetRequest req)
}

Используйте инструмент командной строки Kitex и укажите протокол Hessian2:

kitex -module demo-client -protocol Hessian2 ./api.thrift

Затем инициализируйте DubboCodec и внедрите его в Kitex. Используйте сгенерированный код для написания следующего клиентского кода для реализации вызова Kitex -> Dubbo:

javaClass := "org.cloudwego.kitex.samples.api.GreetProvider"
cli, err := greetservice.NewClient("helloworld",
    // 指定想要访问的服务端地址,也支持 ZooKeeper 服务发现
    client.WithHostPorts("127.0.0.1:21000"),
    // 配置 DubboCodec
    client.WithCodec(
        // 指定想要调用的 Dubbo Interface
        dubbo.NewDubboCodec(dubbo.WithJavaClassName(javaClass))
    ),
)
if err != nil {
   panic(err)
}
    
resp, err := cli.Greet(context.Background(),
    &hello.GreetRequest{Req: "world"})
if err != nil {
    klog.Error(err)
    return
}
klog.Infof("resp: %s", resp.Resp)

Процесс Kitex + codec-dubbo на стороне сервера в основном аналогичен процессу на стороне клиента. Конкретные примеры можно найти на домашней странице проекта.

Расширение типа

Функция Hessian2 без схемы делает реализацию Dubbo «слишком гибкой» и позволяет использовать любой тип. Чтобы адаптироваться к гибкости использования типов Dubbo Hessian2, codec-dubbo поддерживает расширение типов, которое в основном включает в себя пользовательское сопоставление и расширение общего типа Java.

Пользовательское сопоставление

Базовые типы Java имеют соответствующие типы-оболочки, такие как booleanи java.lang.Boolean. boolСопоставление типов Go по умолчанию с java.lang.Booleanтипами Java при сопоставлении типов не распространяется на использование boolean. Чтобы унифицировать взаимодействие с пользователем и позволить им использовать boolтип только на стороне Kitex, мы можем добавить аннотации после определения метода Thrift hessian.argsType="boolean", использовать функцию отражения IDL thriftgo, чтобы заранее сгенерировать метаинформацию IDL и внедрить ее в кодек. dubbo, и затем его можно будет запустить. Динамически java.lang.Booleanперезапишите тип сопоставления по умолчанию на boolean. Конкретное определение бережливости выглядит следующим образом:

service EchoService {
   bool EchoBoolean(1: bool req) (hessian.argsType="boolean")
}

Подобно booleanи java.lang.Boolean, другие базовые типы Java и типы-оболочки также могут быть настроены таким образом. На данный момент полное сопоставление типов, предоставляемое codec-dubbo, выглядит следующим образом:

Расширение общего типа Java

Из-за ограничений типов Thrift мы не можем напрямую использовать общие типы, представленные в библиотеках классов Java. Для этого codec-dubbo поддерживает типы Java, которые Thrift не поддерживает (например , ), и соответствующий java.thrift в пакете codec-dubbo/java . В то же время с помощью предоставленной функции idl-ref. с помощью thriftgo мы можем напрямую использовать Thrift. На эти типы ссылаются в IDL, и соответствующий код генерируется. Текущий java.thrift выглядит следующим образом:java.lang.Objectjava.util.Date

struct Object {} (JavaClassName="java.lang.Object")

struct Date {} (JavaClassName="java.util.Date")

struct Exception {} (JavaClassName="java.lang.Exception")

Чтобы включить эти типы, нам необходимо импортировать их в Thrift IDL include "java.thrift"и добавить параметры при создании кода с помощью инструмента командной строки Kitex -hessian2 java_extensionдля получения пакета расширения.

Инструмент командной строки Kitex автоматически загрузит java.thrift. Вы также можете загрузить его вручную и поместить в корневой каталог проекта. Пример Thrift IDL, ссылающийся на типы в java.thrift:

include "java.thrift"

service EchoService {
    // java.lang.Object
    i64 EchoString2ObjectMap(1: map<string, java.Object> req)
    // java.util.Date
    i64 EchoDate(1: java.Date req)
}

Перегрузка метода

Go не поддерживает перегрузку методов. Эффектов, подобных перегрузке, можно достичь, только определив несколько методов. Чтобы сопоставить несколько методов Go с перегруженными методами Java, аналогично разделу пользовательского сопоставления, мы добавляем тег JavaMethodName после определения метода в Thrift и используем функцию отражения IDL thriftgo для динамического сопоставления Go во время выполнения. Оригинал. имя метода перезаписывается на перегруженный метод в Java, указанный в JavaMethodName.

В качестве примера возьмем EchoMethod на стороне Java:

String EchoMethod(Boolean req);
String EchoMethod(Integer req);
String EchoMethod(int req);
String EchoMethod(Boolean req1, Integer req2);

Мы пишем следующее определение Thrift, чтобы завершить сопоставление перегруженных методов между Go и Java. Обратите внимание, JavaMethodNameчто и hessian.argsTypeможно использовать одновременно:

service EchoService {
    string EchoMethodA(1: bool req) (JavaMethodName="EchoMethod")
    string EchoMethodB(1: i32 req) (JavaMethodName="EchoMethod")
    string EchoMethodC(1: i32 req) (JavaMethodName="EchoMethod", hessian.argsType="int")
    string EchoMethodD(1: bool req1, 2: i32 req2) (JavaMethodName="EchoMethod")
 }

Обработка исключений

codec-dubbo сопоставляет исключения в Java с ошибками в Go. Эти ошибки единообразно реализуют следующий интерфейс:

type Throwabler interface {
    Error() string
    JavaClassName() string
    GetStackTrace() []StackTraceElement
}

Основываясь на методах обработки исключений, официально рекомендованных Dubbo, и текущих потребностях корпоративных пользователей, мы разделяем исключения на общие и пользовательские исключения, принимая во внимание основные потребности и потребности пользователей в масштабируемости.

Общие исключения

codec-dubbo предоставляет распространенные исключения Java в пакете pkg/hessian2/Exception , в настоящее время поддерживая java.lang.Exception.

Общие исключения не требуют поддержки со стороны инструмента командной строки Kitex и могут быть указаны напрямую. Ниже приведены примеры исключений, извлеченных клиентом, и исключений, возвращаемых сервером.

Исключение извлечения клиента

resp, err := cli.Greet(context.Background(),
    &hello.GreetRequest{Req: "world"})
if err != nil {
    // FromError 返回 Throwabler
    exceptionRaw, ok := hessian2_exception.FromError(err)
    if !ok {
        // 视作常规错误处理        
    } else {
        // 若不关心 exceptionRaw 的具体类型,直接调用 Throwabler 提供的方法即可
        klog.Errorf("get %s type Exception", exceptionRaw.JavaClassName())                
        // 若想获得 exceptionRaw 的具体类型,需要进行类型转换,但前提是已知该具体类型
        exception := exceptionRaw.(*hessian2_exception.Exception)
    }
}

Серверная сторона возвращает исключение

func (s *GreetServiceImpl) Greet(ctx context.Context, req *hello.GreetRequest) (resp *hello.GreetResponse, err error) {
    return nil, hessian2_exception.NewException("Your detailed message")
}

Пользовательское исключение

Пользовательские исключения в Java часто наследуют базовое исключение. Здесь, в качестве CustomizedExceptionпримера , CustomizedExceptionоно наследует java.lang.Exception:

public class CustomizedException extends Exception {
    private final String customizedMessage;
    
    public CustomizedException(String customizedMessage) {
        super();
        this.customizedMessage = customizedMessage;
    }
}

Благодаря поддержке thriftgo генерации вложенных структур, чтобы определить соответствующие исключения на стороне Kitex, мы пишем в Thrift следующее определение:

exception CustomizedException {
    // thrift.nested=“true” 注解让 thriftgo 生成嵌套结构体
    1: required java.Exception exception (thrift.nested="true")
    2: required string customizedMessage
}(JavaClassName="org.cloudwego.kitex.samples.api.CustomizedException")

Обратите внимание exceptionна аннотации полей thrift.nested="true", которые позволяют thriftgo генерировать вложенные структуры для достижения эффекта, аналогичного наследованию.

Как и в случае с обычными расширениями типов Java, вам необходимо добавить параметры при использовании инструмента создания шаблонов kitex для генерации кода -hessian2 java_extensionдля получения пакета расширения. Сгенерированный код выглядит следующим образом:

type EchoCustomizedException struct {
        java.Exception `thrift:"exception,1,required" frugal:"1,required,java.Exception" json:"exception"`

        CustomizedMessage string `thrift:"customizedMessage,2,required" frugal:"2,required,string" json:"customizedMessage"`
}

Метод использования соответствует типичным исключениям и не будет здесь повторяться.

Регистрация и обнаружение услуг

Dubbo предоставляет модели регистрации и обнаружения служб как на уровне интерфейса, так и на уровне приложения. Основываясь на текущих потребностях корпоративных пользователей в производственной среде, мы решили отдать приоритет модели уровня интерфейса, основанной на Zookeeper: Dubbo Registry-zookeeper.

В отличие от модели уровня приложения, с которой мы знакомы, модель уровня интерфейса должна поддерживать связь имени интерфейса => службы (в отличие от микросервисов, ближе к обработчику). Одно имя интерфейса будет сопоставлено с несколькими службами, и эти службы могут существовать в одном и том же процессе.

Учитывая, что модель обслуживания на уровне интерфейса Dubbo сильно отличается от модели обслуживания Kitex, а реестр-zookeeper Dubbo для использования должен быть привязан к codec-dubbo, не предполагается изменять исходный реестр-zookeeper в kitex-contrib для создания реестра dubbo. -zookeeper Модуль sub-go codec-dubbo разрабатывается и поддерживается единообразно.

Принимая во внимание модель обслуживания на уровне интерфейса Dubbo, API Kitex и пользовательский опыт, мы предоставляем следующие уровни конфигурации:

  1. Функции WithServers и WithRegistryGroup в реестре/options.go иsolver /options.go обеспечивают настройку на уровне реестра, соответственно указывая адрес Zookeeper и группу, к которой принадлежат эти Zookeeper. Пользователи используют эти функции для создания Kitex registry.Registryи discovery.Resolverэкземпляров.
  2. Конфигурация уровня обслуживания передается client.WithTagс помощью и , а реестры/common.go предоставляют ключи тегов, которые соответствуют метаданным службы в Dubbo «один к одному».server.WithRegistryInfo

пример резольвера

intfName := "org.cloudwego.kitex.samples.api.GreetProvider"
res, err := resolver.NewZookeeperResolver(
    // 指定 zookeeper 服务器的地址,可指定多个,请至少指定一个 
    resolver.WithServers("127.0.0.1:2181"),
)
if err != nil {
    panic(err)
}
cli, err := greetservice.NewClient("helloworld",
    // 配置 ZookeeperResolver
    client.WithResolver(res),
    // 指定想要调用的 dubbo Interface
    client.WithTag(registries.DubboServiceInterfaceKey, intfName),
)
if err != nil {
    panic(err)
}
// 使用 cli 进行 RPC 调用

пример реестра

intfName := "org.cloudwego.kitex.samples.api.GreetProvider"
reg, err := registry.NewZookeeperRegistry(
    // 指定 zookeeper 服务器的地址,可指定多个,请至少指定一个 
    registry.WithServers("127.0.0.1:2181"),
)
if err != nil {
    panic(err)
}

svr := greetservice.NewServer(new(GreetServiceImpl),
    server.WithRegistry(reg),
    // 配置dubbo URL元数据
    server.WithRegistryInfo(&kitex_registry.Info{
        Tags: map[string]string{
            registries.DubboServiceInterfaceKey: intfName,
            // application请与dubbo所设置的ApplicationConfig保持一致,此处仅为示例
            registries.DubboServiceApplicationKey: "application-name",
        }
    }),
)
// 启动 svr

Подведем итог

Kitex поддерживает протокол Dubbo, что является большим шагом для CloudWeGo в интеграции многоязычной облачной среды. Он решает проблемы многих корпоративных пользователей, связанные с преобразованием Java в Go и сосуществованием между Java и Go. попробуйте получить к нему доступ; если у вас возникнут какие-либо проблемы во время использования. Если у вас есть какие-либо вопросы, вы можете присоединиться к нашей группе пользователей Feishu или оставить нам отзыв на Github.

Пиратские ресурсы «Celebrating More Than Years 2» были загружены на npm, из-за чего npmmirror был вынужден приостановить работу службы unpkg, китайская команда искусственного интеллекта Microsoft собрала вещи и отправилась в Соединенные Штаты, в которой участвовали сотни людей. интерфейсная библиотека визуализации и известный проект Baidu с открытым исходным кодом ECharts — «отправляясь в море» для поддержки Fish мошенники использовали TeamViewer для перевода 3,98 миллиона! Что следует делать поставщикам удаленных рабочих столов? Чжоу Хунъи: У Google осталось не так много времени. Рекомендуется, чтобы все продукты были с открытым исходным кодом. Бывший сотрудник известной компании с открытым исходным кодом сообщил новость: после того, как его подчиненные бросили ему вызов, технический руководитель пришел в ярость. уволил беременную сотрудницу. Google показал, как запустить ChromeOS на виртуальной машине Android. Дайте мне совет, какую роль здесь играет time.sleep(6)? Microsoft отвечает на слухи о том, что китайская команда искусственного интеллекта «собирает вещи для Соединенных Штатов» Комментарий People's Daily Online о зарядке офисного программного обеспечения, напоминающей матрешку: Только активно решая «наборы», у нас может быть будущее
{{o.name}}
{{м.имя}}

рекомендация

отmy.oschina.net/u/4843764/blog/11044578
рекомендация