Render arrays are rendered by the renderer service (RendererInterface), which traverses the array and recursively renders each level. Each level of the array can have one or more elements, which can be of two types: properties or children. The properties are the ones whose keys are preceded by a # sign, whereas children are the ones that are not. The children can themselves be an array with properties and children. However, each level needs to have at least one property in order to be considered a level because it is responsible for telling the render system how that level needs to be rendered. As such, property names are specific to the Render API and to the actual thing they need to render, while the names of children can be flexible. In addition to these two types (yes, I lied, there can be more than two), we can also have the variables defined by a theme hook, which are also preceded by the # sign. They are not properties per se but are known by the theme system because they have been registered inside hook_theme().
There are many properties the Render API uses to process a render array. Some of them are quite important, such as #cache and #attached. However, there are a few that are mandatory in order for a render array to make sense, in that they define its core responsibility. The following are the properties that describe what the render array should do and each render array should have one of these.