Without hesitation, the modern high-speed development of the Internet has created a batch of network celebrities, this batch of network red and greatly spawned a particular platform of a large wave of traffic, but left the programmer is a chicken, whether operation or development, every day will worry about the server crash, the program down machine. I’m still nostalgic for the stand-alone structure. I’m even a little jealous of the programmers who worked on apps that had almost no traffic on the Intranet, no overtime, no fear, and no need to buy Overlord shampoo every year.

Referring to the stand-alone architecture, in the Internet application is certainly not hard, traffic peak impact you can doubt life. Upgrading a cluster on a single machine not only brings technical challenges, but also introduces configuration complexity while coping with traffic peak and catering to business. That’s what I’m going to talk about today: configuration management. In the standalone era, no matter what language, Java, c#, a configuration file is enough. With the birth of the so-called micro-service, which seems to be the solution to all problems, more complex configuration problems have been introduced: service information, various parameters of the service, configuration update and so on. As you can imagine, if your service has 100 servers, it is very painful to modify a configuration item and use the single architecture to update one by one. The traditional configuration file method can no longer meet the requirements of developers for configuration management:

  1. Security. If the configuration information is released together with the code, the configuration is likely to be leaked.
  2. Real time. The configuration modification takes effect only after the traditional single-machine architecture service is restarted.
  3. Limitations. Dynamic adjustment is not supported, nor is the most common logging switch.
  4. Environment differentiation. Traditional configuration files make it difficult to distinguish between production, development, and test environments.
  5. The configuration modification record is faulty. In static configuration file mode, it is difficult to trace the change history of this configuration file.

To address these problems, some companies use database record configuration to solve the problem. It’s not that you can’t, but the database does not solve the fundamental problem. For example, how can clients be notified of the latest record changes in real time? Although other solutions can be used, the database-based approach is not optimal.

Whether the configuration center adopts the database way or other ways, the essence of the starting point or to see the specific needs of the business and the corresponding input of human and material resources. Not to say that the Apollo of Ctrip is not good, but to say whether such a huge configuration system is suitable for your company, whether it is suitable for your business. In many cases, the company’s business development is all in a certain stage of rapid spike, it is not necessary to also have no time to input energy to a huge system, deep research on the business gradually developed can slowly after iterations, this is the upgrade process of system architecture, the business will be established at the beginning of the taobao level architecture, will eventually end up everyone tired.

Having said so much, I just want to lu a simple, landing configuration center, to ensure that the configuration center can work normally, there are several points to consider at the beginning of the design:

You need a reliable, consistent storage to support it

After many technical investigations, I finally chose ETCD, not because I like to seek hot spots, but because THE functions of ETCD in dealing with scenes exactly correspond to my needs.

Etcd is an open source project launched by the CoreOS team in June 2013. Its goal is to build a highly available distributed key-value database. Raft protocol is adopted as consistency algorithm in ETCD, and ETCD is implemented based on Go language.

  1. Simple: It is simple to install and configure, and it provides an HTTP API for interaction and is simple to use
  2. Security: Supports SSL certificate authentication
  3. Fast: A single instance supports 2k+ reads per second, according to official benchmark data
  4. Reliability: Raft algorithm is adopted to achieve the availability and consistency of distributed system data
  5. Watch mechanism: ETCD supports the Watch mechanism for a Key or group of keys. Once data changes, ETCD notifies clients in real time.

The configuration of multiple environments is required

Although many storage display parameters do not have such parameters as environment, but they provide similar functions such as directory storage, just like the file directory of Windows, which provides us with strong adaptability to customize functions. For example, our storage A application development environment can be like this: /A /dev/this directory represents the development environment configuration of the A application.

When configuration items change, the client needs to be notified in real time

ETCD, which is based on the first choice, naturally supports the Watch mechanism, so it is good to notify the client in real time when the configuration item changes. Even if the notification fails, we can also customize the time to delay the configuration update. Take a look at the following code later.

Keep it simple

For users, the only service interface provided by the configuration center is to obtain the configuration of a key, which can be a collection of application and environment parameters. To aid tracing, you can expose processing events when an exception occurs in the program, as in the following program:

/// configure center client, application, sub-application, /// </summary> public interface IConfigCenterClient {/// <summary> // Key/New Value/Action (PUT /delete) is an event on etCD/Consul watch. </ /summary> Event Action< String, String, String > ConfigValueChangedEvent; // </summary> Event Action<string, String, String > ConfigValueChangedEvent; // </summary> event Action<Exception> ErrorOccurredEvent; / / / < summary > / / / / / / get the corresponding configuration < summary > / / / < param name = "configKey" > configuration name < param > / / / < param name = "version" > version < param >  /// <returns></returns> string GetConfig(string configKey); }Copy the code

Once the interface is abstracted out, the implementation can be ETCD based, Consul based, or even DB based, showing how interface oriented programming works.

