Автор: Ван Юйсюань (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.Object
java.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 и пользовательский опыт, мы предоставляем следующие уровни конфигурации:
- Функции WithServers и WithRegistryGroup в реестре/options.go иsolver /options.go обеспечивают настройку на уровне реестра, соответственно указывая адрес Zookeeper и группу, к которой принадлежат эти Zookeeper. Пользователи используют эти функции для создания Kitex
registry.Registry
иdiscovery.Resolver
экземпляров. - Конфигурация уровня обслуживания передается
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 о зарядке офисного программного обеспечения, напоминающей матрешку: Только активно решая «наборы», у нас может быть будущее