Хостим облачную службу Azure на обычных vds

в 16:53, , рубрики: .net, azure, vds, vps, wcf

Пишу веб-проекты в visual studio, и с каждой новой версией студии она как будто затачивается для работы с Windows Azure. Мне нравится Азура, хотя я пользуюсь только небольшим набором возможностей. Основное для меня — это Облачная служба. Облачная служба отлично подходит для разворачивания распределенного сервера.

Итак, я создаю облачную службу, в которую добавляю одну веб-роль (виртуальная машина с IIS), один воркер (виртуальная машина без IIS) и общую библиотеку классов. После публикации моим ролям присваивается ip-адрес и разные порты. То есть сразу есть tcp сеть, ручные настройки минимальны и могут делаться в самой студии. Можно, к примеру, сделать общедоступную точку доступа для воркера, но мне это не нужно. Мой воркер будет скрыт от внешних глаз и на нём будет висеть wcf-сервер, а общаться мои роли будут по быстрой локальной сети.

Общие классы я выношу в библиотеку (которую подключаю ко всем ролям), к примеру, интерфейс и канал связи:

    [ServiceContract]
    public interface IwcfChat
    {
        [OperationContract]
        string SendMessage(string userId, string userName, string text);

        [OperationContract]
        string GetMessages(string userId, string userName);
    }

//================

    public sealed class wcfChat:IDisposable
    {
        IwcfChat _channel;
        ChannelFactory<IwcfChat> factory = null;
        public wcfChat()
        {
            NetTcpBinding b = new NetTcpBinding();
            b.Security.Mode = SecurityMode.None;
            b.Security.Message.ClientCredentialType = MessageCredentialType.None;

            #if(DEBUG)
                EndpointAddress address = new EndpointAddress("net.tcp://127.255.0.1:9003/wcfChat");
            #else
                EndpointAddress address = new EndpointAddress("net.tcp://"+spr.wcfIP+":9003/wcfChat"); 
            #endif

                factory = new ChannelFactory<IwcfChat>(b, address);
            factory.Faulted += OnChannelFaulted;
            factory.Open();
        }

        public IwcfChat channel
        {
            get
            {
                if (factory != null && factory.State == CommunicationState.Opened)
                {
                    if(_channel==null) _channel = factory.CreateChannel();
                    return _channel;
                }

                return null;
            }
        }

        void OnChannelFaulted(object sender, EventArgs e)
        {
            factory.Abort();
        }

        public void Dispose()
        {
            factory.Close();
        }
    }

Методы в веб-роли вызываю так:

 using (var chat = new wcfChat())
 {
  res = chat.channel.SendMessage(id, name, text);
 }

Соответственно, в воркере у меня реализация методов из интерфейса (SendMessage, GetMessage), не буду их расписывать, а так же в воркере при старте выполняется код, который делает его хостом для wcf:


 public override bool OnStart()
 {
  // Задайте максимальное число одновременных подключений 
  ServicePointManager.DefaultConnectionLimit = 12;

  // Create the host
  ServiceHost host = new ServiceHost(typeof(wcfChat));

  // Read config parameters
  string hostName = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["port"].IPEndpoint.Address.ToString();
  int port = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["port"].IPEndpoint.Port;
  int mexport = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["mexport"].IPEndpoint.Port;

  // Create Metadata
  ServiceMetadataBehavior metadatabehavior = new ServiceMetadataBehavior();
  host.Description.Behaviors.Add(metadatabehavior);

  Binding mexBinding = MetadataExchangeBindings.CreateMexTcpBinding();
  string mexendpointurl = string.Format("net.tcp://{0}:{1}/wcfChatMetadata", hostName, 8003);
  host.AddServiceEndpoint(typeof(IMetadataExchange), mexBinding, mexendpointurl, new Uri(mexendpointurl));

  // Create end point
  string endpointurl = string.Format("net.tcp://{0}:{1}/wcfChat", hostName, 9003);
  host.AddServiceEndpoint(typeof(IwcfChat), new NetTcpBinding(SecurityMode.None), endpointurl, new Uri(endpointurl));

  // Open the host
  host.Open();

  // Trace output
  Trace.WriteLine("WCF Listening At: " + endpointurl);
  Trace.WriteLine("WCF MetaData Listening At: " + mexendpointurl);


  return base.OnStart();
 }