Need to be able to continue working in case of network failure

In Internet applications, there is always a truth: the network is unreliable. Configuration center as a core system of the company, to ensure as much as possible to provide services. However, precautions should be taken to ensure that the applicable party is not affected during the temporary unavailability of the configuration center. For the client, since the server cannot guarantee high availability, it needs to be done locally: the obtained configuration information can be stored locally, and the information can be persisted with the Watch mechanism. In this way, if the configuration center network is not available, try to ensure that the client program is available. As for the local storage method, it doesn’t matter, even if the text file, or SQllite will work.

Higher performance

One of the most significant business characteristics of the configuration center is that it does not change very often, but the clients use it frequently. Therefore, we can load configuration information into memory, and the data in memory will change with the change of watch mechanism, so that the data in memory is highly consistent with the data on the server side.

The above wordy so much, I believe you also see tired, empty talk theory who will, the landing code is the truth.

Configure the central interface on the client
/// configure center client, application, sub-application, /// </summary> public interface IConfigCenterClient {/// <summary> // Key/New Value/Action (PUT /delete) is an event on etCD/Consul watch. </ /summary> Event Action< String, String, String > ConfigValueChangedEvent; // </summary> Event Action<string, String, String > ConfigValueChangedEvent; // </summary> event Action<Exception> ErrorOccurredEvent; / / / < summary > / / / / / / get the corresponding configuration < summary > / / / < param name = "configKey" > configuration name < param > / / / < param name = "version" > version < param >  /// <returns></returns> string GetConfig(string configKey); } /// </summary> public enum EnvEnum {/// </summary> /// Local environment // </summary> Local=1, / / / < summary > / / / / / / development environment < summary > DEV, / / / < summary > / / / / / / simulation environment < summary > UAT, Public class ConfigCenterETCDProvider: ConfigCenterETCDProvider: ConfigCenterETCDProvider: ConfigCenterBaseProvider IConfigCenterClient {/ / configuration change notification event public event Action < string, string, string> ConfigValueChangedEvent; Public override event Action<Exception> errorReported; Private ConfigCenterETCDOption option {get; set; } private EtcdClient client = null; internal ConfigCenterETCDProvider(ConfigCenterBaseOption _option) : base(_option) { if (_option == null) { throw new Exception("config is null!" ); } option = _option as ConfigCenterETCDOption; if (option == null) { throw new Exception("option type is wrong!" ); } the if (string. IsNullOrWhiteSpace (option. The ConnectionString)) {/ / the default address option. The ConnectionString = "http://127.0.0.1"; } client = new EtcdClient(option.ConnectionString, option.Port, option.Username, option.Password, option.CaCert, option.ClientCert, option.ClientKey, option.PublicRootCa); client.WatchRange(WatchPath, ETCDWatchEvent, exceptionHandler: e => { ErrorOccurredEvent? .Invoke(e); Thread.Sleep(1000); }); InitConfigMapFromLocal(); Public bool SetConfig(string configKey, string configValue) { string key = FillConfigKey(configKey); try { var putRet = client.Put(key, configValue); } catch (Exception e) { ErrorOccurredEvent? .Invoke(e); return false; } return true; } // Delete a configuration value public bool DeleteConfig(string configKey) {string key = FillConfigKey(configKey); try { client.Delete(key); } catch (Exception e) { ErrorOccurredEvent? .Invoke(e); return false; } return true; } #endregion #region base method //etcd protected Override string FillConfigKey(string configKey) {return $"{WatchPath}/{configKey}"; } //etcd obtain remote key protected override (bool isSuccess, string value) GetValueFromServer(string configKey) { try { var value = client.GetVal(configKey); return (true, value); } catch (Exception e) { ErrorOccurredEvent? .Invoke(e); return (false, null); }} #endregion #region private void ETCDWatchEvent(WatchEvent[] Response) {lock (ConfigCenterBaseProvider.ObjLock) { foreach (WatchEvent e in response) { if (e.Type == Mvccpb.Event.Types.EventType.Delete) { if (ConfigMap.ContainsKey(e.Key)) { ConfigMap.Remove(e.Key); } } else { ConfigMap[e.Key] = e.Value; } Console.WriteLine(JsonConvert.SerializeObject(ConfigMap)); if (ConfigValueChangedEvent ! = null) { ConfigValueChangedEvent.Invoke(e.Key, e.Value, e.Type.ToString()); } } if (response ! Null && response.any ()) {// write the latest value to the local file FlushLocalFileFromMap(); } } } #endregion }Copy the code

Since there are too many codes, I will not post them here. If you are interested, you can reply to “Configuration Center” by adding caicai wechat or the public account “Path of Architect Practice”. The complete simplified version of configuration Center based on ETCD is provided with all the codes

More interesting articles

  • Distributed large concurrent series
  • Architectural Design Series
  • Series of interesting algorithms and data structures
  • Design Pattern series