RPC remote calling method in openstack

Time:2022-1-13

As we all know, openstack has two communication modes, one is restful API mode based on HTTP protocol, and the other is RPC call. The application scenarios of the two communication methods are different. In openstack, the former is mainly used for the communication between components (such as the communication between Nova and grace), while the latter is used for the communication between different modules in the same component (such as the communication between Nova compute and Nova scheduler in Nova component).

There are a lot of RPC calls in Nova. When using pycharm to follow functions, you will not be able to click RPC. If you don’t solve it, you can’t see it directly

What is RPC

在这里插入图片描述

If you can’t understand this figure, it’s not very important to look at Nova code. You can just ignore it and look at it later. The top priority is to solve the problem of losing RPC when looking at openstack code

RPC, message queuing, restful

In fact, these three things are not at the same level. In essence, they should not be compared together. However, because they are used for communication, they are easy to be confused, so I’d like to explain

  • Restful: it is mainly used for the communication between components (such as the communication between Nova and grace), or for providing external calling interfaces for components
  • RPC: used for communication between different modules in the same component (such as communication between Nova compute and – Nova scheduler in Nova component)
  • Message queue: it is used to decouple components. It is also used for communication between components, and there will be a queue to temporarily store messages

Typical RPC in Nova

nova/nova/nova/conductor/tasks/live_migrate.py

class LiveMigrationTask(base.TaskBase):
    def __init__(self, context, instance, destination,
                 block_migration, disk_over_commit, migration, compute_rpcapi,
                 servicegroup_api, scheduler_client):
        super(LiveMigrationTask, self).__init__(context, instance)
    ... 

    def _execute(self):
        self._check_instance_is_active()
        self._check_host_is_up(self.source)

        if not self.destination:
            self.destination = self._find_destination()
            self.migration.dest_compute = self.destination
            self.migration.save()
        else:
            self._check_requested_destination()

        # TODO(johngarbutt) need to move complexity out of compute manager
        # TODO(johngarbutt) disk_over_commit?

        #Call live in the computeapi class_ Migration () RPC interface
        return self.compute_rpcapi.live_migration(self.context,
                host=self.source,
                instance=self.instance,
                dest=self.destination,
                block_migration=self.block_migration,
                migration=self.migration,
                migrate_data=self.migrate_data)

conductorwithcompute_rpcapi.live_migrationRemote callcomputeoflive_migration, the process is,conductorwithRPCSend a request toQueueAgain bynova-computereceive

nova/nova/nova/compute/rpcapi.py

class ComputeAPI(object):

    #This is a method called remotely by RPC
    def live_migration(self, ctxt, instance, dest, block_migration, host,
                       migration, migrate_data=None):
        args = {'migration': migration}
        version = '4.2'
        if not self.client.can_send_version(version):
            version = '4.0'

        #Get the RPC client of the target compute host (dest host), that is, the hostip of the called service process
        cctxt = self.client.prepare(server=host, version=version)

        #The remote procedure method cast () is called through the RPC client of the target host object to realize the remote call
        cctxt.cast(ctxt, 'live_migration', instance=instance,
                   dest=dest, block_migration=block_migration,
                   migrate_data=migrate_data, **args)
        #Cast () is called asynchronously and remotely. It will not block other processes. It is suitable for execution processes that need a long time
        #The second parameter of cast () is the function name called by RPC client. The parameters after case () will continue to be passed into the calling function as parameters
        #Live in cast() function_ The migration () function is manager live_ Migration () depends on the function that implements the migration function. In manager Py.

Called fromnova/nova/conductor/tasks/live_migrate.pyreachnova/nova/compute/rpcapi.py, but actuallycomputeService must first berpcapi.pyProvide the interface function, and then the user can
– 1. Import import to use RPC calls
– 2. Class instantiation is introduced by passing parameters

Hot migration here uses class instantiation to pass parameters

Tip: call() indicates synchronous call and cast() indicates asynchronous call

在这里插入图片描述

According to inrpc.pyperhapsrpcapi.pyMediumcast()The second parameter of the service, go to themanager.pyFind a function with the same name as this parameter in therpcFinally, we want to call the function)compute_rpcapi, so I have to find itcomputeLowermannager.py

Why go to manager? It’s nova compute. The manager will always listen to the queue. When there are related RPC requests in the queue, it will complete the request

nova/nova/nova/compute/manager.py

@wrap_exception()
    @wrap_instance_event(prefix='compute')
    @wrap_instance_fault
    def live_migration(self, context, dest, instance, block_migration,
                       migration, migrate_data):
        "" "perform live migration.".

        :param context: security context
        :param dest: destination host
        :param instance: a nova.objects.instance.Instance object
        :param block_migration: if true, prepare for block migration
        :param migration: an nova.objects.Migration object
        :param migrate_data: implementation specific params

        """
        self._set_migration_status(migration, 'queued')

        def dispatch_live_migration(*args, **kwargs):
            with self._live_migration_semaphore:
                #Call_ do_ live_ Migration perform migration
                self._do_live_migration(*args, **kwargs)

        # NOTE(danms): We spawn here to return the RPC worker thread back to
        # the pool. Since what follows could take a really long time, we don't
        # want to tie up RPC workers.
        utils.spawn_n(dispatch_live_migration,
                      context, dest, instance,
                      block_migration, migration,
                      migrate_data)

Of course, the actual work is notmanager.pyofdef live_migration, butlive_migrationFunction to call_do_live_migrationHowever, the next step is the hot migration process, which is not expanded after being written in the previous document. Anyway, the embodiment of RPC is only here

There are many examples in cold migration. I won’t list them one by one. If you are interested, you can go to the blog of cold migration source code analysis

After reading the example, you will find that since the native code has written RPC calls, the corresponding service must have provided RPC interfaces, so you can actually seecompute_rpcapi, you can’t gocomputeLowerrpcI found it in the file. Go straightcomputeLowermanagerSee specific implementation (more than)compute, other services are the same). Of course, if you need to determine whether it is synchronous or asynchronous, don’t steal this step.

summary

A complete RPC should have

  • Component A provides RPC calling interface(rpc.pyperhapsrpcapi.py(file)
  • RPC of component a introduced by component B(importperhapsClass instantiation parameter passing)
  • Component B invokes the RPC of component a (inrpcSend a request to message queue)
  • Component a processes the request (component a hears the request sent to itself)rpcThe request will passmanagerProcess request)

If you just look at the code, go to the correspondingmanagerIt’s OK to find the implementation below, but if you want to add it, you still know where to provide it, how to import it and how to receive it. Only in this way can you know how to add your own RPC call to the code

reference:

https://zhuanlan.zhihu.com/p/36427583
https://blog.csdn.net/Jmilk/article/details/52655645
https://www.cnblogs.com/wongbingming/p/11086773.html
https://blog.csdn.net/qq_33909098/article/details/118578133

This is the end of this article on RPC remote calls in openstack. For more information about RPC calls in openstack, please search previous articles of developeppaer or continue to browse the following articles. I hope you will support developeppaer in the future!