Практика и изучение трафика Tuya smart dubbo-go на миллиардном уровне

Java Go

1.png

Автор | Pan Tianying, Github ID @pantianying, энтузиаст открытого исходного кода, работающий в Tuya Intelligence

Dubbo — это высокопроизводительная облегченная среда RPC, разработанная на основе Java.Dubbo предоставляет широкие возможности управления службами и превосходную масштабируемость. Dubbo-go предоставляет унифицированные сервисные возможности и стандарты между java и golang, что является основной проблемой, которую Tuya Intelligence должна решить в настоящее время. Эта статья разделена на две части: практика и быстрый доступ, в которых рассказывается о практическом опыте работы с dubbo-go в Tuya Smart с целью помочь пользователям быстро получить доступ к RPC-инфраструктуре dubbo-go, надеясь, что все будут делать меньше обходных путей. Кроме того, тестовый код в этой статье основан на версии dubbo-go v1.4.0.

даббо-го шлюз практика

2.png

Использование dubbo-go в Tuya Intelligence показано на рисунке выше.Далее я подробно расскажу о деталях реализации.Я надеюсь, что этот опыт, обобщенный в производственной среде, может вам помочь.

1. Предпосылки

В Tuya Intelligence dubbo-go используется в качестве предпочтительной инфраструктуры RPC для подключения служб golang к исходному кластеру dubbo. Среди них более типичная система шлюза с открытым шлюзом (далее совместно именуемая шлюзом, см. версию с открытым исходным кодом).GitHub.com/Азартные игры Bodog/Азартные игры…). Шлюз динамически загружает информацию о внутреннем интерфейсе dubbo и предоставляет ее в виде HTTP API. Этот шлюз предназначен для решения следующих проблем шлюза предыдущего поколения.

  • Настройка правил открытия интерфейса dubbo через страницу громоздка, а разрешения трудно контролировать;
  • Интерфейс не RESTful и не дружественный к внешним разработчикам;
  • Сильная зависимость и высокий риск обновления;
  • Проблемы с производительностью параллелизма.

2. Архитектурный дизайн

Что касается болевой точки, то подготовка к разработке новой архитектуры шлюза. Во-первых, это выбор языка, модель вызова сопрограммы golang делает ее очень подходящей для создания приложений с интенсивным вводом-выводом golang, а развертывание приложения Java также относительно просто.

После исследования мы решили использовать golang в качестве языка кодирования прокси и использовать dubbo-go для подключения к кластеру провайдера dubbo. Бизнес-приложение на стороне провайдера настраивает информацию о конфигурации API в виде аннотаций с помощью подключаемого модуля Java, который обновляет информацию о конфигурации и метаданные интерфейса dubbo в реестре метаданных (redis на рисунке ниже). Таким образом, конфигурация перемещается со страницы админки в программный код. При кодировании разработчики могут легко увидеть внешнее описание API интерфейса dubbo, и нет необходимости настраивать использование API из другого фона управления.

3.png

3. Практика

Как видно из приведенного выше рисунка, шлюз может динамически загружать информацию интерфейса dubbo, а вызов интерфейса dubbo основан на вызове обобщения dubbo. Обобщенный вызов избавляет клиента от необходимости строить код интерфейса провайдера, в dubbo-go не нужно вызывать методы config.SetConsumerService и hessian.RegisterPOJO, а дополняет модель запроса чистыми параметрами, что делает клиент динамически добавляет и изменяет интерфейс, чтобы он стал возможным. Демонстрационный код с универсальными вызовами в apache/dubbo-sample/golang/generic/go-client.

func test() {
    var appName = "UserProviderGer"
    var referenceConfig = config.ReferenceConfig{
        InterfaceName: "com.ikurento.user.UserProvider",
        Cluster:       "failover",
        Registry:      "hangzhouzk",
        Protocol:      dubbo.DUBBO,
        Generic:       true,
    }
    referenceConfig.GenericLoad(appName) // appName is the unique identification of RPCService
    time.Sleep(3 * time.Second)
    resp, err := referenceConfig.GetRPCService().(*config.GenericService).
        Invoke([]interface{}{"GetUser", []string{"java.lang.String"}, []interface{}{"A003"}})
    if err != nil {
        panic(err)
    }
}

Реализация вызова обобщения на самом деле довольно проста. Его функция действует в слое фильтра dubbo. Общий фильтр был добавлен в цепочку фильтров dubbo в качестве включенного по умолчанию фильтра. Его основная логика заключается в следующем:

