Running a playbook on multiple host groups one at a time

If you have equal count of hosts in each group, you can use pattern + serial.
Ansible forms host list by pattern moving through groups sequentially. So if you have equal count of hosts, then batches formed by serial will be equal to groups.

In your example, if you have exactly 3 hosts in each group, you can use:

- hosts: instance_id_*
  serial: 3
  tasks:
    - ping:

If you don't mind a bit of Ansible patching, you can modify _get_serialized_batches method.
Add this code just before while len(all_hosts) > 0::

    if 'serialize_by_var' in play.get_vars():
        param = play.get_vars()['serialize_by_var']
        sb = []
        def by_param(x):
            vrs = x.get_vars()
            if param in vrs:
                return vrs[param]
            else:
                return None

        s_hosts = sorted(all_hosts,key=by_param)
        for k, g in itertools.groupby(s_hosts, by_param):
            sb.append(list(g))

        display.vv('Serializing by host var "{}": {}'.format(param,sb))
        return sb

And you can serialize hosts by any variable like this:

- hosts: tag_type_edgenode
  vars:
    serialize_by_var: instance_id
  tasks:
    - ping

There is a simpler method using the size (length) of each group. However, this runs on all members of a group, flowing through the groups sequentially. I think OP was asking for how to act on the first member of each group, which I am also working on figuring out.

- name: "Restore selected devices in model_dc"
  hosts: group_1, group_2, group_3, group_4, group_5, group_6, group_7, !excluded
  any_errors_fatal: true    # Stop entire play if one host fails
  gather_facts: no
  order: inventory
  serial: 
    - "{{ groups['group_1'] | length }}" # The number of hosts for first batch
    - "{{ groups['group_2'] | length }}" # The number of hosts for second batch
    - "{{ groups['group_3'] | length }}"
    - "{{ groups['group_4'] | length }}"
    - "{{ groups['group_5'] | length }}"
    - "{{ groups['group_6'] | length }}"
    - "{{ groups['group_7'] | length }}" # The number of hosts for every batch until the end.

Building off of Konstantin's idea, you can do something like this using aliases and a list of patterns:

---
- hosts: "*-server-batch-1,*-servers-batch-2,*-server-batch-3"
  serial: 3
  ...
...


[london]
london-server-batch-1 ansible_host=server1.london.com
london-server-batch-2 ansible_host=server2.london.com
london-server-batch-3 ansible_host=server3.london.com

[tokyo]
tokyo-server-batch-1 ansible_host=server1.tokyo.com
tokyo-server-batch-2 ansible_host=server2.tokyo.com
tokyo-server-batch-3 ansible_host=server3.tokyo.com