Redis Database

First of all, the most important service in SONiC is undoubtedly the central database - Redis! It has 2 major purposes: to store the switch configuration and status of all services, as well as to provide a communication channel among all services.

In order to provide these features, SONiC will create a instance named sonic-db in Redis, and its configuration and sharding information can be found in /var/run/redis/sonic-db/database_config.json.

admin@sonic:~$ cat /var/run/redis/sonic-db/database_config.json
{
    "INSTANCES": {
        "redis": {
            "hostname": "127.0.0.1",
            "port": 6379,
            "unix_socket_path": "/var/run/redis/redis.sock",
            "persistence_for_warm_boot": "yes"
        }
    },
    "DATABASES": {
        "APPL_DB": { "id": 0, "separator": ":", "instance": "redis" },
        "ASIC_DB": { "id": 1, "separator": ":", "instance": "redis" },
        "COUNTERS_DB": { "id": 2, "separator": ":", "instance": "redis" },
        "LOGLEVEL_DB": { "id": 3, "separator": ":", "instance": "redis" },
        "CONFIG_DB": { "id": 4, "separator": "|", "instance": "redis" },
        "PFC_WD_DB": { "id": 5, "separator": ":", "instance": "redis" },
        "FLEX_COUNTER_DB": { "id": 5, "separator": ":", "instance": "redis" },
        "STATE_DB": { "id": 6, "separator": "|", "instance": "redis" },
        "SNMP_OVERLAY_DB": { "id": 7, "separator": "|", "instance": "redis" },
        "RESTAPI_DB": { "id": 8, "separator": "|", "instance": "redis" },
        "GB_ASIC_DB": { "id": 9, "separator": ":", "instance": "redis" },
        "GB_COUNTERS_DB": { "id": 10, "separator": ":", "instance": "redis" },
        "GB_FLEX_COUNTER_DB": { "id": 11, "separator": ":", "instance": "redis" },
        "APPL_STATE_DB": { "id": 14, "separator": ":", "instance": "redis" }
    },
    "VERSION": "1.0"
}

Although there are about ten databases in SONiC that we can see, most of the time we only need to focus on the following few most important databases:

  • CONFIG_DB(ID = 4):存储所有服务的配置信息,比如端口配置,VLAN配置等等。它代表着用户想要交换机达到的状态的数据模型,这也是所有CLI和外部应用程序修改配置时的主要操作对象。
  • APPL_DB(Application DB, ID = 0):存储所有服务的内部状态信息。这些信息有两种:一种是各个服务在读取了CONFIG_DB的配置信息后,自己计算出来的。我们可以理解为各个服务想要交换机达到的状态(Goal State),还有一种是当最终硬件状态发生变化被写回时,有些服务会直接写回到APPL_DB,而不是我们下面马上要介绍的STATE_DB。这些信息我们可以理解为各个服务认为交换机当前的状态(Current State)。
  • STATE_DB(ID = 6):存储着交换机各个部件当前的状态(Current State)。当SONiC中的服务收到了STATE_DB的状态变化,但是发现和Goal State不一致的时候,SONiC就会重新下发配置,直到两者一致。(当然,对于那些回写到APPL_DB状态,服务就会监听APPL_DB的变化,而不是STATE_DB了。)
  • ASIC_DB(ID = 1):存储着SONiC想要交换机ASIC达到状态信息,比如,ACL,路由等等。和APPL_DB不同,这个数据库里面的数据模型是面向ASIC设计的,而不是面向服务抽象的。这样做的目的是为了方便各个厂商进行SAI和ASIC驱动的开发。

Now, we will notice a very intuitive problem: with so many services in the switch, are all configurations and states stored in one database without isolation? What if two services use the same Redis Key? This is a very good question, and SONiC's solution is very direct: continue to partition the tables in each database!

We know that Redis does not have the concept of table in each database, but directly stores data using key-value pairs. Therefore, in order to further partition tables, SONiC's solution is to put the table name into the key and use a separator to separate the table from the key. The separator field in the above configuration file is for this purpose. For example, to retrieve the status of the Ethernet4 port in the PORT_TABLE table in the APPL_DB, we can use PORT_TABLE:Ethernet4 as the key, as follows:

127.0.0.1:6379> select 0
OK

127.0.0.1:6379> hgetall PORT_TABLE:Ethernet4
 1) "admin_status"
 2) "up"
 3) "alias"
 4) "Ethernet6/1"
 5) "index"
 6) "6"
 7) "lanes"
 8) "13,14,15,16"
 9) "mtu"
10) "9100"
11) "speed"
12) "40000"
13) "description"
14) ""
15) "oper_status"
16) "up"

Of course, in SONiC, not only data models but also communication mechanisms are implemented using similar methods to achieve "table-level" isolation.

参考资料

  1. SONiC Architecture