func (ef *GenericFilter) Invoke(ctx context.Context, invoker protocol.Invoker, invocation protocol.Invocation) protocol.Result {
    if invocation.MethodName() == constant.GENERIC && len(invocation.Arguments()) == 3 {
        oldArguments := invocation.Arguments()
        if oldParams, ok := oldArguments[2].([]interface{}); ok {
            newParams := make([]hessian.Object, 0, len(oldParams))
            for i := range oldParams {
                newParams = append(newParams, hessian.Object(struct2MapAll(oldParams[i])))
            }
            newArguments := []interface{}{
                oldArguments[0],
                oldArguments[1],
                newParams,
            }
            newInvocation := invocation2.NewRPCInvocation(invocation.MethodName(), newArguments, invocation.Attachments())
            newInvocation.SetReply(invocation.Reply())
            return invoker.Invoke(ctx, newInvocation)
        }
    }
    return invoker.Invoke(ctx, invocation)
}

Generic Filter преобразует запрошенные пользователем параметры структуры в карту в унифицированном формате ( struct2MapAll в коде) и превращает операции прямой и обратной сериализации классов ( struct в golang) в операции прямой и обратной сериализации карты. Это позволяет жестко внедрить библиотеку hessain без необходимости описания POJO.

Как видно из приведенного выше кода, есть 4 содержимого, которые должны быть динамически созданы в вызове обобщения: InterfaceName требуется в ReferenceConfig, метод в параметре, ParameterTypes и фактический входной параметр requestParams.

Так как же эти параметры, полученные из HTTP API, совпадают?

Это будет использовать упомянутый выше плагин для провайдера для сбора метаданных. После установки плагина приложение сканирует интерфейс dubbo, который необходимо открыть при запуске, и связывает метаданные dubbo с HTTP API. Использование плагина примерно таково: вот несколько простых конфигураций в качестве примеров, аннотаций в реальной работе будет больше.

4.png

В результате метаданные dubbo выглядят следующим образом:

{
    "key": "POST:/hello/{uid}/add",
    "interfaceName": "com.tuya.hello.service.template.IUserServer",
    "methodName": "addUser",
    "parameterTypes": ["com.tuya.gateway.Context", "java.lang.String", "com.tuya.hello.User"],
    "parameterNames": ["context", "uid", "userInfo"],
    "updateTimestamp": "1234567890",
    "permissionDO":{},
    "voMap": {
        "userInfo": {
            "name": "java.lang.String",
            "sex": "java.lang.String",
            "age": "java.lang.Integer"
        }
    },
    "parameterNameHumpToLine": true,
    "resultFiledHumpToLine": false,
    "protocolName": "dubbo",
  .......
}

Подписавшись на указанную выше информацию из центра конфигурации метаданных, Gateway может сопоставить запрос API с интерфейсом dubbo. Затем возьмите параметры из запроса API в качестве входных параметров. Эта функция завершает замкнутый контур потока.

Из приведенного выше контента у вас должно быть четкое представление о топологии проекта этого шлюза. Далее я поделился проблемами и опытом настройки, с которыми столкнулся проект в процессе использования dubbo-go. В начале 2019 года проект dubbo-go был еще на ранней стадии строительства, и пользовательского опыта в посадке не было. Я также участвую в развитии сообщества во время кодирования проекта внутреннего шлюза компании. После решения множества проблем с сериализацией гессейна и реестром зоопарка проект, наконец, прошел через замкнутый цикл. Тем не менее, как основному приложению, работающему по замкнутому циклу, еще предстоит пройти долгий путь от производственной среды, особенно с использованием новой платформы, стабильность которой должна была быть проверена в то время. Полное тестирование плюс завершение функции заняло целый квартал, пока проект не стабилизировался и эффект стресс-теста не стал хорошим. Один шлюз (2C 8G) может достигать 2000 запросов в секунду в полноканальном имитационном стресс-тесте в реальных условиях. Из-за введения относительно тяжелой бизнес-логики (один запрос вызывает в среднем 3 интерфейса dubbo) этот результат стресс-теста соответствует или даже превосходит ожидания.

Обобщил некоторый опыт настройки конфигурации параметров dubbo-go, в основном, некоторых конфигураций, связанных с сетью.