Тут я показал методы типа string, но тип возвращаемого значения может быть абсолютно любой, к примеру, сложный класс, который описан в моей общей библиотеке. Всё, никаких других настроек в вебконфигах, никаких упаковок в xml или SOAP у меня нет. Нет автоматически генерируемых файлов контрактов. Когда я пытался это сделать, в интернетах при поиске информации про wcf всегда всплывает настройка под http со всеми этими упаковками/распаковками. Да, wcf технология изначально придумана для связи разнородных систем, где необходимо сериализовать и передавать как строку. Но если у нас один язык программирования, а клиент и сервер wcf — это всё наша разработка, то не нужно городить огород, всё прекрасно работает.

Таким образом у меня получается распределенный сервер, для затратных операций я делаю отдельный воркер, тут, к примеру, показан чат. Все функции чата вынесены в отдельную виртуальную машину и я могу увеличивать производительность как самого сайта (веб-роли), так, отдельно, и чата.

Такая архитектура мне кажется правильной и может выдержать более сильную нагрузку, чем монолитный проект. Так же всё это разрабатывается и отлаживается как один проект в студии, то есть при вызове метода по wcf я могу в отладке пройти глубже в код, без сообщений типа «внутри отлаживать я не могу, не знаю что там происходит, вот такой вернулся результат».

С Азуровскими инструментами это делается всё легко и просто, я запускаю весь проект одной кнопкой и отлаживаюсь по нему как по одному проекту. Я помню когда-то давно, на одном из проектов была похожая архитектура, но я был молод, и мне там было очень сложно: какие-то фасады, и, если параметры у метода менялись, я изменения в четырёх местах вносил.

Мне нужно нечто подобное сделать на обычных серверах. Не на своих физических серверах, а на vds/vps виртуалках у какого-нибудь обязательно российского хостера. Я нашел забавную технологию у одного из хостеров (1gb.ru), называется ресурс Windows Azure Pack / COSN. По описанию это урезанная версия Азуры и всё должно было бы «взлететь». Конечно же, у них есть пробный период, я посмотрел. В браузере управление как-будто из старой версии портала Азуры (если кто помнит). Из возможностей есть только создание виртуальных машин, объединение их в сеть (вручную), есть service bus — и всё. Так же нет возможности загрузить эту подписку в студию, а в этом и есть многое из удобств. Плюс нет возможности создания облачной службы. В описании сказано, что это «частное облако» будет дорабатываться и дополняться возможностями с оригинальной Азуры, но поддержка сказала, что всё уже давно заморожено, и вообще, это несовместимые технологии («этот Azure Pack совершенно по смыслу не совместим с настоящим Azure. Там что есть, то есть, и есть там маловато. Идеи там общие, но реализация разная совершенно, API разные и так далее.» (с))

В общем, если я арендую у хостинга два vds, то они, во-первых, не связаны tcp сетью. Делать мой воркер общедоступным, связывать их по http(s), нагромождать упаковку/распаковку — это не то, что мне нужно. Во-вторых, по созданию и отладке: получается, в проекте я буду создавать одинаковые MVC проекты и чтобы запустить на локалке проект, мне нужно будет все воркеры вначале по отдельности запустить, а если отлаживаюсь по f10, то внутрь воркера сам проваливаться не будет, нужно будет заходить и вручную точку останова ставить. Это ужасно неудобно.

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

Как такую штуку перенести на обычный хостинг — я не знаю и надеюсь на вашу помощь. Очень интересует, правильно ли я всё делаю в принципе? Верная ли архитектура? Имеет ли она какое-то определенное название (очень тяжело искать информацию, когда не знаешь что искать)? Как правильно создать такой проект для обычных хостингов, его отлаживать и публиковать?

Еще я наткнулся на создание wcf службы и её публикацию, всё быстро и просто, но смысл там тот же самый: публичный http с сериализаций/десериализацией, мне такое не подходит.

Автор: Jeer

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js