How to best read large dataset from disk
A common way is to create a class inheriting tf.keras.utils.Sequence. This class implements a function __getitem__ which is called when you use model.fit() method. In this method, you can simply load one batch at a time, so no need to load the whole dataset. See the documentation. You can also directly use the .npz files when calling __getitem__.
Shuffle data

Do I save my data as is, or do I need to save shuffled batches?

You would implement the method on_epoch_end() that does the shuffling of a list of indices. Then when you load a .npz file, use something like data[indices[i]] which load the index i in the shuffled list of indices.
on_epoch_end is called at the end of each epoch by .fit() method, and you can also use it in __init__ of your Sequence class to initialize the shuffle.
From Keras to Pytorch
Pytorch has similar module called torch.utils.data.Dataset. The conversion is straightforward. See this tutorial.