Когда вы запускаете демо, вы должны увидеть кучу конфигураций в конце файла конфигурации, но если вы не знакомы с базовой сетевой моделью Dubbo-Go, трудно понять смысл этих конфигураций. В настоящее время сетевой слой Dubbo-Go использует Getty в качестве основной структуры для достижения разделения с чтением и управлением бассейна BOUTINE. Getty подвергает концепцию сессии в внешний мир. Сессия предоставляет серию реализаций метода сетевого уровня. Поскольку эта статья не является документом по анализу исходного кода, я не буду обсуждать это здесь. Читатели могут просто подумать, что Dubbo-go поддерживает пул Getty Session, а сессия поддерживает бассейн соединения TCP. Для каждого соединения Getty будет прочитать Corotine и писать сопроводительное сопроводительное сопроводительное, чтобы отделить чтение и запись. Здесь я пытаюсь использовать популярные комментарии, чтобы помочь вам разобраться с несколькими значениями конфигурации, которые оказывают большее влияние на производительность:

protocol_conf:
  # 这里是协议独立的配置,在dubbo协议下,大多数配置即为getty session相关的配置。
  dubbo:
      # 一个session会始终保证connection_number个tcp连接个数,默认是16,
    # 但这里建议大家配置相对小的值,一般系统不需要如此多的连接个数。
    # 每隔reconnect_interval时间,检查连接个数,如果小于connection_number,
    # 就建立连接。填0或不填都为默认值300ms
    reconnect_interval: 0
    connection_number: 2
    # 客户端发送心跳的间隔
    heartbeat_period: "30s"
    # OnCron时session的超时时间,超过session_timeout无返回就关闭session
    session_timeout: "30s"
    # 每一个dubbo interface的客户端,会维护一个最大值为pool_size大小的session池。
    # 每次请求从session池中select一个。所以真实的tcp数量是session数量*connection_number,
    # 而pool_size是session数量的最大值。测试总结下来一般程序4个tcp连接足以。
    pool_size: 4
    # session保活超时时间,也就是超过session_timeout时间没有使用该session,就会关闭该session
    pool_ttl: 600
    # 处理返回值的协程池大小
    gr_pool_size: 1200
    # 读数据和协程池中的缓冲队列长度,目前已经废弃。不使用缓冲队列
    queue_len: 64
    queue_number: 60
    getty_session_param:
      compress_encoding: false
      tcp_no_delay: true
      tcp_keep_alive: true
      keep_alive_period: "120s"
      tcp_r_buf_size: 262144
      tcp_w_buf_size: 65536
      pkg_wq_size: 512
      tcp_read_timeout: "1s"  # 每次读包的超时时间
      tcp_write_timeout: "5s" # 每次写包的超时时间
      wait_timeout: "1s" 
      max_msg_len: 102400     # 最大数据传输长度
      session_name: "client"

даббо-го быстрый доступ

В предыдущей статье были показаны практические результаты даббо-го в Tuya Intelligence, далее мы представим способ быстрого доступа к даббо-го.

Первый шаг: привет мир

Пример использования dubbo-go в настоящее время такой же, как и у dubbo, и находится в проекте apache/dubbo-samples. В каталоге dubbo-sample/golang пользователи могут выбрать интересующий их каталог функций, чтобы быстро проверить эффект кода.

tree dubbo-samples/golang -L 1
dubbo-samples/golang
├── README.md
├── async
├── ci.sh
├── configcenter
├── direct
├── filter
├── general
├── generic
├── go.mod
├── go.sum
├── helloworld
├── multi_registry
└── registry

В качестве примера используем Hello World, следуем шагам в Dubbo-Samples/Golang/Readme.md, запускаем Сервер и Клиент соответственно. Вы можете попробовать Golang для вызова Java, Java для вызова golang, golang для вызова golang, Java для вызова Java. Dubbo-GO поддерживает и интерком по протоколу Dubbo.

Начаем GO-сервер, например, используйте Registry Zookeeper по умолчанию. Сначала убедитесь, что локальный зообетователь работает правильно. Затем выполните следующую команду, вы можете сразу увидеть свой журнал нормальный запуск службы.

export ARCH=mac
export ENV=dev
cd dubbo-samples/golang/helloworld/dubbo/go-server
sh ./assembly/$ARCH/$ENV.sh
cd ./target/darwin/user_info_server-2.6.0-20200608-1056-dev/
sh ./bin/load.sh start

