Redis数据库

首先,在SONiC里面最核心的服务,自然是当之无愧的中心数据库Redis了!它的主要目的有两个:存储所有服务的配置和状态,并且为各个服务提供通信的媒介。

为了提供这些功能,SONiC会在Redis中创建一个名为sonic-db的数据库实例,其配置和分库信息我们可以在/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"
}

虽然我们可以看到SONiC中的数据库有十来个,但是我们大部分时候只需要关注以下几个最重要的数据库就可以了:

  • 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驱动的开发。

这里,我们会发现一个很直观的问题:交换机里面这么多服务,难道所有的配置和状态都放在一个数据库里面没有隔离的么?如果两个服务用了同一个Redis Key怎么办呢?这个问题非常的好,SONiC的解决也很直接,那就是在每个数据库里面继续分表!

我们知道Redis在每个数据库里面并没有表的概念,而是使用key-value的方式来存储数据。所以,为了进一步分表,SONiC的解决方法是将表的名字放入key中,并且使用分隔符将表和key隔开。上面的配置文件中separator字段就是做这个了。比如:APPL_DB中的PORT_TABLE表中的Ethernet4端口的状态,我们可以通过PORT_TABLE:Ethernet4来获取,如下:

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"

当然在SONiC中,不仅仅是数据模型,包括通信机制,都是使用类似的方法来实现“表”级别的隔离的。

参考资料

  1. SONiC Architecture