Просмотр исходного кода

refactor(config): emqx.conf for 5.0

Shawn 4 лет назад
Родитель
Сommit
02c9a3163b
3 измененных файлов с 4883 добавлено и 2732 удалено
  1. 2179 2464
      apps/emqx/etc/emqx.conf
  2. 2467 0
      apps/emqx/etc/emqx.conf.old
  3. 237 268
      apps/emqx/src/emqx_schema.erl

Разница между файлами не показана из-за своего большого размера
+ 2179 - 2464
apps/emqx/etc/emqx.conf


Разница между файлами не показана из-за своего большого размера
+ 2467 - 0
apps/emqx/etc/emqx.conf.old


+ 237 - 268
apps/emqx/src/emqx_schema.erl

@@ -14,6 +14,7 @@
 -type duration_s() :: integer().
 -type duration_ms() :: integer().
 -type bytesize() :: integer().
+-type wordsize() :: bytesize().
 -type percent() :: float().
 -type file() :: string().
 -type comma_separated_list() :: list().
@@ -26,6 +27,7 @@
 -typerefl_from_string({duration_s/0, emqx_schema, to_duration_s}).
 -typerefl_from_string({duration_ms/0, emqx_schema, to_duration_ms}).
 -typerefl_from_string({bytesize/0, emqx_schema, to_bytesize}).
+-typerefl_from_string({wordsize/0, emqx_schema, to_wordsize}).
 -typerefl_from_string({percent/0, emqx_schema, to_percent}).
 -typerefl_from_string({comma_separated_list/0, emqx_schema, to_comma_separated_list}).
 -typerefl_from_string({bar_separated_list/0, emqx_schema, to_bar_separated_list}).
@@ -33,7 +35,8 @@
 -typerefl_from_string({comma_separated_atoms/0, emqx_schema, to_comma_separated_atoms}).
 
 % workaround: prevent being recognized as unused functions