Шаг 2: Используйте dubbo-go в проекте

Выше мы запустили вариант использования с помощью поддерживаемого сообществом тестового кода и сценариев запуска. Далее нам нужно встроить фреймворк dubbo-go в наш код. Многие друзья часто сталкиваются с проблемами на этом этапе.Вот некоторые распространенные проблемы, которые я собрал, чтобы помочь вам.

1) Переменные среды

В настоящее время dubbo-go имеет 3 переменные среды, которые необходимо настроить:

  • CONF_CONSUMER_FILE_PATH: путь к файлу конфигурации на стороне потребителя, который требуется при использовании потребителя;
  • CONF_PROVIDER_FILE_PATH: Путь к файлу конфигурации провайдера, требуется при использовании провайдера;
  • App_log_conf_file: путь к файлу журнала журнала, обязательно;
  • CONF_ROUTER_FILE_PATH: Путь к файлу конфигурации правил File Router, необходимый при использовании File Router.

2) Точки внимания кода

  • Служба внедрения: проверьте, выполняется ли следующий код
# 客户端
func init() {
  config.SetConsumerService(userProvider)
}
# 服务端
func init() {
  config.SetProviderService(new(UserProvider))
}
  • ввести описание сериализации: проверьте, выполняется ли следующий код
hessian.RegisterJavaEnum(Gender(MAN))
  hessian.RegisterJavaEnum(Gender(WOMAN))
  hessian.RegisterPOJO(&User{})

3) Правильно понимать конфигурационный файл

  • Ключ под ссылками/службами, такой как «UserProvider» в следующем примере, должен соответствовать возвращаемому значению службы Reference(), которая является ключом, идентифицирующим интерфейс, который необходимо изменить.
references:
"UserProvider":
  registry: "hangzhouzk"
  protocol : "dubbo"
  interface : "com.ikurento.user.UserProvider"
  cluster: "failover"
  methods :
  - name: "GetUser"
    retries: 3
  • Если у реестра есть только один кластер реестра, вам нужно только настроить один. Несколько IPS разделены запятыми следующим образом:
registries :
"hangzhouzk":
  protocol: "zookeeper"
  timeout    : "3s"
  address: "172.16.120.181:2181,172.16.120.182:2181"
  username: ""
  password: ""

4) Проблемы с java так и идут

Случай взаимодействия между go и java: чтобы адаптироваться к формату верблюжьего регистра java, golang автоматически изменит первую букву метода и свойства на строчную при вызове java-сервисов. Многие студенты намеренно пишут код Java как определения параметров, адаптированные к golang, делают первую букву заглавной и, наконец, не могут сериализоваться и сопоставляться.

Шаг 3: Расширьте функцию

И dubbo-go, и dubbo предоставляют очень богатый механизм расширения. Пользовательский модуль может быть реализован для замены стандартного модуля dubbo-go или для добавления некоторых функций. Например, внедрите Cluster, Filter, Router и т. д., чтобы адаптироваться к потребностям бизнеса. Эти методы внедрения представлены в dubbo-go/common/extension, что позволяет пользователям вызывать и настраивать их.

Второй выпуск Alibaba Summer of Programming набирает обороты!

25 мая 2020 г.Официально запущен второй этап Alibaba Summer of Code (далее — ASoC).Шкала проекта снова обновилась. Есть целых 20 звездных проектов с открытым исходным кодом, такие как Apache Dubbo, Apache RocketMQ, Dragonfly и NACOS из сообщества открытого исходного кода; состав наставников роскошный, в том числе технические эксперты из группы Alibaba Основные члены сообщества открытого исходного кода, наставники инкубатора Apache и т. Д. До 32; поле включает в себя микровисты, контейнеры, AI и другие горячие темы, направленные на объединение сообщества с открытым исходным кодом для создания искренней, справедливой и просто открытого источника Платформа стажировки, с технологией Alibaba с открытым исходным кодом в качестве «толкателя», пусть China Open Source Сообщество и элиты разработчика признаны во всем мире.

Нажми для деталей:developer.aliyun.com/topic/Судьба...

"Облачная нативная платформа AlibabaСосредоточьтесь на микросервисах, бессерверных технологиях, контейнерах, Service Mesh и других технических областях, сосредоточьтесь на популярных тенденциях облачных технологий и практиках крупномасштабного внедрения облачных технологий, а также станьте официальной учетной записью самых облачных разработчиков. "