--export([to_duration/1, to_duration_s/1, to_duration_ms/1, to_bytesize/1,
+-export([to_duration/1, to_duration_s/1, to_duration_ms/1,
+         to_bytesize/1, to_wordsize/1,
          to_flag/1, to_percent/1, to_comma_separated_list/1,
          to_bar_separated_list/1, to_ip_port/1,
          to_comma_separated_atoms/1]).
@@ -41,21 +44,21 @@
 -behaviour(hocon_schema).
 
 -reflect_type([ log_level/0, flag/0, duration/0, duration_s/0, duration_ms/0,
-                bytesize/0, percent/0, file/0,
+                bytesize/0, wordsize/0, percent/0, file/0,
                 comma_separated_list/0, bar_separated_list/0, ip_port/0,
                 comma_separated_atoms/0]).
 
 -export([structs/0, fields/1, translations/0, translation/1]).
 -export([t/1, t/3, t/4, ref/1]).
 -export([conf_get/2, conf_get/3, keys/2, filter/1]).
--export([ssl/2, tr_ssl/2, tr_password_hash/2]).
+-export([ssl/1, tr_ssl/2, tr_password_hash/2]).
 
 %% will be used by emqx_ct_helper to find the dependent apps
 -export([includes/0]).
 
 structs() -> ["cluster", "node", "rpc", "log", "lager",
-              "acl", "mqtt", "zone", "listener", "module", "broker",
-              "plugins", "sysmon", "os_mon", "vm_mon", "alarm", "telemetry"]
+              "acl", "mqtt", "zone", "listeners", "module", "broker",
+              "plugins", "sysmon", "alarm", "telemetry"]
              ++ includes().
 
 -ifdef(TEST).
@@ -69,7 +72,8 @@ includes() ->
 
 fields("cluster") ->
     [ {"name", t(atom(), "ekka.cluster_name", emqxcl)}
-    , {"discovery", t(atom(), undefined, manual)}
+    , {"discovery_strategy", t(union([manual, static, mcast, dns, etcd, k8s]),
+        undefined, manual)}
     , {"autoclean", t(duration(), "ekka.cluster_autoclean", undefined)}
     , {"autoheal", t(flag(), "ekka.cluster_autoheal", false)}
     , {"static", ref("static")}
@@ -83,7 +87,7 @@ fields("cluster") ->
     ];
 
 fields("static") ->
-    [ {"seeds", t(comma_separated_list())}];
+    [ {"seeds", t(list(string()))}];
 
 fields("mcast") ->
     [ {"addr", t(string(), undefined, "239.192.0.1")}
@@ -97,7 +101,8 @@ fields("mcast") ->
     ];
 
 fields("dns") ->
-    [ {"app", t(string())}];
+    [ {"name", t(string())}
+    , {"app", t(string())}];
 
 fields("etcd") ->
     [ {"server", t(comma_separated_list())}
@@ -107,7 +112,7 @@ fields("etcd") ->
     ];
 
 fields("etcd_ssl") ->
-    ssl(undefined, #{});
+    ssl(#{});
 
 fields("k8s") ->
     [ {"apiserver", t(string())}
@@ -125,7 +130,6 @@ fields("rlog") ->
 
 fields("node") ->
     [ {"name", t(string(), "vm_args.-name", "emqx@127.0.0.1", "EMQX_NODE_NAME")}
-    , {"ssl_dist_optfile", t(string(), "vm_args.-ssl_dist_optfile", undefined)}
     , {"cookie", hoconsc:t(string(), #{mapping => "vm_args.-setcookie",
                                        default => "emqxsecretcookie",
                                        sensitive => true,
@@ -133,16 +137,8 @@ fields("node") ->
                                       })}
     , {"data_dir", t(string(), "emqx.data_dir", undefined)}
     , {"etc_dir", t(string(), "emqx.etc_dir", undefined)}
-    , {"heartbeat", t(flag(), undefined, false)}
-    , {"async_threads", t(range(1, 1024), "vm_args.+A", undefined)}
-    , {"process_limit", t(integer(), "vm_args.+P", undefined)}
-    , {"max_ports", t(range(1024, 134217727), "vm_args.+Q", undefined, "EMQX_MAX_PORTS")}
-    , {"dist_buffer_size", fun node__dist_buffer_size/1}
     , {"global_gc_interval", t(duration_s(), "emqx.global_gc_interval", undefined)}
-    , {"fullsweep_after", t(non_neg_integer(),
-                            "vm_args.-env ERL_FULLSWEEP_AFTER", 1000)}
-    , {"max_ets_tables", t(integer(), "vm_args.+e", 256000)}
-    , {"crash_dump", t(file(), "vm_args.-env ERL_CRASH_DUMP", undefined)}
+    , {"crash_dump_dir", t(file(), "vm_args.-env ERL_CRASH_DUMP", undefined)}
     , {"dist_net_ticktime", t(integer(), "vm_args.-kernel net_ticktime", undefined)}
     , {"dist_listen_min", t(integer(), "kernel.inet_dist_listen_min", undefined)}
     , {"dist_listen_max", t(integer(), "kernel.inet_dist_listen_max", undefined)}
@@ -215,50 +211,40 @@ fields("lager") ->
     , {"crash_log", t(flag(), "lager.crash_log", false)}
     ];
 
-fields("acl") ->
-    [ {"allow_anonymous", t(boolean(), "emqx.allow_anonymous", false)}
-    , {"acl_nomatch", t(union(allow, deny), "emqx.acl_nomatch", deny)}
-    , {"acl_file", t(string(), "emqx.acl_file", undefined)}
-    , {"enable_acl_cache", t(flag(), "emqx.enable_acl_cache", true)}
-    , {"acl_cache_ttl", t(duration(), "emqx.acl_cache_ttl", "1m")}
-    , {"acl_cache_max_size", t(range(1, inf), "emqx.acl_cache_max_size", 32)}
-    , {"acl_deny_action", t(union(ignore, disconnect), "emqx.acl_deny_action", ignore)}
-    , {"flapping_detect_policy", t(comma_separated_list(), undefined, "30,1m,5m")}
+fields("stats") ->
+    [ {"enable", t(boolean(), undefined, true)}
     ];
 
-fields("mqtt") ->
-    [ {"max_packet_size", t(bytesize(), "emqx.max_packet_size", "1MB", "EMQX_MAX_PACKET_SIZE")}
-    , {"max_clientid_len", t(integer(), "emqx.max_clientid_len", 65535)}
-    , {"max_topic_levels", t(integer(), "emqx.max_topic_levels", 0)}
-    , {"max_qos_allowed", t(range(0, 2), "emqx.max_qos_allowed", 2)}
-    , {"max_topic_alias", t(integer(), "emqx.max_topic_alias", 65535)}
-    , {"retain_available", t(boolean(), "emqx.retain_available", true)}
-    , {"wildcard_subscription", t(boolean(), "emqx.wildcard_subscription", true)}
-    , {"shared_subscription", t(boolean(), "emqx.shared_subscription", true)}
-    , {"ignore_loop_deliver", t(boolean(), "emqx.ignore_loop_deliver", true)}
-    , {"strict_mode", t(boolean(), "emqx.strict_mode", false)}
-    , {"response_information", t(string(), "emqx.response_information", undefined)}
+fields("auth") ->
+    [ {"enable", t(boolean(), undefined, false)}
     ];
 
-fields("zone") ->
-    [ {"$name", ref("zone_settings")}];
+fields("acl") ->
+    [ {"enable", t(boolean(), undefined, false)}
+    , {"cache", ref("acl_cache")}
+    , {"deny_action", t(union(ignore, disconnect), undefined, ignore)}
+    ];
 
-fields("zone_settings") ->
-    [ {"idle_timeout", t(duration(), undefined, "15s")}
-    , {"allow_anonymous", t(boolean())}
-    , {"acl_nomatch", t(union(allow, deny))}
-    , {"enable_acl", t(flag(), undefined, false)}
-    , {"acl_deny_action", t(union(ignore, disconnect), undefined, ignore)}
-    , {"enable_ban", t(flag(), undefined, false)}
-    , {"enable_stats", t(flag(), undefined, false)}
-    , {"max_packet_size", t(bytesize())}
-    , {"max_clientid_len", t(integer())}
-    , {"max_topic_levels", t(integer())}
-    , {"max_qos_allowed", t(range(0, 2))}
-    , {"max_topic_alias", t(integer())}
-    , {"retain_available", t(boolean())}
-    , {"wildcard_subscription", t(boolean())}
-    , {"shared_subscription", t(boolean())}
+fields("acl_cache") ->
+    [ {"enable", t(boolean(), undefined, true)}
+    , {"max_size", t(range(1, 1048576), undefined, 32)}
+    , {"ttl", t(duration(), undefined, "1m")}
+    ];
+
+fields("mqtt") ->
+    [ {"mountpoint", t(binary(), undefined, <<"">>)}
+    , {"idle_timeout", t(duration(), undefined, "15s")}
+    , {"max_packet_size", t(bytesize(), undefined, "1MB")}
+    , {"max_clientid_len", t(integer(), undefined, 65535)}
+    , {"max_topic_levels", t(integer(), undefined, 0)}
+    , {"max_qos_allowed", t(range(0, 2), undefined, 2)}
+    , {"max_topic_alias", t(integer(), undefined, 65535)}
+    , {"retain_available", t(boolean(), undefined, true)}
+    , {"wildcard_subscription", t(boolean(), undefined, true)}
+    , {"shared_subscription", t(boolean(), undefined, true)}
+    , {"ignore_loop_deliver", t(boolean())}
+    , {"strict_mode", t(boolean(), undefined, false)}
+    , {"response_information", t(string(), undefined, undefined)}
     , {"server_keepalive", t(integer())}
     , {"keepalive_backoff", t(float(), undefined, 0.75)}
     , {"max_subscriptions", t(integer(), undefined, 0)}
@@ -267,121 +253,150 @@ fields("zone_settings") ->
     , {"retry_interval", t(duration_s(), undefined, "30s")}
     , {"max_awaiting_rel", t(duration(), undefined, 0)}
     , {"await_rel_timeout", t(duration_s(), undefined, "300s")}
-    , {"ignore_loop_deliver", t(boolean())}
     , {"session_expiry_interval", t(duration_s(), undefined, "2h")}
     , {"max_mqueue_len", t(integer(), undefined, 1000)}
     , {"mqueue_priorities", t(comma_separated_list(), undefined, "none")}
     , {"mqueue_default_priority", t(union(highest, lowest), undefined, lowest)}
     , {"mqueue_store_qos0", t(boolean(), undefined, true)}
-    , {"enable_flapping_detect", t(flag(), undefined, false)}
-    , {"rate_limit", ref("rate_limit")}
-    , {"conn_congestion", ref("conn_congestion")}
-    , {"quota", ref("quota")}
-    , {"force_gc_policy", t(bar_separated_list())}
-    , {"force_shutdown_policy", t(bar_separated_list(), undefined, "default")}
-    , {"mountpoint", t(string())}
     , {"use_username_as_clientid", t(boolean(), undefined, false)}
-    , {"strict_mode", t(boolean(), undefined, false)}
-    , {"response_information", t(string())}
-    , {"bypass_auth_plugins", t(boolean(), undefined, false)}
+    , {"peer_cert_as_username", maybe_disabled(union([cn, dn, crt, pem, md5]))}
+    , {"peer_cert_as_clientid", maybe_disabled(union([cn, dn, crt, pem, md5]))}
     ];
 
-fields("rate_limit") ->
-    [ {"conn_messages_in", t(comma_separated_list())}
-    , {"conn_bytes_in", t(comma_separated_list())}
+fields("zone") ->
+    [ {"$name", ref("zone_settings")}];
+
+fields("zone_settings") ->
+    [ {"mqtt", ref("mqtt")}
+    , {"acl", ref("acl")}
+    , {"auth", ref("auth")}
+    , {"stats", ref("stats")}
+    , {"flapping_detect", ref("flapping_detect")}
+    , {"force_shutdown", ref("force_shutdown")}
+    , {"conn_congestion", ref("conn_congestion")}
+    , {"force_gc", ref("force_gc")}
+    , {"overall_max_connections", t(integer(), undefined, 2048000)}
+    , {"listeners", t("listeners")}
     ];
 
-fields("conn_congestion") ->
-    [ {"alarm", t(flag(), undefined, false)}
-    , {"min_alarm_sustain_duration", t(duration(), undefined, "1m")}
+fields("rate_limit") ->
+    [ {"max_conn_rate", maybe_infinity(integer(), 1000)}
+    , {"conn_messages_in", t(comma_separated_list())}
+    , {"conn_bytes_in", t(comma_separated_list())}
+    , {"quota", ref("rate_limit_quota")}
     ];
 
-fields("quota") ->
+fields("rate_limit_quota") ->
     [ {"conn_messages_routing", t(comma_separated_list())}
     , {"overall_messages_routing", t(comma_separated_list())}
     ];
 
-fields("listener") ->
-    [ {"tcp", ref("tcp_listener")}
-    , {"ssl", ref("ssl_listener")}
-    , {"ws", ref("ws_listener")}
-    , {"wss", ref("wss_listener")}
+fields("flapping_detect") ->
+    [ {"enable", t(boolean(), undefined, true)}
+    , {"max_count", t(integer(), undefined, 15)}
+    , {"window_time", t(duration(), undefined, "1m")}
+    , {"ban_time", t(duration(), undefined, "5m")}
     ];
 
-fields("tcp_listener") ->
-    [ {"$name", ref("tcp_listener_settings")}];
+fields("force_shutdown") ->
+    [ {"enable", t(boolean(), undefined, true)}
+    , {"max_message_queue_len", t(range(0, inf), undefined, 1000)}
+    , {"max_heap_size", t(wordsize(), undefined, "32MB", undefined,
+        fun(Siz) ->
+            MaxSiz = case erlang:system_info(wordsize) of
+                8 -> % arch_64
+                    (1 bsl 59) - 1;
+                4 -> % arch_32
+                    (1 bsl 27) - 1
+            end,
+            case Siz > MaxSiz of
+                true ->
+                    error(io_lib:format("force_shutdown_policy: heap-size ~s is too large", [Siz]));
+                false ->
+                    ok
+            end
+        end)}
+    ];
 
-fields("ssl_listener") ->
-    [ {"$name", ref("ssl_listener_settings")}];
+fields("conn_congestion") ->
+    [ {"enable_alarm", t(flag(), undefined, false)}
+    , {"min_alarm_sustain_duration", t(duration(), undefined, "1m")}
+    ];
 
-fields("ws_listener") ->
-    [ {"$name", ref("ws_listener_settings")}];
+fields("force_gc") ->
+    [ {"enable", t(boolean(), undefined, true)}
+    , {"count", t(range(0, inf), undefined, 16000)}
+    , {"bytes", t(bytesize(), undefined, "16MB")}
+    ];
 
-fields("wss_listener") ->
-    [ {"$name", ref("wss_listener_settings")}];
+fields("listeners") ->
+    [ {"$name", hoconsc:union(
+        [ ref("mqtt_tcp_listener")
+        , ref("mqtt_ssl_listener")
+        , ref("mqtt_ws_listener")
+        , ref("mqtt_wss_listener")
+        ])}
+    ];
 
-fields("listener_settings") ->
-    [ {"endpoint", t(union(ip_port(), integer()))}
-    , {"acceptors", t(integer(), undefined, 8)}
-    , {"max_connections", t(integer(), undefined, 1024)}
-    , {"max_conn_rate", t(integer())}
-    , {"active_n", t(integer(), undefined, 100)}
-    , {"zone", t(string())}
-    , {"rate_limit", t(comma_separated_list())}
-    , {"access", ref("access")}
-    , {"proxy_protocol", t(flag())}
-    , {"proxy_protocol_timeout", t(duration())}
+fields("mqtt_tcp_listener") ->
+    [ {"type", t(typerefl:atom(tcp))}
+    , {"tcp", ref("tcp_opts")}
+    ] ++ mqtt_listener();
+
+fields("mqtt_ssl_listener") ->
+    [ {"type", t(typerefl:atom(ssl))}
+    , {"ssl", ref("ssl_opts")}
+    , {"tcp", ref("tcp_opts")}
+    ] ++ mqtt_listener();
+
+fields("mqtt_ws_listener") ->
+    [ {"type", t(typerefl:atom(ws))}
+    , {"tcp", ref("tcp_opts")}
+    , {"websocket", ref("ws_opts")}
+    ] ++ mqtt_listener();
+
+fields("mqtt_wss_listener") ->
+    [ {"type", t(typerefl:atom(ws))}
+    , {"tcp", ref("tcp_opts")}
+    , {"ssl", ref("ssl_opts")}
+    , {"websocket", ref("ws_opts")}
+    ] ++ mqtt_listener();
+
+fields("ws_opts") ->
+    [ {"mqtt_path", t(string(), undefined, "/mqtt")}
+    , {"mqtt_piggyback", t(union(single, multiple), undefined, multiple)}
+    , {"compress", t(boolean())}
+    , {"idle_timeout", t(duration())}
+    , {"max_frame_size", t(integer())}
+    , {"fail_if_no_subprotocol", t(boolean(), undefined, true)}
+    , {"supported_subprotocols", t(string(), undefined,
+        "mqtt, mqtt-v3, mqtt-v3.1.1, mqtt-v5")}
+    , {"check_origin_enable", t(boolean(), undefined, false)}
+    , {"allow_origin_absence", t(boolean(), undefined, true)}
+    , {"check_origins", t(comma_separated_list())}
+    , {"proxy_address_header", t(string(), undefined, "x-forwarded-for")}
+    , {"proxy_port_header", t(string(), undefined, "x-forwarded-port")}
+    , {"deflate_opts", ref("deflate_opts")}
+    ];
+
+fields("tcp_opts") ->
+    [ {"active_n", t(integer(), undefined, 100)}
     , {"backlog", t(integer(), undefined, 1024)}
     , {"send_timeout", t(duration(), undefined, "15s")}
     , {"send_timeout_close", t(flag(), undefined, true)}
     , {"recbuf", t(bytesize())}
     , {"sndbuf", t(bytesize())}
     , {"buffer", t(bytesize())}
-    , {"high_watermark", t(bytesize(), undefined, "1MB")}
     , {"tune_buffer", t(flag())}
+    , {"high_watermark", t(bytesize(), undefined, "1MB")}
     , {"nodelay", t(boolean())}
     , {"reuseaddr", t(boolean())}
     ];
 
-fields("tcp_listener_settings") ->
-    [ {"peer_cert_as_username", t(cn)}
-    , {"peer_cert_as_clientid", t(cn)}
-    ] ++ fields("listener_settings");
-
-fields("ssl_listener_settings") ->
-    [ {"peer_cert_as_username", t(union([cn, dn, crt, pem, md5]))}
-    , {"peer_cert_as_clientid", t(union([cn, dn, crt, pem, md5]))}
-    ] ++
-    ssl(undefined, #{handshake_timeout => "15s"
-                   , depth => 10
-                   , reuse_sessions => true}) ++ fields("listener_settings");
-
-fields("ws_listener_settings") ->
-    [ {"mqtt_path", t(string(), undefined, "/mqtt")}
-    , {"fail_if_no_subprotocol", t(boolean(), undefined, true)}
-    , {"supported_subprotocols", t(string(), undefined, "mqtt, mqtt-v3, mqtt-v3.1.1, mqtt-v5")}
-    , {"proxy_address_header", t(string(), undefined, "x-forwarded-for")}
-    , {"proxy_port_header", t(string(), undefined, "x-forwarded-port")}
-    , {"compress", t(boolean())}
-    , {"deflate_opts", ref("deflate_opts")}
-    , {"idle_timeout", t(duration())}
-    , {"max_frame_size", t(integer())}
-    , {"mqtt_piggyback", t(union(single, multiple), undefined, multiple)}
-    , {"check_origin_enable", t(boolean(), undefined, false)}
-    , {"allow_origin_absence", t(boolean(), undefined, true)}
-    , {"check_origins", t(comma_separated_list())}
-        % @fixme
-    ] ++ lists:keydelete("high_watermark", 1, fields("tcp_listener_settings"));
-
-fields("wss_listener_settings") ->
-    % @fixme
-    Ssl = ssl(undefined, #{depth => 10
-                         , reuse_sessions => true}) ++ fields("listener_settings"),
-    Settings = lists:ukeymerge(1, Ssl, fields("ws_listener_settings")),
-    lists:keydelete("high_watermark", 1, Settings);
-
-fields("access") ->
-    [ {"$id", t(string(), undefined, undefined)}];
+fields("ssl_opts") ->
+    ssl(#{handshake_timeout => "15s"
+        , depth => 10
+        , reuse_sessions => true});
 
 fields("deflate_opts") ->
     [ {"level", t(union([none, default, best_compression, best_speed]))}
@@ -414,7 +429,6 @@ fields("subscription_settings") ->
     , {"rh", t(range(0, 2), undefined, 0)}
     ];
 
-
 fields("rewrite") ->
     [ {"rule", ref("rule")}
     , {"pub_rule", ref("rule")}
@@ -431,15 +445,13 @@ fields("plugins") ->
     ];
 
 fields("broker") ->
-    [ {"sys_interval", t(duration(), "emqx.broker_sys_interval", "1m")}
-    , {"sys_heartbeat", t(duration(), "emqx.broker_sys_heartbeat", "30s")}
-    , {"enable_session_registry", t(flag(), "emqx.enable_session_registry", true)}
-    , {"session_locking_strategy", t(union([local, leader, quorum, all]),
-                                     "emqx.session_locking_strategy", quorum)}
-    , {"shared_subscription_strategy", t(union(random, round_robin),
-                                         "emqx.shared_subscription_strategy", round_robin)}
-    , {"shared_dispatch_ack_enabled", t(boolean(), "emqx.shared_dispatch_ack_enabled", false)}
-    , {"route_batch_clean", t(flag(), "emqx.route_batch_clean", true)}
+    [ {"sys_msg_interval", maybe_disabled(duration(), "1m")}
+    , {"sys_heartbeat_interval", maybe_disabled(duration(), "30s")}
+    , {"enable_session_registry", t(flag(), undefined, true)}
+    , {"session_locking_strategy", t(union([local, leader, quorum, all]), undefined, quorum)}
+    , {"shared_subscription_strategy", t(union(random, round_robin), undefined, round_robin)}
+    , {"shared_dispatch_ack_enabled", t(boolean(), undefined, false)}
+    , {"route_batch_clean", t(flag(), undefined, true)}
     , {"perf", ref("perf")}
     ];
 
@@ -449,14 +461,22 @@ fields("perf") ->
     ];
 
 fields("sysmon") ->
-    [ {"long_gc", t(duration(), undefined, 0)}
-    , {"long_schedule", t(duration(), undefined, 240)}
-    , {"large_heap", t(bytesize(), undefined, "8MB")}
+    [ {"vm", ref("sysmon_vm")}
+    , {"os", ref("sysmon_os")}
+    ];
+
+fields("sysmon_vm") ->
+    [ {"process_check_interval", t(duration_s(), undefined, 30)}
+    , {"process_high_watermark", t(percent(), undefined, "80%")}
+    , {"process_low_watermark", t(percent(), undefined, "60%")}
+    , {"long_gc", maybe_disabled(duration())}
+    , {"long_schedule", maybe_disabled(duration(), 240)}
+    , {"large_heap", maybe_disabled(bytesize(), "8MB")}
     , {"busy_dist_port", t(boolean(), undefined, true)}
     , {"busy_port", t(boolean(), undefined, false)}
     ];
 
-fields("os_mon") ->
+fields("sysmon_os") ->
     [ {"cpu_check_interval", t(duration_s(), undefined, 60)}
     , {"cpu_high_watermark", t(percent(), undefined, "80%")}
     , {"cpu_low_watermark", t(percent(), undefined, "60%")}
@@ -465,12 +485,6 @@ fields("os_mon") ->
     , {"procmem_high_watermark", t(percent(), undefined, "5%")}
     ];
 
-fields("vm_mon") ->
-    [ {"check_interval", t(duration_s(), undefined, 30)}
-    , {"process_high_watermark", t(percent(), undefined, "80%")}
-    , {"process_low_watermark", t(percent(), undefined, "60%")}
-    ];
-
 fields("alarm") ->
     [ {"actions", t(comma_separated_list(), undefined, "log,publish")}
     , {"size_limit", t(integer(), undefined, 1000)}
@@ -487,6 +501,15 @@ fields(ExtraField) ->
     Mod = list_to_atom(ExtraField++"_schema"),
     Mod:fields(ExtraField).
 
+mqtt_listener() ->
+    [ {"bind", t(union(ip_port(), integer()))}
+    , {"acceptors", t(integer(), undefined, 8)}
+    , {"max_connections", t(integer(), undefined, 1024000)}
+    , {"access", t(list(string()))}
+    , {"proxy_protocol", t(flag())}
+    , {"proxy_protocol_timeout", t(duration())}
+    ].
+
 translations() -> ["ekka", "vm_args", "gen_rpc", "kernel", "emqx"].
 
 translation("ekka") ->
@@ -509,9 +532,6 @@ translation("emqx") ->
     , {"zones", fun tr_zones/1}
     , {"listeners", fun tr_listeners/1}
     , {"modules", fun tr_modules/1}
-    , {"sysmon", fun tr_sysmon/1}
-    , {"os_mon", fun tr_os_mon/1}
-    , {"vm_mon", fun tr_vm_mon/1}
     , {"alarm", fun tr_alarm/1}
     , {"telemetry", fun tr_telemetry/1}
     ].
@@ -527,19 +547,6 @@ tr_heart(Conf) ->
         _ -> undefined
     end.
 
-%% @doc http://www.erlang.org/doc/man/erl.html#%2bzdbbl
-node__dist_buffer_size(type) -> bytesize();
-node__dist_buffer_size(validator) ->
-    fun(ZDBBL) ->
-        case ZDBBL >= 1024 andalso ZDBBL =< 2147482624 of
-            true ->
-                ok;
-            false ->
-                {error, "must be between 1KB and 2097151KB"}
-        end
-    end;
-node__dist_buffer_size(_) -> undefined.
-
 tr_zdbbl(Conf) ->
     case conf_get("node.dist_buffer_size", Conf) of
         undefined -> undefined;
@@ -834,25 +841,6 @@ tr_modules(Conf) ->
         [{emqx_mod_acl_internal, [{acl_file, conf_get("acl.acl_file", Conf)}]}]
     ]).
 
-tr_sysmon(Conf) ->
-    Keys = maps:to_list(conf_get("sysmon", Conf, #{})),
-    [{binary_to_atom(K), maps:get(value, V)} || {K, V} <- Keys].
-
-tr_os_mon(Conf) ->
-    [{cpu_check_interval, conf_get("os_mon.cpu_check_interval", Conf)}
-    , {cpu_high_watermark, conf_get("os_mon.cpu_high_watermark", Conf) * 100}
-    , {cpu_low_watermark, conf_get("os_mon.cpu_low_watermark", Conf) * 100}
-    , {mem_check_interval, conf_get("os_mon.mem_check_interval", Conf)}
-    , {sysmem_high_watermark, conf_get("os_mon.sysmem_high_watermark", Conf) * 100}
-    , {procmem_high_watermark, conf_get("os_mon.procmem_high_watermark", Conf) * 100}
-    ].
-
-tr_vm_mon(Conf) ->
-    [ {check_interval, conf_get("vm_mon.check_interval", Conf)}
-    , {process_high_watermark, conf_get("vm_mon.process_high_watermark", Conf) * 100}
-    , {process_low_watermark, conf_get("vm_mon.process_low_watermark", Conf) * 100}
-    ].
-
 tr_alarm(Conf) ->
     [ {actions, [list_to_atom(Action) || Action <- conf_get("alarm.actions", Conf)]}
     , {size_limit, conf_get("alarm.size_limit", Conf)}
@@ -966,46 +954,7 @@ rate_limit_num_dur([L, D]) ->
 
 map_zones(_, undefined) ->
     {undefined, undefined};
-map_zones("force_gc_policy", [Count, Bytes]) ->
-    GcPolicy = case to_bytesize(Bytes) of
-                   {error, Reason} ->
-                       error({bytesize, Reason});
-                   {ok, Bytes1} ->
-                       #{bytes => Bytes1,
-                           count => list_to_integer(Count)}
-               end,
-    {force_gc_policy, GcPolicy};
-map_zones("force_shutdown_policy", ["default"]) ->
-    WordSize = erlang:system_info(wordsize),
-    {DefaultLen, DefaultSize} =
-        case WordSize of
-            8 -> % arch_64
-                {10000, hocon_postprocess:bytesize("64MB")};
-            4 -> % arch_32
-                {1000, hocon_postprocess:bytesize("32MB")}
-        end,
-    {force_shutdown_policy, #{message_queue_len => DefaultLen,
-        max_heap_size => DefaultSize div WordSize
-    }};
-map_zones("force_shutdown_policy", [Len, Siz]) ->
-    WordSize = erlang:system_info(wordsize),
-    MaxSiz = case WordSize of
-                 8 -> % arch_64
-                     (1 bsl 59) - 1;
-                 4 -> % arch_32
-                     (1 bsl 27) - 1
-             end,
-    ShutdownPolicy =
-        case to_bytesize(Siz) of
-            {error, Reason} ->
-                error(Reason);
-            {ok, Siz1} when Siz1 > MaxSiz ->
-                error(io_lib:format("force_shutdown_policy: heap-size ~s is too large", [Siz]));
-            {ok, Siz1} ->
-                #{message_queue_len => list_to_integer(Len),
-                    max_heap_size => Siz1 div WordSize}
-        end,
-    {force_shutdown_policy, ShutdownPolicy};
+
 map_zones("mqueue_priorities", Val) ->
     case Val of
         ["none"] -> {mqueue_priorities, none}; % NO_PRIORITY_TABLE
@@ -1019,8 +968,6 @@ map_zones("mqueue_priorities", Val) ->
                                            end, #{}, Val),
             {mqueue_priorities, MqueuePriorities}
     end;
-map_zones("mountpoint", Val) ->
-    {mountpoint, iolist_to_binary(Val)};
 map_zones("response_information", Val) ->
     {response_information, iolist_to_binary(Val)};
 map_zones("rate_limit", Conf) ->
@@ -1094,41 +1041,34 @@ filter(Opts) ->
     [{K, V} || {K, V} <- Opts, V =/= undefined].
 
 %% generate a ssl field.
-%% ssl("emqx", #{"verify" => verify_peer}) will return
-%% [ {"cacertfile", t(string(), "emqx.cacertfile", undefined)}
-%% , {"certfile", t(string(), "emqx.certfile", undefined)}
-%% , {"keyfile", t(string(), "emqx.keyfile", undefined)}
-%% , {"verify", t(union(verify_peer, verify_none), "emqx.verify", verify_peer)}
-%% , {"server_name_indication", "emqx.server_name_indication", undefined)}
-%% ...
-ssl(Mapping, Defaults) ->
-    M = fun (Field) ->
-        case (Mapping) of
-            undefined -> undefined;
-            _ -> Mapping ++ "." ++ Field
-        end end,
+%% ssl(#{"verify" => verify_peer}) will return:
+%%  [ {"cacertfile", t(string(), undefined, undefined)}
+%%  , {"certfile", t(string(), undefined, undefined)}
+%%  , {"keyfile", t(string(), undefined, undefined)}
+%%  , {"verify", t(union(verify_peer, verify_none), undefined, verify_peer)}
+%%  , {"server_name_indication", undefined, undefined)}
+%%  ...]
+ssl(Defaults) ->
     D = fun (Field) -> maps:get(list_to_atom(Field), Defaults, undefined) end,
-    [ {"enable", t(flag(), M("enable"), D("enable"))}
-    , {"cacertfile", t(string(), M("cacertfile"), D("cacertfile"))}
-    , {"certfile", t(string(), M("certfile"), D("certfile"))}
-    , {"keyfile", t(string(), M("keyfile"), D("keyfile"))}
-    , {"verify", t(union(verify_peer, verify_none), M("verify"), D("verify"))}
-    , {"fail_if_no_peer_cert", t(boolean(), M("fail_if_no_peer_cert"), D("fail_if_no_peer_cert"))}
-    , {"secure_renegotiate", t(flag(), M("secure_renegotiate"), D("secure_renegotiate"))}
-    , {"reuse_sessions", t(flag(), M("reuse_sessions"), D("reuse_sessions"))}
-    , {"honor_cipher_order", t(flag(), M("honor_cipher_order"), D("honor_cipher_order"))}
-    , {"handshake_timeout", t(duration(), M("handshake_timeout"), D("handshake_timeout"))}
-    , {"depth", t(integer(), M("depth"), D("depth"))}
-    , {"password", hoconsc:t(string(), #{mapping => M("key_password"),
-                                         default => D("key_password"),
+    [ {"cacertfile", t(string(), undefined, D("cacertfile"))}
+    , {"certfile", t(string(), undefined, D("certfile"))}
+    , {"keyfile", t(string(), undefined, D("keyfile"))}
+    , {"verify", t(union(verify_peer, verify_none), undefined, D("verify"))}
+    , {"fail_if_no_peer_cert", t(boolean(), undefined, D("fail_if_no_peer_cert"))}
+    , {"secure_renegotiate", t(flag(), undefined, D("secure_renegotiate"))}
+    , {"reuse_sessions", t(flag(), undefined, D("reuse_sessions"))}
+    , {"honor_cipher_order", t(flag(), undefined, D("honor_cipher_order"))}
+    , {"handshake_timeout", t(duration(), undefined, D("handshake_timeout"))}
+    , {"depth", t(integer(), undefined, D("depth"))}
+    , {"password", hoconsc:t(string(), #{default => D("key_password"),
                                          sensitive => true
                                         })}
-    , {"dhfile", t(string(), M("dhfile"), D("dhfile"))}
-    , {"server_name_indication", t(union(disable, string()), M("server_name_indication"),
+    , {"dhfile", t(string(), undefined, D("dhfile"))}
+    , {"server_name_indication", t(union(disable, string()), undefined,
                                    D("server_name_indication"))}
-    , {"tls_versions", t(comma_separated_list(), M("tls_versions"), D("tls_versions"))}
-    , {"ciphers", t(comma_separated_list(), M("ciphers"), D("ciphers"))}
-    , {"psk_ciphers", t(comma_separated_list(), M("ciphers"), D("ciphers"))}].
+    , {"tls_versions", t(comma_separated_list(), undefined, D("tls_versions"))}
+    , {"ciphers", t(comma_separated_list(), undefined, D("ciphers"))}
+    , {"psk_ciphers", t(comma_separated_list(), undefined, D("ciphers"))}].
 
 tr_ssl(Field, Conf) ->
     Versions = case conf_get([Field, "tls_versions"], Conf) of
@@ -1220,9 +1160,31 @@ t(Type, Mapping, Default, OverrideEnv) ->
                      , override_env => OverrideEnv
                      }).
 
+t(Type, Mapping, Default, OverrideEnv, Validator) ->
+    hoconsc:t(Type, #{ mapping => Mapping
+                     , default => Default
+                     , override_env => OverrideEnv
+                     , validator => Validator
+                     }).
+
 ref(Field) ->
     fun (type) -> Field; (_) -> undefined end.
 
+maybe_disabled(T) ->
+    maybe_sth(disabled, T, disabled).
+
+maybe_disabled(T, Default) ->
+    maybe_sth(disabled, T, Default).
+
+% maybe_infinity(T) ->
+%     maybe_sth(infinity, T, infinity).
+
+maybe_infinity(T, Default) ->
+    maybe_sth(infinity, T, Default).
+
+maybe_sth(What, Type, Default) ->
+    t(union([What, Type]), undefined, Default).
+
 to_flag(Str) ->
     {ok, hocon_postprocess:onoff(Str)}.
 
@@ -1250,6 +1212,13 @@ to_bytesize(Str) ->
         _ -> {error, Str}
     end.
 
+to_wordsize(Str) ->
+    WordSize = erlang:system_info(wordsize),
+    case to_bytesize(Str) of
+        {ok, Bytes} -> Bytes div WordSize;
+        Error -> Error
+    end.
+
 to_percent(Str) ->
     {ok, hocon_postprocess:percent(Str)}.